Richtig klein: Hat Modularisierung versagt?

Modularisierung war angetreten, die Komplexität zu verringern, aber oft tritt das Gegenteil ein. Es gäbe jedoch einen Ausweg aus dem Dilemma.

In Pocket speichern vorlesen Druckansicht 164 Kommentare lesen
Lesezeit: 13 Min.
Von
  • Felix von Leitner
Inhaltsverzeichnis

Wer sich aktuelle Software anschaut, findet in der Regel riesige Konstrukte, deren Komplexität die mentalen Leistungskapazitäten einer einzelnen Person übersteigen. Häufig haben die Produkte unzählige bekannte Probleme und offene Bugs, die schließlich zu Sicherheitslücken und damit zu potenziellen Einfallstoren für Angriffe werden.

Wer daraufhin den Anbieter wechselt, stellt am Ende häufig ernüchtert fest, dass das andere Produkt genau so schlecht ist, und sich der Umstieg nicht gelohnt hat. Wieso liefern Softwarehersteller keine bessere, fehlerarme und sicheren Produkte aus, damit ihre Kunden zufrieden sind? Um das zu klären, hat sich der Autor dieser Zeilen mit großen und kleinen Softwareherstellern unterhalten und stieß dabei auf eine vielleicht überraschende Erkenntnis: Innerhalb der Softwarehersteller herrscht dieselbe Unzufriedenheit.

Die Softwarehersteller haben sich im Innenverhältnis in für sie unauflösbare Abhängigkeiten von bekannt schwachen oder schlechten Modulen begeben, die sie häufig sogar selbst geschrieben haben, aber aus deren Gravitation sie sich nicht befreien können. Die Entwickler und Ingenieurinnen in den großen Firmen sind häufig selber unzufrieden mit der Qualität des Produkts.

Das erinnert an die berühmte Szene aus "The Matrix", in der Agent Smith erklärt, man habe es ja mit paradiesischen Simulationen probiert, aber die Menschheit stehe halt auf Schmerz, Elend, Entbehrung und einen endlosen Überlebenskampf. Ganz so schnell sollte man die Flinte aber nicht ins Korn werfen. Vielleicht gibt es ja doch noch Grund zur Hoffnung!

Früher war alles ganz einfach: Echte Programmierer und Programmiererinnen schrieben echte Software, die konkrete Aufgaben erfüllte. Das Elend ging los, als jemandem auffiel, dass man die Software durchaus wiederverwerten könnte.

Als Schlussfolgerung kann die Software ihre Parameter als Eingabe einlesen, statt als Konstanten hart in den Quellcode kodierte Werte zu verwenden. Eine Kommandozeile oder Konfigurationsdatei zu parsen ist Routinearbeit, die ein Praktikant erledigen kann. Dafür muss keine hochbezahlte Spezialistin für Differenzialgleichungen ans Werk. Dieser vermeintlich einfache Gedankengang macht aus einem Problem vier:

  1. Wenn der Code wiederverwendet wird, braucht er Wartung.
  2. Wenn jemand anderes den Code für das Einlesen der Parameter schreibt, braucht es Abstimmung zwischen den Entwicklerinnen und Entwicklern, im Idealfall in Form eines expliziten Kontrakts. Unter Kontrakt versteht man in der Softwareentwicklung die Vor- und Nachbedingungen. Die Funktion erwartet von ihrem Aufrufer, dass er Vorbedingungen erfüllt, und dafür sagt sie dem Aufrufer zu, ihre Arbeit zu erledigen, sodass die Nachbedingungen erfüllt sind. Wenn Anne bei Ben die Funktion aufrufen will, dann muss sie vorher jene Initialisierungsroutine aufgerufen haben.
  3. Wenn etwas nicht funktioniert, ist ein Prozess für die Fehlersuche erforderlich, der Schuldzuweisungen und Streit um Zuständigkeiten vermeidet. Da zudem alle nur ihre Hälfte des Programms kennen, braucht es Vertreter beider Seiten.
  4. Die Komplexität des Codes übersteigt das kognitive Limit der Einzelnen. Aussagen über das Programm lassen sich nur experimentell treffen, nicht mehr deduktiv.

Die vier aufgeführten Schwierigkeiten haben weitere Untiefen an Bord. Wartung kostet Zeit und Geld und Teams müssen dafür Personal vorhalten, das sich mit der Herausforderung und dem Code auskennen muss. Firmen wollen Geld sparen, und die Zeit des spezialisierten Personals ist wertvoll. Menschen wollen sich weiterentwickeln und wechseln dafür die Abteilung oder die Firma oder sie gehen in den Ruhestand. Damit geht ihr Wissen verloren.

Ein expliziter Kontrakt ist nur hilfreich, wenn sich beide Seiten bedingungslos daran halten, und das weiß man erst wirklich, wenn man ordentlich getestet hat. Das kostet noch mehr Zeit und Aufwand.

Besonders schwer wiegt Punkt 4, und einige Anreizsysteme in Organisationen verschärfen das Problem zusätzlich. Eine große Sorge in der Softwareentwicklung ist, dass ein Stück Code existiert und diejenigen, die ihn verstehen, das Unternehmen verlassen haben. Zahlreiche Organisationen haben dieses Szenario bereits erlebt. Sei es durch die Pleite eines Zulieferers oder einen Teil der COBOL-Software der Bank, der so alt ist, dass alle Entwickler in den Ruhestand gegangen sind.

Daher sollten Organisationen immer als Mindestanforderung dafür sorgen, dass kein Stück Code von einer einzelnen Person entwickelt wird, sondern immer ein Team mit mindestens drei Personen verantwortlich ist. Wenn allerdings mehrere an einem Modul arbeiten, wird das Management automatisch mehr Arbeit zuweisen als für eine Einzelperson. Das führt in der Praxis zu erhöhter Komplexität und damit zu Punkt 4, der auf Modulebene statt auf Ebene des Gesamtprojekts auftritt.

Das führt zu dem Schluss, dass die Modularisierung häufig genau dem Problem erliegt, das zu lösen sie antrat. Mit anderen Worten: Wenn Modularisierung funktionieren soll, müssen die Module so klein sein, dass nicht nur das verantwortliche Team, sondern alle Einzelnen es verstehen.

Allerdings gibt es auch bei dem Vorgehen genügend Stolperfallen, die letztlich den Zug entgleisen lassen.

Ein Team von Dreien wird die Arbeit unter sich aufteilen. Jeder spezialisiert sich auf einen Teil der Aufgabe und kennt nur den Code für den eigenen Teil gut. Wenn in dem Code des Teams etwas kaputtgeht, kann meist ausschließlich die zuständige Person effektiv helfen.

Hinzu kommen psychologische und soziale Schranken: Sich in fremden Code aufzuhalten, fühlt sich ähnlich an, wie im Wohnzimmer eines Freundes zu sein. Dabei käme niemand auf die Idee, die Wohnung umzudekorieren. Offensichtliche Schwachstellen wie ein schiefes Bild mögen dazu einladen, sie zu beheben. Das kann jedoch nach hinten losgehen, wie der wunderbare Loriot-Sketch "Das schiefe Bild" illustriert.

Wenn ein Detail im Code merkwürdig aussieht, geht man zunächst davon aus, dass sich der Verfasser der Zeilen etwas dabei gedacht hat, und man als Beobachter schlicht den notwendigen Kontext nicht hat, um die Hintergründe zu erkennen.

In der Praxis führt das gerne dazu, dass bei der Wartung die Logik nicht angefasst wird, weil das Wartungspersonal Angst hat, mehr Schaden anzurichten. Stattdessen ist es Usus, am Anfang Code einzufügen, der den Fehler abfängt und separat abhandelt. Das erhöht die kognitive Last des Codes zusätzlich. Im schlimmsten Fall fühlt sich der ursprüngliche Verfasser des Codes durch die Strukturänderungen wie in einem fremden Wohnzimmer – mit den besprochenen Auswirkungen.