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.
 
 
thesis/chapters/evaluation/riverpod.tex

77 lines
8.2 KiB

\section{Riverpod}
\label{eval:riverpod}
Riverpod stellt eine externe Bibliothek zur Zustandsverwaltung dar, welche das Konzept von Provider erweitert und laut eigenen Angaben verbessert. Die Grundlagen dazu sind im \autoref{sec:riverpod} nachzuvollziehen.
\subsection{Implementierung}
Für die Implementierung wurde die Bibliotheken \texttt{riverpod} und \texttt{flutter\_riverpod} in der Version 1.0.3 verwendet.
Die Zustände wurden dabei über diverse Provider. Der Anmeldezustand beispielsweise wurde mittels eines StateNotifierProvider umgesetzt, welcher eine StateNotifier-Klasse, wie im Grundlagenkapitel erläutert, injiziert. Zudem wurde ein FutureProvider genutzt, um die Produkte zu laden und ein einfacher Provider, um den Anmeldezustand mit den geladenen Produkten zu verknüpfen und somit den Rabatt anzuwenden. Der Zustand des Warenkorbs wird über mehrere Provider abgebildet. So stellt ein StateNotifierProvider die Grundlage für den Warenkorb. Diese wird dann anschließend durch weitere Provider um zusätzliche Informationen ergänzt wie beispielsweise den Produktdaten. Alle Provider werden als globale finale Variablen der Benutzeroberfläche zur Verfügung gestellt.
Die Einbindung in die Benutzeroberfläche erfolgte mittels ConsumerWidget. Dafür werden die Basisklassen der Widgets, die auf Zustände zugreifen müssen auf ConsumerWidget geändert. Dadurch erhält man in der build-Methode einen zusätzlichen Parameter, der es erlaubt die Provider anhand ihrer globale Variablen auszulesen.
\subsection{Bewertung}
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.
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.
Da die Provider nicht über den Widget-Baum übergeben werden, ist anzunehmen, dass das Problem mit der Skalierbarkeit mit über 150 Providern, welches bei der Provider-Bibliothek auftritt, hier nicht Anwendung findet.
Auch bei der Koppelung verschiedener Zustände wird hier ein anderer Weg gegangen. So wir hier über einen Array angegeben, von welchen anderen Provider ein Provider abhängt. Die Zustände können im Anschluss wie bei der Benutzung im ConsumerWidget über eine Referenzvariable \texttt{ref} abonniert, verändert oder gelesen werden. Somit skaliert dieser Ansatz der Kopplung mit der wachsenden Größe von zu koppelnden Zuständen und wird nicht durch Generics limitiert.
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.
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.
\begin{lstlisting}[caption={Widget-Test bei Riverpod in total\_price\_test.dart \cite{repo}}, label={lst:riverpodtest}]
testWidgets('test total price widget', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: ProviderScope(
overrides: [
totalPriceProvider.overrideWithValue(10.0),
],
child: const TotalPriceText(),
),
),
);
expect(find.text('Gesamtpreis: 10.00'), findsOneWidget);
});
\end{lstlisting}
Bei den Widget-Tests bietet Riverpod die Möglichkeit an, beliebig viele Provider entweder mit festen Inhalten oder mit anderen Providern zu überschreiben. Besonders die Möglichkeit mit dem Überschreiben durch feste Inhalte vereinfacht das Ersetzen durch Platzhalter, wie im \autoref{lst:riverpodtest} zu sehen ist, sehr.
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:
\lstinputlisting[caption={Anzahl der Render-Vorgä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: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.
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.
Die Möglichkeit andere Zustände über die Referenzvariable zu injizieren hingegen, verbessert die Lesbarkeit, da hier im Vergleich zu ProxyProvider sofort klar wird, warum dieser Provider gelesen oder abonniert werden muss.
Das Problem der tiefen Verschachtlung umgeht Riverpod damit, dass die Provider nicht in den Widget-Baum eingesetzt werden müssen.
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.
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.
Daher wird die Strukturbestimmung mit \textquote{nicht erfüllt} bewertet.