Grundproblem bei einer komplexen Web-Anwendung
Beste UI/UX beißt sich mit Anforderungen an Wartbarkeit
Was macht Frontend-Architektur schwierig?
Das "Problem" ist der Benutzer!
- alles soll wirken wie aus einem Guss
- einheitliches Layout (UI)
- einheitliches Bedienkonzept (UX)
- reaktionsschnelles UI, auch unter Last
- Anzeige soll jederzeit über alle Komponenten konsistent sein
- alles von Anfang an da, ohne Verzögerung
Wo ist das Problem? Das ist doch einfach oder?
Prominente Gegenbeispiele
- Facebook, LinkedIn, XING: Alle kämpfen mit uneinheitlichem Anzeigestand
- Gmail: Ladebalken am Anfang, langsamere erste Page Impression
- Amazon: uneinheitliches Layout und Bedienkonzept
- Viele seiten von Behörden/Ämtern/Großkonzernen etc.: zähes UI, validieren der Eingaben erst nach Submit
Sind die alle unfähig?
Oder liegt das eher an Konflikten mit anderen typischen Anforderungen?
Natürlich soll das alles auch
- schnell und kostengünstig entwickelt werden
- über Jahrzehnte wartbar sein
- als Komponenten oder Teilprojekte entwickelbar sein
- eine einheitliche Architektur haben
- zum Skillset der vorhandenen Entwickler passen
Klassiche Webanwendung
jeder Boot tut gut, jeder Roundtrip setzt Zustand zurück
Copyright 2016, embarc
Klassichen Webanwendungen
- Browser sendet HTTP-Request und empfängt HTML
- Content wird auf der Server-Seite gerendert
- Jede Interaktion wiederholt diesen Zyklus
Klassische Webanwendung: Oft ein nahe liegender Ansatz
- Klassische Webanwendung sind für viele Enterprise-Entwicklungen der natürliche Ausgangspunkt
- Server-Seitige Entwicklung mit Java/C# und HTTP und HTML sind gut verstanden
- kleinere UI-Änderungen können auf Client-Seite mit JavaScript-Schnippseln (jQuery) realisiert werden
- häufig ist dies völlig ausreichend
Grenzen
- UI/UX ist grunsätzlich eingeschränkt
- selbst in vermeintlich klassischen Anwendungen verstecken sich SPAs oft als Teile
- z.B. JSF Komponenten mit einem komplexen UI
- Vermischung von client- und serverseitigem Rendering macht Anwendungsarchitektur und Programmiermodell abenteuerlich
Perfide, da zuerst die Aufwände zur Umsetzung ansteigen und der Code immer unübersichtlicher wird.
Was geht nicht mehr als Klassische Web Anwendung
Ein Beispiel
Gar nicht mal so komplex...
Nächster Schritt
Single-Page Application
Überblick: Single-Page Application
Copyright 2016, embarc
Single-Page Applications (SPAs) verschieben eure Anwendung in den Browser
- eine einzige Seite pro Anwendung/Modul
- läuft ohne signifikanten Server-Anteil
- kann auch als statische Web-Seite laufen
- ermöglicht Offline-Betrieb
- Bedienbarkeit wie Desktop
- Browser bietet mächtige Speicherungsmöglichkeiten
Komponenten basierte Ansätze mit Templates
- Templates nun auf der Clientseite
- Anwendung bekommt Struktur
- Logik hängt an Komponenten, ist keine lose Schnippsel-Sammlung wie bei jQuery
Findet sich wieder in React, Angular, Vue und Web Components
Smart and Dumb Components
Klares Architektur Pattern
Heißt auch Mediator Pattern bei Web Components / Polymer
Smart Components
- Verwalten Teilzustand der Anwendung
- Reichen Teile des Zustands als unveränderliche Daten an Unterkomponente weiter
- Enthalten UI Logik, die sie als Callbacks an ihre Unterkomponenten weiter geben können
- Meist spezifisch für eine Domäne
- Nicht außerhalb der Domäne wiederverwendbar
Dumb Components
- Managen höchstens transienten State
- enthalten keine Logik
- Unterkomponente sind meist selbst nur Dumb Components (es gibt
Ausnahmen)
- haben kein Wissen oder Abhängigkeit zu Oberkomponenten
- wiederverwendbar
Copyright 2017, Nils Hartmann
Code Sample Angular
Smart Component
@Component({
template: `<sub greeting={{greeting}} (onSend)="sent($event)">`
})
export class AppComponent {
// component state
private greeting: string = 'Hiho';
constructor(private greetingService: GreetingService) {
}
// "Business Logic" delegated to service
sent(greeting) {
this.greeting = this.greetingService.greetBack(greeting);
}
}
Grenzen
Besonders bei wachsenden und langlebigen Anwendungen
- Tendenz zu "Gottkomponenten": Zustand und Logik wandern langsam nach oben in eine einzige Komponente
- Vermischung von Framework und UI-Logik (erschwert Austausch das Frameworks)
- Verteilter, veränderlicher Zustand erschwert Wartbarkeit
- Zustand oft nicht klar zuzuordnen
- In welchem Zustand ist die Anwendung?
- Architektur immer noch unklar
- Wo ist Nebenläufigkeit erlaubt?
- Wie läuft die Initialisierungsphase
- Wie testet man die Business Logik?
Nächster Schritt
Redux als Architektur-Muster
Redux
Zustand wird zentral gehalten, UI-Logik geht aus den Komponenten
Selbst kein Framework, sondern nur ein Muster (wie z.B. MVC)
Redux ist unabhängig vom Framework
Implementierungen existieren für alle wichtigen UI-Frameworks
Resultierende Architektur anhand des Redux Musters
Redux extrahiert Verwantwortlichkeiten aus UI-Framework
Code Sample: Reducer
Nur eine Funktion, daher unabhängig vom UI Framework
type Greeting = {
greeting: string;
name: string;
}
type SaveGreetingAction = {
type: 'ADD_GREETING',
greeting: Greeting
}
function greetingsReducer(state: Greeting[] = [],
action: SaveGreetingAction) {
switch (action.type) {
case 'ADD_GREETING':
// immutable operation, creating new state
return [...state, action.greeting];
default:
return state;
}
}
Code Sample: Action Creator
Ebenso unabhängig vom UI Framework
async function loadGreetings(dispatch) {
try {
const response = await fetch(BACKEND_URL);
const json = await response.json();
dispatch({
type: SET_GREETINGS,
greetings: json
});
} catch (err) {
console.error('LOADING GREETINGS FAILED:', err)
}
}
Wieder nur eine Funktion, der einzige Ort an dem asynchrone Operationen erlaubt sind
Ist das nur eine spinnige Idee, oder nutzt das echt jemand?
Zusammenfassung Redux
- Ein Architektur-Muster für UIs
- Kontroll-/Datenfluss in eine Richtung
- Zustand wandert aus Smart Components in zentralen State
- UI-Logik wandert aus Smart Components in Action-Creators und Reducer
- Nebenläufigkeit nur in Action-Creators
- State ist zentral und immutable
- Business Logik ausschließlich in puren Funktionen - Reducer (beste Testbarkeit)
- Nur Reducer dürfen State verändern
- Initialisierung durch initiale Aktion
Grenzen: SPA Ansatz selbst
- SEO
- First-Page-Impressions
- Preview, z.B.
- bei der Vorschau von Suchergebnissen
- oder dem Teilen von Links durch Social Media
SPA: First-Page-Impression
Selbst für eine einfache Web Application kann das Laden und das Aufbauen der Anwendung einige Zeit kosten
und was vom Sever kommt ist eine leere Seite
Nächster Schritt: Universal Web Apps
Universal Rendering: First-Page-Impression
Universal Rendering
- First-Page-Impression wird auf dem Server gerendert
- Links werden als normale HTML-Links in die Seite gerendert
- Beliebig viele andere Seiten werden ebenfalls statisch gerendert
- Läuft dann (zumindest zum Teil) auch ohne JavaScript
- Code fast 100% geteilt zwischen Client und Server
- serverseitiges Rendering mit https://nodejs.org
- Neben Markup liefert der Browser ebenso Zustand
- Wird von JS-Frameworks React, Angular und Vue unterstützt
Herausforderungen / Schwächen
- Aller Zustand muss beim serverseitigen Rendering komplett vorliegen (oder man rendert statische Platzhalter)
- Falls First Page Impression ungültig: Flackern bei Neurendering im Client
- Unterschiedliche Locales auf Server und Client
- Zeitliche veränderliche Daten (Timestamp, Börsenkurs)
- Auch auf dem Server muss JavaScript laufen (zumindest für das Rendering Layer)
- Unklar, ob/wie das mit Web Components - besonders Shadow Dom - funktionieren könnte (headless chrome?,
https://twitter.com/DJCordhose/status/900328374601740288)
- Hilft nur bei "Time to first Meaningful Paint", nicht bei "Time to Interactive"
Was ist mit meiner guten alten Web-Anwendung passiert?
Ist das nicht alles zu kompliziert?
- Klassische, serverseitig gerenderte Anwendungen,
sind häufig wirklich einfacher und besser modularisierbar
- Hohe Anforderungen an UX und UI sind allerdings nicht mit sinnvollem Aufwand mit klassischen Web-Anwendungen umsetzbar
- die Komplexitäten einer Single Page App entspringen aus diesen Anforderungen an UX und UI
- Das Grundproblem ist der Widerspruch zwischen ganzheitlicher UX und Aufteilung in Komponenten / Module / Teams
Bonus Level
Legenden und Mythen
Wir sammeln
Was für potentielle(!) Mythen im Bereich Frontend-Architektur kennt ihr?
- React ist besser als Angular
Legenden und Mythen #1: Single Page Applications (SPA)
- In SPAs kann ich keine Links teilen und auch nicht sinnvoll verlinken:
Link wird im Browser aufgelöst und geroutet
- Back-Button geht nicht: siehe oben
- SPA hat immer eine schlechte First Page Impression:
Universal App oder Code-Splitting hilft
, Web Components brauchen nicht einmal Framework => weniger Code
, Service Workers und HTTP/2 Server Push
- SPA ist unstrukturierter Monolith:
Trennung, Isolation in Module und Teams ist mit gezeigten Ansätzen möglich
- HTML/HTTP sind langlebig, Investition in SPA-Frameworks nicht lohnend, veraltet innerhalb einer Woche:
Business relevante Teile außerhalb des SPA-Webframeworks
Legenden und Mythen #2: JavaScript
Ist JavaScript-Code nicht unwartbar?
- keine Lesbarkeit: moderner JavaScript-Code ist auf Python-Niveau, JSDoc ist Standard
- keine Analysierbarkeit:
wird durch zusätzliche mächtige Typensysteme TypeScript oder Flow erlaubt
- kein Refactoring: folgt aus Analysierbarkeit
- keine Testbarkeit: gezeigte Ansätze erlauben allerbeste Testbarkeit aller Teile
- keine Wiederverwendung:
Dumb Componentes jederzeit wiederverwendbar, bei Smart Components nicht sinnvoll
- keine Möglichkeit zur Strukturieren:
Das moderne JavaScript Modul-System ist mächtig
und erlaubt Strukturierung wie in Java
Legenden und Mythen #3: Integration mit Microservices geht nicht mit Client Side Redering
- Integration im Browser in eine Anwendung
- Anwendung ist in logische Module aufgeteilt, die als ganze Anwendung zusammen laufen
- Pro Seite eine SPA, kann Komponenten aus andern Modulen integrieten
- "Echt" getrennte Anwendung über iFrame und EventBus
- Integration mehrerer Anwendungen über Links, die eine neue Anwendung öffnen und die alte ersetzen
- jedes Modul ist eine eigene SPA Anwendung
- erlaubt Vertikalen wie eine klassische Web-App
- Allerdings: Modul-Wechsel setzt Zustand zurück wenn nicht explizit übertragen
The Doctor is In
| Architektur | Mythos | UI / UX |
20 |
Muss man für SPAs und Universal Apps JavaScript programmieren? |
Warum soll man überhaupt JavaScript machen?
|
Geht das nicht alles auch mit CSS?
|
40 |
Sollte ich nicht jede SPA als Universal App schreiben?
|
Widersprechen SPAs nicht der Grundidee es Webs? |
Wie realisiert man komplexe UI-Komponenten (ala TreeGrid)?
|
60 |
Risiko: Frage eurer Wahl |
Risiko: Frage eurer Wahl |
Risiko: Frage eurer Wahl |
80 |
Wieso funktioniert für SPAs kein Schichtenmodell?
|
Wie schneide ich Module in einer SPA? Geht das mit DDD Aggregate Root?
|
Wann passt eine klassische WebApp besser als eine SPA?
|
100 |
Was kann man retten, wenn man das UI-Framework wechselt? |
Was ist denn eigentlich mit Progressive Web Apps (PWA)? |
Muss ich immer wählen zwischen Frontend-Monolithen oder UX Katastrophe? |
Oliver Zeigermann / @DJCordhose,
http://bit.ly/architektur-herbstcampus