Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Inhaltsverzeichnis
Table of Contents

Einleitung

In diesem Dieses Dokument wird anhand der einer zusammengefassten Dokumentation des Basisprojekts ein Beispiel einen Beispielaufbau für die Dokumentation eines Softwareprojekts gegebendarstellen.

Das Ziel des Dokuments ist es, das Basisprojekt zum Stand des Jahres 2022 2023 knapp zu dokumentieren , und damit eine Orientierung bei der Erstellung der Dokumentation für zukünftige Projektgruppe zu bieten.Die Dokumentation unterteilt sich in mehrere Abschnitte. Im Kapitel

Analyse

...

Analyse

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

Vision

Im "echten Leben" findet Softwareentwicklung praktisch nie mehr auf der grünen Wiese statt, sondern es gibt vorherige Projekte und Prototypen auf die aufgebaut werden kann, und Frameworks die mit eingebunden werden können. Deshalb gibt es auch ein Basisprojekt für das SWP auf dem Aufgebaut werden kann. Das Basissystem soll Das Basissystem dient dazu, den Studierenden den Einstieg in das SWP zu erleichtern, indem es Vorgaben zur Softwarearchitektur macht und Beispiele liefert, wie Dinge anforderungskonform gemacht werden können. Gleichzeitig ist und soll das Basisprojekt nicht perfekt sein, sondern es enthält auch Fehler und Sachen Dinge, die verbessert und erweitert werden können, sodass die Studierenden lernen, auch fremden Code zu verstehen und , zu verbessern und weiterzuentwickeln, um diesen ihren Bedürfnissen anzupassen. Für den Anfang soll das Basisprojekt allerdings ohne Anpassungen funktionieren, um einen sauberen Einstieg in das SWP zu ermöglichen.

Damit das System als Basis dienen kann, müssen einige Systeme implementiert werden und Entscheidungen über die Softwarearchitektur getroffen werden. Es soll eine klare Trennung zwischen Client mit Nutzerinteraktion und Server mit Spiellogik geben. Die Kommunikation mit zwischen den Komponenten erfolgt mit geteilten Klassen geben (Common)ü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. Dies soll unter anderem durch eine möglichst geringe Abhängigkeit zwischen einzelnen Komponenten erreicht werden.  

Daher soll die Architektur des Basissystems Ereignisgetrieben sein, sodass der grundlegende Ablauf der Anwendung durch Ereignisse gesteuert ist. Dabei soll der Informationsfluss und das Interface in Nachrichten eingekapselt werden. Alle Komponenten, für die die Information der Nachricht relevant ist, fangen sie ab und reagieren entsprechend . Damit wird das Observerpattern umgesetzt und es muss kein aktives warten stattfinden(Observerpattern).

Der Client soll nach dem Model-View-Presenter-Pattern aufgebaut werden, um möglichst erweiter- und testbar zu sein. Dabei wird zwischen den Komponenten Modell, View und Presenter unterscheiden. Das Modell ist die eigentliche Anwendung. Der View ist das, was der Betrachter sieht, und sehr "dumm". Der Presenter ist der Mittler zwischen beiden Komponenten, und übersetzt beispielsweise Klicks auf dem View in Nachrichten an das Modell, und Nachrichten im Modell in Dinge die der View anzeigen soll. Dadurch soll der View austauschbar sein, da er nichts vom Presenter weiß.wodurch das Erweitern und Testen vereinfacht wird.

Eine klare und saubere Klassenhierarchie dient ebenfalls einer guten ErweiterbarkeitWeiterhin soll eine klare und saubere Klassenhierarchie eine gute Erweiterbarkeit ermöglichen.

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 Userstories Userstorys formuliert.

Userstories

Login:

...

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

Umsetzung

Zunächst werden die drei Module des Projekts dargestellt, anschließend werden Ereignisse und die Registrierung sowie der Login erläutert.    
    
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. Da es sich bei Client und Server um zwei Anwendungen handelt und um Abhängigkeiten zu reduzieren, dürfen in Zum reduzieren von Abhängigkeiten zwischen Client und Server nur Abhängigkeiten zu Common und nicht zur anderen Anwendung bestehen. Alle geteilten Klassen müssen sich in Common befindendient der Common, welcher alle geteilten Klassen enthält.

Client

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

Der Client wurde nach dem Model-View-Presenter-Pattern implementiert. In diesem Pattern wird zwischen drei Komponenten unterschieden: das Modell mit der dahinterliegenden Logik; der View, der die zugrundeliegende Logik dem/der Nutzer:in graphisch darstellt; und dem Presenter, der zwischen den beiden vermittelt. Dabei soll der View möglichst "dumm" gehalten werden, sodass die Logik möglichst vollständig vom Model gekapselt werden kann. Ziel dieses Patterns ist es, dass der View ausgetauscht werden kann, ohne dass das Model ausgetauscht werden muss.

Server 

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

...

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

Bei den Messages gibt handelt es sich um drei Arten: RequestMessages, ResponseMessages, ServerMessages. RequestMessages werden von einem Client zum Server geschickt. ResponseMessages sind die Antworten des Servers auf eine spezifische RequestMessage. ServerMessages werden vom

  • 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. Ein Beispiel hierfür ist das UserDTO, mit dem der Inhalt von User-Objekten zwischen Client und Server transportiert werden kann, ohne dass das client- oder serverseitige Verhalten der Klasse mitgeliefert werden.

Ereignisgetrieben

Die Kommunikation zwischen Client und Server wie auch die interne Kommunikation erfolgt ereignisgetrieben . Dabei handelt es sich um eine Umsetzung des Observerpatterns. Verschiedene Bestandteile, die miteinander kommunizieren, enthalten mittels des Observerpattern. Dies geschieht über einen Eventbus von Google Guava (https://github.com/google/guava/wiki/EventBusExplained), über den die Kommunikation läuft. Dabei muss es sich in allen Bestandteilen, die miteinander kommunizieren sollen, um das gleiche Eventbus-Objekt handeln. Bestandteile, die das Eventbus-Objekt enthalten, können mit der Methode eventBus.post(Object msg) eine ein Nachrichten-Objekt msg auf den Eventbus legen. Damit andere Bestandteile auf diese Nachricht reagieren können, müssen sie 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 so 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 und die Verarbeitung von, von Nutzer:innen erzeugten Ereignissen, asynchron und ohne Blockaden oder Busy Waiting zu gestalten. Außerdem müssen nicht ein Ereignisse auslösenden Komponenten, nicht alle Komponenten, die das Ereignis weiterverarbeiten, kennen und aufrufen. Dadurch werden Abhängigkeiten reduziert, allerdings lässt sich durch die Betrachtung der Codestelle, die ein Ereignis auslöst, nicht sagen, welche Komponenten darauf reagieren.  reduziert diese Architektur auch Abhängigkeiten.

Komponenten 

Server

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

...

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 (todo: Bild) 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.

Image Added

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.

Image Added

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.

...

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.

Image Added

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. 

...

Klassendiagramme der Module

Client

Image Added

Common

Image Added

Server

Image Added