Besserer Clean Code durch nachhaltige Softwareentwicklung
Besserer Clean Code ist mit nachhaltiger Softwareentwicklung möglich. Dieser Beitrag betont andere Aspekte als Robert C. Martin und verdeutlicht, warum geplanten Up-front Design besser ist als evolutionäres.
Mein erster Blogbeitrag
Nun ist es endlich soweit. Mein Blog ist Online. Es kann schon mal losgehen. Es geht in diesem Blog um das Thema nachhaltige Softwareentwicklung. Aber warum der Name „Software Sunshine Blog“? Das bleibt zunächst noch mein Geheimnis.
Nachhaltige Softwareentwicklung ist nicht das gleiche wie nachhaltige Software
Bei dem Begriff „Nachhaltige Softwareentwicklung“ ist die Nachhaltigkeit bei der Entwicklung der Software gemeint. Also nicht etwa die Nachhaltigkeit der Software selbst. Somit möchte ich mich eindeutig vom Begriff „nachhaltiger Software“ (ohne das zweite Substantiv „Entwicklung“) abgrenzen. Unter diesem Begriff versteht man so eine Art „grüne“ Software. Damit will man vermeiden, den Prozessor zum Heizelement zu machen.
Es geht also um die Nachhaltigkeit bei der Entwicklung von Software und dessen Ergebnis, dem Programm-Quellcode. Es ist der Sourcecode, der nachhaltig sein soll. Er soll auch im weiteren Entwicklungsprozess nachhaltig bleiben. Nachhaltig ist nicht etwa der Uralt-COBOL-Code, für dessen Wartung die Entwickler buchstäblich aus dem Altersheim geholt werden müssen. Das ist das genaue Gegenteil von Nachhaltigkeit, denn hier wurde die längst überfällige Modernisierung versäumt.
Unter Nachhaltigkeit wird allgemein verstanden, dass nicht weniger verbraucht wird wie jeweils nachwachsen kann. Ursprünglich stammt der Begriff aus der Forstwirtschaft. Im Laufe der Softwareentwicklung entsteht normalerweise eine zunehmende Komplexität. Es ist die Ressource „Einfachheit und Klarheit“ (engl. Simplicity), die durch Änderungen und Erweiterungen normalerweise verbraucht wird. Genau diese Simplicity soll nachhaltig erhalten bleiben.
Irgendwo habe ich einmal eine sehr treffende Beschreibung für Simplicity gelesen: „Ein System ist nicht dann einfach, wenn man nichts mehr hinzufügen kann, sondern dann, wenn man nichts mehr weglassen kann.„ (Das Original ist von Antoine de Saint-Exupéry und lautet: „Perfektion ist nicht dann erreicht, wenn es nichts mehr hinzuzufügen gibt, sondern wenn man nichts mehr weglassen kann.“ – , Terre des Hommes, III: L’Avion, p. 60 (1939))
Ohne TDD ist nachhaltige Softwareentwicklung nicht möglich
Man spricht von einer Anhäufung von „Technical Dept“ also eine technische Verschuldung, die jede Weiterentwicklung der Software immer schwieriger macht. Die Symptome dieses Problems nennt man Rigidität und Fragilität. Rigidität heißt, dass Änderungen übermäßig aufwändig sind. Selbst für kleinste Änderungen werden oft utopisch hohe Aufwandsschätzungen abgegeben. Fragilität, das bedeutet, dass bei Änderungen sehr leicht Fehler entstehen. Meist in Bereichen, die mit der eigentlichen Änderung gar nichts zu tun haben und somit auch nicht getestet werden. Unter Nachhaltigkeit bei Softwareentwicklung wird somit die Bemühung verstanden, Änderungen der Software ohne technische Schulden zu machen. Die Ressource Simplicity bleibt dabei gemäß dem KISS-Prinzip zu erhalten. Künftige Erweiterungen der Software sollen genauso einfach sein, wie am ersten Tag.
Die wichtigste Hilfstechnik dabei ist das sogenannte Test Driven Development (TDD). Abgesichert durch sogenannte Unit-Tests, wird der Programmierer dabei in die Lage versetzt, jederzeit Refactorings machen zu können. Das ist Grundvoraussetzung, um überhaupt Clean Code erzeugen zu können. Nach dem Prinzip „First make it work then make it right“ verwandelt der Code sich sukzessive in Clean Code. Durch Unit-Tests verliert der beliebte Programmierspruch „Never change a running system“ erstmals seine Gültigkeit. Das genaue Gegenteil wird nun gefordert. Perfekter Code entsteht nicht durch Planung sondern durch unzählige kleine Verbesserungen. Das ist auch die Arbeitsweise von Malern, Komponisten, Schriftstellern, Steinmetzen, Töpfern, Holzschnitzern, usw. Beim herkömmlichen Programmieren existiert immer die Gefahr, dass mit jeder kleinen „Verbesserung“ neue Fehler eingebaut werden. Mit den Unit-Tests wird nun aber ein Sicherheitsnetz aufgespannt, welches diese Gefahr bannt. Für die traditionelle Rolle des Software-Architekten hat Martin in seinen „Uncle Bob“-Trainingsvideos häufig nur Spott übrig.
Um TDD zu erlernen brauchen Sie einen erfahrenen Coach. Hier kann man vieles falsch machen und hinterher ist die Enttäuschung groß. Sie sollten ihr System so aufsetzen, dass bei jedem Build-Lauf auch alle Unit-Tests kompiliert und ausgeführt werden. Da auf Dauer sehr viele Tests entstehen, ist gute Performance extrem wichtig. Das Ausführen aller Tests sollte insgesamt weniger Zeit kosten als der komplette Build-Lauf. Ansonsten wird TDD sehr schnell als lästig empfunden. Es dürfen keine Implementierungsdetails und keine privaten Methoden getestet werden. Hält man sich nicht daran, dann machen Refactorings auch immer wieder Änderungen an den Tests notwendig. Das wäre dann völlig am Ziel vorbeigeschossen. Genau das muss man vermeiden. Nur wenn man das Programmverhalten ändert, sollen auch die Tests verändert werden.
Clean Code ist fast das Gleiche wie nachhaltige Softwareentwicklung
Es gibt mittlerweile ausgereifte Techniken, um in diesem Sinne nachhaltige Softwareentwicklung zu betreiben. Der Autor Robert C. Martin nennt das Clean Code.
Clean Code ist ein Überbegriff für alles, was hilft technische Schulden zu vermeiden. Ein Programmierer verwendet sehr viel mehr Zeit damit, Code zu lesen als zu schreiben. Dabei ist es immer schwierig, fremden Code zu verstehen. Manche verstehen den eigenen Code nicht mehr, wenn sie ihn eine Weile nicht mehr gesehen haben. Wenn Programmcode sicht nicht aus sich selbst heraus verständlich erklärt, wenn es dazu unzähliger Kommentare bedarf, dann ist er auch nicht clean.
Es geht los mit sauberer Code-Formatierung. Ich hasse es, horizontal scrollen zu müssen. Wenn man beim Lesen das Ende einer Codezeile erreicht hat, weiß und sieht man nicht mehr was am Anfang stand. Zur Einhaltung von Formatierungsregeln, auf die sich das ganze Team geeinigt hat, verwendet man am besten ein Tool. Dieses muss sich in die eigene Entwicklungsumgebung integrieren lassen. Und dann nur Mut, um damit gnadenlos die kunstvollen alten Formatierungen zu zerstören.
Weiter geht es mit der richtigen Namensfindung für Klassen, Methoden, Variablen, etc. Der Code wird dadurch gut lesbar und Kommentare werden überflüssig. Ein Kommentar ist nur dann wirklich notwendig, wenn es ein Defizit im Code gibt.
Methoden und Funktionen sollten auch nur eine einzige Aufgabe erledigen, und sie sollen sie gut erledigen. Dazu reichen in der Regel 3-5 Codezeilen
Nachdem Robert C. Martin die formalen Kriterien für Clean Code abgehandelt hat, geht er ans Eingemachte. Was macht nun inhaltlich guten Clean Code aus? Das wichtigste ist die Einhaltung der SOLID-Prinzipien. Es würde zu weit führen, diese im Einzelnen zu erläutern. Jeder gute Programmierer sollte sie eigentlich sowieso schon kennen und befolgen.
Wenn Sie also nachhaltige Softwareentwicklung betreiben wollen, dann schreiben Sie Clean Code und erzeugen ihn mit TDD.
Alle Prinzipien von Clean Code außer TDD kann man recht sehr gut autodidaktisch erlernen mithilfe der Video-Reihe „Uncle Bob“. Die Videos sind sehr unterhaltsam und das Englisch von Robert C. Martin ist sehr gut zu verstehen. Schauen Sie doch einfach mal in das erste Trainingsvideo rein, es ist kostenlos.
Ist nachhaltige Softwareentwicklung nun das Gleiche wie das Erstellen von Clean Code? Fast, aber nicht ganz!
„Clean Code“ – ein unsauberer Begriff
Mir persönlich gefällt der Begriff „Clean Code“ nicht besonders gut. „Clean“, das klingt nach Wachmittelreklame. Das Wort enthält im Vergleich zu „nachhaltig“ nicht den eigentlichen Zweck. Sehr alt und daher sehr bekannt ist der Begriff „quick and dirty“, wenn in Programmen eine schnelle Lösung eingebaut wird. Eine schnelle Lösung, von der man genau weiß, dass sie die Codequalität verschlechtert. Mit „clean“ assoziiert man also das Gegenteil von „quick and dirty“. Folglich glaubt man, dass gute Codequalität nicht „quick“ zu programieren ist und dass man sehr viel Zeit für die Programmierung benötigt. Das ist falsch. Es gibt etliche Studien, die beweisen, dass mit TDD erstellter Clean Code genauso schnell zu schreiben ist, wie auf konventionelle Weise erzeugter Code.
Ich bin überzeugt davon, dass bei einem Programmierwettbewerb ein Team gut eingespielter TDD-ler jedes andere Team schlagen würde. Das liegt daran, dass sich bei konventioneller Programmierung kleine Fehler einschleichen, die erst mühsam mit dem Debugger gefunden werden müssen. Bei so einem Wettbewerb würde der Schiedsrichter sehr genau die Korrektheit überprüfen, und wenn er Fehler finden würde, dann müsste das jeweilige Team nacharbeiten. Spätestens dann würde das Team TDD in Führung gehen.
Das zweite Wort bei „Clean Code“ gefällt mir nicht wirklich. Es geht nicht um das Ergebnis „Code“ sondern um den Prozess, und der enthält mehr als nur den Code. Man findet höchst selten den Begriff „Clean Coding“. Häufig wird stattdessen der Begriff „Extreme Programming“ (XP) verwendet, was meiner Meinung nach ein abscheuliches Wording ist.
Der Begriff „nachhaltige Softwareentwicklung“ in genau dem Kontext wie er hier verwendet wird, wurde erstmalig im Jahr 2005 in dem großartigen Buch „Sustainable Software Development: An Agile Perspective“ von Kevin Tate erwähnt. Frühere Erwähnungen in genau diesem Sinn sind mir zumindest nicht bekannt. Knapp 3 Jahre später erschien das berühmte Buch „Clean Code: A Handbook of Agile Software Craftsmanship“ von Robert C. Martin. Martins Idealvorstellungen von gutem Code sind fast identisch mit denen von Tate. Diese Übereinstimmung ist erklärbar, weil beide Anhänger von XP und agiler Entwicklung sind. Martin hatte Tates Buch zuvor vermutlich nicht gelesen, denn sonst hätte er Tate zitiert. Im Literaturanhang ist Tate jedenfalls nicht erwähnt. Es ist wirklich schade, dass Tate nicht mehr prägenden Einfluss hatte, und sich somit der Begriff „Sustainable Software Development“ nicht durchgesetzt hat.
Der Unterschied von nachhaltiger Softwareentwicklung und Clean Code
Ist nun nachhaltiger Code, so wie ich ihn mir wünsche, das Gleiche wie Robert C. Martins Clean Code? Verwendet dieser Blog nur ein anderes Wording? Nein, es gibt wichtige Unterschiede im Detail.
Ich möchte zunächst die folgende einfache Formel aufstellen:
Nachhaltiger Code = Clean Code + X
Was beinhaltet nun dieses X? Was unterscheidet nachhaltigen Code von Uncle Bobs Clean Code?
Besserer Clean Code ist mit nachhaltiger Softwareentwicklung machbar.
Die Ideale in Bezug auf Design und Architektur sind geringfügig unterschiedlich. Ich habe andere Vorstellungen davon, wie gutes Moduldesign aus der Mikroperspektive zu entwickeln ist. Aus der Makroperspektive setze ich andere Schwerpunkte bezüglich der Systemarchitektur.
Nachhaltige Softwareentwicklung aus der Mikroperspektive
Man hat bei Robert C. Martin manchmal den Eindruck, dass er glaubt, ein Algorithmus entsteht ganz von allein. Alles, was man dazu braucht ist TDD und die Beachtung von bestimmten Refactoring-Regeln. Exemplarisch dafür ist das Lehrbeispiel bei Uncle Bob zur Primfaktorzerlegung. Er möchte das Publikum von TDD überzeugen und zeigt, dass alleine die konsequente Anwendung von TDD quasi automatisch zum Algorithmus „Sieb des Eratosthenes“ führt. Das Ergebnis ist zwar zugegebenermaßen in Bezug auf Performance noch nicht optimal. Es ist auch nicht genau das, was oben im verlinkten Wikipedia-Beitrag beschrieben ist. Das Erstaunliche ist jedoch, dass alleine aufgrund der Anwendung von Prinzipien ein Algorithmus entstanden ist.
Uncle Bob zeigt dieses Beispiel, nein diesen Zaubertrick, gleich in zwei Videos. Ich war bei einem Code-Dojo dabei, bei dem die Primfaktorzerlegung Gegenstand der Übungsaufgabe war. Es wurde mit Entwicklern durchgeführt, die sehr erfahren bei TDD sind. Sie setzen TDD beinahe alltäglich ein. Bei dieser Übung kam das Team schnell auf Abwege. Über einen längeren Zeitraum entfernten wir uns eher von der Lösung, als dass wir ihr näher kamen. Es entstand ein Phänomen, welches Uncle Bob „Stuck“ nennt. Das ist, wenn man sich festgefressen hat. Wie ein Auto, das im Schlamm festsitzt.
Zugegeben, wir haben aus Unkenntnis auch nicht ganz genau das umfangreiche Regelwerk für gutes Refactoring angewendet, welches Robert C. Martin vorgibt. Ich persönlich glaube, dass TDD extrem hilfreich bei der Entwicklung von Lösungen ist. Sie stellen sich aber nicht von alleine ein. Wenn das so wäre, dann könnte man auch ein Programm schreiben, welches für beliebige Probleme automatisch eine Lösung findet.
Die Mehrzahl aller Programmieraufgaben beinhaltet einfache Probleme, bei denen man einen Lösungsansatz schon im Kopf hat, wenn man mit der Implementierung beginnt. Anders bei sehr schwierigen Problemen: Angenommen Sie bekommen die Aufgabe, den Zeitpunkt von Sonnenauf- und untergang zu berechnen. Als Input bekommen Sie geographischen Koordinaten und ein Tagesdatum. Sie werden sich bei dieser Aufgabe die Zähne ausbeißen, wenn Sie das alleine mit TDD und Refactoring lösen wollen. Selbst, wenn Sie alle zugrundeliegenden astrophysikalischen Gesetze und Konstanten kennen würden, würden Sie mit TDD nicht auf den richtigen Algorithmus kommen. Zumindest nicht in vertretbarer Zeit.
Wie löst man derartige Aufgaben in der Praxis? Man sucht im Internet oder in der wissenschaftlichen Literatur nach einem Algorithmus oder man konsultiert einen Experten. Später, wenn einmal der Algorithmus gefunden ist, wird man bei der Implementierung selbstverständlich TDD einsetzen.
Den überwiegenden Zeitanteil zum Entwickeln von Lösungen, benötigt man in der Praxis weder bei sehr schwierigen Problemen noch bei sehr einfachen Problemen. Das Herausfinden geeigneter Lösungsansätze, das Software-Design ist am aufwändigsten bei mittelschweren Problemen. Gibt es zugleich mehrere Lösungsalternativen, dann kostet die Entscheidungsfindung ebenfalls viel Zeit. Nachhaltige Softwareentwicklung heißt dabei, dass man sich jeweils immer für die einfachste Lösung (Simplicity) entscheidet. Das herauszufinden ist aber meistens nicht einfach (easy). (Wir haben im Deutschen leider keine unterschiedlichen Worte für „simple“ und „easy“.)
Evolutionäres oder geplantes Design
Nachhaltige Softwareentwicklung betont diesen Moment sehr viel stärker als Clean Code nach Robert C. Martin. Er denkt nur einen kurzen Augenblick über das Design nach und beginnt dann gleich mit TDD. Ich glaube nicht, dass sich gutes und vor allem nachhaltiges Design alleine dadurch einstellt. Auch nicht, wenn dabei alle SOLID-Prinzipien penibel eingehalten werden.
In dem sehr lesenswerten Artikel „Is Design Dead?“ befasst sich Martin Fowler mit der Frage ob wir überhaupt noch Software-Design benötigen. Fowler ist Mitunterzeichner des agilen Manifests, überzeugter Anhänger von Clean Code und als Chefentwickler beim Consulting-Unternehmen ThoughtWorks. Er hat somit jede Menge praktische Erfahrung. Trotzdem oder gerade deswegen outet er sich als Anhänger geplanten Designs.
Im Gegensatz zu Fowler und damit wieder in einer Linie mit Robert C. Martin halte ich sehr wenig von UML. Bei der konkreten Design-Planung, vor allem, wenn sie im Team stattfindet, sind grafische Aufzeichnungen sehr hilfreich. Ein Bild sagt mehr als tausend Worte. Vor allem ist es ein ausgezeichnetes Instrument um die Gehirne aller Diskussionsteilnehmer zu synchronisieren. UML ist hierfür aber viel zu umständlich und zu zeitaufwändig.
Das beste Planungsinstrument ist meiner Meinung nach eine Schultafel. Sie bietet genügend Platz und Korrekturen sind schnell und einfach machbar. Schultafeln sind in Besprechungsräumen eher selten anzutreffen. Man muss sich dann eben mit Whiteboard, Flipcharts oder notfalls mit einem Blatt Papier behelfen. Es geht darum, anderen die eigene Vorstellungswelt mitzuteilen. Jede Kritzelei ist hierbei erlaubt. Verboten sind lange Monologe, weil genaues Zuhören und das Entwickeln von Ideen in der eigenen Gedankenwelt sich gegenseitig ausschließen. Diese Art von Planung lebt im hier und jetzt. Für die Dokumentation und Archivierung kann man zum Schluss ein Foto des Tafelbildes machen. Weitere Aufzeichnungen sind nicht notwendig. Es geht darum ein kohärentes Bild in den Köpfen zu hinterlassen.
Entwurfsmuster
Stark auseinander gehen die Meinungen auch hinsichtlich der Verwendung von Entwurfsmustern. Hiermit sind nicht die SOLID-Prinzipien gemeint, sondern jene 23 Entwurfsmuster, die im berühmten Buch „Design Patterns. Elements of Reusable Object-Oriented Software“ der Gang of Four (GOF) beschrieben sind. Robert C. Martin ist ein unbedingter Befürworter von Entwurfsmustern.
Auch mit dem Singleton Pattern hat er keine Probleme. Für viele andere ist das ein absolutes Tabu im Clean Code. Ich persönlich habe dazu auch eine eher pragmatische Einstellung. Es macht Probleme, die man kennen sollte, aber wenn es nicht anders geht, dann darf man es auch einsetzen. Mithilfe von Factory Pattern, kann man den gewünschten Effekt, dass nur eine einzige Instanz existiert, die vielen andern Objekten bekannt sein muss, meistens ebenso gut realisieren. Womit gleich das nächste Pattern angesprochen ist: Das Factory Pattern. Es ist ein unbedingtes Muss für Clean Code. Eine Factory ist ziemlich unproblematisch, solange sie keine zusätzliche Logik bekommt.
Aus meiner Erfahrung muss ich feststellen, dass der Einsatz von Entwurfsmustern häufig dazu führt, dass der Code nicht mehr nachhaltig ist. Es entstehen häufig unnötige Verkomplizierungen. Overengineering ist schlimmer als Copy-And-Paste. Martin Fowler schreibt dazu wörtlich:
The essence of this argument is that patterns are often over-used. The world is full of the legendary programmer, fresh off his first reading of GOF who includes sixteen patterns in 32 lines of code. I remember one evening, fueled by a very nice single malt, running through with Kent a paper to be called „Not Design Patterns: 23 cheap tricks“ We were thinking of such things as use an if statement rather than a strategy. The joke had a point, patterns are often overused, but that doesn’t make them a bad idea. The question is how you use them.
Martin Fowler, Is Design Dead
Anmerkung: Mit „Kent“ ist Kent Beck gemeint, der TDD wiederentdeckt und diese Technik in der heutigen Form erschaffen hat.
Kevin Tate ist nicht grundsätzlich gegen Pattern aber er ist ebenfalls kritisch eingestellt. Er schreibt dazu unter anderem:
The use of design patterns can lead to an unhealthy emphasis on up-front design. I have been on projects where people spent too much time trying to analyze a problem so they could try to identify what design patterns would apply. If you aren’t sure, don’t use a pattern. Simplicity, as always, should be the primary goal. Chances are, if there is a pattern, there it will emerge. You can always refactor to it later, as in.
Kevin Tate, Sustainable Software Development: An Agile Perspective
Exemplarisch für diese Problematik ist Das Observer Pattern, das in vielen Fällen eine sehr elegante Lösungsmöglichkeit ist. Wichtig beim Einsatz ist, dass es keine Rückkopplung des Observers zum beobachteten Objekt gibt. Damit meine ich folgendes Szenario: Der Observer registriert eine Änderung und benachrichtigt ein anderes Objekt, welches dann eine Zustandsänderung am beobachteten Objekt vornimmt, welches dann wieder dazu führt, dass der Observer eine Veränderung registriert usw. Das ergibt bei positiver Rückkopplung eine Endlosschleife. Derartige Fehler erkennt man normalerweise sofort beim Entwickeln. Das Programm friert ein, oder es gibt im Falle rekursiver Programmierung ein Stack Overflow.
Der Bug überlebt aber häufig, wenn eine negative Rückkopplung vorliegt. In diesem Fall pendelt das System nach mehreren Änderungen irgendwann wieder in eine stabilen Zustand ein. Chaotisch wirkt das ganze, wenn man es im Debugger beobachtet. Es ist nicht der Programmcode, der in diesem Fall komplex ist, sondern das Laufzeitverhalten. Das äußerlich sichtbare Programmverhalten ist aber so wie gewünscht, ansonsten hätte man den Fehler erkannt. Das real existierende Laufzeitverhalten war aber so nie vom Programmierer beabsichtigt.
In meiner langjährigen Berufspraxis habe ich derartiges schon öfters gesehen. Normalerweise analysiere Legacy Code, der mir unbekannt ist, indem ich den Programmablauf im Debugger anschaue. Stoße ich dann auf dieses Phänomen, dann bin ich verloren. Der ursprünglich geplante Programmablauf kann nur noch erraten werden. Bugfixings in derart rückgekoppelten Systemen sind extrem schwierig.
Wie kommt so etwas zustande? In vielen Fällen ist derjenige, der das Observer Pattern eingebaut hat, unschuldig. Verbockt hat es jemand anderes, der irgendwann später und unbedacht die Rückkopplung erzeugt hat. Bei zirkulären Modulreferenzen genügt oftmals eine einzige Zuweisung. Das äußerlich sichtbare Programmverhalten ist wie gewünscht, und im Debugger schaut sich das niemand mehr an. Wie kann man das verhindern? Entweder man verzichtet auf das Observer Pattern, was wirklich schade ist, oder man achtet bei der Coderevision darauf, dass es nur hierarchische Referenzen gibt. Insbesondere in der Nähe von Observer Pattern sollten netzartige Modul- oder Objektstrukturen unbedingt vermieden werden. Ich habe mir sagen lassen, es soll tatsächlich noch Entwickler-Teams geben, die keine Coderevisionen durchführen.
Das Problem von netzartigen Strukturen führt zur Makroperspektive.
Nachhaltige Softwareentwicklung aus der Makroperspektive
In seinen Videos macht sich Uncle Bob regelmäßig über Softwarearchitekten lustig. Er verspottet sie als Wichtigtuer. Robert C. Martin fordert, dass Architekten auf jeden Fall auch programmieren sollen, weil sie sonst den Bezug zur Realität verlieren. Diese Forderung kann ich nur unterschreiben. Auch ich habe die Erfahrung gemacht, dass Softwarearchitekten sich häufig exakt so verhalten, wie sie in den Videos charakterisiert werden. Dennoch ist gute Softwarearchitektur extrem wichtig für nachhaltige Softwareentwicklung.
Das Buch „Clean Architecture A CRAFTSMAN’S GUIDE TO SOFTWARE STRUCTURE AND DESIGN“ von Robert C. Martin beschreibt gegenüber seinen vorherigen Clean Code Buch seine Sichtweise von guter Softwarearchitektur. Für ihn gibt es keinen Unterschied zwischen Design und Architektur. Gute Architektur ergibt sich dann quasi von alleine, wenn alle Prinzipien für gutes Design eingehalten werden und der Code mit TDD erzeugt wurde und somit testbar ist.
Nachhaltige Softwareentwicklung ist nach meinem Verständnis mehr. Obwohl die Grenzen fließend sind, gibt es für mich einen Unterschied zwischen Design und Architektur. Dabei halte ich es für weniger wichtig, wie die Definition formuliert wird. Bedeutend sind die Konsequenzen, die man daraus zieht. Wie schon bei meinem Plädoyer für geplantes Design vertrete ich die Meinung, dass das Architekturmodell aus einer Planung hervorgehen sollte. State of the Art ist das nachfolgend abgebildete Architekturmodell, welches aus dem „Domain-driven Design“ entstammt.
Robert C. Martin zieht einen Vergleich heran, um die Unterschiedslosigkeit von Design und Architektur zu begründen. Er sagt: Die Pläne, die ein Architekt eines Gebäudes abliefert, enthalten bereits alle möglichen Design-Details. Der genaue Ort der Lichtschalter, die mögliche Möblierung, das ist alles schon in den Plänen eingezeichnet. Das ist richtig. Nach meinem Verständnis ist Bauarchitektur im übertragenen Sinne keine Softwarearchitektur. Es ist Design. Softwarearchitektur ist weiter übergeordnet. Benutzt man die Metapher, dann ist Softwarearchitektur vergleichbar mit dem Erstellen von Flächennutzungsplänen, Raumordnungsplänen und Bebauungsplänen, bei denen es um die Versorgung und Planung von Straßen, Kanalisation, etc geht. Also: Wie muss eine Software geplant, werden damit alle Plugins harmonisch ineinander greifen können?
Zyklenfreie Architektur
Das Thema zyklenfreie Architektur wird in dem oben genannten Buch von Robert C. Martin unter dem Kapitel „The Acyclic Dependency Principle“ ADP behandelt. Er traut sich aber nicht die Vorteile von hierarchischen Architekturen anzusprechen. Beim Vorläufer der objektorientierten Programmierung, der strukturierten Programmierung aus den 70er Jahren entstand eine hierarchische Struktur ganz von alleine. Hierarchische Strukturen haben den Vorteil, dass das Gehirn die darin enthaltene Ordnung leicht erfasst. Zyklische Programmstrukturen sind sehr viel schwieriger zu verstehen. Irgendwie dreht man sich beim Versuch Verständnis darüber zu gewinnen, auch immer wieder im Kreis. Natürlich will ich nicht zurück in die 70er Jahre. Plugin-Architekturen lassen sich auch nur realisieren, wenn man die Pfeilrichtung der Abhängigkeiten durch Anwendung des „Dependency-Inversion-Prinzips“ umdreht. Hierbei kommen i.d.R. Interfaces zum Einsatz.
Zyklische Programmarchitekturen sind aus meiner Erfahrung der schlimmste Killer von Nachhaltigkeit. Im großartigen Buch „Langlebige Softwarearchitekturen“ von Carola Lilienthal zieht sich dieses Thema wie ein roter Faden durch den gesamten Text. Im Kapitel 5.3 zeigt sie, dass aus Untersuchungen hervorgeht, „dass Menschen dann Wissen gut aufnehmen, es wiedergeben und sich darin zurechtfinden können, wenn es in hierarchischen Strukturen vorliegt“ (Seite 85). Dies bestätigt exakt meine Erfahrungen aus der Berufspraxis. Man sollte also genauestens überlegen, an welchen Stellen klassische Hierarchien sinnvoller sind. Plugin-Strukturen sollten immer auf die eine oder andere Art geordnet sein. Baumartige Strukturen mit geringer Tiefe erleichtern dabei die Abbildung im Kopf.
Zyklen entstehen immer dann unabsichtlich, wenn ein Programmierer sieht, dass eine Methode einer bestimmten Klasse genau das macht, was er an einer anderen Stelle benötigt. Copy-And-Paste kommt nicht in Frage, das ist verpönt. Also wird auf diese Klasse referenziert. Die Methode wird notfalls „public“ gemacht und das Interface wird erweitert. „Problem gelöst“, denkt er. Hätte der Programmierer eine bildhafte Vorstellung der Programmarchitektur im Kopf, dann wüsste er, dass er gerade einen Zyklus geschaffen hat. Im Ergebnis ist das viel schlimmer, als wenn er die Methode mit Copy-And Paste dupliziert hätte.
Eine klare Vorstellung der vorhandenen Programmarchitektur ist das A und O nachhaltiger Softwareentwicklung. Der Programmierer erkennt dann sofort, dass er die benötigte Methode an einen klar definierten anderen Ort umziehen muss. TDD und SOLID alleine verhindern keinen Wildwuchs. Bei großen Zyklen geht die Testbarkeit verloren, und TDD ist nicht mehr möglich. Kleine Zyklen stehen aber nicht im Widerspruch zur TDD. Sie sind zwar beherrschbarer, aber aus gesamtheitlicher Sicht geht die Lesbarkeit verloren.
Jeder, der sich mit nachhaltiger Softwareentwicklung befasst, sollte dieses Buch von Carola Lilienthal gelesen haben. Sie hat über achtzig Softwaresysteme zwischen 30 000 und 15 Mio. Lines of Code (LOC) in Java, C++, C#, ABAP und PHP untersucht. Mit Werkzeugen aus der statischen Code-Analyse erstellte sie Metriken zur grafischen Darstellung von allen Architekturelementen. So entdeckte sie jede Art von Zyklen, auch wenn sie sehr versteckt sind. Mit diesen Werkzeugen ist eine Bewertung der Architektur über den sogenannte „Modularity Maturity Index“ (MMI) möglich. In 11 Geschichten aus der Praxis schildert sie die Erfahrungen bei der Wartung und Weiterentwicklung von Systemen mit unterschiedlichen MMI und LOC. Das Buch ist nicht nur sehr wertvoll für Programmierer sondern auch für Projektmanager. (Letztere können die technischen Details gerne überblättern.) Praktiker erfahren im Anhang, welche Werkzeuge benutzt wurden und wie man sie einsetzt.
Jeder Programmierer, der glaubt, dass viele Interfaces ausreichen, um eine nachhaltige Architektur errichten zu können, sollte das Kapitel 7.4 „Interfaces – das architektonische Allheilmittel?“ lesen. Carola Lilienthal erläutert, dass Interfaces oftmals nur die Abhängigkeit zwischen einzelnen Modulen verschleiern. „Eine echte Modularisierung z.B. im Sinne von fachlichen aufeinander aufbauenden Schnitten oder Microservices wird so nicht erreicht.“ (Seite 131)
Nachhaltige Softwareentwicklung ist auch ohne Agilität möglich
Möglich ja, aber mit Agilität geht es besser!
Es gibt die Ausrede, man müsse sich nicht um Clean Code bemühen, weil es im Unternehmen keine agile Vorgehensweise gibt. Das muss auch nicht unbedingt die Schuld der Geschäftsleitung sein.
Es kann sein, dass der Kunde das nicht will. Wie gewohnt aus der Welt der materiellen Produkte, ist etwas Schlüsselfertiges gewünscht. Wenn ich mir ein neues Auto kaufe, verwende ich einen Fahrzeug-Konfigurator, nachdem ich mich für eine bestimmte Marke entschieden habe. Im Endergebnis habe ich dann für mich das beste Preis/Leistungsverhältnis erzielt. Das Fahrzeug wird zu einen festgesetzten Termin geliefert, so wie von mir konfiguriert. Es ist verständlich, dass man sich das auch bei Software so wünscht. Agilität führt anfänglich zu Verunsicherung. Man muss den Kunden die Vorteile von Agilität gut erklären. Nicht jeder Kunde versteht, dass Software etwas ganz anderes als ein materielles Produkt ist. Die Geschäftsleitung möchte den Kunden nicht verlieren und zum Schluss landet man wieder beim Wasserfall-Modell.
In diesem Fall sollte das Projekt ebenfalls mit nachhaltiger Softwareentwicklung umgesetzt werden. Das ist kein Widerspruch. Die agile Vorgehensweise ist möglich und empfehlenswert bei Legacy-Software, deren Code alles andere als Clean Code ist. Agilität ist sogar außerhalb von Softwareentwicklung möglich. Umgekehrt ist Agilität keine notwendige Voraussetzung für Clean Code. Auch wenn sich Agilität und Clean Code hervorragend ergänzen, ist das eine vom anderen in keiner Weise abhängig. Im Gegenteil: Ich behaupte, das klassische Projektmanagement wird über TDD erstmals machbar. Das liegt einfach daran, dass die Reihenfolge der Entwicklung einzelner Bausteine durch TDD keine Rolle mehr spielt. Durch das Aufheben von Abhängigkeiten zwischen den Modulen wird bei der Projektplanung vieles sehr viel einfacher. So können Terminengpässe nun auch durch frühzeitige Personalaufstockung überwunden werden. Es wird auch besser sichtbar, wenn Termine gefährdet sind.
Insgesamt ist aber Agilität bei der Softwareentwicklung trotzdem sehr empfehlenswert. Der gegenwärtige Hype bei agilen Methoden kann sehr schnell wieder in sich zusammenfallen oder durch etwas ganz anderes ersetzt werden. Nachhaltige Softwareentwicklung ist auch nachhaltig an sich und somit von Modeerscheinungen unabhängig.
Nächster Beitrag: Was ist TCR?
Aus Robert wird irgendwann Paul!
Tippfehler? Freudscher Versprecher?
Danke, ist nun korrigiert. Keine Ahnung warum ich das so konsequent falsch geschrieben habe. Vor Ewigkeiten habe ich mal einige Texte von Paul C. Martin gelesen. Vielleicht hat sich das irgendwie eingebrannt.
Pingback:Besserer Clean Code durch nachhaltige Softwareentwicklung software-sunshine-blog.de/nachhaltige-so… /@sprenzelmanfred ^hg | Novatrend Twitter
Toller Blogeintrag! Wir haben am 26.08.2020 einen Online Talk, wo wir genau darüber diskutieren möchten! Freut mich wenn du mit dabei bist! Infos unter https://ittalk.dev/