Nach meinem Verständnis besteht Top-Down-Design darin, das abstrakte Konzept auf hoher Ebene in kleinere konkrete und nachvollziehbare Teile zu zerlegen, bis der kleinste Baustein definiert ist. Andererseits definiert Bottom-Up Teile mit niedriger Ebene und baut dann nach und nach Blöcke mit höherer Ebene auf, bis das gesamte System gebildet ist.
In der Praxis empfiehlt es sich, die beiden Methoden zu kombinieren: Beginnt mit einer Spezifikation auf hoher Ebene, um das Domänenwissen, seine Beziehung und Einschränkungen vollständig zu spezifizieren. Sobald das Problem verstanden ist, werden kleinste Bausteine erstellt, um das System aufzubauen.
Der Prozess von:
- Anforderungsspezifikation erstellen
- Erstellen Sie eine Designspezifikation (mit Diagrammen)
- Implementieren
- Liefern
- Wiederholen (bei der iterativen Entwicklung wird nicht in jeder Phase ein ganzer Abschnitt ausgeführt, sondern es wird jeweils ein kleiner Teil wiederholt, und es wird eine tägliche Besprechung abgehalten, um sich an die dynamischen Anforderungen des Kunden anzupassen.)
sieht für mich völlig normal aus (mit spezifikationen als pläne). Es hat seine Fehler, aber deshalb haben wir eine iterative Entwicklung erhalten: Anstatt Zeit für eine Phase zu investieren, sagt die Anforderungsanalyse, um alle möglichen Dinge des Domänenwissens zu untersuchen, die Änderungen unterliegen (möglicherweise täglich), machen wir ein bisschen Analyse. ein bisschen designen und dann umsetzen.
Eine andere Möglichkeit ist, dass jede Iteration eine Art Mini-Wasserfall ist, bei dem die Analyse in wenigen Tagen (oder einer Woche) durchgeführt wird. Gleiches gilt für das Design. Der Rest der Zeit wird für die Implementierung aufgewendet. Stimmt etwas mit dem Top-Down-Ansatz in Kombination mit der iterativen Entwicklung nicht?
In seinem Aufsatz Programming Bottom Up scheint Paul Graham zu ermutigen, von unten nach oben zu bauen oder von unten nach oben zu programmieren, jedoch nicht in der Anforderungsanalyse / Entwurfsphase:
Erfahrene Lisp-Programmierer teilen ihre Programme unterschiedlich auf. Neben dem Top-Down-Design folgen sie einem Prinzip, das als Bottom-Up-Design bezeichnet werden kann. Dabei wird die Sprache entsprechend dem Problem geändert.
Was er damit meinte, ist, dass Lisper immer noch Top-Down-Design ausführt, aber das Programm von unten nach oben, stimmt das? Ein weiterer Punkt, den er schrieb:
Hervorzuheben ist, dass Bottom-up-Design nicht bedeutet, dass dasselbe Programm in einer anderen Reihenfolge geschrieben wird. Wenn Sie von unten nach oben arbeiten, haben Sie normalerweise ein anderes Programm. Anstelle eines einzelnen monolithischen Programms erhalten Sie eine größere Sprache mit abstrakteren Operatoren und ein kleineres darin geschriebenes Programm. Anstelle eines Sturzes erhalten Sie einen Bogen.
Bedeutet dies, dass Sie während des Schreibens eines Programms in Lisp ein generisches Tool haben?
Antworten:
Top-down ist eine großartige Möglichkeit, um Dinge zu beschreiben, die Sie kennen, oder um Dinge, die Sie bereits erstellt haben, neu zu erstellen.
Das größte Problem von oben nach unten ist, dass es oft einfach kein "oben" gibt. Sie werden Ihre Meinung darüber ändern, was das System tun soll, während Sie das System entwickeln und die Domäne erkunden. Wie kann Ihr Ausgangspunkt etwas sein, das Sie nicht kennen (dh was das System tun soll)?
Ein "lokales" Top-Down ist eine gute Sache ... einige Überlegungen vor dem Codieren sind eindeutig gut. Aber zu viel zu denken und zu planen ist nicht so, denn was Sie sich vorstellen, ist nicht das reale Szenario (es sei denn, Sie waren bereits vorher dort, dh wenn Sie nicht bauen, sondern umbauen). Globales Top-Down beim Bauen neuer Dinge ist einfach Unsinn.
Bottom-up sollte (global) der Ansatz sein, es sei denn, Sie kennen 100% des Problems, Sie müssen nur die bekannte Lösung codieren und es interessiert Sie nicht, nach möglichen alternativen Lösungen zu suchen.
Lisp-Ansatz ist das destillierte Bottom-up. Sie bauen nicht nur von unten nach oben, sondern können die Steine auch so formen, wie Sie es möchten. Nichts ist festgelegt, Freiheit ist total. Natürlich übernimmt Freiheit Verantwortung und Sie können schreckliche Dinge tun, indem Sie diese Macht missbrauchen.
Aber schrecklicher Code kann in jeder Sprache geschrieben werden. Selbst in Sprachen, die wie Käfige für den Verstand geformt sind, mit der Hoffnung entworfen, dass mit diesen Sprachen sogar Affen gute Programme zum Laufen bringen könnten (eine Idee, die auf so vielen Ebenen so falsch ist, dass es weh tut, wenn man nur daran denkt).
In Ihrem Beispiel geht es um einen Webserver. Nun, im Jahr 2012 ist dies ein genau definiertes Problem. Sie müssen die Spezifikationen befolgen. Ein Webserver ist nur ein Implementierungsproblem. Vor allem, wenn Sie einen Webserver schreiben möchten, der im Wesentlichen mit den meisten anderen Webservern identisch ist, ist nichts wirklich unklar, außer ein paar Details. Selbst in Ihrem Kommentar zu RSA geht es immer noch um ein klar definiertes Problem mit formalen Spezifikationen.
Bei einem genau definierten Problem, mit formalen Spezifikationen und bereits bekannten Lösungen ist die Codierung nur eine Verbindung in den Punkten. Top down ist dafür ok. Dies ist der Himmel für Projektmanager.
In vielen Fällen gibt es jedoch keinen bekannten Ansatz, um die Punkte zu verbinden. Eigentlich ist sehr oft schwer zu sagen, was die Punkte sind.
Angenommen, Sie werden aufgefordert, eine automatische Schneidemaschine anzuweisen, die zu schneidenden Teile auf ein Druckmaterial auszurichten, das nicht perfekt mit dem sich wiederholenden theoretischen Logo übereinstimmt. Sie erhalten die Teile und Bilder des Materials, wie sie von der Maschine aufgenommen wurden.
Was ist eine Ausrichtungsregel? Du entscheidest. Was ist ein Muster, wie kann es dargestellt werden? Du entscheidest. Wie werden die Teile ausgerichtet? Du entscheidest. Können Teile "gebogen" werden? Es kommt darauf an, manche nicht und manche ja, aber natürlich nicht zu viel. Was tun, wenn das Material einfach zu deformiert ist, als dass ein Teil es akzeptabel schneiden könnte? Du entscheidest. Sind alle Materialrollen identisch? Natürlich nicht, aber Sie können den Benutzer nicht daran hindern, Ausrichtungsregeln für jede Rolle anzupassen ... das wäre unpraktisch. Welche Bilder sehen die Kameras? Das Material, was auch immer das bedeuten mag ... es kann Farbe sein, es kann schwarz über schwarz sein, wo nur der Lichtreflex das Muster sichtbar macht. Was bedeutet es , ein Muster zu erkennen? Du entscheidest.
Versuchen Sie nun, die allgemeine Struktur einer Lösung für dieses Problem zu entwerfen und ein Angebot in Geld und Zeit abzugeben. Ich wette, dass sogar Ihre Systemarchitektur (ja, die Architektur) falsch sein wird. Kosten- und Zeitschätzung sind Zufallszahlen.
Wir haben es implementiert und jetzt ist es ein funktionierendes System, aber wir haben uns sehr oft über die Form des Systems Gedanken gemacht. Wir haben ganze Subsysteme hinzugefügt, die jetzt nicht einmal über die Menüs erreichbar sind. Wir haben die Master / Slave-Rollen in Protokollen mehr als einmal gewechselt. Wahrscheinlich haben wir jetzt genug Wissen, um versuchen zu können, es besser wieder aufzubauen.
Andere Unternehmen haben natürlich das gleiche Problem gelöst ... aber wenn Sie nicht zu einem dieser Unternehmen gehören, wird Ihr detailliertes Top-Down-Projekt höchstwahrscheinlich ein Witz sein. Wir können es von oben nach unten gestalten. Das kannst du nicht, weil du es noch nie getan hast.
Sie können wahrscheinlich das gleiche Problem auch lösen. Von unten nach oben arbeiten. Angefangen mit dem, was Sie wissen, über das, was Sie nicht wissen, bis hin zur Summe.
Neue komplexe Softwaresysteme werden angebaut, nicht entworfen. Von Zeit zu Zeit beginnt jemand damit, ein großes neues komplexes falsch spezifiziertes Softwaresystem von Grund auf neu zu entwerfen (beachten Sie, dass es bei einem großen komplexen Softwareprojekt nur drei Möglichkeiten gibt: a) Die Spezifikation ist unscharf, b) Die Spezifikation ist falsch und widerspricht sich von selbst oder c] beides ... und am häufigsten ist [c] der Fall).
Dies sind die typischen Großunternehmensprojekte, bei denen Tausende und Abertausende von Stunden allein in PowerPoint-Folien und UML-Diagrammen investiert werden. Sie versagen ausnahmslos vollständig, nachdem sie peinliche Mengen an Ressourcen verbrannt haben ... oder in ganz besonderen Ausnahmefällen liefern sie schließlich eine überteuerte Software, die nur einen winzigen Teil der anfänglichen Spezifikationen implementiert. Und diese Software wird von den Benutzern ausnahmslos sehr gehasst ... nicht die Art von Software, die Sie kaufen würden, sondern die Art von Software, die Sie verwenden, weil Sie dazu gezwungen werden.
Bedeutet das, dass ich denke, dass Sie nur an Code denken sollten? Natürlich nicht. Aber meiner Meinung nach sollte die Konstruktion von unten beginnen (Ziegel, Betoncode) und nach oben gehen ... und Ihre Aufmerksamkeit und Liebe zum Detail sollte in gewisser Weise "verblassen", wenn Sie weiter von dem entfernt sind, was Sie haben. Top-down wird häufig so dargestellt, als müsste das gesamte System auf einmal auf die gleiche Detailebene gebracht werden: Teilen Sie einfach jeden Knoten so lange auf, bis alles offensichtlich ist. In Realitätsmodulen werden Subsysteme aus Subroutinen "gewachsen". Wenn Sie noch keine Erfahrung mit dem spezifischen Problem haben, ist Ihr Top-Down-Design eines Subsystems, Moduls oder einer Bibliothek schrecklich. Sie können eine gute Bibliothek entwerfen, wenn Sie wissen, welche Funktionen eingefügt werden müssen, und nicht umgekehrt.
Viele der Lisp-Ideen werden immer beliebter (erstklassige Funktionen, Abschlüsse, dynamisches Tippen als Standard, Garbage Collection, Metaprogrammierung, interaktive Entwicklung), aber Lisp ist (unter den mir bekannten Sprachen) immer noch einzigartig, wie einfach es ist, Code zu formen für was du brauchst.
Schlüsselwortparameter zum Beispiel sind bereits vorhanden, aber wenn sie nicht vorhanden sind, können sie hinzugefügt werden. Ich habe es (einschließlich der Schlüsselwortüberprüfung zur Kompilierungszeit) für einen Spielzeug-Lisp-Compiler gemacht, mit dem ich experimentiere, und es erfordert nicht viel Code.
Mit C ++ erhalten Sie stattdessen nur eine Reihe von C ++ - Experten, die Ihnen mitteilen, dass Schlüsselwortparameter nicht so nützlich sind, oder eine unglaublich komplexe, fehlerhafte, halb-unterstützte Template-Implementierung, die in der Tat nicht so nützlich ist. Sind C ++ Klassen erstklassige Objekte? Nein, und Sie können nichts dagegen tun. Können Sie zur Laufzeit oder zur Kompilierungszeit eine Introspektion durchführen? Nein, und Sie können nichts dagegen tun.
Diese Sprachflexibilität von Lisp macht es großartig für das Bottom-up-Bauen. Sie können nicht nur Unterprogramme erstellen, sondern auch die Syntax und die Semantik der Sprache. Und in gewisser Hinsicht ist Lisp selbst von unten nach oben.
quelle
Ich bin mir nicht sicher, wie diese Antwort auf Lisp zutreffen würde, aber ich habe gerade das Lesen von Agile Principles, Patterns and Practices abgeschlossen , und der Autor, Onkel Bob , plädiert nachdrücklich für einen Top-Down-Ansatz für C # (auch für C ++), mit dem ich voll und ganz zufrieden bin zustimmen.
Im Gegensatz zu einigen anderen Antworten, die den Schluss gezogen haben, dass Top-Down-Ansatz bedeutet, dass Sie in der ersten Interaktion nur Dokumente und Gesamtdesign liefern, verweist das Buch auf eine andere Methode: TDD kombiniert mit evolutionärem Design.
Die Idee ist, dass Sie von oben beginnen und Ihre höchsten Abstraktionsebenen (oder lokalen höchsten) definieren. Sobald sie definiert sind, lassen Sie sie nützliche Arbeit leisten, sodass die Funktion Nr. 1 sofort funktioniert. Wenn Sie dann mehr und mehr Funktionen hinzufügen, überarbeiten Sie Ihren Code und entwickeln das Design nach Bedarf, wobei Sie sich stets der SOLID-Prinzipien bewusst sind. Auf diese Weise erhalten Sie nicht zu viele Abstraktionsebenen, und Sie erhalten auch kein Low-Level-Design, das nicht zur Gesamtarchitektur passt. Wenn Sie sich nicht sicher sind, was dies bedeutet, enthält das oben erwähnte Buch ein ganzes Kapitel mit einem Beispiel, in dem Entwickler Konzepte verwenden und mit UML-Diagrammen und Klassen auf niedriger Ebene beginnen. Nur um zu realisieren, dass die Hälfte dieser Klassen nicht benötigt wird, sobald die Codierung tatsächlich beginnt. Im Wesentlichen wird bei diesem Ansatz Code auf niedriger Ebene natürlich unterdrückt, da im Projekt mehr Details auf höherer Ebene definiert werden.
Und schließlich sollten Sie beim Üben von SOLID nicht in eine Situation geraten, in der Sie übergeordnete Abstraktionen definiert haben und dann auf Details eingehen und plötzlich feststellen, dass es keine OOD oder Abstraktionen gibt. Das liegt nicht wirklich am Top-Down-Design, sondern am faulen Engineering.
Wenn Sie mehr über XP und evolutionäres Design erfahren möchten, lesen Sie hier eine gute Lektüre von Martin Fowler, einem weiteren großartigen Autor: "Is Design Dead?"
quelle
Für mich sind die wichtigsten Bemerkungen, die Paul Graham in seinem Artikel macht, folgende:
Oder, wie es in C ++ - Kreisen heißt: Bibliotheksdesign ist Sprachdesign (Bjarne Stroustrup)
Die Grundidee des Top-Down-Designs lautet: Zuerst planen Sie, dann codieren Sie. Beanow hat Recht, wenn er schreibt , dass es Probleme gibt, wenn ausführbarer Code zu spät kommt. Im Bottom-Up-Design haben Sie immer Code und diesen Code, der getestet werden kann.
Außerdem ist Ihr Code nicht flach. Damit meine ich, dass es tendenziell mehr Ebenen mit kleineren Abstraktionen gibt. Beim Top-Down-Design kommt es häufig zu großen Abstrationen bis zu einer willkürlichen Ebene und darunter zu keinerlei Abstraktionen. Von unten nach oben entwickelter Code OTOH enthält häufig weniger Kontroll- und Datenstrukturen auf niedriger Ebene, da diese wahrscheinlich entfernt werden.
quelle
Wenn Sie ein Programm in einer beliebigen Sprache schreiben, nicht nur in Lisp, können Sie im Idealfall eine ganze Reihe allgemeiner Tools schreiben, mit denen Sie Ihr nächstes Programm beschleunigen oder die Geschwindigkeit Ihres aktuellen Programms verbessern können.
In der Praxis kann es schwierig sein, die Übersicht über diese Tools zu behalten. Die Dokumentation ist schlecht und schlecht organisiert, und Leute, die über sie Bescheid wissen, gehen. In der Praxis ist die Wiederverwendung von Code oft schwieriger als es sich lohnt. Wenn der Code jedoch ordnungsgemäß dokumentiert und organisiert ist und sich die Programmierer an den Code halten (oder selbst einen Vorrat an nützlichem Code bereithalten), kann eine Menge Arbeit gespart werden, indem Code aus dem Warehouse geholt und nicht neu erstellt wird.
Alles Design muss von oben nach unten sein, sonst wüsstest du nicht, was du tust. Bauen Sie einen Schuppen oder ein Auto? Das kann man mit Bottom-Up-Design nicht herausfinden. Wenn Sie jedoch ein linkes Vorderrad bauen, denken Sie möglicherweise, dass Sie später mehr Räder benötigen, sowohl für dieses Projekt als auch für andere. Und wenn Sie ein wiederverwendbares Rad bauen, haben Sie vier zum Preis von einem. (Und 18 für den Sattelzug, den Sie als nächstes bauen, alles kostenlos.)
Beachten Sie, dass Sie im Gegensatz zu echten Autos und echten Rädern eine unendliche Anzahl davon gebaut haben, wenn Sie ein Software- "Rad" gebaut haben.
Mehr zum Top-Down-Design: Während Sie damit beginnen müssen, fühle ich mich verpflichtet, darauf hinzuweisen, dass Sie dies herausfinden müssen, wenn Sie kein Rad bauen können möchte bevor Sie viel an Ihrem Auto arbeiten . Sie müssen also fast parallel zur Arbeit von oben nach unten arbeiten. Zu wissen, dass Sie ein Rad bauen können , könnte auch auf viele Projekte hindeuten, an die Sie vorher nicht gedacht hätten, wie zum Beispiel den Sattelzug. Ich denke, der Top-Down-Ansatz muss dominieren, aber mit einer sehr leichten Berührung.
Wenn Sie also Paul Graham weiter umschreiben, erhalten Sie idealerweise beim Schreiben eines Programms viele wiederverwendbare Teile, mit denen Sie viel Zeit im Vergleich zum Originalprogramm und in anderen Programmen sparen können. Um mich ein wenig von Paul Graham zu distanzieren, funktioniert dies in jeder Sprache (obwohl einige den Prozess mehr fördern als andere).
Der Feind dieses fast magischen Prozesses sind Programmierer mit sehr kurzfristigen Aussichten. Dies kann auf Persönlichkeitsstörungen zurückzuführen sein, ist jedoch häufiger auf einen zu schnellen Wechsel von Arbeitsplätzen und Zuständigkeiten sowohl innerhalb als auch zwischen angestellten Unternehmen zurückzuführen.
quelle
Die Verwendung eines Top-Down-Ansatzes mit iterativer Entwicklung liefert in den ersten Iterationen keinen Arbeitscode. Es liefert Designdokumente und solche, zu denen sich der Kunde schwer tun wird, Feedback zu geben. Antworten wie "Ja, ich denke, das ist zu abstrakt für mich" helfen Ihnen nicht dabei, die Besonderheiten des gewünschten Systems durch den Kunden weiter zu spezifizieren.
Stattdessen erstellen Sie nur eine allgemeine Übersicht über das, was angefordert wird. (Anforderungen) als allgemeine Richtlinie dafür zu verwenden, was ein fertiges Produkt definiert und welche Priorität die Implementierung verdient. Von da an erstellen Sie funktionierende Produkte für jede Iteration, mit der der Kunde tatsächlich spielen kann, um zu sehen, ob er dies beabsichtigt hat. Wenn nicht, wird es kein Problem sein, da nicht Hunderte von Stunden für die Entwicklung eines Systems aufgewendet wurden, das anders funktioniert, als es der Kunde jetzt wünscht.
Ich werde nicht für eine andere Person sprechen. Auch habe ich seinen Aufsatz nicht gelesen. Die Antwort, die ich Ihnen gebe, kommt von meiner Ausbildung sowie von Erfahrungen.
Wenn Sie diesen Ansatz verwenden, erhalten Sie abstraktere Bausteine. Nur weil Sie eigenständige Subsysteme erstellen müssen, die sofort präsentiert werden können, können Sie kein Top-Down-Design erstellen, das eng miteinander verzahnt ist und auf einmal implementiert werden muss. Es verbessert die Wiederverwendbarkeit und Wartbarkeit, ermöglicht jedoch vor allem eine flexiblere Reaktion auf Änderungen.
quelle