Ich mache das mit dieser Softwareentwicklung ja schon ein paar Jährchen (irgendwas um die 12 Jahre +/-), und habe dabei wirklich stetig versucht mich zu verbessern. Habe Abends und am Wochenende Blogeinträge und Bücher gelesen, bin zu Konferenzen und Usergroups gegangen oder letztere organisiert, und mich auch ständig mit den neusten Technologien, Praktiken, Methodiken auseinandergesetzt. Dabei baut man sich natürlich so sein eigenes System an Werten und Praktiken, die einen durch den Alltag bringen.
Wenn ich also zusammenfassen müsste, warum ich bestimmte Dinge so tue wie ich sie tue, dann weil ich mir die Strukturierungsmechanismen meiner Software so aussuche, dass diese möglichst auch in mittelgroßen Projekten noch gut skalieren können sollten (was auch immer so genau mittelgroß sein mag). Und was heisst denn skalieren nun schon wieder? Pff! Ok, ich formuliere es anders: Bei der Auswahl dieser Strukturierungsprinzipien gehe ich nach einem denkbar einfachen Modus vor. Ich bewerte Sie nach Ihrem Einfluss auf drei Eigenschaften von Software bzw. Quellcode, denen ich möglichst alles andere unterordne. Diese Eigenschaften sind Lesbarkeit, Testbarkeit und Einfachheit. Aus diesen kann man je nach Argumentation andere Eigenschaften wie Wartbarkeit, Änderbarkeit etc. ableiten. Denn es geht ja vor allem darum, möglichst schnell Produktivität oder andere Werte für ein Geschäft zu schaffen, und flexibel (agil blabla) auf sich ändernde Rahmenbedingungen reagieren zu können. Dabei hilft es mir, diese Eigenschaften in den Vordergrund zu stellen.
OK, bis hierhin soweit klar? Vermutlich nicht, oder? Denn: Hier haben wir nämlich schon wieder sofort das Problem, dass diese drei Eigenschaften sich nur begrenzt messen und in feste Regelwerke pressen lassen. Dazu könnte man eine größere Diskussion zu Messbarkeit von Software und dem Mangel an empirischer Forschung dazu lostreten. Lasse ich in diesem Fall aber lieber. Da mir die Grenzen des Wissens in unserer jungen Branche bewusst sind, habe ich für mich ein paar Daumenregeln entwickelt, um zumindest Testbarkeit und Einfachheit einzuschätzen.
Einfachheit
Beginnen wir mit letzterer, der Einfachheit: Ich sage öfter halb scherzhaft, halb ernst gemeint, dass mein Gehirn zu klein wäre, um große Codestücke wie lange Klassen oder Methoden zu erfassen und zu durchdringen, und ich in Ermangelung von genug geistiger Kapazität meine Code-Elemente daher klein strukturieren muss. Klein heißt für mich: Eine Klasse passt im besten Fall auf maximal 2-3 Bildschirme, was bei aktuellen Bildschirm- und Schriftgrößen auf ca. 100-150 Zeilen Code hinausläuft. Das ist meine Definition von Einfachheit oder Übersichtlichkeit. Dadurch sind diese Klassen und ihre Methoden auch meist auf genau einen bestimmten Zweck zugeschnitten, was schönen Dingen wie dem Single Responsibility Principle Rechnung trägt und häufig auch der Lesbarkeit zuträglich ist.
Lesbarkeit
Lesbarkeit kann ich persönlich selbst mit Daumenregeln nicht mal im Ansatz messen. Ich bin ein großer Freund von Clean Code Methodiken und SOLID Prinzipien etc., aber eine Messbarkeit sehe ich da bis heute nicht. Also falle ich auf Einfachheit als grob überschlagbar messbares Kriterium zurück, und versuche dennoch Clean Code Praktiken und andere Dinge anzuwenden, um der restlichen Unsicherheit noch weiter entgegen zu treten.
Testbarkeit
Kommen wir zur Testbarkeit, die vermutlich einzige wirklich messbare dieser drei Eigenschaften von Software. Messbar warum? Nunja, indirekt. Man kann Testbarkeit natürlich nicht auf einer Skala von 1-10 abtragen. Was man allerdings messen kann, ist die Testabdeckung (Code Coverage) der eigenen Software. Hier peile ich in allen Projekten 90-100% an. Nicht immer 100%, da bestimmte Teile von UI Code oder durch Tools erzeugtem Code entweder nicht, oder nur durch hohen Aufwand zu testen sind. Natürlich kann man die 100% dann trotzdem erreichen, indem man diese Code-Teile von der Coverage-Analyse ausschließt. Hier muss man aber mit Augenmaß vorgehen, um nicht zu viel auszuschließen oder grob zu betrügen. Im Zweifel also lieber nicht tun. Beim Testen ist mir grundsätzlich auch egal, ob das nun durch Unit Tests oder Integration Tests stattfindet. Mir ist wichtiger, dass die Tests eine hohe Aussagekraft über die Funktionsweise der Software haben. D.h. oft nehme ich die Datenbank explizit mit in die Tests, um Fehler in Treiber, Query Engine, Constraints, oder ähnliches auch schon in meinen automatisierten Tests zu bemerken. Geil, oder? OK, nächster Bonuspunkt: Software sollte gewissen Strukturierungsprinzipen folgen, um möglichst einfach testbar zu sein. Lose Kopplung, Abstraktion (Interfaces usw.), kleine Klassen mit genau definierten Aufgaben, etc. So unterstützt die Eigenschaft Testbarkeit auch sofort die Verbesserung der inneren Struktur einer Software. Nun mögen die Klugscheißer unter uns natürlich anmerken, dass man mit hohem Aufwand auch eine schlecht strukturierte Software durchaus testen kann. Das stimmt, selbst solche Software lässt sich von aussen mit UI- oder End-to-End-Test Tools testen, und teilweise sogar eine messbare Testabdeckung erzeugen. Aber meist steht der Aufwand in keinem guten Verhältnis. D.h. man sollte bei der Bewertung der Testbarkeit die Relation dazu nehmen, wieviel Zeit man für das Schreiben von Tests aufwendet, im Vergleich zu der Zeit die man mit dem Schreiben des zu testenden Codes verbringt. Meiner Erfahrung nach, ist ein gutes Verhältnis 2:1, d.h. ich verbringe zwei Drittel der Zeit mit dem Schreiben von Tests, und ein Drittel der Zeit mit dem Code der getestet wird. Das ist ein einigermaßen gesundes Verhältnis, wie ich finde. Und meine Erfahrung lehrt mich, dass das Schreiben von UI oder End-to-End Tests für schlecht strukturiere Software in den allermeisten Fällen massiv mehr Zeit verschlingt, als der Bau der zu testenden Funktion.
Fazit
So, das ist es. Mein eigenes Mini-Wertesystem, welches mich mit einigermaßem gesundem Verstand durch viele Projekte gebracht hat. Diskutiert gerne auf Twitter (https://twitter.com/schmagahimself) oder sonstwo mit mir darüber, bin gespannt.