Da Du diesen Text hier liest, bist Du offensichtlich genau so ein Nerd wie wir. Komm zu uns und bewerbe Dich bei ///\/ DevBoost: https://devboost.com/karriere (https://api.devboost.de)
Komplexität in Softwareprodukten

Komplexität in Softwareprodukten - und wie man damit umgeht

21.04.2022 / Mirko Seifert

In unserer Rolle als Entwicklungspartner für Softwareproduktfirmen begleitet uns das Thema Komplexität permanent. Die meisten Softwarehersteller entwickeln und pflegen sehr große, heterogene Softwaresysteme. Das liegt in der Natur der Sache: Einfache Probleme können oft mit Standardwerkzeugen (z. B. MS Excel) gelöst werden. Softwareprodukte etablieren sich dort wo Domänen umfangreich sind, fachliche Abläufe nicht mehr mit ein paar Tabellen abgebildet werden können oder sehr viele Nutzer beteiligt sind. Dementsprechend wachsen die Softwareprodukte mit ihren Anforderungen über die Zeit. Die Code-Basis wird oft über Jahrzehnte immer größer – teilweise hin zu Größenordnungen, die fast einem modernen Betriebssystem entsprechen.

Auch die Verteilung dieser Softwareprodukte (z. B. in Public Cloud Umgebungen) kann heutzutage einen Grad der Komplexität erreichen, der seine ganz eigenen Herausforderungen mit sich bringt. Zu wissen, welcher Teil der Software wo und für welchen Kunden, in welcher Version läuft oder wo welche Fehler auftreten, ist oft nicht aus dem Stegreif zu beantworten.

Kurzum, ein Umgang mit Komplexität ist für jedes ernsthafte Softwareprodukt unausweichlich. Das zeigt sich nicht nur in der täglichen Arbeit mit unseren Kunden – es ist auch eine der zentralen Herausforderungen, wenn man nachfragt, womit Softwareprodukthersteller heute kämpfen. Das Beherrschen der ständig wachsenden Komplexität beschäftigt alle.

Das möchten wir zum Anlass nehmen und kurz schildern, wie wir als Unternehmen auf das Thema blicken. Aber auch, welche Möglichkeiten es gibt Komplexität zu erkennen, zu bewerten, zu beherrschen und bis zu einem gewissen Grad damit zu leben.

Fachliche und technische Komplexität

Zuallererst müssen wir zwischen zwei Arten von Komplexität unterscheiden – fachlicher Komplexität und technischer Komplexität:

Jeder Product Owner hat damit zu kämpfen, unterschiedlichste Anforderungen unter einen Hut zu bringen. Selbst Nutzer in der exakt gleichen Domäne haben verschiedene Vorstellungen und heterogene Prozesse. Dazu kommen projektspezifische Erweiterungen oder kundenspezifische Anpassungen. Ein Softwareprodukt generisch zu gestalten und gleichzeitig auf die Bedürfnisse aller Nutzer einzugehen ist immer eine Zerreißprobe. So entsteht automatisch in Bezug auf die Fachlichkeit eine inhärente Komplexität. Je nachdem, wie eng der Fokus für das Softwareprodukt gesetzt ist und wie heterogen die Bedürfnisse der Anwender sind, kann diese fachliche Komplexität natürlich von Fall zu Fall variieren.

Im Gegensatz zum Product Owner steht der CTO oder der Softwarearchitekt vor der Herausforderung, die technische Umsetzung des Produktes möglichst einfach zu gestalten, aber gleichzeitig so schnell wie möglich Features zu liefern. Auch das ist eine Zerreißprobe. Software im Eiltempo zu erstellen, um die Zeit bis zur Markteinführung neuer Funktionen so kurz wie möglich zu halten, und gleichzeitig eine saubere, homogene Architektur zu erzielen, stellt selbst die besten CTOs und Architekten vor Herausforderungen.

Die Unterscheidung zwischen fachlicher und technischer Komplexität ist aus unserer Sicht wichtig, weil die fachliche Komplexität sehr stark von außen bestimmt wird. Ein Softwareprodukthersteller hat hier also signifikant weniger Einfluss als in Bezug auf die technische Komplexität. Einen wichtigen Nutzer davon zu überzeugen, dass er auf bestimmte Features verzichten muss, ist im Allgemeinen wesentlich schwieriger als Entwickler davon zu überzeugen technische Komplexität zu beseitigen.

Wie entsteht technische Komplexität?

Fokussieren wir uns also auf die technische Komplexität – denn dort hat man als Softwarehersteller mehr Einfluss. Hier stellt sich die Frage nach den Ursachen, und wie diese Art von Komplexität entsteht. Aus unserer Sicht sind die Ursachen sehr vielfältig.

Softwareentwickler lieben neue Tools und neue Frameworks und führen diese auch oft ein, ohne die Kosten, die dadurch in der Zukunft entstehen, im Detail zu berücksichtigen. So entstehen heterogene Toollandschaften und ein Mix verschiedener Frameworks, der später nur mühsam aufgelöst werden kann. An anderen Stellen entstehen Altlasten durch die Integration von Fremdcode - der Kollege baut einen Prototyp und dieser wird direkt ins Produkt eingebaut.

Gerade wenn Entwickler lange an dem gleichen Produkt arbeiten, stellt sich eine gewisse Betriebsblindheit ein. Die Workarounds und unschönen Stellen werden gemieden oder mit Spezialwissen geschickt umschifft – ein Luxus, den neue Entwickler nicht haben, weil ihnen die Erfahrungen mit den Eigenheiten der Code-Basis fehlt. In Kombination mit Mitarbeiterfluktuation kann dies zu ernsthaften Problemen führen. Wenn jeder Entwickler seinen eigenen Stil und seine eigenen Konzepte in ein Produkt einführt, entsteht zwangsläufig ein unübersichtliches Konstrukt.

Da technische Designs sich auch immer an den fachlichen Anforderungen orientieren, können wechselnde Produkt-Roadmaps oder sich häufig ändernde Kundenanforderungen ebenfalls dazu beitragen, dass eine anfangs saubere technische Umsetzung immer komplexer und unübersichtlicher wird.

Nicht selten haben die Entwickler aber auch einen gewissen Hang zum sogenannten „Overengineering“ und führen technische Komplexität unnötiger Weise ein. Oft geschieht das mit guten Absichten („Wir bauen das hier gleich etwas generischer, dann haben wir es in Zukunft einfacher“), führt aber trotzdem zu unnötig komplexen Strukturen.

Es gibt sicher noch viele weitere Gründe, die man hier aufzählen kann, aber im Kern kann man sagen, dass sich unnötige technische Komplexität nie von vornherein vermeiden lässt. Oft ändern sich Annahmen oder Anforderungen und technische Entscheidungen, die mit bestem Wissen getroffen wurden und sind dann einfach nicht mehr passend für das Produkt.

Komplexität bewerten

Zu erkennen, dass das eigene Softwareprodukt unnötige technische Komplexität besitzt, ist ein erster Schritt in die richtige Richtung. Wenn man aber Teams in Softwareproduktfirmen befragt, an welchen Stellen solche Komplexität genau verortet ist, so zeigen die wenigsten Teams auf genau einen Punkt. Oft gibt es eine Vielzahl von Baustellen, die man angehen müsste.

Da die Arbeit an genau diesen Baustellen aber nur indirekten Nutzen für die Nutzer des Softwareprodukts hat, müssen solche Arbeiten möglichst fokussiert und zielgerichtet sein. Statt alle Baustellen gleichzeitig zu bearbeiten, bleibt nichts anderes übrig als sich die Wichtigste zuerst vorzunehmen. Und um genau diese wichtigste Baustelle zu bestimmen, müssen das Ausmaß der Komplexität und die negativen Auswirkungen erst einmal beziffert werden.

Aus unserer Erfahrung heraus muss das nicht zwangsläufig mit exakten mathematischen Methoden geschehen. Ein gutes Team und ein guter Product Owner sind typischerweise in der Lage ihre größten Schmerzpunkte zu identifizieren. Darüber hinaus hilft hier oft ein Blick von außen, um der oben genannten Betriebsblindheit entgegenzuwirken.

Komplexität beseitigen

Sind die wichtigsten Baustellen oder Bereiche im Produkt mit der höchsten unnötigen Komplexität identifiziert, so muss ein Plan zur Beseitigung her. Das ist nicht immer ganz einfach, denn es handelt sich oft um Strukturen, die tief in das Produkt hineingewachsen sind, Code-Teile, die an vielen Stellen verwendet werden oder Muster die vielfach repliziert wurden. Es handelt sich also um eine technisch sehr anspruchsvolle Arbeit – keine einfache Aufgabe.

Nicht selten sind die entsprechenden Strukturen so stark mit dem Code verwachsen, dass ein Entfernen nur in einer „Big Bang“ Aktion möglich ist. Ein langsames, schrittweises Bearbeiten der Baustelle (zum Beispiel neben der normalen Feature-Entwicklung) scheint unmöglich. Darum scheitern solche Aufräumarbeiten auch regelmäßig. Die einfachen Aufräumarbeiten, die in kleinen Schritten möglich waren, hat oft schon jemand erledigt.

Wie bekommt man also dieses Thema als CTO oder Architekt in den Griff? Aus unserer Sicht helfen hier: klare Planung (sowohl zeitlich als auch in Bezug auf das notwendige Budget) und der Einsatz eines „Spezialteams“, welches nur an genau einer technischen Aufräumaktion arbeitet. Kurze konzentrierte Aktionen sind oft effektiver als monatelange kleinteilige Umbauarbeiten.

Mit Komplexität leben

Bei allem Willen zur Beseitigung unnötiger technischer Komplexität, müssen wir aber auch lernen zu einem gewissen Maß damit zu leben. Die Ursachen sind so vielfältig und teilweise schwer vermeidbar, dass immer technische Komplexität entstehen wird. An vielen Stellen ist das unter Umständen auch kein Problem. Erst wenn die Produktentwicklung leidet, zum Beispiel weil Features zu langsam geliefert werden oder die notwendige Flexibilität fehlt, um auf Kundenwünsche einzugehen, ist dringend Abhilfe geboten. Kein Produktteam kann die gesamte unnötige technische Komplexität beseitigen. Das ist ökonomisch weder sinnvoll noch möglich.

In unserer Rolle als Entwicklungspartner für Softwareproduktfirmen begleiten wir Teams bei genau diesen Fragen und helfen unseren Kunden das Thema aktiv anzugehen. Letztendlich lebt jedes Softwareprodukt davon, neue Funktionen auszuliefern. Die Reduktion technischer Komplexität kann hier Wunder wirken.

Den nächsten Schritt machen

Wenn Du Dich darüber austauschen willst, welche Faktoren für Schnelligkeit und Flexibilität in der Softwareproduktentwicklung sorgen, dann vereinbare jetzt einen Beratungstermin: hier klicken.