Browse Source

Typos

main
Jonas Franz 4 months ago
parent
commit
56b29391e7
  1. 8
      chapters/analyse/analyse.tex
  2. 14
      chapters/basics/state-management.tex
  3. 2
      chapters/conclusion/conclusion.tex
  4. 32
      chapters/evaluation/bloc.tex
  5. 6
      chapters/evaluation/evaluation.tex
  6. 14
      chapters/evaluation/inheritedwidget.tex
  7. 14
      chapters/evaluation/mobx.tex
  8. 14
      chapters/evaluation/provider.tex
  9. 16
      chapters/evaluation/redux.tex
  10. 16
      chapters/evaluation/riverpod.tex
  11. 2
      chapters/realisation/realisation.tex
  12. 3
      hdathesis-config.tex

8
chapters/analyse/analyse.tex

@ -16,7 +16,7 @@ Zur Bewertung von Software-Qualität wurden diverse Anforderungen und Kriterien @@ -16,7 +16,7 @@ Zur Bewertung von Software-Qualität wurden diverse Anforderungen und Kriterien
\blockcquote[470]{Balzert2009}{Fähigkeit des Softwareprodukts änderungsfähig zu sein. Änderungen können Korrekturen, Verbesserungen oder Anpassungen der Software an Änderungen der Umgebung, der Anforderungen und der funktionalen Spezifikationen einschließen}
Daraus ergeben sich auch Anforderungen an die Quelltext-Qualität. Darunter wird beispielsweise die Anforderungen der \textcquote[470]{Balzert2009}{Änderbarkeit[...] [und] Testbarkeit} verstanden. Diese Anforderungen können auch für Zustandsverwaltungssysteme übernommen werden. Zustandsverwaltungssysteme und die Anwendungen, die diese verwenden, müssen effizient veränderbar und erweiterbar sein. Zusätzlich ist eine wichtige Anforderung diese, dass die resultierende Anwendung auch automatisiert testbar sein muss, um zu prüfen, ob sie den gewünschten Anforderungen entspricht.
Daraus ergeben sich auch Anforderungen an die Quelltext-Qualität. Darunter wird beispielsweise die Anforderungen der \textcquote[470]{Balzert2009}{Änderbarkeit[...] [und] Testbarkeit} verstanden. Diese Anforderungen können auch für Zustandsverwaltungssysteme übernommen werden. Zustandsverwaltungssysteme und die Anwendungen, die diese verwenden, müssen effizient veränderbar und erweiterbar sein. Zusätzlich ist eine wichtige Anforderung, dass die resultierende Anwendung auch automatisiert testbar sein muss, um zu prüfen, ob sie den gewünschten Anforderungen entspricht.
Hinzukommend spieln auch noch weitere Anforderungen zur Sicherstellung von Software-Qualität eine Rolle wie in \citetitle{rosenberg1997software} beschrieben wird. So seien die Attribute der Effizienz, Komplexität, Verständlichkeit, Wiederverwendbarkeit und Testbarkeit/Wartbarkeit von Bedeutung. \Autocite[vgl.][1]{rosenberg1997software} Diese Anforderungen lassen sich auf den beschriebenen Evaluationsfall übertragen, müssen allerdings noch auf diesen Anwendungsfall hin angewandt werden.
@ -59,7 +59,7 @@ Da nun die Anforderungen an Zustandsverwaltungssysteme feststehen, können jetzt @@ -59,7 +59,7 @@ Da nun die Anforderungen an Zustandsverwaltungssysteme feststehen, können jetzt
\subsection{Änderbarkeit/Skalierbarkeit}
\label{sec:changeablility}
Um zu untersuchen, ob ein Zustandsverwaltungssystem skalierbar oder nicht aufwendig änderbar ist, muss untersucht werden, wie dieses mit einer wachsenden Größe des Zustands umgeht. Dabei ist ein entscheidendes Kriterium, wie effektiv sich diverse Zustände sich untereinander verknüpfen lassen. Es ist nämlich damit zu rechnen, dass bei einer größer werdenden Anwendung auch die Koppelung zwischen den einzelnen Zuständen zunimmt.
Um zu untersuchen, ob ein Zustandsverwaltungssystem skalierbar oder nicht aufwendig änderbar ist, muss untersucht werden, wie dieses mit einer wachsenden Größe des Zustands umgeht. Dabei ist ein entscheidendes Kriterium, wie effektiv sich diverse Zustände untereinander verknüpfen lassen. Es ist nämlich damit zu rechnen, dass bei einer größer werdenden Anwendung auch die Koppelung zwischen den einzelnen Zuständen zunimmt.
Für dieses Bewertungskriterium wird eine qualitative Bewertungsskala verwendet, welche die Änderbarkeit/Skalierbarkeit mit den Werten \textquote{nicht erfüllt}, \textquote{teilweise erfüllt} und \textquote{vollständig erfüllt} bewertet.
@ -91,7 +91,7 @@ Zur Messung der Komplexität ist es auch möglich, die Komplexität eine Anwendu @@ -91,7 +91,7 @@ Zur Messung der Komplexität ist es auch möglich, die Komplexität eine Anwendu
\end{split}
\end{equation}
Um diese Metrik für die einzelnen Systeme zu bestimmen, wird das Werkzeug \textit{Dart Code Metrics} eingesetzt, welches diverse Metriken für Dart-Quell\-text bestimmen kann. Der von dem Werkzeug berechnete Wert wird leicht abweichend , wie in \autoref{eqn:miImproved} zu sehen, von der Original-Formel auf eine Skala von 0 bis 100 abgebildet, wobei 100 den besten erzielbaren Wert darstellt. \autocite{miDart}
Um diese Metrik für die einzelnen Systeme zu bestimmen, wird das Werkzeug \textit{Dart Code Metrics} eingesetzt, welches diverse Metriken für Dart-Quell\-text bestimmen kann. Der von dem Werkzeug berechnete Wert wird leicht abweichend, wie in \autoref{eqn:miImproved} zu sehen, von der Original-Formel auf eine Skala von 0 bis 100 abgebildet, wobei 100 den besten erzielbaren Wert darstellt. \autocite{miDart}
\begin{equation}
\begin{split}
@ -100,7 +100,7 @@ Um diese Metrik für die einzelnen Systeme zu bestimmen, wird das Werkzeug \text @@ -100,7 +100,7 @@ Um diese Metrik für die einzelnen Systeme zu bestimmen, wird das Werkzeug \text
\end{split}
\end{equation}
Diese Metrik wird dabei als Bewertungsmaßstab verwendet.% und mit erklärenden Auslegungshinweisen ergänzt.
Diese Metrik wird als Bewertungsmaßstab verwendet.% und mit erklärenden Auslegungshinweisen ergänzt.
%Kombination mit quantitativer
%Bewertung

14
chapters/basics/state-management.tex

@ -30,7 +30,7 @@ Zur Auswahl der zu evaluierenden Lösungsansätze wird die Aufzählung von Zusta @@ -30,7 +30,7 @@ Zur Auswahl der zu evaluierenden Lösungsansätze wird die Aufzählung von Zusta
Da eine Evaluation aller aufgezählten Zustandsverwaltungssysteme, den Umfang dieser Ausarbeitung überschreiten würde, wurde die Auswahl eingeschränkt.
Die Ansätze setState und \texttt{Inherited\-Widget} werden in die Evaluation mit aufgenommen, da sie zu der Grundausstattung der Flutter-Standardbibliothek gehören, und somit einen Basiswert für Zustandsverwaltungssysteme bilden und somit relevant sind. Das \ac{bloc}-Pattern wird aufgenommen, da es aufgrund der großen Verbreitung in der Literatur relevant ist. Die Bibliothek Provider wird ebenfalls aufgenommen, da es sich laut der Dokumentation um den empfohlenen Ansatz für Zustandsverwaltung in Flutter handelt, und die Bibliothek mit 6132 Like-Angaben \autocite{providerPub} zu einer der beliebtesten Flutter-Pakete \autocite{pubRanking} auf der Plattform handelt. Riverpod wird ebenfalls aufgenommen, da dies den Ansatz von Provider weiterentwickelt und somit geprüft werden kann, ob diese Bibliothek tatsächlich besser abschneidet als die Original-Bibliothek. Zuletzt werden die Bibliotheken MobX und Redux aufgenommen, da sie besonders aufgrund ihrer Herkunft aus dem React-Ökosystem eine besondere Relevanz für die Evaluation haben, um ebenfalls feststellen zu können, ob bereits in React verbreitete Ansätze auch in Flutter sinnvoll einsetzbar sind.
Die Ansätze setState und \texttt{Inherited\-Widget} werden in die Evaluation mit aufgenommen, da sie zu der Grundausstattung der Flutter-Standardbibliothek gehören, und somit einen Basiswert für Zustandsverwaltungssysteme bilden und somit relevant sind. Das BLoC-Pattern wird aufgenommen, da es aufgrund der großen Verbreitung in der Literatur relevant ist. Die Bibliothek Provider wird ebenfalls aufgenommen, da es sich laut der Dokumentation um den empfohlenen Ansatz für Zustandsverwaltung in Flutter handelt, und die Bibliothek mit 6132 Like-Angaben \autocite{providerPub} zu einer der beliebtesten Flutter-Pakete \autocite{pubRanking} auf der Plattform handelt. Riverpod wird ebenfalls aufgenommen, da dies den Ansatz von Provider weiterentwickelt und somit geprüft werden kann, ob diese Bibliothek tatsächlich besser abschneidet als die Original-Bibliothek. Zuletzt werden die Bibliotheken MobX und Redux aufgenommen, da sie besonders aufgrund ihrer Herkunft aus dem React-Ökosystem eine besondere Relevanz für die Evaluation haben, um ebenfalls feststellen zu können, ob bereits in React verbreitete Ansätze auch in Flutter sinnvoll einsetzbar sind.
\subsection{Mitgelieferte Werkzeuge}
@ -92,7 +92,7 @@ Als Erweiterung des \texttt{InheritedWidget} kann man \texttt{InheritedModel} se @@ -92,7 +92,7 @@ Als Erweiterung des \texttt{InheritedWidget} kann man \texttt{InheritedModel} se
\subsection{Business Logic Components (BLoC)}
\label{sec:bloc}
Das 2018 auf der Entwicklerkonferenz DartConf vorgestellte \ac{bloc}-Pattern ist im Vergleich zu den bisher vorgestellten Ansätzen ein Design-Pattern zur Verwaltung von Zuständen und nicht nur ein Werkzeug des Frameworks. Das Ziel von \ac{bloc} ist es, die komplette Logik von der Benutzeroberfläche zu trennen. \autocite[17]{Faust} Die Logik und der Zustand wird dabei in den namensgebenden \acf{bloc} verwaltet. Die Komponenten haben die Aufgabe, Zustands-Ereignisse von Widgets zu empfange und Widgets zu aktualisieren, wenn sich der Zustand ändert. Diese Komponenten unterliegen grundlegenden, nicht-verhandelbaren Regeln, welche im Vortrag von \citeauthor{blocTalk} definiert worden sind:
Das 2018 auf der Entwicklerkonferenz DartConf vorgestellte BLoC-Pattern ist im Vergleich zu den bisher vorgestellten Ansätzen ein Design-Pattern zur Verwaltung von Zuständen und nicht nur ein Werkzeug des Frameworks. Das Ziel von BLoC ist es, die komplette Logik von der Benutzeroberfläche zu trennen. \autocite[17]{Faust} Die Logik und der Zustand wird dabei in den namensgebenden \acf{bloc} verwaltet. Die Komponenten haben die Aufgabe, Zustands-Ereignisse von Widgets zu empfange und Widgets zu aktualisieren, wenn sich der Zustand ändert. Diese Komponenten unterliegen grundlegenden, nicht-verhandelbaren Regeln, welche im Vortrag von \citeauthor{blocTalk} definiert worden sind:
\blockcquote[24:04]{blocTalk}{\begin{enumerate}
\item Inputs and outputs are simple Streams/Sink only
@ -100,17 +100,17 @@ Das 2018 auf der Entwicklerkonferenz DartConf vorgestellte \ac{bloc}-Pattern ist @@ -100,17 +100,17 @@ Das 2018 auf der Entwicklerkonferenz DartConf vorgestellte \ac{bloc}-Pattern ist
\item No platform branching allowed [...]
\end{enumerate}}
Die erste Regel bedeutet, dass \ac{bloc} weder Methoden noch Variablen nach außen freigeben dürfen, sondern nur über \texttt{Stream}s und \texttt{Sink}s mit Widgets kommunizieren. Ein \texttt{Stream} ist dabei in Flutter ein asynchroner Fluss von Daten oder Ereignissen. Widgets können diesen Ereignisfluss abonnieren und werden dann aktualisiert, wenn sich dieser ändert. Ein \texttt{Sink} ist intern auch eine Art von Stream, welcher aber die Besonderheit hat, dass man von außen neue Ereignisse hinzufügen kann. Über diesen \texttt{Sink} lassen sich also Daten und Ereignisse an das \ac{bloc} übergeben.
Die erste Regel bedeutet, dass BLoC weder Methoden noch Variablen nach außen freigeben dürfen, sondern nur über \texttt{Stream}s und \texttt{Sink}s mit Widgets kommunizieren. Ein \texttt{Stream} ist dabei in Flutter ein asynchroner Fluss von Daten oder Ereignissen. Widgets können diesen Ereignisfluss abonnieren und werden dann aktualisiert, wenn sich dieser ändert. Ein \texttt{Sink} ist intern auch eine Art von Stream, welcher aber die Besonderheit hat, dass man von außen neue Ereignisse hinzufügen kann. Über diesen \texttt{Sink} lassen sich also Daten und Ereignisse an das BLoC übergeben.
% TODO ggf noch beispiele einsetzen, wie die regeln anzuwenden sind
Die zweite Regel sagt aus, dass \ac{bloc} keine Abhängigkeiten zur Benutzeroberfläche haben dürfen. Selbst das Importieren von Flutter-Bibliotheken in diese Dateien ist verboten. Damit wird erreicht, dass \ac{bloc} komplett plattformunabhängig sind, und somit die komplette Benutzeroberfläche theoretisch ersetzt werden könnte, ohne die Logik ändern zu müssen.
Die zweite Regel sagt aus, dass BLoC keine Abhängigkeiten zur Benutzeroberfläche haben dürfen. Selbst das Importieren von Flutter-Bibliotheken in diese Dateien ist verboten. Damit wird erreicht, dass BLoC komplett plattformunabhängig sind, und somit die komplette Benutzeroberfläche theoretisch ersetzt werden könnte, ohne die Logik ändern zu müssen.
Die dritte Regel legt fest, dass innerhalb von \ac{bloc}s keine Unterscheidungen zwischen Betriebssystemen oder Plattformen vorgenommen werden darf.
Die dritte Regel legt fest, dass innerhalb von BLoCs keine Unterscheidungen zwischen Betriebssystemen oder Plattformen vorgenommen werden darf.
Der innere Aufbau der \ac{bloc} ist explizit nicht vorgeschrieben, dient aber dazu die über die \texttt{Sink}s eingehenden Daten und Ereignisse zu verarbeiten und anschließend den neuen Zustand über die \texttt{Stream}s zurück an die Widgets zu propagieren. Technisch kommen hier oft Techniken und Werkzeuge aus der reaktiven Programmierung wie \texttt{RxDart} zum Einsatz.
Der innere Aufbau der BLoC ist explizit nicht vorgeschrieben, dient aber dazu die über die \texttt{Sink}s eingehenden Daten und Ereignisse zu verarbeiten und anschließend den neuen Zustand über die \texttt{Stream}s zurück an die Widgets zu propagieren. Technisch kommen hier oft Techniken und Werkzeuge aus der reaktiven Programmierung wie \texttt{RxDart} zum Einsatz.
Jede Seite (engl. Screen) sollte dabei exakt einem \ac{bloc} zugeordnet sein. Damit die Widgets auf diesen \ac{bloc} zugreifen können, müssen diese \texttt{injectable} sein - also zwischen mehreren Widgets geteilt. Dies kann unter anderem mit den bereits in \autoref{chap:included} vorgestellten Ansätzen umgesetzt werden.
Jede Seite (engl. Screen) sollte dabei exakt einem BLoC zugeordnet sein. Damit die Widgets auf diesen BLoC zugreifen können, müssen diese \texttt{injectable} sein - also zwischen mehreren Widgets geteilt. Dies kann unter anderem mit den bereits in \autoref{chap:included} vorgestellten Ansätzen umgesetzt werden.
\subsection{Provider}
\label{sec:provider}

2
chapters/conclusion/conclusion.tex

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
\chapter{Fazit}
Zum Schluss der Ausarbeitung, werden die Ergebnisse der Evaluation nochmals zusammengefasst und analysiert, inwiefern mit der Evaluation das Ziel der Ausarbeitung erreicht werden konnte. Darauf aufbauend wird eine Empfehlung für verschiedene Anwendungsfälle gegeben. Am Ende folgt ein Ausblick, welche Aspekte der Ausarbeitung in Zukunft noch erweitert werden könnten.
Abschließend werden die Ergebnisse der Evaluation nochmals zusammengefasst und analysiert, inwiefern mit der Evaluation das Ziel der Ausarbeitung erreicht werden konnte. Darauf aufbauend wird eine Empfehlung für verschiedene Anwendungsfälle gegeben, gefolgt von einem Ausblick, welcher Aspekte der Ausarbeitung in Zukunft noch erweitert werden könnten.
Mit der Evaluation konnten bis auf das setState-Konzept alle Zustandsverwaltungssysteme evaluiert werden. Die Bewertungskriterien haben sich dabei größtenteils als aussagekräftig erwiesen. Lediglich der \acl{mi} konnte keine wirklich aussagekräftigen Ergebnisse bieten, da die Ergebnisse alle sehr nah aneinander liegen und so keine Differenzierung zwischen den einzelnen Systemen erfolgt ist. Die Metrik der Effizienz hingegen zeigt relativ aufschlussreich, welche Systeme effizient mit dem Neu-Erstellen von Widgets umgehen und welche nicht. Die qualitativen Bewertungen können zusätzlich einen detaillierten Einblick in die Umsetzung verschiedener Zustandssysteme bieten.

32
chapters/evaluation/bloc.tex

@ -5,9 +5,9 @@ @@ -5,9 +5,9 @@
\subsection{Implementierung}
Für die Implementierung der App mit \ac{bloc} wurden drei \acl{bloc} erstellt. Diese verwalten den Anmeldezustand, den Inhalt des Warenkorbs sowie die verfügbaren Produkte. Die \ac{bloc}s bestehen dabei aus zu teils mehreren \texttt{Stream}s und \texttt{Sink}s, die Zustandsänderungen von außen entgegennehmen und nach außen kommunizieren. Zusätzlich dazu gibt es für die \texttt{Stream}s öffentliche Variablen, welche den aktuellen Zustand wiedergeben. Dies dient, wie auch im Beispiel \autoref{lst:streambuilder} anhand des Parameters \texttt{initialData} zu sehen ist, dazu, dass Widgets, die erst später zum Widget-Tree hinzugefügt werden den aktuellen Zustand zum Zeitpunkt des initialen Erstellens erhalten können, da die Streams immer nur Zustandsänderungen kommunizieren können.
Für die Implementierung der App mit BLoC wurden drei \acl{bloc} erstellt. Diese verwalten den Anmeldezustand, den Inhalt des Warenkorbs sowie die verfügbaren Produkte. Die BLoCs bestehen dabei aus zu teils mehreren \texttt{Stream}s und \texttt{Sink}s, die Zustandsänderungen von außen entgegennehmen und nach außen kommunizieren. Zusätzlich dazu gibt es für die \texttt{Stream}s öffentliche Variablen, welche den aktuellen Zustand wiedergeben. Dies dient, wie auch im Beispiel \autoref{lst:streambuilder} anhand des Parameters \texttt{initialData} zu sehen ist, dazu, dass Widgets, die erst später zum Widget-Tree hinzugefügt werden den aktuellen Zustand zum Zeitpunkt des initialen Erstellens erhalten können, da die Streams immer nur Zustandsänderungen kommunizieren können.
Alle drei \ac{bloc}s werden über ein Widget an die Benutzeroberfläche weitergegeben, welches als Dependency Injection fungiert. Hier wären auch andere Implementierungsvarianten beispielsweise mit dem Service Locator \texttt{get\_it} denkbar gewesen. Der gewählte Ansatz benötigt jedoch keine zusätzliche Bibliothek und verfälscht somit das Ergebnis am wenigsten. Die Widgets der Benutzeroberfläche verwenden dabei \texttt{StreamBuilder}, wie in \autoref{lst:streambuilder} zu sehen ist, um über aktualisierten Zuständen informiert zu werden.
Alle drei BLoCs werden über ein Widget an die Benutzeroberfläche weitergegeben, welches als Dependency Injection fungiert. Hier wären auch andere Implementierungsvarianten beispielsweise mit dem Service Locator \texttt{get\_it} denkbar gewesen. Der gewählte Ansatz benötigt jedoch keine zusätzliche Bibliothek und verfälscht somit das Ergebnis am wenigsten. Die Widgets der Benutzeroberfläche verwenden dabei \texttt{StreamBuilder}, wie in \autoref{lst:streambuilder} zu sehen ist, um über aktualisierten Zuständen informiert zu werden.
\begin{lstlisting}[caption={Verwendung eines StreamBuilder in cart\_button.dart \cite{repo}}, label={lst:streambuilder}]
final cartBloc = AppState.of(context).blocProvider.cartBloc;
@ -30,15 +30,15 @@ return StreamBuilder<int>( @@ -30,15 +30,15 @@ return StreamBuilder<int>(
Im folgenden Abschnitt wird die Implementierung mit BLoC \autocite[branch=\\bloc]{repo} anhand der definierten Bewertungskriterien bewertet.
\paragraph{\nameref{sec:changeablility}}
\paragraph{\nameref*{sec:changeablility}}
Zu \ac{bloc} lässt sich sagen, dass diese sowohl skalierbar als auch änderbar sind. Diese Aussage stützt sich darauf, dass durch die Kommunikation ausschließlich über \texttt{Stream}s und \texttt{Sink}s sich eine einheitliche Schnittstelle schaffen lässt, an die beliege Komponenten sich andocken können. Anders als bei den Widget-basierten Ansätzen wie \texttt{Inherited\-Widget} lassen sich \ac{bloc} komplett plattformunabhängig einsetzen und sind somit für eine weitere Skalierung außerhalb des Flutter-Frameworks durchaus geeignet.
Zu BLoC lässt sich sagen, dass diese sowohl skalierbar als auch änderbar sind. Diese Aussage stützt sich darauf, dass durch die Kommunikation ausschließlich über \texttt{Stream}s und \texttt{Sink}s sich eine einheitliche Schnittstelle schaffen lässt, an die beliege Komponenten sich andocken können. Anders als bei den Widget-basierten Ansätzen wie \texttt{Inherited\-Widget} lassen sich BLoC komplett plattformunabhängig einsetzen und sind somit für eine weitere Skalierung außerhalb des Flutter-Frameworks durchaus geeignet.
Die Koppelung verschiedener Zustände lässt sich somit auch einfach lösen, indem andere \ac{bloc} beispielsweise über den Konstruktor oder ein Dependen\-cy-Injection Tool übergeben werden.
Die Koppelung verschiedener Zustände lässt sich somit auch einfach lösen, indem andere BLoC beispielsweise über den Konstruktor oder ein Dependen\-cy-Injection Tool übergeben werden.
Aufgrund dieser Eigenschaften wird die Bewertung \textquote{vollständig erfüllt} vergeben.
\paragraph{\nameref{sec:testability}} Zur Testbarkeit von \ac{bloc} lässt sich Folgendes sagen. Die Geschäftslogik der einzelnen \ac{bloc} lässt sich gut testen, da das Flutter-Test\-ing-Framework bereits Werkzeuge zum Überprüfen von Streams bereithält, wie sie im Test in \autoref{lst:testbloc} verwendet werden. Hier lassen sich somit auch einfach Unit-Tests verwenden. Falls \ac{bloc} Abhängigkeiten zu anderen \ac{bloc} oder Komponenten haben, müssen diese allerdings gemockt werden. Ohne eine entsprechende Bibliothek entstehen hier zusätzliche Aufwände durch das Implementieren von Mock-Klassen.
\paragraph{\nameref*{sec:testability}} Zur Testbarkeit von BLoC lässt sich Folgendes sagen. Die Geschäftslogik der einzelnen BLoC lässt sich gut testen, da das Flutter-Test\-ing-Framework bereits Werkzeuge zum Überprüfen von Streams bereithält, wie sie im Test in \autoref{lst:testbloc} verwendet werden. Hier lassen sich somit auch einfach Unit-Tests verwenden. Falls BLoC Abhängigkeiten zu anderen BLoC oder Komponenten haben, müssen diese allerdings gemockt werden. Ohne eine entsprechende Bibliothek entstehen hier zusätzliche Aufwände durch das Implementieren von Mock-Klassen.
\begin{lstlisting}[caption={Test des Cart BLoC in cart\_bloc\_test.dart \cite{repo}}, label={lst:testbloc}]
test('test cart bloc', () async {
@ -50,33 +50,33 @@ test('test cart bloc', () async { @@ -50,33 +50,33 @@ test('test cart bloc', () async {
});
\end{lstlisting}
Ein weiterer betrachteter Aspekt beim Testen ist die Testbarkeit von Widgets, die auf \ac{bloc} zugreifen. Hierzu lässt sich sagen, dass das Ersetzen durch Platzhaltern ohne Probleme möglich war. Allerdings hängt dies auch von dem verwendeten Injection-System ab. In diesem Beispiel wurden \texttt{Inherited\-Widgets} verwendet. Daher kann dies äquivalent zu dem dort beschriebenen Beobachtungen (vgl. \autoref{par:ihtesting}) gewertet werden. Zusätzlich dazu lässt sich sagen, dass für das Erzeugen eines Platzhalters (engl. mock) für ein \ac{bloc} die Klasse dieses \ac{bloc} vollständig gemockt werden muss. Hier lassen sich wie im vorhergehenden Absatz beschrieben, mehrere Strategien nutzen.
Ein weiterer betrachteter Aspekt beim Testen ist die Testbarkeit von Widgets, die auf BLoC zugreifen. Hierzu lässt sich sagen, dass das Ersetzen durch Platzhalter ohne Probleme möglich war. Allerdings hängt dies auch von dem verwendeten Injection-System ab. In diesem Beispiel wurden \texttt{Inherited\-Widgets} verwendet. Daher kann dies äquivalent zu dem dort beschriebenen Beobachtungen (vgl. \autoref{par:ihtesting}) gewertet werden. Zusätzlich dazu lässt sich sagen, dass für das Erzeugen eines Platzhalters (engl. mock) für ein BLoC die Klasse dieses BLoC vollständig gemockt werden muss. Hier lassen sich wie im vorhergehenden Absatz beschrieben, mehrere Strategien nutzen.
Aufgrund der einfachen Testbarkeit der Geschäftslogik sowie des möglichen Austausches mit Platzhaltern für Widget-Tests wird die Testbarkeit mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\paragraph{\nameref*{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\lstinputlisting[caption={Anzahl der Rendervorgänge bei BLoC}]{results/bloc/benchmarks.txt}
\paragraph{\nameref{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:bloc}) ergab eine \ac{mi} von 82 für das gesamte Projekt.
\paragraph{\nameref*{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:bloc}) ergab ein \ac{mi} von 82 für das gesamte Projekt.
\paragraph{\nameref{sec:readability}} Die Verständlichkeit und Lesbarkeit bei \ac{bloc} wird anhand der in \autoref{sec:readability} beschriebenen Fragestellungen bewertet.
\paragraph{\nameref*{sec:readability}} Die Verständlichkeit und Lesbarkeit bei BLoC wird anhand der in \autoref{sec:readability} beschriebenen Fragestellungen bewertet.
Zur Verwendung von \ac{bloc} ist es erforderlich, dass man sich mit Konzepten der asynchronen Programmierung beschäftigt, um die Funktionsweise von \texttt{Stream}s und \texttt{Sink}s verstehen zu können. Diese werden in der Flutter-Programmierung sonst selten benötigt. Daher ist davon auszugehen, dass Entwickler*innen diese erst lernen müssen.
Zur Verwendung von BLoC ist es erforderlich, dass man sich mit Konzepten der asynchronen Programmierung beschäftigt, um die Funktionsweise von \texttt{Stream}s und \texttt{Sink}s verstehen zu können. Diese werden in der Flutter-Programmierung sonst selten benötigt. Daher ist davon auszugehen, dass Entwickler*innen diese erst lernen müssen.
Die Struktur der BLoC selber ist schwer nachvollziehbar, da die Kombination von Streams, Sinks und Variablen nicht auf den ersten Blick nachvollziehbar ist. Zudem sind die Schnittstellen zur Benutzeroberfläche nicht wie andere Schnittstellen den Sprachfluss angepasst, sondern werden bestimmt durch die jeweiligen Funktionen von \texttt{Stream}s und \texttt{Sink}s. Außerdem benötigt dieser Ansatz eine Großzahl von Klassen, um beispielsweise Argumente von Ereignissen und Zustände abbilden zu können. Dies erschwert zusätzlich die Lesbarkeit, wie auch von \citeauthor{experienceofdevelopingflutter} festgestellt wurde. \autocite[573]{experienceofdevelopingflutter}
Die tiefe Verschachtlung von Widgets kann bei \ac{bloc} nicht beobachtet werden, da hier nicht das Widget-System als Grundlage zum Einsatz kommt. Allerdings verlangt die Verwendung von \texttt{Stream}s den Einsatz von \texttt{Stream\-Builder}n in der Benutzeroberfläche, wie bereits in \autoref{lst:streambuilder} gezeigt wird. Dies gibt zwar auf der einen Seite große Kontrolle über die Verarbeitung von Zustandsänderungen, macht den Quelltext allerdings schwer lesbar, besonders bei der Verwendung von mehreren \texttt{StreamBuilder}n ineinander.
Die tiefe Verschachtlung von Widgets kann bei BLoC nicht beobachtet werden, da hier nicht das Widget-System als Grundlage zum Einsatz kommt. Allerdings verlangt die Verwendung von \texttt{Stream}s den Einsatz von \texttt{Stream\-Builder}n in der Benutzeroberfläche, wie bereits in \autoref{lst:streambuilder} gezeigt wird. Dies gibt zwar auf der einen Seite große Kontrolle über die Verarbeitung von Zustandsänderungen, macht den Quelltext allerdings schwer lesbar, besonders bei der Verwendung von mehreren \texttt{StreamBuilder}n ineinander.
Zusammenfassend wird die Verständlichkeit und Lesbarkeit mit der Bewertung \textquote{nicht erfüllt} bewertet.
\paragraph{\nameref{sec:documentation}} Die Dokumentation von \ac{bloc} ist schwierig zu bewerten, da es sich bei \ac{bloc} lediglich um ein Konzept handelt. Allerdings gibt es Bibliotheken, welche das Konzept mit Hilfs-Konstrukten versehen und so den Einsatz von \ac{bloc} einfacher machen. Die Dokumentation dieser Bibliotheken umfasst umfangreiche Erklärungen und Beispiele \autocite{blocLib}, die auch auf \ac{bloc} an sich übertragbar sind.
\paragraph{\nameref*{sec:documentation}} Die Dokumentation von BLoC ist schwierig zu bewerten, da es sich bei BLoC lediglich um ein Konzept handelt. Allerdings gibt es Bibliotheken, welche das Konzept mit Hilfs-Konstrukten versehen und so den Einsatz von BLoC einfacher machen. Die Dokumentation dieser Bibliotheken umfasst umfangreiche Erklärungen und Beispiele \autocite{blocLib}, die auch auf BLoC an sich übertragbar sind.
Zusätzlich bestehen eine große Anzahl an Artikeln und anderen Veröffentlichungen zum Thema \ac{bloc}.
Zusätzlich bestehen eine große Anzahl an Artikeln und anderen Veröffentlichungen zum Thema BLoC.
Aufgrund der umfangreichen Dokumentation der beschriebenen Bibliothek und der Großzahl an Veröffentlichungen zu \ac{bloc}, wird die Dokumentation mit \textquote{vollständig erfüllt} bewertet.
Aufgrund der umfangreichen Dokumentation der beschriebenen Bibliothek und der Großzahl an Veröffentlichungen zu BLoC, wird die Dokumentation mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:structure}} Zur Strukturbestimmung lässt sich sagen, dass \ac{bloc} strikte Vorgaben zur Konstruktion von \ac{bloc} macht, aber viele Aspekte wie die Injection in Widgets oder die Dependency Injection innerhalb der \ac{bloc}s unbeantwortet bleibt. Eine technische Forcierung der Struktur eines \ac{bloc} ist nur teilweise erkennbar, da die Verwendung von \texttt{StreamBuilder} die Existenz von \texttt{Stream}s voraussetzt. Weitere technische Forcierungen der Struktur sind auch mangels des Einsatzes einer Bibliothek nicht zu erkennen.
\paragraph{\nameref*{sec:structure}} Zur Strukturbestimmung lässt sich sagen, dass BLoC strikte Vorgaben zur Konstruktion von BLoC macht, aber viele Aspekte wie die Injection in Widgets oder die Dependency Injection innerhalb der BLoCs unbeantwortet bleibt. Eine technische Forcierung der Struktur eines BLoC ist nur teilweise erkennbar, da die Verwendung von \texttt{StreamBuilder} die Existenz von \texttt{Stream}s voraussetzt. Weitere technische Forcierungen der Struktur sind auch mangels des Einsatzes einer Bibliothek nicht zu erkennen.
Daher wird die Strukturbestimmung mit \textquote{teilweise erfüllt} bewertet.

6
chapters/evaluation/evaluation.tex

@ -34,14 +34,14 @@ Die Ergebnisse der Evaluation sind in der \autoref{tbl:results} übersichtlich z @@ -34,14 +34,14 @@ Die Ergebnisse der Evaluation sind in der \autoref{tbl:results} übersichtlich z
\label{tbl:results}}\\
\toprule
Zustandsverwaltung & \rot{Änderbarkeit/Skalierbarkeit} & \rot{Testbarkeit} &
\rot{Effizienz} & \rot{Komplexität/Wartbarkeit} & \rot{Verständlichkeit/Lesbarkeit} &
\rot{Effizienz (in Rendervorgängen)} & \rot{Komplexität/Wartbarkeit (in MI)} & \rot{Verständlichkeit/Lesbarkeit} &
\rot{Dokumentierung} & \rot{Strukturbestimmung} \\
\midrule
\endhead
ohne Zustandsverwaltung & n. a. & n. a. & 1;2 & 83 & n. a. & n. a. & n.a. \\
setState & \multicolumn{7}{c}{nicht umsetzbar} \\
\texttt{Inherited\-Widget} & / & / & 8;6 & 83 & \xmark & / & \xmark \\
\ac{bloc} & \cmark & \cmark & 8;4 & 82 & \xmark & \cmark & / \\
Inherited\-Widget & / & / & 8;6 & 83 & \xmark & / & \xmark \\
BLoC & \cmark & \cmark & 8;4 & 82 & \xmark & \cmark & / \\
Provider & / & \cmark & 3;4 & 83 & / & \cmark & \xmark \\
Riverpod & \cmark & \cmark & 3;4 & 80 & \cmark & \cmark & \xmark \\
Redux & \xmark & / & 8;10 & 82 & / & \cmark & \cmark \\

14
chapters/evaluation/inheritedwidget.tex

@ -15,7 +15,7 @@ Der Funktionsumfang konnte dabei ohne Einschränkungen vollständig implementier @@ -15,7 +15,7 @@ Der Funktionsumfang konnte dabei ohne Einschränkungen vollständig implementier
Im folgenden Abschnitt wird die Implementierung mit \texttt{Inherited\-Widget} \autocite[branch=inheritedwidget]{repo} anhand der definierten Bewertungskriterien bewertet.
\paragraph{\nameref{sec:changeablility}} Bei der Änderbarkeit und Skalierbarkeit wird dieses Zustandsverwaltungssystem mit \textquote{teilweise erfüllt} bewertet.
\paragraph{\nameref*{sec:changeablility}} Bei der Änderbarkeit und Skalierbarkeit wird dieses Zustandsverwaltungssystem mit \textquote{teilweise erfüllt} bewertet.
Eines der Merkmale von skalierbaren und änderbaren Zustandsverwaltungssystemen ist es, dass sich mehrere Zustände untereinander verknüpfen lassen. Dies ist hier eingeschränkt möglich, da um auf einen anderen Zustand zuzugreifen es erforderlich ist, dass dieser im Widget-Baum oberhalb des zugreifenden Zustandswidgets angeordnet ist. Falls dies der Fall ist, lässt sich der Zustand aber wie bei der Benutzeroberfläche (vgl. \autoref{sec:inheritedWidget}) über einen Methoden-Aufruf abrufen.
@ -23,7 +23,7 @@ Negativ bewertet wird hier aber die Tatsache, dass ein Zustand beziehungsweise S @@ -23,7 +23,7 @@ Negativ bewertet wird hier aber die Tatsache, dass ein Zustand beziehungsweise S
Ein weiter Nachteil ist es, dass es erforderlich ist, im \texttt{Inherited\-Widget} eine Methode zu implementieren, die feststellt, ob sich der Zustand im Vergleich zu einem anderen Zustand verändert hat. Dies wird bei wachsender Größe oder Datenstrukturkomplexität eines Zustands unübersichtlich und auch komplex.
\paragraph{\nameref{sec:testability}} Zur Bewertung der Testbarkeit wurden mehrere Tests entsprechend der Anforderungen implementiert.
\paragraph{\nameref*{sec:testability}} Zur Bewertung der Testbarkeit wurden mehrere Tests entsprechend der Anforderungen implementiert.
Das Testen der Geschäftslogik der Stores stellte sich als komplex heraus, da hier keine Unit-Tests, sondern Widget-Tests vonnöten waren. Dies hat auch zur Folge, dass man sich während der Tests auch um den Lebenszyklus der Widgets kümmern muss. So muss man im Test die Hilfs-Funktion \texttt{tester.pump()}, wie in \autoref{lst:testabilityInheritedWidget} zu sehen ist, zum richtigen Moment aufrufen, damit das Framework die Zustandsänderungen umsetzt.
@ -48,12 +48,12 @@ Die Tests für Widgets, die den Zustand konsumieren auf der anderen Hand sind ei @@ -48,12 +48,12 @@ Die Tests für Widgets, die den Zustand konsumieren auf der anderen Hand sind ei
Abschließend erfolgt hier die Bewertung mit \textquote{teilweise erfüllt}.
\paragraph{\nameref{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\paragraph{\nameref*{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\lstinputlisting[caption={Anzahl der Rendervorgänge bei InheritedWidget}]{results/inheritedwidget/benchmarks.txt}
\paragraph{\nameref{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:inheritedwidget}) ergab eine \ac{mi} von 83 für das gesamte Projekt.
\paragraph{\nameref*{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:inheritedwidget}) ergab ein \ac{mi} von 83 für das gesamte Projekt.
\paragraph{\nameref{sec:readability}} Bei der Bewertung der Lesbarkeit sind mehrere Faktoren wichtig.
\paragraph{\nameref*{sec:readability}} Bei der Bewertung der Lesbarkeit sind mehrere Faktoren wichtig.
Der erste Faktor ist die Frage, ob neue Konzepte eingeführt werden. Diese Frage kann mit Nein beantwortet werden, da hier ausschließlich Komponenten aus dem Flutter-Framework in Form verschiedener Widgetes zum Einsatz kommen.
@ -74,11 +74,11 @@ return UserStoreImplementation( @@ -74,11 +74,11 @@ return UserStoreImplementation(
Zusammengefasst wird die Verständlichkeit/Lesbarkeit mit \textquote{nicht erfüllt} bewertet.
\paragraph{\nameref{sec:documentation}} Die Dokumentation gibt ein zwiegespaltenes Bild ab, da zum einen die einzelnen Widget-Typen an sich ausführlich beschrieben werden, allerdings das Zusammenspiel als Zustandsverwaltungssystem als Ganzes in der offiziellen Entwicklerdokumentation gar nicht beleuchtet wird. Dieses Zusammenspiel wird lediglich in Ressourcen, außerhalb der Dokumentation beschrieben. Somit fehlen auch umfangreiche Beispiele, wie das Zustandsverwaltungssystem implementiert oder genutzt werden kann.
\paragraph{\nameref*{sec:documentation}} Die Dokumentation gibt ein zwiegespaltenes Bild ab, da zum einen die einzelnen Widget-Typen an sich ausführlich beschrieben werden, allerdings das Zusammenspiel als Zustandsverwaltungssystem als Ganzes in der offiziellen Entwicklerdokumentation gar nicht beleuchtet wird. Dieses Zusammenspiel wird lediglich in Ressourcen, außerhalb der Dokumentation beschrieben. Somit fehlen auch umfangreiche Beispiele, wie das Zustandsverwaltungssystem implementiert oder genutzt werden kann.
Aufgrund der großen Bandbreite an Dritt-Ressourcen zu \texttt{Inherited\-Widgets} erfolgt hier noch eine Bewertung mit \textquote{teilweise erfüllt}.
\paragraph{\nameref{sec:structure}}
\paragraph{\nameref*{sec:structure}}
Das Konzept mit \texttt{Inherited\-Widgets} stellt keine starren Strukturvorgaben an die Anwendung. Lediglich das Zusammenspiel zwischen \texttt{Inherited\-Widget} und \texttt{Stateful\-Widget} wird dadurch forciert, dass \texttt{Inherited\-Widgets} von sich aus ihren Zustand nicht ändern können. Dies hat allerdings keinen Einfluss auf die Gesamtarchitektur der Anwendung, das \texttt{Inherited\-Widget} und \texttt{Stateful\-Widget} als gemeinsame Komponente betrachtet werden können.

14
chapters/evaluation/mobx.tex

@ -15,13 +15,13 @@ Die Stores werden über ein \texttt{Inherited\-Widget} in die Widget-Tree überg @@ -15,13 +15,13 @@ Die Stores werden über ein \texttt{Inherited\-Widget} in die Widget-Tree überg
Im folgenden Abschnitt wird die Implementierung mit MobX \autocite[branch=\\mobx]{repo} anhand der definierten Bewertungskriterien bewertet.
\paragraph{\nameref{sec:changeablility}} Zur Skalierbarkeit lässt sich sagen, dass hier keine Hindernisse bei der Skalierbarkeit festgestellt werden konnten. So lassen sich beliebig viele Zustände miteinander koppeln, da hier ein einfacher Zugriff auf Observable-Variablen genügt, um Zustandsaktualisierungen zu erhalten.
\paragraph{\nameref*{sec:changeablility}} Zur Skalierbarkeit lässt sich sagen, dass hier keine Hindernisse bei der Skalierbarkeit festgestellt werden konnten. So lassen sich beliebig viele Zustände miteinander koppeln, da hier ein einfacher Zugriff auf Observable-Variablen genügt, um Zustandsaktualisierungen zu erhalten.
Zur Änderbarkeit lässt sich sagen, dass hier zwar keine Abstraktionsschicht wie bei Provider oder Riverpod existiert, aber spätere Änderungen sich durch die Verwendung von beispielsweise Computed-Values ausgleichen lässt und somit eine Rückwärtskompatibilität gewährleistet werden kann.
Aufgrund der einfachen Kopplung von Zuständen und der Änderbarkeit wird MobX hier mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:testability}} Bei der Testbarkeit wird zum einen geprüft, inwiefern sich die Geschäftslogik testen lässt, und wie sich die Zustände bei Widget-Tests durch Platzhalter ersetzen lassen.
\paragraph{\nameref*{sec:testability}} Bei der Testbarkeit wird zum einen geprüft, inwiefern sich die Geschäftslogik testen lässt, und wie sich die Zustände bei Widget-Tests durch Platzhalter ersetzen lassen.
Die Tests der Geschäftslogik konnten ohne zusätzliche Maßnahmen implementiert werden, da nach außen hin hier eine Klasse mit Variablen und Funktionen existiert, die sich mit den Mitteln eines Unit-Test testen lässt.
@ -29,12 +29,12 @@ Bei den Widget-Tests ist es nötig, die Store-Klasse mit neuen Platzhalter-Klass @@ -29,12 +29,12 @@ Bei den Widget-Tests ist es nötig, die Store-Klasse mit neuen Platzhalter-Klass
Die Testbarkeit wird mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\paragraph{\nameref*{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\lstinputlisting[caption={Anzahl der Rendervorgänge bei MobX}]{results/mobx/benchmarks.txt}
\paragraph{\nameref{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:mobx}) ergab eine \ac{mi} von 83 für das gesamte Projekt.
\paragraph{\nameref*{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:mobx}) ergab ein \ac{mi} von 83 für das gesamte Projekt.
\paragraph{\nameref{sec:readability}} Zur Verständlichkeit und Lesbarkeit lässt sich sagen, dass mit MobX hier ein Ansatz verfolgt wird, der zur Lesbarkeit beiträgt, da hier mithilfe der Annotationen wie \texttt{computed} der Sprachfluss beim Lesen unterstützt wird. Zusätzlich beinhalten die Zustandsklassen nur die tatsächlich notwendige Geschäftslogik und Prozeduren für die Zustandsverwaltung werden mittels Quelltext-Generierung ausgelagert. Somit ist die Struktur nachvollziehbar und klar.
\paragraph{\nameref*{sec:readability}} Zur Verständlichkeit und Lesbarkeit lässt sich sagen, dass mit MobX hier ein Ansatz verfolgt wird, der zur Lesbarkeit beiträgt, da hier mithilfe der Annotationen wie \texttt{computed} der Sprachfluss beim Lesen unterstützt wird. Zusätzlich beinhalten die Zustandsklassen nur die tatsächlich notwendige Geschäftslogik und Prozeduren für die Zustandsverwaltung werden mittels Quelltext-Generierung ausgelagert. Somit ist die Struktur nachvollziehbar und klar.
Die Quelltext-Generierung kann allerdings auch ein Risiko darstellen, da Fehler oder Probleme im generierten Quelltext schwer nachzuvollziehen sind und der generierte Quelltext schwer lesbar ist.
@ -44,11 +44,11 @@ Die tiefe Verschachtlung wird bei MobX verhindert, indem hier zur Zustandsverwal @@ -44,11 +44,11 @@ Die tiefe Verschachtlung wird bei MobX verhindert, indem hier zur Zustandsverwal
Die Verständlichkeit und Lesbarkeit wird mit \textquote{vollständig erfüllt} bewertet, allerdings sollte das Risko der Quelltext-Generierung bei einer Entscheidung miteinbezogen werden.
\paragraph{\nameref{sec:documentation}} Die Dokumentation \autocite{mobxDocs} von MobX beschreibt die Grundkonzepte des Zustandsverwaltungssystems und ergänzt diese ebenfalls mit umfangreichen Anwendungsbeispielen. Zusätzlich zur offiziellen Dokumentation existieren noch diverse Drittveröffentlichungen zu MobX und die Dokumentation zur JavaScript-Variante von MobX kann ebenfalls in Teilen für Dart adaptiert werden.
\paragraph{\nameref*{sec:documentation}} Die Dokumentation \autocite{mobxDocs} von MobX beschreibt die Grundkonzepte des Zustandsverwaltungssystems und ergänzt diese ebenfalls mit umfangreichen Anwendungsbeispielen. Zusätzlich zur offiziellen Dokumentation existieren noch diverse Drittveröffentlichungen zu MobX und die Dokumentation zur JavaScript-Variante von MobX kann ebenfalls in Teilen für Dart adaptiert werden.
Die Dokumentierung wird daher mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:structure}} Zur Strukturbestimmung lässt sich sagen, dass MobX über die Annotationen und Quelltext-Generierung eine gewisse Struktur der Zustände vorgibt, allerdings leitet sich daraus keine Struktur für die gesamte Anwendung ab.
\paragraph{\nameref*{sec:structure}} Zur Strukturbestimmung lässt sich sagen, dass MobX über die Annotationen und Quelltext-Generierung eine gewisse Struktur der Zustände vorgibt, allerdings leitet sich daraus keine Struktur für die gesamte Anwendung ab.
Technisch forciert, wird die Struktur der Zustände in Teilen durch die Quell\-text-Generierung, wenn von Vorgaben abgewichen wird. So schlägt beispielsweise die Quell\-text-Generierung fehl, wenn man versucht, Funktionen mit Parametern als \texttt{computed} zu markieren.

14
chapters/evaluation/provider.tex

@ -13,7 +13,7 @@ In die Benutzeroberfläche eingebunden, werden die Provider über diverse Exten\ @@ -13,7 +13,7 @@ In die Benutzeroberfläche eingebunden, werden die Provider über diverse Exten\
Im folgenden Abschnitt wird die Implementierung mit Provider \autocite[branch=\\provider]{repo} anhand der definierten Bewertungskriterien bewertet.
\paragraph{\nameref{sec:changeablility}}
\paragraph{\nameref*{sec:changeablility}}
Das Thema Skalierbarkeit und Änderbarkeit zeigt sich als ambivalent bei Providern. Bei der Änderbarkeit muss man sagen, dass hier Provider einen Vorteil bietet, da durch das Konzept der Provider eine einheitliche Abstraktion für Zustandsverwaltungen geschaffen werden. Somit ist es nicht von Belang, ob ein Zustand über einen Stream, Future oder einen ChangeNotifier abgebildet werden. Dies bietet damit einen Vorteil für Änderbarkeit, da sich Zustände zu einem späteren Zeitpunkt einfach auf ein anderes Zustandsverwaltungsmodell abändern lassen, ohne das Anpassungen außerhalb dieses Zustands vonnöten wären.
@ -23,7 +23,7 @@ Zur Skalierbarkeit lässt sich sagen, dass in der Dokumentation bereits Limitati @@ -23,7 +23,7 @@ Zur Skalierbarkeit lässt sich sagen, dass in der Dokumentation bereits Limitati
Aufgrund der eingeschränkten Skalierbarkeit, wird die Änderbarkeit/Skalierbarkeit mit \textquote{teilweise erfüllt} bewertet.
\paragraph{\nameref{sec:testability}} Zur Testbarkeit lässt sich sagen, dass sowohl die Geschäftslogik als auch verwendende Widgets sich ohne Änderungen am Quelltext der Anwendung testen lassen.
\paragraph{\nameref*{sec:testability}} Zur Testbarkeit lässt sich sagen, dass sowohl die Geschäftslogik als auch verwendende Widgets sich ohne Änderungen am Quelltext der Anwendung testen lassen.
Bei der Geschäftslogik lassen sich die Zustandsklassen komplett ohne die Verwendung von Flutter oder von Provider an sich testen. Somit ist es auch nicht nötig, etwaige Abhängigkeiten zu mocken oder Widget-Tests zu benutzen.
@ -52,12 +52,12 @@ void main() { @@ -52,12 +52,12 @@ void main() {
Da sowohl Widget-Tests als Geschäftslogik-Tests implementierbar waren, \\wird die Testbarkeit mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\paragraph{\nameref*{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\lstinputlisting[caption={Anzahl der Rendervorgänge bei Provider}]{results/provider/benchmarks.txt}
\paragraph{\nameref{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:provider}) ergab eine \ac{mi} von 83 für das gesamte Projekt.
\paragraph{\nameref*{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:provider}) ergab ein \ac{mi} von 83 für das gesamte Projekt.
\paragraph{\nameref{sec:readability}} Die Verständlichkeit und Lesbarkeit lässt sich hier anhand mehrerer Aspekte bewerten.
\paragraph{\nameref*{sec:readability}} Die Verständlichkeit und Lesbarkeit lässt sich hier anhand mehrerer Aspekte bewerten.
Bei Provider werden hauptsächlich bereits bestehende Konzepte von Flutter erweitert. Dies kann beispielsweise an der Injizierung der Zustandsklassen in Widgets beobachtet werden. Hier wird eine ähnliche Syntax wie bei anderen Flutter-Komponenten genutzt wie auch im Beispiel in \autoref{lst:providerof} zu sehen ist. Jedoch muss hier auch angemerkt werden, dass es empfehlenswert ist, immer eine Zustandsklasse zu erstellen, auch wenn die an die Widgets zu übergebenden Zustände einem trivialen Datentyp wie einem \texttt{String} entsprechen, da für das Injizieren immer der Klassen-Name der zu injizierenden Klasse verwendet wird. So ist es also nicht möglich, mehrere Zustände vom Type \texttt{String} gleichzeitig zu verwenden. Diese zusätzlichen Klassen können somit die Lesbarkeit erschweren.
@ -77,10 +77,10 @@ Der letzte untersuchte Aspekt, ist, ob das Zustandsverwaltungssystem, der tiefen @@ -77,10 +77,10 @@ Der letzte untersuchte Aspekt, ist, ob das Zustandsverwaltungssystem, der tiefen
Zusammenfassend wird dieser Bewertungsaspekt mit \textquote{teilweise erfüllt} bewertet.
\paragraph{\nameref{sec:documentation}} Zur Dokumentation \autocite[siehe][]{providerReadme} lässt sich sagen, das diese die Grundkonzepte verständlich erklärt und zusätzlich umfangreiche Beispiele beinhaltet. Jedoch ist die Struktur als einzelne Markdown-Datei nicht übersichtlich. Zusätzlich gibt es einen großen Umfang an Drittveröffentlichungen unter anderem in der offiziellen Flutter-Dokumentation.
\paragraph{\nameref*{sec:documentation}} Zur Dokumentation \autocite[siehe][]{providerReadme} lässt sich sagen, das diese die Grundkonzepte verständlich erklärt und zusätzlich umfangreiche Beispiele beinhaltet. Jedoch ist die Struktur als einzelne Markdown-Datei nicht übersichtlich. Zusätzlich gibt es einen großen Umfang an Drittveröffentlichungen unter anderem in der offiziellen Flutter-Dokumentation.
Die Dokumentierung wird mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:structure}} Zur Strukturbestimmung lässt sich sagen, dass Provider keinen wesentlichen Einfluss auf die Struktur der Anwendung hat. Zudem gibt sie kein einheitliches Vorgehensmodell bei der Implementierung einer Zustandsklasse vor, da hier wie bereits beschrieben, aus mehreren möglichen Modellen wie ChangeNotifier oder Stream gewählt werden kann.
\paragraph{\nameref*{sec:structure}} Zur Strukturbestimmung lässt sich sagen, dass Provider keinen wesentlichen Einfluss auf die Struktur der Anwendung hat. Zudem gibt sie kein einheitliches Vorgehensmodell bei der Implementierung einer Zustandsklasse vor, da hier wie bereits beschrieben, aus mehreren möglichen Modellen wie ChangeNotifier oder Stream gewählt werden kann.
Daher wird die Strukturbestimmung mit \textquote{nicht erfüllt} bewertet.

16
chapters/evaluation/redux.tex

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
\section{Redux}
\label{eval:redux}
Riverpod stellt eine externe Bibliothek zur Zustandsverwaltung dar, welche auf Ansätzen aus dem React-Umfeld basiert. Die Grundlagen dazu sind im \autoref{sec:redux} nachzuvollziehen.
Redux stellt eine externe Bibliothek zur Zustandsverwaltung dar, welche auf Ansätzen aus dem React-Umfeld basiert. Die Grundlagen dazu sind im \autoref{sec:redux} nachzuvollziehen.
\subsection{Implementierung}
@ -17,7 +17,7 @@ Für die Einbindung in die Benutzeroberfläche kommen zwei verschiedene Möglich @@ -17,7 +17,7 @@ Für die Einbindung in die Benutzeroberfläche kommen zwei verschiedene Möglich
Im folgenden Abschnitt wird die Implementierung mit Redux \autocite[branch=\\redux]{repo} anhand der definierten Bewertungskriterien bewertet.
\paragraph{\nameref{sec:changeablility}} Die Änderbarkeit und Skalierbarkeit bei Redux lässt sich anhand verschiedener Aspekte beschreiben.
\paragraph{\nameref*{sec:changeablility}} Die Änderbarkeit und Skalierbarkeit bei Redux lässt sich anhand verschiedener Aspekte beschreiben.
Ein Problem für die Skalierbarkeit kann der zentrale Zustand werden. Dieser besteht aus einer Klasse, die den gesamten Zustand der App abbilden soll. Bei großen Apps, könnte dieses Konzept an seine Grenzen kommen, besonders, wenn eine Anwendung aus mehreren Modulen besteht.
@ -27,7 +27,7 @@ Um die Reducer besser strukturieren zu können, bietet die Bibliothek, Reducer e @@ -27,7 +27,7 @@ Um die Reducer besser strukturieren zu können, bietet die Bibliothek, Reducer e
Zusammenfassend wird die Skalierbarkeit und Änderbarkeit mit \textquote{nicht erfüllt} bewertet.
\paragraph{\nameref{sec:testability}} Für die Testbarkeit werden zum einen Tests der Geschäftslogik und zum anderen Tests von Widgets, die auf den Store zugreifen bewertet.
\paragraph{\nameref*{sec:testability}} Für die Testbarkeit werden zum einen Tests der Geschäftslogik und zum anderen Tests von Widgets, die auf den Store zugreifen bewertet.
Für die Tests der Geschäftslogik ist es ausreichend, den Store manuell zu erstellen und die gewünschte Action zu depeschieren. Anschließend kann anhand des zentralen Zustands geprüft werden, ob das gewünschte Ergebnis eingetreten ist.
@ -37,12 +37,12 @@ Der zentrale Zustand sollte selbst keine Geschäftslogik beinhalten und lässt s @@ -37,12 +37,12 @@ Der zentrale Zustand sollte selbst keine Geschäftslogik beinhalten und lässt s
Aufgrund der Probleme beim Testen der Middlewares, wird die Testbarkeit mit \textquote{teilweise erfüllt} bewertet.
\paragraph{\nameref{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\paragraph{\nameref*{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\lstinputlisting[caption={Anzahl der Rendervorgänge bei Redux}]{results/redux/benchmarks.txt}
\paragraph{\nameref{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:redux}) ergab eine \ac{mi} von 82 für das gesamte Projekt.
\paragraph{\nameref*{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:redux}) ergab ein \ac{mi} von 82 für das gesamte Projekt.
\paragraph{\nameref{sec:readability}} Die Verständlichkeit und Lesbarkeit wird anhand der definierten Aspekte bewertet.
\paragraph{\nameref*{sec:readability}} Die Verständlichkeit und Lesbarkeit wird anhand der definierten Aspekte bewertet.
Redux bringt mit dem aus dem React-Ökosystem stammenden Konzept ein völlig neues Konzept in das Flutter-Ökosystem. Begriffe wie Reducer, Action und Middlewares spielen außerhalb von Redux in Flutter sonst nur eine untergeordnete Rolle. Somit müssen Entwickler*innen hier sich vor der Benutzung zuerst mit diesem Konzept beschäftigen, was für die Verständlichkeit nicht dienlich ist.
@ -52,11 +52,11 @@ Das Problem der tiefen Verschachtlung findet bei Redux keine Anwendung, da hier @@ -52,11 +52,11 @@ Das Problem der tiefen Verschachtlung findet bei Redux keine Anwendung, da hier
Die Verständlich und Lesbarkeit wird abschließend mit \textquote{teilweise erfüllt} bewertet.
\paragraph{\nameref{sec:documentation}} Die Dokumentation \autocite{reduxDocs} von Redux beschreibt die grundlegenden Konzepte, sowie verweist für detaillierte Erklärungen auf die Dokumentation von Redux für React. Zudem existieren in der Dokumentation detaillierte Anwendungsbeispiele. Zusätzlich zur offiziellen Dokumentation, gibt es eine große Zahl an Publikationen für Redux für React, die in großen Teilen anwendbar auf die Flutter-Umsetzung von Redux sind.
\paragraph{\nameref*{sec:documentation}} Die Dokumentation \autocite{reduxDocs} von Redux beschreibt die grundlegenden Konzepte, sowie verweist für detaillierte Erklärungen auf die Dokumentation von Redux für React. Zudem existieren in der Dokumentation detaillierte Anwendungsbeispiele. Zusätzlich zur offiziellen Dokumentation, gibt es eine große Zahl an Publikationen für Redux für React, die in großen Teilen anwendbar auf die Flutter-Umsetzung von Redux sind.
Die Dokumentierung wird daher mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:structure}} Redux bestimmt die Struktur der Anwendung klar mit, da durch die feste Aufteilung in die bereits bestehenden Elemente wie Reducer oder Action, eine Struktur sich impliziert.
\paragraph{\nameref*{sec:structure}} Redux bestimmt die Struktur der Anwendung klar mit, da durch die feste Aufteilung in die bereits bestehenden Elemente wie Reducer oder Action, eine Struktur sich impliziert.
Technisch wird diese zusätzlich forciert, indem über die Bibliothek geprüft wird, ob beispielsweise die Reducer der geforderten Struktur entsprechen. Zusätzlich kann damit sichergestellt werden, dass Reducer immer ausschließlich synchrone Prozeduren durchführen.

16
chapters/evaluation/riverpod.tex

@ -15,7 +15,7 @@ Die Einbindung in die Benutzeroberfläche erfolgte mittels ConsumerWidget. Dafü @@ -15,7 +15,7 @@ Die Einbindung in die Benutzeroberfläche erfolgte mittels ConsumerWidget. Dafü
Im folgenden Abschnitt wird die Implementierung mit Riverpod \autocite[branch=\\riverpod]{repo} anhand der definierten Bewertungskriterien bewertet.
\paragraph{\nameref{sec:changeablility}} Zur Änderbarkeit und Skalierbarkeit bei Riverpod lassen sich Parallelen zu Provider ziehen, da hier ähnliche Konzepte zum Einsatz kommen. So bietet Riverpod auch eine einheitliche Abstraktionsschicht für Zustände und kann somit ChangeNotifier, StateNotifier, Futures, Streams und einfache Werte als Zustand verwalten. Somit werden Änderungen in der Zukunft vereinfacht, da nur die jeweiligen Zustände und Provider angepasst werden müssen und nicht die davon abhängigen Zustände und andere Komponenten.
\paragraph{\nameref*{sec:changeablility}} Zur Änderbarkeit und Skalierbarkeit bei Riverpod lassen sich Parallelen zu Provider ziehen, da hier ähnliche Konzepte zum Einsatz kommen. So bietet Riverpod auch eine einheitliche Abstraktionsschicht für Zustände und kann somit ChangeNotifier, StateNotifier, Futures, Streams und einfache Werte als Zustand verwalten. Somit werden Änderungen in der Zukunft vereinfacht, da nur die jeweiligen Zustände und Provider angepasst werden müssen und nicht die davon abhängigen Zustände und andere Komponenten.
Im Gegensatz zu Provider wurde hier nicht der Weg der Injection via Generics gewählt, sondern auf Variablen gesetzt. Dies hat den Vorteil, dass mehrere Zustände vom gleichen Datentyp existieren können und es immer Sichergestellt ist, dass ein entsprechender Provider überhaupt im verwalteten Gesamtzustand existiert.
@ -25,7 +25,7 @@ Auch bei der Koppelung verschiedener Zustände wird hier ein anderer Weg gegange @@ -25,7 +25,7 @@ Auch bei der Koppelung verschiedener Zustände wird hier ein anderer Weg gegange
Aufgrund der Verbesserungen bei der Skalierbarkeit und Änderbarkeit gegenüber Provider wird diese mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:testability}} Zur Bewertung der Testbarkeit wird zum einen geprüft, inwiefern sich die Geschäftslogik der einzelnen Zustandsklassen testen lässt, und inwiefern es möglich ist, verteilte Zustände bei Widget-Tests durch Platzhalter zu ersetzen.
\paragraph{\nameref*{sec:testability}} Zur Bewertung der Testbarkeit wird zum einen geprüft, inwiefern sich die Geschäftslogik der einzelnen Zustandsklassen testen lässt, und inwiefern es möglich ist, verteilte Zustände bei Widget-Tests durch Platzhalter zu ersetzen.
Die Tests der Geschäftslogik sind ohne Probleme implementierbar. Hier kann komplett auf die Verwendung von Riverpod oder Flutter verzichtet werden, da die Zustandsklassen auch unabhängig von dem Zustandsverwaltungssystem ihre Geschäftslogik behalten. Somit wird hier ein einfacher Unit-Test, welcher die Funktion einer Klasse oder deren Funktionen testet implementiert.
@ -49,16 +49,16 @@ Bei den Widget-Tests bietet Riverpod die Möglichkeit an, beliebig viele Provide @@ -49,16 +49,16 @@ Bei den Widget-Tests bietet Riverpod die Möglichkeit an, beliebig viele Provide
Die Testbarkeit wird daher mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\paragraph{\nameref*{sec:efficiency}} Nach der Ausführung der Teststrecke ergaben die Zähler folgendes Ergebnis:
\lstinputlisting[caption={Anzahl der Rendervorgänge bei Riverpod}]{results/riverpod/benchmarks.txt}
\paragraph{\nameref{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:riverpod}) ergab eine \ac{mi} von 80 für das gesamte Projekt.
\paragraph{\nameref*{sec:complexity}} Die Auswertung der Metriken (vgl. \autoref{metrics:riverpod}) ergab ein \ac{mi} von 80 für das gesamte Projekt.
\paragraph{\nameref{sec:readability}} Zur Verständlichkeit und Lesbarkeit lassen sich mehrere Aspekte in die Bewertung miteinbeziehen.
\paragraph{\nameref*{sec:readability}} Zur Verständlichkeit und Lesbarkeit lassen sich mehrere Aspekte in die Bewertung miteinbeziehen.
Im Gegensatz zu Provider wird bei Riverpod eine neue Syntax zur Injizierung von Providern verwendet. Diese weicht leicht von der in Flutter gebräuchlichen Methodik, die in \autoref{lst:providerof} gezeigt wurde, ab. So muss wie bereits beschrieben die Basisklasse von zugreifenden Widgets geändert werden und über die Referenzvariable \texttt{ref} auf die Zustände zugegriffen werden. Ob dies jedoch schon ausreichend ist, um zu sagen, dass hier von Flutter abweichende Konzepte eingeführt werden, ist fraglich. Allerdings wird durch die Verwendung der Referenzvariable die Lesbarkeit vereinfacht, da so der Aufruf von \texttt{Provider.of<XY>()} entfallen kann.
Die Verwendung von Variablen anstatt Generics zum Abruf der Provider, erhöht die Verständlichkeit, da somit direkt aus dem Variabl-Namen klar wird, um was es sich handelt. Zudem besteht somit die Möglichkeit, mehere Provider mit dem gleichen Datentyp zu haben. Damit kann dann auf Wrapper-Klassen, verzichtet werden, die die Komplexität und damit die Lesbarkeit behindern.
Die Verwendung von Variablen anstatt Generics zum Abruf der Provider, erhöht die Verständlichkeit, da somit direkt aus dem Variabel-Namen klar wird, um was es sich handelt. Zudem besteht somit die Möglichkeit, mehere Provider mit dem gleichen Datentyp zu haben. Damit kann dann auf Wrapper-Klassen, verzichtet werden, die die Komplexität und damit die Lesbarkeit behindern.
Das neu eingeführte Konzept des StateNotifier bietet aus der Perspektive der Lesbarkeit und Verständlichkeit keine Vorteile, da damit die Zustands\-änderungs-Funktionen und der Inhalt des Zustands in getrennten Klassen behandelt werden, zudem muss zur Änderung des Zustands immer eine neue Instanz des Zustandsobjekts \texttt{state} gesetzt werden, was auf den ersten Blick verwirrend wirken kann. Die Vorteile des StateNotifier liegen eher in der Verbesserung der Performance, da hier bei jeder Zustandsänderung tatsächlich geprüft wird, ob die Zustandsvariable selbst sich tatsächlich geändert hat.
@ -68,10 +68,10 @@ Das Problem der tiefen Verschachtlung umgeht Riverpod damit, dass die Provider n @@ -68,10 +68,10 @@ Das Problem der tiefen Verschachtlung umgeht Riverpod damit, dass die Provider n
Da es neben dem StateNotifier auch die Möglichkeit gibt, wie bei Provider, ChangeNotifier einzusetzen, fällt dieser beschriebe Kritikpunkt nicht stark ins Gewicht, weshalb hier eine Bewertung mit \textquote{vollständig erfüllt} erfolgt.
\paragraph{\nameref{sec:documentation}} Die Dokumentation \autocite{riverpodDocs} von Riverpod beschreibt alle Grundkonzepte und beinhaltet diverse Anwendungsbeispiele. Zusätzlich ist ebenfalls dokumentiert, wie automatisierte Tests implementiert werden können. Die Dokumentation ist auch in deutscher Sprache verfügbar.
\paragraph{\nameref*{sec:documentation}} Die Dokumentation \autocite{riverpodDocs} von Riverpod beschreibt alle Grundkonzepte und beinhaltet diverse Anwendungsbeispiele. Zusätzlich ist ebenfalls dokumentiert, wie automatisierte Tests implementiert werden können. Die Dokumentation ist auch in deutscher Sprache verfügbar.
Die Dokumentierung wird mit \textquote{vollständig erfüllt} bewertet.
\paragraph{\nameref{sec:structure}} Ähnlich wie bei Provider lässt sich sagen, dass Riverpod keinen signifikanten Einfluss auf die Struktur der Anwendung hat. Daher kann dieser auch nicht technisch forciert werden.
\paragraph{\nameref*{sec:structure}} Ähnlich wie bei Provider lässt sich sagen, dass Riverpod keinen signifikanten Einfluss auf die Struktur der Anwendung hat. Daher kann dieser auch nicht technisch forciert werden.
Daher wird die Strukturbestimmung mit \textquote{nicht erfüllt} bewertet.

2
chapters/realisation/realisation.tex

@ -17,7 +17,7 @@ Bei der \nameref{sec:changeablility} ist es nötig, einen gewissen Grad von Kopp @@ -17,7 +17,7 @@ Bei der \nameref{sec:changeablility} ist es nötig, einen gewissen Grad von Kopp
Zur Überprüfung der \nameref{sec:testability} ist es erforderlich, Widgets so zu erstellen, dass sie im Rahmen der Implementierung von automatisierten Tests diese Implementierung nicht behindern. Zudem sollte es Anwendungsfälle geben, die auch die Verarbeitung von Zuständen erfordert, um eine gewisse Art von Geschäftslogik mit den Zustandsverwaltungssystemen implementieren und im Anschluss testen zu können.
Die Messung der \nameref{sec:efficiency} erfolgt an verschiedenen Messpunkten. Daher ist es erforderlich, Widgets zur Verfügung zu stellen, die dafür geeignet sind. Besonders gut geeignet sind dabei, Widgets, die außerhalb einer Listendarstellung sind, und somit unabhängig vom Rendering der Liste sind.
Die Messung der \nameref{sec:efficiency} erfolgt an verschiedenen Messpunkten. Daher ist es erforderlich, Widgets zur Verfügung zu stellen, die dafür geeignet sind. Besonders gut geeignet sind dabei Widgets, die außerhalb einer Listendarstellung sind, und somit unabhängig vom Rendering der Liste sind.
Um das Verhalten bei tiefer Verschachtlung (engl. nesting) für das Kriterium der \nameref{sec:readability} prüfen zu können, ist es erforderlich dieses zu provozieren. Am besten kann dies umgesetzt werden, indem es Seiten gibt, die mehrere voneinander unabhängige, seitenweite Zustände haben.

3
hdathesis-config.tex

@ -45,4 +45,5 @@ @@ -45,4 +45,5 @@
%\PassOptionsToPackage{spanish,es-lcroman}{babel}
\usepackage{babel}
\usepackage{acronym}
\usepackage{acronym}

Loading…
Cancel
Save