Im Zeitalter der Digitalisierung und der Industrie 4.0 nimmt Software eine immer größere Rolle ein. So auch im traditionell Hardware-geprägten Maschinen- und Anlagenbau. Kenntnisse über Softwarearchitektur und Softwareentwicklung sind längst zu einer grundlegenden Kompetenz in allen Industrieunternehmen geworden und der Anteil der Ressourcen, die für die Softwareentwicklung aufgewendet werden, wächst stetig weiter.
Gleiches gilt für die Komplexität von Softwaresystemen. Einer jüngsten Studie von McKinsey zum Thema Software in der Automobilindustrie zufolge hat sich der Komplexitätsgrad der Software im letzten Jahrzehnt vervierfacht. Das Problem: Die Produktivität der Softwareentwicklung bleibt hinter der steigenden Komplexität zurück, da zu viele Ressourcen auf das Verwalten und Erhalten bestehender (komplexer) Softwaresysteme verwenden werden müssen. Um dem entgegenzuwirken sind grundlegende Veränderungen bei der Entwicklung und dem Testen von Software notwendig.
Viele Unternehmen machen den Fehler, die Softwareentwicklung hinauszuzögern, bis das Enddesign des Hardwareproduktes feststeht. Hierbei bleibt häufig nur wenig Zeit für Entwicklung und Testen der Softwareanteile. So erhöht sich das Risiko, dass die Software bei Markteinführung nicht den an sie gestellten Qualitätsanforderungen entspricht. Agile Methoden können dem vorbeugen, indem sie kontinuierliche Feedbackschleifen in den Entwicklungsprozess integrieren und diesen so effizienter machen.
Eine gesteigerte Testeffizienz kann dazu beitragen, die Kosten und notwendigen Vorlaufzeiten für Softwaretests und die damit verbundene Fehlerbehebung erheblich zu reduzieren. Erreicht werden kann das durch automatische Tests, die zusätzlich zu den finalen Systemtests auf Ebene der einzelnen Softwaremodule durchgeführt werden. Im folgenden Blog-Beitrag werden wir Ihnen zeigen, wie Modularisierung Ihnen helfen kann, ihre Softwareentwicklung schneller und effizienter zu machen.
Mit den Prinzipien eines Baukastensystems zur modularen Softwarearchitektur
Bevor wir uns im Detail ansehen, wie Modularisierung im Softwarebereich die Qualität und Geschwindigkeit des Entwicklungsprozesses erhöhen kann, werden wir uns zunächst mit der Frage beschäftigen, wie die Prinzipien eines modularen Baukastensystems auf Software übertragen werden können.
Im Unterschied zu einer traditionell monolithischen Softwarearchitektur bündelt eine modulare Softwarearchitektur die verschiedenen Funktionen nicht in einem zentralen System, sondern teilt diese auf verschiedene Softwaremodule auf. Ein Softwaremodul ist dabei als Teil des Codes definiert, welches unabhängig vom restlichen Programmcode entwickelt (Entkopplung) und flexibel in verschiedenen Softwaresystemen eingesetzt werden kann (Kombinierbarkeit).
Leseempfehlung: Lesen Sie mehr über die Grundlagen der Modularisierung in unserem ausführlichen Blog-Artikel “Alles, was Sie zu Modularisierung wissen müssen”.
Die folgende Grafik vergleicht ein monolithisches System, das alle Funktionalitäten abdeckt, mit einer Micro-Service-Architektur, bei der die Funktionalitäten in mehrere Micro-Services aufgeteilt sind (Quelle: https://dev.to/).
Neben den Prinzipien der Entkopplung und Kombinierbarkeit müssen Softwaremodule auch zwei weitere Kernprinzipien der Modularisierung erfüllen: Zum einen müssen sie über eine stabile Schnittstelle verfügen - um diese möglichst passend zu definieren, müssen verschiedene Aspekte wie API-Strategie und Skalierbarkeit berücksichtigt werden - und zum anderen sollte jedes Softwaremodul eine strategische Funktion erfüllen. Wir sprechen in diesem Zusammenhang auch von strategischen Softwaremodulen.
Leseempfehlung: Mehr zum Thema modulare Softwarearchitektur lesen Sie in unserem Beitrag “Digitalisierung und Industrie 4.0 - Mit modularer Maschinensoftware”.
Um strategische Softwaremodule zu definieren, gilt es zu entscheiden, welche Produktfunktionen sich am besten in welchem Modul verankern lassen, sodass notwendige funktionale Änderungen sich nach Möglichkeit auf eine einzige Komponente beschränken und nur eine Fachabteilung involviert werden muss. Außerdem sollten auch bei der Modularisierung von Softwarearchitekturen unternehmensstrategische Aspekte berücksichtigt werden, z.B. zu erwartende zukünftige Änderungen am Portfolio zur Erschließung neuer Kunden.
Neben dem Testen auf Systemebene wird mit einer modularen Softwarearchitektur auch das Testen auf Modulebene möglich. Bei der Softwareentwicklung spricht man hier von sogenannten Modul- oder Komponententests (unit testing), bei denen lediglich ein ausgewählter Codeabschnitt getestet wird, bevor auf der nächsten Teststufe, dem sogenannten Integrationstest, das Zusammenspiel mehrerer Module untereinander getestet wird.
Die Vorteile von Modularisierung für die Effizienz und Qualität von Softwaretests wollen wir nun genauer untersuchen und dabei folgende Aspekte betrachten:
- Testautomatisierung und frühzeitige Fehlererkennung
- Qualitätsverbesserung durch Continuous Integration
- Optimierung des Testaufwands dank stabiler Schnittstellen
- Verringerter Blast-Radius durch Isolierung von Fehlern in einzelnen Softwaremodulen
Modularisierung ermöglicht Testautomatisierung und frühzeitige Fehlererkennung
Im traditionell in der Softwareentwicklung verwendeten V-Modell folgt auf eine lange Entwicklungsphase eine ebenso lange und langwierige Testphase des entwickelten Softwaresystems, bei der überprüft wird, ob alle zu Beginn des Projekts gesammelten Systemanforderungen korrekt berücksichtigt wurden. Das Problem hierbei: Wird ein Fehler erst spät in der Softwareverifizierung gefunden, können zwischen Entwicklung und Fehlerbehebung unter Umständen mehrere Wochen oder sogar Monate liegen, was wiederum dazu führt, dass die Problembehebung länger dauert, weil die zuständigen Entwickler sich erst wieder in den Kontext einarbeiten müssen.
Eine Möglichkeit, das zu verhindern, ist das frühzeitige Einbinden von automatisierten Modultests in den Entwicklungsprozess. Je früher getestet wird, desto schneller und effizienter erfolgt die Fehlerbehebung und desto reibungsloser ist der gesamte Entwicklungsprozess. Das hat mehrere Gründe:
- Da weniger Zeit zwischen dem letzten erfolgreichen Test und dem neuen fehlerhaften Testlauf liegt, hält sich die Anzahl der vorgenommenen Modifikationen in Grenzen, was es für die Entwickler einfacher macht, die Ursache zu identifizieren.
- Unmittelbar nach dem Fertigstellen des neuen Softwaremoduls zu testen bedeutet, dass der beteiligte Entwickler noch nicht in einem neuen Projekt steckt und sich mühsam an länger zurückliegende Arbeiten zurückerinnern muss.
- Der Prozess kann innerhalb der F&E-Abteilung durchgeführt werden, was die Kommunikation effizienter und einfacher macht.
- Der Fehler ist lediglich auf die F&E-Systeme beschränkt.
Die Automatisierung der Tests führt außerdem dazu, dass die Kapazitäten der Entwickler für wichtigere Aufgaben genutzt werden können.
Ein weiterer Grund, der für ein frühzeitiges Testen von Softwaremodulen spricht, ist die Tatsache, dass Fehler und Qualitätsmängel schnell den Ruf des Unternehmens schädigen können, sobald sie einmal unentdeckt bis zum Endkunden gelangen.
Neben der enormen Zeitersparnis, die Komponententests bei der Softwareentwicklung erlauben, lassen sich die Auswirkungen der Modularisierung bei Softwaretests auch konkret in Form der erzielten Kostenersparnis quantifizieren. Wie die nachfolgende Grafik zeigt, ist es in der Regel mindestens zehnmal teurer, einen Fehler in einem Systemtest als in einem Modultest zu finden.
Dieser Faktor wird umso bedeutender, wenn man bedenkt, dass das Testen von Software den größten Kostenpunkt im Entwicklungsprozess darstellt. Außerdem erlauben Modultests eine höhere Testabdeckung als Systemtests und bei Vorliegen einer stabilen Schnittstelle können die Tests mit der Zeit stetig verbessert werden.
Continuous Integration: Mit Modularisierung frühzeitig Integrationsprobleme in der Software erkennen
Im vorherigen Abschnitt wurden die positiven Effekte von frühzeitigen Tests und der Identifikation und dem Beheben von Fehlern auf Modul- und Komponentenebene beschrieben. Aber auch wenn alle einzelnen Softwaremodule für sich genommen fehlerfrei funktionieren, kann es bei der Integration zu unerwarteten Fehlern durch das Zusammenspiel verschiedener Module kommen.
Die Herausforderung für die Entwickler ist hier ähnlich wie zuvor auf Modulebene beschrieben. Wird der Integrationstest final nach der Entwicklung einer Vielzahl von Komponenten durchgeführt, ist die Erkennung und das Beheben von Fehlern häufig kompliziert und zeitintensiv, da die Quelle des Fehlers meist nicht offensichtlich ist.
Eine immer weiter verbreitete Strategie, um Qualität und Effizienz bei der Integration und den damit einhergehenden Tests zu verbessern, ist der Continuous Integration-Ansatz (zu Deutsch: kontinuierliche Integration). Hierbei werden Systemintegration und Systemtests in jedem Schritt, häufig voll- oder teilautomatisiert, vorgenommen, um kürzere Feedbackschleifen und leichtere Fehlerbehebung zu ermöglichen.
Dabei werden nicht nur Probleme bei einzelnen Funktionen, sondern auch bei der Integration in das System erkannt. Das kontinuierliche Testen über den Entwicklungsprozess hinweg erhöht sowohl die Testqualität als auch die Qualität der Software selbst. Es hat sich hierbei bewährt, dass Test und Code von unterschiedlichen Entwicklern geschrieben werden.
Modularisierung optimiert den Testaufwand dank stabiler Schnittstellen
Zu Beginn des Artikels haben wir gesehen, dass Modultests erheblich dazu beitragen, die Gesamtkosten zu senken, die im Zuge der Softwaretests und der Fehlerbehebung entstehen. Doch auch das Aufsetzen und Anpassen von Modultests kostet Geld. Für jedes Modul muss ein passender Test entwickelt werden. Ändert sich das Modul, muss auch der Test entsprechend angepasst werden. Daher ist es umso wichtiger, bei der Definition der einzelnen Softwaremodule sorgfältig vorzugehen, um eine maximale Effizienz bei der Testerstellung zu erreichen.
Hier kommen die anfangs vorgestellten Prinzipien eines modularen Baukastensystems ins Spiel: stabile Schnittstellen und ein strategisches Vorgehen bei der Definition der Softwaremodule. Um qualitativ hochwertige, automatisierte Modultests zu entwickeln, muss gewährleistet sein, dass die Modulschnittstellen über längere Zeiträume hinweg stabil sind und dass auch das Modul an sich möglichst wenig geändert wird - zumindest sollten sich je nach Kundenbedarf häufig verändernde Komponenten nach Möglichkeit in einem Modul gebündelt sein, um den Aufwand der Testanpassung zu reduzieren. Ansonsten lohnt es sich nicht, in automatisierte Tests zu investieren.
Um eine möglichst hohe Stabilität der Schnittstellen zu erreichen, müssen folgenden Aspekte beachtet werden:
- Schnittstellen sollten möglichst zwischen voneinander unabhängigen Softwarefunktionen liegen.
- Mögliche Kundenbedarfe, die in der Zukunft Änderungen am Produkt erfordern könnten.
- Zulässige Änderungen an den Schnittstellen müssen in der Versionsstrategie der Software festgelegt sein, sodass ersichtlich ist, welche Änderungen erlaubt sind und welche nicht.
Durch stabile Schnittstellen zwischen den einzelnen Softwaremodulen ist es möglich, im Laufe der Zeit weitere Funktionen hinzuzufügen, ohne die Abwärtskompatibilität der Software zu beeinträchtigen. Werden zukünftige Anforderungen an die Schnittstellen von Anfang an miteinbezogen, kann die Testqualität optimiert und Kosten bei der Testentwicklung eingespart werden.
Modularisierung der Software reduziert den Blast Radius eines Fehlers
Ein weiterer wichtiger Aspekt zur Steigerung der Effizienz von Softwaretests und der damit verbundenen Fehlerbehebung ist der sogenannte “Blast Radius” (zu Deutsch: Explosionsradius) eines Fehlers. Dieser beschreibt, wie viel Code korrigiert werden muss, um einen gefundenen Fehler in der Software zu beheben. Je nachdem, wie groß das Modul ist, muss unter Umständen ein beachtlicher Teil des Codes ersetzt werden. Fehler in kleineren Modulen lassen sich hingegen nicht nur leichter finden, sondern sind auch leichter zu beheben.
Schauen wir uns als Beispiel drei verschiedene Softwaresysteme an. Das erste Softwaresystem besteht aus einem einzigen Modul, das den gesamten Code enthält. Das zweite System setzt sich aus zwei Modulen zusammen und das dritte hat drei Module. Jedes der Softwaresysteme erfüllt die gleiche Funktion.
Wenn ein Fehler im ersten System auftaucht, müssen wir zuerst den Fehler beheben und anschließend den Test für das gesamte System erneut durchführen. Die Fehlerbehebung und die Wiederholung des Tests werden viel mehr Zeit in Anspruch nehmen als im zweiten oder dritten Beispiel, bei denen der Fehler auf ein kleineres Modul beschränkt ist. Da die anderen (blauen) Module aufgrund standardisierter Schnittstellen nicht betroffen sind, müssen sie nicht erneut getestet werden, um zu überprüfen, ob der Fehler behoben ist. Dies spart viel Zeit bei der Wiederholung von Modultests und erhöht die Qualität und Stabilität des Softwaresystems.
Verstehen wir Modularisierung als Methode, um den Blast Radius möglicher Fehler in der Software zu minimieren, wirft dies jedoch die folgende Frage auf: Wie klein können oder sollten wir Softwaremodule machen? Aus Testsicht scheint es sinnvoll, Module so klein wie möglich zu halten, um die Fehlerbehebung zu vereinfachen. Eine Zerlegung in viele kleine Module bedeutet aber auch eine Vervielfachung der Schnittstellen, deren Definition, Verwaltung und Kontrolle auch Aufwand mit sich bringt. Zudem steigt bei sehr kleinen Modulen das Risiko, dass eine Funktionsänderung innerhalb eines Moduls eine Veränderung der Schnittstelle verursacht.
Es gilt also, ein Gleichgewicht in der Größe der Softwaremodule zu finden, das zwischen einer monolithischen Softwarearchitektur (links in der Abbildung unten) und einer Softwarearchitektur mit vollständig getrennten Komponenten (rechts in der Abbildung unten) liegt. Dies gelingt durch den Modularisierungsansatz des Modular Function Deployment (MFD®). MFD® ermöglicht Baukastensysteme sowohl für Software in Kombination mit Mechatronik und Service Dienstleistungen als auch reine Softwareprodukte. Die optimale Modulgröße und Schnittstellendefinition leitet sich hierbei anhand der gewünschten Kundenbedarfe als auch unternehmensinterner strategischer Zielstellungen ab. Dadurch werden stabile Produktarchitekturen bei gleichzeitig hoher Flexibilität und Anpassungsfähigkeit ermöglicht. Diese Langlebigkeit eines Baukastens gewährleistet hohe Rentabilität der Investition und steigert die Innovationskraft des Unternehmens.
Leseempfehlung: Lesen Sie hier wie Sie mit der MFD® Methode Ihre modulare Produktarchitektur systematisch in 5 Schritten definieren und die passende Größe für Ihre Module definieren können.
Modularisierung als Methode für eine schnellere und effizientere Softwareentwicklung
Modularisierung im Softwarebereich wirkt sich in mehrfacher Hinsicht positiv auf die Effizienz und Qualität des Entwicklungsprozesses aus. Erstens ermöglicht eine modulare Softwarearchitektur Kosten und Zeitaufwand für Tests zu reduzieren, indem Fehler dank automatisierter Modultests frühzeitig erkannt und behoben werden. Zweitens bietet eine modulare Softwarearchitektur eine gute Grundlage für Continuous Integration, was sowohl die Test- als auch die Softwarequalität steigert. Drittens kann der Testaufwand insgesamt reduziert werden, indem die einzelnen Softwaremodule intelligent definiert werden, um eine größtmögliche Testautomatisierung und einen möglichst geringen Anpassungsbedarf der Modultests zu gewährleisten - ausschlaggebend hierfür sind stabile Schnittstellen zwischen den Modulen. Viertens verringert Modularisierung den Blast-Radius möglicher Softwarefehler, indem Fehlerquellen in einzelnen Modulen isoliert werden.
Der erste Schritt auf dem Weg zu einer effizienten Teststrategie Ihrer Software ist das Definieren strategischer Softwaremodule. Um diese übersichtlich zu dokumentieren, können Sie sich hier unser kostenloses Template herunterladen.
Autor
Roger Kulläng
Senior Specialist Software Architectures
roger.kullang@modularmanagement.com
LinkedIn