Sonntag, 16. Dezember 2007

Forensik

Wenn ein System mal nicht so läuft wie geplant und der Kunde meldet einen Fehler, so ist aus der Fehlermeldung alleine meist nicht klar, was passiert ist. Nun beginnt die mühsame Suche nach Spuren, die auf das eigentliche Problem hinweisen. Im Gegensatz zu Kriminalfällen hat der Entwickler es aber selbst in der Hand, für geeignete Spuren zu sorgen. Im Gegensatz zu Kriminellen ist es sogar in seinem eigenen Interesse, möglichst brauchbare Spuren zu hinterlassen.

Welche Möglichkeiten gibt es, Fehler zu analysieren?

Speicherauszug

Unix-Benutzer kennen sicher die dump-Dateien, die übrigbleiben, wenn ein Prozeß unerwartet abstürzt. Diese Speicherauszüge können mit dem Systemdebugger untersucht werden, als ob das Programm an dieser Stelle auf einen Unterbrechungspunkt gelaufen wäre. Wenn man hängende Prozesse untersuchen will, so kann man einen Speicherauszug auch durch das kill-Kommando provozieren.

Ein Speicherauszug beantwortet sofort die Frage, wo der Fehler aufgetreten ist. Nicht immer ist aber klar, wie das Programm da hingekommen ist.

Unter Java gibt es übrigens das Tool jstack mit dem ein Stackdump aller in einer JVM laufenden Threads erzeugt werden kann. So läßt sich feststellen, wo ein Programm hängt.

Logs

Ein seit je her beliebtes Verfahren, Probleme analysierbar zu machen, sind Logs. Hier werden Informationen über den Programmablauf laufend gespeichert, meist in Textdateien. In der Vergangenheit gab es immer wieder Probleme mit dem Loggen aus parallellaufenden Threads oder mit unvollständigen Ausgaben, da Puffer nicht rechtzeitig auf die Platte geschrieben wurden. Die Stabilität sollte heute mit der Verfügbarkeit von Bibliotheken wie log4j kein Problem mehr sein. Allerdings bedeutet umfangreiches Loggen immer noch ein Performanceproblem, insbesondere wenn Dateien benutzt werden. Eine Datei kann zu einer Zeit nur von einem Thread verwendet werden. Häufiges Schreiben blockiert die Festplatte für andere Nutzer. Wird seltener geschrieben, werden die letzten Einträge vor einem Absturz wahrscheinlich nicht mehr abgespeichert.

In vielen Projekten werden die Ausgaben ad hoc von den Entwicklern formuliert. Dies führt dazu, daß sie sehr uneinheitlich und unterschiedlicher Qualität sind. Eine automatische Auswertung ist in der Regel nicht möglich. Für einen effizienten Umgang mit Log-Informationen ist es notwendig, daß ein einheitliches Log-Format vorgegeben wird. Eine Umsetzung dieser Idee findet sich z.B. in den Common Base Events. Eclipse bietet Werkzeuge zum Umgang mit auf dieser Spezifikation erfolgenden Logs. Ein Ziel, das hier verfolgt wird, ist es, eine serviceübergreifende Ablaufverfolgung in einer SOA-Umgebung zu ermöglichen.

Häufig wird Information in einer Log-Meldung benötigt, die sowieso in der Datenbank verfügbar ist. Um den Log nicht übermäßig aufzublähen, empfiehlt es sich, nicht die Information auszugeben sondern nur eine Referenz auf die Datenbank (Schlüssel). Ein logische Schlußfolgerung aus dieser Vorgehensweise ist es, direkt in eine Datenbanktabelle zu loggen. Dann kann die vollständige Information durch eine geeignete Abfrage angezeigt werden. Die Datenbank ist das ideale Ziel von Logs. Das Schreiben ist in der Regel wesentlich effizienter und die Werkzeuge zur Auswertung sind auch vorhanden. Eine Strukturierung der Information ergibt sich aus dem Design der Logtabelle.

Datenhistorie

In Geschäftsanwendungen wird häufig eine Revisionssicherheit der Daten gefordert. Dies bedeutet, das Daten nicht geändert oder gar gelöscht werden, sondern immer neu eingefügt werden. Die aktuellen Daten werden am Einfügezeitpunkt erkannt, der mitgeführt werden muß. Dies erfordert zwar eine Menge zusätzlichen Speicherplatz, der heutzutage aber kaum etwas kostet, und etwas zusätzlichen Entwicklungsaufwand. Jedoch lassen sich so Vorgänge optimal rekonstruieren. Auch wenn es nicht direkt gefordert ist, sollte beim Systemdesign darüber nachgedacht werden, ob eine Historie zumindest für die wichtigsten Daten nicht machbar ist.



Sonntag, 9. Dezember 2007

Die ganze Welt nichts als Entwurfsmuster

Als Gamma et al. 1994 "Design Patterns" veröffentlichten, wurde nicht nur mir endlich klar, was objektorientierte Programmierung bedeuten kann. Vorher verstanden eigentlich nur die Wenigen, die das Glück hatten, mit Smalltalk programmieren zu dürfen, wie man ein Programm aus Objekten aufbaut. Gewiß, da war noch C++. Aber mal ehrlich, die am meisten genutzte Eigenschaft von C++ ist die Rückwärtskompatibilität zu C. Klassen werden meist nur zur groben Modularisierung gebraucht.


Jetzt nach 12 Jahren Java denken die meisten Softwarearchitekten nur noch in Mustern. Das ist an sich eine gute Sache. So wie der Unterschied zwischen einem Amateurschachspieler und einem Profi ist, daß der erste 64 Felder und (bis zu) 32 Figuren sieht und der letztere Positionen (Muster), so sieht der Programmieranfänger Klassen und der Erfahrene die Muster im Zusammenspiel der Klassen.


Leider gibt es aber auch Nebenwirkungen. Gamma erzählte einmal im Anschluß an einen Vortrag, daß er ein Erlebnis gehabt hätte, daß ihn daran zweifeln ließ, ob er mit seinem Buch Gutes geleistet hätte. Jemand hätte ihn um Rat gefragt. Die meisten der Muster hätte er in seinem Design schon untergebracht, aber für eines hätte er noch keine Verwendung gefunden.


In letzter Zeit hatte ich mit mehreren Systemen zu tun, bei denen die meisten Klassen schon in den Namen auf die verwendeten Patterns hinwiesen. So weit, so gut. Leider fehlten aber weitestgehend Klassennamen, die darauf hätten schließen können, wozu das System eigentlich gedacht war. Die einzige Ausnahme war die Datenzugriffsschicht, deren Klassen aber nur Datenbehälter waren ohne jede Funktion.


Hier läuft etwas grundsätzlich schief. Entwurfsmuster sind großartig, um Probleme zu lösen. Sie sind aber kein Selbstzweck. Ein Softwarearchitekt macht keinen besseren Job dadurch, daß er in seiner Architektur beweist, wieviele Entwurfsmuster er kennt.


Ein Problem mit derartigen Architekturen ist es, daß es sehr schwer ist, eine neue Anforderung unterzubringen. Die Anforderung wird wohl eher lauten, bei Kunden eine Überprüfung auf die Anwendbarkeit eines neuen Rabatts zu ermöglichen, als noch einen Listener um eine Factory zu ergänzen. Basiert die Architektur auf der Begriffswelt des Kunden, ist es sehr einfach die neue Anforderung zuzuordnen. Basiert die Architektur aber auf rein technischen Begriffen, geht dieser Zusammenhang verloren.


Die weitaus bessere Methode, zu einer guten Architektur zu kommen, ist es, mit der Fachlichkeit anzufangen und die fachlichen Anforderungen so zu implementieren, daß sie durch Modultests (JUnit o.ä) gesichert ist. Die technischen Anforderungen und Anbindungen können dann im zweiten Schritt dazuentworfen werden.


Natürlich leisten hierbei Entwurfsmuster gute Dienste. Aber die Anwendung eines Musters muß aus der fachlichen Anforderung resultieren.


Wie kommt es nun zu dieser Fehlentwicklung? Ich sehe hier mehrere Gründe:

  • Manchmal liegt es sicher an einem problematischen Rollenverständnis des Architekten. Dieser meint sich von dem "gemeinen" Programmierer dadurch abheben zu müssen, daß er die Abstraktion soweit treibt, bis keiner mehr folgen kann.
  • Häufiger liegt es jedoch daran, daß die fachlichen Anforderungen noch nicht hinreichend klar sind, wenn schon eine Architektur geliefert werden soll.
  • In manchen Organisationen wird bewußt getrennt zwischen fachlichen und technischen Experten. Dies kann nicht gut gehen. Wenn der Architekt keinen Umgang mehr mit dem Kunden hat, so wird er nie dessen Sprache lernen. Die so entstehenden Anwendungen werden nicht mehr die gewünschte Fachlichkeit wiederspiegeln sondern sich in technischer Beliebigkeit auflösen.

Sonntag, 2. Dezember 2007

Dilbert agil

Dilberts Boss hat mal wieder einen neuen Begriff aufgeschnappt. Er will jetzt "agile programming" einführen und erklärt das so, daß ab sofort ohne Planung und ohne Dokumentation entwickelt wird.

Während sonst meist klar ist, daß Dilberts Boss Unsinn redet, verwendet er hier leider weit verbreitete Vorurteile. Häufig höre ich Leute sagen, wenn ich auf agile Prozesse zu sprechen komme: Ach, daß ist wie in unserem letzten Projekt. Da lief auch alles chaotisch und am Ende haben wir dann doch was geliefert.

Leider haben die meisten noch nie das Agile Manifesto gelesen. Agil arbeiten heißt nicht chaotisch zu arbeiten, sondern das ohnehin von außen kommende Chaos beherrschen zu wollen. Das Vorgehen ist wesentlich zielgerichteter als herkömmlich Prozesse.

Planung

Einen Plan über die gesamte Projektlaufzeit zu erstellen ist Zeitverschwendung. Die Randbedingungen werden sich ändern. Kunde wie Auftragnehmer werden dazulernen. Alles vertraglich festschreiben zu wollen und dann den Kunden mit teuren Change Requests zu bestrafen, wenn sich das Festgeschriebene als unzureichend herausstellen sollte, ist nicht gerade förderlich für die Beziehung zum Kunden.

Stattdessen wird beim agilen Vorgehen nicht ein im Vorhinein festgeschriebenes Projekt betrachtet sondern ein kontinuierlicher Entsicklungsprozeß ohne festgelegtes Ende. Dafür werden in kurzen Abständen nutzbare Ergebnisse abgeliefert. Nach jeder Iteration ist der Kunde frei, das weitere Vorgehen in eine neue Richtung zu lenken.

Dadurch, daß im Abstand weniger Wochen Ergebnisse vorzeigbar sein müssen, ist der agile Prozeß wesentlich ambitionierter wie der herkömmliche, bei dem meist nur ein subjektiver Fortschritt von den Beteiligten abgefragt wird und die Entwicklung dann ewig bei einem Fertigstellungsgrad von 90 % stehenbleibt.

Dokumentation

In einem agilen Prozeß wird nichts um seiner selbst Willen getan. Alles dient nur dem Ziel, mit möglichst geringem Aufwand dem Kunden ein möglichst gutes Produkt zu liefern. Deshalb wird es abgelehnt, Dokumentation nach Gewicht herzustellen. es wird aber alle Dokumentation erstellt, die dem Entwicklungsprozeß dient und ganz sicher alle, die der Kunde zur Nutzung seines Produkts braucht (Benutzerhandbuch, Administrationshandbuch etc.). Dokumente, die nur in einer bestimmten Phase sinnvoll sind, werden auch nicht länger weitergepflegt als sie nützlich sind.

Metaprozeß

Der agile Prozeß ist nicht im Sinne von CMMI (zumindest wie es gewöhnlich verstanden wird) festgeschrieben. Es gibt keinen Prozeß der für alle Situationen paßt und genau angibt, was als nächstes zu tun ist. Stattdessen wird der Prozeß regelmäßig von dem gesamten Team reflektiert und angepaßt. Es existiert also ein Prozeß zur Optimierung des Entwicklungsprozesses. Auf dieser Metaebene ist der Prozeß genau definiert. Auf der Ebene der konkreten Handgriffe ist er flexibel.

Fazit

Dilberts Boss meint auch, daß Dilbert einen Film über Kaffee drehen wolle, als Dilbert erwähnt, daß er Javascript verwende. Sei kein solcher Ignorant. Wenn Dilberts Boss seine zielloses Vorgehen für agil hält, so ist agil mit Sicherheit alles andere als ziellos.