Entwicklung eines Generators zur Erstellung von Softwarearchitekturen

Die Herausforderung

Bei der Entwicklung von Software treten bei fortlaufender Dauer, entsprechender Größe, Komplexität und bei häufig auftretenden Änderungen Herausforderungen hinsichtlich der Architektur des zu entwickelnden Softwaresystems auf. Diese bestehen zumeist darin, den immer größer werdenden Quellcode und die zunehmende Anzahl von Softwarekomponenten passend zu organisieren.

Die Architektur des Softwaresystems ist dabei maßgeblich für die Wartung und Anpassungsfähigkeit der Software als auch für die Einarbeitungszeit neuer Entwickler.

Möglicher Lösungsansatz

Für die Entwicklung einer besseren Softwarearchitektur existiert der Ansatz der modellgetriebenen Softwareentwicklung.

Bei diesem Ansatz werden sogenannte domänenspezifische Sprachen (DSL) eingesetzt, um eine abstrakte Beschreibung einer bestimmten Domäne zu erreichen. Aus dieser Beschreibung kann dann mit einem passenden Generator, der die domänenspezifische Sprache transformiert, ein lauffähiger Quellcode generiert werden. Dadurch wird mit einer passenden DSL und einem Code-Generator eine Softwarearchitektur erstellt, die die Wartung und Anpassungsfähigkeit des zu entwickeltem Softwaresystem verbessert.

Was sind eigentlich Softwarearchitekturen?

Eine Softwarearchitektur beschreibt den Aufbau eines Softwaresystems - in der Literatur finden sich einige Konzepte wie ein solcher Aufbau aussehen soll.

Ein sehr bekanntes und mittlerweile auch immer mehr verbreitetes Konzept ist das Domain-Driven-Design von Eric Evans.

Hier wird die Architektur in drei Schichten und zwei Modulen aufgeteilt.

Zum einen existiert die Fachdomänenschicht, in der sich die Hauptlogik des Softwaresystems befinden soll. Dort befinden sich dann Konstrukte wie Entities, Value Objects, Aggregate, Factories, Services und Repositories.

Darüber befindet sich die Applikationsschicht, die den Zugriff auf die Fachdomänenschicht kapselt.

Als oberstes existiert die Präsentationsschicht. Hier befindet sich die Logik zum Anzeigen von Informationen.

Zu den drei Schichten gehört noch das fachliche Modul, das über alle drei Schichten hinweg geht. Dieses wird häufig auch als Bounded-Context bezeichnet, wenn eine Anwendung mehrere fachliche Module enthält. Ein zweites Modul, das Infrastrukturmodel, ist für die Datenbanken oder Anbindungen an REST-APIs vorgesehen.

Ein etwas konkretere Architektur stellt die Clean-Architecture von Robert C. Martin und das Model-View-ViewModel von John Gossman bzw. Josh Smith dar.

Die Clean Architecture ist in einer Kreisstruktur angelegt, in der die Abhängigkeiten der einzelnen Schichten nach innen gerichtet sind. Im inneren befinden sich die Entitäten, weiter außen die Anwendungsfälle und Details wie das User-Interface oder die Datenbank.

Das Model-View-ViewModel enthält die drei Komponenten View, View Model und Model. Die View ist die Benutzeroberfläche, das View Model der Controller zwischen View und Model. Das Model enthält die gesamte Geschäftslogik.


Entwickelter Lösungsansatz eines Code-Generators mit einer DSL

In einem entwickelten Lösungsansatz wurde der Ansatz der modellgetriebenen Architektur in Verbindung mit einer DSL angewendet, um eine Architektur basierend auf dem Konzept Domain-Driven-Design, der Clean-Architecture sowie des Model-View-ViewModels mithilfe eines selbst entwickelten Code-Generators zu generieren. Als Zielplattform wurde Android ausgewählt.

Mit dem Code-Generator sollte es möglich sein, ein lauffähiges Android-Projekt, einen lauffähigen Quellcode für eine Netzwerkkommunikation, eine lokale Datenbank, eine komplexe UI-Struktur und das oben genannte Domain-Driven-Design in Verbindung mit der Clean-Architecture und dem Model-View-ViewModel zu generieren.

Entwurf einer eigenen DSL


Als Grundlage für die zu entwerfende DSL wurde die bereits von uns entwickelte Double Yielding Markup Language (DYML) verwendet. Wie in der Abbildung zu sehen ist, können hier über Symbole wie das „#“ Knoten und über das „@“ Attribute angegeben werden.

Diese Struktur kann beliebig transformiert werden, um eine gewünschte Zielsprache zu generieren.

#item

#greeting hello world
#house @color{green} {
    This is my house.
    @@color{blue} #door
}


Für die eigene DSL wurde der Node-Modus der DYML verwendet. In diesem Modus können wie oben beschrieben selbst definierte Knoten angegeben werden.

Beispielhaft wurde hier eine untere Navigationsleiste mit der eigenen DSL beschrieben. Hier können, wie in Android üblich, Fragmente angegeben werden, um die verschiedenen Ansichten zu beschreiben.

Innerhalb der Fragmente können zum Beispiel ein Model und ein ViewModel angegeben werden, um das Architekturmuster Model-View-ViewModel umzusetzen.

Aus dieser Beschreibung wird dann mithilfe des Code-Generators ausführbarer Java-Code für die Android-Anwendung erzeugt.

#!presentation {

  nameOfPackage "de.worldiety.presentation"
  nameOfLaunchActivity "Bottomnavbar"
  package @name="bottomnav {
    bottomNavbar @name="Bottomnavbar" {
      startDestination "StartFragment"
      fragment @name="StartFragment"{
        model @name="StartFragmentModel" {
          field{
            images "List<ProductImage>"
          }
        }
        viewModel @name=-"StartFragmentViewModel" {
          field {
            welcomeMessage "String"
          }
        }
      }
      fragment@name="ListFragment" {
        model @name="ListFragmentModel" {
          field {
            products "List<Product>"
          }
        }
        viewModel @name="ListFragmentViewModel" {
          field {
            addedSuccessMessage "String"
          }
        }
      }
      fragment @name=ShoppingCardFragment" {
        model @name="ShoppingCardFragmentModel" {
          field {
            products "List<Product>"
          }
        }




Die daraus resultierende Android Anwendung sieht dann so aus, dass zum Beispiel die Navigationsleiste drei Ansichten besitzt, die mit einem Text gekennzeichnet sind.

  • StartFragment
  • ListFragment
  • ShoppingCardFragment

Der Code-Generator wurde in der Programmiersprache Go geschrieben. Daher wurde der Aufbau des Code-Generators nach einem für Go-Projekte verbreiteten Standard aufgebaut. - zentral sind hier die Komponenten “cmd“, “internal“ und “pkg“.

Bei dem verwendeten Standard enthält das Modul “cmd“ eine Komponente mit den Namen der Anwendung, in diesem Fall “androidgenerator“. In diesem befindet sich der Einstiegspunkt des Programms in Form einer “main.go“-Datei. In dieser Datei ist eine “main“-Methode definiert, mit der das Programm gestartet wird.

Im “internal“ Modul hingegen befindet sich der private Anwendungs- und Bibliothekscode, welcher ausschließlich für dieses Projekt vorgesehen und nicht in anderen Bibliotheken oder Projekten portierbar sein soll.

Für den Code-Generator wurden in diesem die drei weiteren Komponenten “android“, “app“ und “dsl“ definiert, in der sich projektspezifische Funktionen befinden. Im „pkg“ Modul befinden sich Komponenten und ein Quellcode, der auch allgemein und projektübergreifend verwendet werden kann.

  1. Der Verarbeitungsablauf des Code-Generators läuft so ab, dass zuerst die dyml-Datei, in der die DSL angegeben wurde, eingelesen wird.

  2. Im zweiten Schritt wird die DSL in die vordefinierten DSL-Modelle transformiert.

  3. Nach dieser Transformation folgt Schritt drei, in dem die DSL-Modelle dazu verwendet werden, um diese in einen abstrakten Syntaxbaum zu überführen.

  4. In Schritt vier werden Renderfunktionen aufgerufen, in denen der abstrakte Syntaxbaum ausgelesen und die einzelnen Java Dateien gerendert werden.

  5. Nachdem alle erforderlichen Renderfunktionen durchgeführt worden sind, erfolgt im letzten Schritt fünf das Schreiben der Dateien und Ordner in einen zuvor angebenden Speicherort.

Die aus dem Code-Generator resultierende Softwarearchitektur besitzt eine Komponente “Presentation“, die für das User-Interface vorgesehen ist und enthält die in Android hierfür existierenden Konstrukte “Activity“ und “Fragment“ sowie anderen Android spezifischen Code.

Diese Komponente nutzt von den vorhandenen “Bounded Context“ Modulen die “Entities“, die “UseCases“ und die konkreten Implementierungen der Repositories der “UseCases“.

Wurden noch weitere Module innerhalb eines “Bounded Context“ und damit Schichten hinzugefügt, stehen diese der “Presentation“ ebenfalls zur Verfügung. Die “Presentation“-Komponente wurde so angelegt, dass sie als äußerste Schicht gemäß Clean-Architecture, agieren kann und alle anderen Komponenten und Module keine Abhängigkeiten zu der “Presentation“- Komponente besitzen. Der zentrale Punkt der Architektur stellt das “Bounded Context“ Modul dar. Dieser existiert sowohl einzeln als auch in dem “Infrastructure“ Modul.

Das “Bounded Context“ Modul kann je nach Anwendungsfall mehrfach vorkommen. Ein einzelnes Modul stellt einen “Bounded Context“ nach Domain-Driven-Design dar und enthält die einzelnen Module “Application“ und “Domain“.

Das “Domain“ Modul enthält die zwei unterschiedlichen Komponenten “Entities Modul“ und “Gradle Modul“. Das “Entities Modul“ beinhaltet Aggregate, Entitäten und Wertobjekte. Die hier definierten Objekte und Regeln können in allen anderen Komponenten, Modulen oder Schichten verwendet werden.

Das “Entities Modul“ eines “Bounded Context“ Modul hat keine Abhängigkeiten zu anderen Komponenten, Modulen oder Schichten. Somit ist es die innerste Schicht im Clean-Architecture Kontext. Um die Möglichkeit zu bieten, weitere Schichten, die auf dem “Entities Modul“ aufbauen, zu definieren, können beliebig viele zusätzliche “Gradle Modul“-Komponenten hinzugefügt werden.

Das “Application Modul“ enthält die zwei unterschiedlichen Komponenten “UseCases Modul“ und “Gradle Modul“. Das “UseCases Modul“ verwendet dabei die Entitäten sowie alle weiteren definierten “Gradle Modul“- Komponenten aus dem Domain Modul. Im “UseCases Modul“ werden die Anwendungsfälle, die zu dem “Bounded Context“ gehören, definiert. Ebenfalls können im “Application Modul“ weitere “Gradle Modul“-Komponenten für neue Schichten definiert werden. Dies können z. B. Factories oder Application-Services sein, die die konkreten Implementierungen aus dem “Infrastructure“ Modul verwenden und die erzeugten Objekte an die “Presentation“- Komponente weiterleiten.

Schlussfolgerung und Aussichten

Mit der entwickelten DSL, der generierten Architektur sowie dem entworfenen Code-Generator kann eine komplett kompilierbare und ausführbare Android-Anwendung generiert werden.

Die entwickelte domänenspezifische Sprache sorgt dafür, dass initial ein Projekt abstrakt beschrieben werden und anschließend direkt in Code mithilfe des entworfenen Code-Generators übersetzt werden kann. Abschließend sei noch gesagt, dass das Thema der Code-Generierung wohl auch in Zukunft ein relevantes Thema bleiben wird.

Wie in diesem Ansatz gezeigt wurde, könnte die hier vorgeschlagene Code-Generierung im Bereich der Softwarearchitektur bei Android-Anwendungen Verwendung finden. Allerdings existieren immer wieder gewisse Einschränkungen und Hürden, die erst überwunden werden müssen, bevor die Code-Generierung außerhalb der wissenschaftlichen Domäne zum Einsatz kommen kann.

Unser Experte

ist für Sie da!

Haben Sie Fragen?

Weitere Blogartikel

01. Mai. 2022

Benutzerdokumentation automatisiert generieren

Blog

Die agile Softwareentwicklung hat sich in den letzten Jahren zu einem wichtigen Ansatz der technischen Umsetzbarkeit entfaltet. Neben den Vorteilen, wie z. B. Flexibilität, Fehlererkennung und erhöhte Performanz durch eine stetige Kommunikation, bringt eine agile Softwareentwicklung jedoch auch Einschränkungen mit sich. So wird die Dokumentation - zu welcher auch die Benutzerdokumentation zählt - eher relativiert betrachtet und zugunsten der engen Zusammenarbeit zwischen Entwickler:innen, Tester:innen, Kund:innen und Nutzer:innen auf ein Minimum beschränkt. Bedingt durch Covid-19 musste der persönliche Kontakt mit Kunden, welcher in einer agilen Entwicklungsumgebung einen hohen Stellenwert besitzt, auf ein Minimum reduziert werden. Dabei gewann Software allgemein in den letzten Jahren immer mehr an Komplexität, welches auch eine zunehmende Rolle in der Organisation von Informationen innerhalb der Benutzerdokumentation zur Folge hat. mehr

28. Apr. 2022

Empathy Maps als UX-Tool

Headerbild Empathy Maps
Blog

In Entwicklungs-, Design- oder Marketing-Teams bestehen oftmals unterschiedliche Vorstellungen von Zielgruppen, bzw. dem Endnutzer einer Applikation. Dies kann dann problematisch werden, wenn bspw. neue Features geplant oder versucht wird, den Endnutzer in Texten sowie Bildern direkt anzusprechen. Vor allem aber führt dies oftmals zu langwierigen Prozessen sowie Entscheidungen über die Nutzer und deren Bedürfnisse. Um dieser Herausforderung entgegenzuwirken, lassen sich unterschiedliche Ansätze sowie Methoden nutzen. Eine besonders effiziente und in der Umsetzung einfache Methode ist die „Empathy Map“. Empathy Maps sind ein agiles Tool im Bereich des User Experience Designs, das dabei hilft, die Nutzer sowie deren Bedürfnisse besser zu verstehen und ein einheitliches Mindset im Projekt-Team zu etablieren. Die Nielsen Norman Group, eine Erfolgreiche UX Beratungsfirma aus Amerika, welche von den User Experience Pionieren, Don Norman und Jakob Nielsen gegründet wurde, definiert Empathy Maps wie folgt: mehr

15. Apr. 2022

Flexibel einsetzbare Markupsprache

Blog

Die Idee, dass Daten wertvoll sind und das strukturierte Speichern dieser sinnvoll ist, wurde schon in den 60er Jahren im Konzept des Generic Coding erkannt. Diese Versuche, eine vereinheitlichte Sprache zur Beschreibung von Daten zu entwickeln, mündeten 1986 in die Entstehung der Standard Generalized Markup Language (SGML), welche sich durch die Verwendung von sogenannten Tags auszeichnet. Die Ähnlichkeit zu modernen Markup-Sprachen wie HTML oder XML ist kein Zufall, da diese SGML-konform entstanden sind, sich aber mittlerweile davon gelöst haben, um ihre Struktur weniger eingeschränkt anpassen zu können. mehr

17. Mär. 2022

Wohin mit all den Daten?

Blog

Kennen Sie es auch? Sie wollen in Ihrem Unternehmen auf bestimmte Daten zugreifen, können diese aber auf die Schnelle nicht finden – einige liegen auf den Rechnern der Mitarbeitenden, andere auf Datenbanken oder in der Cloud und wieder andere innerhalb von Softwaresystemen. Sie fragen sich, ob es nicht eine Möglichkeit gibt, all’ diese Daten ohne einen großen Aufwand zu sammeln und von einem Ort aus nutzen zu können? Die Antwort ist: Ja! Die Digitalisierung von Unternehmen ist in vollem Gange: Prozesse werden optimiert und automatisiert, Kommunikation wird dynamischer und die generelle Effizienz von Unternehmen steigert sich. Die mit der digitalen Transformation einhergehenden, gewaltigen Datenmengen – Stichwort Big Data – können genutzt werden, um Datenanalysen durchzuführen, die hochwertige Erkenntnisse für das eigene Unternehmen generieren können. Aber wo soll man nun beginnen? Daten innerhalb des eigenen Unternehmens sind oftmals weitläufig verteilt, nicht zwangsläufig strukturiert und haben unterschiedliche Dateiformate. Die Nutzung einer geeigneten Infrastruktur, die die Daten automatisiert extrahiert und speichert, stellt die Basis für eine organisierte Datenhaltung dar, die anschließende Auswertungen und Analysen ermöglicht. mehr