Zum Inhalt springen

Aufgabe 09 - Jahresprojekt Sprint 2 - Review, ISP und DIP

Zu Zen-Modus wechseln
  • Du zerlegst ein zu breites Interface nach dem Interface Segregation Principle in kleine, gezielte Schnittstellen.
  • Du schließt Sprint 2 mit Review, Retrospektive und Release ab.
  • Du ersetzt im Jahresprojekt eine fest verdrahtete Abhängigkeit nach dem Dependency Inversion Principle durch eine hereingereichte Abstraktion und wählst die konkreten Klassen an einer einzigen Stelle.
  • Du testest Fachlogik deines Projekts ohne Datenbank, indem du eine Implementierung im Arbeitsspeicher hereinreichst.

Dritte und letzte Woche von Sprint 2. Nach Review und Retrospektive geht es um die zwei letzten Buchstaben von SOLID (Kapitel 14): I (kein Client hängt von Methoden ab, die er nicht braucht) und D (die Geschäftslogik kennt nur die Abstraktion, die Wahl der konkreten Klasse trifft eine einzige Stelle). In fast jedem Jahresprojekt gibt es eine Stelle, an der die Fachlogik ihre Datenbank oder ihren Speicher selbst erzeugt. Genau dort lohnt sich DIP am meisten, denn danach lässt sich die Logik ohne Datenbank testen.

Die Kata: Geräte der Medienwerkstatt. Der Startcode:

interface StudioDevice {
record(seconds: number): string;
play(file: string): void;
printLabel(text: string): void;
}
class Microphone implements StudioDevice {
record(seconds: number): string { return `take-${seconds}s.wav`; }
play(): void { throw new Error("a microphone cannot play"); }
printLabel(): void { throw new Error("a microphone cannot print"); }
}
class Speaker implements StudioDevice {
record(): string { throw new Error("a speaker cannot record"); }
play(file: string): void { console.log(`playing ${file}`); }
printLabel(): void { throw new Error("a speaker cannot print"); }
}
class Playlist {
constructor(private readonly device: StudioDevice) {}
playAll(files: string[]): void {
for (const file of files) this.device.play(file);
}
}

Dafür brauchst du:

  • Kapitel 14 Entwurfsmuster I – SOLID: I und D (Fat Interface, High-Level- und Low-Level-Modul, hereingereichte Abstraktion, Composition Root, DIP gegen Dependency Injection gegen IoC-Container, Zusammenspiel der fünf Prinzipien).
  • Kapitel 05 bis 07 für Review, Retrospektive und Release.
  • Euer Design-Review aus Aufgabe 07 und 08.

Projektordner anlegen siehe https://qiz.at/projektordner

  • Lies vorher kurz https://qiz.at/assignmentsabgabe durch.
  • Nur vollständige Abgaben (siehe https://qiz.at/rules) können positiv bewertet werden.
  • Abgabe- und Testdetails siehe https://qiz.at/assignmentsabgabe
  • Abgegeben wird dein Projektordner mit der Kata (Code und README.md) und den Links auf Sprint-Protokoll, Release, Issues, Merge Requests und Abschnitte im docs/design-review.md des Jahresprojekts. Bezeichner und Kommentare im Code sind Englisch.
  • Wer was beigetragen hat, zeigen Board, Merge Requests und /spend-Einträge (Kapitel 07).
  • Kata: Liste alle Methoden auf, zu denen eine Klasse gezwungen wird, obwohl sie nichts damit anfangen kann. Zerlege StudioDevice in kleine Schnittstellen, sodass keine Klasse mehr eine sinnlose Methode enthält und Playlist nur noch von dem abhängt, was es braucht. Prüfe mit npx tsc --noEmit, dass alles übersetzt.
  • Review von Sprint 2: Vorführung Story für Story gegen die Akzeptanzkriterien, Sprint-Protokoll mit abgenommenen und zurückgelegten Stories, Sprint-Ziel erreicht oder nicht (mit Ursache) und Velocity. Die Lehrkraft geht während der Praxiszeit von Team zu Team (etwa zehn Minuten je Team); bis sie bei euch ist, arbeitet ihr an der Kata und am Projektteil weiter.
  • Retrospektive: Überprüft zuerst die Maßnahme aus Sprint 1 und haltet eine neue, überprüfbare Maßnahme mit verantwortlicher Person fest.

Tipp: Frag bei jeder Klasse der Kata: Würde ein Client, der nur diese Klasse benutzt, alle Methoden des Interfaces aufrufen wollen?

Vollständig, wenn:

  • alle vier sinnlosen Methoden erkannt sind, keine Klasse nach der Zerlegung eine Methode enthält, die sie nicht kann, Playlist nur von einer Schnittstelle mit play abhängt und das Projekt fehlerfrei übersetzt,
  • das Sprint-Protokoll abgenommene und zurückgelegte Stories, die Bewertung des Sprint-Ziels mit Ursache und die Velocity enthält,
  • die alte Maßnahme überprüft ist und die neue Maßnahme überprüfbar ist und eine verantwortliche Person hat.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Release von Sprint 2 nach Kapitel 07 (Release-Merge-Request dev nach main, Tag, Release-Notes, Milestone schließen).
  • DIP im Projekt: Sucht die Stelle, an der eure Fachlogik ihren Datenzugriff selbst erzeugt oder direkt importiert (Datenbank-Client, Datei, fetch auf eine fremde API). Legt dafür ein Issue an und baut in einem Merge Request um: ein Repository-Interface, das nur die Operationen enthält, die die Fachlogik braucht, die bisherige Umsetzung als eine Implementierung davon, die Fachlogik bekommt das Interface über den Konstruktor oder als Parameter hereingereicht.
  • Wählt die konkreten Klassen an einer Stelle eures Projekts aus (Composition Root) und haltet im Design-Review fest, wo sie liegt.
  • Schreibt eine Implementierung im Arbeitsspeicher (InMemory…) und einen Test der Fachlogik, der damit ohne Datenbank und ohne Netzwerk läuft.

Tipp: Wenn in eurer Fachlogik nach dem Umbau noch ein new auf eine konkrete Datenbank- oder Client-Klasse steht, ist die Abhängigkeit noch nicht umgekehrt. Bei Next.js ist eine kleine Datei, die Service und Repository zusammensteckt und von den Routen importiert wird, ein brauchbarer Composition Root.

Vollständig, wenn:

  • Release-Merge-Request, Tag, Release und geschlossener Milestone Sprint 2 existieren,
  • die Fachlogik nur noch vom Repository-Interface abhängt und kein new auf eine konkrete Datenzugriffsklasse enthält,
  • die Auswahl der konkreten Klassen an genau einer Stelle steht und diese im Design-Review benannt ist,
  • ein Test der Fachlogik mit der Implementierung im Arbeitsspeicher grün läuft.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Ergänze einen zweiten Test mit der Implementierung im Arbeitsspeicher, der eine Regel der Fachlogik prüft, die etwas ablehnt.
  • ISP im Projekt: Suche zwei Stellen, an denen eine Funktion oder Komponente ein ganzes Objekt verlangt, aber nur einen Teil davon nutzt (zum Beispiel einen ganzen Benutzer, obwohl nur der Name gebraucht wird). Verkleinere den verlangten Typ und halte im Design-Review fest, was dadurch leichter zu testen oder wiederzuverwenden ist.
  • Baue den Composition Root zu zwei Konfigurationen aus, die eine Umgebungsvariable auswählt: „production“ (echter Datenzugriff) und „demo“ (Implementierung im Arbeitsspeicher mit Beispieldaten). Weise mit git diff --stat nach, dass die Fachlogik dafür unverändert blieb.

Tipp: In TypeScript genügt oft ein kleinerer Typ wie { title: string } statt eines ganzen Objekts. Beispieldaten sind erfunden, keine echten Namen.

Vollständig, wenn:

  • der zweite Test eine ablehnende Regel ohne Datenbank prüft und grün ist,
  • zwei Stellen mit Datei und Zeile verkleinert sind und der Gewinn benannt ist,
  • beide Konfigurationen über die Umgebungsvariable laufen und die Fachlogik nachweislich unverändert ist.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Ordne drei Stellen eures Projekts (oder des verwendeten Frameworks) ein: Ist es DIP, Dependency Injection, beides, keines, oder arbeitet ein IoC-Container? Begründe jede Einordnung in einem Satz mit den zwei getrennten Fragen: Wird die Abhängigkeit hereingereicht, und ist das Hereingereichte eine Abstraktion?
  • Erkläre im Design-Review in drei bis fünf Sätzen, wie die fünf SOLID-Prinzipien in euren Umbauten aus Aufgabe 08 und 09 zusammengewirkt haben: Welche Entscheidung hat welche andere erst möglich gemacht?
  • Beurteile in drei Sätzen, ob euer Projekt einen IoC-Container bräuchte oder die Verdrahtung von Hand reicht, und nenne den Auslöser, bei dem du deine Meinung änderst.

Tipp: Kapitel 14 beschreibt die Kette SRP → OCP, LSP → OCP, ISP → DIP und DIP als Klammer. Belege jeden Zusammenhang mit einer Stelle aus eurem Code.

Vollständig, wenn:

  • die drei Stellen mit beiden Fragen richtig eingeordnet sind,
  • die Erklärung mindestens drei Zusammenhänge zwischen Prinzipien an Stellen des eigenen Codes belegt,
  • die Beurteilung des Containers ein Kriterium und einen Auslöser für einen Meinungswechsel nennt.

Wie unter Allgemein.

Durchschnittlich bis Wesentlich_vollständig: ca. 70 min (5 min Board-Check, 10 min Kata, 25 min Review und Retrospektive, 30 min Release und Repository-Umbau)

GAM

CC-BY-SA

https://qiz.at/rules