Kampf um die richtige Code-Diät

Low-Code vs. High-Level-Modellierung mit funktionaler Programmierung
Keine Kommentare

In den letzten Jahrzehnten hat es eine ganze Reihe von Initiativen gegeben, um das Programmieren aus dem Entwicklungsprozess zu entfernen oder zumindest zu minimieren. Das aktuelle Ergebnis ist die Low-Code-Programmierung, die sich jedoch an der ebenfalls auf Code-Diät gesetzten funktionalen Programmierung messen lassen muss.

Es ist seit jeher der große Traum des IT-Managements: Software entwickeln ohne Programmierer. Wäre das möglich, würde dies bedeuten, auf teure Entwickler weitgehend verzichten zu können. In den 1980er Jahren gab es sogenannte 4GLs, Programmiersprachen der vierten Generation. Diese machten typische Funktionen vieler Softwareapplikationen unmittelbar verfügbar und sollten so den Programmieraufwand drastisch reduzieren. Dabei ging es typischerweise um Applikationen, bei denen Benutzer im wesentlichen Daten eingeben, die in Datenbanken gespeichert, wieder angezeigt und zu Reports verarbeitet werden.

Eine andere Facette dieses Denkens findet sich in den unzähligen Excel-Sheets wieder, die in Unternehmen für kritische IT-Aufgaben herangezogen werden. In der Tat können auch Mitarbeiter, die nicht in Programmierung ausgebildet sind, mit Excel sogar Aufgaben beträchtlicher Komplexität erledigen, möglicherweise unterfüttert durch Code in VBA (Visual Basic for Applications). Spätestens, wenn VBA-Code Einzug hält, wird offensichtlich, dass auch das Erstellen von Excel-Sheets eine Form des Programmierens darstellt. So einfach es auch für Programmierlaien ist, damit anzufangen, stoßen Excel-Sheets irgendwann an ihre Grenzen. Dies betrifft vor allem die Automatisierung größerer Abläufe, die Bewältigung größerer Datenmengen oder die saubere Integration in die Konzern-IT. Die dann anstehende Migration ist oft schmerzhaft und teuer.

Das wohl erfolgreichste Projekt, die beschriebenen „Datenbank-Applikationen“ zu demokratisieren, ist Microsoft Access: Aus Datenbank-Schemata eine CRUD-Anwendung (Create, Read, Update, Delete) mit grafischer Benutzerschnittstelle per Mausklick zusammenzustellen, ist unschlagbar einfach. Aber auch hier gilt: Access-Anwendungen skalieren nur sehr begrenzt. Wenn die Anforderungen steigen, stehen auch hier oft schmerzhafte Migrationen an.

API Conference
Sheen Brisals

Modularizing your API with Domain Storytelling

Henning Schwentner (WPS – Workplace Solutions)

Software Architecture Camp

Modul Funar – Funktionale Softwarearchitektur

mit Dr. Michael Sperber (Active Group GmbH)

Wunsch nach „Softwareentwicklung ohne Programmieren“ führte zu Low-Code

4GLs verloren in den 90er Jahren irgendwann an Bedeutung, denn sie waren zu speziell und eingeschränkt. Der Wunsch des Managements nach „Softwareentwicklung ohne Programmieren“ blieb, und so ist die Bewegung wieder auferstanden in Form von „Low-Code-Plattformen“, die genau das suggerieren. Stattdessen werden Applikationen in einer grafischen Umgebung aus Blöcken zusammengesetzt und können direkt auf skalierbaren Cloud-Plattformen in Betrieb genommen werden, oft als mobilfähige Webanwendungen. Die begrenzte Skalierbarkeit von Excel oder Access ist hier also kein Thema mehr.

Ein genauerer Blick offenbart jedoch auch bei Low-Code-Plattformen die gleichen Einschränkungen wie seinerzeit bei 4GLs, Access und – in gewissem Sinne – auch Excel: Solange es bei einer Softwareanwendung nur um Eingabe, Anzeige und Reporting tabellarischer Daten geht, kommt man mit ihnen ziemlich weit. Jenseits dieses doch recht armseligen Bildes davon, was Software alles kann, stößt Low-Code auf eine Wand.

Beispiel: Programmierung einer Anwendung im Verkehrswesen

Wie sieht das konkret aus? Angenommen, es geht darum, eine Anwendung für die texanische Highway-Behörde zu schreiben, die verfolgt, welche Tiere sich auf dem Highway aufhalten und was mit ihnen passiert. Wir fangen klein an, mit den Gürteltieren. Die Behörde verfolgt, ob die Gürteltiere am Leben sind (viele werden auf dem Highway überfahren) und wieviel sie wiegen. In einer klassischen Datenbankanwendung beginnt dies mit einer Tabelle „Armadillos“ wie folgt:

Id alive? weight
1 True 10
2 False 12
3 True 9

Die erste Zeile repräsentiert ein lebendiges Gürteltier mit 10 kg Gewicht, das zweite ein totes mit 12 kg und so weiter. In einer Low-Code-Anwendung ließe sich jetzt grafisch eine Maske zusammenstellen, mit der diese Tabelle verwaltet werden kann. Dies bedeutet, neue Gürteltiere können eingegeben, die Tabelle angezeigt werden etc.

In Low-Code ist es außerdem möglich, einen Button anzulegen, auf den die Benutzer drücken, wenn gemeldet wird, dass ein Gürteltier überfahren wurde. Mit dem Button würde ein Arbeitsablauf beschrieben, häufig in einer BPMN-artigen Darstellung. Dazu gehört eine Aktion, die beschreibt, was eigentlich passiert. Das könnte etwa so aussehen:

Action: run over armadillo



Change Object



Table: Armadillos

Column: alive?

New value: False

Soweit so gut. Angenommen, die Anwendung wird erweitert, und zwar um Papageien, die plötzlich auf dem Highway aufgetaucht sind. Diese Papageien könnten in einer Tabelle „Parrots“ geführt werden:

id Sentence Weight
1 „Good day!“ 2
2 „Good night“ 1.5

Und auch hier wäre eine Aktion definierbar, welche das Überfahren eines Papageis beschreibt:

Action: run over parrot



Change Object



Table: Parrots

Column: alive?

New value: ""

Auch soweit so gut. Doch wie sieht es aus, wenn die Gürteltiere und Papageien in einer gemeinsamen Ansicht geführt werden sollen? Sie sind in zwei unterschiedlichen Tabellen gelistet, was das schon grundsätzlich erschwert. Das Konzept „ein Tier ist ein Gürteltier oder ein Papagei“ kann in relationalen Datenbanken nicht direkt ausgedrückt werden. Verschiedene Workarounds wären einen Versuch wert,

  • eine große Tabelle, mit allen Spalten aus „Armadillos“ und „Parrots“ und einer weiteren Spalte, die sagt, um welche Art Tier es sich handelt, oder
  • eine Tabelle mit zwei Spalten, die Verweise auf die beiden existierenden Tabellen enthalten, von denen nur jeweils ein Verweis aktiv ist.

Das mit den Workarounds wäre noch eine Weile so machbar, aber schnell käme ein nicht wartungsfähiges Kuddelmuddel dabei heraus. Wie würde es aussehen, wenn man diese Highway-Tiere irgendwie direkter modellieren könnte? Eine Formulierung in der funktionalen Sprache Haskell würde so aussehen:

data Animal =

   Armadillo { armadilloAlive :: Bool,

               armadilloWeight :: Float
 
 | Parrot { parrotSentence :: String,

           parrotWeight :: Float }

Der senkrechte Strich | heißt „oder“. Dementsprechend steht da: Ein Tier (Animal) ist entweder

  • ein Gürteltier, Armadillo, mit der Eigenschaft armadilloAlive vom Typ Bool und der Eigenschaft armadilloWeight vom Typ Float oder
  • ein Papagei mit Eigenschaften für Satz und Gewicht

Um den Tierbestand zu erfassen, lässt sich eine Liste anlegen:

highway = [ Armadillo True 10,

            Parrot "Good day!" 2,

            Armadillo False 12,

            Parrot "Good night!" 1.5]

Es ist also kein Problem, beide Klassen von Tieren zu mischen. Das geht natürlich auch in objektorientierter Programmierung, aber dafür wären ein Interface und zwei vergleichsweise aufwendig zu programmierende Klassen nötig. Die Haskell-Lösung hat also die Vorteile, dass sie mit weniger Code auskommt und sich der Code direkt an der Modellierung orientiert.

Auch Operationen lassen sich mit sehr wenig Code definieren. Zum Beispiel das Überfahren. Die Haskell-Definition besteht aus zwei Gleichungen – eine pro Klasse:

runOver (Armadillo alive weight) = Armadillo False weight

runOver (Parrot sentence weight) = Parrot "" weight

Was die Code-Menge betrifft, ist funktionale Programmierung also gegenüber Low-Code eher noch im Vorteil. Viel wichtiger ist aber, dass der funktionale Code weiterentwickelt werden kann, wenn die Anforderungen wachsen, während die Low-Code-Umgebung an ihre Grenzen stößt.

Moderne Low-Code-Umgebungen sind eine Art „Enterprise-Cloud-4GLs“

Moderne Low-Code-Umgebungen vereinfachen zweifelsfrei viele „Standardaufgaben“ bei der Programmierung, insbesondere bei der Datenbankanbindung und der Gestaltung grafischer Benutzerschnittstellen: Es reicht, alles zusammenzuklicken. Es handelt sich also gewissermaßen um „Enterprise-Cloud-4GLs“, welche die betrieblichen Skalierungsprobleme von Excel und Access beseitigen. Fast könnte man sich wundern, dass „herkömmliche“ Programmiertechnologien da nicht Ähnliches anbieten.

Aber nur fast: Für jede respektable objektorientierte Programmiersprache gibt es „ORMs“, also Object-Relational Mappers, welche viele Aufgaben bei der Abbildung von Domänenobjekten auf die Datenbank automatisieren. Genau wie bei ORMs wird diese Bequemlichkeit beim ersten Wurf der Anbindung aber erkauft durch erhöhte Bindung in der entstehenden Architektur: Das Datenbankmodell ist mit dem Datenmodell untrennbar verbunden, beide müssen sich gemeinsam entwickeln und erben darum jeweils die Marotten des anderen. Das führt zu einer Vielzahl von Problemen, wenn der Code wächst: die angesprochenen Modellierungsschwächen, unkontrollierbares Cache-Verhalten, schwieriges Debugging und großer Aufwand bei Änderungen. Entsprechend sind ORMs auch nach anfänglicher Euphorie aus der Mode geraten.

Mit den UIs verhält es sich ähnlich. Sie werden in Low-Code-Umgebungen (wie bei den großen UI-Baukästen der Vergangenheit – Visual Basic 6 und Delphi) eng an die Datenmodelle gekettet.

Eingeschränkte Skalierbarkeit: Welchen Ausweg aus der Zwickmühle gibt es?

Low-Code-Umgebungen erlauben „Rapid Prototyping“ für einfache Anwendungen, wachsen aber nicht mit, wenn die Anforderungen steigen. Java und C# skalieren besser, aber die hohen Aufwände und großen Umstände zehren an den Budgets und vor allem der Entwicklerseele. Funktionale Sprachen hingegen produzieren zunächst einmal weniger Code, „lower code“ sozusagen. Sie automatisieren zwar nicht alles, aber die exzellente Unterstützung von UI-Programmierung und Datenbanken führt zu kompakten Lösungen ohne die gefürchtete architektonische Kopplung.

Viel wichtiger aber ist das, was uns allen am Herzen liegen sollte: Die Unterstützung für High-Level-Modelle, die Fachdomänen akkurat abbilden und flexibel mitwachsen. Was die Modellierung betrifft, eröffnen sich in der funktionalen Programmierung neue Welten – durch den uniformen Einsatz von Abstraktion und die Anwendung von Mathematik. Das mag alles so klingen, als ob die funktionale Programmierung nur hochqualifizierten Spezialisten vorbehalten sei. Tatsächlich aber ist sie der erfolgreichste Ansatz in der Programmierausbildung und damit für alle Profis in der Programmierung erlernbar.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -