Follow my new blog

Sonntag, 25. März 2007

Contract-first Design Beispielcode und Tool-Hinweise zu User Group Vorträgen

Am 20.3. und 22.3. habe ich Vorträge zum Thema Contract-first Design vor den .NET User Groups in Ulm und München (Download des Beispielcodes) gehalten. Insgesamt lauschten knapp 80 Entwickler meinen Vorschlägen, wie Software ganz grundsätzlich mit Komponenten als binären Codebausteinen diesseits von SOA-Services und jenseits von Objekten strukturiert werden sollte.

Mit Komponenten habe ich da natürlich das gemeint, was ich in meiner Serie "Software als System" als hybrides Swolon im Schnittpunkt zwischen logischer und physischer Swolon-Hierarchie bezeichne. Auf den Weg von den Anforderungen zu den Komponenten oder das Big Picture von "Software als System" konnte ich allerdings nicht eingehen. Dafür war die Zeit zu knapp. Schon die theoretische Begründung und praktische Demonstration echter Komponentenorientierung hat ja 2-3 Stunden gebraucht - und alle UG Mitglieder haben tapfer ausgehalten.

Und hinterher gab es auch noch interessierte Diskussionen, auch wenn die Implikationen meiner Vorschläge einige recht still gemacht hatten. Echte Komponentenorientierung bedeutet nicht nur, Klassen mal wieder mit Interfaces zu versehen, sondern funktioniert nur auf der Basis eines veränderten Entwicklungsprozesses und einer klareren Codeorganisation, als in den meisten heutigen Projekten. Ich hoffe aber, ich konnte auch den Nutzen eines Umdenkens in Richtung echter Komponentenorientierung vermitteln. Wer mehr Produktivität, bessere Testbarkeit, mehr nutzbringende Dokumentation oder schlicht mehr Qualität und Seelenfrieden haben möchte... der kommt um einige Kurskorrekturen in der Softwareentwicklung leider nicht herum.

Zum Glück machen ein paar Tools den Einstieg aber leichter. Konsequente Komponententests brauchen zwar vor allem guten Willen, wenn der dann aber da ist, sind sie technisch recht einfach. VSTS enthält z.B. einen Unit Test Framework, der auch mit TFS integriert ist. Wer das Geld für VSTS allerdings nicht hat, muss nicht zurückstehen. NUnit ist die Mutter aller automatischen Tests und kostenlos. Allerdings ist NUnit nicht wirklich gut in VS2005 integriert. Macht aber nichts, denn NUnit-kompatible Werkzeuge wie Testrunner (s. folgende Abbildung) oder TestDriven lösen das Problem fast oder ganz kostenlos.


Klicken für Originalbild

Ich bin mit Testrunner schon länger sehr zufrieden. Der macht Unit Tests während der Entwicklung wirklich schmerzfrei und bietet darüber hinaus auch noch eine Codecoverage-Analyse und Profilinginformationen.

Aber Tests während der Entwicklung sind natürlich nicht alles. Echte Komponentenorientierung zerlegt eine Lösung in viele Assemblies, die in separaten VS2005 Projektmappen entwickelt werden. Die muss man den Überblick behalten und immer wieder integrieren. Ein erster natürlicher Integrationspunkt ist ein zentraler Build-Prozess, der die Komponenten periodisch unabhängig vom einzelnen Entwickler auf einem dedizierten Rechner nochmal übersetzt und testet und erst bei Fehlerfreiheit für andere zur Nutzung freigibt.

Dafür setze ich FinalBuilder ein (s. folgende Abbildung; bezieht sich allerdings nicht auf das Beispiel aus dem UG Vortrag). Ein wirklich cooles Tool, mit dem sich die Übersetzung von VS2005 Solutions, deren Test, das Deployment auf einen FTP-Server, der Umgang mit einer Versionsverwaltung uvm. automatisieren lässt. Seit ich FinalBuilder habe, schreibe ich keine Batch-Dateien mehr.


Klicken für Originalbild

Das Bild zeigt ein komponentenorientiertes Projekt aus einer Artikelserie in der dotnetpro. Rechts ist das Script zu sehen, mit dem ich alle zugehörigen VS2005 Projektmappen übersetze und teste, rechts liegt die lange Liste mit vorgefertigten Aktivitäten, aus denen ich solche Scripte zusammensetzen kann. Da bleibt kaum ein Wunsch unerfüllt. Interaktion mit virtuellen Maschinen, parallele Abarbeitung, Workflow, VSS-, SVN-, CVS-, TFS-Nutzung... alles drin.

Aber nicht nur ein umfassender Build-Prozess muss aufgesetzt werden, wenn echte Komponentenorientierung die beliebte allumfassende VS2005 Projektmappe in viele kleine zerschlägt. Es sind dann auch Integrationstestläufe womöglich außerhalb VS2005 nötig. Und der Debugger ist dann vielleicht auch nicht auf einem Staging-System zur Hand. Wer dann wissen will, was so läuft in seinem Programm, der braucht Einblick. Den kann Instrumentierung bieten (z.B. TraceSource einsetzen oder Performance Counter einrichten oder in ein Windows Log schreiben), aber ich finde es auch sehr nützlich, ohne vorgedachte Instrumentierung den Verlauf einer Software beobachten zu können. Derzeit gefällt mir dafür sehr gut SpeedTrace Pro (s. folgende Abbildung).


Klicken für Originalbild

Damit kann ich mich an ein Programm anhängen und mir den Verlauf der Arbeit protokollieren lassen. Das Ergebnis lässt sich filtern, zum Quellcode in Bezug setzen, ich kann sogar das Tracing erst bei einem bestimmten "Event" (Methodenaufruf) starten lassen.

Zuguterletzt gehört zur echten Komponentenorientierung dann noch ein Service Locator oder Microkernel. Mein eigener kleiner Microkernel steht zur freien Benutzung mit kurzen Erläuterungen online. Alternativen sind z.B. Spring.Net oder Windsor des Castle Projects. Die bieten mehr Leistung - für meinen persönlichen Geschmack allerdings oft zuviel. Ich persönlich kann mich auch nicht so recht mit dem Konzept der Inversion of Control (IoC) anfreunden, wenn es um das "Zusammennähen" von größeren Komponentengeflechten geht. Wenn es um Komponenten geht, die ich verkaufen will, oder die in Zusammenhängen eingesetzt werden sollen, in denen nicht sicher ein Microkernel vorhanden ist, dann ist IoC eine gute Sache, um Entkopplung aufrecht zu erhalten. Aber ansonsten ziehe ich innerhalb geschlossener Projekte einen Microkernel als generische Factory vor.

Ich würde mich freuen, wenn ich mit dem Beispielcode des Vortrags vor der UG München und der kleinen Werkzeugliste hier den Einstieg in die echt komponentenorientierte Softwareentwicklung ein etwas erleichtern könnte. Wer das Szenario der Beispielanwendung noch nicht kennt, der sei hier kurz eingeführt (s. folgende Abbildung):

Zwei kooperierende Komponenten sollen entwickelt werden. Die Calculator-Komponente kann Zahlenreihen zwischen zwei Grenzwerten berechnen und solche Zahlenreihen laden/speichern. Sie ist die zentrale Logik-Komponente des Szenarios und verkörpert nach außen die gesamte Funktionalität. Für die konkrete Speicherung ist dann allerdings die DataAccess-Komponente zuständig.

Beide Komponenten sind durch einen Kontrakt definiert. Die Spezifikation der Calculator-Komponente besteht aus dem Calculator- und dem DataAccess-Kontrakt, ersteren exportiert sie, letzteren importiert sie. Die Spezifikation der DataAccess-Komponente besteht aus dem DataAccess-Kontrakt, den sie exportiert, und der Beschreibung des Persistenzformats.


Klicken für Originalbild

Das ist natürlich ein supersimples Beispielszenario. Aber es ging bei der Demonstration nicht darum, komplizierte Funktionen zu implementieren, sondern den Prozess der Entwicklung echter Komponenten erlebbar zu machen. Theoretische Erklärungen am Flipchart sind eine Sache. Dann aber zu sehen, wie die Theorie in die Praxis umgesetzt wird, den Schritten wirklich zu folgen, das ist noch eine ganz andere Sache - und ein Vortrag das beste Medium, um das zu vermitteln. Ich hoffe, das hat geklappt. Freue mich über Feedback an: info (at) ralfw.de.

Keine Kommentare: