Sonntag, 25. November 2007

Teamfähigkeit von Organisationen

Wenn Mitarbeiter gesucht werden findet man gewöhnlich die Formulierung "teamfähig und belastbar". Schaut man sich aber dann die Arbeitsbedingungen an, so findet man häufig Organisationen, die alles andere wollen als Teams. Was meine ich damit?

Projektmanagement Tools

Das Projektmanagement sieht es als Aufgabe an, das Projekt in kleine Tasks zu zerlegen, diese in Pertcharts einzutragen und den "Team"-mitgliedern zuzuweisen. Danach wird regelmäßig der Fortschritt bei jedem Einzelnen abgefragt. Durch diese von oben kommende Arbeitsverteilung wird das Team aber zerstört. Teamarbeit sollte bedeuten, daß die Teammitglieder zusammenarbeiten und die Fähigkeiten des Einzelnen dem Team zugute kommt. Stellt aber ein Teammitglied fest, daß es das Ergebnis des Teams deutlich verbessern könnte, wenn es eine Aufgabe leistet, die ihm nicht zugeordnet ist, wird sich das Teammitglied dies dreimal überlegen, denn es hat dann einen geringeren Fortschritt bei der ihm zugewiesenen Aufgabe und schwierige Diskussionen mit dem Projektmanager zu erwarten. Läßt der Projektmanager aber solches Handeln zu, so verliert sein Plan rasch an Wert. Fazit: wenn Projektpläne so benutzt werden, daß die Tasks einzelnen Personen zugewiesen werden, hat man eine Gruppe von Einzelkämpfern.

Individuelle Zielvereinbarungen

Heutzutage sind variable Gehaltsbestandteile sehr beliebt. Häufig sind sie mit individuellen Zielvereinbarungen verbunden. Diese stehen leicht in Konflikt mit den Projektzielen. Wenn ich neben der Projektarbeit noch über das Jahr z.B. ein Abteilungs-Wiki aufbauen soll, muß ich mir überlegen, ob ich an dem Wiki arbeite und mein Gehalt verbessere oder zum Projektfortschritt beitrage. Besonders schwierig wird es, wenn einzelne Teammitglieder Ziele haben, die sich widersprechen oder in Konkurrenz stehen. Will ich nun die Kundenzufriedenheit steigern oder den mittleren Stundensatz durch Einbindung von Offshorekräften senken? Hier kann es bis zur (eventuell unbewußten) Sabotage kommen.

Mitarbeiterbeurteilung

Bei einem Gespräch mit Kollegen fiel neulich die Bemerkung, daß auch der Wunsch besteht, die persönliche Leistung sichtbar zu machen und so ein besseres Gehalt zu erzielen. Daher kamen Vorbehalte gegen Teamarbeit. Dies finde ich besonders traurig. Die Vorgesetzten hoffen darauf, daß die Konkurrenz untereinander zu höherer Leistung anspornt. In Wirklichkeit entsteht aber nur Reibung. Auch wenn das gesamte Team einheitlich beurteilt wird, werden gute Mitarbeiter in der Regel nach einiger Zeit besser dastehen als weniger geeignete. Ein guter Mitarbeiter muß nur dafür sorgen, daß sein jeweiliges Team erfolgreich ist. Allerdings könnten dann auch ganz andere Eigenschaften zu höherem Einkommen führen wie bei dem Einzelkämpfermodell. Eine Person, die in der Lage ist, die Kommunikation in einem Team positiv zu fördern, so daß die Teammitglieder besser arbeiten können, könnte auch bei mäßigen technischen Fähigkeiten sehr gut darstehen, wenn ihr das immer wieder gelingt.

Fazit

Bei vielen althergebrachten Organisationen bedeutet Teamfähigkeit, nicht gegen die von oben vorgegeben Spielregeln aufzumucken, und Belastbarkeit ist notwendig, die dadurch entstehenden Reibungsverluste aufzufangen.

Solche Organisationen sind mittelfristig dem Untergang geweiht. Es gibt heute gut ausgearbeitete Modelle zur Projektarbeit im Team, die eine wesentlich höhere Effizienz erreichen. Diese findet man unter dem Stichwort agil (z.B. Scrum). Firmen, die bei den alten Strukturen bleiben, werden sich in der gleichen Situation finden, wie einige große Firmen der Automobilindustrie, die zu spät erkannt haben, wie die japanischen Konkurrenten die Effizienz und Qualität haben steigern können.

Sonntag, 18. November 2007

Wie man aus einer Ameise (k)einen Elephanten macht

Der Hauptgrund, der meist für die Verwendung von typisierten Sprachen genannt wird, ist, daß Typfehler schon zur Compilezeit abgefangen werden. Wenn man versucht, die Methode trompeten bei einer Ameise aufruft, sollte sich der Compiler beschweren. Bei älteren Java- und C#-Versonen ist das aber spätestens dann eine Illusion, wenn das Tier zwischenzeitlich in einer Collection war. Dort wir alles zum Object, wenn es aus der Collection herausgeholt wird, muß es dann wieder zum Elephanten gecastet wird. Wenn es dann doch eine Ameise war, gibt es einen Laufzeitfehler.

Mit Java 5 und C# 2.0 kamen nun die Generics. Wenn wir nun eine Collection Tierkäfig haben, dann können wir jetzt spezielle Käfige herstellen für Ameisen (Tierkäfig<Ameise>) oder Elephanten (Tierkäfig<Elephant>). Jetzt wird zur Compilezeit sichergestellt, daß in jeden Käfig die passenden Tiere kommen und ein Cast ist beim herausholen nicht mehr notwendig.

So, jetzt ist ja alles gut. Wir verwenden überall eifrig Generics. Auch junge, aufstrebende Architekten entwerfen ambitionierte Frameworks basierend auf Generics. Damit brauchen sie dann aber auch Methoden, die als Argument beliebige Tierkäfige verarbeiten können. Das klingt nun zuerst recht logisch, führt aber bald zu Problemen. Natürlich kann man einen Elephantenkäfig nicht einem Ameisenkäfig zuweisen. Aber auch ein Ameisenkäfig kann normalerweise nicht als Tierkäfig verwendet werden, denn dann könnte man aus dem Ameisenkäfig auch einen Elephanten holen - das gleiche Problem, das wir vor den Generics hatten.

Wenn wir Java verwenden, haben wir eine Lösung. Java kennt nämlich die Begriffe Covarianz und Contravarianz. Eine Zuweisung eines Ameisenkäfigs an einen Tierkäfig kann nämlich ungefährlich sein, wenn wir sicherstellen, daß wir nur allgemeine Tiermethoden aufrufen und keine Tiere hineintun, da wir nicht mehr die Art sicherstellen können. Das heißt Covarianz. In Java sieht das so aus:

String gibTierNamen(TierKäfig<? extends ITier> käfig)

In einen Ameisenkäfig können wir auch Waldameisen hineingeben. Das ist dann Contravarianz. In Java schreibt man dann statt extends super.

C# kennt (bislang, Version 3.0) noch keine keine Co- und Contravarianz. Wenn dann die Entwickler, die das Framework unseres jungen Architekten umsetzen, anfangen, auf Reflection zurückzugreifen, sollte der Architekt ins grübeln kommen:

public static String gibTiernamen(object käfig)

{

MethodInfo mInfo = käfig.GetType().GetMethod("Freilassen");

ITier tier = (ITier)mInfo.Invoke(käfig, null);

return tier.Name;

}

Wenn wir so programmieren, sollten wir doch lieber gleich eine dynamische Programmiersprache wie Python oder Ruby verwenden. Die können dies viel besser.

Wie kann sich nun in C# derzeit retten? Nun, in diesen allgemeinen Methoden wird auch nur allgemein auf das Tier zugegriffen und keine artspezifische Information verwendet. Man definiert einfach ein Interface, daß alle Methoden der Tierkäfigs enthält, die nicht von der Art abhängen. Dieses ist nicht generisch. So kann man jetzt dieses Interface in der allgemeinen Methode verwenden:

public static String gibTierNamen(ITierkäfig käfig)

{

return käfig.Tierart.Name;

}

Sonntag, 4. November 2007

Paradigmenverschiebung bei Programmiersprachen

Es hat sich schon seit einigen Jahren abgezeichnet, aber jetzt mehren sich die Zeichen, daß es beginnt: Die funktionale Programmierung verläßt ihre Nische und wird zum wichtigen Bestandteil zukünftiger Programmiersprachen.

Microsoft plant offensichtlich F# zur gleichberechtigten Sprache neben C# zu machen (Somasegar's WebLog). Dies wäre nur konsequent, da die meisten Neuigkeiten von C# 3.0 - insbesondere LINQ - zuerst in F# ausprobiert und dann in C# übertragen wurden. Wobei C# mit seinen Delegates bereits ein funktionales Element enthält.

Martin Oderskys Scala, eine Sprache für die JVM (alternativ auch CLR), die elegant den objektorientierten und funktionalen Ansatz verbindet, zieht zunehmend Entwickler an, wie z.B. das Lift Web-Framework zeigt.

Die Begeisterung für dynamische Sprachen (Python, Ruby et altera), kommt zum Teil auch daher, daß hier Funktionen vollwertige Elemente sind und die Eleganz funktionaler Programmierung erreicht werden kann. Allerdings wird es Guido van Rossum offensichtlich langsam unheimlich, daß sein Python langsam für viele Nutzer zu einem Lisp ohne Klammern wird (siehe).

Woher nun dieses Interesse? Funktionale Programmierung ist jetzt 50 Jahre alt, wenn man LISP als erste funktionale Sprache ansieht. Im Laufe der Zeit wurden eine Reihe von funktionalen Sprachen entwickelt wie z.B. die ML-Familie, deren jüngstes Kind F# ist, und Haskell. Diese Sprachen führten bislang aber ihr Nischendasein im akademischen Bereich und in der "künstlichen Intelligenz". Sie sind abstrakter und mathematisch besser fundiert als andere Ansätze. Lange Zeit hatten sie den Ruf, weniger effizient zu sein wie imperative und objektorientierte Sprachen.

Die Verwendung in KI-Programmen zeigt, daß die Stärke des funktionalen Ansatzes in der Programmierung von komplexen Algorithmen liegt. Wenn es nur darum geht, Speicherbereiche zu verschieben, geht das auch mit Sprache wie C. Die Anforderungen an Computerprogramme steigen immer weiter und die Entwicklungszeit ist häufig wichtiger als das letzte an Effizienz herauszuholen. Daher lohnt es sich, Sprachen zu bevorzugen, die elegante Formulierungen der Probleme erlauben.

Das funktionale Programmierung erst jetzt ins allgemeine Bewußtsein gerät, hat drei Gründe:

  • Sie verbrauchen mehr Speicher, da sie Daten nicht ändern sondern neu erzeugen. Speicher ist aber jetzt billig.
  • Die Compiler sind besser geworden, so daß effektiverer Code erzeugt wird.
  • Im Gegensatz zu C-Programmen braucht es mehr Erfahrung abzuschätzen, welchen Aufwand ein Stück Code bei der Ausführung braucht. Das ist heute eher akzeptiert als vor zehn Jahren, da dies z.B. auch bei Java nicht immer einfach ist und wir es gewohnt sind mit komplexen Applicationservern und Frameworks umzugehen, deren Innenleben weitgehend unbekannt ist.

Es ist damit zu rechnen, daß sich die gängigen Sprachen (Java und C#) in den nächsten Jahren zu gemischt funktional-objektorientierten Sprachen entwickeln werden. Zum anderen ist es heute leichter, ganz neue Sprachen einzusetzen, da der Microsoftansatz eine CLR für beliebig viele Sprachen zu haben, sich auch in der Welt der JVM durchgesetzt hat und das "J" in JVM nur noch den Ursprung in Java angibt. Interoperabilität zwischen Sprachen ist kein Problem mehr.