16. Juli 2024 von Milena Fluck
Die Restekiste-Falle: Gefahren von Common-Strukturen in Repositories
Hast du eine Restekiste zuhause? Eine Kiste, bei der du nicht genau weißt, was darin ist. Es könnte alles darin sein. Wenn du nach etwas suchst, dann guckst du definitiv mal in dieser Kiste nach. In der Kiste verknoten sich Dinge leicht. In der Kiste existieren Dinge vor sich hin, die man schon längst wegwerfen wollte. Man braucht ewig, um etwas in dieser Kiste wiederzufinden.
Eigentlich hätte man die Kiste schon längst aufräumen müssen und dann kommt dieser eine Sonntag, an dem man sich vornimmt die Kiste endlich aufzuräumen. Vielleicht geht es euch dann wie mir. Ich mache das alle zwei Jahre. Dann werfe ich die Kiste entweder ganz weg oder stelle sie, so wie sie ist, in den Keller, weil mir das Aufräumen viel zu aufwendig ist, ich ohnehin schon Ersatz für die meisten Inhalte besorgt habe oder mir stattdessen lieber etwas Neues kaufe.
In unseren Repos finden ab und zu auch solche Kisten unter Namen wie „Common“ oder „Shared“ – ob als Suffix, Prefix oder alleinstehend. Im Weiteren fasse ich Ordner, Dateien und andere Ressourcen mit solch generischen Labels als Common-Strukturen zusammen. Diese Begrifflichkeiten wirken wie eine Gebrauchsanweisung, statt einem sprechenden Namen. Wobei mir selten Common-Strukturen begegnet sind, die wirklich nur „Common“-Inhalte beherbergen. Wenn Developer nicht wissen wohin mit etwas, dann ab in die Restekiste. Da es viele unterschiedliche und durchaus berechtigte Meinungen zu diesem Thema gibt, habe ich mich entschieden mit einer neutralen Instanz darüber zu sprechen: ChatGPT.
ChatGPT:
In einen Common-Ordner kommen Dateien und Ressourcen, die mehrfach in verschiedenen Teilen eines Projekts oder einer Anwendung verwendet werden. Der Common-Ordner ist dazu da, redundanten Code zu vermeiden und Wiederverwendbarkeit zu fördern.
Hört sich doch erstmal gut an. Dateien und Ressourcen, die “mehrfach” verwendet werden, kommen in so eine Kiste. Aber, ist etwas “common”, wenn es mindestens zwei benutzen oder alle? Wenn alle es benutzen dürfen oder auch nur eine geschlossene Gruppe? Wenn sie es tatsächlich auch nutzen oder wenn sie es generell nur benutzen könnten, aber es bisher nicht nutzen oder vielleicht sogar niemals nutzen werden?
Wäre es nicht gerade bei Dingen, die ich häufig und vielen Stellen benutzen will wichtig, sie schnell mit Hilfe eines präzisen Namen wiederzufinden? Daher habe ich ChatGPT gefragt, was sie denn in so einer Kiste erwarten würde.
ChatGPT:
Utility-Funktionen und -Klassen:
- Helferfunktionen, die in mehreren Modulen gebraucht werden, wie Formatierungsfunktionen oder Validierungsfunktionen
- Generische Klassen, die mehrfach verwendet werden, wie Basisklassen für bestimmte Komponenten
Konstanten und Konfigurationsdateien:
- Globale Konstanten, wie API-Endpunkte und Konfigurationswerte
- Konfigurationsdateien, die projektübergreifend genutzt werden
Gemeinsame Komponenten und Widgets:
- UI-Komponenten, die in verschiedenen Teilen der Anwendung wiederverwendet werden, wie Buttons oder Formularfelder
- Layout-Komponenten oder Themes, die für eine konsistente Darstellung sorgen
Styles und Assets:
- Gemeinsame CSS-Dateien oder Stile, die in mehreren Bereichen verwendet werden
- Geteilte Bilder, Icons oder andere statische Ressourcen
Dienstprogramme und Bibliotheken:
- Drittanbieter-Bibliotheken oder selbst entwickelte Bibliotheken, die projektübergreifend benötigt werden
- Abstraktionen von externen Diensten oder API-Clients
Tests und Mock-Daten:
- Gemeinsame Testhelfer oder Mock-Daten, die in verschiedenen Testfällen gebraucht werden
Danke. Doch wenn sie mir so genau beschreiben kann, was in einen Common-Ordner gehört, wieso sollte man dann nicht einfach Strukturen erstellen, die genauso heißen und in denen man genau diese Dinge findet? Ich habe zudem schon ganz andere Dinge in Common-Ordnern gefunden. Die Dinge, die ChatGPT hier erwartet, hören sich nach querschnittlichen Lösungen an, die ich in fast jedem Software-System vorfinde. Ich habe also noch ein bisschen weiter mit ChatGPT philosophiert und wir kamen zum selben Schluss, dass Common-Strukturen schnell missverstanden werden können.
ChatGPT:
Unklare Begrenzung der Inhalte: Man könnte denken, dass alles, was mehrfach verwendet wird, in den Common-Ordner gehört, was zu einem überfüllten und unstrukturierten Ordner führen kann.
- Missverständliche Namensgebung: Der Begriff "Common" ist sehr allgemein und könnte von Entwicklern unterschiedlich interpretiert werden.
- Fehlende Dokumentation: Ohne Dokumentation könnte es unklar sein, welche Dateien im Common-Ordner vorhanden sind und wie sie verwendet werden sollen.
- Verwirrung über Verantwortlichkeiten: Es könnte unklar sein, wer für die Wartung und Pflege der Inhalte im Common-Ordner verantwortlich ist.
ChatGPT präsentierte mir zu jedem Problem auch eine Lösung. Zum einen die Empfehlung klare Richtlinien zu definieren, was in diese Kiste gehört. Zum anderen soll ich eine README-Datei erstellen, die Zweck und Inhalt des Ordners enthält. Ich soll Verantwortlichkeiten definieren – also einen Maintainer oder ein ganzes Team benennen, das für die Common-Kiste verantwortlich ist. Diesen Tipp fand ich zudem besonders interessant:
ChatGPT: Verwenden Sie spezifischere Namen wie "shared", "utils", "components", "assets", je nach Art der Dateien, die dort gespeichert werden. Das schafft mehr Klarheit.
Ich glaube an der Stelle wurde mir klar, dass ChatGPT und ich keinen gemeinsamen Konsens zum Thema Klarheit erreichen würden. Wenn es so viele Hilfestellungen Bedarf, um etwas zu erklären, ist das dann wirklich der richtige Ansatz? ChatGPT hält aber weiterhin an Common-Strukturen wie einem Common-Ordner fest:
ChatGPT: Ein gut organisierter Common-Ordner hilft, den Code sauber und wartbar zu halten, indem er redundante Implementierungen vermeidet und die Wiederverwendbarkeit von Code fördert.
Zum einen versteckt ChatGPT hier dezent die Vorbedingung “gut organisiert”. Zum anderen: spricht ChatGPT wirklich von einem Common-Ordner oder meint sie in Wirklichkeit Abstraktion? Abstraktion zielt darauf ab allgemeine Schema zur Lösung eines Problems abzuleiten und zu generalisieren. Diese Schema können an einer zentralen Stelle liegen, wodurch sie die Codebasis nicht belasten, es nur eine Wartungsstelle gibt und sie im besten Falle wiederverwendbar sind. Diese “zentrale Stelle” ist dann oft eine Common-Struktur. Abstraktion bietet uns zudem Vorteile beim eindeutigen Labeln von Dateien, Klassen und anderen Bausteinen.
The purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise.
Edsger W. Dijkstra
Wenn ich es schaffe eine konkrete Beobachtung – ein Schema – aus einer speziellen Implementierung zu extrahieren, dann gibt mir das die Möglichkeit dieses Schema genau zu benennen. Es konnte extrahiert werden und versteckt sich nicht mehr in anderen Konstrukten, die unter ganz anderen beispielsweise eher fachlich getriebenen Namen geführt werden. Begriffe wie “common”, “tools” oder “shared” sind das Gegenteil einer präzisen Benennung.
Nach mehreren unglücklichen Langzeitbeziehungen mit Common-Strukturen durfte ich 2022 selbst eine Frontend-Struktur mitgestalten und habe mir vorgenommen „Common“ oder „Shared“ im oder als Label zu vermeiden. Das haben wir auch durchgezogen und es hat tatsächlich funktioniert. Common-Strukturen lösen – wenn “gut organisiert” - das Problem der zentralen Ablage von abstrakten und querschnittlichen Lösungen, die von verschiedensten Konsumenten genutzt werden oder genutzt werden können. Dennoch bergen sie Gefahren, die den Mehrwert übersteigen können. Welche Möglichkeiten neben dem Schaffen von Common-Strukturen haben wir nun, um dennoch die genannten Ziele zu erreichen?
Ziel: Gemeinsam genutzte Dateien und Ressourcen zentral ablegen
Eröffne mehr und dafür kleinere Kisten: Keiner hat gesagt, dass alle gemeinsam genutzten Ressourcen in einem Ordner liegen müssen. Statt einer großen Common-Kiste, empfehlen professionelle Organizer viele kleine Kisten, die sich beliebig aufeinander, nebeneinander oder ineinander stapeln lassen. Dabei hat jede Kiste ihr eigenes und ganz eindeutiges Label. Wenn ein neues Teil in keine der vorhandenen Kisten passt, wird es Zeit neu zu denken, umzustrukturieren oder eine neue Mini-Kiste zu eröffnen. Diese Kisten kann man nun natürlich hinter einer Common-Fassade verstecken - das bedeutet dann eben immer nur einen Klick mehr.
Ziel: Zugriffsrechte regeln – Common ist für alle da?
Einen Ordner “Common” oder “Shared” zu nennen und andere nicht, schützt in der Praxis selten vor ungewünschten Zugriffen. Wenn ihr alles in kleinere Kisten gepackt habt, wird es sogar noch viel einfacher spezifische Zugriffsrechte zu vergeben. Es ist nicht die Benennung, die Hinweise auf die möglichen Einsatzgebiete gibt, sondern Dokumentationen inklusive Modelle, die uns Strukturen erklären und Regeln, die anschlagen, wenn wir Ressourcen außerhalb des definierten Verwendungsbereichs nutzen. Tools, die uns dabei unterstützen, sind beispielsweise Module Boundaries in Nx oder Spring Modulith.
Common-Strukturen sind die stillen Räume einer Screaming Architecture. Sie geben den Lesern selten weitere Informationen und lassen den Interpretationsspielraum offen. Was gut sein kann, jedoch einzelnen Teammitgliedern viel Verantwortung gibt. Sie müssen selbstständig interpretieren und entscheiden, was das Label zu bedeuten hat. Allein das Label auf einer Kiste schränkt den Raum für Interpretation ein.
It holds everybody accountable - and that’s the item that should live in that bin, nothing else.
The Home Edit
Haben alle Teammitglieder eine genaue Vorstellung und gemeinsame Definition, was sie in dieser Kiste finden und was hier abgelegt werden darf, kann das sicher funktionieren. Ob im Haushalt oder unseren Repos Bedarf das erhöhter Kommunikation, Vertrauen und/oder Kontrolle. Es gibt sicher Teams, die ihre Common-Strukturen unter Kontrolle haben und gut kennen. Dennoch sollte weder „Common“ noch „Shared“ ein Label sein, dass man um ein Sammelsurium aus Resten bindet, die nirgendwo sonst so richtig reinpassen. In diesem Fall sind Restekisten eher das Resultat aus der Müßigkeit sich mit dem Inhalt der Kiste auseinanderzusetzen, zu strukturieren und passende Labels zu finden. Wenn man eine solche Restekiste in sein Repo packt, dann darf man sich nicht wundern, wenn die KollegInnen dort auch Dinge hineinwerfen. Stellt euren Kollegen also nicht die Restekiste-Falle.
Ihr möchtet gern mehr über weitere spannende Themen aus der adesso-Welt erfahren? Dann werft auch einen Blick auf unsere bisher erschienenen Blog-Beiträge.