Sollten wir beim Entwerfen eines Programms ein detailliertes Architekturdesign oder nur eine Gliederung schreiben?

8

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"?

EpsilonVector
quelle
1
Das do_ioscheint ein internes Implementierungsdetail dieser Klasse zu sein. Die öffentliche Schnittstelle wird und sollte wahrscheinlich immer noch sein read(...)und write(...)da sie viel ausführlicher über die Absicht des Anrufs ist.
Johannes S.

Antworten:

6

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:

  • Definieren Sie die Schnittstelle
  • Zeichnen Sie ein grobes Design
  • verfeinern, ohne die vereinbarte Schnittstelle zu ändern
Mouviciel
quelle
1
+1 "Optimierungs" -Entscheidungen zur Vermeidung von Codeduplizierungen erfordern nicht unbedingt eine Änderung des ursprünglichen Designs.
Marjan Venema
4

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 #).

Thanos Papathanasiou
quelle
2

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.

mattnz
quelle
2

In den meisten realen Projekten ist es eine Tatsache, dass sich die Dinge ändern:

  • (wie Sie bemerkt haben) Die Umgebung / Plattform / APIs, die das Programm verwenden wird, können sich von den ursprünglich angenommenen unterscheiden
  • Die Anforderungen können sich jederzeit ändern
  • Der Markt / die umliegende Welt kann sich ändern und einige Anforderungen (oder das gesamte Projekt) überflüssig machen.
  • ...

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:

  • Ihr konkretes Design muss an die sich verändernde Welt angepasst werden
  • Ihr Design - Prozess Bedürfnisse angepasst werden solche Möglichkeiten in der Zukunft (dh das nächste Mal denken , durch den Anwendungsfall von Lesen und im Voraus an das Gerät besser zu schreiben) abzudecken.
Péter Török
quelle
2

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:

  • Was sind die Komponenten im System
  • Wie sind die Komponenten verbunden?
  • Was sind die Verantwortlichkeiten der einzelnen Komponenten?
  • Wer sollte an jeder Komponente arbeiten?

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:

  • Welche Logik wird auf der Website leben
  • Welche Logik wird in der API leben
  • Was werden die API-Aufrufverträge sein (beste Vermutung)

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.

ExCodeCowboy
quelle
1

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_fileund write_filegenau zu sagen, was sie tun, während sie nicht do_fileeindeutig sind.

Bücher wie Clean Code , Robert C. Martin und Emergent Design , Scott L. Bain geben Ihnen detailliertere Einblicke in dieses Thema.

Fenton
quelle
1

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.

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.

Wie genau sollte ich Design "verwenden"?

Sie sollten Ihr Design so verwenden, wie es ist. Da es nicht in den Stein geschrieben ist, ist es leicht, es zu ändern.

BЈовић
quelle
1

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.

FinnNk
quelle