Full-Stack mit Angular und Node.js bei einem E-Learning-Unternehmen
Ein betriebliches Sprachlernprodukt: eine Angular-Web-App für Lernende und Admins, eine Node.js-API, die auch die mobilen Apps versorgte, eine Statistikansicht und eine Modernisierung der Tests mit Jest.
Führungskräfte konnten nicht sehen, wie ihre Beschäftigten tatsächlich lernten, und Inhaltsupdates mussten alle Lernenden erreichen, bevor sie weiterüben konnten.
- Rolle:
- Full-Stack-Entwickler: die Angular-Web-App und die Node.js-API hinter allen Clients
- Stack:
- Angular · Node.js · TypeScript · Jest · Jasmine · GitLab
- Zeitraum:
- 2022–2023
- veröffentlicht:
Problem und Rahmenbedingungen
Bei einem E-Learning-Unternehmen brachte das Produkt Beschäftigten von Kundenunternehmen Sprachen bei: Die Lernenden übten in den Apps, und ihre Führungskräfte mussten sehen können, was dieses Üben ergab, also nicht nur, ob jemand Erfolg hatte, sondern auch, wie sehr sich die Leute anstrengten.
Das Team war klein: zwei Entwickler und eine Projektleitung, die die Prioritäten setzte. Ich baute das Node.js-Backend und die Angular-Web-App, der andere Entwickler auf diesem Backend die Flutter-Apps für iOS und Android. Für eine eigene CI/CD-Pipeline blieb da kein Raum (die Versionsverwaltung lief über GitLab), und pragmatische Entscheidungen, die zwei Personen tragen konnten, hatten hohen Stellenwert.
Eine Rahmenbedingung zählte mehr als alle anderen: Die Lerninhalte selbst (Fragen, Antworten, Level) änderten sich mit den Releases, also mussten alle Lernenden auf der aktuellen Version sein, um weiterüben zu können, und Clients und Backend mussten sich einig sein, was „aktuell“ bedeutet.
Architektur
Die Web-App ist eine zur Installation verpackte Angular-SPA auf einer Node.js-API, beide in TypeScript, sodass dieselbe Sprache und vieles von derselben Denkweise vom Bildschirm bis zum Server reichten. Lernende nutzten sie oder die Flutter-Apps. Führungskräfte und Admins nutzten nur die Web-App, über die auch die mobilen Apps eingerichtet, gesteuert und verwaltet wurden.
Im Frontend bildeten nach den Figma-Entwürfen gebaute Komponenten das interaktive Herzstück: die Bausteine für Übungen, Antworten und Fortschritt, aus denen sich ein Lernablauf zusammensetzt. Für Führungskräfte zeigte eine Statistikansicht Nutzungshäufigkeit, aufgewendete Zeit sowie richtige und falsche Antworten, aufgeschlüsselt nach Beschäftigten, als einfache Tabellen statt mit einer Diagrammbibliothek.
Im Backend lieferte die Node.js-API die Lerninhalte an alle Clients und speicherte, was die Lernenden damit taten: gegebene Antworten, aufgewendete Zeit, abgeschlossene Sitzungen. Aus diesen Rohdaten berechnete sie die Zahlen je Beschäftigten für die Statistikansicht, sodass das Frontend fertige Daten erhielt, statt selbst zu zählen.
Die Ebenen trafen sich beim Update-Mechanismus: Neue Releases wurden über den nativen Benachrichtigungskanal angekündigt, die API meldete die aktuelle Inhaltsversion, und sobald ein Update erschienen war, konnten Lernende nach ihrer laufenden Sitzung im Web und auf Mobilgeräten erst weitermachen, wenn sie aktualisiert hatten. Die Entscheidungen dahinter stehen im Entscheidungsprotokoll unten, jede mit der Alternative, gegen die sie sich durchgesetzt hat.
Angular und Node.js nach Vue
Ich kam nach Jahren mit Vue und nur kurzem Kontakt zu Angular in diese Rolle, und die erste Überraschung war struktureller Art: so viele Deklarationen, verteilt auf separate Dateien, für jede einzelne Komponente, wo Vue die ganze Komponente in einer Datei unterbringt. Doch mit der Zeit lernte ich die Disziplin schätzen. Die von Angular erzwungene Struktur hält eine Codebasis auf eine Weise kohärent, die zählt, wenn ein sehr kleines Team sie trägt. TypeScript auf dem Angular-Client und dem Node.js-Server brachte einen zweiten Vorteil: eine Sprache und kein Kontextwechsel, wenn ein Feature von der UI zur API reichte. In diesem Modell produktiv zu arbeiten, auch wenn ich die Ergonomie von Vue weiterhin vorziehe, ist genau die Art von Bandbreite, die ich mir in jedem Team wünschen würde, das ich leite.
Ergebnisse
Die Führungskräfte bekamen, was ihnen gefehlt hatte: Einblick in Nutzungshäufigkeit, investierte Zeit sowie richtige und falsche Antworten, aufgeschlüsselt nach Beschäftigten, erfasst von der API und dargestellt in der Statistikansicht. Das zeigte Einsatz, nicht nur Erfolg. Die Update-Sperre, die sich Clients und Server teilten, hielt alle Lernenden auf aktuellen Inhalten, und wie neue Funktionen genutzt wurden, ließ sich nach jedem Release in der UX-Analyse beobachten. Und die modernisierten Tests machten die tägliche Entwicklungsschleife schneller, mit Tests, die schnell genug waren, um neben dem Programmieren mitzulaufen.
Lehren
Drei Erkenntnisse sind mir geblieben. Erstens: Framework-Disziplin ist ein Feature, keine Einschränkung; die Struktur von Angular leistete für unser kleines Team, was ein Styleguide für größere leistet. Zweitens: Wer beide Enden eines Features verantwortet, entwirft es anders; ob eine Berechnung in die API oder in den Browser gehört, lässt sich leichter entscheiden, wenn dieselbe Person beide Seiten schreibt. Drittens: Ohne CI-Pipeline ist die Ergonomie der Test-Werkzeuge das Quality Gate; die Investition in Jest zahlte sich nicht in einem Dashboard aus, sondern darin, wie schnell die Entwicklungsschleife laufen konnte.
Zentrale Entscheidungen
01 Harte Update-Sperre
Die Weiternutzung im Web und auf Mobilgeräten sperren, bis ein veröffentlichtes Update installiert ist, angekündigt über den nativen Benachrichtigungskanal und abgeglichen mit der Inhaltsversion, die die API meldet.
Jedes Release konnte Fragen, Antworten und Level ändern, also mussten alle Lernenden das aktuelle Paket haben, bevor sie weitermachen konnten, und die auf dem Server gespeicherten Ergebnisse mussten zu den Inhalten passen, die die Lernenden tatsächlich gesehen hatten.
Lernende konnten beenden, woran sie gerade saßen, und mussten dann aktualisieren, um weiterzumachen. Wie stark neu ausgelieferte Funktionen genutzt wurden, zeigte die UX-Analyse nach den Releases.
verworfen: Lernende auf veralteten Inhalten weitermachen und aktualisieren lassen, wann es ihnen passt
02 Statistiken auf dem Server berechnet
Nutzungshäufigkeit, aufgewendete Zeit sowie richtige und falsche Antworten je Beschäftigten in der Node.js-API zusammenfassen und der Statistikansicht fertige Zahlen liefern.
Die Antwortdaten wachsen mit jeder Sitzung; die Berechnung auf dem Server hielt die Datenmenge klein, die Angular-Ansicht einfach und die Zahlen überall einheitlich.
Die Statistikansicht blieb eine einfache Tabellenkomponente, die anzeigte, was die API lieferte, und sich dadurch auch leicht testen ließ.
verworfen: Rohdaten an den Browser schicken und die Statistiken in Angular berechnen
03 Jest für Unit-Tests
Jest für neue Unit-Tests einführen und dabei die bestehenden Jasmine-Workflows aktualisieren.
In einer großen TypeScript-Codebasis sorgten die parallelen Worker von Jest, das erneute Ausführen nur geänderter Dateien und ein reaktionsschneller Watch-Modus dafür, dass die Tests mit dem Programmieren Schritt halten konnten.
Jest brachte außerdem die Werkzeuge in einem Paket zusammen (Runner, Assertions, Mocks und Spies, Coverage), und Snapshot-Tests boten eine Regressionsprüfung für generierte Konfiguration und komplexe serialisierte Ausgaben. Da Jest auf Node.js läuft, passten dieselben Test-Werkzeuge zum Angular-Client und zum Backend-Code. Die Entwicklungsschleife war unser Quality Gate, und genau dort zählt die Ergonomie von Tests am meisten.
verworfen: Allein beim Standard-Setup von Angular mit Jasmine/Karma bleiben
Kennzahlen
| Kennzahl | Wert | Status |
|---|---|---|
| Gebaute Kernkomponenten | 14 | eigene Angabe |
Eigene Angaben: Nach den Figma-Entwürfen gebaute Komponenten für den zentralen Lernablauf