Software Entwicklung

Don’t assume!

Manche Weisheiten sind so einfach, dass man sie immer wieder vergisst. Aus diesem Grund hänge ich mir solche gerne bei mir im Büro an die Wand, damit ich regelmäßig mit der Nase drauf gestoßen werden.

In regelmäßigen (oder wahrscheinlich eher unregelmäßgen) Abständen werde ich diese jetzt auch in meinem Blog posten. Ihr findet diese Artikel dann alle unter dem Tag „An meiner Wand”. Den Anfang macht heute die folgende Weisheit von Oscar Wilde:

Don’t assume – it makes an «ass» of «u» and «me».

Auf den ersten Blick klingt das in der Software-Entwicklung etwas seltsam, da wir alle wissen, dass in kaum einem Software-Entwicklungsprojekt immer alle Anforderungen klar auf dem Tisch liegen. Dabei bleibt uns als Entwicklern oft nichts anderes übrig, als Annahmen zu treffen.

Wichtig ist aber, dass man sich in solchen Moment bewusst sein muss, wo man nur Annahmen trifft. Sonst macht man ganz plötzlich Annahmen, von denen man annimmt, dass es Fakten sind. Und nichts ist schlimmer, als Annahmen über Annahmen zu treffen.

Und genau da beginnt das Problem. Sie treffen Entscheidungen auf Basis von Fakten, die nur in Ihrer Vorstellung existieren. Typische Annahmen, die zu Problemen führen sind:

  • „Ich denke nicht, dass der Kunde diese Anforderung nochmal ändern wird. Die ist in Stein gemeißelt.”
  • „Unsere Applikation ist so langsam, weil wir Datenbank XXX verwenden, wir müssen stattdessen die Datenbank YYY einsetzen.”

Während die erste Annahme dazu führt, dass Sie dem Kunden Flexibilität nehmen, investieren Sie bei der zweiten Annahme Zeit und Aufwand in eine Optimierung, die unter Umständen unnötig ist. Damit landen Sie nämlich bei Premature Optimization, und darüber hat Donald Knuth mal gesagt:

Premature optimization is the root of all evil.

Bevor Sie also annehmen, dass ein Kunde eine Anforderung in Stein gemeißelt hat und darauf hin eine Architektur-Entscheidung treffen, sprechen Sie doch lieber mit dem Kunden darüber. Erklären Sie ihm zur Not auch, welche Vor- und Nachteile hat, wenn er genau diese Anforderung unumstößlich festlegt und Ihnen damit eine bestimmte Architekturentscheidung ermöglicht.

Und bevor Sie annehmen zu wissen, wo das Performance-Problem Ihrer Anwendung liegt, fragen Sie doch einfach einen Profiler und stützen Ihre Entscheidungen auf Fakten.

Jedes Jahr eine neue Programmiersprache

Chad Fowler schreibt in seinem Buch „Der leidenschaftliche Programmierer” (im Original „The Passionate Programmer”), dass man jedes Jahr eine neue Programmiersprache lernen sollte.

Da ich mich für einen leidenschaftlichen Programmierer halte, habe ich mir mal Gedanken dazu gemacht, ob ich diesen Tipp in meiner bisherigen Laufbahn befolgt habe. Dabei kam ich auf die folgende Liste von Programmiersprachen, die ich bisher gelernt habe:

  • 1987: Basic
    Damit hat wohl jeder angefangen. Bei mir war es hauptsächlich die Grafik-Programmierung auf meinem Commodore 128D.
  • 1990: Amiga Basic
    Nachdem ich dann einen Amiga 500 hatte, ging es natürlich mit Amiga Basic weiter.
  • 1990: Assembler
    Demo-Programmierung auf dem Amiga 500 und 1200 war einige Jahre meine größte Liebe. Man findet heute sogar noch Demos von mir im Netz.
  • 1991: ARexx
    In ARexx habe ich etwas geschrieben, was man heute wohl als Chat-Bot bezeichnen würde. User, die sich auf unser BBS eingewählt haben, dachten, sie chatten mit unserem Admin, haben sich aber nur mit meinem Programm unterhalten.
  • 1992: Turbo Pascal
    Musste ich zwangsläufig in der Schule lernen, hat mich jedoch nie wirklich begeistert.
  • 1994: Gopher
    Im ersten (und einzigen) Semester meines Informatik-Studiums, seltsamerweise konnte ich im Netz gar nichts mehr dazu finden.
  • 1997: Visual Basic
    Das musste ich lernen, als ich eine Software, für den Comic-Laden, in dem ich gejobbt habe, in Access umgesetzt habe. Es war besser, als es klingt.
  • 1998: HTML
    Ich hatte das Internet entdeckt.
  • 1998: JavaScript
    Und ich hatte entdeckt, dass Webseiten auch interaktiv sein können.
  • 1998: PHP3
    Und dann hatte ich entdeckt, dass Daten für Webseiten aus Datenbanken kommen sollen.
  • 2000: PHP4
    Da bin ich dann ziemlich lange bei PHP hängen geblieben.
  • 2001: ActionScript
    Wer zu dieser Zeit in einer Agentur gearbeitet hat, kam nicht drum rum, auch mal in Flash zu programmieren.
  • 2002: XSLT
    Die Vermischung von Content, Layout und Logik hat mir noch nie gefallen, also musste ich was dagegen tun.
  • 2004: C
    Und wollte natürlich auch mal eine Extension für PHP schreiben. Das hat zwar funktioniert, aber trotzdem habe ich C ziemlich schnell wieder aufgegeben.
  • 2004: PHP5
    Und immer die aktuellste PHP Version einsetzen.
  • 2005: Java
    Habe ich ursprünglich nur gelernt, weil ein Kollege der Meinung war, man könne eine PHP-Anwendung von mir nicht in Java schreiben und ich ihn vom Gegenteil überzeugen wollte. Mittlerweile fühle ich mich in Java mindestens genauso wohl, wie in PHP.
  • 2009: Groovy
    Irgendwann wollte ich doch mal ausprobieren, wie es sich anfühlt, die Stärken von PHP und Java zu vereinen. Leider hat es sich für mich nicht so besonders angefühlt und besonders viel Code ist nicht dabei raus gekommen.

Wenn ich alles zusammenrechne, so schaffe ich es in 22 Jahren auf 17 Programmiersprachen, ich hatte also 5 leidenschaftslose Jahre. Ich hoffe mal, Mr. Fowler sieht das nicht so eng.

Tatsächlich hatte ich 1995 meine lang geplante Entwicklerlaufbahn an den Nagel gehängt und mich stattdessen für ein Pädagogik-Studium entschieden. Der Weg zurück zur Entwicklung war nicht sehr linear und hat gut 2 Jahre gedauert.

Doch nun haben wir 2010, wie soll es also weiter gehen? Weiter geht es dieses Jahr mit Ruby; das Buch dazu habe ich heute bestellt. Es ist also nicht auszuschließen, dass Sie bald an dieser Stelle auch Artikel zu Ruby finden werden. Das wiederum wird Mr. Fowler sicher gefallen, schließlich ist der einer der Mitbegründer von Ruby Central.

23 Dinge über Software-Entwicklung in Teams

Artikel der Serie "23 Dinge"

  1. 23 Dinge über Software-Entwicklung in Teams
  2. 23 Dinge #0: Menschen

Auf der PHP World 2009 in München habe ich einen Vortrag mit dem Titel „23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten” gehalten.

Der Vortrag war gut besucht und ein voller Erfolg. Um die Inhalte einer breiteren Öffentlichkeit zugänglich zu machen, werde ich in den nächsten Wochen jedes der 23 Dinge heraus greifen und in einem Eintrag in meinem Blog genauer betrachten. Eine feste Timeline gibt es dafür nicht, genau so könnte es sein, dass ich die Reihenfolge vom Vortrag abweichen wird.

new-Operator in PHP überladen…

…oder besser nicht? Mit der Extension test_helpers, die Sebastian Bergmann in seinem PHPUnit Channel veröffentlicht hat, ist es möglich, einzugreifen, wenn ein Objekt mit Hilfe des new-Operators erzeugt wird und stattdessen eine andere Klasse zu instanziieren. Das kann vor allem bei Tests nötig werden, wenn es die Architektur einer Anwendung nicht erlaubt, einzelne Klassen auszutauschen:

class NewsFeedGenerator {
    public function generateFeed() {
        $newsTable = new NewsEntryTable();
        foreach ($newsTable->getEntries() as $entry) {
            // hier wird der Newsfeed generiert.
        }
    }
}

Wenn Sie für diese Klasse einen Unit-Test schreiben möchten, der prüft, ob die Klasse einen korrekten Newsfeed generiert, dann sind sie im Test immer davon abhängig, dass sie wissen, welche Einträge aktuell in der Datenbank stehen. Alternativ könnten Sie natürlich auch sicherstellen, dass die Datenbank im Voraus mit den entsprechend erwarteten Einträgen gefüllt wird.

Ein Unittest sollte allerdings eine einzelne Komponente (in diesem Fall den Newsfeed-Generator) isoliert testen, damit der Test nicht fehl schlägt, bloss weil die Datenbank im Moment nicht verfügbar ist. Aus diesem Grund werden in Unit-Tests Mock-Objekte eingesetzt, die das gewünschte Verhalten simulieren. Ein Mock für die Klasse NewsEntryTable könnte ganz einfach implementiert werden:

class NewsEntryTableMock {
    public function getEntries() {
        return array(
            array('id' => 1, 'title' => 'Title 1', 'desc' => 'Description 1'),
            array('id' => 2, 'title' => 'Title 2', 'desc' => 'Description 2')
            // etc.
        );
    }
}

Wenn Sie diese Klasse verwenden, um den Newsfeed zu erzeugen, können Sie sich sicher sein, dass Sie immer die selben Daten als Basis verwenden.

Doch wie bekommen Sie die Klasse NewsFeedGenerator dazu, diese Datenquelle zu nutzen?

Mit Hilfe der neuen Extension ist das ganz einfach, Sie ersetzen die Klasse NewsEntryTable durch NewsEntryTableMock:

function overload_callback($className) {
    if ($className === 'NewsEntryTable') {
        return 'NewsEntryTableMock';
    }
    return $className;
}
set_new_overload('overload_callback');

Wenn Sie nun eine Instanz von NewsEntryTable erzeugen möchten, dann erzeugt PHP stattdessen eine Instanz von NewsEntryTableMock und sie können Ihren Newsfeed-Generator isoliert testen. Problem gelöst, möchte man meinen.

Das Problem ist jedoch nicht, dass ihr Test nicht isoliert ablaufen kann, sondern dass Sie eine feste Kopplung zwischen NewsFeedGenerator und NewsEntryTable in Ihrer Applikation haben. Was passiert, wenn Sie die Datenquelle auch im Betrieb austauschen müssen, da die Newseinträge nicht mehr in einer Datenbank sondern einer XML- oder CSV-Datei gespeichert werden, oder sogar über einen Service von einer anderen Applikation abgefragt werden müssen? Mit der aktuellen Architektur haben Sie dazu keine Möglichkeiten. Mit dem Einsatz von Dependency Injection jedoch schon:

class NewsFeedGenerator {
    protected $dataSource;
    public function __construct(NewsDataSource $dataSource) {
        $this->dataSource = $dataSource
    }
    public function generateFeed() {
        foreach ($this->dataSource->getEntries() as $entry) {
            // hier wird der Newsfeed generiert.
        }
    }
}
interface NewsDataSource {
    public function getEntries();
}
class DBNewsDataSource implements NewsDataSource {
    public function getEntries() {
        // Aus der Datenbank lesen
    }
}

$ds = new DBNewsDataSource();
$generator = new NewsFeedGenerator($ds);

Die beiden Klassen sind nun nicht mehr voneinander abhängig, NewsFeedGenerator hat nur noch eine Abhängigkeit auf das entsprechende Interface, nicht mehr auf die Implementierung. Sie können die Implementierung für den Test oder auch im Live-Betrieb austauschen, ohne dazu die Extension verwenden zu müssen.

Sie mögen Sich nun fragen, wo das Problem liegt, wenn Sie die Klasse durch den Einsatz der test_helpers Extension austauschen, da Sie feste Abhängigkeiten haben. Ein Test für schlecht designten Code ist sicher besser als kein Test für schlecht designten Code. Das hängt jedoch davon ab, was man sich von Tests verspricht. Ich war noch nie ein großer Freund von Unit-Tests, es langweilt mich meistens, Tests zu schreiben. Was mich jedoch dazu gebracht hat, trotzdem Tests zu schreiben, ist, dass ich festgestellt habe, dass die Architektur der Applikation besser wird. Tests sind ein zweiter Client für die Applikation, der uns zwingt, die Applikation aus einem anderen Blickwinkel zu sehen. Durch Tests deckt man Abhängigkeiten auf und wird gezwungen, diese zu lösen. Die ganze Applikation wird loser gekoppelt und einzelne Komponenten leichtegwichtiger.

Das Risiko, das ich also beim Einsatz dieser Extension sehe, ist, dass man nicht mehr gezwungen wird, über die Kopplung nachzudenken. Damit geht ein großer Vorteil von Unit-Tests verloren. Sofern Sie sich sicher sind, dass eine Entkopplung zweier Klassen keine weiteren Vorteile (oder sogar Nachteile) bringt, sollte einem Einsatz der Extension nichts mehr im Wege stehen.

Wenn Sie also test-helpers einsetzen möchten, dann denken Sie jedes Mal darüber nach, ob Sie nicht ein grundlegendes Problem mit Abhängigkeiten haben und besser Ihre Applikation refaktorisieren sollten.

Stubbles needs you!


Dank Frank Kleine kann man jetzt auf Facebook Fan von Stubbles werden. Stubbles ist ein PHP5 Framework, das ich zusammen mit Frank gegründet habe, als wir unsere PHP-Systeme bei 1&1 von meinem alten Framework auf PHP5 migieren wollten.

Das Framework unterscheidet sich von anderen PHP-Frameworks hauptsächlich durch seine Nähe zu Java. So wird gemeinsam genutzter Code über STAR-Archive verteilt, Klassen werden in Namespaces abgelegt und Applikationen hauptsächlich über den Inversion-of-Control-Container konfiguriert, der dem Google-Guice Container aus der Java-Welt nachempfunden wurde.

Daneben ist es auch möglich, Annotations in der Java-Syntax einzusetzen, diese müssen in PHP natürlich in PHPDoc-Kommentare eingebettet werden und werden dann zur Runtime über die Reflection API ausgelesen.

Da ich mittlerweile kaum noch mit PHP entwickle, sondern mich (zumindest beruflich) mehr mit IT Management befasse, wird das Framework aktuell hauptsächlich von Frank und seinem Team weiterentwickelt.

Sonar für PHP

In einem Blog Posting von SQLI durfte ich heute voller Freude lesen, dass bei SQLI daran gearbeitet wird, Sonar auch für PHP-Projekte nutzbar zu machen.

Sonar is an open platform to manage code quality. As such, it covers in its core version the 7 axes of code quality:

  • Architecture & Design
  • Duplications
  • Unit Tests
  • Complexity
  • Potential Bugs
  • Coding Rules
  • Comments

Im Java-Bereich setzen wir bei 1&1 Sonar bereits seit einiger Zeit erfolgreich ein. Nach jedem Commit erzeugt Hudson im Sinne der kontinuierlichen Integration einen kompletten Integrationsbuild, führt Tests aus und analysiert mit Hilfe von Checkstyle den gesamten Sourcecode. Die Ergebnisse davon werden in Sonar visualisiert und geben einen schnellen Überblick, wie es um die Qualität der Applikation bestellt ist. Dabei sind nicht die absoluten Kennzahlen das Maß aller Dinge, sondern mehr die Entwicklung, die die Projekte machen. Eine Testabdeckung von 5% ist grandios, wenn sie gestern noch bei 0% war.

Neben dem Nutzen für uns Entwickler bietet Sonar auch noch einen Nutzen für mein alter ego als IT Manager: Sonar berechnet uns mit Hilfe eines Plugins den technischen Kredit in Euro, den wir aufnehmen, wenn wir bei einer Entwicklung den Fokus auf den Liefertermin statt der Qualität setzen. Diese Zahl gibt Auskunft darüber, wie viel es unser Unternehmen kosten wird, die Applikation an unsere Qualitätsstandards anzupassen. Damit kann für Folgeprojekte argumentiert werden, da die Qualitätsprobleme für das Management sichtbar gemacht werden.

Eine Integration von PHP-Projekten in Sonar war schon lange mein Wunsch, da wir neben unseren Java-Applikationen auch einige business-kritische Applikationen mit PHP betreiben, die bislang noch nicht entsprechend analysiert werden.

Die Entwickler bei SQLI haben es jetzt geschafft, Daten aus SQLI_CodeSniffer (einem Wrapper für PHP_CodeSniffer), PHPUnit (mit XDebug code coverage), PHP_Depend und dem PHPUnit pmd Report in Sonar zu importieren. Im Blog Eintrag gibt es bislang leider erst ein paar Screenshots, produktiv kann das System noch nicht eingesetzt werden.

Ich werde die Entwicklung bei SQLI auf jeden Fall weiter beobachten und bin damit sicher nicht alleine.