1. Inhaltsverzeichnis

2. Einleitung

Dieses Dokument wird anhand einer zusammengefassten Dokumentation des Basisprojekts einen Beispielaufbau für die Dokumentation eines Softwareprojekts darstellen.

Das Ziel des Dokuments ist es, das Basisprojekt zum Stand des Jahres 2023 knapp zu dokumentieren und damit eine Orientierung bei der Erstellung der Dokumentation für zukünftige Projektgruppe zu bieten.

3. Analyse

In diesem Kapitel wird zunächst die Vision des Basisprojekts beschrieben und danach die Anforderungsanalyse mit Userstorys und Akzeptanzkriterien dargestellt.

3.1. Vision

Das Basissystem dient dazu, den Studierenden den Einstieg in das SWP zu erleichtern, indem es Vorgaben zur Softwarearchitektur macht und Beispiele liefert. Gleichzeitig ist und soll das Basisprojekt nicht perfekt sein, sondern es enthält auch Fehler und Dinge, die verbessert und erweitert werden können, sodass die Studierenden lernen, auch fremden Code zu verstehen, zu verbessern und weiterzuentwickeln, um diesen ihren Bedürfnissen anzupassen.

Es soll eine klare Trennung zwischen Client mit Nutzerinteraktion und Server mit Spiellogik geben. Die Kommunikation zwischen den Komponenten erfolgt mit geteilten Klassen über den "Common". Auf dem Client sollen Login, Registrierung und ein rudimentäres Hauptmenü als Orientierung dienen. Auf dem Server soll eine dementsprechende Nutzerverwaltung vorhanden sein. Damit die beiden Komponenten zusammenarbeiten können, muss auch schon die Netzwerkkommunikation implementiert sein.

Das System soll möglichst einfach zu erweitern sein, da es nur als Fundament für die Studierendenprojekte dient und von ihnen erweitert werden muss.

Daher soll die Architektur des Basissystems Ereignisgetrieben sein, sodass der grundlegende Ablauf der Anwendung durch Ereignisse gesteuert ist. Alle Komponenten, für die die Information der Nachricht relevant ist, fangen sie ab und reagieren entsprechend (Observerpattern).

Der Client soll nach dem Model-View-Presenter-Pattern aufgebaut werden, wodurch das Erweitern und Testen vereinfacht wird.

Eine klare und saubere Klassenhierarchie dient ebenfalls einer guten Erweiterbarkeit.

3.2. Anforderungsanalyse

In diesem Abschnitt werden aus der Vision konkrete Ziele und Anforderungen abgeleitet. Da in der Entwicklung des Basissystems das Scrumverfahren genutzt wurde, sind die Anforderungen als Userstorys formuliert.

3.2.1. Userstories

3.2.1.1. Login:

Als registrierte:r Nutze:r möchte ich mich beim Spiel einloggen können, damit ich mit anderen Nutzer:innen chatten kann.
Akzeptanzkriterien:
Die Nutzer:in wird bei einem Fehlschlag informiert.
Die Nutzerin wird bei Erfolg in das Hauptmenü geleitet.
Alle anderen Nutzer:innen sollen sehen können, dass sich jemand neues angemeldet hat.
Im Loginformular werden Nickname und Passwort abgefragt.

3.2.1.2. Registrierung

Als Nutzer:in möchte ich mich vor dem Einloggen registrieren, um einen eindeutigen und persistenten Account zu erhalten.
Akzeptanzkriterien:
Die Nutzer:in wird bei einem Fehlschlag informiert.
Im Formular werden Nickname und Passwort abgefragt.
Das Passwort muss doppelt angegeben werden, um Fehler zu vermeiden.
Der Account wird bei Erfolg der Registrierung gespeichert.
Die Nutzerin kann sich nach der Registrierung einloggen.

3.2.1.3. UI

Als Nutzer:in möchte ich, dass die Menügestaltung möglichst einheitlich ist, damit ich mich immer einfach zurechtfinden kann.

4. Umsetzung

Das Basissystem gliedert sich in drei Module: Server, Client und Common. Der Client ist der Bestandteil, der das Userinterface enthält und auf den Systemen der Spieler läuft. Der Server ist der Bestandteil, der die Nutzer- und Spielverwaltung enthält. Common enthält zwischen Server und Client geteilte Klassen. Zum reduzieren von Abhängigkeiten zwischen Client und Server dient der Common, welcher alle geteilten Klassen enthält.

4.1. Client

Der Client beinhaltet alle ausschließlich clientseitigen Klassen, Interfaces und Ressourcen. Die Aufgabe des Clients ist die Präsentation des Spiels und der umgebenden Serverlogik.

4.2. Server 

Der Server enthält die Nutzer- und Spielverwaltung und später die Spiellogik.

4.3. Common

Das Modul Common enthält Klassen, die sich Client und Server teilen. Hauptsächlich sind dies Messages und DataTransferObjects (DTO).       

Bei den Messages handelt es sich um drei Arten:

  • RequestMessages: Anfragen von Client an Server
  • ResponseMessages: Antworten von Server auf spezifische RequestMessage
  • ServerMessages: Nachricht von Server an einen oder mehrere Clients

Die DTO dienen zur Übertragung von größeren Datenobjekten.

4.4. Ereignisgetrieben

Die Kommunikation zwischen Client und Server wie auch die interne Kommunikation erfolgt ereignisgetrieben mittels des Observerpattern. Dies geschieht über einen Eventbus von Google Guava (https://github.com/google/guava/wiki/EventBusExplained). Bestandteile, die das Eventbus-Objekt enthalten, können mit der Methode eventBus.post(Object msg) ein Nachrichten-Objekt msg auf den Eventbus legen. Zum Lesen dieser Nachricht muss das gewünschte Bestandteil  bei dem Eventbus als Listener registriert sein.
Dies geschieht mit der Methode eventBus.register(Object listener). Die Reaktion auf eine Nachricht msg der Klasse Type erfolgt mit einer Methode mit einem Parameter der Klasse Type oder einer Oberklasse davon. Der Name einer Methode ist in der Regel onType(Type msg) - also on + Klassenname. Diese Methode muss mit der Annotation @Subscribe versehen sein.

Die ereignisgetriebene Architektur ermöglicht es, die Netzwerkkommunikation asynchron und ohne Blockaden oder Busy Waiting zu gestalten. Außerdem reduziert diese Architektur auch Abhängigkeiten.

4.5. Komponenten 

4.5.1. Server

Der Server lässt sich momentan in drei Hauptkomponenten aufteilen, die den Unterpackages des Servers entsprechenden.

In den meisten Komponenten gibt es mindesten eine spezialisierte Klasse, die Service heißt. Diese Klasse übernimmt das Anfangen von Requests und absenden von ResponseMessages.

Kommunikation übernimmt das Senden und Empfangen von Nachrichten zu den Clients.

Das Usermanagement übernimmt die Nutzerverwaltung. Im Usermanagement übernimmt der UserStore, die Speicherung der User:innen. Im Moment ist mit dem MainMemoryUserStore nur ein UserStore implementiert, der die Nutzer im RAM vorhält und nicht persistent speichern kann. Das Usermanagement stellt Methoden, zum Ein- und Ausloggen, zum Erstellen und Löschen, zum Updaten und zum Abfragen der gerade eingeloggten User:innen bereit.

Das Lobbymanagement übernimmt die Verwaltung der Lobbies. Es stellt Methoden zum Erzeugen und Löschen sowie zur Suche von Lobbies nach Namen bereit.

4.5.2. Client

Die Aufteilung im Client ist etwas anders, hier gibt es die Login-, Registration- und MainMenuPresenter und zugehörige Events. Daneben gibt es einen Client und Lobbyservice, um Request an den Server zu senden, und den SceneManager, der die Views und Presenter initialisiert. Daneben fängt der SceneManager verschieden ShowScene-Events ab, woraufhin er dann die spezifizierte Szene mit dem entsprechenden View anzeigt.

4.5.2.1. Login: 

In diesem Abschnitt wird die Funktionsweise des Logins beschrieben, und die oben beschriebenen Konzepte noch einmal in ihrer Anwendung im Loginprozess aufgezeigt. Die Beschreibung ist deshalb ausführlicher als bei anderen Abschnitten.

Bevor registrierte User:innen am Spiel teilnehmen können, müssen sie sich zunächst einloggen. Das Loginformular ist das erste was ein:e User:in sieht, wenn der Client gestartet wird. Es besteht wie im Bild zu sehen aus zwei Textfeldern, eines für den Nickname und eines für das Passwort. Daneben gibt es zwei Buttons einen, um den Login zu bestätigen, und ein anderen der zum Regsitrierungsdialog führt.

Im Regelfall gibt der/die Nutzer:in die entsprechenden Daten in die Testfelder ein und klickt den Login-Button. Nach dem Login Model-View-Presenter-Pattern löst diese Aktion im View, der durch die LoginView.fxml beschrieben ist, die Methode onLoginButtonPressed im LoginPresenter, die Username und Passwort an das Model im UserService vermittelt. Durch den UserService wird eine LoginRequest mit Username und Passwort erstellt und auf den Eventbus gepostet. Da die LoginRequest der Kommunikation zwischen Client und Server dient und von beiden Modulen benutzt wird, ist sie Teil des Commmon-Moduls. In der Client-Anwendung subscribet die Methode onRequestMessage in der ClientConnection-Klasse auf alle RequestMessages.
Diese Methode fängt die gepostete LoginRequest ab und sendet sie, wenn es eine Verbindung gibt, an den Server. Durch die Nutzung des Eventbuses gibt es in diesem Fall keine Abhängigkeit von UserService und ClientConnection wo der UserService die ClientConnection kennt und sich darum kümmern muss, dass die RequestMessage an die korrekte Methode übergeben wird. Am Server wird die RequestMessage von der Methode process im ServerHandler empfangen, und auf den Eventbus des Servers gepostet. Hier fängt der AuthenticationService die LoginRequest ab, und versucht den/die User:in beim UserManagement einzuloggen. Das Einloggen im UserManagement ist erfolgreich, wenn es eine:n User:in  mit entsprechendem Namen und Passwort gibt. Wenn das Einloggen funktioniert, wird eine ClientAuthorizedMessage und ansonsten eine ServerExceptionMessage erstellt und auf den Eventbus gepostet. Diese Messages werden wiederum im ServerHandler abgefangen. Hier wird eine aufgrund der ClientAuthorizedMessage eine LoginSuccessfulResponse und den Client, der sich eingeloggt hat geschickt, und eine UserLoggedInMessage an alle Clients gesendet.

Die Nachrichten werden in den Clients abgefangen und auf den Eventbus gepostet. Die LoginSuccesfulResponse löst in der ClientApp aus, dass durch den SceneManager das Hauptmenü gezeigt wird, und im MainMenuPresenter, dass alle zur Zeit angemeldeten User:innen angezeigt werden. Die UserLoggedInMessage sorgt dafür, dass in anderen Clients, der/die gerade neu eingeloggte User:in zu dieser Liste hinzugefügt wird.

4.5.2.2. Registrierung:

Bevor User:innen sich einloggen können, müssen sie sich registrieren. Der Registrierungsdialog besteht aus drei Textfeldern, eines für den Nickname und zwei für das Passwort. Daneben gibt es zwei Buttons, "Register", um die Registrierung zu bestätigen, und "Cancel", um sie abzubrechen und den Dialog zu verlassen.

Beim Registrieren wird überprüft, dass tatsächlich ein Nickname und ein Passwort angegeben wurden, und dass das Passwort korrekt wiederholt wurde. Außerdem darf nicht schon ein User mit diesem Username existieren. 

4.5.2.3. Hauptmenü

Das Hauptmenü besteht aus eine Liste mit den zur Zeit angemeldeten User:innen und zwei Buttons: "Create Lobby" und "Join Lobby".

5. Testdokumentation

Im Basisprojekt wurde der geschriebene Code mithilfe von automatisierten Unittests getestet. In diesem Kapitel wird das Vorgehen bei den Tests, welche Tests es gibt und was sie abdecken, beschrieben.

5.1. Vorgehen

Zum Testen wurde das Framework "JUnit" genutzt.  Dabei orientieren sich die Tests in der Regel am Konzept "Arrange, Act, Assert". Hierbei werden zunächst alle benötigten Objekte initialisiert und in den richtigen Zustand gebracht. Dazu kann es Hilfsmethoden geben, insbesondere wenn dieselbe Konfiguration öfter benötigt wird. Nach dem "Arrange"-Schritt wird die zu testende Aktion ausgeführt. Mittels Asserts wird daraufhin überprüft, ob die getestete Aktion tatsächlich die erwarteten Auswirkungen hatte.

Die GUI konnte auf diese Weise allerdings nicht getestet werden. Hierfür wurde die Funktionsweise der GUI immer wieder manuell überprüft.  

5.2. Was wurde getestet?

5.2.1. Client

Im Client gibt es eine Testabdeckung von 7 % der Codezeilen und 10 % der Methoden. Es wurden Tests für das RegistrationErrorEvent und den UserService geschrieben.

5.2.2. Common

Die Tests im Common decken 36 % der Methoden und 50 % der Codezeilen ab. Es wurden Tests für die DTOs geschrieben und welche, die die (de)serialisierbarkeit der Messages überprüfen.

5.2.3. Server

Im Server decken die Tests 31 % der Methoden und 32 % der Codezeilen ab. Die Tests beschränken sich auf die Klassen des UserManagements.

6. Ausblick

Die grundlegenden Funktionen eine Client-Server-Architektur und einer Nutzerverwaltung wurden im Basisprojekt umgesetzt. Diese Basis kann jetzt für die Implementierung beliebiger (Brett-)spiele genutzt werden. Allerdings fehlen auch noch einige Funktionen der Nutzerverwaltung wie das Logout von Nutzer:innen. Daneben gibt es schon ein einfaches Lobbysystem, dass aber momentan noch nicht im Client aufrufbar ist. Vor einer Brettspielimplementierung müssten diese beiden Probleme noch behoben werden.

Neben der Brettspielimplementierung ist auch es auch möglich auf Grundlage des Basissystems eine Chatanwendung zu entwickeln. Dies ließe sich auch mit der Brettspielimplementierung kombinieren.

7. Anhang

7.1. Klassendiagramme der Module

7.1.1. Client

7.1.2. Common

7.1.3. Server




  • No labels