DanLevy.net

Hüte dich vor den Ein-Zweck-Menschen

So rein, dass es wehtut

Das Single Responsibility Principle ist eine jener Ideen, die so vernünftig klingen, dass sie an deinem Urteilsvermögen vorbeirutschen können.

Mach eine Sache. Mach sie gut. Halte Module fokussiert. Gib Code einen Grund, sich zu ändern. Guter Rat.

Dann verwandelt jemand diesen Rat in ein Maßband und verkündet, jede Funktion über fünf Zeilen sei ein Code Smell.

Das Problem ist nicht SRP. Das Problem ist, „klein” als Ersatz für „kohärent” zu behandeln.

An diesem Punkt hast du die Ein-Zweck-Menschen getroffen: Entwickler, die mit Modularität nicht unbedingt falsch liegen, aber nützliche Grenzen mit maximaler Fragmentierung verwechselt haben.

Gewalt in der Softwarearchitektur
Komponenten, Komponenten überall

I. Die nützliche Idee darunter

Das Hinzufügen einer einzigen Checkbox zu einem Formular sollte idealerweise nur eine Datei betreffen. Nicht 8 Dateien über 5 Verzeichnisse verteilt … Ich schaue dich an, React/Redux.

Wenn SRP mit Urteilskraft angewendet wird, hilft es. Code-Einheiten, die auf eine einzelne konzeptuelle Aufgabe fokussiert sind, sind leichter zu verstehen. Tests können Verhalten an einer sinnvollen Grenze ansprechen. Klare Module erleichtern es, einen Teil des Systems zu ändern, ohne den Rest der Anwendung mit in den Raum zu zerren.

Sogar die klassischen Unix-Beispiele sind pragmatischer, als der Slogan vermuten lässt. ls listet Dateien, ja, aber es koordiniert auch Aufrufe wie opendir, readdir, closedir und stat. Die nützliche Einheit ist nicht die kleinstmögliche Operation. Die nützliche Einheit ist die kleinste kohärente Sache, die die Aufgabe löst.

Die ursprüngliche Unix-Philosophie handelte von Komposition und Einfachheit, nicht davon, alles auf eine einzelne Funktion oder Datei zu reduzieren.

Diese Unterscheidung ist wichtig. „Eine Verantwortung” ist nicht dasselbe wie „eine Zeile Verhalten.”

II. Über-Abstraktion: Wenn Einfachheit in Chaos umschlägt

Unser Architekt besteht darauf, dass jede Funktion länger als 5 Zeilen ein ‘Code Smell’ ist. Unsere Codebasis riecht jetzt leicht nach ahnungsloser Verzweiflung.

Der Fehlermodus ist leicht zu erkennen, nachdem er deine Woche bereits verschlechtert hat.

Die Codebasis hat mehr Dateien, aber weniger Form. Jeder Helper hat einen Helper. Jedes Konzept wurde über Ordner verteilt, die nach technischen Rollen benannt sind, statt nach Produktbedeutung. Das Hinzufügen einer Checkbox erfordert das Anfassen einer Komponente, eines Hooks, eines Selectors, einer Action, eines Reducers, einer Konstante, einer Test-Fixture und eines Barrel-Exports, der meist nur existiert, damit die Import-Pfade nicht schuldbewusst aussehen.

Kein Ausweg aus diesem unendlichen Arbeitsmuster
Komponenten, Komponenten überall

Was hat all diese Reinheit gebracht?

Ich habe in den Abgrund von Codebasen gestarrt, in denen ein geradliniges 100-Zeilen-Feature über 15+ Dateien viviseziert wurde, jede ein „reines” kleines Engelchen mit vielleicht ein oder zwei Funktionen. Der kognitive Sprengstoff, zu versuchen, dieses Durcheinander im Kopf zu halten, hat jeden theoretischen Gewinn aus der Trennung völlig zunichte gemacht. Es war nicht einfacher; es war nur verstreut.

III. Der Preis der Perfektion: Auswirkungen auf Entwickler

Wir verbringen mehr Zeit mit Debatten über Dateistruktur und Namenskonventionen als mit dem tatsächlichen Liefern von Features. Ist das Agile?

So chaotisch, dass es an Kunst grenzt
So chaotisch, dass es an Kunst grenzt

Diese pathologische Fragmentierung ist nicht nur ein ästhetisches Problem. Sie verändert, wie Entwickler ihre Aufmerksamkeit einsetzen:

Der Produktivitätsabfluss: Vergiss technische Schulden; dies sind organisationale Schulden, die durch zwanghaftes Verzeichnis-Nesting angehäuft wurden. Jede kleine Anpassung wird zu einer archäologischen Grabung durch Schichten von Abstraktion. Zeit verschwindet im schwarzen Loch von cd .. und grep.

Die Test-Steuer: Statt Vertrauen zu geben, wird die Test-Suite zur Quelle von Reibung. Stunden schmelzen dahin, um Tests zu fixen, die durch triviale Refaktorings gebrochen wurden – Tests, die zu eng an den mikroskopischen Details klebten, die sie eigentlich verifizieren sollten.

Die kognitive Last: Es gibt eine harte Grenze dafür, wie viele getrennte Informationen ein menschliches Gehirn gleichzeitig jonglieren kann. Entwickler dazu zu zwingen, den Programmablauf aus einem Dutzend verstreuter Dateien zusammenzusetzen, behindert aktiv das Verständnis und macht sichere Änderungen schwerer.

IV. Pragmatismus umarmen: Eine praktische Alternative

Ich schlug vor, zwei verwandte Funktionen in dieselbe Datei zu legen. Der Raum reagierte, als hätte ich vorgeschlagen, Staging zu löschen. — Ein sich erholender puristischer Leser

Der Ausweg ist nicht, SRP aufzugeben. Die Antwort ist, es auf der richtigen Bedeutungsebene anzuwenden.

So sieht das in der Praxis aus:

Das Ziel ist nicht theoretische Perfektion, würdig einer PhD-Arbeit; es ist, Code zu schaffen, den deine Kollegen (und das zukünftige Ich) navigieren, verstehen und ändern können, ohne das Gebäude anzünden zu wollen.

Manchmal bedeutet das, eine Datei ist 200 Zeilen lang statt 50. Manchmal holt eine Funktion Daten und transformiert sie leicht. Manchmal hat eine Klasse zwei Verantwortlichkeiten, die so eng gekoppelt sind, dass sie zusammen leben sollten. Wenn es das System insgesamt handhabbarer macht, ist es wahrscheinlich die richtige Entscheidung.

Bleib unerbittlich fokussiert auf die praktischen Fragen:

V. Fazit: Kohärenten und wartbaren Code fördern

Das Single Responsibility Principle ist ein nützliches Werkzeug. Es ist kein Mandat, deine Codebasis zu atomarem Staub zu pulverisieren. Wie jedes Werkzeug hängt sein Wert vom Urteil der Person ab, die es benutzt.

Wenn du also den Ein-Zweck-Menschen begegnest, bereit, Krieg gegen jede Funktion zu führen, die es wagt, drei Zeilen zu überschreiten, atme tief durch. Erinnere dich an die 12-Dateien-Checkbox.

Unser Job ist nicht, theoretisch makellose Schneeflocken-Funktionen zu konstruieren. Unser Job ist, Software zu bauen, die funktioniert, Probleme löst und den nächsten Menschen, der sie anfassen muss, nicht bestraft.

Bleib pragmatisch. Fokussiere auf Ergebnisse. Lass das Streben nach perfekter Reinheit nicht zum Feind von wartbarem Code werden. Deine Vernunft und die Geschwindigkeit deines Teams hängen davon ab.

¹ Die Ironie dabei ist, dass das Erreichen tatsächlicher Ein-Zweckigkeit auf den untersten Ebenen immense Komplexität erfordert, die direkt unter der Oberfläche verborgen liegt.

² Hier geht es um konzeptuelle Reinheit: die Idee, dass eine Funktion logisch nur „eine Sache” tun sollte. Verwechsle das nicht mit dem Konzept der „pure function” aus der funktionalen Programmierung ohne Seiteneffekte, was eine andere, manchmal verwandte Idee ist.