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.
 
 

82 lines
8.6 KiB

\section{BLoC}
\label{eval:bloc}
\acl{bloc} sind ein weit verbreitetes Konzept zur Zustandsverwaltung. Die Grundlagen zu diesem Zustandsverwaltungssystem wurden bereits in \autoref{sec:bloc} eruiert.
\subsection{Implementierung}
Für die Implementierung der App mit \ac{bloc} wurden drei \acl{bloc} erstellt. Diese verwalten den 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.
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.
\begin{lstlisting}[caption={Verwendung eines StreamBuilder in cart\_button.dart \cite{repo}}, label={lst:streambuilder}]
final cartBloc = AppState.of(context).blocProvider.cartBloc;
return StreamBuilder<int>(
stream: cartBloc.numberOfProductsStream,
initialData: cartBloc.numberOfProducts,
builder: (context, snapshot) {
BenchmarkCounters.cartButton++;
return ElevatedButton.icon(
onPressed: () => Navigator.of(context).pushRouteKey(RouteKey.cart),
icon: const Icon(Icons.shopping_basket),
label: Text('Warenkorb (${snapshot.requireData} Produkte)'),
);
},
);
\end{lstlisting}
\subsection{Bewertung}
Im folgenden Abschnitt wird die Implementierung mit BLoC \autocite[branch=bloc]{repo} anhand der definierten Bewertungskriterien bewertet.
\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 InheritedWidget lassen sich \ac{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 Dependency-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-Testing-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.
\begin{lstlisting}[caption={Test des Cart BLoC in cart\_bloc\_test.dart \cite{repo}}, label={lst:testbloc}]
test('test cart bloc', () async {
const productBlocMock = ProductBlocMock();
final cartBloc = CartBloc(productBlocMock);
final expectedCart = {demoProducts.first: 1};
expectLater(cartBloc.cartStream, emits(expectedCart));
cartBloc.quantityEventSink.add(IncreaseQuantityEvent(demoProducts.first));
});
\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 InheritedWidgets 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.
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:
\lstinputlisting[caption={Anzahl der Render-Vorgä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:readability}} Die Verständlichkeit und Lesbarkeit bei \ac{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.
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. Zudem 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{StreamBuilder}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.
Zusätzlich bestehen eine große Anzahl an Artikeln und anderen Veröffentlichungen zum Thema \ac{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.
\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.
Daher wird die Strukturbestimmung mit \textquote{teilweise erfüllt} bewertet.