TU Wien:Software Engineering und Projektmanagement PR (Biffl): Difference between revisions

From VoWi
Jump to navigation Jump to search
Similarly named LVAs (Resources):
 
(97 intermediate revisions by 11 users not shown)
Line 1: Line 1:
{{TU Wien LVA umbenannt (2011)|alt=Software Engineering und Projektmanagement LU}}
== Daten ==
== Daten ==
{{LVA-Daten
{{LVA-Daten
|ects=6
|ects=6
|vortragende=[http://qse.ifs.tuwien.ac.at/~biffl/ Prof. Biffl] und [http://qse.ifs.tuwien.ac.at/~winkler/ DI Winkler]
|vortragende=[[tiss.person:124531|Stefan Biffl]]; [[tiss.person:60080|Peter Frühwirt]]; [[tiss.person:52257|Dietmar Winkler]]
|institut=[http://qse.ifs.tuwien.ac.at/ E188/1 - Institut für Softwaretechnik und Interaktive Systeme, Abteilung Information & Software Engineering, Gruppe für Quality Software Engineering]
|abteilung=Quality Software Engineering
|homepage=http://tuwel.tuwien.ac.at
|id=188909
|wann=WS
|alias=Software Engineering and Projectmanagement@en
|homepage=https://tuwel.tuwien.ac.at/course/view.php?id=153
|letzte_abhaltung=2022WS
|sprache=de
|abbr=SEPM
|mattermost=software-engineering-und-projektmanagement
|zuordnungen=
|zuordnungen=
     {{Zuordnung|E033531|Unbekannt oder "Prä-Modul-Ära" - EDIT ME}}
     {{Zuordnung|E033526|INT/SEP - Software Engineering und Projektmanagement}}
     {{Zuordnung|E033532|Unbekannt oder "Prä-Modul-Ära" - EDIT ME}}
     {{Zuordnung|E033532|Software Engineering und Projektmanagement alt}}
     {{Zuordnung|E033533|Unbekannt oder "Prä-Modul-Ära" - EDIT ME}}
     {{Zuordnung|E033533|Software Engineering und Projektmanagement alt}}
     {{Zuordnung|E033534|Unbekannt oder "Prä-Modul-Ära" - EDIT ME}}
     {{Zuordnung|E033534|Software Engineering und Projektmanagement alt}}
    {{Zuordnung|E033526|INT/SEP – Software Engineering und Projektmanagement}}
}}
}}
{{mattermost-channel|software-engineering-und-projektmanagement}}


== Inhalt ==
== Inhalt ==
Line 32: Line 35:
** Unit Tests
** Unit Tests
** Dokumentation (Beschreibung mit Klassendiagrammen und Use-Case-Diagrammen)
** Dokumentation (Beschreibung mit Klassendiagrammen und Use-Case-Diagrammen)
Folgendes gibt es s2022 (und davor seit?) nicht mehr:
* '''Abgabegespräch'''
* '''Abgabegespräch'''
** '''Live Test''' (40 Minuten Zeit um kleine Programmieraufgaben zu lösen)
** '''Live Test''' (40 Minuten Zeit um kleine Programmieraufgaben zu lösen)
** Abgabegespräch (Ein Tutor schaut sich deine Dokumentation und deine Lösung für das Einzelbeispiel an)
** 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]]
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]]
Line 42: Line 46:
''Für eine Beschreibung der Gruppenphase am INSO siehe [[TU Wien:Software Engineering und Projektmanagement PR (Grechenig)]]''
''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 "MP3 Player".
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.
Während der gesamten Gruppenphase steht euch ein zugeteilter Tutor (je nach Wunsch) mehr oder weniger intensiv und hilfreich zur Seite.
Line 49: Line 53:
Am QSE gibt es einige Vorgaben bezüglich der Technologien. Zu verwenden sind:
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
* Maven
* git
* H2
* Redmine als PM tool (wird inkl. git repository vom Institut zur Verfügung gestellt)
* Angular
* Spring (Dependency Injection)
 
<b>Post-S19:</b> Wir mussten (!) Hibernate verwenden beim QSE, das könnte aber auch von Semester zu Semester unterschiedlich sein...


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


==== Projektablauf ====
==== Projektablauf ====


* '''Projektvorschlag und -auftragsphase''' (Ihr schreibt einen Projektvorschlag der angenommen oder abgelehnt wird, und auf Basis dessen einen Projektauftrag)
* '''Projektvorschlag und -auftragsphase''' (Ihr schreibt einen Projektvorschlag der angenommen oder abgelehnt wird, und auf Basis dessen einen Projektauftrag)
* '''Wöchentliche Jour fixe''' Termine mit eurem Tutor
* '''Wöchentliche Jour fixe''' Termine mit eurer Tutorin/eurem Tutor
* Zu drei '''Management Review''' Terminen, präsentiert ihr dem euch zugewiesenen Univ. Assistenten euer Produkt, beim letzten Termin werdet ihr von ihm auch benotet.
* 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".
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 einen Teamkoordinator, einen Systemarchitekten, einen Dokumentationsverantwortlichen, einen Testverantwortlichen und eventuell deren Stellvertreter. Jede dieser Rollen ist mit sog. horizontalen und vertikalen Verantwortlichkeiten behaftet. Normalerweise denkt jeder gleich an die Horizontalen Verantwortlichkeiten. Z.B. Als Team-Koordinator(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.
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:'''
'''Sommersemester 2008:'''
Line 91: Line 103:


== Prüfung ==
== Prüfung ==
Eine Person vom Institut die während des Projekts den "Auftraggeber" spielt ist für die Benotung eigentlich zuständig, oft wird aber in Übereinkunft mit dem Tutor und/oder der Gruppe benotet. Je nach Auftraggeber 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.
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 des Tutors und des 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 [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 (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.
Line 118: Line 130:
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).
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).


'''SS14''': 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.
'''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.


'''S2018''': Einzelphase:
'''SS2018''': Einzelphase:
Zeitaufwand ist angegeben mit:
Zeitaufwand ist angegeben mit:
* Einarbeitung in die Technologien des Einzelbeispiels: 8 Stunden
* Einarbeitung in die Technologien des Einzelbeispiels: 8 Stunden
Line 129: Line 141:


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.
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 ==
== Dauer der Zeugnisausstellung ==
noch offen
Bei unserer Gruppe ca. 1 Monat nach der Abgabe (Wir hatten damals aber noch etwas nachzureichen)
 
== Lösungen ==
Da die Beispiele zwischen den Semestern meist recht ähnlich bleiben kann es sich schon lohnen sich Lösungen aus letzteren Semestern anzusehen.
 
=== Einzephase ===
* [https://github.com/mah-luke/SEPM_einzel Einzephase WS2021]
* [https://github.com/flofriday/SEPM-Einzelphase Einzelphase SS2021]
* [https://github.com/InMediCode/at.ac.tuwien.sepm_individual.ss19 Einzelphase SS2019]
* [https://github.com/littleLemming/sepm_einzelbsp_ws16 Einzephase WS2016]
* [https://github.com/hschne/tuwien.sepm Einzelphase SS2016]
* [https://github.com/pgrosslicht/SEPM-SS15 Einzephase SS2015]
 
=== Gruppenphase ===
* [https://github.com/stefnotch/sepm-project Gruppenphase SS2022 (nur Frontend)]
* [https://github.com/flofriday/SEPM-Gruppenphase Gruppenphase SS2021]
* [https://github.com/Eric-Spooner/edulium Gruppenphase SS2015]
* [https://github.com/schuay/sepm Gruppenphase SS2012]


== Tipps ==
== Tipps ==
* Das Tutorial zum Einzelbeispiel unbedingt besuchen. Wenn möglich aufnehmen, da einem dort ein idealer Start zur schichtenübergreifenden Implementierung vorgezeigt wird.
 
=== '''LVA Allgemein''' ===
* 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.
* 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.
* 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.
* Besucht das Scrum-Tutorial, da bis zum 1. IR primär nur Agilo-Docs zu erstellen sind bzw. die Sprintplanung durchzuführen ist.
* Plant genug Zeit für die LVA ein, die besagten Wochenstunden reichen wie gesagt bei weitem nicht!
* 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)
* Seit 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.
* 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.
** Ü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.
* 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.
* Als Anfänger (speziell User Interface..) beginnt rechtzeitig mit Literaturrecherche und Büffeln.
 
* Unterm Semester gibt es immer wieder gezielte Tech-Vortraege und "Experten"-Treffen fuer die Gruppen, Hinschauen lohnt ! (hat mich damals vor einer undurchfuehrbaren Projektidee bewahrt)
=== '''Einzelphase - Anfangen''' ===
* 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 mMn nur Nachteile.
 
* Angabe lesen! Sonst vergisst man eine Tech Story und darf danach aufwendig refactoren
* Angular CLI braucht man nicht unbedingt installieren. Einfach <code>npm run ng generate component component/horse-create</code> und es geht
** Oder etwas kürzer <code>npm run ng g c component/horse-create</code>
* Backend und Frontend ''separat'' in der Entwicklungsumgebung öffnen.
* Nie und nimmer <code>git add .</code> verwenden, das führt am Anfang schnell dazu, dass ihr die Git Techstory verletzt.
** Entweder <code>git add -p</code> oder einen sinnvollen Git Client wie GitKraken verwenden.
* Zum Anfangen bei der Einzelphase lohnt es sich Intellij richtig zu verwenden [[Datei:TU_Wien-Software_Engineering_und_Projektmanagement_PR_(Biffl)_-_Getting_Started_with_Intellij.pdf]]
 
'''Checkstyle importieren / Reformat Code on Save'''
 
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 und wenn man mit der Maus über "Reformat code" geht, steht "Configure scope". Darauf klicken und bei dem Zahnrad anschließend "Import Scheme" und "Checkstyle configuration" auswählen und das "checkstyle.xml" auswählen. Das importiert alle vorgegebenen Settings bezüglich Code Style und sobald man seinen Code speichert, werden nicht verwendete Imports entfernt und falsche Einrückungen richtig gestellt.
 
=== '''Einzelphase - Backend''' ===
 
==== Allgemein ====
 
* 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 <code>application.yml</code> einstellen. Also <code>spring.mvc.format.date</code> und <code>spring.mvc.format.date-time</code>  und <code>spring.mvc.format.time</code>  muss man auf <code>iso</code> setzen)
* Emails korrekt zu validieren ist verdammt schwer, siehe [[https:Email_address#Examples|Beispiele von gültigen Adressen]] und zusätzlich sind wir im 21. Jahrhundert, also sind [[https:International_email|Unicode Emails]] etwas das sinnvoll ist. SEPM Team ist aber mit sehr primitiver, und teilweise völlig falscher Validierung zufrieden.
 
==== Endpoint ====
* https://http.cat/ ist die einzig wahre HTTP Status Code Quelle
*In DTOs können <code>@NotNull</code>, <code>@Min</code>, <code>@Email</code> verwendet werden. Um diese dann auch zu valideren, muss man <code>@Validated</code> 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.
*<code>Duration</code>s in DTOs funktionieren standardmäßig nicht gut.
 
==== Pitfalls ====
 
* <code>PreparedStatement.setLong()</code> ist cursed, du musst selber zuerst auf <code>== null</code> überprüfen
* <code>ResultSet.getLong()</code> ist gleich cursed, du musst danach auf <code>resultSet.wasNull()</code> überprüfen
* Wenn ein Unit Tests die Datenbank verändert, braucht er <code>@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)</code> oder https://stackoverflow.com/a/37246354/3492994 um die produktive DB nicht verändern, oder angreifen. Dafür kann man speziell für diese eigene Datensätze generieren und eine in-memory DB verwenden, somit ist man auf der sicheren Seite und haut sich nicht irgendwas in production zam. (<code>@Transactional</code> wurde im WS22 verboten)
* 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. <code>delete from horse where id < 0</code> ), dann muss man zuerst alle Objekte die darauf zeigen löschen bzw. die Referenzen auf <code>NULL</code> setzen
*Mit der Powershell geht <code>java -Dspring.profiles.active=datagen -jar target/e00000007-0.0.1-SNAPSHOT.jar</code> nicht. Verwend cmd oder die Git Bash
*<code>null</code> in Java [https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions|ist ein Fehler].
 
==== Persistence ====
 
* 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#)
*Um Owner oder Parents in der gleichen Query mitzuladen kann man <code>LEFT JOIN</code> machen (Ausnahme: Eltern-Baum, das war eine [https://www.h2database.com/html/advanced.html#recursive_queries 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 <code>WHERE LOCATE('cat', 'all cats are cute') >= 1</code>
**Und mit <code>LOWER()</code> kann man etwas zu Kleinbuchstaben konvertieren. Wenn man die beiden kombiniert, bekommt man eine Case ''In''sensitive Search, also Groß-Kleinschreibung ist dann egal.
**Und mit <code>CONCAT()</code> kann man mehrere Strings zusammenfügen, ist bei firstname-lastname Suchen sehr praktisch <code>CONCAT(firstname, ' ', lastname)</code>
*Ignoring empty search parts can be done using it <code>WHERE (text IS NULL OR LOCATE(text, 'all cats are cute') >= 1)</code>
* Die jdbcTemplate hat praktische überladene Methoden wie <code>jdbcTemplate.query(SQL_WHATEVER, this::mapRow, horse.name(), horse.gender());</code> . 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.
*H2 Console ist Gold Wert http://localhost:8080/h2-console . Datenbank läuft auf <code>jdbc:h2:./wendydb</code>
 
==== Configuration ====
 
* Eine Tech-Story erfordert, dass debug logs für die Applikation auch ausgegeben werden. Also gehört folgendes in die <code>application.yml</code> Datei<syntaxhighlight lang="yaml">
logging:
  level:
    at.ac.tuwien.sepm.assignment.individual: DEBUG
</syntaxhighlight>
 
* Es ist empfehlenswert immer das korrekte ISO Datumsformat zu verwenden<syntaxhighlight lang="yaml">
spring.mvc.format.date: iso
spring.mvc.format.date-time: iso
spring.mvc.format.time: iso
</syntaxhighlight>
 
=== '''Einzelphase - Frontend''' ===
 
* Zuerst Angular Tutorial anschauen, dann Frontend anfangen. [https://angular.io/tutorial Offizielle Doku ist gut]
* Frontend startet man mit <code>npm run start</code>
* Angular CLI braucht man nicht unbedingt installieren. Einfach <code>npm run ng generate component component/horse-create</code> und es geht
* Webbrowser haben richtig nette Entwicklerwerkzeuge ([https://developer.mozilla.org/en-US/docs/Tools Firefox], [https://developer.chrome.com/docs/devtools/overview/ Chrome]). Dort gibt es eine "Console" mit Fehlermeldungen und einen "Network" Tab wo man die REST Requests sieht.
* Typescript im Template ist nicht <code>"strict": true</code> eingestellt. Zwar ist es leichter für Anfänger, aber es kann auch ein bissi cursed sein weil es klar falschen Code durchlässt. Kannst gerne korrigieren (siehe <code>tsconfig.base.json</code>)
* Im <code>package.json</code> 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 <code>this.route.paramMap.subscribe()</code> aufrufen<syntaxhighlight lang="typescript">
this.route.paramMap.subscribe({
      next: params => {
        const id = params.get("id");
      }
    });
</syntaxhighlight>
* 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.)
** Eslint installieren https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
** Error Lens installieren https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens
** Prettier installieren https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
** Neben dem <code>package.json</code> eine <code>.prettierrc</code> Datei erstellen und folgendes reingeben<syntaxhighlight lang="json">
{
  "singleQuote": true
}
</syntaxhighlight>
** Und am besten auch '''Settings''' => '''Format On Save''' => Enable format on save
 
==== Advanced ====
 
* Man kann Angular Components in anderen Components verwenden https://angular.io/guide/inputs-outputs
 
==== Pitfalls ====
 
* Vergiss ja nie auf <code>.subscribe()</code> . 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 ====
 
* Reactive Forms sind nicht typisiert, also wird auch die Entwicklungsumgebung nicht wissen, dass <code>horseForm.value.name</code> existiert und ein <code>string</code> ist https://github.com/angular/angular/issues/13721
* So erstellte 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 <code>[disabled]</code> zu setzen ist cursed (und wegen [https://github.com/angular/angular/pull/35311#issuecomment-776414760 Backwards-Compatibility] wirds auch nicht so schnell gefixt). Verwend etwas wie <code><input type="radio" [attr.disabled]="canChangeGender ? true : null" /></code>
* Angular's form input binding ist signifikant komplexer als das von vergleichbaren Alternativen. Es gibt sowohl <code>ngModel</code>, als auch <code>formControl</code> wobei es in beiden Fälle etwas verschiedene Ansätze zur Validierung gibt. Falls man <code>ngModel</code> mit einem Form verwendet, darf man nicht vergessen das [https://stackoverflow.com/a/40462057/3492994 name Attribute] zu setzen.
* Angular's <code>HttpParams</code> URL Encoding ist broken (Probier nach <code>a++&b=+</code> zu suchen und schau was für einen Text das Backend empfängt. Zumindest das <code>+</code> 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 [https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams URLSearchParams] machen<syntaxhighlight lang="typescript">
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);
</syntaxhighlight>
 
=== '''Gruppenphase - Allgemein''' ===
-
 
=== '''Gruppenphase - Backend''' ===
 
* Checkstyle kann auf Warnings gesetzt werden (<code><violationSeverity>warning</violationSeverity></code> in der <code>pom.xml</code>, 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. [https://prettier.io/ 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. [https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ 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 [https://haveibeenpwned.com/ 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 ====
 
* IntelliJ Ultimate ist empfohlen, wenn man JPQL Queries verwendet. Dann werden Queries wie <code>@Query("SELECT DISTINCT u FROM user u LEFT JOIN FETCH u.orders WHERE u.id = ?1")</code> 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, [https://docs.microsoft.com/en-us/ef/core/querying/related-data/eager wie beim C# Entity Framework], gibt es in der Java Welt [https://docs.oracle.com/cd/E11035_01/kodo41/full/html/ejb3_langref.html#ejb3_langref_fetch_joins 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:<syntaxhighlight lang="java">
// 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
}
 
</syntaxhighlight>
** Die Criteria API oder EntityGraphs sind nicht empfehlenswert, da sie um einiges komplizierter und noch undurchschaubarer sind.
 
* Bei dem Projekt ist alles standardmäßig <code>FetchType.LAZY</code>
** Dementsprechend braucht man <code>@Transactional</code>.
** Also wenn man auf <code>someMessage.user</code> zum ersten mal zugreift, wird der dazugehörige ApplicationUser aus der Datenbank geladen.
** Wenn man auf <code>someUser.messages</code> 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 <code>JOIN FETCH</code> verwendet. Bitte nicht auf <code>DISTINCT</code>  vergessen, da Spring in seiner unendlichen Weißheit sonst das gleiche Objekt mehrmals zurückgibt.
***<code>FetchType.EAGER</code> ist zu vermeiden, da es bei größeren Datenmengen zu zahlreichen zusätzlichen SQL queries führen kann.
* Die Endpoint Methoden [https://towardsdev.com/spring-boot-data-access-layer-best-practices-c544d400de7b sollten] mit <code>@Transactional</code> annotiert werden, damit die klassische [https://stackoverflow.com/questions/21574236/how-to-fix-org-hibernate-lazyinitializationexception-could-not-initialize-prox could not initialize proxy - no Session] Fehlermeldung nicht auftritt.
*Bei <code>@OneToMany</code> und <code>@ManyToOne</code> sollte man ''immer beide Seiten setzen''. z.B. <code>myUser.getMessages().add(myMessage); myMessage.setUser(myUser);</code>
*<code>@Formula</code> kann zu ziemlichen Performance Probleme führen, also bitte vermeiden. [https://thorben-janssen.com/6-hibernate-mappings-you-should-avoid-for-high-performance-applications/#4_Avoid_the_Formula_annotation]
*Auf Annotationen darf man nicht vergessen. Leider bekommt man selten eine gute Warnung/Fehlermeldung diesbezüglich.
*<code>@Embedded</code> ist standardmäßig broken, um es sinnvoll zu verwenden muss man eine [https://stackoverflow.com/a/43412964/3492994 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. [https://stackoverflow.com/questions/65634479/embeddable-composite-key-is-not-throwing-integrity-exception-in-with-spring-dat]
 
==== Global Exception Handler ====
 
* Mittels <code>@ControllerAdvice</code> und <code>ResponseEntityExceptionHandler</code> kann man einen globalen Exception Handler definieren.
** Standardmäßig so schlecht wie ein <code>try {} catch(RuntimeException e) { /* do nothing */ }</code> über den gesamten Code
** Um den Exception Handler sinnvoll zu machen, braucht man mindestens<syntaxhighlight lang="java">
@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);
}
</syntaxhighlight>
 
==== Mapstruct ====
 
* Offizielle Dokumentation sehr sparsam geschrieben.
* Kompliziertere Mappings kann man so machen<syntaxhighlight lang="java">
@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);
</syntaxhighlight>
* Boolean Variablen werden oft falsch behandelt, z.B. bei <code>private boolean isSuperuser</code> generiert Intellij getters und setters mit denen Mapstruct nicht immer umgehen kann.
*Mapstruct generiert Code im Hintergrund. Teilweise muss das Projekt explizit mit Maven <code>mvn</code> 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''' ===
 
* 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.


== Verbesserungsvorschläge / Kritik ==
== Verbesserungsvorschläge / Kritik ==
Line 150: Line 437:


Es ist nicht nachvollziehbar, warum die TU die Softwareentwicklung für Informatik-Studien so schlampig lehrt!
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.


[[Kategorie:Programmierung und Softwareentwicklung]]
[[Kategorie:Programmierung und Softwareentwicklung]]

Latest revision as of 10:49, 8 December 2022

Daten[edit]

Lecturers Stefan BifflPeter FrühwirtDietmar Winkler
ECTS 6
Alias Software Engineering and Projectmanagement (en)
Department Forschungsbereich Quality Software Engineering
When winter semester
Last iteration 2022WS
Language Deutsch
Abbreviation SEPM
Mattermost software-engineering-und-projektmanagementRegisterMattermost-Infos
Links tiss:188909, Homepage
Zuordnungen
Bachelor Wirtschaftsinformatik Pflichtmodul INT/SEP - Software Engineering und Projektmanagement
Bachelor Medieninformatik und Visual Computing Pflichtmodul Software Engineering und Projektmanagement alt
Bachelor Medizinische Informatik Pflichtmodul Software Engineering und Projektmanagement alt
Bachelor Software & Information Engineering Pflichtmodul Software Engineering und Projektmanagement alt


Inhalt[edit]

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

Ablauf[edit]

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[edit]

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

Gruppenphase (QSE)[edit]

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[edit]

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[edit]

  • 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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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

Zeitaufwand[edit]

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[edit]

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

Lösungen[edit]

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

Einzephase[edit]

Gruppenphase[edit]

Tipps[edit]

LVA Allgemein[edit]

  • 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.
  • 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[edit]

  • 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.
  • 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 Datei:TU Wien-Software Engineering und Projektmanagement PR (Biffl) - Getting Started with Intellij.pdf

Checkstyle importieren / Reformat Code on Save

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 und wenn man mit der Maus über "Reformat code" geht, steht "Configure scope". Darauf klicken und bei dem Zahnrad anschließend "Import Scheme" und "Checkstyle configuration" auswählen und das "checkstyle.xml" auswählen. Das importiert alle vorgegebenen Settings bezüglich Code Style und sobald man seinen Code speichert, werden nicht verwendete Imports entfernt und falsche Einrückungen richtig gestellt.

Einzelphase - Backend[edit]

Allgemein[edit]

  • 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)
  • Emails korrekt zu validieren ist verdammt schwer, siehe Beispiele von gültigen Adressen und zusätzlich sind wir im 21. Jahrhundert, also sind Unicode Emails etwas das sinnvoll ist. SEPM Team ist aber mit sehr primitiver, und teilweise völlig falscher Validierung zufrieden.

Endpoint[edit]

  • 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[edit]

  • 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
  • Wenn ein Unit Tests die Datenbank verändert, braucht er @DirtiesContext(methodMode = MethodMode.AFTER_METHOD) oder https://stackoverflow.com/a/37246354/3492994 um die produktive DB nicht verändern, oder angreifen. Dafür kann man speziell für diese eigene Datensätze generieren und eine in-memory DB verwenden, somit ist man auf der sicheren Seite und haut sich nicht irgendwas in production zam. (@Transactional wurde im WS22 verboten)
  • 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[edit]

  • 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#)
  • 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)
  • 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.
  • H2 Console ist Gold Wert http://localhost:8080/h2-console . Datenbank läuft auf jdbc:h2:./wendydb

Configuration[edit]

  • 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:
        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
    

Einzelphase - Frontend[edit]

  • 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.
  • Typescript im Template ist nicht "strict": true eingestellt. Zwar ist es leichter für Anfänger, aber es kann auch ein bissi cursed sein weil es klar falschen Code durchlässt. Kannst gerne korrigieren (siehe tsconfig.base.json)
  • 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[edit]

Pitfalls[edit]

  • 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[edit]

  • Reactive Forms sind nicht typisiert, also wird auch die Entwicklungsumgebung nicht wissen, dass horseForm.value.name existiert und ein string ist https://github.com/angular/angular/issues/13721
  • So erstellte 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);
      

Gruppenphase - Allgemein[edit]

-

Gruppenphase - Backend[edit]

  • 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[edit]

  • 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.
  • 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 mit @Transactional annotiert werden, 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[edit]

  • 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[edit]

  • 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[edit]

  • 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.

Verbesserungsvorschläge / Kritik[edit]

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.