2020-08-18 Logo die vierte, Dagger, Authorization Requests mit Retrofit

Und wieder haben wir uns mit unserem Logo beschäftigt. Mittlerweile nimmt es Gestalt an. Es gibt noch eine Sache, die wir zu beanstanden haben und dann werden wir es im Blog posten.
Ansonsten hat in diesem „Sprint“ hauptsächlich jeder für sich gearbeitet und Verena hat ihre Erkenntnisse mit Dagger geteilt.

Peter
Ich habe mich erneut mit Retrofit beschäftigt. Was uns hauptsächlich noch gefehlt hat ist eine Möglichkeit, um die Authorization Information mit einem Retrofit-Call mitgeben zu können. Also entweder User-Credentials oder später einen Token, wie er von einem Identity Provider erzeugt wird. Auch hier hatte Verena bereits Vorarbeit geleistet und es ausprobiert.

In Retrofit ist das Mitgeben der Authorization Information relativ einfach.
Es gibt die folgenden Möglichkeiten:

  • einem Webservice Call über eine Annotation @Header-Informationen mitgeben, die dem Http-Header hinzugefügt werden
  • oder alternativ kann über das Client Objekt „OkHttpClient“ ein Interceptor übergeben werden. OkHttpClient ist das Standard Framework für Http-Requests, das auch von Retrofit verwendet wird.
    Mit Hilfe des Interceptors kann der Http-Request um weitere Informationen erweitert werden.
    Der Vorteil dabei ist, es muss nicht jedem Webservice-Call separat ein Header hinzugefügt werden, sondern es kann an zentraler Stelle erfolgen.

Wichtig dabei ist, die übermittelten Informationen zu encrypten. Die Implementierung zur Übermittelung von User-Credentials mit Hilfe eines Interceptors kann wie folgt aussehen:

class AuthorizationInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()

        val username: String = "test"
        val password: String = "test"
        val base: String = "$username:$password"

        val authorizationHeader: String =
            "Basic " + Base64.getEncoder().encodeToString(base.toByteArray())

        val newRequest = originalRequest.newBuilder()
            .header("Authorization", authorizationHeader)
            .build()
        return chain.proceed(newRequest)
    }
}

Die restliche Zeit habe ich mich mit Spring Boot beschäftigt. Die Übergabe von Benutzername und Passwort – zum Auslesen – war einfach.
Allerdings werden POST-Requests von Spring Boot verboten. Ich habe zwar Möglichkeiten gefunden das Verhalten zu unterdrücken, aber es soll unter Prüfung des Benutzers und seiner Berechtigungen funktionieren.
Da werde ich nächste Woche weiter machen.

Verena
Nach den zahlreichen Tutorials von Coding in Flow verwendet die RestAccess-API nun als unsere erste Library Dependency Injection mit Dagger2.
Eine Anmerkung dazu: Beim Verwenden von Dagger muss oft ein „Rebuild“ des Projektes durchgeführt werden, damit z.B. die Components anhand des definierten Interfaces generiert werden. Beim Definieren der Dependencies wird schnell mal z.B. eine Annotation vergessen und es kommt zu einem Build-Fehler.
Eine Sache, die ich gelernt habe, war, dass ein „Rebuild“ in Android Studio nicht die gleichen Fehlermeldungen produziert wie ein einzelner „Build“ über das Gradle-Menü. Taucht also z.B. eine kryptische Fehlermeldung wie diese auf:

„A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution“

kann im Gradle-Menü über app->Tasks->build->build der einzelne Schritt ausgeführt werden, was bei mir z.B. für den gleichen Fehler diese zusätzliche Fehlermeldung ausgespuckt hat:

„error: @Component.Builder has setters for modules or components that aren’t required: [@org.jetbrains.annotations.NotNull com.outlivethesun.restaccess.dagger.IRestAccessComponent.Builder..”

Weitaus hilfreicher, da man hier auch auf die Stelle, an der der Fehler auftritt, hingewiesen wird.
Was die Testbarkeit angeht, können anstatt zusätzliche Test-Components anzulegen, auch einfach die Klassen separat geunittested werden, da ohnehin alles, was per DI hinzugefügt wird, auch von außen sichtbar ist. Vielleicht brauchen wir die Test-Components irgendwann, aber für jetzt passt es auch erstmal so.

Die Möglichkeit, die Konfigurationen über eine Properties-Datei auszulesen wandert gerade in eine separate Library.

2020-08-11 Logo die dritte, Dagger und Retrofit

Hier kommt der Blog-Beitrag an diesem 35 Grad heißen Tag. Trotz der Wärme haben wir einiges geschafft.

Was macht das Logo? Wir sind immer noch dran. Derzeit probieren wir unterschiedlichen Farben aus. Generell haben wir aber immer noch Änderungswünsche. Auf dem Logo werden eine Waage und zwei Personen zu sehen sein. Allerdings kann die Anordnung auch als ein Gesicht interpretiert werden. Deshalb hatten wir noch eine Idee, die wir bereits als Anforderungswunsch angefordert haben, um das Logo noch eindeutiger zu machen.
Außerdem sind wir mit unserem neuen Ansprechpartner des Cyberforums in Kontakt getreten. Vielleicht können wir von dort noch etwas Unterstützung bekommen.

Peter
Auch diese Woche habe ich mit Retrofit und Spring Boot rumgespielt.
Da ich mit der in Memory Datenbank (H2) von Spring Boot arbeite, habe ich mir über Postman „Collections“ angelegt. Damit kann ein vorgegebener Satz an Requests auf einmal abgesetzt werden. Zum Befüllen der H2-Datenbank sehr geeignet – die ich sonst Request für Request per Hand abgesetzt habe. Supercool das Tool.

Was habe ich in Spring Boot gemacht? In Spring Boot haben wir nun die Möglichkeit zum Filtern von Felder und außerdem das Paging von Daten, sowie die Sortierung der Ergebnisse eingebaut. Um das Paging und Sortieren habe ich ein kleine API gestrickt, die wir mehr oder weniger generisch auch für weitere Entitäten nutzen können.
Es können jetzt bspw. folgende Abfragen gemacht werden:

Alle Personen der Seite 0 beschaffen, wobei mit einmal 3 Einträge zurückgegeben werden. Die Daten werden absteigend nach dem firstname und aufsteigend nach dem lastname sortiert.
http://localhost:8080/api/persons?pageNumber=0&pageSize=3&sort=firstname:desc,lastname:asc

Alternativ kann über den Parameter „order“ eine default Sortierreihenfolge angegeben werden. Die Default Sortierreihenfolge kann aber für jedes Attribut überschrieben werden. Im folgenden Beispiel würden z.B. alle Einträge, bis auf firstname absteigend sortiert werden. Das „:asc“ hinter dem firstname hat eine höhere Priorität als das default „order=desc“
http://localhost:8080/api/persons?pageNumber=0&pageSize=3&sort=firstname:asc&order=desc


In Retrofit gibt es nun ein neues Objekt PageRequestDTO. Das Objekt erhält das Ergebnis der Page-Anfrage. Dort sind nicht nur die Daten enthalten, sondern auch allgemeine Page Informationen. Beispielsweise ist es möglich auszulesen, auf welcher Seite ich bin, wie viele Einträge gelesen werden, wie viele Einträge und Seiten noch übrig sind. Bekommt man von Spring Boot alles geschenkt.
Außerdem haben Verena und ich uns der Retrofit-Generic gewidmet. Damit haben wir einen großen Teil des Retrofit Standardcodes gekapselt und können Abfragen mit nur wenigen Zeilen Code ausführen und auch das Ergebnis zurückbekommen. In der kleinen API müssen wir uns allerdings noch um die Fehlerbehandlung kümmern. Ein Webservice Request sieht bei uns nun wie folgt aus:

Die ServiceFactory erzeugt einen Service für IPersonDTOService. Dieser Service hat alle Methoden, um auf Personen zuzugreifen. Für die Ausführung des Calls wird der ServiceExecutor verwendet, der asynchron den Request absetzt, das Ergebnis in den gewünschten Typen umwandelt und zurückliefert. Deutlich kürzer als das bestehende Coding und wir können an zentraler Stelle ein default Webservice Call Fehlerhandling implementieren. Für Spezialfälle können wir eh weiterhin auf die Standardfunktionen zugreifen.

val personDTO = ServiceExecutor().execute(
    ServiceFactory().createService(IPersonDTOService::class.java).findById(id)
)

Verena

Diese Woche habe ich mich weiter mit den Dagger Tutorials von Coding in Flow beschäftigt und angefangen, in der RestAccess-API den Service Locator durch Dependency Injection zu ersetzen.

Letztes Mal hatte ich mir ein paar Kotlin-Libraries angeschaut, um unsere Konfigurationen wie URIs, Client-IDs, Ports etc. hinterlegen zu können, damit wir nicht jeder das Coding anpassen müssen, sondern lediglich die Werte im Config-File anpassen und dieses immer wieder verwenden können. Letztendlich habe ich mich doch für eine herkömmliche Methode entschieden, ein properties-File anzulegen. Ich hatte auch zuerst die SharedPreferences in Android gefunden, habe allerdings gelesen, dass diese lesbar als xml abgelegt werden, was sich z.B. für unsere Keys nicht eignet. SharedPreferences könnten so mit einem gerooteten Handy angepasst werden. Deshalb haben wir jetzt ein Properties-File, welches mit der App kompiliert wird und mit weniger Aufwand ausgelesen werden kann als gedacht.

2020-08-04 Urlaub, Logo Review und Webservice Calls

Diese Woche ist Verena im Urlaub, trotzdem ging es weiter.
Unser Logo für die App nimmt weiter Gestalt an. Beim Review war Verena auch noch dabei. Bisher sind wir mit den Farben und dem Gesamteindruck aber noch nicht zufrieden und stehen weiterhin in Kontakt mit Gigblast, die wir auf Fiverr gefunden haben.
Ansonsten ging es diese Tage vorrangig um „Best Practices“ für die Bereitstellung und die Konsumierung von Webservices.

Peter
Als Backend für die Bereitstellung von Webservices nutzen wir Spring Boot. Unsere bisherigen Implementierungen waren aber sehr rudimentär. D.h. wir hatten Ressourcen wie eine Person, die man erstellen und hinzufügen, bestehende aktualisieren, löschen und auslesen konnte.
Zukünftig wird das Model aber deutlich komplexer sein. Es wird Beziehungen zwischen Ressourcen geben, es soll gefiltert, sortiert und gepagt werden.

Bisher haben wir bei einer Abfrage einer Ressource auch generell alle Attribute zurückgegeben. Obwohl ich zu Beginn der Meinung war, es macht nichts aus immer alles zurückzugeben, ist es im mobilen Sektor natürlich sinnvoll die Menge der zu übertragenen Daten so gering wie möglich zu halten. Außerdem ist es auch der Performance zuträglich.

Das Thema Einschränkung hat mich am meisten interessiert, deshalb habe ich damit begonnen zu schauen wie Daten, Attribute und Felder gefiltert werden können.  Beispielsweise sollte folgende Abfrage möglich sein:

http://localhost:8080/api/persons?fields=id,firstname

Mit diesem RESTCall werden alle Personen ausgelesen, aber von diesen Personen lediglich die Attribute id und firstname zurückgegeben.

Da es viele Endpunkte zum Auslesen von Ressourcen geben wird, wäre der Implementierungsaufwand für die Ausprogrammierung jedes Endpunkts recht hoch. Deshalb habe ich nach einem generischen Ansatz gesucht. Auch nach längerer Suche bin ich mit den vorgeschlagenen Lösungen aber nicht so recht zufrieden gewesen. Letztendlich hatte ich sogar überlegt es selbst und händisch zu implementieren. Dann bin ich aber über stackoverflow auf die Library Squiggly gestoßen. Mega cool. Lediglich nur 4 Votes für diese Hammer Lösung, die genau das kann, was wir brauchen. Dependency hinzufügen, eine Config-Klasse implementieren und nach 5 – 10 min Aufwand war es möglich für alle Ressourcen nach beliebigen Attributen zu filtern. Das Ausschließen von Attributen ist genauso möglich. Auch das Filtern von nested Attributen hat auf Anhieb funktioniert. Hat mich richtig aus den Socken gehauen. Denn generell funktioniert eine Lösung entweder erst einmal gar nicht oder macht nicht das was man braucht.
Hier ein paar Beispiele, die unterstützt werden

http://localhost:8080/api/persons?fields=id,firstnameAlle Personen beschaffen, id und firstname zurückgeben
http://localhost:8080/api/persons?fields=*Alle Personen mit allen Feldern zurückgeben (oder einfach „?field=*“ weglassen)
http://localhost:8080/api/persons?fields=-firstnameAlle Personen beschaffen das Attribut firstname vom Ergebnis ausschließen
http://localhost:8080/api/persons/1?fields=id,firstnamePerson zur id 1 beschaffen, id und firstname zurückgeben
http://localhost:8080/api/persons/1?fields=firstname,teams.namePerson zur id 1 beschaffen, firstname und das nested Attribut teams.name zurückgeben
http://localhost:8080/api/persons?fields=-teams.descriptionAlle Personen beschaffen und das nested Attribut teams.description ausschließen

Nächstes Thema war ein Best Practice für die Umsetzung der Webservices. Generell gibt es nun grob die folgenden Komponenten:

  • Endpunkte (Controller) – die Endpunkte selbst, die von außen aufgerufen werden können
  • Service Klassen – eine Art Use Cases, die für die Beschaffung, Filterung, Sortierung bestimmter Daten verantwortlich sind
  • DTOs – Data Transfer Objekte, die bestimmte Informationen bspw. unterschiedlichen Entitäten wrappen
  • Repositories – speziell für das Speichern, Auslesen von Daten aus bspw. einer Datenbank
  • Model – Entitäten, wie Personen, Teams etc.

Letztes Thema war das Konsumieren der Webservices aus einer App heraus – mit Hilfe von Retrofit. Hier hatten wir ein bestehendes Beispiel aus den letzten Wochen, das ebenfalls wenig komplex war.
Nach etwas rumspielen ist es nun aber auch möglich, nested Ressources mit auszulesen und Daten zu filtern. Ein Beispiel ist unser PersonDTOService. Über @Query ist es jetzt beispielsweise möglich die Filterkriterien zu übergeben, die im Ergebnis berücksichtigt werden. Zum Beispiel die Einschränkung des Ergebnisses auf bestimmte Attribute wie: firstname.

interface IPersonDTOService {

    @GET("persons")
    fun findAll(): Call<List<PersonDTO>>

    @GET("persons")
    fun findAll(@Query("fields") fields: String): Call<List<PersonDTO>>

    @GET("persons/{id}")
    fun findById(@Path("id") id: Long): Call<PersonDTO>

    @GET("persons/{id}")
    fun findById(@Path("id") id: Long, @Query("fields") fields: String): Call<PersonDTO>

    @POST("persons")
    fun addPerson(@Body personDTO: PersonDTO): Call<PersonDTO>
}

Last but not least habe ich begonnen die Verwendung von Retrofit etwas zu vereinfachen, da oft Coding doppelt geschrieben werden muss. Damit werde ich allerdings kommende Woche weitermachen.

2020-07-28 Refactoring RestAccess API, Einarbeitung in Dagger2 & Retrofit, die ersten Entwürfe unseres App Logos sind da

Die dritte Woche in Folge, in der wir uns viel Zeit für bestehende Konzepte und APIs genommen haben. Zum einen wollen wir Dagger zum Injecten nutzen und Retrofit für den Zugriff auf Webservices.

Außerdem haben „wir“ das Thema App Logo vorangetrieben. Am Montag haben wir unserem Logo Dealer des Vertrauens eine Nachricht geschickt und keine 24 Stunden später hatten wir die ersten 3 Entwürfe im Postfach. 100% zufrieden waren wir auf Anhieb nicht, haben aber einen Entwurf als unseren Favoriten auserkoren. Unsere Änderungswünsche haben wir direkt zurückgeschickt und warten gespannt auf Rückmeldung, um das fertige Logo in einem der nächsten Blog-Beiträge präsentieren zu können.

Verena

Der Kampf ging diese Woche weiter: „Die Rückkehr von AppAuth“. Mittlerweile ist das Setup von Keycloak und AppAuth abgeschlossen und Webservices können auch bei mir mithilfe eines Berechtigungstokens aufgerufen worden. Nachdem alles lief, ist mir aufgefallen, dass das Ersetzen von RxJava durch die Coroutines auf Anhieb funktioniert hat. Ein absolutes Plus für Kotlin. Das nächste Ziel wäre, die Aufrufe einfacher zu gestalten und gewisse Informationen in eine Config-Datei auszulagern, damit für unsere jeweilige lokale Installation nur noch die eigenen Konfigurationen verwendet werden und das Coding davon unberührt bleibt. Für die Config hatte ich mir mehrere Libraries angeschaut, die ich auf https://www.kotlinresources.com/ gefunden habe. Auf der Seite sind Github-Repositories durchsuchbar. Allerdings war bis jetzt keine Library davon so einfach nutzbar wie in der Beschreibung versprochen, weitestgehend bugfrei bzw. wird überhaupt noch gepflegt.

Außerdem hatte ich angefangen, mir Dagger2 als Dependency Injection Framework anzuschauen und habe dazu eine Tutorial-Serie von Coding in Flow angefangen. 

Peter

Vorrangig habe ich mich mit Retrofit beschäftigt und indirekt noch einmal das Thema Coroutinen gefestigt.

Retrofit als Library vereinfacht den Zugriff auf Webservices. Für den einen oder anderen mag es vermessen klingen es mit Spring Boot Web zu vergleichen. Aber das Konzept hinter Retrofit ist vergleichbar und ebenso eingängig wie das von Spring Boot Web. Es wird mit stark typisierten Objekten gearbeitet. Kein JSON oder XML. Stattdessen kümmert sich Retrofit um die Befüllung des http Headers, den Aufruf der Webservices, die Konvertierung von JSON / XML in das gewünschte Objekt Format und umgekehrt. Dafür ist ein Service Interface zu definieren – das Pendant zum Webserver. Durch Annotationen kann zwischen GET, POST, PUT, DELETE Requests unterschieden werden. Retrofit übernimmt dabei die Generierung einer Klasse zum Interface.

Ein Service könnte wir folgt definiert werden.

interface IPersonService {
    @GET(„persons“)
    fun findAll(): Call<List<Person>>

    @GET(„persons/{id}“)
    fun findById(@Path(„id“) id: Long): Call<Person>

    @POST(„persons“)
    fun addPerson(@Body person: Person): Call<Person>
}

Die Annotation gibt die http Method an. Über das Literal (hier „persons“) wird die Ressource angegeben, die abgerufen werden soll. Der Aufruf erfolgt über die zugehörige Kotlin Funktion (bspw. findAll()) . Das Ergebnis ist ein Retrofit-spezifisches Objekt vom Typ Call, das später aufgerufen werden muss, um den eigentlichen Rest-Call durchzuführen. Über eine Callback-Methode kann das Ergebnis (die Response) des Calls ausgewertet und verarbeitet werden.

Quellen und Videos gibt es im Netz reichlich. Nicht vergessen die Permission „Internet“ zuzuweisen.

Das war es von meiner Seite :).

2020-07-21 Keycloak, Coroutines und Retrofit

Besser zu spät als nie gibt es heute (2020-07-23), um 2 Tage verspätet den Blogbeitrag. Diese Woche waren wir zu faul ihn pünktlich zu „liefern“. Trotzdem datieren wir ihn zurück auf den 2020-07-21. Das gibt ein besseres Gefühl und stärkt die Moral.

Was stand an diese Woche? Wie auch die letzte stand diese im Zeichen der Wissensaneignung. Im Speziellen ging es um Coroutines. Was sind Coroutinen? Wie funktionieren sie? Welche Möglichkeiten hat man? Passend zum Thema ging es weiterhin um den Aufruf von Webservices aus einer Android Anwendung heraus. Verena hatte sich im Vorfeld sowohl mit Coroutinen, als auch mit Retrofit für den Aufruf von Webservices beschäftigt und wir haben darüber gesprochen was möglich ist und ausprobiert.
Coroutine btw ist Kotlins Lösung mit der „asynchronen“ Ausführung von Funktionen umzugehen. D.h. bspw. mit Threads zu arbeiten. Aber auch sequenzielle Ausführungen in gesonderten Threads sind möglich. Generell ist bei der Nutzung von Coroutines eine Funktion in Kotlin als „suspend fun“ zu deklarieren. Damit ist die Ausführung im allgemeinen Main-Thread der App allerdings nicht möglich. Stattdessen muss die „suspend fun“ in sogenannten Coroutinen aufgerufen werden. Dazu zählen bspw.:

  • runBlocking: um die suspend fun sequenziell zur Anwendung auszuführen
  • GlobalScope.async: für eine asynchrone Ausführung

Wie immer hat Kotlin – für unseren Geschmack – eine super Lösung ausgeliefert, die auf den ersten Blick verständlich und durchgängig funktioniert.

Drittes Thema diese Woche war: Keycloak als IdProvider. Wie bereits in einem vorherigen Blogbeitrag erwähnt, wollen wir Keycloak als IdProvider einsetzen und haben es bereits in einer vorherigen App verwendet. Für den Zugriff auf Keycloak aus Android nutzen wir App Auth. Ganz einfach haben wir uns damit aber auch dieses Mal nicht getan. Denn obwohl wir schon Beispiele implementiert und eine Vorlage hatten, haben wir gekämpft alles zum Laufen zu bekommen und sind bisher auch nicht fertig geworden. Wahrscheinlich müssen wir uns die ganze Flow-Thematik noch einmal zu Gemüte führen oder um App Auth ein kleine API stricken, die speziell auf unsere Wünsche zugeschnitten ist und die Verwendung für uns noch etwas einfacher gestaltet.

Letztes Thema in dieser Woche war es einen Anbieter zu finden, der uns ein Logo für unsere App kreieren kann. Verena war bereits auf der Suche und ist auch fündig geworden. Kontakt haben wir schon einmal aufgenommen, um Fragen im Vorfeld zu klären. Nächste Woche geht es damit weiter.

2020-07-14 Knowledge Research

Unsere letzten beiden Tage haben sich größtenteils um Forschung und das Schließen von Wissenslücken gedreht.

MVI (Model View Intent)
Ein wichtiges Thema ist dabei immer noch unsere App Architektur und welche Best Practices es speziell aus der Android Welt gibt.
Verena hatte hierfür bereits einiges an Vorarbeit geleistet und ein Beispiel implementiert. Nachdem wir das Thema in der Vergangenheit bereits diskutiert haben, gab es bei einem zweiten Blick auf die Architektur noch ein paar Ideen, wie wir sie für unsere Zwecke anpassen könnten. Im Speziellen geht es dabei um Android MVI (Model View Intent).
Die Idee dabei ist es pro View einen View State zu haben, der alle Informationen für diese View bereitstellt. Der State ist änderbar. Bspw. gibt es Events, die durch Benutzereingaben ausgelöst werden. Durch das Event werden andere Operationen getriggert (Intents – Absichten). Die Abarbeitung eines Intents kann wiederum zur Änderung des UIs führen. Dafür gibt es spezielle Results, die wiederum den View State verändern. Das wäre ein Beispiel für einen Flow. Ein Beispiel zu Android MVI Kotlin Coroutines & Flow findet ihr hier und ein Beispiel für die Testimplementierung von Verena hier.

Clean Architecture
Etwas abstrakter ist die Clean Architecture. Der Gedanke dabei ist es die unterschiedlichen Ebenen und die Kommunikation zwischen diesen Levels darzustellen.
Im Inneren befinden sich die „Entities“. Dazu zählt das Model und die Business Logic / Business Rules.
Um sie herum befinden sich Use Cases. Use Cases werden ausgelöst und verändern bspw. das Model.
Etwas weiter außen befinden sich Presenter, Gateways und Controller. Dazu zählt bspw. das View Model. Hier ist die Logik für die Kommunikation mit dem UI, der View, hinterlegt. In umgekehrter Richtung lösen bspw. Presenter Use Cases aus.
Ganz außen befinden sich Frameworks, Treiber, Devices, Datenbanken etc.
Charakteristisch für den Kreis sind zwei Prinzipien:

  • Abstraktions-Prinzip: Je weiter innen ein Kreis liegt, desto abstrakter ist er. Und umgekehrt, je weiter außen ein Kreis liegt, desto konkreter ist dieser. Hier bedeutet es: je weiter innen ein Kreis liegt, desto weniger unterliegt er dem Einfluss der Veränderung äußerer Komponenten. Bspw. sollte das Ändern der Datenquelle / DB (ganz außen), keine Änderung der Business Regeln oder des Models nach sich ziehen.
  • Abhängigkeits-Regel: Diese Regel besagt, dass jeder Kreis immer nur eine Abhängigkeit zum nächst inneren Kreis haben darf. Bspw. darf der Presenter (z.B. das View Model) lediglich abhängig von den Use Cases sein.
Quelle: https://rubygarage.org/blog/clean-android-architecture#article_title_0

Ein gutes Beispiel ist das Clean Architecture Tutorial for Android: Getting Started.

Verena

Ich habe mir das nächste Kapitel im Designing for Behavior Change-Buch geschnappt, in dem es darum ging, Motivationen zu finden, die den User dazu animieren, auf eine bestimmte Weise zu handeln. In einem Abschnitt ging es um die Diskussion, ob man seine User „bestrafen“ sollte, wenn sie etwas nicht tun. Die generelle Antwort ist nein, aber ein interessanter Ansatz ist, sich User ihre Strafe selbst aussuchen/auferlegen zu lassen, also z.B. „Wenn ich X nicht tue, spende ich einen Betrag an eine Einrichtung, die gegen meine Prinzipien verstößt“. Ein weiterer Abschnitt ist darauf eingegangen, wie man Dinge, die so weit in der Zukunft liegen, dass sie für den Moment nicht motivierend sind, in die Gegenwart holt und hat Ansätze vermittelt, um „Das kann ich auch morgen noch erledigen“ zu überwinden und sofort tätig zu werden. Ein Beispiel dafür ist eine Software, um Menschen künstlich altern zu lassen und ihnen aufzuzeigen, welche Folgen ihre Lebensweise für die Zukunft hat. Für unseren Blog wussten wir nicht, ob ein Impressum notwendig ist, da keine persönlichen Daten dritter Personen gespeichert werden und es sich bei unserem Blog auch nicht um einen Internetauftritt eines Gewerbes handelt. Nach kurzer Recherche sind wir zu dem Schluss gekommen, dass wir damit wohl eine Grauzone betreten und haben das Impressum vorsichtshalber gelassen.

Peter

Größtenteils habe ich mich in das Thema App Architektur eingelesen.
Zweites Thema für mich war die Beantwortung der Frage: Wie können fremde Identity Provider in Keycloak eingebunden werden, welches für den Login in unsere App verwenden wollen. Da Keycloak Open ID Connect unterstützt, wollten wir zur Authentifizierung an die App auch Logins von Drittanbietern (wie Google oder Facebook) unterstützen. Damit ist es nicht erforderlich speziell für die App einen neuen Benutzer anlegen zu müssen, sondern es kann stattdessen ein bestehender bspw. Google Account verwendet werden.

2020-07-07 Naming the child, Produkt-Treppe® und Refactoring

Schon letzte Woche haben wir uns mit dem Namen unserer App beschäftigt, die kreativen Ideen von Verena besprochen und wollten ihn diese Woche festlegen. Kurz: „TeamSlimster“ ist der Gewinner.
Damit können wir mit der Entwicklung beginnen. Bzw. erst einmal können wir Projekte und Git Repositories anlegen, um gemeinsam daran arbeiten zu können.

Außerdem haben wir unser Backlog aufgeräumt. Ein spezielles Tool für das Verschieben von Tickets von offen bis geschlossen nutzen wir bisher nicht, sondern „Microsoft To do“. Für unsere Zwecke bisher auch vollkommen ausreichend. Allerdings haben wir begonnen unseren Tasks einen Prefix zu geben, um Zugehörigkeiten sichtbar zu machen. Nachdem wir unser Backlog in Refinements etwas aufgebaut haben und sich die Anzahl der Stories erhöht hatte, ging damit aber auch die Übersichtlichkeit verloren. Unsere Lösung ist es eine Liste pro „Kategorie“, wie App, Blog etc. anzulegen.

Woran wir ebenfalls intensiv gearbeitet haben, war unsere Produkt-Treppe®. Wir haben uns noch einmal Gedanken über die Personen, die die App nutzen sollen, gemacht und dazu mit Personas und einer Empathy Map begonnen. Bei der Empathy Map handelt es sich um ein Tool, bei dem man sich darüber Gedanken macht, inwiefern eine Persona über die Sinnesorgane mit einem bestimmten Thema konfrontiert wird. In unserem Fall geht es um dickere Menschen, die möglicherweise abnehmen wollen. D.h. was hören sie? Was sagen andere Menschen? Was sehen sie? Was denken sie? Dabei kam das folgende Brainstorming heraus.

Verena

Unser Roundtrip-App-Beispiel ist um eine Funktionalität reicher geworden. Es ist ein User-Counter hinzugekommen, der exemplarisch einen „Flow“ simuliert, bei dem alle paar Sekunden ein Request neue Daten abruft und dadurch das UI mit neuen Daten updatet. Hierfür gibt es eine Experimental-Version des MutableStateFlows, einem Flow, der sich wie ein BehaviourSubject in React verhält und mit dessen Hilfe der Flow kontinuierlich mit neuen Werten aktualisiert werden kann.

Danach ist unsere RestAccess-API nach Kotlin umgezogen und ich habe die in RxJava implementierten Webservice-Calls durch Kotlin Coroutinen ersetzt. Getestet werden muss es noch, wofür die Testumgebung eingerichtet werden muss. Die erste Aufgabe für nächste Woche. Und es gab noch einen kleinen Kampf mit dem Gradle Build nach dem Umzug zu Kotlin. Stackoverflow kam wie immer zur Rettung.

Peter

Ich habe mich noch einmal mit der Produkt-Treppe® befasst und begonnen einen Artikel darüber zu schreiben, was sie für uns ist und wie wir sie nutzen wollen.

Ansonsten habe ich begonnen mir das Beispiel von Verena für die Android Cleancode Architektur anzuschauen. Dabei geht es darum, welche Komponenten es in einer Android App gibt (bspw. Model, ViewModel und View) und wie diese miteinander kommunizieren (Intent und State).

2020-06-30 Namenssuche, Impressum & Datenschutzerklärung und erstes Backlog Refinement

Diese Woche haben wir mit dem ersten Backlog Refinement begonnen. Viele Stories sind dabei nicht herausgekommen, da wir die Dinge, die wir für die App umsetzen wollen, nur in groben Punkten beschrieben haben. D.h. wir lehnen unsere Arbeitsweise an Scrum an – auch wenn nicht ganz so strickt, wie in einem festen Scrum-Team. Diese gewohnte Arbeitsweise aus unserer beruflichen Tätigkeit gibt eine gewisse Vertrautheit und Planungssicherheit. Die Dinge, die wir uns für diese Tage vorgenommen hatten, haben wir bspw. größtenteils erledigt bekommen.

Letztendlich war eine wichtige Story, sich einen Namen für die App zu überlegen. Gerade Verena hat dazu viele kreative Vorschläge gemacht, die wir bis zur kommenden Woche sacken lassen und dann eine Entscheidung treffen wollen. Wie immer posten wir euch die Vorschläge und lassen euch bis nächste Woche Zeit eure Stimme abzugeben (hier der Link).

Peter
Diese Woche habe ich das Buch Business Model Produkt-Treppe® zu Ende gelesen. Es handelt sich dabei um ein Business Model, das u.a. speziell für smarte Teams konzipiert wurde, um schnell und einfach ein eigenes Produkt-Portfolio zu entwerfen. Das Thema an sich empfinde ich zwar als trocken, aber es wurde im gleichnamigen Buch sehr interessant erklärt. Darüber werde ich in den kommenden Monaten (ich wollte erst Wochen schreiben) noch etwas genauer berichten und vorstellen, wie unsere Produkt-Treppe® aussieht.

Technisch habe ich mich in Richtung Modelcaching in Android beschäftigt. Im Speziellen geht es um die Möglichkeiten wie Model-Repositories aufgebaut, eingebunden und bspw. durch Webservice-Calls befüllt werden können. Für unsere vorherige App hatten wir bereits eine ähnliche Implementierung, auf die ich gerne aufsetzen würde. Außerdem habe ich für ein paar spezielle Anforderungen nach Best Practices gesucht: Wie werden Sperren im Webservice-Umfeld gehandhabt und welche ORM-Tools stehen im Android Umfeld zur Verfügung.

Für das Sperren von Entitäten gibt es Dank Spring Boot eine relativ einfache Lösung, die ich verlinke.

Zum Thema ORM bin ich über SugarORM gestolpert. Auf den ersten Blick sehr einfach und brauchbar: Die Entitäten erben von einer bestimmten Klasse und haben damit Methoden wie save(), delete() und findById(). Die Vererbung empfinde ich dabei auch als Nachteil und würde die Persistenz-Operationen gerne vom Model trennen.
Vorteil ist, dass Tabellen und scheinbar auch die Datenbank generiert werden und man in ein paar Minuten eine Beispielanwendung umsetzen kann. Hier kämpfe ich derzeit noch mit dem Problem, dass Tabellen nicht generiert werden können. Aber das wird sich finden.

Verena
Nachdem letzte Woche die Entscheidung für die Architektur gefallen ist, standen diese Woche die UnitTests für das ViewModel und den Umgang mit LiveData und die Kotlin Coroutinen innerhalb der Testumgebung an. Nicht ganz trivial umzusetzen und nach einigen Dependency-Fights und einer Reise in die Abgründe von StackOverflow wollte sich ein Fehler partout nicht fixen lassen. Also blieb nur die Möglichkeit, selbst einen StackOverflow-Artikel zu verfassen. Am schnellsten erhält man dort Antworten mit einem MCVE, einem Minimal Complete Verifiable Example, welches nur das Coding enthält, welches zum Fehler führt. Es ist nicht das erste Mal, dass mir dabei der Fehler aufgefallen ist und somit fühlt sich die Woche doch noch erfolgreich an.

Nachdem wir einen russischen Kommentar auf unserem Blog entdeckt haben, wurde es außerdem Zeit, uns mit dem Impressum und der Datenschutzerklärung zu befassen.

2020-06-23 Ziele definieren und Einarbeitung in Kotlin

Nachdem wir uns vorgenommen hatten, regelmäßig Artikel zu veröffentlichen, ist im letzten Monat erst einmal nichts mehr passiert.
Deshalb haben wir uns ein festes To-do erstellt, um jede Woche zumindest grob zu posten, was wir gemacht haben, womit wir uns beschäftigen oder woran wir arbeiten – selbst, wenn dabei nur ein paar Sätze rauskommen.
Vielleicht kann man das als eine Art Tagebuch betrachten. Vielleicht wird es für uns mal interessant sein, wenn wir darin lesen, zu sehen, wie wir uns entwickelt haben, mit welchen Problemen wir uns rumgeplagt haben.

Die letzten zwei Tage haben sich jedenfalls darum gedreht, dass wir in den letzten Wochen kaum vorangekommen sind. Also haben wir besprochen, wie wir weiter machen wollen. Wir haben uns überlegt, was wir überhaupt mit der APP erreichen wollen. Welche Probleme gibt es momentan zu bewältigen? In welche Themen müssen wir uns einlesen? Wie wollen wir den Blog weiter nutzen?

Letztendlich haben wir begonnen eine Art Backlog in Form einer To-do-Liste aufzubauen. Kommenden Montag werden wir unser erstes Backlog Refinement abhalten und die ersten Stories erstellen. Unser Ziel ist es bis Ende des Jahres einen Prototyp zu erstellen. Neben einer Login-Funktion soll es für unsere App (Details müssen noch folgen) möglich sein, Benutzergruppen anzulegen, diesen beizutreten und Gruppenziele zu definieren und diese gemeinsam mit anderen Gruppenmitgliedern anzugehen.

Parallel beschäftigen wir uns mit der Einarbeitung in Kotlin, App Architektur und Business Konzepten.

Die Ergebnisse werden wir in diesem Blog veröffentlichen.

Zum Schluss geben wir beide noch einen etwas detaillierten Einblick in die Themen, mit denen wir uns konkret befassen.

Verena
Seit dieser Woche steht unsere MVI-Architektur in Kotlin. Mit Hilfe einer simplen Beispiel-App, die einen Roundtrip zwischen UI, ViewModel und Repository simuliert, habe ich sie ausprobiert. Die Kombination von LiveData und Kotlins Coroutinen wirkt weitaus einfacher als DataBinding und RxKotlin und hat uns erst einmal überzeugt, weshalb wir uns dafür entschieden haben, die Architektur für unsere App zu verwenden. Das Repository ist noch gemockt, wird allerdings der nächste Schritt sein bevor es langsam mit der konkreten Implementierung losgehen kann.

Peter
Ich bin momentan weiter dabei mich in der Androidwelt zurechtzufinden. Speziell geht es auch darum die Apps und was dazu gehört in Kotlin umzusetzen.
Zur Motivation habe ich mir ein kleines Spiel überlegt. Nichts Neues – ein old school Snake -, das ich mit der Android Graphics Library umsetze. Ich könnte was Sinnvolleres entwickeln, aber an Spielen zu arbeiten, hat mich schon immer motiviert. Viele Probleme habe ich auch bereits gelöst. Es gibt eine Möglichkeit eine Snake zu platzieren, einen Rahmen zu setzen, Snake Elemente zum Einsammeln anzuzeigen und über einen simplen Controller kann die Snake gesteuert werden. Die gespawnten Snake Elemente können auch bereits eingesammelt werden. Allerdings fehlt momentan noch die Kollisionserkennung für die Rahmen Elemente.
Generell habe ich dabei viele Builder verwendet. D.h. es gibt einen separaten Builder für das Spielfeld, um die Grenzen festzulegen.
Über einen Snake-Builder kann gesetzt werden, mit wie vielen Elementen die Snake beginnen soll, wo sie platziert werden soll und in welche Richtung sie sich bewegen soll.
Um die Snake zu steuern, kann mit einem Controller-Builder eine Art Steuerkreuz dargestellt werden. Lustigerweise kann ich bspw. auch beliebige Controller hinzufügen, um die gleiche Snake zu steuern. Vielleicht ergeben sich daraus lustige Spielmodus.
Nicht zuletzt gibt es einen Builder, um Snake Elemente, die eingesammelt werden können zu spawnen. Lustige Features dabei sind die Möglichkeit, die Elemente in zufälligen Farben zu erzeugen und anzuzeigen. Und es ist möglich einen Timer zu setzen, um Elemente zu spawnen. Bspw. kann ich sagen: bitte jede Sekunde ein neues Snake Element zum Einsammeln auf das Spielfeld platzieren. Im Screenshot sieht man, wie die momentane Umsetzung aussieht.
Mittlerweile habe ich mich durch das Spiel auch schon ganz gut in Kotlin eingearbeitet. So viel von mir.

Startschuss

Es ist soweit, die erste Stufe auf der Produkt-Treppe® ist erklommen. Hier kommt unser Blog, der euch an den Entwicklungen auf dem Weg zur ersten App teilhaben lässt.

Ob Entwicklungsprozess oder neue und geplante Features, App-Idee-Ausarbeitung, Einarbeitung in neue Themen wie Firmengründung, App-Entwicklung, UX, psychologische Themen wie beispielsweise Verhaltensforschung und wer weiß was noch so alles dazu kommt: Wir möchten euch über alles informieren, was uns auf unserem Weg wichtig erscheint.

Vielleicht inspiriert oder motiviert es den ein oder anderen, selbst ein Projekt zu starten und dieser Blog gibt euch eine erste Orientierung, wo ihr anfangen könntet.

Moment..Produkt-Treppe®? Mehr dazu im nächsten Post.