Utilizzo della grammatica del linguaggio naturale in API fluente

14

Sto armeggiando con un'astrazione di query su API di database WebSQL / Phonegap e mi trovo sia attirato, sia dubbioso, a definire un'API fluente che imita l'uso della grammatica naturale della lingua inglese.

Potrebbe essere più semplice spiegarlo tramite esempi. Quelle che seguono sono tutte query valide nella mia grammatica e i commenti spiegano la semantica prevista:

//find user where name equals "foo" or email starts with "[email protected]"
find("user").where("name").equals("foo").and("email").startsWith("[email protected]")

//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);

Modifica basata sul feedback di Quentin Pradet : Inoltre, sembra che l'API debba supportare sia forme di verbo plurali che singolari, quindi:

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

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

Per motivi di dubbio, supponiamo di non aver esaurito tutti i possibili costrutti qui. Supponiamo anche che io possa coprire la maggior parte frasi inglesi corrette - dopo tutto, la grammatica stessa è limitata ai verbi e alle congiunzioni definite da SQL.

Modifica relativa al raggruppamento : una "frase" è un gruppo e la precedenza è definita in SQL: da sinistra a destra. Gruppi multipli possono essere espressi con più istruzioni where :

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

Come puoi vedere, la definizione di ogni metodo dipende dal contesto grammaticale in cui si trova. Ad esempio, l'argomento "metodi di congiunzione" or() e and() può essere escluso, o fai riferimento a un nome di campo o valore atteso.

Per me è molto intuitivo, ma mi piacerebbe che tu sentissi il tuo feedback: questa è una buona e utile API, o dovrei fare retromarcia per un'implementazione più rapida?

Per la cronaca: questa libreria fornirà anche un'API più convenzionale e non fluente basata sugli oggetti di configurazione.

    
posta fencliff 01.03.2013 - 15:52
fonte

4 risposte

23

Penso che sia molto sbagliato. Studio la lingua naturale ed è piena di ambiguità che può essere risolta solo con il contesto e molta conoscenza umana. Il fatto che i linguaggi di programmazione non siano ambigui è un'ottima cosa! Non penso che tu voglia che i metodi cambino in base al contesto:

  • Questo aggiunge più sorprese dato che porti ambiguità
  • I tuoi utenti vorranno utilizzare costruzioni che non saranno coperte, ad es. %codice%
  • È difficile segnalare errori: cosa puoi fare con find("user").where("name").and("email").equals("foo"); ?

Let's also presume that I can cover most correct English sentences - after all, the grammar itself is limited to the verbs and conjuctions defined by SQL.

No, non puoi coprire le frasi inglesi più corrette. Altri hanno provato prima, e diventa molto complicato molto rapidamente. Si chiama comprensione del linguaggio naturale ma nessuno ci prova veramente: stiamo cercando di risolvere prima i problemi più piccoli. Per la tua libreria, in pratica hai due opzioni:

  • o ti limiti a un sottoinsieme di inglese: questo ti dà SQL,
  • o cerchi di coprire "inglese" e scopri che non è possibile a causa dell'ambiguità, della complessità e della diversità della lingua.
risposta data 01.03.2013 - 16:00
fonte
3

Tendo a concordare in qualche modo con i post degli altri che questo non è un grande progetto. Tuttavia, credo di avere diversi motivi.

Stai presentando ciò che vedo come una sintassi concreta per le query SQL. Sono fermamente convinto che la sintassi concreta non possa mai aiutare una lingua, solo male se è cattiva.

Tuttavia, sintassi astratta è una storia diversa. La sintassi astratta definisce la struttura della tua lingua e come le frasi possono essere combinate per costruire frasi più grandi. Sento che il successo di un linguaggio dipende strongmente dalla qualità della sua definizione sintattica astratta.

Il mio problema con l'API fluente non è che sia ambiguo, o poco chiaro o non espressivo - è che nasconde il linguaggio reale e la sua struttura, e così facendo, finisce per rendere le cose molto più complicate di quanto non abbiano essere (introducendo ambiguità, errori di sintassi non ovvi, ecc.).

Dato che hai detto che fornirai anche una "API più convenzionale", sembra che tu sappia già tutto questo. Per quello dico "Bene!" Ma ciò non significa che non puoi sviluppare la tua API fluente in parallelo! Una singola definizione di sintassi astratta può supportare più sintassi concrete. Mentre dovresti tenere a mente che la sintassi astratta è il vero affare, una sintassi concreta può anche essere molto utile.

    
risposta data 01.03.2013 - 18:59
fonte
2

Oltre agli ottimi punti di Quentin Pradet, dubito dei presunti benefici di questa lingua.

Probabilmente il punto di una grammatica vicino al linguaggio naturale è renderlo accessibile. Ma SQL è già abbastanza vicino al linguaggio naturale. Uno di questi è davvero più vicino all'inglese rispetto all'altro?

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

select user from table where name = 'foo'

Non vedo davvero i benefici della tua grammatica, dal punto di vista dell'intuitività o della leggibilità. In effetti, la versione SQL sembra più leggibile (ed è più facile da scrivere) a causa dei suoi spazi bianchi.

    
risposta data 01.03.2013 - 17:12
fonte
2

Ci sono un certo numero di bad meno delle decisioni di progettazione ideali che sembrano essere state prese nel considerare questa API.

Il primo è la questione dell'utilità: quale scopo serve? Sembra che stia creando una struttura dati che verrà compilata in un dialetto di SQL. Per inciso, la grammatica sembra essere un insieme limitato di SQL. La domanda su "quale vantaggio serve a usare semplicemente SQL?" diventa la chiave. Se è più complicato scrivere usando l'interfaccia fluente che scrivere una stringa con l'interpolazione appropriata, allora non si scriverà usando questa API.

L'inglese è ambiguo. Il tentativo di modellare un'interfaccia fluente in inglese è una scelta sbagliata (è meglio usare Latina ). Quando ci sono più analisi valide dello stesso insieme di catene di chiamate, questo porta a confusione e sorpresa . Nessuno di questi è un bene da avere in una API.

Esistono più parti di SQL che questa API sta esponendo. Le unioni (in una qualsiasi delle loro innumerevoli forme) sono notevolmente assenti dall'insieme di esempi. Le sottoquery ( foo in (select id from bar) ), i sindacati e il gruppo per sono alcune delle cose che vengono spesso utilizzate. Raggruppamenti complessi di logica non sembrano essere presenti in alcun modo intuitivo.

Se si scriveva usando questa API e poi si è riscontrato che l'API non è in grado di esprimere la query desiderata, si perderebbe un tempo significativo. È una scelta sbagliata usare stili misti per fare una query in un'applicazione (query semplici in questa API, complessa in sql raw) - e alla fine sarà usato quello più espressivo.

Mentre la programmazione è diffusa, la fluenza inglese no. Anche con una limitazione del linguaggio a "SQL like" ci sono delle sfumature su come un madrelingua dovrebbe leggere qualcosa e qualcuno che ha l'inglese come seconda o terza lingua.

C'è una ridondanza non necessaria nell'API per il gusto dell'inglese. In particolare equal() vs equals() facendo la stessa cosa. Anche se non ne sono certo, credo che is() sia un no-op aggiunto per l'intimità di un inglese più vicino. Accolgo con favore qualsiasi ascolto delle mie lamentele sulla ridondanza dei metodi in ruby in chat - non commettere lo stesso errore.

Siediti e scrivi una serie completa di esempi delle query che desideri poter utilizzare. Determina chi gestirai tutti questi esempi in un modo non ambiguo meno ingombrante delle stesse query. Se non puoi, valuta se vale la pena di seguire il percorso di scrittura dell'API. SQL è dove è oggi (non è perfetto, ma non ho trovato niente di meglio) per decenni di raffinatezza.

RFC 1925 - The Twelve Networking Truths

(12) In protocol design, perfection has been reached not when there is nothing left to add, but when there is nothing left to take away.

    
risposta data 01.03.2013 - 17:15
fonte

Leggi altre domande sui tag