Il top-down è un ottimo modo per descrivere cose che sai o per ricostruire cose che hai già costruito.
Il più grande problema dall'alto verso il basso è che abbastanza spesso semplicemente non esiste un "top". Cambierai idea di cosa dovrebbe fare il sistema durante lo sviluppo del sistema e durante l'esplorazione del dominio. Come può essere il tuo punto di partenza qualcosa che non conosci (ovvero cosa vuoi che faccia il sistema)?
Un top down "locale" è una buona cosa ... pensare in anticipo sulla programmazione è chiaramente buono. Ma pensare e pianificare troppo non lo è, perché quello che stai immaginando non è il vero scenario (a meno che tu non sia già stato lì prima, cioè se non stai costruendo, ma ricostruendo). Il top-down globale quando si costruiscono cose nuove è semplicemente una sciocchezza.
Il bottom-up dovrebbe essere (a livello globale) l'approccio, a meno che non si conosca il 100% del problema, è necessario solo la soluzione nota da codificare e non ti interessa cercare possibili soluzioni alternative.
L'approccio di Lisp è il distillato dal basso verso l'alto. Non solo costruisci dal basso verso l'alto, ma puoi anche modellare i mattoni nel modo in cui ne hai bisogno. Niente è fisso, la libertà è totale. Naturalmente la libertà si assume la responsabilità e puoi fare cose orribili abusando di questo potere.
Ma un codice orribile può essere scritto in qualsiasi lingua. Anche in linguaggi modellati come gabbie per la mente, progettati con la speranza che con quelle lingue anche le scimmie potessero mettere in moto programmi validi (un'idea così sbagliata su così tanti livelli che fa male anche solo a pensarci).
Il tuo esempio riguarda un server web. Ora nel 2012 questo è un problema ben definito, hai delle specifiche da seguire. Un web server è solo un problema di implementazione. Soprattutto se stai mirando a scrivere un server web sostanzialmente identico agli altri gajillion di server web che sono là fuori, nulla è davvero poco chiaro, tranne alcune minuzie. Anche il tuo commento su RSA parla ancora di un problema chiaramente definito, con specifiche formali.
Con un problema ben definito, con specifiche formali e soluzioni già note, la codifica si collega semplicemente nei punti. In alto va bene per quello. Questo è il paradiso del project manager.
In molti casi, tuttavia, non esiste un approccio ben noto per collegare i punti. In realtà molto spesso è difficile dire anche quali siano i punti.
Supponiamo, ad esempio, che ti venga chiesto di indicare a una macchina da taglio automatica di allineare le parti da tagliare a un materiale stampato che non è perfettamente conforme al teorico logo ripetitivo. Vengono fornite le parti e le immagini del materiale prese dalla macchina.
Che cos'è una regola di allineamento? Tu decidi. Cos'è uno schema, come rappresentarlo? Tu decidi. Come allineare le parti? Tu decidi. Le parti possono essere "piegate"? Dipende, alcuni no e alcuni sì, ma ovviamente non troppo. Cosa fare se il materiale è troppo deformato per una parte per tagliarlo in modo accettabile? Tu decidi. Tutti i rotoli di materiale sono identici? Certo che no, ma non puoi bug all'utente di adattare le regole di allineamento per ogni lancio ... sarebbe impraticabile. Quali immagini vedono le telecamere? Il materiale, qualunque cosa possa significare ... può essere colore, può essere nero su nero dove solo il riflesso della luce rende evidente il motivo. Cosa significa riconoscere un modello? Tu decidi.
Ora prova a progettare la struttura generale di una soluzione per questo problema e dai un preventivo, in termini di tempo e denaro. La mia scommessa è che anche l'architettura del tuo sistema ... (sì, l'architettura) sarà sbagliata. La stima dei costi e dei tempi sarà costituita da numeri casuali.
Lo abbiamo implementato e ora è un sistema funzionante, ma abbiamo cambiato idea sulla stessa forma del sistema un gran numero di volte. Abbiamo aggiunto interi sottosistemi che ora non possono nemmeno essere raggiunti dai menu. Abbiamo cambiato i ruoli master / slave nei protocolli più di una volta. Probabilmente ora abbiamo abbastanza conoscenze per tentare di ricostruirla meglio.
Ovviamente altre aziende hanno risolto lo stesso problema ... ma a meno che tu non sia in una di queste società molto probabilmente il tuo progetto dettagliato top-down sarà uno scherzo. Possiamo progettarlo dall'alto verso il basso. Non puoi perché non l'hai mai fatto prima.
Probabilmente puoi risolvere anche lo stesso problema. Lavorando dal basso verso l'alto comunque. A partire da ciò che sai, imparando ciò che non sai e sommando.
Vengono sviluppati nuovi sistemi software complessi, non progettati. Di tanto in tanto qualcuno inizia a progettare da zero un nuovo grande sistema software mal specificato. oppure c] entrambi ... e molto spesso [c] è il caso).
Questi sono i tipici progetti di grandi aziende con migliaia e migliaia di ore gettati nelle diapositive powerpoint e nei soli diagrammi UML. Invariabilmente falliscono completamente dopo aver bruciato quantità imbarazzanti di risorse ... o in alcuni casi eccezionali, alla fine forniscono un software troppo costoso che implementa solo una piccola parte delle specifiche iniziali. E quel software invariabilmente è profondamente odiato dagli utenti ... non il tipo di software che compreresti, ma il tipo di software che usi perché sei costretto a farlo.
Questo significa che penso che dovresti pensare solo al codice? Ovviamente no. Ma secondo me la costruzione dovrebbe iniziare dal basso (mattoni, codice concreto) e dovrebbe aumentare ... e la tua attenzione e attenzione ai dettagli dovrebbero in un certo senso "svanire" man mano che ti allontani da ciò che hai. Il top-down è spesso presentato come se dovessi mettere lo stesso livello di dettaglio all'intero sistema in una sola volta: tienilo sempre diviso ogni nodo fino a quando tutto è ovvio ... nei moduli di realtà, il sottosistema viene "cresciuto" dalle subroutine. Se non si ha una precedente esperienza nel problema specifico, la progettazione dall'alto in basso di un sottosistema, modulo o libreria sarà orribile. Puoi progettare una buona libreria una volta che sai quali funzioni inserire, non viceversa.
Molte delle idee di Lisp stanno diventando più popolari (funzioni di prima classe, chiusure, tipizzazione dinamica di default, garbage collection, metaprogrammazione, sviluppo interattivo) ma Lisp è ancora oggi (tra le lingue che conosco) abbastanza unico in quanto è facile modellare il codice per quello che ti serve.
I parametri delle parole chiave, ad esempio, sono già presenti, ma se non fossero presenti potrebbero essere aggiunti. L'ho fatto (inclusa la verifica delle parole chiave al momento della compilazione) per un compilatore Lisp giocattolo con cui sto sperimentando e non richiede molto codice.
Con C ++ invece il massimo che puoi ottenere è un gruppo di esperti C ++ che ti dicono che i parametri delle parole chiave non sono così utili, o un'implementazione del modello incredibilmente complessa, spezzata e con metà backup che in effetti non è così utile. Le classi C ++ sono oggetti di prima classe? No e non c'è niente che tu possa fare al riguardo. Puoi avere introspezione in fase di esecuzione o in fase di compilazione? No e non c'è niente che tu possa fare al riguardo.
Questa flessibilità linguistica di Lisp è ciò che la rende eccezionale per l'edilizia dal basso. Puoi creare non solo subroutine, ma anche la sintassi e la semantica della lingua. E in un certo senso Lisp stesso è dal basso verso l'alto.