TU Wien:Software Engineering und Projektmanagement PR (Biffl)

Aus VoWi
Zur Navigation springen Zur Suche springen
Ähnlich benannte LVAs (Materialien):

Daten[Bearbeiten | Quelltext bearbeiten]

Vortragende Stefan BifflPeter FrühwirtKristof MeixnerFelix Paul RinkerDietmar Winkler
ECTS 6
Alias Software Engineering and Projectmanagement (en)
Letzte Abhaltung 2023S
Sprache Deutsch
Abkürzung SEPM
Mattermost software-engineering-und-projektmanagementRegisterMattermost-Infos
Links tiss:188909 , Homepage
Zuordnungen
Bachelorstudium Wirtschaftsinformatik
Bachelorstudium Medieninformatik und Visual Computing
Bachelorstudium Medizinische Informatik
Bachelorstudium Software & Information Engineering


Inhalt[Bearbeiten | Quelltext bearbeiten]

Üben von Software Engineerung und Projektmanagement anhand eines kleinen Projektes in der Gruppe.

Ablauf[Bearbeiten | Quelltext bearbeiten]

Die LVA besteht aus 1) der Eingangsphase 2) der Gruppenphase. Die Eingangsphase wird vom INSO und QSE gemeinsam abgehalten. Für die Gruppenphase könnt ihr eine Institutspräferenz abgeben, letztendlich werden die Gruppen aber entsprechend auf die Institute aufgeteilt.

Eingangsphase[Bearbeiten | Quelltext bearbeiten]

Die Eingangsphase (dessen positiver Abschluss Voraussetzung für die Gruppenphase ist) absolvierst du alleine und besteht aus

  • Einstiegstest zu UML und Architekturdesign (proforma Anmeldung, nach dem Test wird auf jeden Fall ein Zeugnis ausgestellt)
  • Diversen Tutorials (ohne Anwesenheitspflicht aber sehr zu empfehlen!)
  • Einzelbeispiel
    • Eigenständig ein kleines Verwaltungs-Programm in Java und mit Hilfe von HSQLDB implementieren.
    • Unit Tests
    • Dokumentation (Beschreibung mit Klassendiagrammen und Use-Case-Diagrammen)

Folgendes gibt es s2022 (und davor seit?) nicht mehr:

  • Abgabegespräch
    • Live Test (40 Minuten Zeit um kleine Programmieraufgaben zu lösen)
    • Abgabegespräch (Ein_e Tutor_in schaut sich deine Dokumentation und deine Lösung für das Einzelbeispiel an)

Die Einzelphase wird an sich auch mit Punkten benotet, ob diese Punkte dann wirklich in die Benotung einfließen ist von Institut und Auftraggeber abhängig, in meinem Fall hat sich bei der Endbenotung niemand mehr für die damaligen Punkte interessiert. Genaueres siehe #Prüfung

Dauer der Punkteausstellung für die Einzelphase[Bearbeiten | Quelltext bearbeiten]

Nach der Deadline für die Einzelphase braucht es ein paar Tage bis man weiß, wie viele Punkte man in der Einzelphase bekommt und dementsprechend auch ob man zur Gruppenphase zugelassen ist.

Semester Deadline bekanntgabe erreichter Punkte Ende Gruppenanmeldung
2023S 28.03.2023 02.04.2023 04.04.2023

Gruppenphase (QSE)[Bearbeiten | Quelltext bearbeiten]

Für eine Beschreibung der Gruppenphase am INSO siehe TU Wien:Software Engineering und Projektmanagement PR (Grechenig)

In der Gruppenphase arbeiten 5-6 Personen in einem Team an einem Projekt. Die Teamzusammenstellung ist grundsätzlich frei wählbar, seid ihr allerdings weniger als 5, werden Gruppen zusammengelegt oder leere Plätze aufgefüllt. Auch das Projekt ist generell frei wählbar, wenn das Institut euren Projektvorschlag annimmt. Grundsätzlich nicht angenommen werden Spiele, Web-Applikationen oder verteilte Systeme. Als alternative gibt es das vom Institut vorgeschlagene Projekt "Fotoverwaltung".

Während der gesamten Gruppenphase steht euch ein zugeteilter Tutor (je nach Wunsch) mehr oder weniger intensiv und hilfreich zur Seite.

Vorgaben[Bearbeiten | Quelltext bearbeiten]

Am QSE gibt es einige Vorgaben bezüglich der Technologien. Zu verwenden sind:

  • Gitlab:
    • git-Repository
    • Tickets
    • Zeit buchen
  • Java 11
  • Spring (Dependency Injection)
  • Maven
  • H2
  • Angular

Post-S19: Wir mussten (!) Hibernate verwenden beim QSE, das könnte aber auch von Semester zu Semester unterschiedlich sein...

Pre-S19: Nicht erlaubt sind OR-Mapper jeglicher Art (Hibernate, JPA, ...). Datenbankanbindung muss also komplett selbst implementiert werden.

Projektablauf[Bearbeiten | Quelltext bearbeiten]

  • Projektvorschlag und -auftragsphase (Ihr schreibt einen Projektvorschlag der angenommen oder abgelehnt wird, und auf Basis dessen einen Projektauftrag)
  • Wöchentliche Jour fixe Termine mit eurer Tutorin/eurem Tutor
  • Zu drei Management Review Terminen, präsentiert ihr dem euch zugewiesenen Univ. Assistent_innen euer Produkt, beim letzten Termin werdet ihr auch benotet.

Wer denkt, dabei wird nur programmiert, liegt falsch, mit Dokumentation wird die meiste Zeit verbracht. Das Projekt durchläuft die klassischen Phasen des Sofwaredesigns: Analyse, Entwurf und Implementation. Testen und Qualitätssicherung sollten zu diesen Phasen parallel laufen (etwa mit Test-Driven Development). Während die klassischen Phasen der Softwareentwicklung aufgrund der Rahmenbedingungen der LU durchlaufen werden, wird versucht agile Methoden wie SCRUM einzusetzen. Das bedeutet wiederum das während der Implementierung, Use-Cases und nicht Komponenten an die Gruppenmitglieder verteilt werden. Jedes Gruppenmitglied programmiert also einen Use Case bzw. ein "Feature" statt eine Komponente wie z.B. "Datenbank" oder "GUI".

Dabei übernehmen die Gruppenmitglieder spezielle Rollen. Es gibt eine_n Teamkoordinator_in, eine_n Systemarchitekt_in, eine_n Dokumentationsverantwortliche_n, eine_n Testverantwortliche_n und eventuell deren Stellvertreter_in. Jede dieser Rollen ist mit sog. horizontalen und vertikalen Verantwortlichkeiten behaftet. Normalerweise denkt jede_r gleich an die Horizontalen Verantwortlichkeiten. Z.B. Als Team-Koordinator_in(TK) hat man die Aufgabe über den Projektstatus bescheid zu wissen, also zu wissen "wie weit" die Gruppe ist. Woher weiß man aber wie weit die Arbeit im Team fortgeschritten ist? Die anderen Gruppenmitglieder haben nämlich in ihrer vertikalen Rolle die Aufgabe Stundenlisten und andere Projektmanagement Artefakte zu führen, welche die horizontale Rolle des TK's erst ermöglichen. Der TK kann also z.B. aufgrund der Stundenlisten von anderen Gruppenmitgliedern beurteilen "wie weit" die Gruppe ist.

Sommersemester 2008: Die in der Gruppe einzunehmenden Rollen waren Projektleitung, Technische Architektur, Infrastruktur, GUI Design, Dokumentation und Testen. Allerdings wurde mehrmals betont und Wert darauf gelegt, dass jeder alles machen muss. Die Arbeit wurde also auf komponentenbasis aufgeteilt und jeder musste seine Komponente selbst designen, programmieren, dokumentieren und testen. Die Gruppenarbeit ist weit aus anspruchsvoller als das Einzelbeispiel, daher rächt es sich, wenn man sich beim Einzelbeispiel versucht durchzuschummeln. Design Pattern - Prüfungen gab es keine. Es hilft aber sehr, sich über das DAO-Pattern (Data Access Object) im Klaren zu sein. Dieses war der Schwerpunkt der diessemestrigen Projektarbeit.

Architectural Review[Bearbeiten | Quelltext bearbeiten]

Gegen Ende wird ein Gruppenmitglied zu einem Gespräch eingeladen, bei dem der Code durchgegangen wird. Dazu muss der oder die Eingeladene einen guten Überblick über die Architektur haben.

SS 2011: Es gab keine Prüfungen während des Semsters und auch nur ein Treffen (Tester). In der letzten Semsterwoche gab es ein Abgabegespräch über das gesamte Projekt, zu dem eine Person pro Gruppe 48h zuvor zufällig(?) ausgewählt wurde. Das sorgte für Stress und Diskussionen, war aber halb so schlimm.

SS 2015: Die Person, die zum Architectural Review erscheinen muss, wird nicht mehr zufällig ausgewählt, sondern von der Gruppe bestimmt.

Benötigte/Empfehlenswerte Vorkenntnisse[Bearbeiten | Quelltext bearbeiten]

Benötigt: Grundlagen der Programmkonstruktion VU, Datenmodellierung VU, sehr empfehlenswert: Objektorientierte Modellierung VU, Objektorientierte Programmiertechniken VU

Wer hier noch keine Kenntnisse über User-Interfaces und Programmdatenbankzugriffe besitzt (was im Allgemeinen die Regel ist, wenn man keine dementsprechende LVA im Studienplan hat und privat nicht allzuviel programmiert) sollte sich allerspätestens in den zwei Wochen, die man für die Solorunde hat, darin einarbeiten.

Des weiteren würde ich dringend empfehlen sich mit Java-GUI Gestaltung mit Swing (ohne GUI-Editor) und mit JUnit zu befassen, da das Einzelbeispiel beides voraussetzt und wenn man sich erst einarbeiten muss in die Technologien wird die Zeit schon sehr knapp. Außerdem sollte man die Vorlesung Datenbanksysteme VU absolviert haben, damit man ein ungefähres Verständnis von JDBC vorweisen kann.

Vortrag[Bearbeiten | Quelltext bearbeiten]

Keiner, die gleichnamige VO ist zum Verständnis und Absolvieren der LU auf gar keinen Fall notwendig, der Einführungsvortrag zu den verwendeten Technologien ist aber auf jeden Fall zu empfehlen!

Prüfung[Bearbeiten | Quelltext bearbeiten]

Eine Person vom Institut die während des Projekts die_den "Auftraggeber_in" spielt ist für die Benotung eigentlich zuständig, oft wird aber in Übereinkunft mit der_dem Tutor_in und/oder der Gruppe benotet. Je nach Auftraggeber_in werden Gruppennoten oder verschiedene Noten für jedes einzelne Gruppenmitglied verteilt. Im Allgemeinen ist die Benotung sehr mild, die größte Hürde der LV liegt darin, die Einzelphase zu überstehen.

Zusatz [aus Tutorensicht]: Der letzte Satz stimmt, solange man sich an die Vorgaben der Tutorin/des Tutors und der Assistentin/s Assistenten hält und eine Software ablieftert, die halbwegs mit den anfänglichen Anforderungen übereinstimmt. Es ist keine Seltenheit, dass einzelne Gruppenmitglieder negativ beurteilt werden, auch dass ganze Gruppen negativ abschließen bzw. abbrechen (weil klar ist, dass sie es nicht schaffen werden) kommt 1-2-mal pro Semester vor. (üblicherweise hat SEPM 15-20 (SS) bzw. 25-30 (WS) Gruppen pro Institut).

Zusatz (WS 2010/11): Am INSO ist der Aufwand nicht sehr hoch. Die größte Hürde ist wirklich die Einzelphase. Ich habe ein Gut (U2) bekommen, mit höchstens 8 Stunden Aufwand pro Woche. Ich würde auf jeden Fall das INSO empfehlen, weil hier schon ein Grundgerüst (TLCore) vorhanden ist und man nur einzelne UseCases implementieren muss. Man kann sich also wirklich auf das Projektmamagement und das Implementieren konzentrieren.

Zusatz [aus Tutorensicht]: Der Aufwand ist auch am QSE nicht höher, der reale Unterschied liegt bei den verwendeten Technologien und der Vorgabe des Projekts. [QSE: Entweder eigene Idee oder MP3-Player; Inso: Ticketline]

Weiter Meinung(SS 2011): INSO war sehr angenehm. QSE kann ich nicht beurteilen. Man hört aber leider gar nichts positives. Ein Freund von mit hats am QSE gemacht. Seine Worte: "Wenn man eine Herausforderung braucht, dann machs beim QSE". Am INSO hab ich 120 Stunden investiert. Ein großzügiger TL Core ist vorgegeben. Beim QSE muss man alles von Grund auf programmieren. Ein anderer Bekannter war am QSE schon fertig mit seiner Arbeit, die dann sehr gelobt wurde. Doch sie konnten ihm am Ende kein Zeugnis ausstellen, weil sie ein falsches Framework verwendet haben(früh bemerkt...). Sie haben dann im Sommer programmieren müssen.

Weiter Meinung II (SS 2011): Hab die Übung am QSE gemacht (unsere Gruppe wurde entgegen unserer Präferenz dem QSE zugeteilt) und wurde nach dem anfänglichem Schock positiv überrascht. Ich habe wirklich viel gelernt, sowohl Tutorin als auch Assistent waren sehr angenehm und die Note passt auch. Allerdings waren es pro Person schon ca. 200 Stunden, die in die Übung reingesteckt wurden. Das mit dem falschen Framework kann ich fast nicht glauben, da bei uns betont wurde, dass es auf die Technologien und nicht auf spezifische Frameworks ankommt.

Meinung (SS 2015): Übung am QSE bei Prof. Biffl, Arbeitsaufwand war exorbitant über den 6 ECTS, Betreuungsverhältnis eher mau (trotz wöchtenlicher Treffen mit dem Tutor, der sich aber eher weniger für das ganze zu Interessieren schien), Prof. Biffl wirkte recht herablassend und schob auch den einen oder anderen sexistischen Kommentar gegenüber unseren weiblichen Teammitgliedern. INSO wäre wohl besser gewesen. EDIT von jemanden der INSO gemacht hat: War genau der selbe Scheiss (minus vielleicht der sexistischen Kommentare, hab aber weder am Institut noch in einer Gruppe dort eine Frau gesehen). Der Arbeitsaufwand ist in dem PR einfach zu hoch. Wer kein Team von Leuten hat, die das schon mal in einem professionellen Umfang gemacht haben, wird die meiste Zeit damit verbringen, irgendwelche Quirks von Java Bibliotheken zu zähmen (inklusive Bugs die außerhalb eines Stackoverflow Artikels nirgendwo dokumentiert sind), während ausschließlich Ergebnisse (also "der Projektfortschritt") bewertet werden. Nachfragen beim Tutor wurde meistens "auf die nächste Stunde" verschoben, Antworten kamen dann nie. So eine wichtige LVA, so schlampig in einen 6 ECTS Kurs gequetscht! Sollte auf 9 oder 12 ECTS und mindestens 2 verschiedene Kurse aufgeteilt werden!

Anmerkung: Beim INSO gab es im SS 2017 Betreuung durch eine Tutorin.

Literatur[Bearbeiten | Quelltext bearbeiten]

Online-Tutorials zu Maven, Spring Framework,.. sind hilfreich.

Zeitaufwand[Bearbeiten | Quelltext bearbeiten]

Hoch! Am Beginn des Projekts muss ein Zeitplan erstellt werden. Da 1 ECTS 25 Arbeitsstunden übers Semester entspricht werden bei diesem Zeitplan dann für die 6 ECTS der LV jedem Studierenden etwa 150 Arbeitsstunden zugemessen. Im Endeffekt liegt der Zeitaufwand aber doch unter den 150 Stunden pro Semester, was einem subjektiv aber noch immer weit mehr vorkommt als für andere LVs mit 4 SWS/6 ECTS!

Man sollte dafür allermindestens 5 Stunden pro Woche einplanen, Teamkoordinator und Softwarearchitekt generell noch weit mehr. Da man in dieser LVA eine Stundenliste mit seinen Arbeitsstunden führen muss, merkt man, wieviel Zeit man eigentlich reininvestiert. Aus eigener Erfahrung und aus Berichten von Kollegen reichen die investierten Stunden in das Projekt einer Person (die zu einer positiven Note führen!) von 80-100 (Mitläufer, die kaum etwas im Projekt machen) bis über 250 Stunden (beschäftigt sich das ganze Semester über mit fast nichts anderem als der Übung). Üblicherweise kann man, wenn man in einem guten Team ist, am Ende für jeden mit ca. 100-150 Stunden (eher kleines Projekt, oder große Gruppe) bis 200 Stunden (umfangreiches Projekt, kleine Gruppe) rechnen. Wie oben aber schon erwähnt, fällt üblicherweise deutlich mehr Aufwand auf Teamkoordinator und technischen Architekten, die dann auch die 200+ Stunden-Kandidaten sind.

Es ist notwendig diese Zeit aufzuteilen und mehrmals pro Woche etwas für das Projekt zu arbeiten. Insbesondere berufstätige Studenten werden hiermit vielleicht ein Problem haben. Man behindert andere Gruppenmitglieder wenn immer nur am Tag vor der Deadline die Arbeit angefangen wird (Es muss Zeit für Reviews bleiben).

SS2014: Unsere Gruppe hatte einen Gesamtaufwand von 750 Stunden für das Projekt, und ich muss dazu sagen, dass niemand wirkliche praktische Erfahrung hatte. Von denen hatte der Teamkoordinator 170, alle anderen zw 100-130 und das schwächste Glied um die 70, wenn man die Einzelphase miteinbezieht dann lagen schon alle über den geplanten 150 Stunden. Dennoch muss ich sagen, dass es sich wirklich lohnt, hier viel hineinzubuttern, man lernt in jedem Bereich dieses Projektes so viel.

SS2018: Einzelphase: Zeitaufwand ist angegeben mit:

  • Einarbeitung in die Technologien des Einzelbeispiels: 8 Stunden
  • Implementierung Einzelbeispiel: 20 Stunden

Mit 80h (unfertig) liege ich da etwas drüber, von Kolleg_innen habe ich bis jetzt Werte bis zu 110h gehört.

andere Meinung zur Einzelphase SS2018: Mit 85h hatte ich alles implementiert (Einarbeitungsdauer in die Technologien ist hierbei schon drin). Weiters muss erwähnt werden, dass bei mir eine Jahre lange Programmierabstinenz vorlag, was zu einem erhöhten Einarbeitungsbedarf führte. (~10h). Die 20h+8h sind aber natürlich ein unerreichbares Ziel. Von KollegInnen habe ich teilweise von Implementierungszeiten von bis zu 130h gehört. Fortsetzung nach Gruppenphase (26.06.2018): Für die Gruppenphase brauchte unser 6-Mann Team insgesamt 350h.

ad 2018) Die 28h sind unerreichbar. Bin ein relativ guter Programmierer und auch in Übung (war davor auch in einer HTL Zweig Informatik) und hatte einen Zeitaufwand von ~60 Stunden. Dabei war die Lösung aber keineswegs fertig, sehr schlampig und unsauber (interessiert nach dem Abgabegespräch eh niemanden mehr ;-)). Wenn ich das halbwegs vernünftig gemacht hätte, hätte ich mit mindestens 80 Stunden gerechnet. Es wurde von der LVA Leitung später auch (mündlich bei der Besprechung zur Gruppenphase) zugegeben (nachdem sich einige im TUWEL Forum beschwert haben), dass der Zeitaufwand "etwas" größer war. Dafür (zumindest am QSE) wurde die Gruppenphase etwas verkürzt. Dort hatten wir dann einen vorgeschriebenen Zeitaufwand von 80h.

SS2019: Einzelphase: Hab insgesamt knapp 48 Stunden investiert, wobei meine Vorkenntnisse schon etwas eingeschlafen aber nach etwa 10h Arbeit wieder vorhanden waren. Geplant sind laut Tutoren etwa 40h Arbeitszeit für das Einzelbeispiel. Es gab einige Unklarheiten bei der Angabe die auch teilweise fehlerhaft war (wurde entweder korrigiert oder man musste einfach im TUWEL-Forum nachlesen). Der Aufwand im allgemeinen hielt sich aber in Grenzen wenn man etwas selbst mitdenkt und nicht bei jeder Kleinigkeit ins Forum postet, beim Abgabegespräch kann man durchaus argumentieren warum man etwas so gelöst hat, wichtig ist dabei das die HTTP-Codes passen (bspw. keine 5XXer Codes zurückgeben, nur 400 oder 404 bzw. 200 oder 201). Insgesamt hab ich auf das Beispiel dann 79/80 Punkten erhalten für eigentlich überschaubaren Aufwand.

Zweite Meinung S19: Einzelphase kann ich mich anschließen. Stimmt alles soweit mit meinen Erfahrungen überein (Hatte ca. 28h und um die 65 Punkte herum). Die Gruppenphase hingegen war massiv drüber. Uns wurde gesagt, dass jeder ca 100-150h Zeit aufwenden wird für die Gruppenphase, allerdings waren wir alle im Team darüber. Mit ca. 200h pro Mitglied war der Aufwand deutlich höher als angegeben. Meine Gruppe war beim QSE und wir hatten eine eigene Projektidee, aber ich weiß nicht, ob das beim INSO wirklich anders läuft, da das TicketLine lt. unserem damaligen Tutor viel aufwendiger ist. Also man sollte sich vorher gut überlegen, ob man wirklich die Zeit für SEPM hat.

Dauer der Zeugnisausstellung[Bearbeiten | Quelltext bearbeiten]

Bei unserer Gruppe ca. 1 Monat nach der Abgabe (Wir hatten damals aber noch etwas nachzureichen)

Lösungen[Bearbeiten | Quelltext bearbeiten]

Da die Beispiele zwischen den Semestern meist recht ähnlich bleiben kann es sich schon lohnen sich Lösungen aus letzteren Semestern anzusehen.

Einzephase[Bearbeiten | Quelltext bearbeiten]

Gruppenphase[Bearbeiten | Quelltext bearbeiten]

Tipps[Bearbeiten | Quelltext bearbeiten]

LVA Allgemein[Bearbeiten | Quelltext bearbeiten]

  • Das Tutorial zum Einzelbeispiel unbedingt besuchen. Wenn möglich aufnehmen, da einem dort ein idealer Start zur Schichtenübergreifenden Implementierung vorgezeigt wird.
    • Aber es erklärt nicht alles, also ist es empfehlenswert auch online Quellen zu suchen und von dort zu lernen. Speziell der Frontend (Angular) Teil wird gänzlich neu für die meisten sein.
    • Als Anfänger (speziell Frontend..) beginnt rechtzeitig mit Angular lernen und üben.
  • Plant genug Zeit für die LVA ein, die besagten Wochenstunden reichen wie gesagt bei weitem nicht!
  • Seid nicht bescheiden beim Aufschreiben eurer Stundenliste. Ihr könnt davon ausgehen, dass andere Gruppenteilnehmer ordentlich Stunden aufschlagen werden zu der reellen Zeit, die sie verbraucht haben. Wenn ihr spart, seid ihr am Ende die Dummen, auch wenn ihr reell mehr oder genauso viel gearbeitet habt.
    • Übertreibt dabei aber nicht, es können durchaus auch die Stunden für Meetings notiert werden, aber es sollten keinesfalls falsche Sachen auf der Stundenliste stehen! Durchschnittlich sollte jeder auf 150 - 200 Stunden kommen.
    • Zum Aufzeichnen der Arbeitszeit bietet sich z.B. https://timetagger.app/app/ oder https://track.toggl.com/timer an.
  • Macht diese LVA mit Bekannten, es gibt nichts Schlimmeres, als einer unfähigen Gruppe zugeteilt zu werden oder einer, mit der man sich nicht versteht.
  • Besucht das Scrum-Tutorial, da bis zum 1. IR primär nur Agilo-Docs zu erstellen sind bzw. die Sprintplanung durchzuführen ist.
  • Unterm Semester gibt es immer wieder gezielte Tech-Vortraege und "Experten"-Treffen fuer die Gruppen, Hinschauen lohnt ! (hat mich damals vor einer undurchführbaren Projektidee bewahrt)
  • Es ist wichtig, sich jede Woche in der Gruppe zu treffen, Projekt aufteilen(Tickets in Redmine erstellen) und am meisten ist es wichtig, dass sich jeder halbwegs verantwortlich für das Projekt fühlt. Die Rollen sagen nur aus, dass sich derjenige darauf mehr fokusieren soll, aber nicht, dass wenn ich zB. ein BuildManager bin, dass ich alles so liegen lassen kann und mir es wurscht ist, was mit der Projekt passiert. Des Weiteren empfehle ich frühe Deadlines zu setzen und nicht einen Tag vor'm Meilenstein fertig zu werden. Erspart viel Stress und man lernt auch, nicht alles auf den letzten Drucker zu erledigen, hat nur Nachteile.
  • Bei uns musste jedes Teammitglied mindestens einen Use-Case vollständig implementieren (Also UI, Service, Persistenz, + Tests), bei eigenen Projektideen also darauf achten, dass es genug Möglichkeiten gibt.

Einzelphase - Anfangen[Bearbeiten | Quelltext bearbeiten]

  • Angabe lesen! Sonst vergisst man eine Tech Story und darf danach aufwendig refactoren
  • Angular CLI braucht man nicht unbedingt installieren. Einfach npm run ng generate component component/horse-create und es geht
    • Oder etwas kürzer npm run ng g c component/horse-create
  • Backend und Frontend separat in der Entwicklungsumgebung öffnen.
  • .db Dateien und die Log Dateien gehören ins .gitignore.
    • # Add this at the end of your .gitignore
      log/
      *.db
  • Nie und nimmer git add . verwenden, das führt am Anfang schnell dazu, dass ihr die Git Techstory verletzt.
    • Entweder git add -p oder einen sinnvollen Git Client wie GitKraken verwenden.
  • Zum Anfangen bei der Einzelphase lohnt es sich Intellij richtig zu verwenden. Hier ist ein Tutorial.
    • Leerzeichen oder Sonderzeichen im Dateipfad werden nicht unterstützt und führen zu zufälligen Fehlermeldungen.
  • Time Tracking am besten gleich mit Excel machen, ansonsten verrechnet man sich. OnlyOffice ist gratis und geht offline.

Checkstyle importieren / Reformat Code on Save

Als erstes muss man das den Checkstyle Plugin installieren https://plugins.jetbrains.com/plugin/1065-checkstyle-idea

Dann in IntelliJ auf File -> Settings gehen, und "Editor" aufklappen. Dort auf Code Style drücken, und bei dem "Scheme" am besten "Project" auswählen. Links davon ist dann ein Zahnrad, wo man "Import Scheme" und "Checkstyle configuration" auswählt. Dann kann man die "checkstyle.xml" Datei importieren. Das importiert alle vorgegebenen Settings bezüglich Code Style.

Dann in IntelliJ auf File -> Settings gehen, nach "Actions on Save" suchen oder "Tools" aufklappen und dort auf Actions on Save klicken. Bei "Reformat code" und "Optimize imports" einen Haken setzen. Jetzt, sobald man seinen Code speichert, werden nicht verwendete Imports entfernt und falsche Einrückungen richtig gestellt.

Einzelphase - Backend[Bearbeiten | Quelltext bearbeiten]

Allgemein[Bearbeiten | Quelltext bearbeiten]

  • Du wirst einige DTOs brauchen, verschiedene REST Schnittstellen geben verschiedene Sachen zurück
  • Sex ist ein Enum
  • Birthdate ist ein LocalDate am Backend (ISO Datumsformat muss man global in der application.yml einstellen. Also spring.mvc.format.date und spring.mvc.format.date-time und spring.mvc.format.time muss man auf iso setzen)
  • SEPM vereinfacht vieles, in der realen Welt muss man auf mehr achten.

Endpoint[Bearbeiten | Quelltext bearbeiten]

  • https://http.cat/ ist die einzig wahre HTTP Status Code Quelle
  • In DTOs können @NotNull, @Min, @Email verwendet werden. Um diese dann auch zu valideren, muss man @Validated im Endpoint hinzufügen.
    • Man kann schnell sehr viele DTOs haben, wovon viele auch eine Validierung brauchen. Validation Groups lösen das Problem nicht, sondern machen es eher komplexer.
  • Durations in DTOs funktionieren standardmäßig nicht gut.

Pitfalls[Bearbeiten | Quelltext bearbeiten]

  • PreparedStatement.setLong() ist cursed, du musst selber zuerst auf == null überprüfen
  • ResultSet.getLong() ist gleich cursed, du musst danach auf resultSet.wasNull() überprüfen
  • Auf regelmäßiges git committen nicht vergessen, sonst wird das lästig
  • Bei foreign keys muss man aufpassen. Wenn man ein Objekt löscht (z.B. delete from horse where id < 0 ), dann muss man zuerst alle Objekte die darauf zeigen löschen bzw. die Referenzen auf NULL setzen
  • Mit der Powershell geht java -Dspring.profiles.active=datagen -jar target/e00000007-0.0.1-SNAPSHOT.jar nicht. Verwend cmd oder die Git Bash
  • null in Java ein Fehler.

Persistence[Bearbeiten | Quelltext bearbeiten]

  • JPA war bei uns nicht die empfohlene Variante, was auch Sinn macht, da JPA teilweise sehr unintuitiv ist, von Javas Typsystem enorm zurückgehalten wird und auch keine wahrhaftig gute offizielle Dokumentation hat. (vgl. mit Entity Framework aus C#)
  • H2 Console ist Gold Wert http://localhost:8080/h2-console . Datenbank läuft auf jdbc:h2:./wendydb
  • Um Owner oder Parents in der gleichen Query mitzuladen kann man LEFT JOIN machen (Ausnahme: Eltern-Baum, das war eine rekursive Query)
    • Hier eignet es sich auch Entities zu haben die andere Entities referenzieren und nicht nur die IDs haben.
  • Case Sensitive Searches in SQL gehen mit WHERE LOCATE('cat', 'all cats are cute') >= 1
    • Und mit LOWER() kann man etwas zu Kleinbuchstaben konvertieren. Wenn man die beiden kombiniert, bekommt man eine Case Insensitive Search, also Groß-Kleinschreibung ist dann egal.
    • Und mit CONCAT() kann man mehrere Strings zusammenfügen, ist bei firstname-lastname Suchen sehr praktisch CONCAT(firstname, ' ', lastname)
  • Ignoring empty search parts can be done using it WHERE (text IS NULL OR LOCATE(text, 'all cats are cute') >= 1) The Ignore operation does not always work properly when using LIKE %_% so it is better to use LOCATE.
  • Die jdbcTemplate hat praktische überladene Methoden wie jdbcTemplate.query(SQL_WHATEVER, this::mapRow, horse.name(), horse.gender()); . Ist aber mit Vorsicht zu genießen, weil Java keine Union Types hat und dementsprechend Fehler wie "Enums" oder "LocalDate" dort reingeben nicht abfängt.
  • Die Insert Statements werden in der angegebenen Reihenfolge ausgeführt, und somit kann man mother und father horses erst referenzieren nachdem sie eingefügt wurden. Gib also die ältesten Pferde zuerst an und dann die jüngeren.

Configuration[Bearbeiten | Quelltext bearbeiten]

  • Eine Tech-Story erfordert, dass debug logs für die Applikation auch ausgegeben werden. Also gehört folgendes in die application.yml Datei
    logging:
      level:
        root: INFO
        at.ac.tuwien.sepm.assignment.individual: DEBUG
    
  • Es ist empfehlenswert immer das korrekte ISO Datumsformat zu verwenden
    spring.mvc.format.date: iso
    spring.mvc.format.date-time: iso
    spring.mvc.format.time: iso
    


Testing[Bearbeiten | Quelltext bearbeiten]

Einzelphase - Frontend[Bearbeiten | Quelltext bearbeiten]

  • Zuerst Angular Tutorial anschauen, dann Frontend anfangen. Offizielle Doku ist gut
  • Frontend startet man mit npm run start
  • Angular CLI braucht man nicht unbedingt installieren. Einfach npm run ng generate component component/horse-create und es geht
  • Webbrowser haben richtig nette Entwicklerwerkzeuge (Firefox, Chrome). Dort gibt es eine "Console" mit Fehlermeldungen und einen "Network" Tab wo man die REST Requests sieht.
  • Im package.json sind die Dependencies spezifiziert. Manche davon (Bootstrap, ngBootstrap) können enorm praktisch sein und dir Arbeit ersparen, frag deine Studienkollegen die sich mehr auskennen ;)
  • Angulars Ansatz zu Routing ist eher kompliziert und lädt die Seite nicht neu wenn es das vermeiden kann. Stattdessen muss man selber this.route.paramMap.subscribe() aufrufen
    this.route.paramMap.subscribe({
          next: params => {
            const id = params.get("id");
          }
        });
    
  • Wenn man so weit ist, dass man seinen Frontend linten will, dann gehen folgende Schritte wenn man VSCode verwendet. (Ist auch mein empfohlener IDE Setup, speziell dann für die Gruppenphase.)

Advanced[Bearbeiten | Quelltext bearbeiten]

  • Man kann Angular Components in anderen Components verwenden https://angular.io/guide/inputs-outputs
  • Es lohnt sich sich ein wenig mit Rxjs auseinanderzusetzen. Zumindest sollte man verstehen, was Observables sind und wie man mit diesen arbeiten kann.
    • Observables manuell zu subscriben, wie es im Sepm-Template gemacht wird (wurde?) ist nicht gängig und führt schnell zu Leaks, da Subscriptions generell unsubscribed werden müssen (mit wenigen Ausnahmen).
    • Vor allem die async pipe ist sehr nützlich, da man damit leicht Werte aus Observables (bspw. http-requests mit angular http-modul) im Template verwenden kann
    • Hier ein einfaches Beispiel ohne Error handling und loading. Mit Observables und async pipe ist der loading state allerdings trivial und error handling auch sehr einfach. Siehe Video
      export class HorseDetail {    
          horse$ = horseService.getHorse(id);
          constructor (public horseService: HorseService){}
      }
      
      Das horse$ Observables kann dann einfach im Template per async pipe als stinknormales JS-Objekt verwendet werden.
      <ng-container *ngIf="horse$ | async as horse">
          <span>{{ horse.name }}</span>
      </ng-container>
      
  • Grade wenn man Applikationen mit viel Interaktivität entwickelt, wo sich der State häufig ändert, sind Observables sehr nützlich, da man Observables auf neue Observables mappen kann. Erhält das "originale" Observable einen neuen Werten, dann erhalten auch alle Observable die aus diesem erzeugt wurden neue Werte.

Pitfalls[Bearbeiten | Quelltext bearbeiten]

  • Vergiss ja nie auf .subscribe() . Sonst wird der HTTP Request nie ausgeführt und man sucht ewig nach dem Fehler
  • Wenn man am Frontend validiert, sollte man auch am Frontend dafür Fehlermeldungen ausgeben. Empfehlung ist einfach nur am Backend zu validieren.

Angular ist Schmutz[Bearbeiten | Quelltext bearbeiten]

  • Angular Forms sind nicht accessible-by-default, was man bedenken soll wenn jemals Menschen mit Behinderung die Seite verwenden sollen https://github.com/angular/angular/issues/9121#issuecomment-861812264
  • Radio Buttons auf [disabled] zu setzen ist cursed (und wegen Backwards-Compatibility wirds auch nicht so schnell gefixt). Verwend etwas wie <input type="radio" [attr.disabled]="canChangeGender ? true : null" />
  • Angular's form input binding ist signifikant komplexer als das von vergleichbaren Alternativen. Es gibt sowohl ngModel, als auch formControl wobei es in beiden Fälle etwas verschiedene Ansätze zur Validierung gibt. Falls man ngModel mit einem Form verwendet, darf man nicht vergessen das name Attribute zu setzen.
  • Angular's HttpParams URL Encoding ist broken (Probier nach a++&b=+ zu suchen und schau was für einen Text das Backend empfängt. Zumindest das + wird ein Leerzeichen sein.). Mann muss es händisch machen https://github.com/angular/angular/issues/11058
    • Also um bei einem GET Request die params zu setzen muss man es mit URLSearchParams machen
      const searchParams = new URLSearchParams();
      if (horseSearch.name) {
        searchParams.append('name', horseSearch.name);
      }
      if (horseSearch.description) {
        searchParams.append('description', horseSearch.description);
      }
      
      return this.http.get<Horse[]>(baseUri + '/filter' + '?' + searchParams);
      


Einzelphase - Feedback[Bearbeiten | Quelltext bearbeiten]

Gruppenphase - Allgemein[Bearbeiten | Quelltext bearbeiten]

  • Falls alternative Technologien zugelassen werden, dann lohnt es sich das ernsthaft zu überlegen

Gruppenphase - Backend[Bearbeiten | Quelltext bearbeiten]

  • Checkstyle kann auf Warnings gesetzt werden (<violationSeverity>warning</violationSeverity> in der pom.xml, da es im Vergleich zu Eslint keine wirklichen Fehler entdeckt. Vielmehr achtet es darauf, dass Code überall gleich formatiert ist. Bessere Tools können dieses auch automatisch machen, wie u.a. Prettier für Javascript.
  • Spring Security ist eher kompliziert, was dazu führt, dass die Security automatisch leidet. Ein sicheres System sollte auch leicht verständlich sein, ansonsten schleichen sich leicht kleine Fehler ein.
    • Das 2022 Template hat Stateless JWT verwendet. Refresh Tokens, welche es sicherer machen würden, wurden der Einfachheit halber nicht verwendet. Die andere Alternative sind stateful JWTs.
    • Passwörter werden gehasht und gesaltet, und dann in der Datenbank persistiert. In der Praxis sollte man Passwörter vermeiden, oder zumindest einen Plan B haben für wenn die Datenbank geleakt wird.
  • Spring startet sehr langsam, und es gibt keine sinnvolle Lösung. Das sogenannte Hot Reloading von Spring funktioniert selten gut, und ist eher zu vermeiden.

JPA[Bearbeiten | Quelltext bearbeiten]

  • IntelliJ Ultimate ist empfohlen, wenn man JPQL Queries verwendet. Dann werden Queries wie @Query("SELECT DISTINCT u FROM user u LEFT JOIN FETCH u.orders WHERE u.id = ?1") auch von der IDE erkannt und teilweise überprüft.
    • Dieses garantiert nicht, dass Queries auch zur Laufzeit funktionieren. Einfache Integration Tests für die Endpoints sind empfehlenswert.
    • Elegantere APIs mit guter, offizieller Dokumentation, wie beim C# Entity Framework, gibt es in der Java Welt eher nicht. Also komplexere Queries sind mit JPA sehr aufwändig und teilweise unmöglich.
  • Queries schreiben ist anfänglich nicht leicht, außerdem ist JPQL nicht mit SQL zu verwechseln.
    • Ein paar Beispiele:
      // UserRepository interface, the actual implementation is automatically created at runtime by Spring
      @Repository
      public interface UserRepository extends JpaRepository<ApplicationUser, Long> {
      
      	// Notice how in typical SQL it would be SELECT u.* from user u
      	@Query("SELECT u FROM user u")
      	List<ApplicationUser> findAll(); // This is just an example, as this very method already exists in JpaRepository/Repository
      
      	@Query("SELECT u FROM user u WHERE u.id = ?")
      	ApplicationUser getById(Long id); // This is just an example, as this very method already exists in JpaRepository/Repository
      	
      	// Joins work similar to how they do in SQL, however, instead of writing ON, you write a .property
      	// So, if a user has a Set<Message> messages, then we can join it
      	@Query("SELECT m from user u LEFT JOIN u.messages m WHERE u.id = ?1")
      	List<Message> getUserMessages(Long userId);	
      	
      	// Since we have a bidirectional association, we could just as well have written
      	@Query("SELECT m from messages m WHERE m.user.id = ?1")
      	List<Message> getUserMessages1(Long userId);
      	
      	
      	// Eager loading can be done with JOIN FETCH, but don't forget to use DISTINCT!
      	// Eager loading basically means "load the user and more in a single SQL query"
          @Query("""
      SELECT DISTINCT u from user u 
      LEFT JOIN FETCH u.messages m 
      WHERE u.userName = ?1
      """)
      	List<Message> loadUserWithMessages(String userName);
      	
      	// Pagination is supported out of the box https://www.baeldung.com/spring-data-jpa-pagination-sorting
          // With FETCH JOIN, you need a countQuery https://stackoverflow.com/questions/21549480/spring-data-fetch-join-with-paging-is-not-working
      	@Query("SELECT u FROM user u")
      	Page<ApplicationUser> findAll(Pageable p); // called like userRepository.findAll(PageRequest.of(5, 10)); to get page 5, and each page has 10 elements
      }
      
      // Entities
      
      @Entity(name = "user") // Database name
      public class ApplicationUser {
        @Id // Primary key
        @GeneratedValue(strategy = GenerationType.IDENTITY) // Automatically generated, don't rely on this being generated in a certain order
        private Long id;
      
        private String userName;
        
        // cascade means that saving, deleting, etc. will also happen to the messages
        // for example, if a user gets deleted, the all of their messages will also get deleted
        // mappedBy specifies the name of the @ManyToOne on the other side
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
        private Set<Message> messages = new HashSet<>();
        
        // TODO: empty constructor, getters and setters, equals and hashCode
      }
      
      @Entity(name = "message")
      public class Message {
        // optional = false makes sure that you never accidentally forget to set this side
        @ManyToOne(optional = false) // note that in the database, the message will have a foreign key!
        private ApplicationUser user; // this name is what mappedBy references
        
        // TODO: empty constructor, getters and setters, equals and hashCode
      }
      
    • Die Criteria API oder EntityGraphs sind nicht empfehlenswert, da sie um einiges komplizierter und noch undurchschaubarer sind.
    • Die Criteria API ist standardmäßig nicht Type-Safe, was ein Antipattern ist. Man muss @StaticMetamodel verwenden wenn man type safety haben will.
  • Bei dem Projekt ist alles standardmäßig FetchType.LAZY
    • Dementsprechend braucht man @Transactional.
    • Also wenn man auf someMessage.user zum ersten mal zugreift, wird der dazugehörige ApplicationUser aus der Datenbank geladen.
    • Wenn man auf someUser.messages zugreift, hat man oftmals das n+1 Problem, weil jede einzelne Message mit einer separaten Query geladen werden könnte.
      • Hier sollte man eine eigene Query schreiben, die JOIN FETCH verwendet. Bitte nicht auf DISTINCT vergessen, da Spring in seiner unendlichen Weißheit sonst das gleiche Objekt mehrmals zurückgibt.
      • FetchType.EAGER ist zu vermeiden, da es bei größeren Datenmengen zu zahlreichen zusätzlichen SQL queries führen kann.
  • Die Endpoint Methoden sollten nicht mit @Transactional annotiert werden, sondern die darunterliegenden Servicemethoden, damit die klassische could not initialize proxy - no Session Fehlermeldung nicht auftritt.
  • Bei @OneToMany und @ManyToOne sollte man immer beide Seiten setzen. z.B. myUser.getMessages().add(myMessage); myMessage.setUser(myUser);
  • @Formula kann zu ziemlichen Performance Probleme führen, also bitte vermeiden. [1]
  • Auf Annotationen darf man nicht vergessen. Leider bekommt man selten eine gute Warnung/Fehlermeldung diesbezüglich.
  • @Embedded ist standardmäßig broken, um es sinnvoll zu verwenden muss man eine Hibernate-spezifische Naming Strategy verwenden.
  • Datenbank-Schemas sind so zu designen, dass keine "inconsistencies" entstehen können. Hier ist Concurrency ein signifikantes Problem, z.B. bei einem Konzert sollte es nicht möglich sein, dass zwei User den gleichen Sitzplatz gleichzeitig reservieren.
  • Bezüglich Concurrency bieten sich als alternative zu "Composite Keys" einfache "Unique Constraints" über mehrere Columns in Kombination mit einem "Surrogate Key" (einfach inkrementierte ID) an, da Composite Keys bei einer erneuten Query an die Datenbank den alten Eintrag einfach überschreiben (mergen) und Unique Constraints eine Exception werfen, wenn der Eintrag mit den spezifizierten Constraints schon existiert, was in den meißten Fällen dem gewünschten Verhalten entspricht. [2]

Global Exception Handler[Bearbeiten | Quelltext bearbeiten]

  • Mittels @ControllerAdvice und ResponseEntityExceptionHandler kann man einen globalen Exception Handler definieren.
    • Standardmäßig so schlecht wie ein try {} catch(RuntimeException e) { /* do nothing */ } über den gesamten Code
    • Um den Exception Handler sinnvoll zu machen, braucht man mindestens
      @Override
      protected ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
          LOGGER.warn("Internal exception", ex);
          return super.handleExceptionInternal(ex, body, headers, status, request);
      }
      

Mapstruct[Bearbeiten | Quelltext bearbeiten]

  • Offizielle Dokumentation sehr sparsam geschrieben.
  • Kompliziertere Mappings kann man so machen
    @Mappings({ // multiple mappings can be placed here
        // expression = Java code that will take something from the input
        // target = name of the output field in UserDto
        @Mapping(expression = "java(user.messages.size())", target = "messageCount"),
    })
    UserDto userToUserDto(ApplicationUser user);
    
  • Boolean Variablen werden oft falsch behandelt, z.B. bei private boolean isSuperuser generiert Intellij getters und setters mit denen Mapstruct nicht immer umgehen kann.
  • Mapstruct generiert Code im Hintergrund. Teilweise muss das Projekt explizit mit Maven mvn gestartet werden, damit Mapstruct neuen Code generiert.
  • Mapstruct gibt keine Warnings aus, wenn Namen von Felder nicht gleich heißen, sondern setzt diese einfach auf null. (Antipattern #15

Gruppenphase - Frontend[Bearbeiten | Quelltext bearbeiten]

  • Hier sind die gleichen Tipps wie bei der Einzelphase relevant. Ein signifikanter Unterschied ist, dass man auch andere Frameworks statt Angular vorschlagen kann. Diese Entscheidung sollte man ganz am Anfang treffen, und das umschreiben der Template muss man selber machen. Dennoch kann es Sinn machen, speziell wenn Gruppenmitglieder schon Erfahrung mit Web-Entwicklung haben, bzw. sehr schlechte Angular Erfahrungen gemacht haben. Typische Entscheidungen wären Vue.js 3, Svelte oder React.

Highlights / Lob[Bearbeiten | Quelltext bearbeiten]

noch offen

Verbesserungsvorschläge / Kritik[Bearbeiten | Quelltext bearbeiten]

Ganz klar zu wenig Zeit vorgesehen für so eine wichtige LVA! Ich kenne kaum jemanden, der unter 150 Stunden brauchte, oft 200+! Man muss ja den "Vorbereitungsteil" auch mitrechnen und der alleine kann schon 50+ Stunden ausmachen. Ich weiß nicht, ob es da intern einen Streit unter den Professoren gab, aber die Stundeneinteilung ist einfach nicht nachvollziehbar. Dieses PR sollte auf mindestens 2 LVAs aufgeteilt werden und mindestens 9 ECTS wert sein!

Statt des "Einführungsteils", der einfach eine unterbetreute Übung + Computer-Prüfung ist, sollte klar der Organisationsvorgang geübt werden. Es gibt zwar eine SEPM VO, die besteht aber größtenteils aus theoretischen ISO-Definitionen, die für Großfirmen gedacht sind. Das SCRUM-Tutorial aus dem PR ist eine 1.5 Stunden Vorlesung. Es wird nur einmal kurz erklärt, wie korrektes Testen funktioniert, obwohl Tests so zentral für das Projekt (und die Prüfung) sind! Das ist im Prinzip die gesamte "Vorbereitung" auf die Übung! Normalerweise bildet die VO eine adäquate Basis für die Übung, das ist hier sicher nicht der Fall!

Es ist nicht nachvollziehbar, warum die TU die Softwareentwicklung für Informatik-Studien so schlampig lehrt!

Sowohl die Wahl der Technologien, als auch die sehr kurz gehaltenen Einführungen darin sind suboptimal. Dementsprechend hat diese Vowi Seite auch eine sehr lange Liste an Tipps, die von Studierenden gesammelt wurde, anstatt das die LVA bessere Technolgien mit guten Tutorials wählt.