Kann / sollte das Prinzip der einheitlichen Verantwortung auf neuen Kodex angewendet werden?

20

Das Prinzip ist definiert als Module mit einem Änderungsgrund . Meine Frage ist, sicherlich sind diese Gründe für die Änderung nicht bekannt, bis der Code tatsächlich zu ändern beginnt? Ziemlich jeder Code hat zahlreiche Gründe, warum er sich möglicherweise ändern könnte. Wenn Sie jedoch versuchen, all dies zu antizipieren und Ihren Code in diesem Sinne zu entwerfen, erhalten Sie sehr schlechten Code. Ist es nicht eine bessere Idee, SRP erst dann wirklich anzuwenden, wenn Anfragen zur Änderung des Codes eingehen? Genauer gesagt, wenn sich ein Codeteil aus mehreren Gründen mehr als einmal geändert hat, um zu beweisen, dass es mehrere Änderungsgründe gibt. Es klingt sehr anti-agil zu versuchen, Gründe für eine Veränderung zu erraten.

Ein Beispiel wäre ein Stück Code, der ein Dokument druckt. Es wird eine Anforderung zum Ändern des Dokuments zum Drucken in PDF gesendet. Anschließend wird eine zweite Anforderung zum Ändern des Dokuments zum Anwenden einer anderen Formatierung auf das Dokument gesendet. Zu diesem Zeitpunkt haben Sie den Beweis für mehr als einen Grund für eine Änderung (und einen Verstoß gegen das SRP) und sollten das entsprechende Refactoring durchführen.

SeeNoWeevil
quelle
6
@Frank - so wird es eigentlich gemeinhin definiert - siehe zB en.wikipedia.org/wiki/Single_responsibility_principle
Joris Timmermans
1
So wie Sie es ausdrücken, verstehe ich die Definition von SRP nicht.
Pieter B
2
Jede Codezeile hat (mindestens) zwei Gründe, geändert zu werden: Sie trägt zu einem Fehler bei oder beeinträchtigt eine neue Anforderung.
Bart van Ingen Schenau
1
@BartvanIngenSchenau: LOL ;-) Wenn du das so siehst, kann das SRP nirgendwo angewendet werden.
Doc Brown
1
@DocBrown: Sie können SRP mit dem Ändern des Quellcodes koppeln, wenn Sie dies nicht tun. Zum Beispiel, wenn Sie SRP so interpretieren, dass Sie in der Lage sind, einen vollständigen Bericht darüber zu geben, was eine Klasse / Funktion in einem Satz tut, ohne das Wort und zu verwenden (und keine Wieselformulierung, um diese Einschränkung zu umgehen).
Bart van Ingen Schenau

Antworten:

27

Natürlich sagt Ihnen das YAGNI- Prinzip, dass Sie SRP erst anwenden müssen, wenn Sie es wirklich benötigen. Die Frage, die Sie sich stellen sollten, lautet jedoch: Muss ich SRP erst anwenden und erst dann, wenn ich meinen Code tatsächlich ändern muss?

Nach meiner Erfahrung bringt die Anwendung von SRP einen Vorteil viel früher: Sie müssen herausfinden, wo und wie Sie eine bestimmte Änderung in Ihrem Code anwenden können. Für diese Aufgabe müssen Sie Ihre vorhandenen Funktionen und Klassen lesen und verstehen. Dies wird sehr viel einfacher, wenn alle Ihre Funktionen und Klassen eine bestimmte Verantwortung haben. Daher sollten Sie SRP anwenden, wenn es das Lesen Ihres Codes erleichtert, wenn es Ihre Funktionen kleiner und selbsterklärender macht. Die Antwort lautet also Ja , es ist sinnvoll, SRP auch für neuen Code anzuwenden.

Wenn Ihr Druckcode beispielsweise ein Dokument liest, das Dokument formatiert und das Ergebnis auf einem bestimmten Gerät druckt, sind dies drei klare, trennbare Verantwortlichkeiten. Also mache mindestens 3 Funktionen daraus und gib ihnen die entsprechenden Namen. Beispielsweise:

 void RunPrintWorkflow()
 {
     var document = ReadDocument();
     var formattedDocument = FormatDocument(document);
     PrintDocumentToScreen(formattedDocument);
 }

Wenn Sie nun eine neue Anforderung zum Ändern der Dokumentformatierung oder zum Drucken in PDF erhalten, wissen Sie genau, an welcher dieser Funktionen oder Stellen im Code Sie Änderungen vornehmen müssen, und noch wichtiger, wo nicht.

Also, wenn Sie auf eine Funktion , kommen Sie nicht verstehen , weil die Funktion tut „zu viel“, und Sie sind nicht sicher , ob und wo eine Änderung zu übernehmen, dann betrachten die Funktion in separate, kleinere Funktionen Refactoring. Warten Sie nicht, bis Sie etwas ändern müssen. Code wird zehnmal häufiger gelesen als geändert, und kleinere Funktionen sind viel einfacher zu lesen. Wenn eine Funktion eine bestimmte Komplexität aufweist, können Sie sie meiner Erfahrung nach immer in verschiedene Verantwortlichkeiten aufteilen, unabhängig davon, welche Änderungen in Zukunft vorgenommen werden. Bob Martin geht normalerweise noch einen Schritt weiter, siehe den Link, den ich in meinen Kommentaren unten angegeben habe.

BEARBEITEN: zu Ihrem Kommentar: Die Hauptverantwortung der äußeren Funktion im obigen Beispiel besteht nicht darin, auf einem bestimmten Gerät zu drucken oder das Dokument zu formatieren - es ist die Integration des Druckworkflows . Auf der Abstraktionsebene der äußeren Funktion ist eine neue Anforderung wie "Dokumente sollten nicht mehr formatiert werden" oder "Dokumente sollten verschickt statt gedruckt werden" nur "der gleiche Grund" - nämlich "Der Druckworkflow hat sich geändert". Wenn wir über solche Dinge sprechen, ist es wichtig, auf der richtigen Abstraktionsebene zu bleiben .

Doc Brown
quelle
Im Allgemeinen entwickle ich immer mit TDD, sodass ich in meinem Beispiel die gesamte Logik physikalisch nicht in einem Modul hätte halten können, da es unmöglich wäre, sie zu testen. Dies ist nur ein Nebenprodukt von TDD und nicht, weil ich SRP absichtlich anwende. Mein Beispiel hatte ziemlich klare, getrennte Verantwortlichkeiten, also vielleicht kein gutes Beispiel. Ich denke, was ich frage, ist, können Sie ein neues Stück Code schreiben und eindeutig sagen, ja, dies verstößt nicht gegen SRP? Sind die Gründe für eine Änderung nicht im Wesentlichen vom Unternehmen definiert?
SeeNoWeevil
3
@thecapsaicinkid: ja, das kannst du (zumindest durch sofortiges refactoring). Aber Sie werden sehr, sehr kleine Funktionen bekommen - und das gefällt nicht jedem Programmierer. Siehe folgendes Beispiel: sites.google.com/site/unclebobconsultingllc/…
Doc Brown
Wenn Sie SRP anwenden, indem Sie Gründe für eine Änderung antizipieren, könnte ich in Ihrem Beispiel immer noch behaupten, dass es mehr als eine einzige Grundänderung gibt. Das Unternehmen könnte entscheiden, dass es ein Dokument nicht mehr formatieren möchte, und später entscheiden, dass es per E-Mail gesendet und nicht gedruckt werden soll. BEARBEITEN: Lesen Sie einfach den Link, und obwohl mir das Endergebnis nicht besonders gefällt, ist "Extrahieren, bis Sie einfach nicht mehr extrahieren können" viel sinnvoller und weniger zweideutig als "nur ein Grund zur Änderung". Nicht sehr pragmatisch.
SeeNoWeevil
1
@thecapsaicinkid: siehe meine bearbeiten. Die Hauptverantwortung der äußeren Funktion besteht nicht darin, auf einem bestimmten Gerät zu drucken oder das Dokument zu formatieren, sondern den Druckworkflow zu integrieren. Und wenn sich dieser Workflow ändert, ist dies der einzige Grund, warum sich die Funktion ändert
Doc Brown
Ihr Kommentar zum Festhalten an der richtigen Abstraktionsebene scheint das zu sein, was mir gefehlt hat. Ein Beispiel: Ich habe eine Klasse, die ich als "Erstellt Datenstrukturen aus einem JSON-Array" beschreiben würde. Klingt für mich nach einer einzigen Verantwortung. Durchläuft die Objekte in einem JSON-Array und ordnet sie POJOs zu. Wenn ich mich an die gleiche Abstraktionsebene wie meine Beschreibung halte, ist es schwierig zu argumentieren, dass es mehrere Gründe für eine Änderung gibt, z. B. wie JSON dem Objekt zugeordnet wird. Als weniger abstrakt Ich könnte argumentieren , es mehr als ein Grund zum Beispiel hat , wie ich Datumsfelder Änderungen abzubilden, wie numerische Werte Tage usw. abgebildet werden
SeeNoWeevil
7

Ich glaube, Sie verstehen SRP falsch.

Der einzige Grund für die Änderung besteht NICHT darin, den Code zu ändern, sondern darin, was Ihr Code tut.

Pieter B
quelle
3

Ich denke, die Definition von SRP als "einen Grund zur Änderung haben" ist aus genau diesem Grund irreführend. Nehmen Sie es genau zum Nennwert: Das Prinzip der Einzelverantwortung besagt, dass eine Klasse oder Funktion genau eine Verantwortung haben sollte. Nur einen Grund zur Veränderung zu haben, ist ein Nebeneffekt, wenn man zunächst nur eine Sache tut. Es gibt keinen Grund, warum Sie sich nicht mindestens um eine einzelne Verantwortung in Ihrem Code bemühen können, ohne zu wissen, wie sich dieser in Zukunft ändern könnte.

Einer der besten Anhaltspunkte dafür ist, wenn Sie Klassen- oder Funktionsnamen auswählen. Wenn nicht sofort ersichtlich ist, wie die Klasse benannt werden soll, der Name besonders lang / komplex ist oder der Name allgemeine Begriffe wie "Manager" oder "Dienstprogramm" verwendet, verstößt er wahrscheinlich gegen die SRP. In ähnlicher Weise sollte bei der Dokumentation der API schnell ersichtlich werden, ob Sie SRP verletzen, basierend auf der von Ihnen beschriebenen Funktionalität.

Es gibt natürlich Nuancen bei SRP, die Sie erst später im Projekt kennen - eine scheinbar einzelne Verantwortung stellte sich als zwei oder drei heraus. In diesen Fällen müssen Sie eine Umgestaltung vornehmen, um SRP zu implementieren. Dies bedeutet jedoch nicht, dass SRP ignoriert werden sollte, bis Sie eine Änderungsanforderung erhalten. das ist gegen den Zweck von SRP!

Wenn Sie direkt mit Ihrem Beispiel sprechen möchten, sollten Sie Ihre Druckmethode dokumentieren. Wenn Sie würde sagen , „diese Methode formatiert die Daten für den Druck und sendet sie an den Drucker,“ dass und ist das, was man bekommt: die nicht eine einzige Verantwortung ist, das ist zwei Aufgaben: die Formatierung und an den Drucker senden. Wenn Sie dies erkennen und in zwei Funktionen / Klassen aufteilen, haben Sie zum Zeitpunkt Ihrer Änderungsanforderungen bereits nur einen Grund für jede Sektion, sich zu ändern.

Adrian
quelle
3

Ein Beispiel wäre ein Stück Code, der ein Dokument druckt. Es wird eine Anforderung zum Ändern des Dokuments zum Drucken in PDF gesendet. Anschließend wird eine zweite Anforderung zum Ändern des Dokuments zum Anwenden einer anderen Formatierung auf das Dokument gesendet. Zu diesem Zeitpunkt haben Sie den Beweis für mehr als einen Grund für eine Änderung (und einen Verstoß gegen das SRP) und sollten das entsprechende Refactoring durchführen.

Ich habe mich so oft in den Fuß geschossen, weil ich zu viel Zeit damit verbracht habe, den Code an diese Änderungen anzupassen. Anstatt nur das verdammt blöde PDF zu drucken.

Refactor zum Reduzieren von Code

Das Muster für den einmaligen Gebrauch kann zum Aufblähen von Code führen. Wo Pakete mit kleinen spezifischen Klassen verschmutzt werden, die einen Müllhaufen Code erzeugen, der im Einzelfall keinen Sinn ergibt. Sie müssen Dutzende von Quelldateien öffnen, um zu verstehen, wie es zum Druckteil kommt. Darüber hinaus können Hunderte, wenn nicht Tausende von Codezeilen vorhanden sein, um nur 10 Codezeilen auszuführen, die den eigentlichen Druck ausführen.

Erstelle ein Bullseye

Das Einwegmuster sollte den Quellcode reduzieren und die Wiederverwendung von Code verbessern. Es sollte Spezialisierung und spezifische Implementierungen schaffen. Eine Art bullseyeim Quellcode für Sie go to specific tasks. Wenn beim Drucken ein Problem auftrat, wussten Sie genau, wo Sie es beheben können.

Einmalgebrauch bedeutet keine mehrdeutige Frakturierung

Ja, Sie haben Code, der bereits ein Dokument druckt. Ja, Sie müssen jetzt den Code ändern, um auch PDFs zu drucken. Ja, Sie müssen jetzt die Formatierung des Dokuments ändern.

Sind Sie sicher, dass sich das usageerheblich geändert hat?

Wenn Refactoring dazu führt, dass Teile des Quellcodes zu stark verallgemeinert werden. Bis zu dem Punkt, an dem die ursprüngliche Absicht von printing stuffnicht mehr explizit ist, haben Sie im Quellcode mehrdeutige Brüche erstellt.

Wird der Neue das schnell herausfinden können?

Pflegen Sie Ihren Quellcode immer in einer Organisation, die am einfachsten zu verstehen ist.

Sei kein Uhrmacher

Viel zu oft habe ich Entwickler gesehen, die ein Okular aufgesetzt haben, und mich auf die kleinen Details konzentriert, bis zu dem Punkt, dass niemand sonst die Teile wieder zusammenfügen kann, wenn sie auseinanderfallen.

Bildbeschreibung hier eingeben

Reactgular
quelle
2

Ein Grund für die Änderung ist letztendlich eine Änderung der Spezifikation oder der Informationen zur Umgebung, in der die Anwendung ausgeführt wird. Aus diesem Grund schreibt Ihnen ein Prinzip mit einer einzigen Verantwortung vor, dass Sie jede Komponente (Klasse, Funktion, Modul, Service ...) so schreiben müssen, dass die Spezifikation und die Ausführungsumgebung so wenig wie möglich berücksichtigt werden.

Da Sie die Spezifikation und Umgebung beim Schreiben der Komponente kennen, können Sie das Prinzip anwenden.

Wenn Sie das Beispiel eines Codes betrachten, der ein Dokument druckt. Sie sollten überlegen, ob Sie die Layoutvorlage definieren können, ohne zu berücksichtigen, dass das Dokument im PDF-Format vorliegt. Sie können, also sagt SRP Ihnen, dass Sie sollten.

Natürlich sagt dir YAGNI, dass du es nicht tun sollst. Sie müssen ein Gleichgewicht zwischen den Gestaltungsprinzipien finden.

Jan Hudec
quelle
2

Flup geht in die richtige Richtung. Das "Prinzip der einheitlichen Verantwortung" galt ursprünglich für Verfahren. Zum Beispiel würde Dennis Ritchie sagen, dass eine Funktion eines tun und es gut machen sollte. Dann würde Bjarne Stroustrup in C ++ sagen, dass eine Klasse eines tun und es gut machen sollte.

Beachten Sie, dass diese beiden Regeln, außer als Faustregeln, formal wenig oder gar nichts miteinander zu tun haben. Sie bieten nur das, was in der Programmiersprache bequem ausgedrückt werden kann. Nun, das ist etwas. Aber es ist eine ganz andere Geschichte als die, mit der Flup fährt.

Moderne (dh agile und DDD) Implementierungen konzentrieren sich mehr auf das, was für das Unternehmen wichtig ist, als auf das, was die Programmiersprache ausdrücken kann. Das Überraschende ist, dass die Programmiersprachen noch nicht aufgeholt haben. Alte FORTRAN-ähnliche Sprachen übernehmen Verantwortlichkeiten, die zu den wichtigsten konzeptuellen Modellen der Zeit passen: die Prozesse, die auf jede Karte angewendet wurden, während sie den Kartenleser durchliefen, oder (wie in C) die Verarbeitung, die jeden Interrupt begleitete. Dann kamen ADT-Sprachen, die so weit gereift waren, dass sie erfassten, was die DDD-Leute später als wichtig neu erfanden (obwohl Jim Neighbors das meiste davon herausgefunden, veröffentlicht und 1968 verwendet hatte): das, was wir heute Klassen nennen . (Sie sind keine Module.)

Dieser Schritt war weniger eine Evolution als ein Pendelschlag. Als das Pendel zu Daten schwang, verloren wir die FORTRAN-eigene Anwendungsfallmodellierung. Das ist in Ordnung, wenn Sie sich in erster Linie auf die Daten oder Formen auf einem Bildschirm konzentrieren. Es ist ein großartiges Modell für Programme wie PowerPoint oder zumindest für seine einfachen Operationen.

Was verloren gegangen ist , ist die Systemverantwortung . Wir verkaufen keine DDD-Elemente. Und wir haben keine guten Unterrichtsmethoden. Wir verkaufen Systemverantwortlichkeiten. Auf einer bestimmten Ebene müssen Sie Ihr System nach dem Prinzip der Einzelverantwortung auslegen.

Wenn Sie sich also Leute wie Rebecca Wirfs-Brock oder mich ansehen, die früher über Klassenmethoden gesprochen haben, sprechen wir jetzt über Anwendungsfälle. Das verkaufen wir. Das sind die Systemoperationen. Ein Anwendungsfall sollte eine einzige Verantwortung haben. Ein Anwendungsfall ist selten eine architektonische Einheit. Aber alle versuchten so zu tun, als ob es so wäre. Erleben Sie zum Beispiel die SOA-Leute.

Aus diesem Grund freue ich mich sehr über die DCI-Architektur von Trygve Reenskaug, die im obigen Lean Architecture-Buch beschrieben ist. Es verleiht dem, was früher eine willkürliche und mystische Ablehnung der "Einzelverantwortung" war, endlich eine wirkliche Gestalt - wie man in den meisten der obigen Argumente findet. Diese Statur bezieht sich auf menschliche mentale Modelle: Endbenutzer zuerst UND Programmierer zweitens. Es bezieht sich auf geschäftliche Anliegen. Und fast zufällig kapselt es den Wandel, wenn Flup uns herausfordert.

Das Prinzip der einmaligen Verantwortung, wie wir es kennen, ist entweder ein Dinosaurier, der seit seinen Anfängen übrig ist, oder ein Steckenpferd, das wir als Ersatz für das Verständnis verwenden. Sie müssen einige dieser Hobbypferde zurücklassen, um großartige Software zu entwickeln. Und das erfordert ein Umdenken. Die Dinge einfach und leicht verständlich zu halten funktioniert nur, wenn das Problem einfach und leicht verständlich ist. Diese Lösungen interessieren mich nicht sonderlich: Sie sind nicht typisch und die Herausforderung liegt nicht darin.

Fertig werden
quelle
2
Als ich das las, was du geschrieben hast, habe ich irgendwo auf dem Weg alles aus den Augen verloren, worüber du redest. Gute Antworten behandeln die Frage nicht als Ausgangspunkt für einen Streifzug durch den Wald, sondern als ein bestimmtes Thema, mit dem alle Schriften verknüpft werden.
Donal Fellows
1
Ah, du bist einer von denen, wie einer meiner alten Manager. "Wir wollen es nicht verstehen, wir wollen es verbessern!" Das zentrale thematische Thema ist eines der Prinzipien: Das ist das "P" in "SRP". Vielleicht hätte ich die Frage direkt beantwortet, wenn es die richtige Frage gewesen wäre: Es war nicht so. Sie können das mit demjenigen aufnehmen, der die Frage gestellt hat.
Cope
Irgendwo hier ist eine gute Antwort vergraben. Ich denke ...
RubberDuck
0

Ja, das Single-Responsibility-Prinzip sollte auf neuen Code angewendet werden.

Aber! Was ist eine Verantwortung?

Ist "druckt einen Bericht eine Verantwortung"? Ich glaube, die Antwort ist "Vielleicht".

Versuchen wir, die Definition von SRP als "nur einen einzigen Änderungsgrund haben" zu verwenden.

Angenommen, Sie haben eine Funktion zum Drucken von Berichten. Wenn Sie zwei Änderungen haben:

  1. Ändern Sie diese Funktion, da Ihr Bericht einen schwarzen Hintergrund haben muss
  2. Ändern Sie diese Funktion, da Sie als PDF drucken müssen

Dann lautet die erste Änderung "Ändern des Berichtsstils", die andere "Ändern des Berichtsausgabeformats", und Sie sollten sie jetzt in zwei verschiedene Funktionen einteilen, da dies unterschiedliche Dinge sind.

Aber wenn Ihre zweite Änderung gewesen wäre:

2b. Ändern Sie diese Funktion, da für Ihren Bericht eine andere Schriftart erforderlich ist

Ich würde sagen, dass beide Änderungen "den Berichtsstil ändern" und in einer Funktion bleiben können.

Wo bleibt uns das also? Wie üblich sollten Sie versuchen, die Dinge einfach und leicht verständlich zu halten. Wenn das Ändern der Hintergrundfarbe 20 Codezeilen und das Ändern der Schriftart 20 Codezeilen bedeutet, führen Sie die beiden Funktionen erneut aus. Wenn es sich jeweils um eine Zeile handelt, belassen Sie diese in einer.

Sarien
quelle
0

Wenn Sie ein neues System entwerfen, sollten Sie überlegen, welche Änderungen Sie möglicherweise während der Lebensdauer vornehmen müssen und wie teuer diese für die Architektur sind, die Sie implementieren. Das Aufteilen Ihres Systems in Module ist eine teure Entscheidung, um Fehler zu machen.

Eine gute Informationsquelle ist das mentale Modell im Kopf der Domain-Experten des Unternehmens. Nehmen Sie das Beispiel des Dokuments, der Formatierung und des PDF. Die Domain-Experten werden Ihnen wahrscheinlich mitteilen, dass sie ihre Briefe mithilfe von Dokumentvorlagen formatieren. Entweder stationär oder in Word oder was auch immer. Sie können diese Informationen abrufen, bevor Sie mit dem Codieren beginnen, und sie in Ihrem Entwurf verwenden.

Eine gute Lektüre über diese Dinge: Lean Architecture by Coplien

flup
quelle
0

"Drucken" ist sehr ähnlich wie "Ansicht" in MVC. Jeder, der die Grundlagen von Objekten versteht, würde das verstehen.

Es liegt in der Verantwortung des Systems . Es ist als MVC-Mechanismus implementiert, der einen Drucker (die Ansicht), das zu druckende Objekt (das Modul) sowie die Druckeranforderung und -optionen (vom Controller) umfasst.

Der Versuch, dies als Klassen- oder Modulverantwortung zu lokalisieren, ist idiotisch und spiegelt das 30-jährige Denken wider. Wir haben seitdem viel gelernt, und dies wird in der Literatur und im Code reifer Programmierer ausführlich belegt.

Fertig werden
quelle
0

Ist es nicht eine bessere Idee, SRP erst dann wirklich anzuwenden, wenn Anfragen zur Änderung des Codes eingehen?

Im Idealfall haben Sie bereits eine gute Vorstellung von den Verantwortlichkeiten der verschiedenen Teile des Codes. Teilen Sie die Zuständigkeiten entsprechend Ihren ersten Instinkten auf, wobei Sie möglicherweise berücksichtigen, was die von Ihnen verwendeten Bibliotheken tun möchten (eine Aufgabe, eine Verantwortung an eine Bibliothek zu delegieren, ist in der Regel eine großartige Aufgabe, vorausgesetzt, die Bibliothek kann die Aufgabe tatsächlich ausführen ). Verfeinern Sie dann Ihr Verständnis der Verantwortlichkeiten entsprechend den sich ändernden Anforderungen. Je besser Sie das System anfangs verstehen, desto weniger müssen Sie die Verantwortungszuweisungen grundlegend ändern (obwohl Sie manchmal feststellen, dass eine Verantwortlichkeit am besten in untergeordnete Verantwortlichkeiten unterteilt ist).

Nicht, dass Sie sich lange darum kümmern müssten. Ein wichtiges Merkmal von Code ist, dass er später geändert werden kann. Sie müssen ihn nicht beim ersten Mal vollständig korrigieren. Versuchen Sie einfach, mit der Zeit besser zu werden, um zu lernen, welche Art von Formverantwortung Sie haben, damit Sie in Zukunft weniger Fehler machen können.

Ein Beispiel wäre ein Stück Code, der ein Dokument druckt. Es wird eine Anforderung zum Ändern des Dokuments zum Drucken in PDF gesendet. Anschließend wird eine zweite Anforderung zum Ändern des Dokuments zum Anwenden einer anderen Formatierung auf das Dokument gesendet. Zu diesem Zeitpunkt haben Sie den Beweis für mehr als einen Grund für eine Änderung (und einen Verstoß gegen das SRP) und sollten das entsprechende Refactoring durchführen.

Dies ist ein klarer Hinweis darauf, dass die Gesamtverantwortung - das „Drucken“ des Codes - untergeordnete Aufgaben hat und in Teile geteilt werden sollte. Dies ist keine Verletzung von SRP per se , sondern ein Hinweis darauf, dass wahrscheinlich eine Partitionierung (möglicherweise in Unteraufgaben "Formatieren" und "Rendern") erforderlich ist. Können Sie diese Verantwortlichkeiten klar beschreiben, damit Sie verstehen, was in den Teilaufgaben vor sich geht, ohne auf deren Umsetzung zu achten? Wenn Sie können, sind es wahrscheinlich vernünftige Spaltungen.

Es könnte auch klarer sein, wenn wir uns ein einfaches reales Beispiel ansehen. Betrachten wir die sort()Utility-Methode in java.util.Arrays. Was tut es? Es sortiert ein Array und das ist alles, was es tut. Es druckt die Elemente nicht aus, es findet nicht das moralisch passendste Mitglied, es pfeift Dixie nicht . Es sortiert nur ein Array. Sie müssen auch nicht wissen, wie. Das Sortieren ist die einzige Verantwortung dieser Methode. (Tatsächlich gibt es in Java viele Sortiermethoden aus etwas hässlichen technischen Gründen, die mit primitiven Typen zu tun haben. Sie müssen sich jedoch nicht darum kümmern, da sie alle die gleichen Verantwortlichkeiten haben.)

Machen Sie Ihre Methoden, Ihre Klassen, Ihre Module zu einer so klar definierten Rolle im Leben. Es reduziert die Menge, die Sie sofort verstehen müssen, und ermöglicht es Ihnen wiederum, ein großes System zu entwerfen und zu warten.

Donal Fellows
quelle