web-dev-qa-db-ja.com

Fluent APIでの自然言語文法の使用

私はWebSQL/Phonegap Database APIに対するクエリの抽象化をいじくり回しており、自然な英語の文法の使用を模倣する流暢なAPIを定義することに惹かれ、疑わしいと感じています。

例でこれを説明するのが最も簡単かもしれません。以下はすべて私の文法で有効なクエリであり、コメントは意図された意味を説明しています。

_//find user where name equals "foo" or email starts with "foo@"
find("user").where("name").equals("foo").and("email").startsWith("foo@")

//find user where name equals "foo" or "bar"
find("user").where("name").equals("foo").or("bar");

//find user where name equals "foo" or ends with "bar"
find("user").where("name").equals("foo").or().endsWith("bar");

//find user where name equals or ends with "foo"
find("user").where("name").equals().or().endsWith("foo");

//find user where name equals "foo" and email is not like "%contoso.com"
find("user").where("name").equals("foo").and("email").is().not().like("%contoso.com");

//where name is not null
find("user").where("name").is().not().null();

//find post where author is "foo" and id is in (1,2,3)
find("post").where("author").is("foo").and("id").is().in(1, 2, 3);

//find post where id is between 1 and 100
find("post").where("id").is().between(1).and(100);
_

Quentin Pradetのフィードバックに基づいて編集:さらに、APIは複数形と単数形の両方の動詞形式をサポートする必要があるようです。

_//a equals b
find("post").where("foo").equals(1);

//a and b (both) equal c
find("post").where("foo").and("bar").equal(2);
_

質問のために、ここではすべての可能な構成を使い尽くしていないと仮定しましょう。 most正しい英語の文をカバーできると仮定しましょう-結局のところ、文法自体はSQLによって定義された動詞と語彙に制限されています。


グループ化に関する編集:1つの「文」は1つのグループであり、優先順位はSQLで定義されているとおりです(左から右)。複数のグループ化は、複数のwhereステートメントで表すことができます。

_//the conjunctive "and()" between where statements is optional
find("post")
  .where("foo").and("bar").equal(2).and()
  .where("baz").isLessThan(5);
_

ご覧のとおり、各メソッドの定義は、そのメソッドが含まれている文法コンテキストに依存しています。たとえば、「結合メソッド」_or()and()の引数は省略できます。 orフィールド名を参照or期待値。

私にはこれは非常に直感的に感じられますが、フィードバックをお願いします。これは優れた便利なAPIですか、それともより単純な実装に戻しますか?

記録のために:このライブラリーは、構成オブジェクトに基づいた、より一般的な非流暢APIも提供します。

14
fencliff

それは非常に間違っていると思います。私は自然言語を研究していますが、それは文脈と多くの人間の知識によってのみ解決できる曖昧さでいっぱいです。プログラミング言語があいまいではないということは非常に良いことです!コンテキストに応じてメソッドの意味を変えたいとは思わない:

  • あいまいさをもたらすので、これはより多くの驚きを追加します
  • あなたのユーザーはあなたがカバーしないであろう構造を使いたいでしょう、例えば。 find("user").where("name").and("email").equals("foo");
  • エラーを報告するのは難しい:find("user").where("name").not().is().null();で何ができるか?

また、私が最も正しい英語の文をカバーできると仮定しましょう-結局のところ、文法自体はSQLによって定義された動詞と語彙に限定されています。

いいえ、ほとんどの正しい英語の文章をカバーすることはできません。他の人は以前に試したことがあり、それは非常にすぐに複雑になります。これは 自然言語理解 と呼ばれていますが、実際にそうしようとする人はいません。まず、小さな問題を解決しようとしています。ライブラリには、基本的に2つのオプションがあります。

  • 自分を英語のサブセットに制限するか、SQLを提供するか、
  • または、「英語」をカバーしようとしても、あいまいさ、複雑さ、言語の多様性のために不可能であることがわかります。
23
Quentin Pradet

これは素晴らしいデザインではないと他の人の投稿に多少同意する傾向があります。しかし、私にはさまざまな理由があると思います。

SQLクエリの具体的な構文として私が見ているものを提示しています。 具体的な構文は言語を助けることはできず、悪い場合にのみ害を及ぼすと私は強く信じています。

ただし、抽象的な構文は別の話です。抽象構文は、言語の構造と、フレーズを組み合わせてより大きなフレーズを作成する方法を定義します。言語の成功は、その抽象構文定義の品質に大きく依存すると私は感じています。

流暢なAPIの私の問題は、あいまいであったり、不明瞭であったり、表現力がないことではありません。実際の言語とその構造を隠し、その結果、必要以上に複雑なものになってしまうことです(あいまいさ、明白でない構文エラーなどを導入することにより)。

「より一般的なAPI」も提供するとのことですが、これはすべてご存じのようです。それに「いいね!」と言います。しかし、だからといって流暢なAPIを並行して開発できないということではありません。 1つの抽象構文定義で、複数の具象構文をサポートできます。抽象構文は本物だということを覚えておかなければなりませんが、具体的な構文も非常に役立ちます。

3
user39685

クエンティンプラデットの非常に優れた点に加えて、私はこの言語の主張されている利点に疑問を抱いています。

おそらく自然言語に近い文法のポイントは、それをアクセス可能にすることです。しかし、SQLはすでに自然言語にかなり近いです。これらの1つは他のものよりも本当に英語に近いですか?

find("user").where("name").equals("foo")

select user from table where name = 'foo'

直感性や読みやすさの観点から、文法の利点は本当にわかりません。実際、SQLバージョンは空白のため、読みやすく(そして入力しやすく)見えます。

2
user82096

いくつかあります 悪い このAPIを検討する際に行われたと思われる理想的な設計決定よりも少ない。

最初は実用性の問題です-それはどんな目的に役立ちますか?これは、SQLの方言にコンパイルされるデータ構造を作成しているようです。ちなみに、文法はSQLの限られたセットのようです。 「SQLを使用するだけではどのような利点があるのか​​」という質問です。キーになります。適切な補間を含む文字列を単に書き込むよりも、流れるようなインターフェイスを使用して書き込むほうが面倒な場合は、このAPIを使用して書き込むことはありません。

英語があいまいです。英語で流暢なインターフェイスをモデル化しようとするのはよくない選択です( Latin を使用するほうがよいでしょう)。同じ呼び出しチェーンのセットの有効な解析が複数ある場合、混乱と 驚き が発生します。これらはどちらも、APIで使用するのに適したものではありません。

このAPIが公開しているよりも多くの部分がSQLにあります。結合(無数の形式のいずれか)は、サンプルセットでは特にありません。サブクエリ(foo in (select id from bar))、共用体、およびグループ化は、よく使用されるものの一部です。ロジックの複雑なグループは、直感的な方法で存在するようには見えません。

このAPIを使用して作成していて、APIが目的のクエリを表現できないことが判明した場合、かなりの時間が失われます。アプリケーションでクエリを実行するために混合スタイル(このAPIでは単純なクエリ、生のSQLでは複雑)を使用することはお勧めできません。最終的にはより表現力のあるものが使用されます。

プログラミングは広く普及していますが、英語は流暢ではありません。言語が「SQLライク」に制限されている場合でも、ネイティブスピーカーが何かを読む方法や、第2または第3言語として英語を話す人にはニュアンスがあります。

英語のために、APIに不要な冗長性があります。特にequal()equals()は同じことをしています。確かではありませんが、is()は、一致する英語をより近くするために追加された操作ではないと思います。 Ruby)でメソッドの冗長性についての私の怒りを聞くのを歓迎します-同じ過ちを犯さないでください。

座って、使用したいクエリの包括的なサンプルセットを書き出します。これらの例のすべてを、クエリ自体よりも煩わしくない明確な方法で誰が処理するかを決定します。できない場合は、APIを作成する方法を検討する価値があるかどうかを検討してください。何十年にもわたる洗練の中で、SQLは現在のところにあります(完璧ではありませんが、これ以上優れたものはありません)。

RFC 1925 -12のネットワークの真実

(12)プロトコルの設計では、追加するものが残っていないときではなく、削除するものが残っていないときに完全に達しています。

2
user40980