Diamond Kata mittels Flow-Design und ISOP

Zuvor gelesene Blogs:

Meine Vorgehensweise

Um das Problem zu verstehen, habe ich selbst diese Kata vorab mittels Flow-Design entworfen. Zuvor habe ich das Problem genau unter die Lupe genommen, heißt ich habe anhand von Beispielen (mittels Papier und Bleistift) nach notwendiger Funktionalität gesucht. Dann habe ich mein Flow-Design erstellt. So stelle ich mir also eine Lösung des Problems vor.

clip_image001

Testfälle zu finden war aufgrund des einfachen Problems, nicht wirklich schwierig. „A“ als Input stellt IMHO den einzigen Sonderfall dar (keine Leerzeichen notwendig). Um die Implementierung voranzutreiben, waren nach „A“, zuerst „B“ und dann „C“ als Input sinnvoll. Das war es allerdings auch schon an priorisierten Testfällen.

Dann habe ich mit der Implementierung des ersten Testfalls („A“) begonnen und ein Walking Skeleton basierend auf meinem Flow-Design erstellt. Das einfache zurückgeben von „A“ (hartcodiert), erschien zu wenig, jedoch für die Implementierung des Grundgerüsts eine gute Hilfe um sicherzustellen, dass die Daten durch alle Methoden fließen. D.h. ich habe das „A“ vom Input durch mein Walking Skeleton zum Output fließen lassen.

Walking Skeleton

image

Somit war der erste Test auf Grün und das Grundgerüst platziert. Man sieht, mein Flow-Design entspricht genau der Implementierung. In diesem Fall war die Implementierung reines Handwerk und daher schnell getippt. Kreativ war ich beim Flow-Design, hier wurde also Ingenieurstätigkeit von mir erbracht.

Mein nächster Testfall war der Input „B“. Dafür war es notwendig, den nächsten Teil des Walking Skeleton zu implementieren:

Walking Skeleton für Testfall „B“

image

Jetzt hätte ich mittels Informed TDD die Methoden die derzeit noch nicht implementiert waren, jede für sich umsetzen können. Erschien mir allerdings zu viel Aufwand für das einfache Problem zu sein. Hier hätte man mit Sicherheit in kleineren Schritten vorgehen können.

Implementierung

image

Ich muss gestehen, hier habe ich einmal auf einen Commit vergessen. Ich habe Prepend_Spaces_To() und Append_Spaces_To() in eine Methode zusammengefügt, da die Implementierungen fast ident waren. Dabei war der Test für den Input „B“ bereits zuvor auf Grün. Somit handelte es sich um ein legitimes Refactoring. Außerdem sind zwei Hilfsfunktionen hinzugekommen, um die notwendigen Leerzeichen zu erzeugen. IMHO handelt es sich dabei um Designdetails, die ich in der Phase des Flow-Design nicht entdeckt habe (was jedoch OK ist).

Die in der Skizze mit Refactoring gekennzeichneten Änderungen im Flow-Design nachgezogen. Es handelt sich also um die zweite Version meines Flow-Designs:

clip_image002

Mein letzter Testfall „C“ sollte eigentlich aufgrund der bis dahin implementierten Funktionalität sofort auf Grün laufen. Allerdings hatte ich einen Fehler in meiner Implementierung der Methode zur Erstellung der Leerzeichen, die in der Mitte von Buchstaben injiziert werden.

Behebung des Fehlers von Leerzeichen

image

Aufgrund der Kompaktheit und Verständlichkeit der Methode, war die Fehlerbehebung allerdings trivial. Zuletzt habe ich noch ein paar Umbenennungen durchgeführt, und Parameternamen hinzugefügt, um die Verständlichkeit zu erhöhen. Hinzufügen von neuer Funktionalität war zu diesem Zeitpunkt nicht mehr notwendig.

Soweit ich die von mir weiter oben erwähnten Blog-Posts verstanden habe, hat Seb Rose des Öfteren das Problem, dass seine Testfälle zu grobgranular sind, d.h. zu viel an Implementierung erfordern, bis sie tatsächlich auf Grün sind. Somit ändert er kontinuierlich bestehende Testfälle, damit er kleinere Schritte in seiner Implementierung vornehmen kann. Diese Testfälle sind dann letztendlich in der finalen Version nicht mehr sichtbar.

IMHO entspricht das in etwa dem „Informed TDD„-Gedanken. D.h., nachdem meine Walking Skeletons auf Grün waren, hätte ich eigene Testfälle für diese Funktionseinheiten entwerfen können. Dabei hätte ich jeweils immer nur eine Methode implementiert und die jeweils anderen ge-stubbed. Natürlich könnte man auch die Integrationsfunktion Insert_Spaces() in eine eigene Klasse verschieben. Diese hätte dann ebenfalls isoliert getestet werden können.

Was mir beim Flow-Design außerordentlich gut gefällt, ist das umgesetzte Integration Operation Segregation Principle (IOSP). Ausschließlich in den grün gekennzeichneten Funktionseinheiten ist Logik enthalten (if-Statements, etc.). Integrationsmethoden machen nichts anderes, als andere Funktionseinheiten zusammenzufügen. Operationseinheiten haben absolut keine Abhängigkeiten auf andere Operationen. Ausschließlich Integrationen haben Abhängigkeiten.

Hier sieht man die Version von Seb Rose. Was auffällt, in dieser Implementierung wird nicht zwischen Integration und Operation getrennt. Ich hätte sogar gesagt, dass hier eine Operation (Create()) von einer Integration (BuildLine()) abhängt. Operationen sollten jedoch als Blätter in einem Baum implementiert werden, sofern man das IOSP umsetzen möchte.

Ich möchte hier nicht alle Vorteile von Flow-Design, IOSP und Informed TDD aufzählen. Das kann Ralf Westphal natürlich viel besser. Ich empfehle daher sowohl seinen englischen, als auch seinen deutschen Blog nach diesen Themen zu durchsuchen. Auch seine Bücher sind natürlich eine spitzen Quelle, um sich intensiver mit der Thematik zu beschäftigen.

Hier noch die endgültige Version von meiner Lösung:

using System;
using System.Collections.Generic;
using System.Linq;
namespace domain
{
public class Diamond_Builder
{
private const string NEW_LINE = "
";
private const char WHITE_SPACE = ' ';
private static readonly List<string> alphabet = new List<string>
{
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z"
};
public string Build_Diamond(string middle_letter)
{
var letters = Get_Necessary_Letters(last_letter: middle_letter);
var letters_with_spaces = Insert_Spaces(letters);
var diamond = Duplicate_First_Half_of_Diamond(half_diamond: letters_with_spaces);
var result_diamond = To_String(diamond);
return result_diamond;
}
private List<string> Get_Necessary_Letters(string last_letter)
{
var index_of_last_letter = alphabet.IndexOf(last_letter);
var letters = alphabet.Take(count: index_of_last_letter + 1).ToList();
var correct_nr_of_letters = letters
.Where(l => l != "A")
.Select(l => l + l)
.ToList();
correct_nr_of_letters.Insert(0, "A");
return correct_nr_of_letters;
}
private List<string> Insert_Spaces(List<string> letters)
{
var letters_with_left_and_right_spaces = Add_Left_And_Right_Spaces_To(letters);
var letters_with_spaces = Inject_Spaces_in_the_Middle(letters_with_left_and_right_spaces);
return letters_with_spaces;
}
private List<string> Add_Left_And_Right_Spaces_To(List<string> letters)
{
var spaces = Create_Spaces_For(letters);
var letters_with_prepended_spaces = letters
.Zip(spaces, (l, s) => s + l + s)
.ToList();
return letters_with_prepended_spaces;
}
private IEnumerable<string> Create_Spaces_For(IReadOnlyCollection<string> letters)
{
var spaces = new List<string>();
for (var i = letters.Count - 1; i > 0; i--)
spaces.Add(new String(WHITE_SPACE, count: i));
spaces.Add("");
return spaces;
}
private List<string> Inject_Spaces_in_the_Middle(List<string> letters)
{
var spaces = Create_Middle_Spaces_For(letters);
var letters_with_middle_spaces = letters
.Zip(spaces, (l, s) => l.Insert(startIndex: (l.Count() / 2), value: s))
.ToList();
return letters_with_middle_spaces;
}
private IEnumerable<string> Create_Middle_Spaces_For(List<string> letters)
{
var spaces = new List<string> { "" };
var odd_nr = 1;
letters.ForEach(l =>
{
spaces.Add(new String(WHITE_SPACE, count: odd_nr));
odd_nr += 2;
});
return spaces;
}
private IEnumerable<string> Duplicate_First_Half_of_Diamond(List<string> half_diamond)
{
var duplicate = half_diamond
.Take(count: half_diamond.Count - 1)
.ToList();
duplicate.Reverse();
half_diamond.AddRange(duplicate);
return half_diamond;
}
private string To_String(IEnumerable<string> diamond)
{
return string.Join(separator: NEW_LINE, values: diamond);
}
}
}
Veröffentlicht unter Flow-Design, IOSP, Kata, TDD | 1 Kommentar

TDD 2.0 – Teil 2 | TDD as if you meant it (TDDaiymi)

“TDD ist kein Zauberstab, der aus dem Nichts wohlstrukturierten Code herstellt.” – Ralf Westphal [1]

TDD 2.0 – Teil 1 | Problemanalyse, Lösungsfindung, Implementierung

Die Refactoring-Phase in TDD dient dazu Code zu strukturieren. Es gibt allerdings keine generellen Rezepte nach welchen Kriterien man verbessertes Design als Entwickler erzeugen kann. Code Smells, wie z.B.: Duplikation, sind zwar gute Ansatzpunkte, allerdings führt die Bereinigungen dieser in TDD 1.0 nicht automatisch zu guter Struktur (= Aspekte meiner Lösung für das vorhandene Problem werden durch Refactoring nicht automatisch im Code abgebildet).

Ralf Westphal beschreibt in einer vierteiligen dotnetpro-Artikelserie, wie seiner Meinung nach das neue TDD, also TDD 2.0,auszusehen hat. Den ersten Teil habe ich bereits hier zusammengefasst. Darin ging es um die ersten beiden (neuen) Phasen: Problemanalyse und Lösungsfindung.

In diesem Post fasse ich den zweiten Teil [1] der Artikelserie von Ralf zusammen: die Implementierungsphase. Ralfs Kritik von TDD 1.0 ist das Refaktorisieren, das nicht durch die Methode selbst erzwungen wird. Dadurch wird diese Phase willkürlich von Entwicklern eingesetzt bzw. es wird komplett darauf verzichtet. Struktur kann, muss allerdings nicht, dabei entstehen. Genau das ändert sich bei TDD 2.0 in der Implementierungsphase durch den Einsatz von TDD as if you meant it.

Die Regeln von TDDaiymi sind einfach: Produktionscode wird immer nur in die Test-methode geschrieben. Fehler müssen zuerst in der Testmethode reproduziert und behoben werden. Dann wird in den Testmethoden nach Wiederholungsmustern gesucht, die Anzeichen zur Refaktorisierung darstellen.

Produktionscode nur in Testmethoden? Ja. Laut Ralf treten dabei folgende Effekte auf:

“Erstens konzentriere ich mich bei jedem Testfall nur darauf, genau diesen Testfall grün zu bekommen. Die Fokussierung ist viel größer. Ich muss keine Kompromisse bei der Lösung eingehen. Das bedeutet auch, ich bewege mich tastend fort. … Und zweitens entstehen viel häufiger (Wiederholungs-)Muster. Die sind Leitsterne für die Refaktorisierung.” [1]

Keine Kompromisse?

Da man bei TDDaiymi die Behebung eines Fehlers immer in der Testmethode selbst programmiert, läuft man nicht Gefahr,  andere Tests kaputt zu machen. Das sieht bei TDD 1.0 anders aus. Die Regeln besagen: Bereits erzeugte Tests, die einmal auf Grün waren, dürfen nicht mehr Rot werden. Deshalb muss man sich bei jedem neuen Test plus Implementierung darauf konzentrieren, dass die neue Lösung ebenfalls alte Tests berücksichtigt und nicht zerstört. Das ist in TDD 2.0 nicht mehr der Fall, denn Tests plus deren Implementierung sind unabhängig von anderen Tests. Genial.

In [1] implementiert Ralf zuerst mittels TDD 1.0 und danach mittels TDD 2.0 die Kata “WordWrap”. Bei letzterer Vorgehensweise wird allerdings nur von der dritten Phase, Implementierung mittels TDDaiymi, Gebrauch gemacht. Zur Erinnerung noch einmal die aktualisierte Version von TDD:

image

Ganz bewusst wurde auf die beiden vorhergehenden Phasen verzichtet, da TDDaiymi der Schwerpunkt des Artikels war. Ralf ergänzt, dass die entstandene Struktur bereits in der Solve-Phase hätte entdeckt werden können.

Kritik TDD 1.0

Trotz disziplinierter Anwendung von TDD 1.0 führt dies nicht im Entferntesten zu Code, der leicht verständlich ist. Unter [3] findet man sowohl Tests als auch Produktionscode der Implementierung. Folgendes Code-Snippet zeigt nur den Produktionscode aus [3]. Leider wurde ausschließlich die komplette Implementierung eingecheckt, sodass man in der Git-History die einzelnen Schritte nicht erkennen kann.


public class Wrapper
{
public static string Wrap(string text, int zeilenlänge)
{
return Wrap("", text, zeilenlänge);
}
private static string Wrap(string umgebrochen, string text, int zeilenlänge)
{
if (text == "") return umgebrochen;
var zeile = text.Substring(0, Math.Min(text.Length, zeilenlänge));
var rest = zeilenlänge >= text.Length
? ""
: text.Substring(zeilenlänge, text.Length – zeile.Length);
if (!zeile.EndsWith(" ") && !rest.StartsWith(" "))
{
var index_of_last_whitespace = zeile.LastIndexOf(" ");
if (index_of_last_whitespace > 0)
{
var wortkopf = zeile.Substring(index_of_last_whitespace + 1);
zeile = zeile.Substring(0, index_of_last_whitespace);
rest = wortkopf + rest;
}
}
zeile = zeile.Trim();
rest = rest.Trim();
umgebrochen += (umgebrochen == "" ? "" : "\n") + zeile;
return Wrap(umgebrochen, rest, zeilenlänge);
}
}

view raw

Wrapper.cs

hosted with ❤ by GitHub

Besser mit TDD 2.0

Folgendes Code-Snippet zeigt die Lösung aus [4], die mittels TDDaiymi erzeugt wurde.


class WrapperV2
{
public static string Wrap(string text, int zeilenlänge)
{
return Wrap("", text, zeilenlänge);
}
static string Wrap(string umgebrochen, string text, int zeilenlänge)
{
if (text == "") return umgebrochen;
var abbruch = Zeile_abbrechen(text, zeilenlänge);
abbruch = Abbruch_bei_Leerzeichen_präferieren(abbruch);
umgebrochen = Umbrechen(umgebrochen, abbruch.Zeile);
return Wrap(umgebrochen, abbruch.Rest, zeilenlänge);
}
static dynamic Zeile_abbrechen(string text, int zeilenlänge)
{
dynamic abbruch = new ExpandoObject();
abbruch.Zeile = text.Substring(0, text.Length < zeilenlänge
? text.Length
: zeilenlänge);
abbruch.Rest = zeilenlänge >= text.Length
? ""
: text.Substring(zeilenlänge);
return abbruch;
}
static dynamic Abbruch_bei_Leerzeichen_präferieren(dynamic abbruch)
{
if (!abbruch.Zeile.EndsWith(" ") && !abbruch.Rest.StartsWith(" "))
{
var index_letztes_leerzeichen = abbruch.Zeile.LastIndexOf(" ");
if (index_letztes_leerzeichen > 0)
{
var wortkopf = abbruch.Zeile.Substring(index_letztes_leerzeichen + 1);
abbruch.Zeile = abbruch.Zeile.Substring(0, index_letztes_leerzeichen);
abbruch.Rest = wortkopf + abbruch.Rest;
}
}
abbruch.Zeile = abbruch.Zeile.Trim();
abbruch.Rest = abbruch.Rest.TrimStart();
return abbruch;
}
static string Umbrechen(string umgebrochen, string zeile)
{
return umgebrochen + (umgebrochen == "" ? "" : "\n") + zeile;
}
}

view raw

WrapperTDD20.cs

hosted with ❤ by GitHub

Auffällig bei dieser Implementierung ist die domänenspezifische Trennung unter- schiedlicher Aspekte. Man kann anhand des Codes genau erkennen wie die Lösung funktioniert.

In [1] wird jeder Schritt von Rot auf Grün ganz genau von Ralf erklärt. In einer tabellenartigen Darstellung befindet sich auf der linken Seite immer der Test und auf der rechten Seite die Implementierung (bei TDDaiymi erneut der Test + Produktionscode im Test). Fantastisch.

Trotzdem fiel es mir nicht besonders leicht, die einzelnen Refaktorisierungen von Ralf nachzuvollziehen. Das lag vielleicht daran, dass ich mich schon vor einiger Zeit einmal an TDDaiymi versucht habe und daher eine gewisse Vorstellung darüber hatte, wie diese Methode anzuwenden ist. Da es jedoch kaum Literatur dazu gibt, war es sehr aufschlussreich zu sehen, wie Ralf dabei vorgeht. Noch genialer wäre ein Screencast, bei dem man Ralf bei seinem Vorgehen beobachten könnte. Und siehe da Smiley :

Zwar ist die Lösung in diesem Video nicht 1:1 dieselbe wie in dem dotnetpro Artikel [1], aber es hat mir auf jeden Fall unglaublich geholfen. Nachdem ich dann selbst mehrmals WordWrap mittels TDDaiymi übte, war es mir endlich möglich, folgende Aussage von Ralf nachzuvollziehen:

“Bei TDD 2.0 hingegen gibt es zunächst gar keinen Produktionscode. Da gibt es nur Tests – bis sich ein Muster herausschält. Man ist von vornherein also im Mustererkennungsmodus für die Refaktorisierung. Weil es eine Implementierungsrichtlinie für Grün gibt – schreibe Code zunächst in der Testmethode –, wird man quasi in die Refaktorisierung gezwungen.” [1]

Ich behaupte, dass man dieses Gefühl des Mustererkennungsmodus nur verstehen kann, wenn man TDDaiymi selbst mehrmals ausprobiert hat. Man ist ständig auf der Suche nach Wiederholungen, die auf neue Aspekte hindeuten könnten.

Gelerntes

Folgende Punkte aus [2] hat Ralf unter “Was ich gelernt habe” zusammengefasst:

– Refaktorisierung ist nicht mehr optional, sondern muss vorgenommen werden.
– Dopplungen in Testmethoden sorgen ganz natürlich dafür, dass Aspekte in Lösungsmethoden verpackt werden (DRY).
– Weitere Methoden entstehen nur bei Sensibilität für SRP.
– Es ist wirklich wichtig, Lösungen zuerst in der Testmethode zu implementieren. Nur so werden Aspekte sichtbar, die sonst in Lösungsmethoden untergehen würden.

Ich finde TDDaiymi weiterhin nicht unbedingt einfach. Das Video von Ralf plus der dotnetpro Artikel [1] helfen jedoch ungemein. Ralfs Erkenntnisse stimmen mit meinen überein.

Offene Fragen

Einige Fragen stellen sich mir jedoch weiterhin: Wie sieht TDD 2.0 in realen Anwendungen aus? Kommt TDDaiymi für die komplette Applikation zur Anwendung oder nur für Teilaspekte? Ist TDDaiymi nur für die Erforschung innerer Strukturen von Klassen?

Aussichten

Im nächsten Teil hoffe ich einige dieser Fragen beantworten zu können. Außerdem beschreibt Ralf zum einen was man eigentlich unter Design versteht, zum anderen wird anhand der BowlingGame Kata der komplette TDD 2.0 Zyklus vorgeführt.

Referenzen

[1] dotnetpro Artikel: Ab ins Grüne von Ralf Westphal http://bit.ly/1i79VMi
[2] XP Days 2012 Slides zu TDDaiymi von Ralf Westphal: http://bit.ly/1ln74kQ
[3] WordWrap mittels TDD 1.0 von Ralf Westphal: http://bit.ly/1bIxnd3
[4] WordWrap mittels TDD 2.0 von Ralf Westphal: http://bit.ly/19K8408

Weitere Referenzen aus [1]:

Robert C. Martin, The Craftsman 62 – The Dark path http://bit.ly/1kDOVS8
Robert C. Martin, Uncle Bob’s Blog, The Transformation Priority Premise (Leider offline)
Code Cop, Word Wrap Kata Variants, http://bit.ly/1j8OUDW
Keith Braithwaite, TDD as if you meant it http://bit.ly/1a9JhCZ
Keith Braithwaite, TDD as if you meant it (Video) http://bit.ly/K7kbc3
Gojko Adzic, Thought-provoking TDD exercise at the Software Crapftsmanship conference http://bit.ly/1iiTK10
Gojko Adzic, TDD as if you meant it – revisited http://bit.ly/1c8BYoX

Veröffentlicht unter Refactoring, Software Craftsmanship, TDD | Verschlagwortet mit , , | Kommentar hinterlassen

TDD 2.0 – Problemanalyse, Lösungsfindung, Implementierung

[Update (10/12/2013): Rechtschreibung]

Schon mal bei einem Coding Dojo etwas frustriert gewesen, da absolut keine Lösung in Sicht war? Praktiziert eigentlich jeder Softwareentwickler TDD auf dieselbe Art und Weise? Kann bzw. muss eine so fundamentale Vorgehensweise wie TDD weiterentwickelt werden? Ralf Westphal meint ja!

Wer mich kennt, der weiß, dass ich ein Fanboy von Ralf Westphal bin. Warum? Ich finde, dass es nicht besonders viele Personen in meiner Branche gibt, die bestehende Dinge hinterfragen und vorantreiben. Ralf ist allerdings für mich genau einer dieser Menschen, die grundlegende Bereiche der Softwareentwicklung verbessern möchten. Ein Beispiel dafür ist die Testgetriebene Entwicklung, die vor ca. 10 Jahren von Kent Beck ins Leben gerufen wurde. Täglich stelle ich fest, dass diese Disziplin noch nicht wirklich in Wien (bzw. Österreich) bei der Entwickler-Community angekommen ist.

Auch bei aktuellen Konferenzen werden nach wie vor jede Menge Einführungsveranstaltungen zum Thema TDD angeboten. Von Universitäten und Fachhochschulen will ich gar nicht reden. OK, an eine Vorlesung erinnere ich mich, in der das Thema kurz einmal erwähnt, ja sogar demonstriert wurde. Unterm Strich obliegt es jedoch jedem selbst diese so wichtige Disziplin zu erlernen und ständig zu üben.

Ralf Westphal hat aus meiner Sicht eine sehr beeindruckende Artikelserie in der dotnetpro geschrieben, die meiner Meinung nach öffentlich kostenlos zugänglich gemacht werden sollte, um möglichst viele Entwickler damit zu erreichen. Im ersten Teil dieser Serie kritisiert er die gegenwärtige Praxis von TDD. Zum Teil entsprechen diese Kritiken meinen persönlichen Erfahrungen. Die beiden Hauptpunkte sind: mangelndes Refactoring, d.h. die dritte Phase von TDD wird nur marginal von Entwicklern durchgeführt, und die nicht vorhandene Trennung von Lösungsfindung und Implementierung.

Kritik: Mangelndes Refactoring

Warum funktionieren die ersten beiden Phasen, Red + Green, besser als die letzte? Diese Frage stellt sich auch Ralf. Ist es mangelndes Wissen bezüglich prinzipiengetreuen Programmierens? Fehlender Spaß an der Sache? Geht es einfach schlicht weg auch ohne? Es ist mit Sicherheit eine Kombination aller dieser Dinge.

Ich habe TDD so gelernt, dass man in der Red-Phase immer nur genau so viel Produktionscode schreibt, bis Tests grün sind. Dadurch vermeidet man Code zu schreiben, den man nur eventuell brauchen könnte. So entstehen Lösungen die dem KISS Prinzip entsprechen. Das Problem damit ist, dass die Verständlichkeit dadurch nicht gerade  erhöht wird. Natürlich entfernt man Duplikation und achtet darauf Magic-Numbers/Strings zu vermeiden; und klar ist es leichter, in KISS basierten Implementierungen Erweiterungen durchzuführen als in 1000-zeiligen Methoden. Jedoch muss man nach wie vor Codearchäologie betreiben um den Code verstehen zu können. KISS is not enough!

Mir persönlich stellt sich auch immer wieder die Frage: Wann habe ich genug Refactoring betrieben? Oder anders formuliert: Wann habe ich genug Struktur in meiner Implementierung untergebracht um Evolvierbarkeit zu ermöglichen und Nachvoll-ziehbarkeit für den nächsten Bearbeiter zu gewährleisten? Deshalb programmieren wir in der Arbeit ausschließlich zu zweit (und das nicht nur zur Fehlerbehebung bzw. wenn es Probleme gibt).

Der Punkt ist, es gibt keine klaren Regeln zur dritten Phase von TDD. Noch dazu ist Design aka Refactoring zum großen Teil subjektiv. Ralf ist der Meinung, dass fehlender Druck zum Refactoring ein Grund für die aktuell gelebte TDD-Praxis sein könnte. Dabei bezieht sich der fehlende Druck auf die Methode selbst.

Kritik: Fehlende Phase zur Lösungsfindung

Wenn man TDD betreibt dann muss einem eines ganz klar bewusst sein: TDD führt nicht automatisch zur Lösung eines Problems. Ohne Denken geht es einfach nicht! Schon öfters habe ich bei Coderetreats feststellen müssen, dass Entwickler beim Programmieren ins Stocken geraten. “Welchen Test schreiben wir denn jetzt? Uff, da müssen wir aber jede Menge umbauen!” Das Problem ist, dass wir gleichzeitig zu lösen und zu implementieren versuchen.

Ralf sagt dazu folgendes [1]:

Zwischen Testcode und Produktionscode liegt immer Nachdenken, das heißt die Entwicklung einer Lösung im Kopf des Programmierers. Wenn das jedoch während des Codierens stattfinden soll, ist der Prozess eingeschränkt. Dazu müsste der Programmierer präemptives Multitasking betreiben und immer wieder zwischen Codieren und Lösen wechseln. Das sind zwei kreative, um Hirnkapazität konkurrierende Tätigkeiten.

TDD 2.0

Wie sich vielleicht erahnen lässt, gehört die Trennung zwischen Lösungsfindung und der Implementierung (Red+Green+Refactoring) unter anderem zum Verbesserungsvorschlag von Ralf. Ebenfalls wird die Problemanalyse explizit der Lösungsfindung vorangestellt. Man erhält folgende drei Phasen für TDD 2.0:

image

Die Abbildung habe ich von Ralfs Blog geborgt. Man findet sie hier. Diese wird auch in der dotnetpro Artikelserie mehrmals verwendet.  Für Ralf handelt es sich dabei um den minimalen Softwareentwicklungsprozess je Inkrement. Weniger geht nicht!

Wenn man heutzutage TDD gelehrt bekommt, sei es durch erfahrene Entwickler, durch Bücher oder eventuell durch Videos im Web, wird ausschließlich die Refactoring-Phase zum Designen verwendet. Kent Beck schreibt in seinem Buch Test-Driven Development By Example:

1. Write a test. …
2. Make it run. …
3. Make it right. …

oder

First we’ll solve the ‘that works’ part of the problem. Then we’ll solve the ‘clean code’ part.

Dadurch entsteht Codestruktur relativ spät und überraschend. Auch ich habe es bis jetzt hauptsächlich so geübt, jedoch halte ich die Refactoring-Phase strikt ein. Schon alleine aus dem Grund weil sie mir einfach Spaß macht. Trotzdem entstehen dadurch Abstraktionen erst, wenn ich z.B. Duplikation entferne. Zu spät aus Ralfs Sicht. Warum hoffen, dass Struktur nur nach mehrmaligen Refactoring entsteht? Außerdem darf es niemals ausgelassen/vergessen/verschoben werden. Leider zeigt die Praxis jedoch Gegenteiliges.

Ralf meint:

Schluss mit Überraschungen!

In TDD 2.0 macht man sich schon in der Lösungsphase Gedanken zum Design. Durch tiefes Problemverständnis versucht man eventuelle Aspekte herauszuarbeiten, die in der Lösung vorkommen sollen. Wenn man bis jetzt immer einfach darauf los gecoded hat, dann kann es zu Beginn schon ein bisschen schwer fallen, die IDE zuerst vorab geschlossen zu lassen. Zunächst nur Zettel und Stift nehmen, die Lösung versuchen zu visualisieren und aussagekräftige Bezeichnungen zu finden. Verrückt oder?

Aber halt! Schalten wir einen Gang zurück. Man wäre gut beraten, die erste Phase in TDD 2.0 nicht auszulassen. Die ist nämlich absolute Voraussetzung zur Lösungsfindung. In dieser geht es darum, ein tiefes Verständnis für die Problemdomäne zu entwickeln. Hat man das Problem nicht verstanden, dann ist es natürlich auch nicht möglich eine Lösung zu finden. Klingt logisch oder? Ich kann mich noch genau an mein erstes Coderetreat erinnern. Bereits in der ersten Session wurde von meinem Pairing Partner folgendes gesagt: “Na schreib einfach einmal einen Test”. Ich habe mich dem Druck gebeugt und einfach mal drauf los getippselt. Nicht besonders hilfreich. Mehr darüber werde ich einmal in einem separaten Post zum Thema Coding Dojos und Coderetreats berichten.

Ich habe oft den Eindruck, dass es in der Natur des Entwicklers liegt, lieber in eine IDE zu starren als vorab das Problem zu diskutieren. Schon oft habe ich gemerkt, dass mein Pairing Partner lieber einmal drauflos tippen würde, anstatt mit mir das Problem näher zu analysieren. Dadurch würde man sich viel Zeit sparen, da man nicht ins Stocken gerät bzw. mitten in der Implementierung auf Dinge stößt, die in Folge einen beträchtlichen Umbau erfordern.

Bewusstes Zeit nehmen für alle drei Phasen, um das geht es in Wirklichkeit in TDD 2.0. Bevor man sich das nächste Mal an die Implementierung eines neuen Features heranwagt, könnte man doch mal folgende Checkliste beachten:

IMG_0359

Auf den dritten Punkt der Checkliste bin ich bisher noch überhaupt nicht eingegangen. Woher weiß man eigentlich, welcher Testfall der nächste ist. Meiner Erfahrung nach, wird diese Entscheidung von Entwicklern relativ ad hoc getroffen. Ich habe es eigentlich noch nie erlebt, dass vorab Testfälle von jemanden überlegt und nach Schwierigkeitsgrad priorisiert wurden. Ohne dem kann es während der Implementierung zum Stillstand kommen, da man nicht so recht weiß, welcher Test dann der nächste ist. Eindeutig ein Zeichen dafür, dass man zu wenig priorisiert hat. TDD 2.0 bietet jedoch hier die Möglichkeit in die früheren Phasen zurückzuspringen. Wenn man allerdings schon Probleme bei der Priorisierung hat, dann muss man höchstwahrscheinlich noch weiter an der Lösungsfindung bzw. an der Problemanalyse arbeiten.

Wie geht’s weiter?

Der aufmerksame Leser wird bemerkt haben, dass diese Zusammenfassung ausschließlich auf die Verbesserung einer der beiden Kritikpunkte eingeht, nämlich auf den der Trennung von Lösungsfindung und Implementierung. Druck zur Refaktorisierung wird weiterhin nicht durch die Methode selbst ausgeübt. Darüber werde ich in meinem nächsten Post berichten.

Vertiefung

Ralf hat glücklicherweise schon einige Artikel über seinen Blog veröffentlicht die ebenfalls diese hier zusammengefasste Thematik behandeln. Wem TDD interessiert und wer gerne ein paar Beispiele zu diesem Material hätte, dem sei dringend empfohlen Ralfs Beiträge zu lesen.

Sehr zu empfehlen sind auch die dazugehörigen Kommentare von Ralf. Also auch diese unbedingt lesen. Da gibts noch mal richtig viel Input und Erklärung zum Material.

Wer die originale dotnetpro Artikelserie kaufen möchte, der findet sie hier:

[1] Teil 1 (03/2013)

Veröffentlicht unter Refactoring, Software Craftsmanship, TDD | Verschlagwortet mit , , | 1 Kommentar

Lerngruppen @ Work | Teil 3

In Teil 1 beschreibe ich den Grund warum ich in der Arbeit Lerngruppen initiiert habe. Schon bereits nach kurzer Zeit konnte man Veränderung innerhalb der Abteilung erkennen. Darüber habe ich Teil 2 berichtet. In diesem Post beschreibe ich die eher etwas negativen Erfahrungen die ich bis hierhin gemacht habe.

Realität

Lerngruppen finden nach wie vor alle 14 Tage statt. Lernmaterialien werden nur sehr selten nach einer Woche ausgeschickt. Meistens wird beim Aussenden des Outlook-Termins der nächsten Study-Group etwas Vorbereitungsmaterial in Form einiger Links hinzugefügt. Das Organisieren der Lerngruppen habe ausschließlich ich übernommen. D.h. niemand (ein oder zwei Ausnahmen gab es) innerhalb der Abteilung meldet sich freiwillig um die nächste Study-Group vorzubereiten. Warum das so ist, konnte ich bis jetzt nicht wirklich erklären.

Das Visualisieren der Lerngruppenadministration wird derzeit auf einem Flip-Chart Blatt durchgeführt und sieht wie folgt aus:

image 

Diskussionen nach abgehaltenen Vorträgen kommen nicht wirklich zu Stande. Hin und wieder werden (meistens von den gleichen Personen) ein paar Verständnisfragen gestellt. Positiv anzumerken ist, dass von jedem innerhalb der Abteilung schon mindestens einmal eine Study-Group übernommen worden ist.

Ab und an waren sogar wirklich ausgesprochen gut vorbereitete Lerngruppen dabei. Meines Erachtens waren Study-Groups dann am erfolgreichsten, wenn der Vortragende sich die Mühe gemacht hat, kleine Workshops in seine Präsentation einzubauen. Es gab Termine wo man in Kleingruppen oder aber auch alleine kleine Aufgaben erledigen durfte.

In der nächsten Abbildung sieht man einen Übungsteil in Aktion.

image

In der Lerngruppe ging es um das Thema „Werte“ und gehörte meines Erachtens zu den besten bis jetzt organisierten Terminen. Leider gibt es auch Abteilungsmitglieder die nichts mit diesen Workshops anfangen können. D.h., wenn alle anderen am Zusammenarbeiten sind, wird dann hartnäckig beim Mittun ausgesetzt.

Fazit: Mein Bauchgefühl sagt mir, würde ich aufhören die Lerngruppen zu organisieren, würden diese künftig nicht mehr stattfinden.

Naive Annahme

Ich halte Weiterbildung in meiner Branche nicht nur für unbedingt notwendig, sondern ich habe einfach Spaß daran, tägliches Neues zu lernen. Das war natürlich nicht immer so in meinem Leben. Seitdem ich jedoch meine Leidenschaft für die Softwareentwicklung entdeckt habe, hat sich auch mein generelles Lerninteresse drastisch erhöht. Eine Unterscheidung zwischen Hobby und Beruf gibt es bei mir nicht mehr.

Deshalb war ich besonders glücklich darüber, dass unser Abteilungsleiter diese Lerngruppen genehmigt hatte. Gemeinsam mit dem Team lernen. Großartig. Allerdings musste ich nach einiger Zeit feststellen, dass hauptsächlich ich Themen für die Study-Group vorbereitete. Das war eigentlich ok für mich. Leider arteten die Lerngruppen jedoch zu reinen Frontalvorträgen aus.

Diskussionen fanden nur noch vereinzelt statt. Ausgeschickte Materialien zur Vorbereitung wurden weitestgehend ignoriert. Das frustriert natürlich. Warum ist das so? Lernen meine Kollegen nicht genauso gerne wie ich? Sind die Themen nicht interessant genug?

Ohne Vorbereitung gibt es keine Diskussion. Ohne Diskussion gibt es keine Verbesserung der Kommunikation innerhalb des Teams. Was mache ich also falsch?

Erst vor kurzem hatte ich ein Aha-Erlebnis nachdem ich Ralf Westphals tollen Post zum Thema Slack gelesen hatte. Wer den noch nicht kennt, sollte diesen unbedingt jetzt studieren und dann wieder zu diesem Blog zurückkehren.

Es war leider naiv von mir zu glauben, dass nur weil uns unser Abteilungsleiter offiziell Zeit und Raum für gemeinsames Lernen zur Verfügung stellt auch jeder aktiv daran teilnehmen würde.

Wenn man seinem Team eine tolle Bibliothek an Sachbüchern bereitstellt, heißt es ja auch noch lange nicht, dass diese auch tatsächlich gelesen werden. Das habe ich jetzt begriffen. Was kann ich also tun, um meine Kollegen dazu zu motivieren sich auf Lerngruppen vorzubereiten?

Ich werde es auf jeden Fall mit Ralfs Vorschlägen probieren:

„Mein Vorschlag: Die Nutzung von Slack sollte immer wieder nachgefragt werden. Man muss an den Menschen ziehen. Pull ist also nicht nur für die Softwareentwicklung ein wichtiges Prinzip. Auch die Mitarbeiterentwicklung braucht es. Immer wieder muss der Slack-Geber klar machen, dass er wünscht, dass der Spielraum genutzt wird.

Fragen wie “Warum hast du den Slack nicht genutzt?” sind da allerdings weniger hilfreich als “Was hast du in deinem Slack gemacht?” Erstere sind nämlich wieder mehr oder weniger subtil drohend/kontrollierend, Letztere hingegen interessiert und in sich wiederum freistellend.

Slack-Nutzung vorleben und Slack-Nutzung interessiert nachfragen, das scheint mir sehr wichtig, um Menschen anzuleiten, mit Freiräumen umzugehen.

  • Was hast du zuletzt “erforscht” in der Zeit, die dir das Unternehmen dafür bietet?
  • An welchem Fach-/Sachbuch liest du gerade, das du dir von dem Literaturbudget des Unternehmens gekauft hast?
  • Was hast du auf der letzten Fortbildung gelernt, die die das Unternehmen ermöglicht hat?
  • Wie hast du deinen Entscheidungsspielraum genutzt, den dir das Unternehmen bietet?

Das Medium, um Zug in dieser Weise auszuüben, ist für mich “die Runde”, also ein ungezwungenes, allerdings fokussiertes Treffen. Zeit für solche Runden ist im Wochenkalender für alle vorzusehen. Das ist Führungsaufgabe. Und da wird dann nachgefragt, ausgetauscht und Slack gelebt.“

Investition

Das Thema Softwareentwicklung ist so breitgefächert, sodass es eine ganze Menge zu lernen gibt. Damit meine ich nicht nur die technischen Dinge, sondern vielmehr die „soften“ Themen. Das Entwickeln von Software ist Teamarbeit und auch das Arbeiten im Team muss verstärkt gelernt und geübt werden.

Ich bin der Meinung, dass jeder der in dieser Branche tätig ist, aktiv und bewusst in seiner Freizeit an sich und seinen Fähigkeiten arbeiten muss.

Wenn man dann noch zusätzlich die Möglichkeit bekommt, im Team miteinander zu lernen, dann sollte man das unbedingt ausnutzen und wertschätzen und jede einzelne Minute davon genießen. Denn eines sollte jedem bewusst sein, die untere Hälfte in der folgenden Abbildung ist auf jeden Fall die sinnvollere und meiner Meinung nach auch die unterhaltsamere.

Peer learning vs Lecture

Das Bild habe ich mir von Staffan Nöteberg geborgt: http://twitpic.com/c9l1zx

Veröffentlicht unter Lerngruppen | Verschlagwortet mit , | 1 Kommentar

Lerngruppen @ Work | Teil 2

Im ersten Teil dieser dreiteiligen Serie zum Thema Lerngruppen in der Arbeit beschreibe ich den Grund warum ich diese Art von Treffen innerhalb unserer Abteilung vorgeschlagen habe. Ohne große Überzeugungsarbeit genehmigte mein Chef diese tolle Möglichkeit um im Team miteinander zu lernen. Nachfolgend beschreibe ich zum einen wie ich die Organisation dieser Lerngruppen handhabe, zum anderen wie die ersten beiden Treffen abliefen und welche Auswirkungen sie hatten.

Die Wand

Beim Einführen der Lerngruppen hatte ich eine genaue Vorstellung darüber, welche Themen die Kommunikation fördern könnten. Außerdem wollte ich mein über die Jahre aufgebautes Wissen bezüglich Agiler Softwareentwicklung an meine Kollegen weitergeben. Da ich zur damaligen Zeit bereits einiges an Material über Visualisierung am Arbeitsplatz gelesen hatte und mir die Vorteile daher bewusst waren, nahm ich die Administration der Lerngruppe als Anlass, unsere erste Informationswand innerhalb der Abteilung aufzubauen. Nichts Aufwendiges. Eine simple Pinnwand, die zum damaligen Zeitpunkt sowieso ausschließlich als Ersatzkleiderhaken diente.

image image

Mir war folgendes sehr wichtig: Jeder sollte zu jedem beliebigen Zeitpunkt sehen können, welche Themen zur Auswahl stehen und welche bereits abgearbeitet wurden. Man sollte erkennen können, wer die nächste Lerngruppe organisiert und ob derjenige bereits Lernmaterialien zur Verfügung gestellt hat. Kurz gesagt, die Administration sollte komplett transparent ablaufen. Nicht versteckt in irgendeinem Programm.

Der Initialpool an Themen wurde von mir an die Wand gepinnt. Darunter waren z.B.: Einführung in die Agile Softwareentwicklung, SOLID-Prinzipien, Einführung in XP, Einführung in Regular Expressions, Einführung in Ruby, Wie funktioniert unser Gehirn, etc. zu finden. Ein Mischmasch aus technischen als  auch „soften“ Themen. 

Nach den ersten paar Lerngruppen sah unsere Informationswand wie folgt aus:

image image

Die erste Lerngruppe

An die erste Lerngruppe kann ich mich noch ganz genau erinnern. Sie wurde von unserem Abteilungsleiter übernommen. Ober sich dazu verpflichtet gefühlt hat? Er nahm diesen Termin als Anlass um uns die Idee eines Projekts zu präsentieren an dem er gerade tüftelte.

Ich war etwas enttäuscht darüber, dass es kein von mir vorgeschlagenes Thema war. Egal. Eine Regel der Lerngruppe war, dass jeder über Themen reden könne, die einem interessieren. Schön wäre es jedoch gewesen, wenn es nichts mit der Arbeit zu tun gehabt hätte. Damit wollte ich bezwecken, dass meine Kollegen endlich einmal etwas außerhalb ihrer gewohnten Arbeitsumgebung zum Thema Softwareentwicklung vermittelt bekommen. Nichts desto trotz war ich froh darüber, dass die Lerngruppe ins Rollen kam. Außerdem wollte ich nicht schon in der ersten Sitzung jemanden bezüglich seines Themas bevormunden, noch dazu wenn es sich dabei um meinen Chef handelte.

Es gab sogar einiges an Material was man vorher studieren konnte. Dies diente jedoch nicht ausschließlich der Lerngruppe zur Vorbereitung sondern auch als Konzept für die eigentliche Präsentation seiner Idee vor dem Vorstand des Unternehmens.

Meine erste Lerngruppe

Die zweite Lerngruppe wurde von mir übernommen. Mit den Hauptzielen Kommunikation und Wissensweitergabe im Hinterkopf wählte ich das Thema: „Eine Einführung in Kanban“. Als großer Fan von Henrik Kniberg und beeindruckt von der Art und Weise wie er Themen präsentiert, nahm ich eines meiner absoluten Lieblingsbücher von ihm „Lean from the Trenches“ als Grundlage für meine Präsentation.

Im Buch findet man eine Case Study über ein größeres Projekt und wie sich mittels Kanban Kommunikation in Teams fördern lässt. Durch ständiges Reflektieren über die getane Arbeit, findet man Möglichkeiten, wie sich alle zusammen verbessern können. Wurzelproblemanalyse ist hier das Zauberwort.

Folgende Aufzeichnung von Henrik diente mir als weitere Grundlage für die Lerngruppe:

Kanban and Scrum – making the most of both – Henrik Kniberg from Øredev on Vimeo.

Die zugehörigen Slides zum Video sind ebenfalls online zu finden. Damit sich meine Teamkollegen auch auf das Treffen vorbereiten konnten, schickte ich nach einer Woche den Wiki-Eintrag zum Thema Kanban via Mail aus. In diesem findet man die wichtigsten Begriffe kurz beschrieben. Meines Erachtens ausreichend Material um über das Thema nach meinem Vortrag zu diskutieren.

Zu Beginn meiner Lerngruppe fragte ich meine Kollegen, woran sie sich aus dem Wiki-Eintrag erinnern konnten. Diese Schlagworte hielt ich auf einem Flip Chart fest. Damit konnte ich während meines Vortrags immer wieder auf diese verweisen und den Zusammenhang zu meiner Präsentation herstellen. Soweit ich mich erinnern kann, fanden alle Teilnehmer an meinen Vortrag großen Gefallen. Doch ich hatte keine Vorstellung darüber, was ich mit dieser Lerngruppe ins Rollen bringen würde. Zwar nicht unmittelbar danach, jedoch nach kurzer Zeit sah unser Abteilungsbereich wie folgt aus:

image image

image image

Ich würde niemals behaupten, dass wir Kanban nach dem Buch leben, nicht im Entferntesten. Jedoch helfen die Whiteboards dabei, Arbeitsvorgänge zu visualisieren, die Kommunikation innerhalb des Teams zu verbessern und Transparenz zu schaffen im Sinne „Wer tut gerade Was“. Damit wurde der erste Schritt in die richtige Richtung getan. Wo es vorher keine Kommunikation gab, wird jetzt mehrmalig am Tag vor dem Whiteboard miteinander diskutiert.

Wie geht es weiter?

Bis hierhin könnte man annehmen, das Lernen im Team Spaß machen sollte. Es gibt sogar positive, sichtbare Auswirkungen im Arbeitsalltag. Leider habe ich eine grundsätzlich falsche Annahme getroffen. Darüber und inwiefern sich die Realität zur ursprünglichen Idee der Lerngruppen unterscheidet, berichte ich im nächsten Post.

Veröffentlicht unter Lerngruppen | Verschlagwortet mit , | 1 Kommentar

Lerngruppen @ Work

Kontext

Ich arbeite nun schon etwa 6 Jahre für dasselbe Unternehmen. Was genau dessen Dienstleistungen und Produkte sind, kann man hier nachlesen. Die Abteilung für die ich arbeite besteht derzeit aus neun Personen und nennt sich „New Technologies“. Wie der Name schon erahnen lässt, arbeiten wir mit (relativ) neuen Technologien. Folgende Abbildung zeigt die derzeitige Situation innerhalb der Abteilung bezüglich Verantwortlichkeiten:

image

Grundsätzlich gibt es eine Unterteilung in ein Java- (braun) und in ein .Net- (gelb) Team. Personen, die hauptsächlich miteinander zu tun haben besitzen die gleiche Farbe. Ich gehöre zu den rot-markierten Kreisen im .Net Bereich, habe allerdings auch schon im Java-Team gearbeitet. Wie man nur unschwer erkennen kann, hat eine Person äußerst viele Verantwortlichkeiten. Dabei handelt es sich um den NT-Abteilungsleiter, der gleichzeitig auch Bestandteil des Java-Teams ist.

In der folgenden Abbildung sieht man, dass unsere Abteilung aus sieben Entwicklern, einer Testerin und einer Business-Analystin besteht. Soviel zur derzeitigen Abteilungskonstellation.

image

Warum Lerngruppen?

Vor etwas mehr als einem Jahr, habe ich eine gewisse Unruhe innerhalb der Abteilung festgestellt. Bei einigen Personen hatte sich ein gewisser Frust aufgestaut, auch bei mir. Eine Hauptursache dafür war mangelnde Kommunikation innerhalb der gesamten Abteilung. Zur damaligen Zeit war es auch so, dass alle Personen ihre Aufgaben ausschließlich alleine umgesetzt haben.

Wenn man in unsere Abteilung kam, dann hat man eigentlich nur selten Personen miteinander arbeiten sehen. Warum das so war? Ich vermute eine Kombination aus Charaktereigenschaften (die meisten eher introvertiert), Gewohnheit, Frust und eventuell auch Angst. Ich stellte mir also die Frage wie ich Kommunikation innerhalb der Abteilung fördern und Personen wieder dazu motivieren könnte, verstärkt miteinander zu arbeiten?

Bei einer Nachmittagskaffeerunde habe ich dann also einmal das Thema „Lerngruppe“ erwähnt. Bis auf den Abteilungsleiter waren alle Personen anwesend. Sehr überrascht darüber, dass diese Idee bei allen Abteilungsmitgliedern positiv ankam, beschrieb ich ihnen meine Vorstellung eines solchen Zusammentreffens.

Vision einer Lerngruppe

Jede Woche bereitet ein Mitarbeiter ein Thema vor, dass er dann in der Gruppe im Rahmen eines kurzen Vortrags (ca. 30 Minuten) präsentiert. Im Anschluss soll es zur Vertiefung durch Diskussion kommen. Dabei können eventuell entstandene Fragen geklärt, oder sogar Möglichkeiten zur Adaptierung innerhalb der Abteilung gefunden werden. Kann man das Gelernte vielleicht direkt anwenden? Wenn nicht, was wäre notwendig um es in Gang zu bringen?

Das Thema ist beliebig. Jeder kann präsentieren was er möchte. Wichtig dabei ist, dass Material für die restlichen Teilnehmer vom Vortragenden zur Verfügung gestellt wird, damit jeder sich vorbereiten kann. Das individuell Gelernte soll ja zur Diskussion anregen um das eigentliche Ziel zu erreichen, nämlich Kommunikation innerhalb der Abteilung zu fördern.

Außerdem muss die Lerngruppe während der offiziellen Arbeitszeit abgehalten werden. Dafür ist natürlich die Zustimmung des Abteilungsleiters einzuholen.

Zustimmung ohne Einwände

Mit dem von mir vorgeschlagenen Ablauf waren alle einverstanden. Wir einigten uns darauf, die Zustimmung des Abteilungsleiters im nächsten Abteilungsmeeting einzuholen. Wer aber konkret fragen sollte wurde nicht vereinbart.

Da saßen wir nun in diesem Meeting und nachdem die routinemäßige Informationsrunde vorbei war und sich keiner zur Lerngruppe äußerte, fasste ich mir ein Herz und übernahm die Initiative. War ja auch schließlich mein Vorschlag, also Zähne zusammenbeißen und los.

Wie erwartet war der Abteilungsleiter mit der Idee einverstanden, korrigierte jedoch den Rhythmus von einer auf zwei Wochen, mit der Begründung, dass der Aufwand zu groß wäre. Äußerst glücklich über die Zustimmung unseres Chefs, konnten wir alle mit den neuen Rahmenbedingungen leben.

Weiterer Verlauf

Die ersten Schritte zur verbesserten Kommunikation innerhalb des Teams wurden erfolgreich gesetzt. Im nächsten Post berichte ich über die Organisation der Lerngruppen und inwieweit sich die Realität von meiner ursprünglichen Vorstellung dieser Treffen unterscheidet.

Veröffentlicht unter Lerngruppen | Verschlagwortet mit , | 3 Kommentare

Software Wartung und Evolution | Portierung eines Altsystems von PL/I nach Java

Im Rahmen der Lehrveranstaltung Software Wartung und Evolution musste ich ein PL/I Programm analysieren, dokumentieren und nach Java portieren. Im restlichen Post beschreibe ich Schritt für Schritt, wie ich bei dieser Übung vorgegangen bin. Ich bin in meiner bisherigen IT-Laufbahn noch nie mit PL/I in Berührung gekommen und daher ein absoluter Beginner bezüglich dieser Programmiersprache. Nachdem ich das zu untersuchende Programm von der Lehrveranstaltungshomepage heruntergeladen und kurz überflogen hatte, war meine erste Idee im Web nach einem PL/I Compiler zu suchen um ein paar Codebeispiele selbst zu tippen, zu kompilieren und auszuführen.

Nach ein bisschen googlen musste ich leider feststellen, dass diese Programmiersprache nicht mehr wirklich supported bzw. weiterentwickelt wird. Allerdings hatte ich Glück eine Demo-Version einer PL/I-Programmierumgebung von IBM in einem Forum zu finden.  Ich habe die Datei pliwintb.zip heruntergeladen und in einer VMWare unter Windows XP installiert. Nach kurzer Einarbeitungsphase, habe ich das erste “Hello World”-Programm erfolgreich kompiliert, ge-linkt und ausgeführt.

PL/I Hello World Demo

 

 

 

 

 

 

Mit Hilfe des Buchs “Das neue PL/I” habe ich mich ein bis zwei Stunden in PL/I eingelesen und ein paar Beispielprogramme abgetippt und ausgeführt. Danach habe ich begonnen, das für die Uni-Übung zu analysierende Programm Zeile für Zeile selbst zu implementieren und zu testen. Falls mir Schlüsselwörter und Sprachkonstrukte noch nicht bekannt waren, habe ich diese einfach in dem weiter oben erwähnten Buch nachgeschlagen. Falls mir dann immer einige Dinge noch unklar waren, habe ich einfach ein kurzes Programm geschrieben, um die mir noch unverständliche Funktionalität zu testen.

Die folgende Aufgabenstellung und der zugehörige Tipp ist von der Lehrveranstaltungs-hompage entnommen. Danach gebe ich eine Ausführliche Dokumentation des zu portierenden PL/I-Programmes.

Aufgabenstellung

Im Rahmen der Analyse und Portierung eines Altsystems von PL/I nach Java, konnte der Großteil der Arbeit bereits erfolgreich durchgeführt werden. Ein kleiner Programmteil konnte jedoch – mangels Dokumentation – noch nicht analysiert und portiert werden.

Ihre Aufgabe ist es, den verbliebenen Teil des PL/1 Sourcecodes zu analysieren, dessen Funktionsweise zu erklären und den Sourcecode geeignet zu re-dokumentieren. Weiters soll die Funktionsweise des PL/1 Programms in Java übersetzt/portiert werden.

Hier ein von mir erstelltes Gist auf Github des Progamms: PROGRAMXYZ.pli

Tipps

Ev. gibt es einen guten Grund warum die ursprünglichen Programmierer genau diesen Programmteil nicht dokumentiert hatten.

Es ist nicht notwendig (und unter Umständen auch nicht ohne weitere Änderungen möglich) den bestehenden Code lauffähig zu bekommen. Sollten Sie dennoch versuchen, den Code direkt zu übersetzen und Erfolg dabei haben, können Sie Zusatzpunkte erlangen.

Codeanalyse

Nachdem ich das Programm genau analysiert und einige mögliche Benutzereingaben auf altmodische Weise, nämlich mit Zettel und Bleistift, durchgespielt hatte, wurde die Funktionalität des Programms eindeutig. Es handelt sich um das bekannte Spiel “Master-Mind”. 

In den folgenden Absätzen beschreibe ich die Teile des Quellcodes, von denen ich nicht wusste, was sie genau tun und wofür sie da sind. Um meiner Beschreibung besser folgen zu können, würde ich empfehlen, den kompletten Quellcode des Programms herunterzuladen und jeweils die von mir beschriebene Zeile nachzuschlagen.  

Aufgrund der ersten Zeile des Programms weiß der Compiler (zumindest der von IBM) alles über deutsche Buchstaben: 

*process names ('äöüß', 'ÄÖÜ$');

Der folgende Programmausschnitt definiert die Methodensignatur des Hauptprogamms. Man kann diese Methode mit der Main-Methode eines jeden lauffähigen Java-Programms vergleichen Bei dem Schlüsselwort reorder handelt es sich um eine Optimierungsangabe für den Compiler. Es bewirkt, dass der Compiler gewisse Anweisungen beliebig umordnen kann, wenn dadurch die Ausführungszeit verkürzt wird.

 PROGRAMXYZ:
 procedure options (main reorder);

Für alle möglichen Farbeingaben wird ein eigener Datentyp definiert. Hier wäre die Angabe von tatsächlichen Farben statt Optionen für die Benutzung des Programms “schöner” gewesen. Anstatt vom Benutzer Optionen zu verlangen, wäre die Angabe von z.B. “grün blau rot grün” noch spielgetreuer gewesen:

 define ordinal COLOR 
    (INVALID, OPTION1, OPTION2, OPTION3, OPTION4, OPTION5, OPTION6);

Für die Tipps des Benutzers und für die „ausgedachte“ Wahl (Code) des Computers werden als Datentypen Matrizen verwendet.

 dcl Code dim (4) type COLOR;
 dcl TIP dim (4) type COLOR;

Nach der Deklaration aller notwendigen Variablen wird durch den Aufruf der Methode RANDOM die “Code”-Matrix befüllt. Dabei handelt es sich also um die vom Spieler zu erratene Farbwahl des Computers. Per Definition wird die RANDOM-Methode vier Mal aufgerufen, da es sich um eine Matrix mit der entsprechenden Dimension handelt. Dabei handelt es sich mein Meinung nach um eine äußerst interessante Funktionalität, dich ich so in noch keiner anderen Programmiersprache gesehen habe.

 Code = RANDOM();

RANDOM-Funktion unter die Lupe genommen:

Diese Methode gibt eine gültige Farboption, die zufällig gewählt wird, zurück. Dieser Zufallsmechanismus funktioniert wie folgt: die von PL/I zur Verfügung gestellte random-Funktion ergibt eine Zahl zwischen 0 und 1, wobei 0 und 1 ausgeschlossen sind. Wenn man diese Zahl nun mit sechs multipliziert, ergibt das natürlich eine Zahl zwischen 0 und 6. Um diese als Index für die COLORCODE Matrix verwenden zu können, benötigt man die PL/I-Funktion trunc, die einfach den Nachkommateil der Zahl verwirft.

 RANDOM:
 procedure returns (type COLOR);
   dcl Zahl float init (0) static;
   dcl COLORCODE dim (0:5) type COLOR nonasgn static
      init (OPTION1, OPTION2, OPTION3, OPTION4, OPTION5, OPTION6);

   if Zahl = 0
      then Zahl = random(time());
      else Zahl = random();
   return (COLORCODE(trunc(Zahl*6)));
 end RANDOM;  

Nach dem initialsieren der Code-Matrix, d.h. der Farbwahl des Computers,  ist der Benutzer am Zug. Seine Eingabe wird innerhalb einer Endlosschleife im Hauptprogramm entgegengenommen.

 do loop;
    display ('TIP?') reply (ANSWER);
    ...
    end;

Danach wird vom Programm versucht, die Benutzereingabe in einen gültigen Tipp umzuwandeln. Dabei wird versucht, die Eingabe zu parsen und in eine Matrix zu konvertieren. Diese Aufgabe übernimmt wiederum eine kurze Subroutine namens TRANSLATION die vom Hauptprogramm aus aufgerufen wird.

call TRANSLATION (ANSWER, TIP);

TRANSLATION-Funktion unter die Lupe genommen:

Der erste Schritt ist das Initialisieren der TIP-Matrix mit dem Wert INVALID. Danach wird die Benutzereingabe, mittels PL/I zur Verfügung gestellter translate-Funktion, in Großbuchstaben umgewandelt.  Interessant sind auch die beiden PL/I-Funktionen verify und search. In Ersterer wird das erste Argument darauf hin untersucht, ob es ausschließlich aus den Zeichen des zweiten Arguments besteht. Das dritte Argument gibt die Position an, ab der diese Bedingung Gültigkeit erlangen soll. Verify gibt entweder 0 zurück, sofern alle Zeichen gültig sind, oder die Position des ersten nicht gültigen Zeichens. Die sehr ähnliche search-Funktion durchsucht das erste Argument nach dem ersten Vorkommnis des als zweiten Argument übergebenen Zeichens.

Trans

Sobald die notwendigen Positionen (für Letter und Blank) ermittelt worden sind, wird mittels substring-Methode, das sich durch die Positionen ergebende Wort, aus der Benutzereingabe herauskopiert. Dieses wird danach auf Gültigkeit hin überprüft, d.h. handelt es sich um eine valide Farboption, und gegebenenfalls an der entsprechenden Position in der Tipp-Matrix gespeichert. 

 TRANSLATION:
 procedure (ANSWER, TIP);
/* Variablen-Deklaration */



TIP = INVALID; if length(ANSWER) = 0 then return; S = translate(ANSWER,'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ', 'abcdefghijklmnopqrstuvwxyzäöü'); Blankpos = 1; do I = 1 to 4; Letterpos = verify(S, ' ', Blankpos); if Letterpos = 0 then leave; Blankpos = search(S, ' ', Letterpos); if Blankpos = 0 then Blankpos = length(S)+1; do F = OPTION1 upthru OPTION6; if substr(S, Letterpos, Blankpos-Letterpos) = ordinalname(F) then TIP(I) = F; end; end; end TRANSLATION;

Nach dem Aufruf der TRANSLATION-Methode hat man eine initialisierte Tipp-Matrix die nun auf Richtigkeit hin überprüft werden kann. Die any-Funktion wird von PL/I zur Verfügung gestellt und erwartet als Argument eine Matrix. Es wird für jedes Element in TIP überprüft ob es den Wert INVALID besitzt. Als Ergebnis erhält man eine neue Matrix die nur aus Bit-Werten besteht. Sofern eines der Felder in der neuen Matrix auf den Wert Wahr (1’b’) gesetzt wurde und somit ursprünglich den Wert INVALID hatte, ergibt die any-Funktion ebenfalls wahr (OR-Verknüpfung).

 if any(TIP = INVALID) then

display ('INVALID COLOR!');

Die all-Funktion verhält sich ähnlich zur any-Funktion jedoch handelt es sich hier um eine AND-Verknüpfung, d.h. alle Elemente der übergebenen Matrix müssen den Wert Wahr (‘1’b) besitzen. In diesem Fall muss jede Farboption des Tipps der jeweiligen Farbeoption der Code-Matrix entsprechen. Ist das der Fall, handelt es sich um einen richtigen Benutzertipp und die do-Schleife wird unterbrochen und das Programm beendet.

 if all(TIP = Code) 
    then leave;

Ansonsten wird mittels einer weiteren Subroutine namens EVALUATION diejenigen Treffer des Tipps ermittelt, die entweder die richtige Farbe und richtige Position (HITS) oder nur die richtige Farbe (HITS_OTHER_POSITION) besitzen. 

 do loop;
    ...
    call EVALUATION (Code, TIP, HITS, HITS_OTHER_POSITION);
    ...

EVALUATION-Funktion unter die Lupe genommen:

 EVALUATION: 
 procedure (Code, Tip, HITS, HITS_OTHER_POSITION);
   
/* Variablen-Deklaration */
HITS = sum(Tip = Code); HITS_OVERALL = 0; do F = OPTION1 upthru OPTION6; HITS_OVERALL += min(sum(Tip = F), sum(Code = F)); end; HITS_OTHER_POSITION = HITS_OVERALL - HITS; end EVALUATION;

Wie auch schon bei der any- und all-Funktion, handelt es sich bei dem übergebenen Argument der von PL/I zur Verfügung gestellten sum-Funktion, um eine Bit-Matrix. Wenn also die in der Tip-Matrix eingetragenen Farboptionen mit denen der in der Code-Matrix übereinstimmen, werden alle Elemente die den Wert Wahr (1’b’) besitzen, aufsummiert (Hits). Um die Anzahl der Treffer zu berechnen, bei denen nur die Farbe korrekt ist, wird zuerst in einer do-Schleife für jede mögliche Farboption, die Anzahl der gesamten Treffer ermittelt und aufsummiert. Danach werden von den gesamten Treffern die Hits abgezogen und man erhält genau die Treffer bei denen nur die Farbe korrekt ist.

EVAL

Programmterminierung

Die Endlosschleife des Hauptprogamms wird erst dann unterbrochen, bis die Tipp- und die Code-Matrix übereinstimmen oder der Benutzer eine leere Eingabe  macht. D.h. der Benutzer spielt so lange, bis er die richtige Kombination erraten hat oder bis er das Spiel durch eine leere Zeichenkette abbricht.

Zusatzpunkte

In der Aufgabenstellung findet man unter Tipps den Hinweis, dass das zu untersuchende Programm nicht ohne Änderungen lauffähig sei. Zusatzpunkte könne man dadurch erreichen, indem man die Ursache für für das Nichtfunktionieren herausfindet und dann das Programm so abändert, damit es lauffähig wird.

Was mir beim ersten Überfliegen des Programms sofort aufgefallen ist, ist die Namensgleichheit der selbst erstellten Funktion RANDOM und der entsprechenden PL/I-Funktion. Da diese Funktion leider nicht mit meinem gefunden Compiler funktioniert, konnte ich das Programm auch nicht lauffähig bekommen. Allerdings habe ich ein kurzes Programm geschrieben, dass zumindest zeigt, dass eine solche Namensgleichheit nicht vorkommen darf.

Programm für das Aufzeigen eines Namenkonflikts

 

 

 

 

 

 

 

Fazit

Obwohl es sich bei PL/I um eine doch etwas in die Jahre gekommene Programmier-sprache handelt, finde ich doch einige Sprachkonstrukte sehr interessant. Zum Beispiel die Matrizen-Operationen wie any oder all finde ich äußerst gut lesbar und leicht zu verstehen.

Veröffentlicht unter University | Verschlagwortet mit | 1 Kommentar

Refactoring Kata mit IntelliJ – Jason Gorman’s Assault Course

Vor kurzem habe ich mich dazu entschlossen, auf eine neue IDE umzusteigen. Da ich die letzten Jahre hauptsächlich mit Eclipse und NetBeans gearbeitet habe und wirklich jeder meiner Rock Star Programmer IntelliJ empfiehlt, war es höchste Zeit für mich, diese IDE einmal auszuprobieren. Da ich wirklich ein großer Eclipse Fan bin habe ich bis jetzt keinen sonderliches Verlangen danach verspürt, die Entwicklungsumgebung zu wechseln. Die große Anzahl an Shortcuts – ich steh besonders auf Strg + 3 – und die außerordentlich gute Integration von Maven mittels des m2eclipse-Plugin, machte Eclipse zu meiner absoluten Lieblings-IDE (zumindest bis vor kurzem).

Ich habe IntelliJ jetzt seit ungefähr zwei bis drei Wochen intensiv getestet. Mein Hauptaugenmerk lag dabei auf den Editor-Qualitäten, der Maven- und Groovy-Integration und bis jetzt bin ich absolut begeistert. Die Shortcut-Möglichkeiten sind um einiges ausgereifter als in Eclipse. Ich habe mittels Jason Gorman’s vor kurzem geposteten Assout Course, einige der tollen Refactorings von IntelliJ getestet. Der folgende Screencast zeigt mich beim Üben des Refactoring Katas in IntelliJ:

My version of Jason Gorman’s Refactoring Kata using IntelliJ

 

 

 

 

 

 

 

Zum Vergleich hier der Screencast von Jason Gorman mittels Eclipse:

Aussault Course by Jason Gorman using Eclipse

 

 

 

 

 

 

Den Source-Code des Kurses kann man hier downloaden.

Ich mache einige Dinge ein bisschen anders als Jason Gorman. Zum Beispiel führe ich Extract-Method-Refactorings immer von unten nach oben durch, da ich gerne meinen Source-Code von oben nach unten, d.h. alle Methoden in der entsprechenden Aufrufreihenfolge, organisiere. Das erlaubt mir meinen Quellcode wie ein Stückchen Prosa zu lesen. Diese Idee stammt übrigens aus Robert C. Martin’s Buch “Clean Code”.

Zuerst werden ein paar Methoden aufgrund von Verantwortlichkeiten in andere Klassen verschoben und extrahiert. Danach wird ein switch-Block durch den Einsatz des Strategy-Patterns ersetzt. Ich habe für das Projekt auch ein Github Repository angelegt. Von dort kann man den Ausgangszustand des Katas für IntelliJ clonen. Nachdem ich mit einem kompletten Durchgang fertig bin, “reverte” ich immer alle Files in den Ausgangszustand um das tägliche Üben zu erleichtern.

Fazit: IntelliJ rockt! Btw. Strg + 3 ist in IntelliJ Strg+Shift+A.

Veröffentlicht unter Kata, Programming, Refactoring | Verschlagwortet mit | Kommentar hinterlassen

IBM WebSphere Application Server v7 und EJB 2.1 / 3.0

In diesem Beitrag beschreibe ich, wie man ein einfaches EJB-Modul “from Scratch” erstellt und danach auf einem Application Server installiert. Hierzu verwende ich für die Entwicklung den Rational Software Architect in der Version 7.5.5.3 und den WebSphere Application Server in der Version 7.0.0.13.

Mein EJB-Modul wird ausschließlich aus einer Stateless Session Bean bestehen die einen einfachen String zurückgibt. Eine Einführung in die EJB-Technologie würde diesen Beitrag jedoch bei weitem sprengen. Jedoch gibt es eine Vielzahl von Online-Ressourcen die man sehr leicht “er-googlen” kann.

Folgende Dinge deckt dieser Blogbeitrag ab:

  • Die Erstellung eines einfachen EJB-Modules in der Version 2.1/3.0
  • Die Einbindung des Moduls in ein Enterprise Archive.
  • Das Deployment des EARs am Application Server.
  • Den Aufruf der Stateless Session Bean aus einem Standalone Java Client.

Im ersten Anlauf werde ich so ziemlich jeden Schritt bei meiner Vorgehensweise ohne Hilfe meiner IDE erledigen. Nur die Erstellung meiner Java Klassen werde ich im Rational Software Architect vornehmen. Auch das Exportieren der Jar Dateien werde ich dem RSA überlassen.

Der folgende Screencast zeigt die Erstellung des EJB v2.1 Projekts und das Deployment am Application Server durch Ausführung eines Jython-Administrationsskipts. Eine Stateless Session Bean, die ich als MessageServiceSLSB bezeichnet habe, retourniert einen einfachen String.

EJB v2.1 Projekt und Deployment am Application Server

 

 

 

 

 

 

IBM Spezifische Konfigurationsdateien

Um das EJB Modul erfolgreich am Application Server installieren zu können, muss man einige IBM spezifische Konfigurationsdateien zusätzlich erstellen.

ibm-ejb-jar-bnd.xmi: Diese Datei ist zwingend für ein erfolgreiches Deployment notwendig. In dieser werden die Bindungen der in der ejb-jar.xml definierten Elemente an die Ressourcen der Laufzeitumgebung eingetragen. Dazu gehören unter anderem die Abbildungen der einzelnen Ressourcen auf die JNDI-Namen innerhalb der Laufzeitumgebung oder die Abbildung der Sicherheitsrollen auf Elemente der Benutzerverwaltung.

ibm-ejb-jar-ext.xmi: In dieser Datei werden Einstellungen festgelegt, die das Laufzeitverhalten des WebSphere Application Servers beeinflussen, die die Standard EJB Spezifikation erweitern.

Im nächsten Screencast zeige ich die Erstellung einer simplen Standalone Java Client Anwendung, die den deployten Message Service aufruft. Dabei muss man folgende Dinge beachten: Der Client benötigt einige Bibliotheken um den Service erfolgreich aufrufen zu können. Deshalb muss man

  • die WAS v7 Runtime,
  • die notwendigen MessageService Interfaces plus deren generierte Stub-Klassen und
  • die Jar-Datei: “com.ibm.ws.admin.client_7.0.0.jar”

im Java Build Path der Client Anwendung hinzufügen. 

Die zuletzt genannte Datei befindet sich im Server (WAS v7)  Home-Verzeichnis im runtimes-Directory. Im Screencast habe ich dafür eine User-Library in der IDE angelegt um das Hinzufügen zu Projekten zu beschleunigen. Interessant ist auch, dass ich aus dem im zuvor gezeigten Video erstellen Enterprise Archive, alle Files bis auf die Interfaces und die zugehörigen Stubs aus der Jar Datei des EJB Projekts entferne, da sie von der Client Anwendung nicht benötigt werden.

Aufruf der Stateless Session Bean aus einem Standalone Java Client

 

 

 

 

 

 

Bis zu dieser Stelle im Beitrag habe ich ein EJB Modul der Version 2.1 in einem Enterprise Archive integriert, die notwendigen Stub-Klassen mittels ejbdeploy Kommando generiert und eine Client Anwendung erstellt, die den Service meiner installierten EJB Anwendung aufruft.

Erstellung einer EJB 3.0 Anwendung

Die folgenden beiden Screencasts zeigen im Prinzip genau das Gleiche wie die Vorherigen nur verwende ich EJBs in der aktuelleren Version 3.0. Der Unterschied besteht darin, dass für die Generierung der Stubs nicht mehr das Tool ejbdeploy.bat sondern createEJBStubs.bat zum Einsatz kommt. Wie bereits weiter oben erwähnt, gehe ich hier nicht auf die Technologie (EJBs) selbst ein. Dazu findet man ausreichend im Netz.

Implementierung eines EJB v3.0 Projekts und Deployment auf einem IBM WebSphere Application Server

 

 

 

 

 

 

 

 

Erstellung einer Standalone Java Anwendung die eine Stateless Session Bean aufruft

 

 

 

 

 

 

 

 

Mit diesem Blog wollte ich zeigen, wie einfach die Erstellung eines EJB Projekts und dessen Deployment auf einem WebSphere Application Server funktionieren. Natürlich muss man hierzu wissen, mit welchen Tools man die notwendigen Stubs generiert und wie man automatisiert EARs mittels Jython am WAS installieren kann. Dieses Wissen habe ich mir zum Teil über Schulungen, IBM Redbooks aber auch Internet Foren und der Hilfe von Kollegen angeeignet.

Ich werde in einem weiteren Blog erneut ein EJB Projekt (2.1/3.0) und eine entsprechende Standalone Client Anwendung erstellen, jedoch werde ich dafür erheblichen Gebrauch der Enterprise-Tools des Rational Software Architects machen. Dadurch werden einige bisher durchgeführten Schritte komplett transparent für den Entwickler und der Deployment Vorgang erheblich vereinfacht.

Veröffentlicht unter Development | Verschlagwortet mit , , , , , , | Kommentar hinterlassen

Personal Knowledge Base

In letzter Zeit kommt es des Öfteren vor, dass mich sowohl Arbeits- als auch Universitätskollegen nach meinen Quellen bezüglich aktueller Informationen betreffend meines Lieblingsthemas “Softwareentwicklung” fragen. Deshalb habe ich mich endlich dazu aufraffen können, eine Liste von Ressourcen zusammenzustellen, die ich hauptsächlich verwende.

Google-Reader (Blogs)

Ich benutze schon seit langer Zeit den Newsreader von Google (Google-Reader) und bin eigentlich recht zufrieden. Der Reader erlaubt es Blogs zu abonnieren und dann zu taggen, weiterzuempfehlen und in Verzeichnisse zusammenzufassen. Die folgende Liste enthält die von mir am meisten gelesenen Blogs:

Blogs meiner persönlichen “Rock Star”-Programmer
Blogs von Autoren
Blogs von IT-Seiten 
Blogs von Podcasts

Twitter

Wer glaubt auf Twitter nur sinnlose Statusnachrichten zu lesen, liegt gänzlich daneben. So ziemlich jeder meiner “Rock Star”-Programmer besitzt einen Twitter-Account. Die Möglichkeit über so genannte Hashes zu bestimmten Themen Nachrichten zu lesen, ermöglicht mir ständigen Informationsaustausch mit Gleichgesinnten. Sehr empfehlenswert dabei sind (wie war es anders zu erwarten): #goos, #tdd, #cleancode. Außerdem sind die meisten Personen äußerst hilfsbereit falls man etwaige Fragen zu bestimmten Themen hat. Erst heute habe ich mit Jason van Zyl (Maven) bezüglich der Erstellung von Maven 3 Plug-ins korrespondiert. Ich hatte einige Fragen betreffend der notwendigen Dependecies um Plug-ins erstellen zu können und er konnte mir diese sofort nennen.

Bücher

Ich werde hier jetzt nicht  anfangen Bücher aufzuzählen die ich für lesenswert empfinde… oder doch, eines werde ich erwähnen. Wenn man so wie ich, Interesse an Softwareentwicklung und Objektorientierter Programmierung besitzt, dann gibt es derzeit kein besseres, lesenswerteres Buch als: Growing Object-Oriented Software Guided By Tests. Ich habe bereits hier in einer dreiteiligen Serie darüber geschrieben.

Seit kurzem gibt es einen coolen Service: Any New Books? bei dem man sich registriert und dann zu bestimmten Themen via Mail Nachrichten über neue Bücher erhält.

Das Wichtigste dabei ist niemals aufhören zu lesen Winking smile

Groups

Natürlich dürfen Foren bzw. Groups in dieser Liste meiner Quellen nicht fehlen. Die folgenden zwei Groups befassen sich mit meinen aktuellen Lieblingsthemen.

Yahoo Test-driven Development Group
Google Growing Object-Oriented Software Group

Code-Sharing

Aktuell sehr beliebt ist auch GitHub. Hier findet man außerordentlich viele und oft sehr hilfreiche Quelltexte in jeglicher Programmiersprache. Wie bei Twitter habe ich auch bei GitHub alle meine “Rock Star”-Programmer finden und natürlich auch gleich “follow”en können.

Wie oft lese ich nun meine Blogs und Twitternachrichten? Täglich ca. ein bis zwei Stunden. Die wichtigsten Nachrichten speichere ich mir dann mittels Delicious-Bookmarks, die übrigens auch hier zu finden sind. Wenn ich nicht gleich Zeit finde, alle Neuigkeiten zu lesen, dann verwende ich hierfür Instapaper. Dabei handelt es sich im Grunde um eine To-Read Liste, bei der auch Beiträge archiviert werden können.

So, das war’s fürs erste einmal. Wenn mir noch weitere Quellen einfallen sollten, werde ich diese diesem Blog hinzufügen. Wenn mir jemand seine eigenen Quellen weiterempfehlen möchte, kann er diese gern in einem Kommentar zusammenfassen.

Veröffentlicht unter Resources | 1 Kommentar