Scrum’s not agile

13.01.2012

Hypotheses on agility and software development.

What is the meaning of Agility?

“Agility is about staying successful in an ever-changing environment” – Jürgen Appelo, Management 3.0

Is Scrum Agile?

No. No process is agile, the team and especially the individuals who form the team are agile!

Individuals and interactions over processes and tools.” - Agile Manifesto

Does Scrum prescribe what to do?

No. Each team member is an expert in his field of knowledge and knows what to do to make the team successful.

“Build projects around motivated individuals. Give them the environment and support they need, and trust them to get the job done.” – Agile Manifesto, 12 Principles

Then, what is the value of Scrum and other agile methodologies?

Scrum..

  • provides a minimal structure and best practices to help the team being agile.
  • provides a protected setting, in which the team can develop freely.
  • demands working software at the end of each sprint, which is the primary goal of every software development project.
  • prescribes the application of a Definition of Done to determine, when a job is done.

“Working software is the primary measure of progress” – Agile Manifesto, 12 Principles

Is Scrum sufficient to be successful?

No. It is not sufficient to just employ the best practices from scrum to stay successful over an extended period of time. You need technical excellence and must enforce quality standards to stay successful.

“Continuous attention to technical excellence and good design enhances agility” – Agile Manifesto, 12 Principles


Dodging SmartGWT Pitfalls

06.01.2011

Das Google Web Toolkit (GWT) und dessen API für Smart Client (SmartGWT) haben in den letzten Jahren eine grosse Anhängerschaft gewonnen. Sie bieten dem Entwickler ein umfassendes Framework mit einer grossen Auswahl von fertigen GUI-Komponenten wie Formulare, Tabs, Buttons, Listen, etc. das eine effiziente und zeitsparende Programmierung von Rich Internet Applications (RIA) erlaubt. Im Gegensatz zu den meisten vergleichbaren Frameworks wird dabei in Java entwickelt, das daraufhin in Javascript und HTML cross-compiled wird. Dies ermöglicht das Erstellen von hochgradig interaktiven und komplexen Web-Applikationen, die ohne jedes zusätzliche Plug-in im Browser laufen.

Wie beim Einstieg in jede Technologie gibt es aber auch bei SmartGWT eine Anzahl von klassischen Anfängerfehlern (a.k.a „Pitfalls“), die einem Entwickler am Anfang das Leben schwer machen können und im ungünstigsten Fall für erheblichen Verlust von Zeit (und Nerven) sorgen. Dieser Blog-Eintrag soll ein paar der häufigsten Pitfalls aufzeigen, um damit zukünftigen SmartGWT-Einsteigern das Leben zu erleichtern.

Development Mode vs. Web Mode

Der sogenannte „Development Mode“ erlaubt dem Entwickler die Applikation nach Codeänderungen auf die Schnelle zu starten (und zu Debuggen) ohne das die ganze Applikation dafür neu deployed werden muss. Dabei wird die Applikation über eine separate „Development Console“ gestartet, die auch etwaige Fehlermeldung mit Stacktrace anzeigt, die im Browser nicht zu sehen sind.
Das Verhalten der Applikation in „Development Mode“ sollte dabei identisch zum Verhalten als im normalen „Web mode“ sein. Dies ist aber besonders bezüglich fehlerhaftem Code nicht immer der Fall. Während im „Development Mode“ gewisse Fehler wie Nullpointer Exceptions in nativem Javascript Code grosszügig verkraftet und lediglich eine Fehlermeldung in der „Development Console“ anzeigt, führen selbige im „Web Mode“ oft zum Blockieren der ganzen Anwendung ohne das dem Benutzer die Ursache mitgeteilt wird. Die Gefahr besteht deshalb hauptsächlich darin, dass ein Entwickler beim Programmieren eines Feature bei sich lokal immer nur im „Development Mode“ testet, und es anschliessend commitet, wodurch der umbemerkte Fehler daraufhin in der Test- oder Integrations-Umgebung gelangt, wo die Applikation natürlich im normalen „Web Mode“ läuft, und im schlimmsten Fall die ganze Applikation blockieren kann. Da der Benutzer dabei aber keine spezifische Fehlermeldung erhält, kann die Reproduktion und Behebung solcher Bugs sehr schwierig sein.

Lösung:
Um dies zu verhindern, empfiehlt es sich immer vor dem Commiten von Code dessen Funktionalität auch noch einmal im „Web Mode“ zu testen. Weiter hat es sich bewährt beim Entry Point der Applikation ein try-catch block zu platzieren, der alle bis dahin nicht abgefangene Exceptions behandelt und sie zumindest dem Benutzer in einer Form präsentiert, die einen brauchbaren Bug-Report ermöglichen.

Overlay Types und Vererbung

Javascript Overlay Types bieten die Möglichkeit Java Klassen um native Javascript Objekte zu wrappen. Dies erlaubt nebst einer einfache Handhabung einen minimalen Overhead für die Verarbeitung häufig verwendete Objekte und resultiert dadurch in einer sehr hohe Performanz. Overlay Types sollten jedoch mit Vorsicht eingesetzt werden, denn neben den eben genannten Vorteilen, besitzen sie auch einige Nachteile. Eine vorschnelle Entscheidung, ganze Klassen-Hierarchien für zentrale Objekte der Applikation als Overlay Types umzusetzen, kann im späteren Verlauf der Entwicklung zu Problemen führen, wenn deren Einschränkungen zu unzähligen (und schwer wartbaren) Workarounds zwingen. Hier deswegen eine kleines Code-Snippet, das einige der bedeutendsten Einschränkungen von Overlay Types aufzeigt. Auf den ersten Blick scheint es (abgesehen von der speziellen native Javascript- Methode „fooNative“ dem korrekten Java-Syntax zu folgen:

public class myOverlay extends JavaScriptObject {

    Integer i;

    public final native String fooNative()
        /*-{ return this.first_name; }-*/;

    public void foo() {
        i = 1;
    }
}

Keine Instanziierung mit „new“ Operator möglich

Der Versuch, ein Overlay Type mit dem „new“ Operator zu instantiieren, scheitert mit der Fehlermeldung:

[ERROR] ‘new’ cannot be used to create instances of JavaScriptObject subclasses; instances must originate in JavaScript

Workaround:
Verwenden der statischen Methode zur Erzeugung eines  „JavaScriptObject“s:
myOverlay test = (myOverlay) JavaScriptObject.createObject();

Keine Public Konstruktoren erlaubt

Aber auch dann meckert der Compiler weiterhin, da der default Konstruktor automatisch public ist:

[ERROR] Constructors must be ‘protected’ in subclasses of JavaScriptObject

Workaround:
Manuell einen protected Konstruktor definieren.

Instanz-Variablen in Java Klasse sind nicht erlaubt.

Overlay Types erlauben keine Instanz-Variablen. Die nächste Fehlermeldung bezieht sich daher auf die dritte Zeile:

[ERROR]  Instance fields cannot be used in subclasses of JavaScriptObject

Workaround:
Nur möglich für primitive Typen oder Subklassen von Overlay Type, durch Setzen als Javascript-Variablen in nativen Methoden.

Einschränkungen bezüglich Vererbung

Overlay Types erlauben keine nicht-finale Methoden, ausser in finalen Klassen. Die Methode „foo“ führt daher zu folgender Fehlermeldung:

[ERROR] Instance methods must be ‘final’ in non-final subclasses of JavaScriptObject

Workaround:
Die Klasse oder die Methode „finale“ machen. Da dadurch eine Subklasse die Methoden ihrer Superklasse nicht mehr überschreiben kann, geht damit natürlich einer der Vorteile der Verwendung von Vererbungs-Hierarchien  verloren. Auch die Alternative, dass verschiedene Overlay Type Subklassen ein gemeinsames Interface implementieren, erlaubt GWT nicht. Als weitere Einschränkung liefert der Vergleichsoperator „instanceof“ beim Vergleich zweier Overlay Type Objekte fälschlicherweise immer „true“ zurück, unabhängig von ihrer realen Vererbungs-Beziehung.

Fazit

Overlay Types sollten nur für Performance-kritische Objekte verwendet werden, die in keiner komplexen Vererbungshierarchien zueinander stehen sollen. Für alle anderen Anwendungszwecke ist der Entwickler mit POJOs besser bedient, und erspart sich einen Menge von hässlichen Workarounds.

Nicht eindeutige Ids von Komponenten

Ein kleiner aber doch klassischer Fehler ist das manuelle Vergeben von nicht-eindeutigen Komponenten-Ids. Die meisten GWT Komponenten erlauben dem Entwickler manuell die verwendete Id der Javascript Repräsentation einer Komponente zu definieren. Verwendet man versehentlich die selbe Id für zwei verschiedene Komponenten, wird dies zur Kompilierzeit zwar nicht bemerkt, führt aber zur Laufzeit zu Kollisionen im DOM-Tree. Dies kann dann zu scheinbar nicht-deterministischem Verhalten der Applikation führen, was das Auffinden dieser Fehlerursache sehr erschwert.

Lösung:
Wenn möglich, manuelles Vergeben von Ids unterlassen, GWT generiert dann automatisch eine eindeutige Id für die Komponente.

Vermischen von GWT-Core und SmartGWT Komponenten

Eine weit verbreitete Fehlerursache ist auch das unbedachte Vermischen von GWT-Core und SmartGWT Komponenten. Dies führt auch wiederum zu keinen Fehler zur Kompilierzeit, kann aber genau wie die nicht-eindeutigen Komponenten-Ids zu schwer zu isolierenden Fehlverhalten zur Laufzeit führen. Oftmals äussert sich dies in Form von HTML-Layout und Z-Ordering Problemen und führt dazu dass andere, eigentlich völlig unbeteiligte GUI Komponenten plötzlich nicht mehr auf User-Interaktion reagieren.

Lösung:
Ausser in Ausnahmefällen ist das direkte Verwenden von GWT-Core Komponenten in einer SmartGWT-Applikation gar nicht nötig, da für praktisch alle GWT-Core Komponenten ein entsprechender SmartGWT-Wrapper existiert.

Referenzen

Offizielle GWT Homepage
http://code.google.com/intl/de-DE/webtoolkit/overview.html
Offizielle SmartGWT Homepage
http://code.google.com/p/smartgwt/
SmartGWT showcase
http://www.smartclient.com/smartgwt/showcase/
SmartClient Forum
http://forums.smartclient.com/forumdisplay.php?f=14


Cleaner Code durch Anti-Patterns (-vermeidung)

13.12.2010

Mit Interesse habe ich den Artikel im Javamagazin 12.2010 „Clean Code muss sein, aber wie?“ gelesen und kann dem darin gesagten nur zustimmen. Aber ein Prinzip, das mir wichtiger erscheint als das DRY-Prinzip und die sonstigen genannten, wurde nicht angesprochen. Ich meine die korrekte Verwendung von Sprachkonstrukten. Im Artikel wurde folgendes (gekürzte) Code-Snippet als Beispiel verwendet:

public class FileProcessor {
    public void processXMLFile(File f) {
        InputStream is = null;
        try {
            is = new FileInputStream(f);
            processXML(is);
        } catch (Exception e) {
            // Ausnahme sinnvoll behandeln
        } finally {
            try {
                if (is != null) { // ***
                    is.close();
                }
            } catch (IOException e) {
                // Ausnahme sinnvoll behandeln
            }
        }
    }

    private void processXML(InputStream is) {
        // InputStream verwenden
    }

    // more methods ...
}

Und diese Art von Codefragmenten sehe ich in letzter Zeit öfters; in Zeitschriften, bei Reviews von Kollegen und erstaunlicherweise im Java-Tutorial über Ausnahmen! So, was ist nun falsch an diesem Codefragment im Sinne meiner Behauptung? Für mich ist immer ein sicheres Indiz für die falsche Verwendung eines Ressourcenschutzblocks die Überprüfung der Ressource-Variablen auf null im finally Block um eine NullPointerException zu vermeiden (im Beispiel mit // *** gekennzeichnet). Ich sehe darin ein Anti-Pattern, denn es widerspricht dem Idiom für Ressourcenschutzblöcke:

acquire resource;
try {
  use resource;
// optional
} catch (<Exception_you_want_to_handle> e) {
  recover your data or encapsulate in other exception;
// optional end
} finally {
  release resource;
}

Und was machen wir nun in unserem konkreten Beispiel? Wir refaktorieren den Code!
Nach obigen Idiom sollte der Code folgendermassen aussehen:

    public void processXMLFile(File f) {
        InputStream is = new FileInputStream(f); // ***
        try {
            processXML(is);
        } catch (Exception e) {
            // Ausnahme sinnvoll behandeln
        } finally {
            is.close(); // ###
        }
    }

Nun ja, jetzt entspricht der Code dem Idiom, dafür haben wir aber jetzt andere Probleme. Der Code kompiliert nicht mehr, da es an den Stellen // *** und // ### unbehandelte Ausnahmen gibt. Das erste Problem ist, dass der Konstruktor ebenfalls eine Ausnahme werfen kann. Wenn wir nicht die FileNotFoundException in die Methodensignatur aufnehmen wollen (Specify), dann müssen wir sie eben in einem try-catch Block einkleiden (Catch). Nicht das nur der Konstruktor eine Ausnahme werfen kann, nein auch beim Schliessen des Streams kann es eine IOException geben. Meine IDE schlägt mir vor, die FileNotFoundException im try-catch-Block zu einer IOException zu generalisieren. Hier müssen wir aber vorsichtig sein um uns nicht ein anderes Anti-Pattern einzuhandeln. Ich meine „Ausnahmen im finally Block“, die eine mögliche Ausnahme während der Nutzung der Ressource verdecken. Problematisch wäre das in unserem Beispiel, wenn in der Methode processXML() die IOException von InputStream.read() zur Methodensignatur hinzugefügt würde. Damit die Fehlerzustände unterscheidbar bleiben, füge ich einfach einen weiteren catch-Block hinzu und erhalte somit folgenden refaktorierten Code:

public class FileProcessor {
    public void processXMLFile(File f) {
        try {
            InputStream is = new FileInputStream(f);  // acquire
            try {
                processXML(is);        // use
            } finally {
                is.close();          // release
            }
        } catch (FileNotFoundException e) {
             // can't open stream
        } catch (IOException e){
            // can't close stream
        }
    }

    private void processXML(InputStream is) {
        // InputStream verwenden
        try {
            int i = is.read();
    // do something with the data
        } catch (IOException e) {
            // can't read stream
        }
    }
}

Jetzt entspricht unser Code dem Idiom und behandelt auch die Ausnahmen, die beim Besorgen und Freigeben der Ressource geworfen werden können. Als Nebenprodukt ist noch ein weiteres Anti-Pattern im Zusammenhang mit Ausnahmen verschwunden: das „Catch-Exception-Anti-Pattern“, das zu unspezifisch die Ausnahme behandelt und wodurch wertvolle Typinformationen über die Ausnahme verloren gehen. Die Aussage „Ausnahme sinnvoll behandeln“ lässt sich mit einer generellen Exception auch ziemlich schwer interpretieren. Wie man überhaupt Ausnahmen sinnvoll behandelt ist ein anderes Thema über das man wieder einen eigenen Artikel schreiben könnte.

Fazit

Diese kleine Abhandlung hat gezeigt, dass man auch durch die Refaktorierung von Antipatterns zu „CleanCode“ und damit robusteren, verständlicheren und wartbaren Code kommen kann und dass das und die korrekte Verwendung von Sprachkonstrukten/Idiomen vor der Anwendung weiterer Prinzipien des CleanCode kommen sollte. Zudem wurde das Anti-Pattern „Nullcheck der Ressourcen-Variablen im finally-Block“ eingeführt, dass ich, nach einer zugegebenermassen oberflächlichen Recherche, noch nirgends erwähnt fand und das leider als Beispiel in neuralgischen Quellen Verwendung findet, sodass man sich nicht wundern muss, dass unerfahrene Programmierer das einfach so verwenden.

Literatur und Quellen


Willkommen bei bluesky IT-Solutions AG!

22.11.2010

bluesky IT-Solutions AG ist ein technologiegetriebenes IT-Diensleistungsunternehmen mit Sitz in Münchenstein/Schweiz.

Wir arbeiten viel mit offenen Standards und Open-Source Komponenten, um mit diesem Blend an Technologien optimale Lösungen für unsere Kunden zu entwickeln.
Um unsere Erfahrungen der Community zurück zu geben, haben wir diesen Blog ins Leben gerufen.
Aktuell setzen wir unter anderem

  • Jackrabbit / JCR 2.0
  • GWT
  • SmartGWT
  • jBPM
  • jBoss
  • Tomcat 6
  • Hibernate
  • JEE-Stack (JEE5 / JEE6)
  • Verschiedene RDBMS (Oracle, MySQL)
  • LDAP

ein.

Wir werden in diesem Blog über den Einsatz dieser Komponenten sowie unsere Erfahrungen in verschiedenen Umgebungen berichten.

Viel Spass
Euer bluesky-Team


Follow

Bekomme jeden neuen Artikel in deinen Posteingang.