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.
86 lines
9.0 KiB
86 lines
9.0 KiB
\section{Provider}
|
|
\label{eval:provider}
|
|
|
|
Provider stellt die erste externe Bibliothek zur Zustandsverwaltung dar, die in dieser Ausarbeitung evaluiert wird. Die Grundlagen dazu sind im \autoref{sec:provider} nachzuvollziehen.
|
|
|
|
\subsection{Implementierung}
|
|
|
|
Für die Implementierung der Zustandsverwaltung mit der Provider Bibliothek wurde die Version 6.0.2 eingesetzt. Die Zustände wurden dabei in 4 Stores beziehungsweise Providern umgesetzt. Für die Verwaltung des Anmeldezustands wurde ein ChangeNotifier mit gleichnamigen Provider verwendet (siehe dazu \autoref{lst:providerStore}). Zum Laden der Produkte wurde eine FutureProvider eingesetzt. Dieser stellt das Ergebnis eines Futures, also einer asynchronen Operation, zur Verfügung und kann auch auf Fehler beim Warten auf das Future reagieren. Für die Produktliste wurde eine ProxyProvider2 eingesetzt. Dieser ermöglicht es, die Zustände zweier verschiedener Provider zu kombinieren. In diesem Fall wurde der Zustand der beiden bereits beschriebenen Provider kombiniert, um den Rabatt anzuwenden. Für die Abbildung des Warenkorbs wurde ein ChangeNotifierProxyProvider verwendet. Dies stellt eine Mischung aus einem ProxyProvider und einem ChangeNotifierProvider dar, und ermöglicht es so ChangeNotifier-Klassen, über Änderungen von anderen Providern zu informieren.
|
|
|
|
In die Benutzeroberfläche eingebunden, werden die Provider über diverse Extension-Funktionen für den BuildContext. Dabei lässt sich der Zustand abonnieren oder exakt einmal abrufen, falls keine Aktualisierungen erwünscht sind. Zudem lässt sich auch ein Teil des Zustands selektieren, was dazu führt, dass das Widget nur aktualisiert wird, wenn sich dieser Teil des Zustands tatsächlich ändert.
|
|
|
|
\subsection{Bewertung}
|
|
|
|
Im folgenden Abschnitt wird die Implementierung mit Provider \autocite[branch=provider]{repo} anhand der definierten Bewertungskriterien bewertet.
|
|
|
|
\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 von Nöten wären.
|
|
|
|
Eine Designentscheidung von Provider zum Nachteil der Änderbarkeit ist es, dass Provider alleine über Ihren Klassentyp per Generic in Widgets injiziert werden. Dabei kann zur Kompilierungszeit nicht geprüft werden, ob der referenzierte Zustand sich auch tatsächlich in der Widget-Hierarchie befindet. Somit können bei Änderungen in der Hierarchie von Widgets zu einem späteren Zeitpunkt Laufzeitfehler auftreten, die nicht durch den Compiler gefunden werden können.
|
|
|
|
Zur Skalierbarkeit lässt sich sagen, dass in der Dokumentation bereits Limitationen für den Einsatz von Providern gezeigt werden. So träten ab der Verwendung von mehr als 150 Providern StackOverflowErrors auf. \autocite{providerReadme} Zudem ist die Koppelung von Zuständen stark begränzt. Dies liegt daran, dass es für jede Anzahl der zu koppelnden Zustände eine entsprechende Klasse in der Provider-Bibliothek geben muss. Aktuell ist dies mit der Klasse ProxyProvider6 auf sechs Klassen begrenzt. Ob diese Limitation in der Realität jedoch tatsächlich relevant ist, ist fraglich, da es wohl architekturell besser wäre in diesem Fall, die Zustände in mehrere Zustände zusammenzufassen.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Bei den Tests der Widgets, die auf Zustände zugreifen, lässt sich sagen, dass das Mocking hier unaufwendig ist, da Provider die jeweiligen Zustände abstrahiert und so es möglich ist, einfache \textquote{Value}-Provider zu injizieren, wie in \autoref{lst:providertest} zu sehen ist. Diese können dann wie im Beispiel zu sehen ist, einfache Klassen injizieren, die die Eigenschaften der ursprünglichen Zustandsklasse überschreiben.
|
|
|
|
\begin{lstlisting}[caption={Widget-Test bei Provider in total\_price\_test.dart \cite{repo}}, label={lst:providertest}]
|
|
class CartStoreMock extends CartStore {
|
|
@override
|
|
double get totalPrice => 10.0;
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('test total price', (tester) async {
|
|
final widgetTree = MaterialApp(
|
|
home: ChangeNotifierProvider.value(
|
|
value: CartStoreMock() as CartStore,
|
|
child: const TotalPriceText(),
|
|
),
|
|
);
|
|
await tester.pumpWidget(widgetTree);
|
|
final correctText = find.text("Gesamtpreis: 10.00");
|
|
expect(correctText, findsOneWidget);
|
|
});
|
|
}
|
|
\end{lstlisting}
|
|
|
|
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:
|
|
\lstinputlisting[caption={Anzahl der Render-Vorgä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: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 ein ähnliches 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 das 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.
|
|
|
|
\begin{lstlisting}[caption={Vergleich des Abrufs von Zuständen zwischen Flutter und Provider}, label={lst:providerof}]
|
|
// Abruf der Bildschirmausrichtung
|
|
// aus der Flutter-Standardbibliothek
|
|
MediaQuery.of(context).orientation;
|
|
// Abruf des Einkaufwagenzustands
|
|
Provider.of<CartStore>(context).cart;
|
|
\end{lstlisting}
|
|
|
|
Die Zustandsklassen an sich führen auch keine neuen Konzepte ein und Verwenden bereits bekannte Konzepte wie die ChangeNotifier. Diese Zustandsklassen bieten auch eine gute Lesbarkeit, da hier direkt über Variabeln auf den Zustand zugegriffen wird und über Funktionen dieser direkt geändert wird. Hier muss also keine Spezialbehandlung aufgrund der Zustandsverwaltung genutzt werden.
|
|
|
|
Auf der anderen Seite werden Konstrukte wie der ProxyProvider, welcher die Verknüpfung von mehreren Zuständen ermöglicht, schnell auf Grund der vielen Parameter unübersichtlich.
|
|
|
|
Der letzte untersuchte Aspekt, ist ob das Zustandsverwaltungssystem, der tiefen Verschachtlung wirksam entgegentritt. Dazu lässt sich konstatieren, dass hier durch die Einführung eines sogenannten \texttt{MultiProvider} dieses Problem umgangen wird. Zwar muss bei Provider, alle Provider in den Widget-Baum eingesetz werden, allerdings kann ein \texttt{MultiProvider} eine Liste von Providern entgegen nehmen und in den Widget-Baum einsetzen. Somit kommt es nicht zu einer tiefen Verschachtlung.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Daher wird die Strukturbestimmung mit \textquote{nicht erfüllt} bewertet. |