Quali sono gli argomenti contro l'analisi del modo Cthulhu?

24

Mi è stato assegnato il compito di implementare un linguaggio specifico di dominio per uno strumento che potrebbe diventare piuttosto importante per l'azienda. Il linguaggio è semplice ma non banale, consente già cicli annidati, concatenazione di stringhe, ecc. Ed è praticamente certo che altri costrutti verranno aggiunti all'avanzamento del progetto.

So per esperienza che scrivere un lexer / parser a mano, a meno che la grammatica sia banale, sia un processo che richiede tempo e soggetto a errori. Quindi mi restavano due opzioni: un generatore di parser à la yacc o una libreria di combinatori come Parsec. Anche il primo era buono, ma ho scelto quest'ultimo per vari motivi e ho implementato la soluzione in un linguaggio funzionale.

Il risultato è piuttosto spettacolare per i miei occhi, il codice è molto conciso, elegante e leggibile / fluente. Ammetto che potrebbe sembrare un po 'strano se non hai mai programmato qualcosa di diverso da java / c #, ma questo sarebbe vero per tutto ciò che non è stato scritto in java / c #.

Ad un certo punto, tuttavia, sono stato letteralmente attaccato da un collega. Dopo una rapida occhiata al mio schermo, ha dichiarato che il codice è incomprensibile e che non dovrei reinventare l'analisi, ma usare solo uno stack e String.Split come fanno tutti. Ha fatto un sacco di rumore, e non ho potuto convincerlo, in parte perché sono stato colto di sorpresa e non avevo una spiegazione chiara, in parte perché la sua opinione era immutabile (nessun gioco di parole). Mi sono persino offerto di spiegargli la lingua, ma senza risultato.

Sono sicuro che la discussione verrà rivista di fronte alla gestione, quindi sto preparando alcuni argomenti solidi.

Questi sono i primi motivi che mi vengono in mente per evitare una soluzione basata su String.Split:

  • hai bisogno di molti if per gestire casi speciali e le cose rapidamente sfuggono al controllo
  • molti indici di array hardcoded rendono la manutenzione dolorosa
  • estremamente difficile da gestire cose come una chiamata di funzione come argomento del metodo (ad esempio, aggiungi ((aggiungi a, b), c)
  • molto difficile fornire messaggi di errore significativi in caso di errori di sintassi (molto probabile che accada)
  • Sono tutto per semplicità, chiarezza ed evitare inutili ciarlatani intelligenti, ma credo anche che sia un errore smorzare ogni parte del codebase in modo che anche un flipper di hamburger possa capirlo. È lo stesso argomento che sento per non usare le interfacce, non adottare la separazione delle preoccupazioni, copiare il codice di copiatura, ecc. Un minimo di competenza tecnica e volontà di imparare è necessario per lavorare su un progetto software dopo tutto. (Non userò questo argomento perché probabilmente suonerà offensivo e iniziare una guerra non aiuterà nessuno)

Quali sono i tuoi argomenti preferiti contro analizzando il modo Cthulhu ? *

* naturalmente se riesci a convincermi che ha ragione, sarò perfettamente felice anch'io

    
posta smarmy53 17.12.2011 - 08:51
fonte

6 risposte

33

La differenza fondamentale tra i due approcci è che quello che considera l'unico modo corretto è imperativo e il tuo è dichiarativo.

  • Il tuo approccio dichiara esplicitamente le regole, cioè le regole della grammatica sono (quasi) direttamente codificate nel tuo codice, e la libreria parser trasforma automaticamente l'input raw in output analizzato, mentre si prende cura dello stato e di altre cose che sono difficile da gestire. Il tuo codice è scritto all'interno di un singolo livello di astrazione, che coincide con il dominio del problema: analisi. È ragionevole assumere la correttezza di parsec, il che significa che l'unica stanza per l'errore è che la definizione della grammatica è sbagliata. Ma poi hai di nuovo oggetti regola completamente qualificati e sono facilmente testati separatamente. Potrebbe anche valere la pena notare che le librerie parser mature vengono fornite con una funzionalità importante: segnalazione degli errori. Il recupero dell'errore decente quando l'analisi è andato storto non è banale. Come prova, invoco il parse error, unexpected T_PAAMAYIM_NEKUDOTAYIM di PHP: D

  • Il suo approccio manipola le stringhe, mantiene in modo esplicito lo stato e solleva manualmente l'input non elaborato in input analizzati. Devi scrivere tutto da solo, inclusa la segnalazione degli errori. E quando qualcosa va storto, sei completamente perso.

L'ironia consiste nel fatto che la correttezza di un parser scritto con il tuo approccio è dimostrata relativamente facilmente. Nel suo caso, è quasi impossibile.

There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.

C. A. R. Hoare

Il tuo approccio è quello più semplice. Tutto ciò che preclude è per lui allargare un po 'il suo orizzonte. Il risultato del suo approccio sarà sempre contorto, indipendentemente dall'ampiezza del tuo orizzonte.
Per essere onesti, mi sembra che il ragazzo sia solo un pazzo ignorante, che soffre della sindrome da blub , abbastanza arrogante da presumere che tu abbia torto e ti urli contro, se non ti capisce.

Alla fine, comunque, la domanda è: chi dovrà mantenerla? Se sei tu, allora è la tua chiamata, non importa quello che qualcuno dice. Se sarà lui, allora ci sono solo due possibilità: trovare un modo per fargli capire la libreria del parser o scrivere un parser imperativo per lui. Ti suggerisco di generarlo dalla tua struttura parser: D

    
risposta data 17.12.2011 - 11:22
fonte
10

Una grammatica delle espressioni di analisi (come l'approccio del parser Packrat) o il combinatore di parser non reinventano l'analisi. Queste sono tecniche ben consolidate nel mondo della programmazione funzionale e, nelle mani giuste, possono essere più leggibili rispetto alle alternative. Alcuni anni fa ho visto una dimostrazione abbastanza convincente di PEG in C # che sarebbe diventato il mio strumento di prima scelta per grammatiche relativamente semplici.

Se hai una soluzione elegante che utilizza parser combinator o un PEG, dovrebbe essere una vendita relativamente facile: è abbastanza estensibile, di solito relativamente facile da leggere una volta superata la paura della programmazione funzionale ed è a volte più facile da leggere di l'offerta di strumenti tipici del parser generator, anche se dipende molto dalla grammatica e dal livello di esperienza che si ha con entrambi i toolset. È anche abbastanza facile scrivere test per. Certo, ci sono alcune ambiguità grammaticali che possono causare prestazioni di parsing piuttosto orribili negli scenari peggiori (o un sacco di consumo di memoria con Packrat), ma il caso medio è abbastanza decente e in realtà alcune ambiguità grammaticali sono meglio gestite con PEG rispetto a LALR, come Ricordo.

Usare Split e uno stack funziona con grammatiche più semplici di un PEG o può supportare, ma è molto probabile che con il tempo o reinventerai la discesa ricorsiva male, o avrai un set di comportamenti traballante che tu " ll cerotto nella sottomissione al costo di un codice estremamente non strutturato. Se si dispone solo di semplici regole di tokenizzazione, probabilmente non è così male, ma come si aggiunge la complessità, sarà probabilmente la soluzione meno gestibile. Prenderò invece un generatore di parser.

Personalmente, la mia prima inclinazione quando ho bisogno di costruire una DSL sarebbe di usare qualcosa come Boo (.Net) o Groovy (JVM), dato che ottengo tutta la forza di un linguaggio di programmazione esistente e un'incredibile personalizzazione costruendo macro e semplici aggiustamenti alla pipeline del compilatore, senza dover implementare le cose noiose che finirei se avessi iniziato da zero (loop, variabili, modello di oggetti, ecc.). Se fossi in un negozio con sviluppo di Ruby o Lisp, userei solo le espressioni che hanno senso lì (metaprogrammazione, ecc.)

Ma sospetto che il tuo vero problema riguardi la cultura o l'ego. Sei sicuro che il tuo collega non sarebbe andato fuori di testa se avessi usato Antlr o Flex / Bison? Sospetto che "discutere" per la tua soluzione possa essere una battaglia persa; potrebbe essere necessario dedicare più tempo a un approccio più morbido che utilizza le tecniche di costruzione del consenso anziché rivolgersi all'autorità di gestione locale. Associando la programmazione e dimostrando la velocità con cui è possibile modificare le regolazioni grammaticali senza sacrificare la manutenibilità, e facendo una borsa marrone per spiegare la tecnica, la sua storia e così via, possono andare oltre 10 punti elenco e una "Rude Q & A" in qualche incontro conflittuale.

    
risposta data 17.12.2011 - 11:22
fonte
9

Non sono esperto nell'analizzare algoritmi e simili, ma penso che la prova del budino sia nel mangiare. Quindi se tutto il resto fallisce, potresti offrirgli di implementare il parser a modo suo. Poi

  • confronta il tempo investito in entrambe le soluzioni,
  • esegui entrambe le soluzioni attraverso un test di accettazione completo per vedere quale ha meno bug e
  • avere un giudice indipendente confronta il codice risultante in dimensioni e chiarezza con il tuo.

Affinché il test sia davvero equo, è possibile che entrambe le soluzioni implementino la stessa API e utilizzi un banco di prova comune (o un framework di test delle unità conosciuto da entrambi). Ognuno di voi potrebbe scrivere qualsiasi numero e tipo di casi di test funzionali e assicurarsi che la propria soluzione li superi tutti. E, naturalmente, idealmente nessuno di voi dovrebbe avere accesso alla realizzazione dell'altro prima della scadenza. Il test decisivo sarebbe quindi quello di testare trasversalmente entrambe le soluzioni utilizzando la suite di test sviluppata dallo sviluppatore altro .

    
risposta data 17.12.2011 - 10:19
fonte
7

L'hai chiesto come se avessi una domanda tecnica, ma come probabilmente già sapevi, non c'è nessuna domanda tecnica qui. Il tuo approccio è di gran lunga superiore all'hacking di qualcosa a livello di personaggio.

Il vero problema è che il tuo (presumibilmente più esperto) collega è insicuro e si sente minacciato dalle tue conoscenze. Non lo persuaderai con argomenti tecnici ; questo lo renderà più difensivo. Invece dovrai trovare un modo per alleviare le sue paure. Non posso offrire molti suggerimenti, ma potresti provare a mostrare grande considerazione per la sua conoscenza del codice legacy.

Infine, se il tuo manager è d'accordo con le sue speciose argomentazioni tecniche e scarta la tua soluzione, allora penso che dovrai cercare un'altra posizione. Chiaramente saresti più prezioso e più apprezzato in un'organizzazione più sofisticata.

    
risposta data 18.12.2011 - 04:58
fonte
4

Sarò breve:

Analizzare la via di Cthulhu è difficile. Questa è l'argomentazione più semplice e convincente contro di essa.

Può fare il trucco per le lingue semplici; dì, lingue regolari. Probabilmente però non sarà più facile di un'espressione regolare.

Può anche fare il trucco per linguaggi un po 'più complessi.

Tuttavia, mi piacerebbe vedere un parser Cthulhu per qualsiasi lingua con annidamento, o semplicemente "significativo stato" - espressioni matematiche, o il tuo esempio (chiamate di funzioni annidate).

Immagina cosa succederebbe se qualcuno provasse a cthulhu un parser per un tale linguaggio (non banale e privo di contesto). Ammesso che sia abbastanza intelligente da scrivere un parser corretto, scommetterei che durante la codifica avrebbe "scoperto" prima tokenizaton e poi l'analisi ricorsiva della discesa - in qualche modo.

Dopodiché, la cosa è semplice: "Guarda, hai scritto qualcosa che si chiama parser di discesa ricorsivo! Sai che può essere generato automaticamente da una semplice descrizione grammaticale, proprio come le espressioni regolari?

Per farla breve:
L'unica cosa che può impedire a qualcuno di usare l'approccio civile è la loro ignoranza.

    
risposta data 09.06.2012 - 12:22
fonte
1

Forse anche lavorare su una buona semantica DSL è importante (la sintassi conta, ma anche la semantica). Se non hai familiarità con questi problemi, ti suggerirei di leggere alcuni libri, come Pragmatica dei linguaggi di programmazione (di M. Scott) e Christian Queinnec. Lisp in piccoli pezzi . Cambridge University Press, 1996.

Leggendo i lavori recenti nelle conferenze DSL, ad es. Anche DSL2011 dovrebbe essere d'aiuto.

Progettazione e amp; implementare un linguaggio specifico di dominio è difficile (e la maggior parte della difficoltà è l'analisi non !).

Non capisco cosa intendi per analizzare la via Cthulhu ; Immagino che tu voglia solo analizzare in un modo bizzarro.

    
risposta data 17.12.2011 - 22:22
fonte

Leggi altre domande sui tag