FLYT CONSULTING Matko Smoljan
← Zurück zum Blog

"Warum erfahren wir erst jetzt von Problemen?"

· 7 Min. Lesezeit

Gemeint ist: “Warum erfahren wir erst so spät im Sprint/Epic/Projekt, dass es Probleme gibt?”

Ein Klassiker. Wer ein paar Jahre in der Tech-Branche verbracht hat, hat eine Variante davon sicher schon mehr als einmal gehört oder selbst gesagt.

Sehr oft ist der erste Reflex, verinnerlicht oder sogar offen ausgesprochen, dem Engineering-Team die Schuld zu geben oder zumindest dessen Senioritätsstufe in Frage zu stellen. Wenn das der Fall ist, könnte eure Kultur bereits auf dem Weg den Bach runter sein, und das liegt nicht an den genannten Personen. Also zieht euch die Handschuhe an und macht euch bereit, sie da rauszuholen.

Um die Ursache zu veranschaulichen, beginne ich mit einer realen Anforderung (sensible Details ausgelassen): Jedes Mal, wenn man die Seite eines Teams in der Webanwendung öffnet, soll die zuvor über ein Dropdown ausgewählte Unterseite aus dem Cache geladen werden (damit man wieder auf der ersten Seite landet, wenn man das Team eine Weile nicht öffnet).

Skizze einer Webanwendung, die eine gecachte Unterseite aus dem Browser-Speicher lädt, mit unbeantworteten Fragen zur Cache-Ablaufzeit

Meine intuitive Schätzung dafür, ohne tieferes Nachdenken, wäre 2-3 Stunden gewesen, inklusive Review-Zeit und Deployment. Für jeden Nicht-Techniker mag alles darüber hinaus für so eine einfache Sache lächerlich erscheinen. OK, dann bauen wir es.

Wir speichern einfach die ausgewählte Team-ID im Browser-Speicher. Der Browser begrenzt, wie viel Speicher eine Website nutzen darf, aber es sollte ohnehin nicht so viel sein. Eigentlich sollten wir eine Liste von Team-IDs speichern, weil Benutzer häufig Zugriff auf mehrere Teams einer Organisation haben.

Moment, ich habe gerade “Organisation” gesagt. Manche haben auch Zugriff auf mehrere Organisationen, das müssen wir berücksichtigen. OK, nach etwas Recherche und investierter Zeit stellen wir fest, dass ein Team nicht in mehreren Organisationen sein kann. Obwohl wir also etwas Extra-Zeit verloren haben, sind wir zumindest sicher, dass das nicht relevant ist.

OK, jetzt wollen wir also unsere Liste von Team-IDs speichern. Nachdem wir einige Zeit darüber nachgedacht haben, in welchem Browser-Speichertyp wir diese ablegen sollen, entscheiden wir uns für Local Storage.

OK, aber wenn der Benutzer morgen wiederkommt, soll er wieder auf der ersten Unterseite starten (daher der Cache). Oder doch nicht? Die Anforderung besagt nur, dass es einen Cache geben soll, was auf eine vage Form eines Ablaufmechanismus hindeutet. Das macht es notwendig, einen Weg zu finden, Daten im Local Storage zu invalidieren, was bedeutet, dass eine Art Cache-Management-Mechanismus gebaut werden muss, möglicherweise einschließlich einer zusätzlichen Bibliothek. Aber viele Details fehlen noch in der Anforderung:

  • Was passiert, wenn der Benutzer die Team-Seite erneut besucht? Wird die Ablaufzeit für dieses Team zurückgesetzt?
  • Wird alles um Mitternacht zurückgesetzt und alle Teams zeigen die erste Unterseite, oder bekommt jedes besuchte Team einen eigenen 24-Stunden-Countdown?
  • Im Mitternachts-Szenario müssen wir sicherstellen, dass “Mitternacht” in der Zeitzone des Benutzers und nicht in UTC verfolgt wird.

(Bitte beachtet, dass ich nicht vorschlage, dass ihr immer derart detaillierte Anforderungen dokumentiert haben solltet, aber idealerweise solltet ihr in der Lage sein, schnelle Entscheidungen dazu mit eurem PM oder PO zu treffen.)

Vielleicht wäre ein ablaufendes Cookie eine bessere Option als Local Storage? Aber einige Browser haben Beschränkungen für die Anzahl der Cookies pro Domain, also wollen wir diesen Speicher wahrscheinlich nicht verschmutzen.

Nach einer Weile könntet ihr entscheiden, dass es einfacher wäre, das im Backend zu lösen, da ihr zumindest eine bereits laufende Redis-Instanz habt, die das handhaben und dort bereinigen könnte. Aber dann müsst ihr:

  • Die IDs über Endpunkte speichern und abrufen und auch das Frontend entsprechend anpassen.
  • Ihr müsst jetzt auch Team-IDs mit Benutzern verknüpfen und all diese individuellen Kombinationen verfolgen, weil zwei oder mehr Benutzer Zugriff auf dasselbe Team haben könnten, aber unterschiedliche Unterseiten auswählen. Sie könnten auch in verschiedenen Zeitzonen sein und/oder unterschiedliche Ablaufzeiten haben.
  • Und so weiter und so fort…

Also, auch wenn ihr keine Entwickler seid, habt ihr inzwischen sicher bemerkt, dass die Implementierung ein Vielfaches der ursprünglichen Schätzung dauern würde. Einige dieser Dinge sind nach kurzem Nachdenken vorhersehbar, aber die meisten nicht, bis ihr tatsächlich Zeit für solche Features aufwendet (also sowohl darüber nachdenkt als auch sie entwickelt). Außerdem werden unter höherem Lieferdruck mehr dieser Überlegungen am Anfang übersehen.

Es ist nicht ungewöhnlich, dass dies bei mehreren Tickets innerhalb desselben Sprints oder Epics passiert. Für die Tickets, die das Team früh aufgegriffen hat, erfahrt ihr vielleicht sogar “rechtzeitig” von Problemen, eskaliert früh genug an eure Vorgesetzten und alles ist gut. Aber wenn das in späteren Phasen passiert, und das kann definitiv vorkommen, könnt ihr:

  • Eskalieren mit sofortiger negativer Auswirkung auf die Teammoral. Wenn das eure Standardreaktion auf aufgeworfene Probleme ist, werdet ihr eure Kultur mit tausend kleinen Schnitten zerstören. Ihr werdet auch euer Projekt weiter gefährden, indem ihr den Fokus von der Entwicklung auf unzählige Stunden in Retrospektiven und anderen Meetings verlagert, um herauszufinden “was schiefgelaufen ist”.
  • Daran arbeiten, eure Erwartungen und euren Prozess widerstandsfähiger gegenüber solchen Updates zu machen. “Widerstandsfähig” bedeutet nicht “beim nächsten Mal besser vorausplanen” (das ist reines Wunschdenken), sondern einen klaren Weg nach vorn zu haben und die Kosten der Anpassung jedes Mal zu senken, wenn so etwas passiert.

Ich bin offensichtlich für den letzteren Ansatz. Also, wie werdet ihr widerstandsfähiger?

Hier ein paar Ideen:

  • Schafft den Begriff “zu spät sein” ab, und versetzt euch generell in die Denkweise, Überraschungen zu erwarten.
  • Wenn eine Verlängerung des Zeitrahmens keine Option ist (stellt sicher, dass ihr selten in dieser Situation seid!), plant euren Umfang so, dass ihr davon etwas abschneiden könnt, um ein wichtiges Datum noch zu treffen.
  • Fangt nicht an, wiederholt Fragen zu stellen, wie die wahrgenommene Verzögerung passieren konnte. Das ist sehr ermüdend für das Team, und ihr werdet meistens Variationen derselben Antwort hören.
  • Vereinfacht eure Reaktion auf jede Überraschung (“kein Drama”). Ihr könntet versucht sein, ein paar Meetings obendrauf zu setzen, häufiger nach Status-Updates zu fragen, für jeden Sprint eine Retrospektive anzusetzen usw., aber tut das nicht. Vertraut stattdessen eurem Team und versucht, mehr Wert aus den Status-Meetings herauszuholen, die ihr bereits habt, und schaut dann, ob sogar einige davon gestrichen werden können, um mehr Raum für Auslieferung zu schaffen.
  • Versprecht keine konkreten Termine an Kunden! Es ist in Ordnung und sogar wichtig, sie auf dem Laufenden zu halten, woran ihr arbeitet und was ihr in Zukunft plant, aber die Formulierung muss sorgfältig sein, und es muss für sie klar sein, dass sich die Zeitpläne ändern können. Das kann wegen unvorhergesehener Probleme passieren, aber genauso wegen sich ständig ändernder Geschäftsziele, also ergibt diese Strategie aus mehreren Blickwinkeln Sinn.
  • Nehmt Schätzungen niemals als Zusage, denn so werdet ihr Zusagen meistens brechen. Noch wichtiger: Kommuniziert sie nicht nach außen (siehe vorheriger Punkt). Warum? Weil Schätzungen normalerweise zu dem Zeitpunkt gemacht werden, an dem ihr am wenigsten über die bevorstehende Arbeit wisst, sodass sie oft falsch sein werden, wenn sie nicht angepasst werden.
  • Wendet moderne Software-Engineering-Praktiken an, wie Trunk-Based Development, Test-Driven Development, Feature Flags, Continuous Delivery, Pair Programming usw., um sicherzustellen, dass ihr eure Software in kleinen Stücken und häufig ausliefern könnt.
  • In Bezug auf den vorherigen Punkt: Strebt an, mehrmals täglich in Produktion zu deployen. So wird eure gesamte Organisation immer die aktuelle Version eurer Software nutzen und angemessene Erwartungen haben.
  • Ersetzt Schätzungen durch Prognosen. Eine Schätzung ist eine Zahl, die festgelegt wird, wenn ihr am wenigsten über die Arbeit wisst; eine Prognose wird laufend daraus neu berechnet, wie die Auslieferung tatsächlich voranschreitet. Haltet diese Prognose zugänglich und aktuell, damit ihr frühzeitig auf Änderungen reagieren könnt.