Freitag, 1. April 2011

Skalierbarkeit als Gläserne Decke in der Agilität

Agile Softwareentwicklung fokussiert sich auf verlässliche Lieferung von Nutzen. Je schneller sie den liefert, desto besser. Meistens. Die Frage ist nur, wie die Geschwindigkeit erhöht werden kann. Wie skaliert Softwareproduktion?

Skalieren ganz allgemein

Skalieren oder skalierbar sein heißt, auf mehr Bedarf so reagieren zu können, das er gedeckt wird. Wenn ein Website normalerweise 10 Transaktionen in der Sekunde verarbeitet, zu Weihnachten aber 1000 Transaktionen pro Sekunde anfallen würden, die Technik die jedoch nicht verarbeiten kann, dann skaliert der Website schlecht.

Einen Produktionsschritt wie “Transaktion verarbeiten” oder “Supportanfrage beantworten” oder “Briefe zustellen” können Sie skalieren, indem Sie die Ausführung beschleunigen (scale-up) oder mehr Ressourcen für die Ausführung bereitstellen (scale-out).

image

Supporter könnten schneller sprechen oder weniger lange überlegen müssen für eine Antwort, Briefzusteller könnten schneller radeln oder weniger mit Passanten plaudern. Beides würde die jeweiligen Produktionsschritte beschleunigen, so dass in derselben Zeit mehr Anfragen beantwortet oder mehr Briefe zugestellt würden.

Oder der steigende Bedarf wird auf mehr Ressourcen verteilt; die Supporter und Briefträger werden nicht schneller, aber es gibt einfach mehr. Wenn 1000 Briefe nicht mehr von einem, sondern 10 Briefträgern zugestellt werden, dann braucht das sicherlich nur noch ein zehntel der Zeit.

Skalieren durch scale-up (Aufbau) ist eigentlich immer grundsätzlich möglich. Bessere Ressourcen schaffen einfach mehr weg.

Skalieren durch scale-out (Ausbau) ist jedoch nicht immer möglich. Manche Tätigkeiten lassen sich nicht auf mehr Ressourcen verteilen. Einen Roman zu schreiben, lässt sich z.B. nicht dadurch beschleunigen, dass man 5 Autoren damit beschäftigt statt einem.

Was nicht heißt, dass man die Romanproduktion nicht mit mehr Ressourcen beschleunigen könnte. Die “Produktionswerkstatt” von Ken Follett macht es vor.

Daraus folgt, dass es noch einen weiteren Weg gibt, zu skalieren: Fokussierung. Ressourcen schaffen mehr, wenn sie sich auf ihre eigentliche Tätigkeit besser konzentrieren können.

image

Ich nenne das mal scale-in, um auszudrücken, dass hierfür eine Wendung nach innen, eine Besinnung auf das Wesentliche nötig ist.

Die Softwareproduktion skalieren

Auf die Softwareentwicklung als Produktionsprozess lassen sich die Skalierungsmuster natürlich übertragen.

image

Was tun, um mehr “Packerl” zu produzieren? Wenn der Bedarf steigt, dann müssen die Kaufwilligen befriedigt werden. Jeder Kunde bekommt ein “Packerl”. Natürlich müssen diese “Packerl” nicht alle gleich aussehen. Der erste Kunde kann als “Packerl” die Softwareversion 1.0.0.0 bekommen, der nächste die Version 1.0.0.1, der übernächste ebenfalls 1.0.0.1, der vierte 1.0.0.2 usw. Manche Kunden bekommen einfach die aktuelle Version, für andere wird speziell ein Feature eingebaut, ohne das sie nicht kaufen würden.

Nochmal: Wie kann die Softwareproduktion eine steigende Nachfrage befriedigen? Auf dieser Abstraktionsebene kann die Antwort nur lauten: scale-up. Die Softwareproduktion als ganzes muss schneller werden. Sie muss neue Wünsche schneller in “Packerl” transformieren oder sie muss einfach nur mehr “Packerl” hinten rausschieben (also Kunden mit einer existierenden Softwareversion befriedigen).

Und wie kann die Softwareproduktion als Ganzes schneller werden? Keine Ahnung. Für eine Antwort ist mehr Detail nötig. Wie funktioniert die Produktion im Einzelnen?

image

Jetzt gibt es Ansatzpunkte. Zum Beispiel könnte der Vertrieb beschleunigt werden, am ehesten wohl durch scale-out. Aber das lohnt natürlich nur, wenn es genug zu verkaufen gibt, d.h. die Softwareentwicklung mehr liefert als bisher in den existierenden Bedarf hinein abgesetzt werden konnte.

Wenn die das aber nicht tut, wenn sie der Engpass ist, wie könnte die Softwareentwicklung skalieren?

Die Softwareentwicklung skalieren

Mein Gefühl ist, dass Unternehmen sich mit der Skalierung der Softwareentwicklung schwer tun. Sie erkennen sie zwar als Engpass – doch sie reagieren unangemessen.

Kann nicht sein – Scale-in

Das die Softwareentwicklung skalieren könnte, dass sie mehr Kapazität hätte und schneller wäre, wenn sie sich denn mehr auf ihr eigentlichen Geschäft konzentrieren könnte, das haben viele Entscheider nicht im Blick. Es kann doch nicht sein, dass die Softwareentwicklung heute etwas Kontraproduktives tut; alles, was sie tut, muss sie tun. Das ist nötig. Support durch Softwareentwickler muss sein. Teilnahme an vielen Besprechungen muss sein. Statusreports und Timetracking muss sein. Dokumentationen müssen gepflegt werden.

Da ist einfach kein Fett, was weggeschnitten werden könnte.

So sehen es viele Entscheider und können also nicht denken, dass ein scale-in hilfreich wäre.

Allerdings denken Sie das, wenn ein Training oder andere Fortbildungsmaßnahme vorgeschlagen wird. Da haben sie das Gefühl, dass das etwas Unnötiges ist.

Darf nicht sein – Scale-up

Wo jedoch Fortbildung (oder gar Ausbildung) fehlt, da kann auch kein scale-up stattfinden. Denn nur durch Lernen kann die Softwareentwicklung mit den gegebenen Ressourcen ja schneller werden. Das kostet zwar erstmal Zeit, doch dann wird noch mehr Zeit gespart.

Flüssigere Technologiebedienung, bessere Prozesse, geschmeidigere Kommunikation: all das kann man lernen, all das bringt höhere Produktivität. Doch das kostet Zeit und Geld. Also sind Entscheider, die in der “Kostendenke” stecken, sehr unwillig, scale-up-Maßnahmen zu bewilligen.

Muss sein – Scale-out

So bleibt denn nur ein scale-out, um die Softwareentwicklung zu beschleunigen. Die Softwareentwicklung muss sozusagen multipliziert werden:

image

Das bedeutet, die Anforderungen werden von mehreren “Entwicklungsinstanzen” parallel bearbeitet.

Hört sich plausibel an, oder? Entspricht auch der Sichtweise auf Software. Die wird nämlich meist als ein Ganzes, als ein Programm, eine Anwendung so gesehen, wie der Auftraggeber sie ordert.

“Entwickeln Sie für uns eine Faktura!” – also kommt am Ende eine EXE (mit ein paar DLLs) heraus.

Dasselbe Spiel bei einer AVA-Software, einer Warenwirtschaft, einer Branchensoftware für den Rolladen- und Jalousiebau… der Markt will eine Lösung, also wird eine EXE produziert.

image

Die Erfüllung des Kundenwunsches hängt von einer Anwendung ab. Die wiederum hängt davon ab, dass alle Anforderungen erfüllt werden. Und die hängen davon ab, dass sie in einer EXE (mit zugehörigen DLLs) platziert werden.

Scale-out als Gläserne Decke

Die Softwareentwicklung mit scale-out zu beschleunigen, hört sich plausibel an, oder? In jedem Fall ist das das übliche Vorgehen. Wo 5 Entwickler sind, da werden 5 Anforderungen (Features) gleichzeitig in Angriff genommen. Na, vielleicht 4, denn manchmal ist eine Anforderung so schwierig umzusetzen, dass sich besser zwei Entwickler darum kümmern.

In jedem Fall wird bei Produktionsengpässen in der Softwareentwicklung reflexhaft zu scale-out gegriffen. Damit scheinen alle Probleme gelöst. Erstens kann man so alle Entwickler auslasten. Zweitens geht es doch so am schnellsten voran. Oder? Drittens kann man das quasi aus dem Stand. Und umso besser, je mehr Anforderungen schon vorliegen. Man muss dann nur noch ein paar mehr Entwickler dran setzen. Am besten solche, die billiger sind.

Leider entstehen die erwarteten Vorteile dabei – wenn überhaupt – nur kurzfristig. Scale-out auf der Basis von Anforderungen führt nämlich zu einigen Problemen:

Problem #1: Konflikte

Anforderungen sind Durchstiche. Für jede Anforderung muss daher potenziell an allen Schichten einer Codebasis geändert werden. Das kann zu Konflikten führen. Das können physische Konflikte in den Quelldateien sein, die ein Versionskontrollsystem anzeigt. Das können aber auch noch schlimmere Konflikte bei logischen Abhängigkeiten sein.

Problem #2: Verzahnung

Wo Anforderungen parallel umgesetzt werden ohne nähere Planung - Warum sollte es die auch geben, denn ein scale-out auf dieser Ebene soll sie ja gerade vermeiden? Wer mehr plante, der müsste kein scale-out nach Anforderungen betreiben. – da entstehen schnell viele Abhängigkeiten im Code. Code der einen Anforderung nimmt Bezug auf Code, der von einer anderen stammt, weil zwischen beiden ja keine Barriere existiert. Entwickler, die auf Anforderungen konzentriert sind, durchforsten die gesamte Codebasis nach hilfreicher, schon existierer Funktionalität und binden sich daran.

Problem #3: Geringe Geschwindigkeit

Jede Anforderung wird nur von einem Entwickler bearbeitet. Der mag das zwar so schnell tun, wie er kann, doch auf das Gesamtsystem gesehen, ist das nicht die maximale Geschwindigkeit. Bei 5 Entwicklern wird jede Anforderung nur mit 20% der Kapazität bearbeitet. Ihre Umsetzung dauert also 5 mal so lange wie (theoretisch) nötig.

Anforderungen parallel in einem Team bearbeiten entspricht Multithreading-Code. Mehrere Threads im Hintergrund nehmen dem Vordergrundthread Arbeit ab; der friert nicht ein. Doch dafür werden die einzelnen Aufgaben nicht mit maximaler Geschwindigkeit bearbeitet. Der Nutzen: es wird Latenz verborgen.

Ist das aber, was Softwareentwicklung soll? Soll sie möglichst schnell mit vielen Aufgaben beginnen, um den Kunden (oder die Anforderungsdefinition) wieder frei zu geben für anderes Kaum.

Softwareentwicklung soll vielmehr jede Anforderung so schnell wie möglich umsetzen. Erstens, um dem Kunden möglichst schnell Nutzen zu bieten. Es geht also nicht um Entlastung von upstream Produktionsschritten, sondern um Bedienung von downstream Produktionsschritten bzw. des Marktes.

Zweitens um so schnell wie möglich Feedback darüber zu bekommen, ob überhaupt erfolgreich umgesetzt wurde. Denn das wissen wir ja: Nur weil irgendwo Anforderungen stehen, kommt am Ende nicht unbedingt Code heraus, der Gefallen beim Kunden findet. Also muss die Softwareentwicklung daran interessiert sein, mit höchster Geschwindigkeit zu jeder Anforderung Feedback zu generieren. Latenz ist mithin nicht zu verbergen, sondern zu reduzieren.

Problem #4: Hoher WIP

Jede Anforderung wird also nur mit ein Anteil von 1/n bei n Ressourcen umgesetzt. Das heißt, jede Anforderung verweilt sehr lange in der Softwareentwicklung. Immer sind also viele verschiedene Anforderungen in Produktion (work in progress, WIP).

Ob diese Produktion ein Erfolg ist und Geld bringt, stellt sich allerdings erst am Ende heraus, wenn der Kunde sie abgenommen hat. Viele Anforderungen gleichzeitig zu bearbeiten, ist zwar sehr geschäftig, verdient an sich jedoch kein Geld, sondern kostet erstmal nur welches.

Jede Anforderung, die begonnen, jedoch noch nicht fertiggestellt und abgenommen ist, kann potenziell Geld verbrennen. Deshalb ist der WIP zu minimieren. Am besten ist der WIP sogar 1.

Bis eine Anforderung fertiggestellt und abgenommen ist, ist sie auf Halde produziert. Sie ist im System und kostet gerade Geld, weil an ihr gearbeitet wird. Oder sie liegt fertig herum, ohne abgenommen worden zu sein und hat damit Geld gekostet. In beiden Fällen ist es ungewiss, ob der ganze Aufwand gelohnt hat; Kapital ist in ihr gebunden. Das ist betriebswirtschaftlicher Quatsch.

Ob es in besonderen Fällen betriebswirtschaftlich günstig sein kann, Anforderungen auf Halde zu produzieren, um einen Puffer zu haben für nachfolgende Produktionsschritte, lasse ich mal außen vor. Darüber kann man reden. Ich glaube nur nicht, dass daran jeman denkt, der scale-out für die Softwareentwicklung anordnet.

Grenze für die Agilität

Wenn Agilität schnell Kundennutzen herstellen will, wenn Agilität daran glaubt, dass häufiges Feedback nötig ist, um zufriedenstellende Software zu entwickeln, dann kann scale-out nicht der richtige Weg sein.

Scale-out auf Anforderungsebene widerspricht der Agilität oder begrenzt sie zumindest. Das heißt, wer Scrum o.ä. einführt in der Hoffnung, nun endlich maximal schnell Software zu produzieren, der lügt sich in die Tasche, solange er die Features im Sprint parallel entwickeln lässt.

Zu einem agilen Vorgehen muss also noch mehr kommen, um das Ziel der Agilität wirklich zu erreichen. Das geht nur, wenn jede Anforderung mit maximal möglicher Geschwindigkeit bearbeitet wird und der WIP minimal ist.

Architektur erhöht Teamskalierbarkeit

Ich verstehe, dass scale-out so verführerisch ist. Es scheint einfacher zu implementieren zu sein als scale-up oder scale-in. Bei scale-up und scale-in geht es ans Eingemachte, an die Kultur eines Unternehmens. Bei scale-out kann (scheinbar) alles/viel mehr beim Alten bleiben. Deshalb ist als erstes zu fragen, ob scale-out nicht doch irgendwie möglich ist?

Aus meiner Sicht lautet die Antwort ja. Scale-out ist möglich, wenn man ein wenig Architektur betreibt. Statt nämlich die Anforderungen des Kunden einfach nur in eine Anwendung umzusetzen, sollte überlegt werden, wie daraus mehrere Anwendungen werden können.

image

Die Zerlegung eines großen Wunschkonvolutes kann im Rahmen der architektonischen Planung über die Zerlegungsebenen Bounded Context und Partition/App geschehen. Jede App steht dann für eine EXE, die einer Nutzerrolle dient.

Mit scale-out kann dann gleichzeitig an Anforderungen verschiedener Apps gearbeitet werden. Das macht einen gewissen Sinn, weil die Zielgruppen verschieden sind. Gegenüber jeder Zielgruppe beginnt die Arbeit an einer Anforderung also möglichst schnell; die Latenz zu verbergen schafft Zufriedenheit.

Dass die Umsetzung der Anforderungen dann immer noch langsam ist, ist nicht so schlimm (Problem #3), denn die Probleme #1, #2 und #4 verschwinden. Ja, selbst #4 verschwindet, weil WIP pro Anwendung gerechnet werden kann, da die Abnahme pro Anwendung erfolgt.

Der Agilität ist damit durchaus Genüge getan. Pro App wird maximal schnell gearbeitet und Feedback eingeholt. Gleichzeitig kommt aber auch das Gesamtsystem voran.

Eine Zerlegung des großen Ganzen in Bounded Contexts und Apps bringt aber nicht nur für die Skalierbarkeit des Teams Vorteile. Auch die Evolvierbarkeit und die Usability steigen.

A little architecture can go a long way ;-)

Arbeitsorganisation erhöht Teamskalierbarkeit

Was aber, wenn sich das Ganze nicht gut in Apps zerlegen lässt? Oder was, wenn es weniger Apps als Entwickler gibt?

Für noch mehr scale-out Effekt reicht es nicht, die Anforderungen in Apps zu gruppieren. Wirklich höchste Geschwindigkeit pro Anforderung erreicht die Softwareentwicklung nur, wenn sie alle Entwickler (soweit sinnvoll) an eine Anforderung setzt. WIP=1 und Minimierung der Latenz sollten im Sinne agiler Softwareentwicklung das Ziel sein.

Das lässt sich erreichen durch Zerlegung der Anforderungen in Aufgaben. Soweit allerdings nur ein erster Schritt. Probleme #3 und #4 mögen damit gelöst sein. Um jedoch auch noch #1 und #2 in den Griff zu bekommen, ist als zweiter Schritt Komponentenorientierung unverzichtbar.

image

Mit Komponenten können alle Entwickler ungestört an ihren Aufgaben arbeiten. Ob dann ein Entwickler immer in einer Komponente Aufgaben umsetzt oder nur Aufgaben für eine App realisiert, das sei dahingestellt. Hier ist nur wichtig, dass komponentenorientierte Aufgaben der Schlüssel zu maximaler Teamperformance ist.

Nur mit Komponenten lassen sich Anforderungen echt parallel realisieren, um Kunden schnellstmöglichen Nutzen zu bieten und von ihnen Feedback zu bekommen. Ohne Komponenten stoßen Teams an eine gläserne Decke bei der Skalierbarkeit.

Mit Komponenten jedoch bekommt die Softwareentwicklung nicht nur echtes scale-out Potenzial, sondern macht den Code einfacher testbar, erhöht die Evolvierbarkeit und hat bessere Chancen auf Wiederverwendung von Funktionseinheiten.

Aber das bedeutet natürlich nicht, dass deshalb scale-up und scale-in vernachlässigt werden sollten. Auch da gilt es Potenzial zu aktivieren, um schneller und kostengünstiger Software produzieren zu können.

5 Kommentare:

Heinz Meister hat gesagt…

Mir deinem Ergebnis, dass es Vorteile bringt, in Komponenten zu denken und zu entwickeln und das es Vorteile bringen kann, mehrere statt eine EXE zu erstellen, stimme ich überein.

Deine Argumentation, die dich dahin führt, stimmt aber leider hinten von vorne nicht. Nehmen wir mal das Beispiel WIP. Durch Scale-up wird WIP gesenkt nicht erhöht.

Es ist ja normalerweise so, dass eine Firma über eine bestimmte Anzahl von (festangestellten) Entwicklern verfügt. Diese Zahl mag im Laufe der Zeit schwanken, aber auf einen überschaubaren Zeitraum betrachtet ist sie relativ konstant. Nehmen wir an, eine Firma hat fünf Entwickler und glücklicherweise auch fünf Kunden, die alle jeweils eine größere Anwendung haben wollen. Man könnte jedem Entwickler sein Projekt zuteilen, das er von Anfang bis Ende alleine bearbeitet. Oder man steckt alle Entwickler zunächst in das erste Projekt, dann alle in das zweite usw., also auf das jeweilige Projekt bezogen scale-out. Wenn es innerhalb der Anwendungen jeweils (mindestens) fünf relativ unabhängige Anforderungen gibt, wird das gut skalieren und die Entwicklungszeit einer Anwendung beträgt jetzt nur 1/5. Anschließend fließt für das fertiggestellte Projekt das Geld. Genauso bei 2/5, 3/5, 4/5 und 5/5. Zu jedem dieser Termine hatte sich also nur 1/5 der WIP angesammelt im Vergleich dazu, dass jeder Entwickler sein Projekt alleine bearbeitet und somit das Geld für alle Projekte zusammen erst zum Zeitpunkt 5/5 fließt und somit zu diesem Zeitpunkt auch 5/5 WIP angesammelt waren.

Sicher, das war jetzt ein idealisiertes Szenario, aber ich denke, es zeigt, worum es geht: dass durch scale out WIP dramatisch gesenkt wird. Durch scale out sind weniger und nicht mehr Anforderungen in Produktion, bevor sie abgerechnet werden können.

Genauso bei Problem #3. Die absolute Geschwindigkeit der Bearbeitung einer Anforderung sinkt doch nicht deshalb um Faktor fünf, weil vier andere Entwickler parallel dazu an anderen Anforderungen arbeiten. Solange die Anforderung unabhängig von den anderen ist, wird die Umsetzung solange dauern, wie sie eben braucht. Natürlich dauert sie relativ auf die Laufzeit des einen Projekts gesehen jetzt 100% statt vorher nur 20%, aber nur deshalb, weil sich die Laufzeit des Projekts auf 20% verringert hat. Die Anforderung dauert also auf die Laufzeit des Projekt gerechnet nur deshalb fünfmal so lange, weil das Projekt jetzt fünfmal schneller fertig ist. Mithin dauert die Umsetzung der einen Anforderung genauso lange wie vorher.

Sicher, wieder alles idealisiert, aber der Punkt sollte klar geworden sein.

Ralf Westphal - One Man Think Tank hat gesagt…

@Heinz: "Die absolute Geschwindigkeit der Bearbeitung einer Anforderung sinkt doch nicht deshalb um Faktor fünf, weil vier andere Entwickler parallel dazu an anderen Anforderungen arbeiten."

Wenn ich eine Anforderung mit 1 Entwickler in 5 Tagen umsetzen kann und sie mit 5 Entwicklern in 1 Tag schaffe, dann ist die Geschwindigkeit mit 1 Entwickler nur 1/5 der möglichen Geschwindigkeit.

Voraussetzung ist natürlich, dass ich die Anforderung überhaupt mit 5 Entwicklern gleichzeitig in solcher Weise bearbeiten kann. Darum geht es ja am Ende meines Beitrags.

Die meisten Shops können das nicht. Sie verstehen nicht, wie sie 1 Anforderung so strukturieren können, dass 5 Aufgaben auskommen, die 5 Entwickler parallel erledigen können, so dass ein Ergebnis in 1 Zeittag vorliegt. (Dass immer noch 5 Personentage drin stecken, ist ja klar. Wir reden ja über scale-out und nicht scale-up.)

"Nehmen wir an, eine Firma hat fünf Entwickler und glücklicherweise auch fünf Kunden, die alle jeweils eine größere Anwendung haben wollen." Hier beschreibst du ein Szenario, dass dem am Ende mit den mehreren Apps ähnlich ist.

Dazu habe ich ja gesagt, dass der WIP pro App 1 ist, wenn jeder der 5 Entwickler an einer App arbeitet. Und das ist ok, denn jede App bringt für sich Geld.

Bei 5 Kunden kannst du nicht zuerst Kunde A und danach Kunde B bedienen. Bei 5 Kunden musst du "Latenz verbergen" und "Multithreading" betreiben, also WIP>1 in Bezug auf die Softwareentwicklung ingesamt einstellen.

Das ändert aber nichts daran, dass jede Anforderung dann immer noch langsam umgesetzt wird, du also nicht schnellstmögl Feedback erhältst.

Mir gehts darum zu zeigen, dass ohne Komponentenorientierung, also die schiere Fähigkeit, Anforderungen so zu zerlegen, dass an jeder mehrere Entwickler arbeiten können, Agilität nicht voll gelebt werden kann. Du kannst ohne Komponentenorientierung einfach nicht entscheiden, dass du 5 Entwickler auf 1 Anforderung wirfst. Du kannst also den WIP-Regler für das Unternehmen nicht beliebig einstellen, sondern hast zwangsläufig WIP>1 auf alles gerechnet. (Im besten Fall WIP=1 für 1 Anwendung, die von 1 Entwickler betreut wird - dann aber mit geringer Geschwindigkeit.)

Anonym hat gesagt…

Occam's Rasiermesser: Viele Köche verderben den Brei.

Anonym hat gesagt…

Interessanter Artikel. Frage, ist Scale-in nicht das gleiche wie scale-up? In dem Beispiel wird aufgeführt, dass der Briefträger nicht mehr mit Passanten redet und schneller fährt. Das würde ich auch unter Fokussieren auf die Aufgabe verstehen.

Frage ist auch, ob der Entwicklungsprozess wirklich so teilbar ist. Gerade in SW-Entwicklung wächst mit zunehmender Entwicklerzahl der Kommunikations- und Abstimmungsbedarf exponentiell. Dies könnte die Skaleneffekte schnell übertreffen. More people in late project will make it later.

Ralf Westphal - One Man Think Tank hat gesagt…

Stimmt, nicht mehr mit Passanten sprechen, ist Scale-In. Aber schneller radeln ist Scale-Up.

Den Brooks kenne ich natürlich. Und ab einer gewissen Größe gilt der auch. Er wird nur gern hergenommen als generelles Argument, dass mehr Leute nichts brächten. Das halte ich für falsch.

Mit geeigneten Methoden lässt sich Software so entwickeln, dass mehr Leute auch mehr bringen. Die meisten Teams können das aber nicht.

Kommentar veröffentlichen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.