Child pages
  • AD


Application Design (AD)

AD ist eine Veranstaltung im 2. Semester Code & Context. Diese Seite (mit den entsprechenden Unterseiten) wird fortlaufend aktualisiert. Es wäre also sinnvoll, wenn Sie die Seite bookmarken

Application Design - Aktuelles

Die Veranstaltung beginnt am Mo 31.05. um 10:00. Sie findet virtuell in Zoom statt. Hier sind die Einwahldaten: 

Bitte treten Sie folgendem ILIAS-Kurs bei: https://ilias.th-koeln.de/ilias.php?ref_id=1923299&cmdClass=ilobjcoursegui&cmd=edit&cmdNode=w9:l5&baseClass=ilRepositoryGUI.

Inhalte dieser Seite

Ziel der Veranstaltung

Die Veranstaltung AD versucht Sie mit grundlegenden Überlegungen beim Design und der Implementierung von komplexen Softwaresystemen vertraut zu machen. Dabei lege ich Wert darauf, das theoretische Wissen auch praktisch umzusetzen. Folgendes Learning Outcome liegt der Veranstaltung zugrunde - das sollten Sie am Ende können, wenn Sie für sich das Beste aus der Veranstaltung herausholen.

Als

SW-Entwickler*in oder SW-Architekt*in

kann ichein Softwaresystem für eine gegebene Aufgabenstellung iterativ konzipieren und mit gängigen Tools implementieren,
indem ich
  1. passende Prinzipien, Patterns und Architekturstile für mein IT-System auswähle, wie etwa die SOLID-Prinzipien und eine Schichtenarchitektur,
  2. ein Domain Model nach dem Ansatz des Domain-Driven-Design (DDD) in Building Blocks konzipiere und mit Hilfe von Spring JPA umsetze, 
  3. meine Domäne(n) in Aggregates strukturiere
  4. diese Aggregates als REST Level 2 API für die Kommunikation mit Umsystemen und Clients verfügbar mache, und dies mit Spring Web MVC umsetze
so dass ich

eine nachhaltig wartbare Software mit passender, langlebige und änderungsfähiger Architektur erstellt habe.

Organisation der Veranstaltung

AD ist eine Blockveranstaltung in Code & Context in der Zeit von 31.05. bis 11.06.2021. Dabei werde ich folgende Struktur anwenden.

  • Die Tage sind als Workshop angelegt und gehen von 10:00 bis 16:00, mit einer Mittagspause, die wir je nach Tages-Agenda aushandeln. 
  • Die Workshops bestehen aus Inhaltsimpulsen, selbstständigen praktischen (Programmier- und Modellier-)Übungen und Gruppenreflektionen. 
    • Die Inhalte der Veranstaltung sind parallel auch als Lehrvideos anzuschauen (siehe Zeitplan mit Inhalten unten, dort sind die Videos direkt verlinkt). Darüber hinaus gibt es auch ein begleitendes Script zu den Videos. 
    • Eine begleitende Programmieraufgabe wird in Form von zwei Gitlab-Repos zur Verfügung gestellt. 
  • Ein Feedback ist auch außerhalb der Workshop-Zeiten möglich, bevorzugt über Discord (siehe unten). 
  • Der Mittwoch ist als Selbstlern-Tag konzipiert. 

Team

Das sind die Lehrenden für AD:

  • Ansprechpartner für Feedback zur Veranstaltung, weitergehende Fragen / Anregungen / Wünsche, Rückfragen zu Vorlesungsinhalten
  • Erreichbar am besten Discord, wenn es um Fragen von allgemeinem Interesse geht
    • bei persönlichen Anliegen am besten per Email (antwortet in der Regel innerhalb eines Tages, sonst bitte nochmal nachfragen)
  • für weitergehende persönliche Anliegen am besten eine Sprechstunde buchen: https://calendly.com/bente/termine (aber bitte probieren Sie erstmal, ob es auch via Discord oder Mail zu klären ist)
  • Ansprechpartner für technische Problem mit Gitlab oder der sonstigen Infrastruktur, sowie in Fragen der Programmierung
  • erreichbar am besten über den Discord-Server, ersatzweise per Email
  • Sie dürfen gerne außerhalb "üblicher" Zeiten Fragen stellen, eine Antwort dauert dann unter Umständen nur etwas länger.

Beratung vorzugsweise via Discord

Als sehr effektive Plattform zur Beratung und Diskussion hat sich bei uns Discord herausgestellt. Sie können daher dem ArchiLab-Discord-Server beitreten: https://discord.gg/YYNYb5whU8. Wählen Sie dann "COCO" als Rolle, und Sie sehen die Channels für diese Veranstaltung. 

Wer Discord nicht nutzen will, kann mich auch direkt per Mail kontaktieren. 

Für die Workshops nutzen wir immer denselben Zoom-Link: 

Videos und Script

Die Inhalte der Veranstaltung werde ich in Form von kurzen Impulsen in die Workshops einbetten. Ergänzend können Sie die wichtigsten Inhalte als Lehr-Videos vor- oder nacharbeiten, wenn Sie möchten. (AD ist so konzipiert, dass Sie auch ohne Videos folgen können - dafür haben wir ja das Workshop-Format. Aber vielleicht hilft es, manche Inhalte noch einmal in anderer Form anschauen zu können.)

Die Videos zur Vorlesung finden Sie auf dem ArchiLab-Youtube-Kanal: https://www.youtube.com/channel/UC29euiLjp5m-hPoU3QP3nGA/. Nicht alle Videos sind für diese Veranstaltung relevant. Die hier interessanten Videos habe ich in der "Zeitplan und Inhalt"-Tabelle unten verlinkt.  

Zu diesen ausgewählten Videos ist auch ein Script verfügbar. Das wird laufend ergänzt. Sie finden es in ILIAS: https://ilias.th-koeln.de/goto.php?target=file_1930651_download&client_id=ILIAS_FH_Koeln

Programmieraufgaben

Diese Veranstaltung enthält eine begleitende Programmieraufgabe - d.h. Sie wenden den Stoff der Veranstaltung direkt anhand Ihres eigenes Codes an. Jede/r von Ihnen bekommt eine individuelle Aufgabenstellung. Sie werden leicht feststellen, dass allen Individualisierungen dieselbe Basis-Aufgabenstellung zugrunde liegt. Aber jede/r muss eine individuelle Lösung abgeben.

Einfach "Copy/Paste" (falls jemand in Versuchung gerät ...) funktioniert also nicht. Darüber hinaus sind ein paar versteckte Copy/Paste-Indikatoren eingebaut. Offensichtlich kopierte Lösungen werte ich wie eine nicht erfolgte Abgabe. 

Zu den technischen Randbedingungen gibt's ein eigenes Kapitel weiter unten hier auf der Seite. 

Bewertung

Die Note wird sich aus den folgenden beiden Bestandteilen zusammensetzen: 

  • Funktionalität ("Tests E1 grün") - 50%
  • REST API Spezifikation ("Tests E2 grün") - 5%
  • REST API Implementierung ("Tests E3 grün") - 10%
  • Code Quality - ("Video zu SOLID Anwendung und Eindrücke aus dem Code") - 35%


max. PunkteAspektPunkteKriterien
30Funktionalität korrekt umgesetzt6E1ParsingTests grün (3)


6E1ValidationTests grün (3)


18E1HiddenTests, E1MovementTests grün (9)




70Qualitätsaspekte10allgemeine Clean-Code-Regeln im Code angewendet 


10Domänenklassen (Entities) und Package-Struktur sinnvoll gewählt (Single Responsibility Principle)


10Sinnvolle Domain Primitives mit Validierung


10Business Logic ist in den richtigen Entities / VOs (und nicht in Serviceklassen)


20Algorithmische Umsetzung (vollständige, originelle, kompakte, verständliche Lösung)


10Zykel sinnvoll vermieden (...)




21Bonus21

E3RestTests grün (7)

Noten: Minimum 40 Punkte für eine 4,0, ab 90 Punkte 1,0

Zeitplan und Inhalt

Stand heute werden wir folgendem Zeitplan für die zwei Wochen folgen: 


     DatumThemaInhalt (Details)Unterstützende Videos
1Mo, 31.05., 10:00 - 16:00

0) Einführung, Orga, Praktikum

1) Modelle

Vormittag

  • Ziele der Veranstaltung, Zeitplan, Learning Outcome, Bewertung
  • Programmieraufgabe für diese Veranstaltung
  • Domain Model (fachliches Datenmodell)

Nachmittag

  • abschließende Reflektion: Erarbeitung der Domain Models, erste Schritte beim Programmieren
  • Entities und Value Objects
2Di, 01.06., 10:00 - 16:002) Persistenz mit JPA

Vormittag

  • Domain Primitives
  • Persistierung mit Spring Data JPA

Nachmittag

  • Abbildung von Beziehungen in JPA
3Mi, 02.06.Selbstlernzeit
4Do, 03.06.Fronleichnam (Feiertag)
5Fr, 04.06., 10:00 - 12:303) Domain-Driven Design und SOLID

Vormittag

  • Grundlagen DDD
  • SOLID Principles
  • abschließende Reflektion: Hindernisse bei der Umsetzung

Nachmittag: Community & Reflection

6Mo, 07.06., 10:00 - 16:004) Aggregates und REST

Vormittag

  • Aggregates
  • REST-Prinzipien

Nachmittag

  • Nach dem Mittag:
  • abschließende Reflektion
  • Was sind Aggregates
  • Regeln für Aggregates
  • Aggregates mit Spring JPA
  • HTTP-Grundlagen und -Tools
  • Prinzipien von REST
7Di, 08.06., 10:00 - 16:00

Vormittag

  • REST Maturity Levels 0 - 2
  • Guter Stil bei REST
  • Coding REST

Nachmittag

  • Postman als Testing-/Dev-Tool
  • Umsetzung in Spring Web MVC
8Mi 09.06.Selbstlernzeit
9Do, 10.06., 10:00 - 16:00Offene Fragen

Vormittag

  • Diskussion offener Fragen

Nachmittag

  • abschließende Reflektion

10Fr, 11.06., 10:00 - 16:00

Vormittag

  • Überblick offene Fragen
  • Ausblick auf Microservice Architecture

Nachmittag

  • abschließende Reflektion

Programmieraufgaben

Die Programmieraufgabe finden Sie unter https://git.st.archi-lab.io/students/coco/ss21/ad

Dort finden Sie am Montag Ihr persönliches Repo. Dafür ist es unbedingt nötig, dass Sie sich vorab einmal mit Ihrer CampusID dort anmelden. 

Die Aufgaben sind für Sie persönlich individualisiert. Lösungen können also nicht einfach zwischen den Aufgabenstellungen ausgetauscht werden. 

Um die Aufgaben erfolgreich bearbeiten zu können, müssen Sie sich Ihr eigenes Repository lokal clonen (mit Git). Achtung: Um die Funktionalität des Projekts zu gewährleisten, dürfen Sie nichts, was außerhalb des Ordners "src/main" liegt, verändern (insbesondere nichts zur pom.xml hinzufügen). 

Zusätzliche Informationen zu Git und Java

Hier finden Sie noch zusätzliche Infos: 

Persönliche Feedbackseite

Für jede/n Student*in wird eine persönliche Testseite generiert. Diese listet sämtliche Tests des Übungsprojektes auf und wird bei jeder Codeänderung aktualisiert (dauert teils mehrere Minuten). Anhand der Testseite ist erkennbar, welche Tests durchlaufen (grün sind). Der Link zur Testseite hängt von dem jeweiligen Repository-Namen ab. Hier eine schrittweise Anleitung, wie man zur jeweiligen eigenen Testseite kommt.

  • (1) Als erstes ist es wichtig, die UUID des Projekts herauszufinden. Dazu schauen wir uns den Namen des Projekts an und kopieren die UUID aus dem Ende des Namens. Im folgenden Screenshot ist die UUID rot markiert:

Tools

SSH

Wer im Gitlab kein Passwort hinterlassen möchte, um auf das remote Repository zu pushen kann sich auch einen ssh key generieren und diesen in gitlab eintragen. Eine Anleitung hierzu findet man hier: https://docs.gitlab.com/ee/ssh/. Da sich durch Nutzung von SSH unter anderem das Protokoll ändert, muss man beim Clonen eines Repositories den Link anpassen. Normalerweise würde man ein Repository mit folgendem Befehl klonen:

git clone https://git.st.archi-lab.io/students/coco/ss21/ad/tests/basics_tests_group_<uuid>

Durch Nutzung von SSH würde sich dieser Befehl zu folgendem ändern:

git clone ssh://git@git.st.archi-lab.io:22996/coco/ss21/ad/tests/basics_tests_group_<uuid>.git

Git Config mit multiplen Identitäten

Wer mehrere Git Servern parallel arbeiten will (z.B. CoCo vs. ArchiLab), der kann eine Git Config mit multiplen Identitäten nutzen. Hier sind zwei Anleitungslinks (danke an S.A. für den Hinweis): 

Java Development

Für die Java-Entwicklung brauchen Sie zwei Arten von Tools: 

  • Git: am besten die Git Bash
  • IDE: hier bieten sich zwei Optionen an: 
    • IntelliJ Ultimate (frei für Studierende)
    • Visual Studio Code

Eindrücke aus den Repos

Mo, 07.06.

Stand der Repos

  • 1x fast komplett grün
  • 1x sind 2-3 Tests grün
  • Rest komplett rot - teilweise noch gar nicht gepusht.

Bitte machen Sie das regelmäßig!

Sie haben dann auch Ihre persönliche Testseite: http://students.pages.st.archi-lab.io/coco/ss21/ad/tests/ad_tests_group_<UUID>/

Entities haben IDs als Referenz, nicht Entities

@Entity
@NoArgsConstructor
@Getter
public class Connection {
@Id
private final UUID id = UUID.randomUUID();
private UUID transportTechnologyId;
private UUID sourceFieldId;
private String sourcePointString;
private UUID destinationFieldId;
private String destinationPointString;


public Connection(UUID transportTechnologyId, UUID sourceFieldId, String sourcePointString, UUID destinationFieldId, String destinationPointString) {
this.transportTechnologyId = transportTechnologyId;
this.sourceFieldId = sourceFieldId;
this.sourcePointString = sourcePointString;
this.destinationFieldId = destinationFieldId;
this.destinationPointString = destinationPointString;
}
...

besser: Entities als Referenz mit OneToOne, OneToMany, ManyToOne, ManyToMany Annotationen

Packages am besten fachlich zusammenfassen

Packages wie "repositories" oder "validation" sind eher eine technische Sicht. Besser wäre es, alles fachlich zusammengehörige auch in ein Package zu tun. 

Eingabefehler kann man sehr gut beim Parsen in den Domain Primitives abfangen

In Ihrem Fall bieten sich RuntimeExceptions an, weil die in den Service-Methoden nicht mehr deklariert werden müssen (die dürfen Sie ja nicht ändern). Dann brauchen Sie aber auch kein Wrapping von Exceptions zu machen, so wie hier: 

public UUID addField(Integer height, Integer width) {
try {
Field field = Field.initializeFromDimensions(height, width);
fieldRepository.save(field);
return field.getId();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid Field Dimensions");
}
}

Domain Primitives sollten alle zugehörigen Daten beinhalten

Das Move-Kommando z.B. besteht aus Richtung und Anzahl Schritte. Wenn man den Test auf negative Schritte woanders hin packt (siehe Beispiel), dann verteilt man Funktionalität über die Codebasis. 

(Robot-Klasse)
public void
move(Command command, Integer steps) {
if (steps < 0) {
throw new MaintenanceDroidException("Negative steps aren't allowed");
}
for (int i = 0; i < steps; i++) {
this.move(command);
}
}

Hinweis auf Text Adventure Beispiel Repo

Das Textadventure-Beispiel (siehe https://www.archi-lab.io/pages/viewpage.action?pageId=55607329) gibt es jetzt auch auf JPA umgeschrieben. Sie können das Repo von https://git.st.archi-lab.io/students/st2/ss21/exercises/textadventure-jpa.git clonen.

Da sind eine Menge Fragestellungen drin, die auch hier relevant sind.

(Disclaimer: Ich habe noch ein paar Bugs mit der Persistenz drin - ich nutze ein filebasiertes H2, damit das Game persistierbar wird. So 100% sauber funktioniert das noch nicht. Aber ich wollte Ihnen den Code schon mal zugänglich machen.)

Di, 08.06.

Stand der Tests

Heute Morgen mal mit Strichliste durchgezählt:

  • 1x Alles überwiegend oder komplett grün
  • 0x E1 komplett grün
  • 0x E1 überwiegend grün
  • 4x E1 teilweise grün
  • 14x alles rot
  • 12x nicht erkennbar bearbeitet (noch gar nicht gepusht?)

Kernfragen, die Sie _vor_ der Beschäftigung mit Spring klären sollten

(schon mündlich am Mo Nachmittag kommuniziert, hier nochmal zum Nachlesen ...). Folgende beiden Fragen sollten Sie für sich klar haben, vielleicht auf einem Blatt Papier klären: 

  1. Ihr Robot steht auf Zelle (3,4) und soll zwei Schritte nach rechts (Osten) laufen. Wie genau  ermitteln Sie, ob er dahin kann?
    1. Keine Wände im Weg?
    2. Kein anderer Robot auf der Zielzelle?
  2. Ihr Robot soll ein [tr,<UUID>] Kommando ausführen. Wie genau  ermitteln Sie, ob das geht?
    1. Gibts die Connection?
    2. Wenn ja, wie ist Zielzelle?
    3. Ist die besetzt, oder kann der Robot da hin?

Verschiedene falsche Kombinationen Entity / Repo

  • public interface SpaceRepository extends CrudRepository<SpaceRepository, UUID> {}
    • (Repo- statt Entityname in CrudRepository<EntityType, ID-Type>
  • Entity ohne ID
  • Repo für eine Entity, die aber als "Embeddable" getaggt ist
  • Repo ohne Angabe des Entities und des ID-Typs: 
    public interface ConnectionRepository extends CrudRepository {
  • ...

Test-Feedback kann man sinnvoll nutzen

Beispiel: 

  • Letzte sichtbare Zeile: "Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0"
  • Oder in einem anderen Fall (nicht im Bild gezeigt): 
    Caused by: java.lang.IllegalArgumentException: The given domain class does not contain an id attribute!

Zirkuläre Abhängigkeiten

Beispiel: Cell kennt Robot, Robot referenziert Cell

public class Cell {
@OneToOne
private TidyUpRobot tidyUpRobot;
...
public class TidyUpRobot {
@OneToOne
private Cell cell;
  • Zum einen funktioniert das technisch so nicht (eine der beiden Seiten muss "ownen", die andere muss ein ( mappedBy "<memberName>" )  angeben => einfach mal googlen). 
  • Zum anderen (wichtiger): Bidirektionale Beziehungen sollte man vermeiden, weil sie die beiden Klassen fest zusammenbinden. Sie können z.B. in einem REST API nicht mehr ohne besondere Kniffe nur eins von beiden nach außen geben - das andere kommt immer  mit!

Connection "wörtlich" aus dem gegebenen API übernommen (mit UUIDs statt Entity-Bezügen)

War am Montag schon mal da, hier nochmal: 

public class Connection {
@Id
private final UUID id = UUID.randomUUID();

private UUID transportCategory;

//Source
private UUID sourceSpaceId;
private String sourcePointString;

//Destination
private UUID destinationSpaceId;
private String destinationPointString;
}

Bitte keine "kleingeschriebenen" Basistypen als Members

int, float, double etc. können keine NULL-Werte abbilden, die in Datenbanken oft vorkommen. Daher sollten bei Entities und Value Objects immer großgeschriebene Typen verwendet werden (Integer, Float, ...). Die kennen nämlich ein "null". 


@Getter
@Setter
private int height = 5;

@Getter
@Setter
private int width = 6;

Wenn man das nicht macht, bekommt man Hibernate-Exceptions. 

Wenn man in Domain Primitives einen String parsed, dann sollte man auch eine Exception bei Fehlern werfen

Folgende (sehr gute!) Parsing-Methode in einer Klasse "Barrier":

public Barrier barrierFromBarrierString(String barrierString) {
// (Details des Parsings, aber keine Fehlerbehandlung ...)
return this;
}

Nested Embeddables

Ich bin gefragt worden, ob man Value Objects schachteln kann (Embeddable innerhalb Embeddable). Ich habe das nicht präzise beantwortet. 

  • Embedded in Embeddable geht  (also eine "zu-1" Beziehung)
  • ElementCollection in Embeddable geht nicht 


Do, 10.06., mittags

Stand der Tests

 mit Strichliste durchgezählt:

  • 1x Alles überwiegend oder komplett grün
  • 1x E1 komplett grün
  • 2x E1 überwiegend grün
  • 7x E1 teilweise grün
  • 17x alles rot
  • 6x nicht erkennbar bearbeitet (noch gar nicht gepusht?)

Fr, 11.06.

  • 10:00
    • Ausblick auf Microservice Architecture
    • Aktueller Stand: Was ist mir aufgefallen? 
  • 15:00 - Abschluss
    • Retro - keep, drop, try


Eindrücke aus fünf zufällig gezogenen Repos

KriterienBeobachtungen
allgemeine Clean-Code-Regeln im Code angewendet 
  • Groß- / Kleinschreibung (Konstruktor groß, Methoden klein)
  • Methodenlänge meist gut
Domänenklassen (Entities) und Package-Struktur sinnvoll gewählt (Single Responsibility Principle)
  • Package-Struktur passt meistens, manchmal etwas feingranular
    • Wo kommen "Hilfsklassen" hin? (Parser, Translator, ...)
    • wenn, dann bitte nahe bei den fachlichen Klassen, die das nutzen
Sinnvolle Domain Primitives mit Validierung
  • nicht immer ganz konsequent durchgehalten
    • es macht wenig Sinn, im Programm mit Command- oder Wall-Strings, UUIDs oder einzelnen x-/y-Werten zu arbeiten
Business Logic ist in den richtigen Entities / VOs (und nicht in Serviceklassen)
  • meist gut - im Wesentlichen nur Lifecycle-Operationen
Algorithmische Umsetzung (vollständige, originelle, kompakte, verständliche Lösung)
  • nicht wirklich zu erkennen, noch zu sehr in der Entwicklung
Zykel sinnvoll vermieden (...)
  • nicht wirklich zu erkennen, noch zu sehr in der Entwicklung