dark

Die Qual der Wahl

Avatar

Wahlen in München: ca. 950.000 Wähler, 400.000 Briefwähler, 1.000 Wahllokale, Rechenfehler, 10.000 Seiten Papier. Um hier besser zu werden hat der Stadtrat der Landeshauptstadt München beschlossen die Datenerhebung in den Wahllokalen zu digitalisieren. Umgesetzt wurde dieser Beschluss in Form einer offline-fähigen Single-Page-Application und Spring-Microservices im Backend.

Wahlen in einer Großstadt sind eine Herausforderung

 

Bei Wahlen in einer Großstadt fallen sehr viele Daten an. Die meisten davon auf Papier. Es fängt mit dem Wählerverzeichnis, also der Liste in der alle wahlberechtigten Bürger stehen, an und hört mit der Niederschrift auf. Nach der Stimmenauszählung im Wahllokal, werden in diese vom Wahlvorstand die Auszählungsergebnisse eingetragen. Je nach Andrang und Komplexität der Wahl ist dieser Schritt kurz vor Mitternacht abgeschlossen. Am nächsten Morgen, dem Wahlmontag, werden die Daten aus den Niederschriften von vielen fleißigen Helfern im Wahlamt vom Papier in ein Computersystem übertragen.

 

Die Probleme, die bei diesem Vorgehen auftreten liegen klar auf der Hand. Am Montag nach der Wahl entsteht ein großer Aufwand, um Daten, die kurz vorher auf Papier geschrieben wurden, digital zu erfassen. Das zweite Problem ist nicht so offensichtlich: Papier ist geduldig. Zu geduldig. Nach einem anstrengenden Wahltag und Auszählung müssen die ehrenamtlichen Helfer, mitten in der Nacht, mehr oder weniger komplexe – bei Kommunalwahlen sind sie durchaus komplex – Berechnungen zur Ermittlung des Ergebnisses durchführen. Sie werden von einem Taschenrechner unterstützt, aber trotzdem ist die Wahrscheinlichkeit, dass hier Fehler passieren relativ hoch. Eine vorgegebene Prüfung der erfassten Zahlen findet frühestens im Wahlamt, in grober Form, statt.

 

Um das besser zu machen, ist man in München auf die Idee gekommen, dass die Daten im Wahllokal direkt digital erfasst werden könnten. Ein Wahllokalsystem (WLS) könnte den Wahlvorstand bei der Dateneingabe durch Plausibilisierung unterstützen. Die Datenübertragung am Montag würde natürlich komplett entfallen. Papier wird dadurch leider nicht gespart. Die Niederschrift muss nach wie vor in Papierform vorliegen und vom Wahlvorstand unterschrieben werden. Dies ist eine gesetzliche Vorgabe.

 

Zwei weitere Vorteile einer digitalen Verbindung in die Wahllokale, liegt in der Kommunikation. Der Wahlvorstand kann online die Wahlbeteiligung übermitteln. Gibt eine Person ihre Stimme ab, so wird der Zähler einfach um eins erhöht. Dadurch ist es möglich, die Wahlbeteiligung in Echtzeit zu messen. Früher wurden 20 Wahllokale abtelefoniert und die Ergebnisse hochgerechnet. Bei 750 Urnenwahllokalen kann man sich vorstellen, wie genau diese Aussagen waren. Auch die Kommunikation von der Zentrale in die Wahllokale ist deutlich einfacher. Um alle Wahllokale über eine Änderung zu informieren, musste vor fünf Jahren ein Dutzend Menschen eine Stunde lang telefonieren – immer in der Hoffnung alle zu erreichen. Mit dem Wahllokalsystem geht das per Push-Nachricht. Diese Argumente haben den Münchner Stadtrat überzeugt. Er stellte das Budget zur Verfügung und die Umsetzung konnte beginnen.

 

Die Architektur

 

Eine der ersten Fragen, die bei Planung einer Softwarearchitektur innerhalb der Verwaltung geklärt werden muss, ist, von wo die Nutzer auf die Anwendung zugreifen. Die Regel ist ein Zugriff aus dem Backbone, inzwischen gibt es aber auch immer öfter Zugriffe aus dem Internet. Das ist auch in diesem Szenario der Fall. Die Wahllokale greifen aus dem Internet über eine sichere Verbindung auf das Wahllokalsystem zu (Abb. 1, Nr. 1). Interne Administratoren können aus dem Backbone die Applikation konfigurieren (Abb. 1, Nr. 2). Das heißt, ein Teil der Anwendung wird nach außen frei gegeben, der größte Teil ist im internen Netz. Welcher Teil der Anwendung von wo aus erreichbar ist, wird über zwei API-Gateways entschieden (Abb. 1, Nr. 3). In diesem Szenario sind es zwei API-Gateways. Natürlich können es auch mehr oder weniger sein. Diese sind so konfiguriert, dass die Clients tatsächlich nur auf den Teil der Anwendung Zugriff haben, den sie wirklich benötigen. Zudem verifiziert das Gateway jede Anfrage gegen die Security-Komponente – in diesem Fall mit OAuth gegen Keycloak.

 

Wichtig ist auch immer der Schutzbedarf der Daten. Bei Wahldaten ist naturgemäß die Integrität ein hohes Gut. Es darf für dritte keine Möglichkeit geben, die Daten auf der Strecke zwischen Wahllokal und Backend, aber natürlich auch nicht innerhalb des Kernsystems, zu manipulieren. Eine weitreichende Entscheidung in diesem Kontext war, dass die Authentifizierung der Rechner im Wahllokal über ein Zertifikat erfolgen muss. Es werden entsprechend alle Rechner in den Wahllokalen mit einer Zertifikatsdatei ausgeliefert. Für die Durchführung einer Wahl ist auch entscheidend, dass die Applikation robust ist. Fehler der Nutzer müssen abgefangen werden, aber auch Netzausfälle und Lastspitzen. Das ist vor allem deshalb eine Herausforderung, weil die Anwendung nicht regelmäßig produktiv betrieben wird. Wahlen finden in sehr großen Abständen statt. Dann muss in einem Zeitfenster von wenigen Stunden alles funktionieren. Eine Einschwingphase wie bei klassischen Applikationen, die in täglicher Nutzung sind, gibt es hier nicht.

 

Diese Rahmenbedingungen haben dazu geführt, dass im Backend das Spring-Framework (Spring-Boot) verwendet wird. Ein weiterer Pluspunkt für Spring sind die zahlreichen Plugins wie Spring-Security oder Spring-Data. Um auf Lastspitzen gezielter reagieren zu können wurde die Entscheidung getroffen, das Backend nicht monolithisch aufzubauen, sondern mit Hilfe einer Microservice-Architektur. Auch hier gibt es durch Spring-Cloud eine Framework-Unterstützung. Die Services und Gateways müssen miteinander kommunizieren. Damit man im laufenden Betrieb neue Service-Instanzen zu- bzw. abschalten kann, dürfen die Domains der Services natürlich nicht hart im Code verdrahtet sein. Erreicht wird das über eine zentrale Registry, bei der jeder Service unter einem Alias registriert und beliebig viele reale Adressen hinterlegt sind. Die aufrufende Komponente lädt in regelmäßigem Intervall die aktuellen URLs der Aliase aus der Registry und spricht diese im Round-Robin-Verfahren an.

 

Das Wahllokalsystem ist eine Anwendung, die in eine Gruppe anderer Wahlapplikationen eingebettet ist. Das sind in der Regel Kaufanwendungen. Der Zugriff auf diese Systeme erfolgt über mehrere Enterprise-Application-Integration-Komponenten (EAI) (Abb. 1, Nr. 5).

 

Front- und Backend-Architektur des Wahllokalsystems. (Abb. 1)

 

Frontend als Progressive-Web-Application

 

Jedes Wahllokal ist mit einem so genannten Wahlkoffer ausgestattet. Dies ist ein Notebook mit Drucker, fest verbaut in einer Art Koffer. Auf dem Rechner sind bereits alle notwendigen Installationen und Konfigurationen vorgenommen worden. So wird sichergestellt, dass die Auslieferung an die 1.000 Wahllokale kurz vor dem Wahlsonntag erfolgen kann. Die Inbetriebnahme der Geräte erfolgt durch den Wahlvorstand. Die Anwendung wird von ehrenamtlichen Laien bedient. Diese müssen unter Druck komplexe Aufgaben erledigen. Hier soll die Anwendung bestmöglich unterstützen. Um einen Wiedererkennungswert zu schaffen wurde als Styleguide die Material-Design-Spezifikation von Google verwendet. Auf Basis von Web-Components und Polymer wurde eine Progressive-Web-Application (PWA) gebaut, mit der die Kollegen im Wahllokal auch dann noch arbeiten können, wenn aktuell keine Verbindung mit dem Internet besteht.

 

Offline-Fähigkeit

 

Eine offlinefähige PWA basiert in der Regel auf einem Service-Worker. Das ist ein JavaScript-Programm, das unabhängig von der Webseite im Hintergrund läuft. Es kann zwar nicht den DOM manipulieren, hat aber vollen Zugriff auf die Netzwerkkommunikation, die vom Browser weg und zum JavaScript-Programm hin verläuft. Zusätzlich kann der Service-Worker auf die IndexedDB-API zugreifen. Die Technologie bietet bereits von Haus aus ein automatisches und feingranular konfigurierbares Caching von statischen Ressourcen. Auch ein Puffern von Netzwerkanfragen, die aufgrund mangelnder Konnektivität ins Leere liefen, lässt sich umsetzen. Das ist zwar bereits ein guter Ansatz, der allerdings einen Anwendungsfall außer Acht lässt: Was passiert, wenn diese statischen Ressourcen durch die Interaktion des Nutzers mit der Anwendung verändert werden? Wie führt man lesende und schreibende Netzwerkanfragen zusammen, um eine vollständige Offline-Fähigkeit zu erreichen?

 

Das Problem lässt sich durch Bord-Mittel des Service-Workers nicht lösen. Er bietet allerdings Funktionen an, die man genau für diesen Zweck einsetzen kann. Beispielsweise durch sogenannte Fetch-Events[1]. Ein Fetch-Event wird direkt vom Browser, bei jedem über die Fetch-API[2] abgesetzten Netzwerk-Request, erzeugt und an den Global-Scope des Service-Worker übergeben. Dieser kann dann beliebige Dinge mit den Daten machen, beispielsweise die Anfrage an die aufgerufene URL weitergeben oder aber die Informationen zwischenspeichern, falls keine aktive Internetverbindung besteht. Über das Fetch-Event kann auch eine Antwort an die aufrufende Anwendung zurückgegeben werden. Im besten Fall merkt der Nutzer vor dem Rechner oder Smartphone gar nicht, ob er mit dem Internet verbunden ist, oder nicht. Über dieses Feature lässt sich der Service-Worker als eine Art Middleware zwischen Browser und Backend einbauen.

 

Service-Worker in der Browser-Backend-Kommunikation. (Abb. 2)

 

Kombiniert man diese Möglichkeit mit einer REST-konformen HTTP-API, erhält man eine einfache Möglichkeit sämtlichen Anwendungs-Traffic automatisch offlinefähig werden zu lassen. Jede Ressource ist über eine eindeutige URL zu erreichen. Über die HTTP-Methode wird zwischen lesenden und schreibenden Anfragen unterschieden.

 

Lesende Anfragen (Abb. 2, Nr. 1) werden lokal in der IndexedDB des Browsers zwischengespeichert (Abb. 2, Nr. 4) und bei Bedarf wieder ausgeliefert (Abb. 2, Nr. 6 + 5). Die eindeutige Ressourcen-URL dient hierbei als Key zum Speichern der Daten. Schreibende Anfragen werden durch den SW ans Backend geschickt (Abb. 2, Nr. 2 + 3) und die zu sendenden Daten werden in der IndexedDB wieder mit der eindeutigen URL als Key gespeichert. Außerdem werden die Daten um einen zusätzlichen Dirty-Flag ergänzt. Dieser ist true, wenn ein schreibender Request nachweislich nicht im Backend gespeichert werden konnte, z.B. auf Grund von Netzwerkfehler, Backend-Fehler etc.

 

Abschließend muss nur noch eine Synchronisationslogik implementiert werden, die eventuell vorhandene Dirty-Daten wieder ans Backend sendet. Im Falle des Wahllokalsystems ist diese Logik sehr simpel: Ein Wahlvorstand arbeitet nur auf seinen eigenen Daten, somit können keine Konflikte mit anderen Nutzern bei der Synchronisation auftreten und die zuvor fehlgeschlagenen Anfragen müssen nur in zeitlich korrekter Reihenfolge erneut ans Backend gesendet werden.

 

Application-State

Polymer, bzw. die Web-Components-Spezifikation ist stark auf die Trennung zwischen Komponenten fokussiert. Von Haus aus gibt es, anders als beispielsweise bei Angular, nur wenig Mittel um Zustände über die gesamte Anwendung hinweg zu teilen. Trotzdem wird in etwas komplexeren Client-Anwendungen in der Regel eine Zustandsverwaltung benötigt. Gelöst werden kann dies über eine zusätzlich JavaScript-Bibliothek, die in die Anwendung eingebunden wird. Im konkreten Fall ist dies Redux[4]. Das ist ein Datenspeicher (Store), der über Aktionen (Actions) modifiziert werden kann. Ansonsten wird auf den Datenspeicher ausschließlich lesend zugegriffen.

 

Ohne Zugriff auf das Backend der Anwendung ist es auch notwendig, dass das Frontend seinen eigenen Application-State pflegt. Über einen gut definierten State lassen sich Validierungs- und Plausibilisierungsregeln leicht implementieren. Auch eine automatische Navigation in der Anwendung lässt sich so bewerkstelligen: Je nach Fortschritt des Nutzers in der Bearbeitung seiner Daten kann die Anwendung anhand des States die nächsten Schritte einblenden.

 

Redux schafft es, die von Polymer lose gekoppelten Komponenten wieder zu einer großen Gesamtanwendung zusammenzubringen und verhindert komplizierten Glue-Code. Der event-basierte Ansatz harmoniert hervorragend mit dem modernen Programmier-Stil des Databindings und bindet die Komponenten gleichzeitig nicht so fest aneinander, dass Abhängigkeiten entstehen.

 

Backend als Microservice-Application

 

Wie oben schon angedeutet, ist das Backend in Form einer Microservice-Architektur konzipiert und letztendlich umgesetzt worden. Ausschlaggebend für diese Entscheidung waren zwei Aspekte. Einmal gibt es bei der Wahl Lastspitzen (zu Beginn und am Ende), die Durch das verteilte Deployment optimal abgefangen werden können. Der zweite Grund liegt im Lifecycle-Management. Große, monolithische Anwendungen bringen bei Erneuerungen (beispielsweise Versions-Updates von grundlegenden Frameworks) immer das Problem mit, dass die Maßnahme für das komplette Verfahren in einem Zug durchgeführt werden muss. Dies ist oft ein organisatorisches Problem. Durch die physische Auftrennung der Applikation können auch die Lifecycle-Maßnahmen getrennt voneinander durchgeführt werden. Die komplette Architektur vorzustellen würde den Rahmen des Artikels übersteigen, deshalb wird auf zwei Aspekte detaillierter eingegangen: Security und Service-zu-Service-Aufrufe.

 

Security

 

In Sachen Security spielt sowohl die Authentifizierung als auch die Autorisierung eine wichtige Rolle. Nicht jeder, der potenziell Zugang zur Anwendung hat, darf auch alle Operationen ausführen. Im ersten Schritt wird der Rechner authentifiziert. Nur ein Rechner mit gültigem Zertifikat kann die Verbindung zum Server aufbauen, auf dem der Wahllokal-Client liegt. Hat der anfragende Rechner kein entsprechendes Zertifikat, wird er vom Proxy-Server abgewiesen.

 

Im zweiten Schritt wird ein Nutzer (jedes Wahllokal wird als ein Nutzer angesehen) authentifiziert. Er meldet sich über den Browser mit Nutzername und Passwort an. Im Rahmen der Wahllokalanwendung werden die Passwörter vor der Wahl zufallsbasiert generiert. Bei der Passwortgenerierung wird dieses Wertepaar serverseitig in einem Verzeichnisdienst gespeichert. Zusammen mit dem Nutzernamen werden die Passwörter ausgedruckt und zu den verplombten Wahlunterlagen gegeben. Diese werden kurz vor der Wahl in die Wahllokale transportiert und erst am Wahltag vom Wahlvorstand geöffnet. Danach wird der Wahlkoffer in Betrieb genommen und das Wahllokal meldet sich mit seinem Nutzernamen und Passwort an der Applikation an.

 

Die Anmeldedaten werden über eine verschlüsselte Verbindung vom API-Gateway entgegengenommen (Abb. 3, Nr. 1) und gegen den OAuth-Server – in diesem Fall ein Keycloak – aufgelöst (Abb. 3, Nr. 2). Dafür geht der OAuth-Server gegen den Verzeichnisdienst, in dem zuvor die generierten Anmeldedaten gespeichert wurden. Konnten die Anmeldedaten im Verzeichnisdienst gefunden werden, erzeugt Keycloak einen Token und schickt diesen zurück an das API-Gateway (Abb. 3, Nr. 3). Aus Sicherheitsgründen verlässt der Token das API-Gateway nicht. Trotz allen zusätzlichen Schutzmaßnahmen wird der Client wie ein fremdes System behandelt. Im API-Gateway wird der Token in einer Session gespeichert und der Client bekommt die Session-ID zurückgeschickt. Mit dieser ID kann der Client dann Requests an das Backend schicken. Vorsicht ist geboten, wenn es aus Gründen der Ausfallsicherheit mehrere Instanzen des API-Gateways gibt. Dann muss entweder die Session geteilt werden, oder der vorgeschaltete Proxy-Server vergibt Sticky-Sessions. Bei jedem Request wird nun innerhalb des API-Gateways über die Session-ID der Token geladen und in die Service-Aufrufe eingebettet (Abb. 3, Nr. 4). Da jeder Nutzer einen eindeutigen und persönlichen Token hat, ist es möglich – selbst bei kaskadierenden Service-Aufrufen – nachzuvollziehen, welche Person den Aufruf initiiert hat. Das ist einerseits wichtig, um nachverfolgen zu können, wer wann Daten im System modifiziert hat. Andererseits ist es so möglich, einen nutzerspezifischen Security-Kontext im jeweiligen Service aufzubauen. Das wiederum ist wichtig, um bestimmen zu können, welche Operationen der Nutzer innerhalb eines Service ausführen darf. Die Informationen über die Berechtigungen werden nicht im Token mitgeliefert. Grundsätzlich wäre das über einen JSON-Web-Token (JWT) möglich. Da dieser aber im Header transportiert wird, ist die Größe des Tokens durch die Standard-Einstellungen der Server beschränkt. Diese kann man in der Regel modifizieren. Daran muss man aber auch beim Transfer nach der Produktion denken. Es ist zumindest ein weiteres, vermeidbares Risiko.  An dieser Stelle muss man die Entscheidung treffen, ob man mit wenigen, sehr groben Rollen arbeiten kann. Dann ist diese Methode durchaus sinnvoll. Bevorzugt man ein fein granulares Berechtigungskonzept, beispielsweise auf Ebene der Operationen, dann wird der JWT schnell zu groß. Abhilfe kann hier geschaffen werden, indem bei jedem Request die Berechtigungen des Nutzers vom OAuth-Server geholt werden (Abb. 3, Nr. 5 + 6). Das ist erst einmal ein Overhead. Dieser kann aber relativ einfach durch intelligentes Caching an der Schnittstelle zum Security-Server minimiert werden.

 

Kommunikationswege zum Aufbau des Security-Kontextes. (Abb. 3)

 

Service-zu-Service-Calls

 

Ein weiterer interessanter Aspekt, der in einer Microservice-Architektur völlig anders umgesetzt wird, als in einer monolitischen Anwendung, ist die Kommunikationen zwischen den Modulen. Es wird in der Regel nicht nur eine Kommunikation zwischen API-Gateway und Service geben, sondern im Rahmen von kaskadierenden Aufrufen auch unter den Services selbst. Das kann man event-basiert lösen, indem man die Services an einen Bus anschließt, auf dem die Nachrichten übertragen werden. Vorteil dieser Lösung ist, dass die einzelnen Services sich tatsächlich nicht kennen. Jeder Service kennt nur die Adresse des Busses und weiß auf welche Ereignisse er reagieren muss. Dadurch kann man weitestgehend eine lose Kopplung zwischen den Komponenten erzielen und sogar neue Services in die Anwendung einbinden – quasi per Plug-and-Play – ohne andere Services anfassen zu müssen. Trotzdem können sie miteinander kommunizieren. Nachteil dieser Lösung ist, dass die Kommunikation sehr implizit erfolgt. D.h. wenn Service A eine Nachricht erzeugt, dann weiß er (und damit auch der Entwickler) nicht, was diese Nachricht im Rest des Systems auslöst. Dieser Ansatz war für die Landeshauptstadt München zu diesem Zeitpunkt ungewohnt. Bisher wurden monolithische Anwendungen mit direkten Kommunikationsbeziehungen entwickelt. Um nicht den zweiten Schritt vor dem ersten zu machen, wurde beschlossen, in dieser kritischen Applikation ebenfalls auf direkte Kommunikationsbeziehungen zu setzen.

 

Spring bietet hierfür auch eine Reihe ausgereifter Werkzeuge. Zentral ist in einer klassischen (virtuellen) Serverlandschaft[3] die Registry. In dieser wird für jeden Service ein Alias gespeichert. Diesem Alias werden die URLs der Service-Instanzen zugeordnet. Ein aufrufender Service lädt von dieser Registry regelmäßig die aktuellen Instanzen der Aliase herunter und speichert diese zwischen (Abb 4, Nr. 1 + 2). Bei einer Anfrage wird lokal anhand des Alias eine verfügbare URL aufgelöst (im Round-Robin-Verfahren) und die Anfrage an diese URL gestellt. Dieses Verhalten bringt Spring-Cloud mit sich und muss nur bei Bedarf angepasst werden. Für den Entwickler selbst sind die Aufrufe relativ unkompliziert zu implementieren. Für jeden aufzurufenden Service wird im einfachsten Fall ein Client-Interface erstellt. Auf diesem wird mit der Annotation @FeignClient der Alias angegeben (in diesem Fall ServiceC) und gegebenenfalls eine Fallback-Klasse die einspringt, wenn ServiceC nicht erreichbar ist. (Listing 1) zeigt einen Code-Ausschnitt.

 

 

 

Im Interface selbst müssen nur noch die Methoden mit den entsprechenden Mappings angegeben werden, wie man sie auch aus den Spring-Controller-Klassen kennt. Die Clients können innerhalb des Spring-Kontextes per Dependency-Injection eingebunden und verwendet werden. Beispielsweise um die hello Ressource in ServiceC aufzurufen (Abb. 4, Nr. 3).

 

Kommunikationswege für einen Service-zu-Service-Aufruf. (Abb. 4)

Fazit:

 

Der in diesem Artikel dargestellte Zustand ist nicht identisch mit dem ersten Wurf der Anwendung. Das Wahllokalsystem hat in den vergangenen Monaten einen Wandel durchlaufen. Technische Probleme in Fremdsystemen, mangelnde Resilienz gegenüber diesen und ein historisch gewachsenes Frontend erforderten einen kleinen Neuanfang. Es wurde schnell festgestellt, dass der bisherige Service-Schnitt im Backend an mehr als nur einer Stelle schlecht gewählt war, was zu unnötigem Netzwerk-Traffic und Abhängigkeiten führte. Auch wurde REST an vielen Stellen nicht konsequent eingehalten, was die Kommunikation zwischen Frontend und Backend nicht übersichtlicher gestaltete.

 

Zu guter Letzt wurde das Frontend komplett neu aufgebaut. Zuvor wurde auf eine veraltete Angular-Version (1.6) gesetzt und die Code-Basis war stark verworren, sodass Änderungen am Client immer das Risiko neuer Bugs mit sich zogen. Auch die Offlinefähigkeit war hoch komplex umgesetzt und wurde regelmäßig in der Entwicklung falsch bedient, was zu weiteren Problemen führte.

 

Ziel war es also gewesen, das Backend zu entzerren, Kommunikationsbeziehungen und Abhängigkeiten zwischen Services abzubauen und eine einheitliche API bereitzustellen, mit der ein neues Frontend gut zusammenarbeiten kann. Das Frontend sollte modularer werden, stark getrennte Komponenten mit klar definierten Aufgaben und Funktionen – weshalb Polymer mit Web-Components zum Einsatz gekommen ist. Diese Modularisierung in Kombination mit einer stark vereinfachten Offlinefähigkeit und Statemanagement hat nicht nur der Qualität der Code-Basis, sondern auch dem Verhalten und der Nutzerfreundlichkeit der Anwendung einen gehörigen Schub gegeben. Die neue Architektur hilft auch dabei, schnell kurzfristige Anforderungen für die unterschiedlichen unterstützten Wahlarten zu implementieren.

 

Auch wenn nur wenige Monate Zeit für diesen Rewrite zur Verfügung standen, konnte alles On-Time fertig gestellt werden und auch den Kunden überzeugen. Eine Weiterentwicklung des Angular-Frontends hätte weitaus mehr Zeit gekostet. Auch wenn ein Neuanfang zunächst schwer und risikobehaftet erscheint, so kann er in einigen Fällen doch von Altlasten befreien und die Qualität des Gesamtprodukts nachhaltig verbessern. Die Europawahl im Mai wird zeigen, ob das in diesem Fall auch so war.

 

 

Claus Straube ist IT Architekt bei der Landeshauptstadt München. Dort beschäftigt er sich damit, wie man neue IT Trends gewinnbringend für die IT einer großen Kommune nutzen kann. Schwerpunktthemen sind Java Anwendungsarchitekturen, JavaScript Technologien und Automatisierung in der Entwicklung. In den letzten Jahren hat er zahlreiche Vorträge gehalten und Artikel geschrieben.

www.muenchen.de

GitHub: github.com/xdoo

 

Fabian Wilms arbeitet seit 2017 bei it@M, dem IT-Dienstleister der Stadt München, als Lead Developer in verschiedenen Projekten für das Kreisverwaltungsreferat. Dort ist er für die Planung der Infrastruktur, die Anwendungsarchitektur und die Koordinierung der Entwicklung zuständig. Er steigt auch selbst gerne tief in den Code ein, um Architekturentscheidungen auch aus Entwicklersicht auf ihre Praktikabilität zu prüfen.

www.muenchen.de

Github: github.com/FabianWilms

 

 

Links:

[1] https://mzl.la/2C6XMXB

[2] https://mzl.la/2Wqn9xi

[3] In containerbasierten Infrastrukturen, wie beispielsweise Openshift, kann man auf die Registry verzichten, weil die Aufrufe von Container zu Container grundsätzlich über einen Alias aufgelöst werden. Die Verwaltung der Instanzen übernimmt hier die Infrastruktur und nicht die Anwendung selbst.

[4] https://redux.js.org/

 

 

Total
0
Shares
Previous Post

API-Design – Do’s and Don’ts

Next Post

MicroProfile für Microservices mit Java EE

Related Posts