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 può diventare abbastanza importante per l'azienda. Il linguaggio è semplice ma non banale, consente già loop nidificati, concatenazione di stringhe, ecc. Ed è praticamente sicuro che altri costrutti verranno aggiunti man mano che il progetto avanza.

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

Il risultato è abbastanza 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 qualsiasi cosa non scritta 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 avrei dovuto reinventare l'analisi ma usare solo uno stack e una stringa. Spaccare come fanno tutti. Ha fatto molto rumore e non sono riuscito a convincerlo, in parte perché sono stato colto di sorpresa e non ho avuto spiegazioni chiare, in parte perché la sua opinione era immutabile (nessun gioco di parole). Mi sono persino offerto di spiegargli la lingua, ma senza risultati.

Sono sicuro che la discussione tornerà in superficie davanti al management, quindi sto preparando alcuni argomenti concreti.

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

  • hai bisogno di molti ifs per gestire casi speciali e le cose vanno rapidamente fuori controllo
  • molti indici array codificati rendono la manutenzione dolorosa
  • estremamente difficile gestire cose come una chiamata di funzione come argomento del metodo (es. add ((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 cose criptiche, ma credo anche che sia un errore smorzare ogni parte della base di codice in modo che anche una pinna da hamburger possa capirla. È lo stesso argomento che sento per non usare le interfacce, non adottare la separazione delle preoccupazioni, copiare e incollare il codice, ecc. Dopo tutto, è necessario un minimo di competenza tecnica e volontà di apprendere per lavorare su un progetto software. (Non userò questo argomento perché probabilmente suonerà offensivo, e iniziare una guerra non aiuterà nessuno)

Quali sono i tuoi argomenti preferiti contro l' analisi del modo Cthulhu ? *

* ovviamente se riesci a convincermi che ha ragione, sarò anche perfettamente felice


9
Mi sembra che il tuo collega si offra volontario per realizzare il progetto DSL per te!
GrandmasterB,

23
"Non dovrei reinventare l'analisi ma usare solo uno stack e String. Spaccare come fanno tutti" - accidenti, quel ragazzo dovrebbe essere contento che l'ignoranza non faccia male ...
Michael Borgwardt,

4
Consiglia al tuo collega di non tornare a questa discussione a meno che non abbia letto l'intero Libro del Drago e superato un test. Altrimenti non ha il diritto di discutere di qualsiasi argomento relativo all'analisi.
SK-logic,

4
scusa, chi stava reinventando l'analisi?
rwong,

2
Penso che la mia testa esploderà letteralmente la prossima volta che vedrò qualcuno che usa la parola "letteralmente" in senso figurato.

Risposte:


33

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

  • Il tuo approccio dichiara esplicitamente le regole, ovvero le regole della grammatica sono (quasi) direttamente codificate nel tuo codice e la libreria del parser trasforma automaticamente l'input non elaborato in output analizzato, mentre si prende cura dello stato e di altre cose che sono difficili da gestire. Il codice è scritto all'interno di un singolo livello di astrazione, che coincide con il dominio problematico: analisi. È ragionevole supporre la correttezza di parsec, il che significa che l'unica stanza per l'errore qui è che la tua definizione grammaticale è sbagliata. Ma poi hai oggetti delle regole pienamente qualificati e possono essere facilmente testati in modo isolato. Inoltre, vale la pena notare che le librerie di parser mature hanno una caratteristica importante: la segnalazione degli errori. Il recupero di errori decenti quando l'analisi è andata storta non è banale. Come prova, invoco PHP parse error, unexpected T_PAAMAYIM_NEKUDOTAYIM: D

  • Il suo approccio manipola le stringhe, mantiene esplicitamente lo stato e solleva manualmente l'input non elaborato in input analizzato. Devi scrivere tutto da solo, inclusa la segnalazione degli errori. E quando qualcosa va storto, sei totalmente 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.

Esistono due modi per costruire un progetto software: un modo è renderlo così semplice che non ci siano ovviamente carenze e l'altro è renderlo così complicato che non ci sono carenze evidenti. Il primo metodo è molto più difficile.

CAR Hoare

Il tuo approccio è quello più semplice. Tutto ciò che gli impedisce è di allargare un po 'il suo orizzonte. Il risultato del suo approccio sarà sempre contorto, non importa quanto ampio sia il tuo orizzonte.
Ad essere sincero, mi sembra che il ragazzo sia solo un idiota ignorante, che soffre di sindrome blub , abbastanza arrogante da presumere che ti sbagli e urlare contro di te, se non ti capisce.

Alla fine, tuttavia, la domanda è: chi dovrà mantenerlo? 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 struttura del tuo parser: D


Ottima spiegazione della differenza tra i due approcci.
smarmy53,

6
Apparentemente ti sei collegato a TVTropes per programmatori. Arrivederci pomeriggio ...
Izkata,

10

Una grammatica di espressione di analisi (come l'approccio parser di Packrat) o un combinatore di parser non sta reinventando l'analisi. Queste sono tecniche ben consolidate nel mondo della programmazione funzionale e, nelle mani giuste, possono essere più leggibili delle alternative. Ho visto una dimostrazione abbastanza convincente di PEG in C # alcuni anni fa che lo renderebbe il mio strumento di primo ricorso per grammatiche relativamente semplici.

Se hai una soluzione elegante che usa combinatori di parser 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 è talvolta più facile da leggere rispetto al tipico generatore di parser offrono strumenti, anche se ciò dipende molto dalla grammatica e dal livello di esperienza che hai con entrambi i set di strumenti. È anche abbastanza facile scrivere test per. Naturalmente, ci sono alcune ambiguità grammaticali che possono portare a prestazioni di analisi piuttosto terribili 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, poiché Richiamo.

L'uso di Split e uno stack funziona con alcune grammatiche più semplici di un PEG o può supportare, ma è molto probabile che col tempo reinventerai male la discesa ricorsiva, o avrai un insieme sfacciato di comportamenti che bandirai- aiuti alla presentazione a scapito di un codice estremamente non strutturato. Se hai solo semplici regole di tokenizzazione, probabilmente non è poi così male, ma quando aggiungi complessità, sarà probabilmente la soluzione meno gestibile. Invece, prenderei un generatore di parser.

Personalmente, la mia prima inclinazione quando ho bisogno di costruire un DSL sarebbe 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 partissi da zero (loop, variabili, modello a oggetti, ecc.). Se fossi in un negozio a fare lo sviluppo di Ruby o Lisp, userei semplicemente gli idiomi 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 impazzito 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 tecniche di costruzione del consenso piuttosto che fare appello all'autorità di gestione locale. Associare la programmazione e dimostrare la rapidità con cui è possibile apportare modifiche alla grammatica senza sacrificare la manutenibilità, e fare un brownbag per spiegare la tecnica, la sua storia e così via, può andare oltre 10 punti elenco e un "scortese domande e risposte" in alcuni incontro conflittuale.


9

Non sono esperto di analisi di 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

  • confrontare il tempo investito in entrambe le soluzioni,
  • eseguire entrambe le soluzioni attraverso un test di accettazione completo per vedere quale ha meno bug e
  • chiedi a un giudice indipendente di confrontare il codice risultante in termini di dimensioni e chiarezza con il tuo.

Affinché i test siano davvero corretti, è possibile che entrambe le soluzioni implementino la stessa API e utilizzino un banco di prova comune (o un framework di unit test conosciuto da entrambi). Entrambi potete scrivere qualsiasi numero e tipo di casi di test funzionali e assicurarvi che la sua soluzione li superi tutti. E naturalmente, idealmente nessuno dei due dovrebbe avere accesso all'implementazione dell'altro prima della scadenza. Il test decisivo sarebbe quindi quello di eseguire il cross-test di entrambe le soluzioni utilizzando la suite di test sviluppata dall'altro sviluppatore.


Questa è una grande idea! Sarebbe facile usare anche un framework di test delle unità commont.
smarmy53,

1
+1 per fare in modo che il collega esegua la versione divisa ... L'OP è stato incaricato di crearlo, quindi è lui quello che molto probabilmente dovrà supportarlo, non il collega. Solo suggerirlo a lui in cima al suo altro lavoro potrebbe essere abbastanza per toglierlo di schiena.
Izkata,

7

Lo hai fatto come se avessi una domanda tecnica, ma come probabilmente già sapevi, qui non ci sono domande tecniche. Il tuo approccio è di gran lunga superiore all'hacking di qualcosa a livello di personaggio.

Il vero problema è che il tuo collega (presumibilmente più esperto) è insicuro e si sente minacciato dalle tue conoscenze. Non lo convincerai 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 rispetto per la sua conoscenza del codice legacy.

Infine, se il tuo manager è d'accordo con i suoi argomenti tecnici speciosi 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.


Hai ragione, sapevo già che il mio approccio è superiore, tuttavia non sono riuscito a tirar fuori una spiegazione valida e convincente, ovvero le informazioni tecniche che sto cercando. Concordare il lato "interazione umana" del problema è importante quanto quello tecnico (se non di più).
smarmy53

4

Sarò breve:

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

Può fare il trucco per le lingue semplici; diciamo, lingue regolari. Tuttavia, probabilmente 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 "significativamente stateful" - espressioni matematiche o il tuo esempio (chiamate di funzione nidificate).

Immagina cosa accadrebbe se qualcuno provasse a cthulhu un parser per tale linguaggio (non banale senza contesto). Purché sia ​​abbastanza intelligente da scrivere un parser corretto, scommetterei che durante la programmazione avrebbe "scoperto" prima il tokenizaton e poi l'analisi della discesa ricorsiva - in qualche modo.

Dopodiché, la cosa è semplice: "Ehi guarda, hai scritto qualcosa che si chiama parser ricorsivo di discesa! 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 civilizzato è la sua ignoranza.


1

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

Anche la lettura di articoli recenti nelle conferenze DSL, ad esempio DSL2011, dovrebbe aiutare.

Progettare e implementare un linguaggio specifico di dominio è difficile (e la maggior parte delle difficoltà non è l' analisi!).

Non capisco davvero cosa intendi analizzando la via di Cthulhu ; Immagino che intendi solo analizzare in qualche modo bizzarro.


Buoni collegamenti. Per quanto riguarda Cthulhu, scusa, ho dimenticato il link. È un riferimento a un classico articolo di codinghorror : codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html . Ho aggiornato il post originale.
smarmy53
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.