7 Dinge die eine moderne Web-App braucht

7 dinge die eine moderne web app braucht

In diesem Artikel erläutere Ich 7 wichtige Merkmale die eine moderne und benutzerfreundliche Web-App ausmacht.
Unabhängig davon, ob diese als Monolith oder Microservice Architektur aufgebaut wurde oder eine SPA oder Multipage Anwendung ist.

1. Eine intuitive Benutzeroberfläche (UI)

Die Benutzeroberfläche (UI) sollte nach Möglichkeit intuitiv und einfach zu bedienen sein, sodass Anwender auch ohne Dokumentation, den Inhalt und den Zweck einer Seite verstehen können.
Hierbei gilt es, komplexe Sachverhalte zu vereinfachen und verständlich zu visualisieren. Es sollten nur Informationen angezeigt werden, die für den User und dem jeweiligen Anwendungsfall relevant sind.

2. Asynchrone Verarbeitung

Die asynchrone Verarbeitung von Webanfragen ist insbesondere in der UI unerlässlich, da sonst das Browser Fenster blockiert und die Anwendung für den Zeitraum der Verarbeitung nicht benutzbar ist.
Aber auch im Backend ist der Einsatz von async und await sinnvoll, um den Mainthread der Anwendung nicht zu blockieren.

3. Robuste Web-Endpoints

Damit die UI unabhängig vom Backend entwickelt werden kann und nicht bei jeder Änderung die am Backend passiert, angepasst werden muss, sollten die Web-Endpoints stabil sein. Das bedeutetet, dass sie nur geändert werden, wenn es aus UI-Sicht notwendig ist.

Mithilfe von UI spezifischen DTOs (POCOs) für Requests und Responses und der Separierung von Endpoints nach deren Aktion (Create, Update, Delete, Action) und der Zustandsveränderbarkeit des Responses in der UI (readonly vs. read/write) für GET Abfragen, kann dies erreicht werden.


Routing Convention

Neben den DTOs ist auch ein einheitliches und verständliches Routing wichtig, auf dessen Standards sich alle im Entwicklerteam verlassen können.

Etabliert hat sich dabei der REST Standard mit Plural in der Route, gefolgt von der Entity-ID.
Ebenso sollten die Routen benannt werden, damit diese über OpenAPI verständliche Bezeichner erhalten.

[HttpGet("/orders/{id}", Name = nameof(GetOrder)]
public async Task<ActionResult<Order>> GetOrder([Required] int id) {}

Die Eingabeparameter sollten entweder als [Required] oder optional ([FromQuery] string? filterProperty) gekennzeichnet sein. Generell gilt, dass das Backend der UI nicht vertraut und daher Payload Properties generell als optional (?) behandeln sollte und die Eingaben vor der Ausführung validiert.

Hierzu gehört zur Einhaltung von Web Standards ein verständlicher HttpResponse mit dem zugehörigen HttpResponse Code. Durch Nutzung des generischen Typs ActionResult<T> können zur Validierung hilfreiche Rückgaben an die UI gemacht werden (NoContent, NotFound, Ok, etc.). Aus Sicherheitsgründen und aus Gründen der Benutzerfreundlichkeit, sollten Ausnahmen (Exceptions) behandelt werden und nicht der Stacktrace zurück gesendet werden.

4. Kurze Antwortzeiten

Damit die UI nicht lange auf Antworten des Backends warten muss, sollten alle Daten die an das Frontend übermittelt werden, komprimiert werden. Hierdurch wird die Größe der zu übermittelten Daten um ein Vielfaches verringert und die Übertragungszeit erheblich verkürzt (~Faktor 10).

Hierfür gibt es verschiedene Provider, welche unterschiedliche Komprimierungsverfahren einsetzen.


Filtern und Pagen

Vor der Komprimierung von Responses, sollte nach Möglichkeit die Inhaltslänge der Responses durch sinnvolles Filtern und Pagen verringert werden.


WebSockets mit Echtzeit-Updates (SignalR)

Damit die UI nicht selbst nach Änderungen auf dem Server fragen muss, haben sich WebSockets über SignalR bewährt. Dadurch bekommt die UI über eine dauerhafte Verbindung zum Server mitgeteilt, wenn sich der Zustand von Responses auf dem Server verändert hat. Hilfreich ist das insbesondere um nur Deltas an den Clients zu senden, statt erneut den kompletten Response.

5. Saubere Software Architektur

Eine saubere Softwarearchitektur auf der sich alle im Team verlassen können, sorgt für wartbareren und zuverlässigeren Code mit kürzeren Entwicklungszeiten, der flexibel gehostet und auf unterschiedlicher Infrastruktur genutzt werden kann.

Durch die Trennung des Business Layers (Core) von Infrastruktur und Client lässt sich der Business Layer mit unterschiedlichen Clients (z.B. Console, Desktop, WebApp, App) und Infrastruktur (z.B. PostGre/MSSQL, RabbitMQ/Kafka, Redis) nutzen und wiederverwenden.

Durch Anwendung des Single Responsibility Prinzips (SRP) und des Dependency Inversion Principle, welche in .NET einfach über Klassenkomposition und Dependency Injection umgesetzt werden können, lassen sich Teile der Anwendung gesondert als Modul oder Service bereitstellen und skalieren.

6. Personalisierbarkeit

Die Personalisierbarkeit der Anwendung an die Arbeitsweisen ihrer User, sorgt für eine größere Anwendungs-Akzeptanz und Zufriedenheit.
Es gibt manchmal nichts Ärgerliches als Einstellungen jedes Mal erneut vornehmen zu müssen oder sich nach kurzer Zeit wiederholt einloggen zu müssen (Single Sign-On). Im Gegensatz dazu erfreut es, wenn das Design angepasst und regionale Aspekte wie Sprache, Währung oder die lokale Zeitzone berücksichtigt werden.

7. Einfache Wartbarkeit

Damit die Anwendung auch während des Betriebes leichter gewartet und Fehler überprüft werden können, ist es sinnvoll die Anwendung von außen zu konfigurieren und hilfreiche Details über den Zustand (Health Check), Prozessfluss und Fehler zu loggen und bereitzustellen.

Dazu gehört auch das präventive Verhindern von Fehlern, in dem neben Compiler Fehlern, ebenso Warnings behoben werden und die Anwendung ausreichend getestet wird.


Nach oben scrollen