Probleme beim Einloggen
Ralf Westphal Spieglein, Spieglein - Iteration, Review, Issue Tracking
Und wann tun Sie es? Wann wenden Sie das Urprinzip und seine "Ableitungen" auf Ihren Code an? Das ist ja auch nur der Anfang. Andere Prinzipien und Regeln kommen dazu, die auf Ihren Code einwirken.
Befolgen Sie das Urprinzip ständig?
Bei der Versionskontrolle ist das nicht so schwierig. Einfach kontinuierlich während der Entwicklung kleine Verbesserungen einchecken. Nicht einmal am Ende des Tages oder gar am Ende der Woche. Nein, immer wenn Sie einen kleinen Erfolg verbuchen können. Sie erreichen im Verlauf der Implementierung eines Features einen stabilen Punkt? Die Tests sind grün? Dann einchecken.
Auch der Zeitpunkt für automatisierte Tests ist nicht schwer zu bestimmen. Er ist immer. Sie testen ständig. "Code a little, test a little" sagte schon weiland Kent Beck (http://members.pingnet.ch/gamma/junit.htm).
Dito bei der automatisierten Produktion. Die ist auch immer. Deshalb heißt sie ja Continuous Integration. Darüber müssen Sie sich sogar am wenigsten Sorgen machen. Sie läuft im Hintergrund ohne Ihr Zutun.
Wie ist´s nun aber mit der Anwendung der Prinzipien? Achten Sie ständig darauf, DRY zu sein, während Sie ein Feature X implementieren? Streben Sie gleichzeitig Funktionalität/Korrektheit und Innere Qualität an?
Nein. Innere Qualität ist eine Invariante. Das bedeutet, sie muss nicht ständig vorhanden sein, sondern nur am Ende einer Veränderungsperiode. So wie am Ende einer Transaktion die Daten konsistent sein müssen, zwischendurch aber nicht notwendig, so müssen auch die Prinzipien nicht zu jeder Sekunde alle voll eingehalten sein.
So gilt denn auch "Red, green, refactor", d.h. erst korrekte Funktionalität, dann Innere Qualität. Prinzipien müssen erst angewandt werden/sein, wenn die Funktionalität stimmt. Dann ist es Zeit, die korrekte Funktionalität in der Inneren Qualität anzuheben.
Das kann im täglichen Implementierungswahnsinn nach 15 Minuten oder 1 Stunde sein. Sie können eine Refaktorisierung als Prinzipienanwendung also quasi als Pause einplanen. Sozusagen zur Entspannung Qualität schaffen.
Was Sie da so im Tagesgeschäft erreichen in Bezug auf Innere Qualität, wird seine Grenzen haben. Erwarten Sie nicht, dass Sie größere Qualitätsprobleme in diesen "Miniiterationen" von Code-a-little()-Test-a-little(red-green)-Refactor()-Code-a-little()-... aus dem Code räumen können. Dazu sitzt Ihnen die funktionalitätstreibende Kraft zu sehr im Nacken. Dennoch sollten Sie Pausen zur Refaktorisierung des Überschaubaren einlegen.
Erwarten Sie auch nicht, dass Sie größere Qualitätsprobleme überhaupt im Tagesgeschäft sehen. Dafür sind Sie womöglich zu betriebsblind.
Es bleibt also die Frage: Wann tun Sie es? Wann räumen Sie die größeren "Design Issues" aus dem Code?
Die Antwort ist einfach: ebenfalls nach einer bzw. im Rahmen einer Iteration. Nach dem Urprinzip ist der nächste CCD-Baustein auf Ihrem Weg daher die Einführung von Iterationen. Die müssen nicht im Sinne von Scrum echte Sprints sein. Mit Absicht haben wir darauf im CCD-Wiki auch keinen Bezug genommen. CCD-Iterationen sind noch einfacher: Es geht nur darum, dass Sie sich einen Zeithorizont schaffen, der im Bereich 1 bis 3 Wochen liegt, in dem Sie wasimmer Sie wollen, wiederholt einplanen können.
Alles, was Sie nicht vergessen wollen, planen Sie in Iterationen ein. Alles, worüber Sie nicht ständig wieder diskutieren wollen, planen Sie in Iterationen ein. Im roten Grad haben wir das für Sie schon getan. Der definiert als kleinste Iteration den Tag. Und am Ende jedes Tages reflektieren Sie über die Einhaltung der CCD-Bausteine. Jeden Tag. Immer. Ohne nachzudenken. Ganz unemotional.
Für Ihr Projekt tun Sie das dann z.B. wochenweise. Sie definieren als Teamiteration 5 Tage und setzen z.B. auf den Mittwoch Nachtmittag einen Codereview. Wieder ein CCD-Baustein. Indem Sie ganz einfach laut Plan, der jedem zugänglich ist, jede Woche einmal einen Codereview machen, wissen Sie, wann Sie größere Qualitätsprobleme finden: immer wieder Mittwochs. Mindestens.
Und damit wissen Sie auch, wann Sie das Urprinzip anwenden: am Donnerstag. Denn nach dem Codereview ist die größere Refactorisierung. Wasimmer Sie an Veränderungswürdigem während des wöchentlichen Codereviews finden, das tragen Sie - nächster CCD-Baustein - in Ihr Issue Tracking Tool ein und erledigen es schnellstmöglich. Am besten gleich donnerstags.
Takten Sie Ihre Arbeit! Denn wenn Sie erstmal einen offiziellen Takt (Iteration) haben, dann müssen Sie nicht fürchten, die CCD-Prinzipien allzulange zu vernachlässigen, selbst wenn es mal im Tagesgeschäft noch höher hergeht. Und Sie müssen auch nicht ständig wieder mit Kollegen oder dem Chef darüber diskutieren, mal wieder einen Review (Reflektion des Codes) oder eine Retrospektive (Reflektion des Prozesses) einzulegen. Die sind einfach ganz regelmäßig dran.
Achten Sie nur darauf, dass die Ergebnisse solcher Reflektionen ins Issue Tracking Eingang finden wie jeder Featurerequest des Kunden. Da darf es keinen Unterschied geben. Verschieben Sie das Refaktorisierung also nach dem Aufdecken von "Code Smells" nicht, sondern nehmen Sie sie in Angriff. Sonst wird es nur schlimmer!
Jetzt sind Sie gerüstet für mehr Prinzipien, Regeln und Praktiken. Sie haben ein Sicherheitsnetz für angstefreie Arbeit am Code, sie erkennen erste "Problemzonen" (oder sollte ich sagen: Feuchtgebiete? ;-) - und Sie wissen, dass Sie die Problemzonen garantiert angehen: der Testbalken muss nur grün werden oder die Iteration enden. Reflexion ist das Zauberwort.
-Ralf Westphal
Ralf Westphal Das Urprinzip - DRY und seine Spezialisierungen SRP und SoC
Was tun mit all der hergestellten Testbarkeit? Versionsverwaltung + automatisierte Tests + automatisierte Produktion sind ja nur ein Rahmen für angstfreie Veränderung. Wohin aber den Code verändern? Was unterscheidet Code mit hoher "innerer Qualität" von Legacy Code?
Wie wesentlichen Antworten im Leben ist die auf diese Frage auch einfach:
Hohe "innere Qualität" zeichnet sich vor allem durch die Abwesenheit von Wiederholungen jeder Art aus.
Und wie alle wesentlichen Antworten im Leben bedarf auch diese der Interpretation und stetiger Anstrengung, ihr gerecht zu werden.
Das zu dieser Antwort passende Urprinzip ist DRY: Don´t Repeat Yourself. Es hat nicht umsonst Aufnahme in den roten Grad gefunden. Wiederholungen sind zu vermeiden, weil jede Wiederholung den Keim der Inkonsistenz in sich trägt. In der Datenbankentwicklung ist Normalisierung nicht umsonst ein zentrales Thema. Für die Codeentwicklung ist DRY das Pendant. (Ja, das bedeutet auch, dass gelegentlich Code moist/feucht sein darf, so wie Datenbankschemata auch gelegentlich bewusst denormalisiert sind. Beides sollte aber nur mit Bedacht zugelassen werden.)
Sobald Ihr Code im Rahmen der Angstfreiheit aufgehängt ist, beginnen Sie also am besten mit der Suche nach den offensichtlichen und dann den subtilen Wiederholungen.
Wiederholungen können winzig sein wie eine Zahlkonstante im Code. Oder sind können ausgedehnt sein wie ganze Klassen - die sich dann natürlich irgendwie schon unterscheiden. Wirklich 1:1 wiederkehrende Codeabschnitte sind kaum mehr als einige Zeilen lang. Am Anfang mag zwar oft auch bei längeren Wiederholungen ein 1:1 Copy&Paste stehen - doch der kopierte Code wird meist an seinen neuen Kontext angepasst, so dass er nur noch ähnlich zum Original ist.
Der Übergang von der offensichtlichen zur subtilen Wiederholung ist also fließend und recht schnell. Sie müssen also Ihre Wahrnehmung dafür sensibilisieren, mehr oder weniger ähnliche Codeabschnitte zu entdecken. Insofern warten Sie auch vergeblich darauf, dass Tools Sie entscheidend bei der "Austrocknung" Ihres Codes helfen. Die Muster, um die es geht, sind eher logisch/semantisch denn textuell/syntaktisch.
Auf der nächsten Stufe verliert sich dann sogar jede handfeste Spur von Wiederholung. Über die sichtbaren Wiederholungen von Artefakten hinaus gibt es nämlich auch die von Bedeutungen. Ein Beispiel: In den Eventhandlern eines Fensters finden Sie an vielen Stellen Zugriffe auf die Datenbank. Die sehen alle ganz, ganz anders aus, weil es in jedem Eventhandler um andere Daten geht. Dennoch liegen Wiederholungen vor! Die Bedeutung dieser Abschnitten mit DB-Zugriff ist gleich: es geht eben wiederholt um DB-Zugriff.
Die Verantwortlichkeit von Code für den Umgang mit der Datenbank wiederholt sich, auch wenn die Anweisungen sehr verschieden sind. Wenn sich an dieser Grundverantwortlichkeit etwas ändert, dann muss womöglich an vielen, sich ansonsten unähnlichen Stellen nachgezogen werden.
Das DRY-Prinzip ist somit das Urprinzip unterhalb des Single Responsibility Principles (SRP). Im Sinne von Occams Skalpell könnte das Clean Code Developer Bausteinsystem deshalb sogar auf SRP verzichten. Es wiederholt in anderen Worten letztlich nur, was DRY schon beschreibt. DRY ist umfassend; es bezieht sich auf jede Art von Wiederholung. SRP ist spezifischer, indem es auf semantische Wiederholungen fokussiert.
Dasselbe gilt für dann auch für das Separation of Concerns Prinzip (SoC), welches wiederum aus SRP hervorgehend gedacht werden kann. SoC ist noch spezifischer als SRP, weil Concerns eine Untermenge aller Verantwortlichkeiten sind. Verantwortlichkeiten sollen nur verschieden sein; Concerns/Belange jedoch sind sogar noch orthogonal zueinander.
Wenn Sie in den Eventhandlern eines WinForms-Formulars zum Beispiel Code zu den Themen:
-Graphische Anzeige
-Datenbankzugriff
-Geschäftslogikberechnung
-Validation
-Menüsteuerung
-Sicherheit
-Geschäftsregeln
finden, dann sind das alles natürlich unterschiedliche Verantwortlichkeiten. SRP verlangt dann nur, sie alle irgendwie zusammenzufassen.
SoC geht jedoch weiter. Für SoC stehen manche Verantwortlichkeiten in einer Linie oder liegen in Schichten aufeinander, z.B.
-Graphische Anzeige, Menüsteuerung
-Geschäftslogikberechnung, Geschäftsregeln
-Datenbankzugriff
Andere Verantwortlichkeiten jedoch lassen sich zwar absodern, nicht jedoch eindeutig in dieser Linie oder einer Schicht verorten. Das sind dann orthogonale oder übergreifende Belange wie z.B.
-Validation
-Sicherheit
Wie eingangs erwähnt, brauchen gerade einfache Antworten immer wieder Interpretation, um echt handlungsleitend zu werden. SRP und SoC sind in diesem Sinn als Auslegungen zu verstehen. Deshalb belassen wir sie auch im CCD-Bausteinsystem.
Sobald Sie Testbarkeit hergestellt haben und Ihrem Code mehr "innere Qualität" geben wollen, machen Sie sich auf die nimmerendende Suche nach Wiederholungen. Das leitende Urprinzip ist DRY mit seinen Konkretisierungen SRP und SoC.
-Ralf
Stefan Lieser Erfahrungen eines Clean Code Developers
Das Buch „Design Patterns“ der „Gang of Four“ war mein Schlüsselerlebnis und der Einstieg in eine neue Art und Weise der Softwareentwicklung. Hatte ich vorher, trotz (oder vielleicht wegen) Informatikstudium, arg daran gezweifelt, dass die Softwareentwicklung jemals eine ingenieurmäßige Vorgehensweise an den Tag legen würde, so war ich durch die im Buch dargestellten Entwurfsmuster plötzlich sehr positiv gestimmt. Endlich musste ich nicht mehr für jedes Problem das Rad neu erfinden. Endlich konnte ich mir vorstellen, dass es möglich sein muss Code so zu schreiben, dass er nicht nach wenigen Wochen schon so verrottet ist dass nichts mehr geht.
Nachdem ich die üblicherweise auftretende Patternkrankheit (eine Phase in der man aber auch jedes Pattern unbedingt in seinen Projekten unterbringen muss) überstanden hatte, begann ich mit der testgetriebenen Entwicklung. Auch das ein Schlüsselerlebnis! Endlich Sicherheit. Endlich Zuversicht, dass beim Ergänzen weiterer Features die vorhandenen weiterhin funktionieren.
Zwei weitere Bücher die mir die Augen geöffnet haben: „Refactoring“ von Fowler und „Refactoring to Patterns“ von Kerievski. In Verbindung mit automatisierten Tests als Sicherheitsnetz hatte ich endlich einen Weg gefunden meinen Code zu verbessern. Endlich kann ich der Software Entropie Einhalt gebieten.
Die Mischung aus Patterns, Tests und Refactoring waren erste Grundbausteine auf meinem Weg zum Clean Code Developer, ohne dass der Begriff bereits geprägt war. Natürlich musste ich meine eigenen sehr positiven Erfahrungen weiter geben. So habe ich begonnen Vorträge in .NET User Groups zu halten. Aber auch meine Kollegen kamen nicht zu kurz. Sie „durften“ sich manchen Ausbruch von Begeisterung anhören und ernteten oft Kopfschütteln über in meinen Augen völlig unzureichende Praktiken der Softwareentwicklung. Sicher war ich im Eifer des Gefechts manches mal zu ungeduldig und zu fordernd, aber im Laufe der Zeit stellte sich der gewünschte Erfolg durchaus ein.
So wurden beispielsweise Schnittstellen zu Fremdsystemen in kurzer Zeit entwickelt und liefen sofort nach Auslieferung. Neue oder geänderte Anforderungen können wir nun sehr schnell umsetzen und haben durch die Testabdeckung die Sicherheit, dass alles so funktioniert wie es soll. Inzwischen können wir feststellen, dass der Supportaufwand bei den Altprodukten weiter konstant bleibt oder sogar ansteigt, während bei den nach CCD Manier entwickelten Produkten selten Support anfällt.
Die Einführung der Prinzipien, Regeln und Praktiken des Clean Code Developers würde mir heute sicher leichter fallen. Als ich begann meine Kollegen damit zu „beglücken“ fehlte manchmal die Struktur. So versteht man den Wert eines Continuous Integration Prozesses wahrscheinlich erst wirklich, wenn man den Nutzen von automatisierten Tests persönlich erfahren hat. Die eigene Reflexion über die Art und Weise wie ich versucht habe meine Kollegen an die Problematik heranzuführen hat mit dazu beigetragen die Clean Code Developer Initiative ins Leben zu rufen. Heute steht mit dem CCD Wiki eine durchdachte Vorgehensweise zur Verfügung die ein einzelner Entwickler oder auch ein Team „lediglich“ anzuwenden braucht. Aus meiner Erfahrung kann ich nur sagen: Es lohnt sich!
Herzliche Grüße
Stefan Lieser
--
http://www.lieser-online.de/blog/?page_id=151
Ralf Westphal Testbarkeit herstellen - Dependency Inversion
Wenn die Grundlage für jede angstfreie Veränderung automatisierte Tests sind, wie können die denn in legacy code eingeführt werden? Testbarkeit herzustellen, ist daher für mich der erste Anwendungsfall für CCD Prinzipien.
Während im roten Grad DRY und KISS als Prinzipien eingeführt werden, stelle ich in dieser Roadmap das Dependency Inversion Principle an den Anfang. ("Working effectively with Legacy Code", zu finden in der CCD Literaturliste, nennt noch andere Möglichkeiten, die ich allerdings für weniger CCD-gemäß halte.)
Um Fehler, die in automatisierten Tests auftreten, möglichst einfach lokalisieren zu können, sollte jeder Test sich nur eine vergleichsweise kleine Codeeinheit zur Brust nehmen. Nur dann kann ein Test auch überhaupt schnell werden. Das ist wichtig, weil nur schnelle Tests so häufig wie nötig ausgeführt werden.
Die unmittelbar wichtigen Tests für jeden CCD sind daher Unit Tests. Vom gelben Grad hole ich sie ebenfalls hier an den Anfang des Weges. Automatisierte Unit Tests machen angstfrei. Sie sind leichtgewichtig und daher mit wenig Aufwand auch lokal begrenzt einführbar. Allerdings ist etwas Infrastruktur dafür nötig, ein Test-Framework wie NUnit und ein Testrunner wie NUnit Console oder ReSharper oder Testdriven.Net.
Unit Tests machen aber nur wirklich Freude, wenn ihr "system under test" (SUT) überschaubar ist. Jeder einzelne Test sollte nur einen recht kleinen Codebereich abdecken. Insbesondere sind Durchstiche zu vermeiden. Sie sind Thema für Integrationstests jeder Art.
Das Dependency Inversion Principle (DIP) hilft nun, Codegeflechte aufzubrechen. Statt Code aus einem Stück zu weben, ziehen Sie mit DIP Nähte ein.
Und bei existierendem Code zerreißen Sie das vorhandene Gewebe und nähen es sozusagen als Patchwork anschließend wieder zusammen. Der Vorteil: Sie können dann in Tests jedem SUT seine Abhängigkeiten unterschieben, wie es eben passt. Damit konzentrieren Sie den Test auf das SUT und vermeiden Nebeneffekte durch ganz anderen Code tief unten im call tree unterhalb des SUT.
Sobald Sie eine Versionsverwaltung als "Angstkiler #1" aufgesetzt haben, steht für den "Angstkiller #2" das Unit Testing und DIP auf dem Programm. Die automatisierte Produktion können Sie nebenbei aufsetzen, falls noch nicht geschehen. In die beziehen Sie natürlich schrittweise auch die automatisierten Tests ein.
Im CCD Wiki finden sich Unit Tests erst im gelben Grad. Der Grund: Sie erfodern schon Veränderungen an der Codebasis ohne dass der Gesamteffekt anschließend abgeschätzt werden könnte. Uns schien es im Sinne eines einfacher zu gehenden Weges für den Einzelnen auch simpler, Unit Tests erst so spät einzuführen. Gibt es jedoch breiten Konsens zu automatisierter Testbarkeit, dann dürfen Sie gern früher in Unit Tests einsteigen.
Für den Fall jedoch, dass Sie die schon auf ein umfassenderes Testfundament stellen wollen, führen Sie parallel Integrationstests ein. Integrationstests, die durch das UI hindurch Anwendungsteile testen. Oder Integrationstests, die mit dem Mitteln des Unit Testings schon dicht unter der Oberfläche ansetzen - falls das möglich ist.
Dann können Sie zuerst einen Integrationstest aufsetzen, der auch die Funktionalität prüft, die sie im nächsten Schritt dann isoliert mit einem Unit Test abdecken. Gehen Sie also depth first vor: vom Integrationstest zum Unit Test. Breadth first ist womöglich aufwändiger und würde bedeuten, erst alle Integrationstests zu entwickeln, bevor sie tiefer steigen.
In jedem Fall gehört zur Herstellung von Angstfreiheit das DIP ganz an den Anfang des CCD-Weges.
-Ralf Westphal

Moderatoren

Infos zu den Moderatoren

Über die Gruppe "Clean Code Developer"

  • Gegründet: 11.03.2009
  • Mitglieder: 5.022
  • Sichtbarkeit: offen
  • Beiträge: 491
  • Kommentare: 2.987