Wenn ich Design für eine Aufgabe mache, kämpfe ich immer wieder gegen dieses quälende Gefühl, dass es, abgesehen davon, dass es sich um eine allgemeine Gliederung handelt, am Ende mehr oder weniger ignoriert wird. Ich gebe Ihnen ein Beispiel:
Ich habe ein Frontend für ein Gerät geschrieben, das Lese- / Schreibvorgänge hat. Im Klassendiagramm war es absolut sinnvoll, ihm eine Lese- und eine Schreibfunktion zu geben. Als es jedoch darauf ankam, sie tatsächlich zu schreiben, stellte ich fest, dass sie buchstäblich dieselbe Funktion waren, wobei nur eine Codezeile geändert wurde (Aufruf von Lese- und Schreibfunktionen). Um eine Codeduplizierung zu vermeiden, implementierte ich schließlich eine do_io-Funktion mit einem Parameter, der zwischen unterscheidet Operationen. Auf Wiedersehen Original Design.
Dies ist keine furchtbar störende Änderung, aber sie kommt häufig vor und kann auch in kritischeren Teilen des Programms auftreten. Ich frage mich daher, ob es sinnvoll ist, mehr Details als eine allgemeine Gliederung zu entwerfen, zumindest wenn dies der Fall ist kommt zur Architektur des Programms (natürlich müssen Sie bei der Angabe einer API alles genau formulieren).
Dies mag nur das Ergebnis meiner Unerfahrenheit im Design sein, aber andererseits haben wir agile Methoden, die sagen: "Wir geben die Planung weit im Voraus auf, alles wird sich sowieso in ein paar Tagen ändern", was häufig der Fall ist wie ich mich fühle.
Wie genau sollte ich Design "verwenden"?
do_io
scheint ein internes Implementierungsdetail dieser Klasse zu sein. Die öffentliche Schnittstelle wird und sollte wahrscheinlich immer noch seinread(...)
undwrite(...)
da sie viel ausführlicher über die Absicht des Anrufs ist.Antworten:
Wenn es sinnvoll war, Lese- und Schreibvorgänge bereitzustellen, warum sollten Sie diese entfernen?
Aus Anwendersicht macht es immer noch Sinn. Die Implementierungsdetails sollten eine bereitgestellte Schnittstelle nicht beeinträchtigen.
Sie können ein internes do_io erstellen, das durch Lesen und Schreiben aufgerufen wird.
Am Ende folgt der Entwurfsprozess diesen Schritten:
quelle
Das Architekturdesign eines Programms entwickelt sich im Laufe der Zeit. Ich denke nicht, dass Sie am Anfang alle Informationen haben, die Sie benötigen, um ein korrektes Design zu haben.
Wenn Sie sich also an das Design halten, an das Sie am Anfang gedacht haben, werden Sie sich wahrscheinlich einschränken.
Sofern Sie keine öffentliche API erstellen, ist es meiner Meinung nach in Ordnung, unterwegs Änderungen am Design vorzunehmen.
Eines der besten Dinge, die Sie tun können, ist, in ein Tool zu investieren, das das Design aus dem Code extrahieren kann (wie NDepend für C #).
quelle
Agile behauptet, dieses Problem mit einigem Erfolg zu beantworten. Fred Brooks hatte die Antwort jedoch vor 40 Jahren, als er schrieb: "Schreiben Sie eine, um sie wegzuwerfen, weil Sie es sowieso tun". Diejenigen, die die Geschichte nicht studieren, sind dazu verdammt, sie zu wiederholen.
Was Sie also tun müssen, ist, das Design als einen Plan zu behandeln, der nur zum Zweck der Änderung erstellt wurde. Designs, die nicht geändert werden können, sind zum Scheitern verurteilt. Sie müssen bereit sein, schlechte wegzuwerfen.
Wenn es sich bei dem Design um eine öffentliche API, eine Schnittstelle oder dergleichen handelt, ist große Vorsicht geboten, da die Kosten für Änderungen hoch sind. Die Unfähigkeit, Änderungen vorzunehmen, führt jedoch zum Scheitern.
Denken Sie nicht für eine Sekunde, dass Sie gut genug sind und wissen Sie genug, um es beim ersten, zweiten oder sogar dritten Mal richtig zu machen.
quelle
In den meisten realen Projekten ist es eine Tatsache, dass sich die Dinge ändern:
Aus diesem Grund lehnen agile Methoden Big Design Up Front ab, da sie nur ein falsches Sicherheitsgefühl vermitteln, viel unnötigen Aufwand erfordern und die Anpassung an die unvermeidlichen Änderungen erschweren.
Allerdings tut Agile nicht auf „weit voraus zu planen aufgeben“ gleich . Agile Methoden erfordern die notwendige sorgfältige und durchdachte Planung, nur nicht mehr. Sie sind sehr diszipliniert und unterscheiden sich von der "Cowboy-Codierung". Die richtige Menge an Design zu machen ist ein kontinuierlicher Versuch, das richtige Gleichgewicht zwischen Über- und Unterdesign zu finden. Aber meiner Meinung nach ist es besser, ein wenig auf der Seite von zu viel zu irren, als zu wenig zu tun.
Das ursprüngliche Design sollte nicht versuchen, alles abzudecken, sondern Ihnen ein sicheres Gefühl geben, dass Sie wissen, wie Sie mit der Implementierung fortfahren können, Sie haben Antworten auf die grundlegenden Fragen zur Architektur und Sie haben ein mentales Modell für die bekannte Verwendung Fälle werden im wirklichen Leben funktionieren. In der agilen Ansicht besteht der eigentliche Test eines Entwurfs in der Implementierung. Es ist daher in Ordnung, bereits während der Entwurfsphase mit dem Schreiben von Code zu beginnen, um ein Gefühl dafür zu bekommen, wie das geplante Design aussehen würde, oder um schnell eine Annahme zu prototypisieren / zu validieren . Beachten Sie jedoch, dass die meisten dieser frühen Arbeiten weggeworfen werden müssen, sobald die Antwort auf die gegebene Frage festgelegt ist. Es ist fast immer eine schlechte Sache, eine echte Produktions-App aus einem frühen Prototyp zu erstellen.
Es ist auch in Ordnung, das Design zu ändern, wenn Sie während der Implementierung eine neue wichtige Erkenntnis vornehmen. Dies ist ein wichtiges Feedback auf zwei Ebenen:
quelle
Es ist immer wichtig, wenn Sie ein Dokument erstellen, um zu verstehen, wozu es dient.
Ich denke, wir müssen vorsichtig sein, was wir "Architektur" -Dokumente nennen. Es ist alles eine Frage des Umfangs.
Wenn Sie über ein System sprechen, das mehrere Teams oder Gruppen von Teams erfordert, dann sprechen Sie über ein Dokument, dessen Zweck darin besteht, mindestens Einzelheiten zu beschreiben:
Wenn Ihr Dokument für ein kleineres System bestimmt ist, können Sie die Anzahl der Elemente reduzieren, die Sie einbeziehen müssen, da einige Annahmen dem vorhandenen System inhärent sind. Angenommen, Sie stellen eine Funktion zusammen, die auf einer Website ausgeführt werden muss, und einige neue Aufrufe in einer API. Dann dient Ihr Dokument als Möglichkeit, Folgendes festzulegen:
Diese Gliederungsdokumente dienen dazu, Gespräche darüber in den Vordergrund zu rücken, wer was tun soll und wie sie sich integrieren sollen. Sobald diese Entscheidungen getroffen sind, können Teams weitgehend autonom mit einer viel geringeren Wahrscheinlichkeit von Integrationsproblemen arbeiten.
Je mehr Integrationsprobleme Sie wahrnehmen, desto detaillierter sollten Dokumente sein.
quelle
Sie scheinen auf ein allgemeines Rätsel in der Softwareentwicklung gestoßen zu sein. Es ist nicht möglich, ein gesamtes System zu planen, bevor Sie mit dem Erstellen beginnen, da Sie zu viele Dinge noch nicht wissen.
Dies ist der Grund, warum agile Methoden iterative Entwicklung verwenden, da sie es ermöglichen, durch regelmäßiges Feedback die Richtung der Software zu ändern, anstatt zuzulassen, dass die Dinge immer weiter von dem entfernt werden, was tatsächlich benötigt wird. Jede Änderung wirkt sich auf das Design aus.
Nachdem ich dies alles gesagt habe, hätte ich tatsächlich zwei Methoden für das spezifische Szenario geschrieben, das Sie oben beschrieben haben, aber ich hätte die gemeinsame Logik in eine dritte private Methode eingekapselt, die von den beiden Methoden verwendet werden kann. Auf diese Weise sind die öffentlichen Methoden für nur eine Sache verantwortlich und leicht zu benennen
read_file
undwrite_file
genau zu sagen, was sie tun, während sie nichtdo_file
eindeutig sind.Bücher wie Clean Code , Robert C. Martin und Emergent Design , Scott L. Bain geben Ihnen detailliertere Einblicke in dieses Thema.
quelle
Es ist nicht möglich, jedes einzelne Detail im Voraus zu planen. Es ist durchaus akzeptabel, hier und da Änderungen vorzunehmen.
Es ist jedoch wichtig, vorausschauend zu planen. Agil zu sein bedeutet nicht, kein Design und überhaupt keine Planung zu haben , aber es bedeutet, dass Sie Änderungen erwarten.
Sie sollten Ihr Design so verwenden, wie es ist. Da es nicht in den Stein geschrieben ist, ist es leicht, es zu ändern.
quelle
Die Zeit, die Sie für die Architektur aufwenden, sollte vom Risikograd in diesem Teil des Systems abhängen.
Im Allgemeinen sollten Sie ziemlich früh eine Entscheidung über den / die Architekturstil (e) treffen - Ebenen, Komponenten, Pub-Sub usw. usw. Keine Menge an sauberem Code und lose Kopplung wird es einfach machen, die Stile spät zu wechseln ein Projekt.
Auf diese Weise erhalten Sie eine grundlegende Vorstellung von den verschiedenen Bausteinen in Ihrem System und der Roadmap, wenn sich Ihr System und Ihre Anforderungen im Laufe der Zeit weiterentwickeln.
Sobald Sie mit Anwendungsfällen vertraut sind, sollten Sie meines Erachtens genug Design ausführen, um sicherzustellen, dass Sie das Problem und die Lösung vollständig verstehen. Wenn es sich um einen Kesselplattencode handelt, den Sie immer wieder gemacht haben, ist das Risiko eines Fehlers (im architektonischen Sinne - Sie müssen natürlich noch testen) ziemlich gering, und daher ist die Menge an Vorab-Design wahrscheinlich ziemlich minimal sein. Wenn es sich um ein neues Problem handelt oder um ein Problem mit einer unklaren Lösung oder um ein Problem, das für das Unternehmen möglicherweise ein Risiko darstellt, verdient es viel mehr Zeit, sich Gedanken zu machen.
Es gibt natürlich eine Vielzahl von Möglichkeiten, dies zu tun - UML, Prototypen, Whiteboard-Skizzen usw. Unabhängig von der verwendeten Methode ist es wichtig, sich daran zu erinnern, dass sie Ihnen helfen sollen, über Ihr Design nachzudenken und zu kommunizieren.
quelle