Mobile Apps – Architektur zählt!

15. Juni 2016

Cross-Plattformentwicklung ist dank verfügbarer Technologien, Produkte und schlüsselfertiger Tutorials zumindest technisch kein Hexenwerk. Leider wird die Bedeutung von Architektur oft unterschätzt.

Cross-Plattformentwicklung für mobile Anwendungen ist ein seit Jahren stark zunehmender Trend, gerade für Business Apps. Anders als Consumer Apps müssen sich Business Apps in die bestehende Infrastruktur von Unternehmen integrieren und haben oft höhere Anforderungen an Aspekte wie Security oder Offline-Fähigkeit.

Ein weiterer Unterschied zwischen Business und Consumer Apps besteht in der Bandbreite der zu unterstützenden Plattformen. Im Consumer-Bereich kann man diese sicher auf Android und iOS beschränken, bei Business-Apps kommt fast zwangsweise Windows hinzu. Ein Grund kann sein, dass die Funktionen auch auf dem Desktop benötigt werden. Ein anderer Grund liegt in der bereits bestehenden Code-Basis und dem Know-How der Entwickler.

Vor diesem Hintergrund haben sich zwei Ansätze für die Cross-Plattformentwicklung für iOS, Android und Windows herauskristallisiert: Cordova, das den auf jeder Plattform vorhandenen Browser als Laufzeitumgebung nutzt, um lokal auf dem Gerät plattformunabhängiges HTML und JavaScript auszuführen. Und Xamarin, das mit Hilfe von Mono die Entwicklung von .NET-Anwendungen für iOS und Android erlaubt. Nachdem Microsoft Xamarin übernommen hat und das Framework kostenfrei zur Verfügung stellt, dürfte dieser Ansatz weiter Zulauf bekommen – speziell bei C#-Entwicklern.

Xamarin hat gegenüber Cordova den Vorteil, dass die Anwendungen nativ auf den jeweiligen Geräten laufen. Sämtliche Funktionen der jeweiligen Plattform sind zugängig und der Anwender erkennt keine Verhaltensunterschiede verglichen mit Anwendungen, die mit den originären Entwicklungsumgebungen geschrieben wurden. Und C#-Entwickler haben den Vorteil, dass sie sich in ihrer gewohnten Umgebung befinden: Visual Studio, .NET und C#. Das senkt die Einstiegshürde natürlich ganz erheblich.

Hinweis: Ich nutze im weiteren Verlauf Xamarin.Forms als Grundlage für die Diskussion. Die Argumente sind aber ohne weiteres auch auf Cordova übertragbar.

Die technische Basis ist vorhanden

Der schnelle Einstieg in die Cross-Plattform-Entwicklung wird mit dem Quickstart-Beispiel für Xamarin.Forms demonstriert:

Bild 1 - Projektstruktur

Die Solution besteht aus einem Projekt, das den gemeinsamen Code aufnimmt und drei Frontend-Projekten für die plattformspezifischen Anteile; die Idee ist natürlich, dass im gemeinsam genutzten Projekt der größte Code-Anteil entsteht.

Genügend Beispiele, wie man andere Anforderungen plattformübergreifend adressiert, findet man ebenfalls. Für die Datenhaltung hat sich etwa SQLite etabliert (link).

Wer sich mit Cordova auseinandersetzt, findet dort ähnliche Einführungen wie z.B. „Create your first app“ (link) oder das SQLite plugin (link).

Abseits dieser reinen Frontend-Thematik kommt bei mobilen Business Apps sehr schnell die Frage nach Backend-Integration auf oder die Synchronisierung von Daten über mehrere Geräte hinweg. Mit Azure App Services für Mobile Apps wird auch hier eine passende technische Lösung schlüsselfertig vorgestellt (link).

Es gibt also mehr als genug Quick-Starts, Templates und Tutorials, um loszulegen und kleine, überschaubare Anwendungen umzusetzen.

Technik alleine ist nicht ausreichend

Die Technik selbst ist in der Regel also nicht das Problem, in der Praxis werden die Erwartungen aber oft nicht erfüllt. Wir hatten etwa einen Kunden, der auf Xamarin aufsetzte und sich beklagt hat, dass er in seiner Lösung kaum mehr als 30% Code-Sharing hat. Bei einem anderen Kunden hätte die Fachseite gerne das UI an eine Fremdfirma vergeben, während sich die eigenen Entwickler auf die Fachfunktionen konzentrieren; leider war die Code-Basis nicht so sauber aufgeteilt, dass dies möglich gewesen wäre.

Die Technik alleine kann also nicht die Lösung sein.

Den oben angesprochenen Tutorials ist eines gemeinsam: Sie klären die technischen Fragestellungen, also APIs und Infrastruktur. Womit der Entwickler alleine gelassen wird, sind die abstrakteren Fragen. Wie halte ich das Datenmodell meiner SQLite-Datenbank mit der SQL-Server-Datenbank synchron? Welche Strategie nutzen Azure App Services zur Realisierung der Offline-Fähigkeit? Ist diese für meine Anwendung geeignet? Wie kann ich meine Logik testen, ohne von Authentifizierung abhängig zu sein?

Man muss sich also nicht nur Gedanken machen, welche APIs man aufruft, sondern auch, in welchen Klassen man diese Aufrufe vornimmt und wie man das Ganze automatisiert testbar gestaltet. Man muss die Strategien zu Offline-Fähigkeit oder auch Authentifizierung bezüglich der eigenen Anforderungen hinterfragen. Und man muss in der Lage sein, gewählte Lösungsansätze zwischen den verschiedenen Teilanwendungen – Backends und Frontends – konsistent zu halten.

Kurz gesagt: Es geht um Architektur.

Softwarearchitektur

Beim Stichwort „Architektur“ denkt der typische Entwickler sofort an die klassische Schichtenarchitektur, die für eine mobile Anwendung in erster Näherung so aussehen könnte:

Bild 2 - Architektur

Das ist in der Tat ein guter Ausgangspunkt. Insbesondere ist diese Darstellung frei von der gewählten Implementierungstechnologie, so dass man bestimmte Aspekte sehr allgemein lösen kann. Zum Beispiel kann man bereits in dieser einfachen Darstellung diskutieren, ob nur Online-Zugriff auf Backend-Systeme möglich ist oder ob lokale Speicherung hinzukommt und wo die Synchronisierung ansetzt.

Für eine konkrete Technologie muss das Bild aber weiter verfeinert werden, um dem Entwickler zusätzliche Hinweise zu geben. Bei Xamarin sollte man erkennen können, welche Teile als PCL (portable class libraries) ausgelegt werden und welche plattformabhängig sind. Sowohl diese als auch die einzelnen Schichten sollten durch klar erkennbare Schnittstellen abstrahiert werden.

Diese Trennung in Schichten sorgt für eine klare Trennung der Verantwortlichkeiten (Separation of Concerns) und ist an sich keine Besonderheit mobiler Anwendungen. Durch die Trennung teilen sich die Schichten aber oft von selbst in plattformabhängige und –unabhängige Bereiche ein.

Die bewusste Trennung von plattformabhängigen Diensten setzt voraus, dass man sich mit der Frage, welche Teilaspekte tatsächlich plattformabhängig sind, bewusst auseinandersetzt. Um ein konkretes Beispiel zu bringen: Navigation lässt sich rein technisch auf die Anzeige einer neuen Page reduzieren. Muss ich aber unterschiedliche Formfaktoren abdecken, dann kann das im Falle eines Tablets den Austausch eines Teilfragmentes meiner Oberfläche bedeuten, während auf einem Smartphone ein Dialog erscheint. Ob ich dies im plattformunabhängigen Code der ViewModels durch Fallunterscheidungen abdecke oder im plattformabhängigen Code des Navigationsdienstes realisiere, ist eine Entscheidung, die so oder so ausfallen kann – zumindest sollte sie aber bewusst und in Kenntnis der Konsequenzen getroffen werden.

Nicht zuletzt hat die Trennung in plattformabhängigen und –unabhängigen Code einen positiven Einfluss auf die Testbarkeit, denn ich kann PCLs mit regulären Unittest-Projekten in Visual Studio abdecken und plattformabhängige Funktionen durch Mock-Objekte simulieren.

Hier zeigt sich übrigens, dass „Cross-Plattform“ nicht unbedingt eine Beschränkung auf die gemeinsame Schnittmenge sein muss. Man kann durchaus Features, die nur auf einer Plattform vorhanden sind, zum Nutzen der anderen Plattformen verwenden.

Bei den angesprochenen Unittest-Projekten etwa laufen die Tests zwar auf dem Desktop, aber die Logik ändert sich ja nicht, so dass der Qualitätsgewinn auf allen Plattformen zum Tragen kommt.

Ein anderes Beispiel: Für mein Backend nutze ich SQL Server, bei den mobilen Apps SQLite. Für SQL Server habe ich mit Datenbank-Projekten und Entity Framework eine gute Unterstützung, was Tools und Code-Generierung angeht. Mit geeigneten T4-Templates kann ich mir aus dem Entity Framework-Modell des Backends aber auch die entsprechende Logik für SQLite für die mobilen Apps erzeugen lassen.

Systemumgebung

Mobile Anwendungen unterscheiden sich in einigen Punkten grundsätzlich von klassischen Desktop- oder Server-Anwendungen. Dies beginnt bereits beim Deployment, bei dem die Betreiber der AppStores eine zusätzliche Hürde darstellen, die mindestens Zeitverzug mit sich bringt – Hotfixes werden also ein Problem. Läuft die Anwendung, stellt sich die Frage nach dem Zugriff auf Backend-Systeme. Von der grundsätzlichen Erreichbarkeit über das Internet und Themen wie Authentifizierung einmal abgesehen, ist es unwahrscheinlich, dass existierende Backendsysteme bereits auf die besonderen Anforderungen von mobilen Anwendungen vorbereitet sind.

Bild 3 - Systemübersicht

Ich muss mir also Gedanken machen, wie ich den Ressourcen-Beschränkungen mobiler Geräte Rechnung tragen kann. Schlechte Verbindungen und das Datenvolumen der Mobilfunk-Verbindungen sind ein Aspekt; sobald Offline-Fähigkeit hinzukommt, muss man sich außerdem mit Synchronisierung und Konflikten auseinandersetzen. Ein Pattern, das in diesem Zusammenhang gerne verwendet wird, ist CQRS (Command-Query-Responsibility-Segregation), weil es Datenmengen reduziert und Konflikte auf natürliche Weise umgeht. Allerdings hat CQRS – wenn man es konsequent einsetzt – grundlegende Auswirkungen auf das Datenmodell und die Anwendungslogik.

Der Einsatz von CQRS gehört also zu den Weichenstellungen, die sich nachträglich nur sehr schwer korrigieren lassen. Nicht zuletzt weicht CQRS deutlich von der „Last-one-wins“-Strategie ab, die bei Azure App Services für Mobile Apps zum Einsatz kommt. Wer sich also von den schnellen Erfolgserlebnissen der einschlägigen Tutorials blenden lässt, hat womöglich aufs falsche Pferd gesetzt.

Zukunftssicherheit

Wer sich mit Cross-Plattformentwicklung beschäftigt, tut dies üblicherweise, um Aufwände zu reduzieren und Synergieeffekte zu nutzen. Und bei einer Momentaufnahme erfüllt das auch die Erwartungen. Bringt man jedoch den Faktor Zeit mit ins Spiel, dann wird Heterogenität womöglich doch wieder zu einem Thema, mit dem man sich beschäftigen muss. Im Projekt können jederzeit neue Anforderungen entstehen; daneben könnten sich durch die schnellen Innovationszyklen bei mobilen Geräten (oder auch bei Cloud-Services, die man verwendet) die Rahmenbedingungen ändern.

Anders ausgedrückt sollte man gerade bei Business Apps, die einen deutlich längeren Lebenszyklus haben als Consumer Apps, damit rechnen, dass trotz Cross-Plattform-Ansatz weitere Plattformen separat unterstützt werden müssen. Das könnte zum Beispiel die Einbettung in ein SharePoint-Portal sein – es könnte aber auch um eine Plattform gehen, die heute vielleicht noch gar nicht existiert.

Wenn man in die Situation kommt, nachträglich eine weitere Plattform unterstützen zu müssen, mit der kein Code-Sharing möglich ist, dann ist eine solide Architektur und eine saubere Code-Basis trotzdem der beste Ausgangspunkt.

Wenn ich die grundlegende Anwendungsarchitektur übertragen kann, anstatt mir erneut Gedanken zum Beispiel über die Umsetzung von Offline-Fähigkeit zu machen, dann findet Wiederverwendung zumindest auf Ebene der Konzepte statt. Wenn ich darüber hinaus meine Code- und Klassenstruktur vergleichbar halte – einfach indem ich meine existierende C#-Klasse in JavaScript in eine TypeScript-Klasse überführe – nutze ich nicht nur das bisher erarbeitete Wissen. Ich beuge zudem diffizilen Detailunterschieden vor, die sich bei einer unabhängigen Neuimplementierung einschleichen können. Diese können technischer Art sein – etwa unterschiedliche Auflösung von Konflikten bei geräteübergreifender Synchronisierung – oder Unterschiede bei der Benutzerführung, die dem Anwender das Leben unnötig schwermachen. Nicht zuletzt wirkt sich das positiv auf die Wartbarkeit aus, denn Änderungen lassen sich leichter zwischen den beiden Systemen abgleichen.

Fazit: Architektur zählt!

Ich habe die drei Bereiche Softwarearchitektur, Systemumgebung und Zukunftssicherheit herausgegriffen, um zu belegen, dass Architektur für mobile Anwendungen mindestens genauso wichtig ist, wie in den klassischen Bereichen.

Tatsächlich ist die Liste der spezifischen Herausforderungen für die Entwicklung mobiler Business Apps noch deutlich länger:

  • Heterogene Plattformen, die verstanden und unterstützt werden wollen
  • Neue Bedienerparadigmen und Einsatzszenarien
  • Deployment über AppStores, Enterprise-Stores oder Side-Loading.
  • Neue Ansätze bei Authentifizierung und Security
  • Spezielle Integrationsanforderungen in die bestehende IT-Landschaft
  • Offline-Fähigkeit benötigt Synchronisierung und Konfliktbehandlung
  • Fehlertracking und Diagnose auf dem mobilen Gerät

Man könnte die Liste sicher fortsetzen.

Natürlich kann es sein, dass der Beispielcode aus einem Tutorial ausreichend ist, um die Anforderungen umzusetzen. Ich sehe aber zu oft Anwendungen die auf Basis von Tutorials schnelle Erfolge vorweisen konnten, um dann im Projektverlauf festzustellen, dass weitergehende Funktionalitäten unnötige Aufwände verursachen oder schlicht nicht umsetzbar sind.

Aufgrund meiner Erfahrung und die meiner Kollegen aus zahlreichen Business App-Projekten mit unterschiedlichen Cross-Plattform-Technologien plädiere ich daher für eine bewusste Auseinandersetzung mit Architektur, um die Erwartungen von IT, Fachseite und Anwendern zu erfüllen.

Das ist umso wichtiger, da die meisten Entwickler auf deutlich weniger Erfahrung im Bereich mobiler Apps bauen können, als das bei klassischen Web- oder Windows-Anwendungen der Fall ist.