You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
7.9 KiB
85 lines
7.9 KiB
\section{InheritedWidget}
|
|
\label{eval:inheritedwidget}
|
|
|
|
Wie in \autoref{sec:inheritedWidget} beschrieben, stellen \texttt{Inherited\-Widgets} eine Option für die Zustandsverwaltung dar, die ohne externe Bibliotheken auskommt und somit nur Bordmittel des Flutter-Frameworks benutzen.
|
|
|
|
\subsection{Implementierung}
|
|
|
|
Für die Implementierung dieses Ansatzes wurden mehrere Stores konstruiert, welche den Anmeldezustand, die geladenen Produkte und die im Warenkorb befindliche Anzahl der Produkte modellieren. Ein Store besteht dabei immer aus einem \texttt{Inherited\-Widget} und einem \texttt{Stateful\-Widget}. Das \texttt{Inherited\-Widget} erhält dabei vom \texttt{Stateful\-Widget} die Daten und Methoden, welche nach außen abrufbar sein sollen. Zustandsänderungen und Verknüpfungen mit anderen Stores finden ausschließlich im \texttt{Stateful\-Widget} statt.
|
|
|
|
Die Benutzeroberfläche greift auf die Stores ausschließlich über die \texttt{In\-heri\-ted\-Widgets} zu, wie bereits im \autoref{sec:inheritedWidget} beschrieben wurde.
|
|
|
|
Der Funktionsumfang konnte dabei ohne Einschränkungen vollständig implementiert werden.
|
|
|
|
\subsection{Bewertung}
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Negativ bewertet wird hier aber die Tatsache, dass ein Zustand beziehungsweise Store immer aus mindestens drei Klassen bestehen muss. Dies macht es erforderlich, alle nach außen zugängliche Funktionen oder Variablen per Konstruktoraufruf von dem \texttt{Stateful\-Widget} zum \texttt{Inherited\-Widget} zu übergeben. Bei wachsender Größe eines Zustands wird dies unübersichtlich.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
\begin{lstlisting}[caption={Aufbau eines einfachen Flutter-Widgets in Dart}, label={lst:testabilityInheritedWidget}]
|
|
testWidgets('test cart store', (tester) async {
|
|
final widgetTree = ProductStore(
|
|
products: RemoteResource.finished(demoProducts),
|
|
child: CartStoreImplementation(child: Container()),
|
|
);
|
|
await tester.pumpWidget(widgetTree);
|
|
final cartStoreFinder = find.byType(CartStore);
|
|
expect(cartStoreFinder, findsOneWidget);
|
|
var cartStore = tester.widget<CartStore>(cartStoreFinder);
|
|
cartStore.increaseAmount(demoProducts.first);
|
|
await tester.pump();
|
|
cartStore = tester.widget<CartStore>(cartStoreFinder);
|
|
expect(cartStore.amountOfProduct(demoProducts.first), 1);
|
|
});
|
|
\end{lstlisting}
|
|
\label{par:ihtesting}
|
|
Die Tests für Widgets, die den Zustand konsumieren auf der anderen Hand sind einfach umzusetzen, da die Geschäftslogik im besten Fall komplett von der Speicherung der emittierten Daten getrennt wird. So ist es möglich ein \texttt{Inherited\-Widget} ohne das dazugehörige \texttt{Stateful\-Widget} zu initialiseren und die benötigten Mock-Daten über den Konstruktor zu übergeben.
|
|
|
|
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:
|
|
\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: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.
|
|
|
|
Der zweite Faktor hierbei ist die Frage, inwiefern die Struktur klar nachvollziehbar und verständlich ist. Dies ist bei \texttt{Inherited\-Widgets} nicht der Fall, da besonders die Konstruktion aus mehreren Widgets und Widget-Typen schwer nachvollziehbar ist. So gibt es keinen zentralen Ort, welcher die Geschäftslogik übersichtlich zusammenfasst. Im Gegenteil ist es hier notwendig, die Geschäftslogik als Teil eines \texttt{Stateful\-Widgets} zu implementieren, was die Lesbarkeit definitiv erschwert. Hinzu kommt der große Umfang an Boilerplate-Quelltext, da selbst für einfache Zustände wie das Speichern des Anmeldezustands drei Klassen benötigt werden.
|
|
|
|
Der letzte Faktor befasst sich mit der tiefen Verschachtlung von Widgets (engl. Nesting). Nesting wirkt sich negativ auf die Lesbarkeit von Widgets aus. Auf Nesting kann allerdings bei diesem Ansatz nicht verzichtet werden, da \texttt{Inherited\-Widgets} in die Baumstruktur eingebaut werden, wie in \autoref{lst:nestingInheritedWidget} zu sehen ist, und somit immer ein Child-Widget übergeben bekommen.
|
|
|
|
\begin{lstlisting}[caption={Nesting bei \texttt{Inherited\-Widgets} in app.dart \cite{repo}}, label={lst:nestingInheritedWidget}]
|
|
return UserStoreImplementation(
|
|
child: ProductStoreImplementation(
|
|
productService: productService,
|
|
child: CartStoreImplementation(
|
|
child: child,
|
|
),
|
|
),
|
|
);
|
|
\end{lstlisting}
|
|
|
|
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.
|
|
|
|
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}}
|
|
|
|
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.
|
|
|
|
Somit wird hier eine Bewertung mit \textquote{nicht erfüllt} vorgenommen. |