Schlagwort-Archive: Programmierung
Konfigurationsdateien in Softwareanwendungen
Wieso benötigen wir überhaupt die Möglichkeit, Konfigurationen einer Anwendung in Textdateien zu speichern? Genügt nicht einfach eine Datenbank für diesen Zweck? Die Antwort auf diese Frage ist recht trivial. Denn die Information, wie sich eine Anwendung mit einer Datenbank verbinden kann, lässt sich ja schlecht in der Datenbank selbst speichern.
Jetzt könnte man sicher argumentieren, dass man solche Dinge mit einer integrierten Datenbank (embedded) wie beispielsweise SQLite hinbekommt. Das mag auch grundsätzlich korrekt sein. Leider ist diese Lösung für hoch skalierbare Anwendungen nicht wirklich praktikabel. Zudem muss man nicht immer gleich mit Kanonen auf Spatzen schießen. Das Speichern wichtiger Konfigurationsparameter in Textdateien hat bereits eine lange Tradition in der Softwareentwicklung. Mittlerweile haben sich aber auch verschiedene Textformate wie INI, XML, JSON und YAML für diesen Anwendungsfall etabliert. Angesichts dessen stellt sich die Frage, auf welches Format man am besten für das eigene Projekt zurückgreifen sollte.
INI Dateien
Eines der ältesten Formate sind die bekannten INI Dateien. Sie speichern Informationen nach dem Schlüssel = Wert Prinzip. Wenn ein Schlüssel in solch einer INI-Datei mehrfach vorkommt, wird der finale Wert immer durch den zuletzt in der Datei vorkommenden Wert überschrieben.
; Example of an INI File
[Section-name]
key=value ; inline
text="text configuration with spaces and \' quotas"
string='can be also like this'
char=passwort
# numbers & digets
number=123
hexa=0x123
octa=0123
binary=0b1111
float=123.12
# boolean values
value-1=true
value-0=false
Wie wir in dem kleinen Beispiel sehen können, ist die Syntax in INI-Dateien sehr einfach gehalten. Der Sektionsname [section]
dient vor allem der Gruppierung einzelner Parameter und verbessert die Lesbarkeit. Kommentare können entweder durch ;
oder #
gekennzeichnet werden. Ansonsten gibt es die Möglichkeit, verschiedene Text- und Zahlen-Formate, sowie Boolean-Wert zu definieren.
Web-Entwickler kennen INI Files vor allem von der PHP-Konfiguration, der php.ini in der wichtige Eigenschaften wie die Größe des Datei-Uploads festgelegt werden können. Auch unter Windows sind INI-Dateien noch immer verbreitet, obwohl seit Windows 95 für diesen Zweck die Registry eingeführt wurde.
Properties
Eine andere sehr bewährte Lösung sind sogenannte property Files. Besonders verbreitet ist diese Lösung in Java-Programmen, da Java bereits eine einfache Klasse mitbringt, die mit Properties umgehen kann. Das Format key=value ist den INI-Dateien entlehnt. Kommentare werden ebenfalls mit # eingeleitet.
# PostgreSQL
hibernate.dialect.database = org.hibernate.dialect.PostgreSQLDialect
jdbc.driverClassName = org.postgresql.Driver
jdbc.url = jdbc:postgresql://127.0.0.1:5432/together-test
Um in Java-Programmen beim Einlesen der .propreties auch die Typsicherheit zu gewährleisten, hat die Bibliothek TP-CORE eine erweiterte Implementierung. Trotz dass die Properties als Strings eingelesen werden, kann auf die Werte mittels Typisierung zugegriffen werden. Eine ausführliche Beschreibung, wie die Klasse PropertyReader verwendet werden kann, findet sich in der Dokumentation.
Auch im Maven Build Prozess können .property Dateien als Filter für Substitutionen genutzt werden. Selbstredend sind Properties nicht nur auf Maven und Java beschränkt. Auch in Sprachen wie Dart, nodeJS, Python und Ruby ist dieses Konzept nutzbar. Um eine größtmögliche Kompatibilität der Dateien zwischen den verschiedenen Sprachen zu gewährleisten, sollten exotische Optionen zur Notation vermieden werden.
XML
XML ist seit vielen Jahren auch eine weitverbreitete Option, Konfigurationen in einer Anwendung veränderlich zu speichern. Gegenüber INI und Property Dateien bietet XML mehr Flexibilität in der Definition der Daten. Ein sehr wichtiger Aspekt ist die Möglichkeit, fixe Strukturen durch eine Grammatik zu definieren. Dies erlaubt eine Validierung auch für sehr komplexe Daten. Dank der beiden Prüfmechanismen Wohlgeformtheit und Datenvalidierung gegen eine Grammatik lassen sich mögliche Konfigurationsfehler erheblich reduzieren.
Bekannte Einsatzszenarien für XML finden sich beispielsweise in Java Enterprise Projekten (J EE) mit der web.xml oder der Spring Framework und Hibernate Konfiguration. Die Mächtigkeit von XML gestattet sogar die Nutzung als Domain Specific Language (DSL), wie es bei dem Build-Werkzeug Apache Maven zum Einsatz kommt.
Dank vieler frei verfügbarer Bibliotheken existiert für nahezu jede Programmiersprache eine Implementierung, um XML-Dateien einzulesen und gezielt auf Daten zuzugreifen. Die bei Web-Entwicklern beliebte Sprache PHP hat zum Beispiel mit der Simple XML Erweiterung eine sehr einfache und intuitive Lösung, um mit XML umzugehen.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/assembly/ApplicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>${jsf.project.stage}</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
JavaScript Object Notation oder kurz JSON ist eine vergleichsweise neue Technik, obwohl diese mittlerweile auch schon einige Jahre existiert. Auch JSON hat für nahezu jede Programmiersprache eine entsprechende Implementierung. Das häufigste Einsatzszenario für JSON ist der Datentausch in Microservices. Der Grund liegt in der Kompaktheit von JSON. Gegenüber XML ist der zu übertragene Datenstrom in Webservices wie XML RPC oder SOAP mit JSON aufgrund der Notation wesentlich geringer.
Ein signifikanter Unterschied zwischen JSON und XML besteht aber auch im Bereich der Validierung. Grundsätzlich findet sich auf der offiziellen Homepage [1] zu JSON keine Möglichkeit, eine Grammatik wie in XML mit DTD oder Schema zu definieren. Auf GitHub existiert zwar ein Proposal zu einer JSON-Grammatik [2] hierzu fehlen aber entsprechende Implementierungen, um diese Technologie auch in Projekten einsetzen zu können.
Eine Weiterentwicklung zu JSON ist JSON5 [3], das bereits 2012 begonnen wurde und als Spezifikation in der Version 1.0.0 [4] seit dem Jahr 2018 offiziell veröffentlicht ist. Zweck dieser Entwicklung war es, die Lesbarkeit von JSON für Menschen erheblich zu verbessern. Hier wurden wichtige Funktionen, wie beispielsweise die Möglichkeit, Kommentare zu schreiben, hinzugefügt. JSON5 ist als Erweiterung vollständig zu JSON kompatibel. Um einen kurzen Eindruck zu JSON5 zu gewinnen, hier ein kleines Beispiel:
{
// comments
unquoted: 'and you can quote me on that',
singleQuotes: 'I can use "double quotes" here',
lineBreaks: "Look, Mom! \
No \\n's!",
hexadecimal: 0xdecaf,
leadingDecimalPoint: .8675309, andTrailing: 8675309.,
positiveSign: +1,
trailingComma: 'in objects', andIn: ['arrays',],
"backwardsCompatible": "with JSON",
}
YAML
Viele moderne Anwendungen, wie zum Beispiel YAML, zur Konfiguration. Die sehr kompakte Notation erinnert stark an die Programmiersprache Python. Aktuell ist YAML in der Version 1.2 veröffentlicht.
Der Vorteil von YAML gegenüber anderen Spezifikationen ist die extreme Kompaktheit. Gleichzeitig besitzt die Version 1.2 eine Grammatik zu Validierung. Trotz der Kompaktheit liegt der Fokus von YAML 1.2 in einer guten Lesbarkeit für Maschinen als auch Menschen. Ob YAML dieses Ziel erreicht hat, überlasse ich jedem selbst zu entscheiden. Auf der offiziellen Homepage findet man alle Ressourcen, die für eine Verwendung im eigenen Projekt benötigt werden. Dazu zählt auch eine Übersicht zu den vorhandenen Implementierungen. Das Design der YAML Homepage gibt auch schon einen guten Vorgeschmack auf die Übersichtlichkeit von YAML Dateien. Anbei noch ein sehr kompaktes Beispiel einer Prometheus Konfiguration in YAML:
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
# - "first.rules"
# - "second.rules"
#IP: 127.0.0.1
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['127.0.0.1:8080']
# SPRING BOOT WEB APP
- job_name: spring-boot-sample
scrape_interval: 60s
scrape_timeout: 50s
scheme: "http"
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['127.0.0.1:8888']
tls_config:
insecure_skip_verify: true
Resümee
Alle hier vorgestellten Techniken sind im praktischen Einsatz in vielen Projekten erprobt. Sicher mag es für spezielle Anwendungen wie REST Services einige Präferenzen geben. Für meinen persönlichen Geschmack bevorzuge ich für Konfigurationsdateien das XML Format. Dies ist leicht im Programm zu verarbeiten, extrem flexibel und bei geschickter Modellierung auch kompakt und hervorragend für Menschen lesbar.
Referenzen
Abonnement / Subscription
Ruby: die Entwicklungsumgebung einrichten
Ruby ist seit vielen Jahren eine sehr etablierte Programmiersprache, die durchaus auch Anfängern empfohlen werden kann. Ruby folgt dem objektorientierten Paradigma und enthält sehr viele Konzepte, um OOP gut zu unterstützen. Außerdem lassen sich dank des Frameworks Ruby on Rails unkompliziert komplexe Webanwendungen entwickeln.
Die schwierigste Hürde beim Einstieg in Ruby, die es zu meistern gilt, ist die Installation der gesamten Entwicklungsumgebung. Angesichts dessen habe ich dieses kurze Tutorial zum Einstieg mit Ruby verfasst. Beginnen wir daher auch gleich mit der Installation.
Mein Betriebssystem ist ein Debian 12 Linux und Ruby lässt sich sehr einfach mit der Anweisung sudo apt-get install ruby-full
installieren. Dieses Vorgehen kann auf alle Debian basierte Linux Distributionen wie z. B. Ubuntu übertragen werden. Anschließend kann mit ruby -v
der Erfolg in der Bash überprüft werden.
ed@:~$ ruby -v
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux-gnu]
Wenn wir nun dem Tutorial auf der Ruby on Rails Homepage folgen und das Rails Framework über gem rails
installieren wollen, stoßen wir bereits auf das erste Problem. Wegen fehlender Berechtigungen lassen sich keine Bibliotheken für Ruby installieren. Nun konnten wir auf die Idee kommen, die Bibliotheken, als Superuser mit sudo
zu installieren. Dies Losung ist leider nur temporär und verhindert, dass später in der Entwicklungsumgebung die Bibliotheken korrekt gefunden werden. Besser ist es, einen Ordner für die GEMs im home Verzeichnis des Nutzers anzulegen und dies über eine Systemvariable bereitzustellen.
export GEM_HOME=/home/<user>/.ruby-gems
export PATH=$PATH:/home/<user>/.ruby-gems
Die oben stehende Zeile ist an das Ende der Datei .bashrc einzutragen, damit die Änderungen auch persistent bleiben. Wichtig ist, dass <user>
gegen den richtigen Nutzernamen ausgetauscht wird. Den Erfolg dieser Aktion lasst sich über gem environment
überprüfen und sollte eine ähnliche Ausgabe wie nachstehend ergeben.
ed@:~$ gem environment
RubyGems Environment:
- RUBYGEMS VERSION: 3.3.15
- RUBY VERSION: 3.1.2 (2022-04-12 patchlevel 20) [x86_64-linux-gnu]
- INSTALLATION DIRECTORY: /home/ed/.ruby-gems
- USER INSTALLATION DIRECTORY: /home/ed/.local/share/gem/ruby/3.1.0
- RUBY EXECUTABLE: /usr/bin/ruby3.1
- GIT EXECUTABLE: /usr/bin/git
- EXECUTABLE DIRECTORY: /home/ed/Programs/gem-repository/bin
- SPEC CACHE DIRECTORY: /home/ed/.local/share/gem/specs
- SYSTEM CONFIGURATION DIRECTORY: /etc
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-linux
- GEM PATHS:
- /home/ed/Programs/gem-repository
- /home/ed/.local/share/gem/ruby/3.1.0
- /var/lib/gems/3.1.0
- /usr/local/lib/ruby/gems/3.1.0
- /usr/lib/ruby/gems/3.1.0
- /usr/lib/x86_64-linux-gnu/ruby/gems/3.1.0
- /usr/share/rubygems-integration/3.1.0
- /usr/share/rubygems-integration/all
- /usr/lib/x86_64-linux-gnu/rubygems-integration/3.1.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => false
- :bulk_threshold => 1000
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- /home/ed/.local/bin
- /usr/local/bin
- /usr/bin
- /bin
- /usr/local/games
- /usr/games
- /snap/bin
- /home/ed/Programs/maven/bin
- /usr/share/openjfx/lib
- /home/ed/.local/bin
Mit dieser Einstellung lassen sich nun ohne Schwierigkeiten Ruby GEMs installieren. Das probieren wir auch gleich aus und installieren, das Ruby on Rails Framework, was uns bei der Entwickelung von Webapplikationen unterstützt: gem install rails
. Dies sollte indessen ohne Fehlermeldungen durchlaufen und mit dem Kommando rails -v
sehen wir, ob wir erfolgreich waren.
Im nächsten Schritt können wir nun ein neues Rails Projekt anlegen. Hier bediene ich mich dem Beispiel aus der Ruby on Rails Dokumentation und schreibe in die Bash: rails new blog
. Dies erzeugt ein entsprechendes Verzeichnis namens blog mit den Projektdateien. Nachdem wir in das Verzeichnis gewechselt sind müssen wir noch alle Abhängigkeiten installieren. Das geschieht über: bundle install
.
Hier stoßen wir nun auf ein weiteres Problem. Die Installation kann nicht beendet werden, weil es anscheinend ein Problem mit der Bibliothek psych
gibt. Das tatsächliche Problem ist allerdings, dass auf der Betriebssystemebene die Unterstützung für YAML-Dateien fehlt. Das lässt sich rasch beheben, indem das YAML-Paket nachinstalliert wird.
sudo apt-get install libyaml-dev
Das Problem mit psych
bei Ruby on Rails besteht schon eine Weile und ist mit der YAML Installation behoben, so, dass nun auch die Anweisung bundle install
erfolgreich durchläuft. Jetzt sind wir auch in der Lage, den Server für die Rails Anwendung zu starten: bin/rails server
.
ed@:~/blog$ bin/rails server
=> Booting Puma
=> Rails 7.1.3.3 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.2 (ruby 3.1.2-p20) ("The Eagle of Durango")
* Min threads: 5
* Max threads: 5
* Environment: development
* PID: 12316
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
Rufen wir nun im Webbrowser die URL http://127.0.0.1:3000 auf, sehen wir unsere Rails Webanwendung.

Mit diesen Schritten haben wir nun eine funktionierende Ruby Umgebung auf unserem System erstellt. Nun ist es an der Zeit, sich für eine geeignete Entwicklungsumgebung zu entscheiden. Wer nur gelegentlich ein paar Scripte anpasst, dem genügen VIM und Sublime Text als Editoren. Für komplexe Softwareprojekte sollte wiederum auf eine vollständige IDE zurückgegriffen werden, da dies die Arbeit erheblich vereinfacht. Die beste Empfehlung ist die kostenpflichtige IDE RubyMine von JetBrains. Wer Ruby Open Source Projekte als Entwickler unterstützt, kann eine kostenfreie Lizenz beantragen.
Eine frei verfügbare Ruby IDE ist VSCode von Microsoft. Hier müssen aber zunächst ein paar Plug-ins eingebunden werden, und für meinen Geschmack ist VSCode auch nicht sehr intuitiv. Ruby Integration für die klassischen Java IDEs Eclipse und NetBeans sind recht veraltet und nur mit sehr viel Mühe zum Laufen zu bekommen.
Damit haben wir auch schon alle wichtigen Punkte, die notwendig sind, eine funktionierende Ruby-Umgebung auf dem eigenen System einzurichten, besprochen. Ich hoffe, mit diesem kleinen Workshop die Einstiegshürde zum Erlernen von Ruby erheblich gesenkt zu haben. Wenn Ihr diesen Artikel mögt, freue ich mich über ein Like und die Weiterempfehlung an eure Freunde.
Entwickler Tage remote 2024
Test Driven: from zero to hero
In der Softwarebranche ist es üblich, dass die Codebasis eine ausreichende Testautomatisierung aufweist. Denn dies ist für einen stabilen DevOps-Prozess und sicheres Refactoring notwendig. Aber die Realität sieht oft ganz anders aus. Fast jedes Projekt, an dem ich während meiner Karriere teilgenommen habe, hatte keine Zeile Testcode. Wenn wir darüber nachdenken, dass seit über 40 Jahren immer noch 80% aller kommerziellen Softwareprojekte scheitern, sollte uns das nicht überraschen. Aber das muss nicht so sein. In diesem Vortrag zeige ich, wie einfach es ist, auch in großen Projekten einen testgetriebenen Ansatz einzuführen. Das technische Setup ist ein Standard-Java-Projekt mit Apache Maven und JUnit 5.
Modern Times
Die meisten DevOps-Teams sind überzeugt, dass die Automatisierung selbst und die Automatisierung selbst eine große Herausforderung darstellt. Es scheint dringend notwendig zu sein, alles zu automatisieren – sogar die Automatisierung selbst. Dies ist für die meisten DevOps-Teams ein allgemeines Verständnis und somit Motivation. Werfen wir einen Blick auf typische, kontinuierliche Dummheiten bei der Transformation vom reinen Konfigurationsmanagement zum DevOps-Engineer.

Die meisten DevOps-Teams sind davon überzeugt, dass die Automatisierung selbst und die Automatisierung selbst eine große Herausforderung darstellt. Es scheint dringend notwendig zu sein, alles zu automatisieren – sogar die Automatisierung selbst. Dies ist für die meisten DevOps-Teams ein allgemeines Verständnis und somit Motivation. Werfen wir einen Blick auf typische, kontinuierliche Dummheiten bei der Transformation vom reinen Konfigurationsmanagement zum DevOps-Engineer.
- Build-Logik kann eine fehlerhafte Architektur nicht reparieren. Zahlreiche SCM-Zusammenführungskonflikte entstehen durch die fehlende Kapselung der Geschäftslogik. Bei Funktionen, die über viele Module oder Dienste verteilt sind, ist die Wahrscheinlichkeit hoch, dass eine Datei von mehreren Entwicklern bearbeitet wird.
- Die Notwendigkeit orchestrierter Builds deutet auf Architekturprobleme hin. Transitive Abhängigkeiten, fehlende Kapselung und eine umfangreiche Abhängigkeitskette sind typische Gründe für das Henne-Ei-Problem. Entwerfen Sie Ihre Artefakte so unabhängig wie möglich.
- Build-Logik wird von Entwicklern und nicht von Administratoren entwickelt. Personen mit Fokus auf den Betrieb haben andere Konzepte zur Pflege von Artefakt-Builds als Softwareentwickler. Ein gutes Beispiel für eine Anti-Pattern-Build-Struktur sind webMethods der Software AG. webMethods bietet keinen Repository-Server wie Sonatype Nexus zum Teilen von Abhängigkeiten. Der Build verweist immer auf die Abhängigkeiten innerhalb einer webMethods-Installation. Diese Vorgehensweise verstößt gegen die Grundidee der Build-Automatisierung, die im Buch „Praktiken eines agilen Entwicklers“ von 2006 beschrieben wird.
- Nicht alles auf einmal. Teilen Sie die Build-Jobs in konkrete Ziele auf, wie z. B. Artefakt erstellen, Abnahmetests durchführen, API-Dokumentation erstellen und Berichte generieren. Wenn einer der letzten Schritte fehlschlägt, müssen Sie nicht alles wiederholen. Die Ausführungszeit des Builds wird drastisch reduziert, und die Build-Infrastruktur lässt sich leichter warten.
- Geben Sie Ihrer Build-Infrastruktur nicht zu viel Flexibilität. Dieser Punkt hängt eng mit dem ersten Thema zusammen, das ich erläutert habe. Ein undisziplinierter Build-Manager erstellt extrem komplexe Skripte, die niemand versteht. Der JavaScript-Task-Runner Grunt ist ein Beispiel dafür, wie eine Build-Logik unübersichtlich und unleserlich werden kann. Dies ist einer der Gründe, warum ich mich für Maven als Build-Tool für Java-Projekte entscheide, da es die Steuerung verständlicher Builds ermöglicht.
- Es besteht keine Notwendigkeit, die Automatisierung zu automatisieren. Komplexe Automatisierungsstufen verursachen per Definition höhere Kosten als einfache Aufgaben. Überlegen Sie sich immer vorher, welchen Nutzen Ihre Automatisierungsaktivitäten bringen, um zu prüfen, ob es sich lohnt, Zeit und Geld dafür aufzuwenden.
- Wir tun, was wir können, aber können wir auch, was wir tun? Oder mit den Worten von Gardy Bloch: „A fool with a tool is still a fool.“ Verstehen Sie die Anforderungen Ihres Projekts und entscheiden Sie auf dieser Grundlage, welches Tool Sie wählen. Wenn Ihnen die Ressourcen fehlen, kann Sie selbst die professionellste Lösung nicht unterstützen. Wenn Sie Ihr Problem verstanden haben, können Sie neue, professionelle und fortgeschrittene Prozesse erlernen.
- Die Build-Logik wurde zunächst in der lokalen Entwicklungsumgebung ausgeführt. Wenn Ihr Build nicht auf Ihrem lokalen Entwicklungsrechner läuft, nennen Sie es nicht Build-Logik. Es ist nur ein Hack. Die Build-Logik muss plattform- und IDE-unabhängig sein.
- Vermischen Sie Quellcode-Repositories nicht. mit anderen Dateien Die Organisation der Quellen in mehreren Ordnern innerhalb eines riesigen Verzeichnisses führt zu einem komplexen Build ohne jegliche Flexibilität. Quellen sollten nach Technologie oder separaten, unabhängigen Modulen strukturiert sein.
Viele der genannten Punkte lassen sich anhand der aktuellen Situation in fast jedem Projekt nachvollziehen. Die Lösung für eine erfolgreiche Problembehebung ist meist nicht allzu kompliziert. Sie erfordert lediglich ein wenig Aufmerksamkeit und gute Planung. Mein wichtigster Ratschlag ist das KISS-Prinzip (Keep it simple, stupid). Das bedeutet, den Standardprozess so weit wie möglich unverändert zu übernehmen. Man muss das Rad nicht neu erfinden. Es gibt Gründe, warum ein Standard zum Standard wird. Hier ist ein kurzer Plan, dem Sie folgen können:
- Erstens: Verstehen Sie das Problem.
- Zweitens: Suchen Sie nach einer Standardlösung für den Prozess.
- Drittens: Entwickeln Sie einen Plan zur Integration der Lösung in die bestehende Prozesslandschaft. Dies bedeutet, Tools zu entfernen, die Standardprozesse nicht unterstützen.
Wenn Sie Ihren eigenen Weg Schritt für Schritt gehen, ohne zu weit zu springen, können Sie schnell positive Ergebnisse erzielen.
Übrigens: Wenn Sie Unterstützung für einen erfolgreichen DevOps-Prozess benötigen, kontaktieren Sie mich gerne. Ich biete praktische Beratung und Schulungen zum Aufbau eines leistungsstarken DevOps-Teams an.
Continuous Integration mit Jenkins

Buch bestellen | Code Listings
Moderne Softwareentwicklung besteht aus viel mehr als nur aus Code und Kaffee. Ohne passende Deployment-Strategien und eine saubere Release-Verwaltung laufen selbst kleine Projekte schnell aus dem Ruder und werden unbeherrschbar.
Dieses Praxisbuch zeigt Ihnen, wie Sie mit Jenkins, Git und Nexus eine CI-Pipeline aufbauen. Erfahren Sie direkt aus der Praxis, was für erfolgreiche Software-Projekte essenziell ist: Source Control Management, flächendeckende Softwaretests mit einer sinnvollen Qualitätskontrolle und ein gut organisiertes Deployment. Marco Schulz gibt Ihnen seine Erfahrung aus zahlreichen internationalen IT-Projekten weiter und hält eine Menge Tipps und Überlegungen zu gutem Software Engineering für Sie parat.
Marco Schulz, 2021, 400 Seiten, Rheinwerk Computing, ISBN 978-3-8362-7834-8
- The Big Picture DevOps, Continuous Deployment, Build Jobs, Pipelines … ist all das wirklich nötig, wenn es nur um ein paar Zeilen Java-Code geht? Marco Schulz zeigt Ihnen, welche Vorteile moderne Entwicklungsparadigmen bieten, wie Sie Open-Source-Werkzeuge zu einer effektiven Toolchain zusammenfügen und damit Ihre Software professionell und zeitgemäß verwalten.
- Professionelle Code-Verwaltung Programmieren wäre viel einfacher, wenn Sie sich um den bestehenden Code keine Gedanken machen müssten. Da die Integration neuer Funktionen aber eine Standardaufgabe in der Software-Entwicklung ist, dreht sich hier alles um Merging-Konflikte, die Vergabe von sinnvollen Release-Nummern und das Schreiben von Unit- und Integrationstests. So behalten Sie den Überblick und arbeiten effektiv und agil im Team.
- Toolchains für moderne Software-Projekte Jenkins ist das wichtigste Werkzeug, wenn es um komfortable CI-Pipelines und automatisierte Builds geht. In diesem Praxisbuch finden Sie aber noch viel mehr: Git, Maven, Nexus, SonarQube und viele andere Tools helfen Ihnen bei der Verwaltung Ihrer Codebasis.
Errata: Auch wenn die Erstellung des Buches mit viel Sorgfalt durchgeführt wurde, kommt es durchaus vor, das sich Fehler einschleichen. Dank hilfreicher Hinweise von aufmerksamen Lesern finden Sie an dieser Stelle Korrekturen.
Seite 32: Literaturliste
[2.1] Gene Kim, The Unicorn Project, 2019, IT Revolution Press, ISBN: 978-1942788768
[2.2] Gene Kim, The Phoenix Project, 2013, IT Revolution Press, ISBN: 978-0-9882625-7-7
Rezensionen
Date vs. Boolean
Beim Entwurf von Datenmodellen und den dazugehörigen Tabellen nutzen wir manchmal Boolean als Datentyp. Im Allgemeinen sind diese Flags nicht wirklich problematisch. Aber vielleicht gibt es eine bessere Lösung für dieses Datendesign. Lassen Sie mich, Ihnen ein kurzes Beispiel für meine Anliegen geben.
Nehmen wir an, wir müssen eine einfache Domäne zum Speichern von Artikeln entwerfen. Wie ein Blog-System oder ein Content-Management-System. Neben dem Inhalt des Artikels und dem Namen des Autors könnten wir ein Flag benötigen, das dem System mitteilt, ob der Artikel für die Öffentlichkeit sichtbar ist. So etwas wie veröffentlicht als boolescher Wert. Aber es gibt auch weitere Anforderung, ein Datum, wann für den Artikel die Veröffentlichung geplant ist. In den meisten Datenbankentwürfen, die ich beobachtet habe, gibt es für diese Umstände einen Boolean: published
und ein Datum: publishingDate
. Meiner Meinung nach ist dieses Design ein wenig redundant und auch fehleranfällig. Als schnelle Schlussfolgerung möchte ich eher dazu raten, von Anfang an nur Date anstelle von Boolean zu verwenden.
Das Szenario, das ich oben beschrieben habe, kann auch auf viele andere Domänenlösungen übertragen werden. Nachdem wir eine Vorstellung davon bekommen haben, warum wir Boolean durch den Datentyp Date ersetzen sollten, werden wir uns nun den Details widmen, wie wir dieses Ziel erreichen können.
Der Umgang mit Standard-SQL lässt vermuten, dass der Austausch eines Datenbankmanagementsystems (DBMS) gegen ein anderes kein großes Problem darstellen sollte. Die Realität sieht leider ein wenig anders aus. Nicht alle verfügbaren Datentypen für Datum wie Timestamp sind wirklich empfehlenswert zu verwenden. Aus Erfahrung ziehe ich es vor, das einfache java.util.Date zu verwenden, um zukünftige Probleme und andere Überraschungen zu vermeiden. Das gespeicherte Format in der Datenbanktabelle sieht wie folgt aus: ‘JJJJ-MM-tt HH:mm:ss.0’. Zwischen dem Datum und der Uhrzeit steht ein einzelnes Leerzeichen und .0 bezeichnet einen Offset. Dieser Offset beschreibt die Zeitzone. Die mitteleuropäische Standardzeitzone CET hat einen Versatz von einer Stunde. Das bedeutet UTC+01:00 im internationalen Format. Um den Offset separat zu definieren, habe ich gute Ergebnisse mit java.util.TimeZone erzielt, das perfekt mit Date zusammenarbeitet.
Bevor wir fortfahren, zeige ich Ihnen einen kleinen Codeschnipsel in Java für den O/R Manager Hibernate und wie damit die zugehörigen Tabellenspalten erstellt werden können.
Abonnement / Subscription
[English] This content is only available to subscribers.
[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.
Abonnement / Subscription
[English] This content is only available to subscribers.
[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.
Schauen wir uns das obige Listing etwas genauer an. Als erstes sehen wir die @CreationTimestamp Annotation. Das bedeutet, dass beim Erstellen des ArticleDO-Objekts die Variable created mit der aktuellen Zeit initialisiert wird. Dieser Wert sollte sich nie ändern, da ein Artikel nur einmal erstellt, aber mehrmals geändert werden kann. Die Zeitzone wird in einem String gespeichert. Im Konstruktor kann man sehen, wie die System Timezone ausgelesen werden kann – aber Vorsicht, dieser Wert sollte nicht zu sehr vertraut werden. Wenn Sie einen Benutzer wie mich haben, der viel reist, werden Sie sehen, dass ich an allen Orten die gleiche Systemzeit habe, da ich diese normalerweise nie ändere. Als Standardzeitzone definiere ich den richtigen String für UTC-0. Das Gleiche mache ich für die Variable published. Datum kann auch durch einen String erstellt werden, den wir verwenden, um unseren Standard-Nullwert zu setzen. Der Setter für published hat die Möglichkeit, ein zukünftiges Datum zu definieren oder die aktuelle Zeit zu verwenden, falls der Artikel sofort veröffentlicht werden soll. Am Ende des Listings demonstriere ich einen einfachen SQL-Import für einen einzelnen Datensatz.
Aber man sollte nicht zu schnell vorgehen. Wir müssen auch ein wenig darauf achten, wie wir mit dem UTC-Offset umgehen. Denn ich habe in großen Systemen mehrfach Probleme beobachtet, die auftraten, weil Entwickler nur Standardwerte verwendet haben.
Die Zeitzone im Allgemeinen ist Teil des Internationalisierungskonzepts. Um die Zeitverschiebungen korrekt zu verwalten, können wir zwischen verschiedenen Strategien wählen. Wie in so vielen anderen Fällen gibt es kein eindeutiges Richtig oder Falsch. Alles hängt von den Umständen und Notwendigkeiten Ihrer Anwendung ab. Wenn eine Website nur national genutzt wird, wie für ein kleines Unternehmen, und keine zeitkritischen Ereignisse involviert sind, wird alles sehr einfach. In diesem Fall ist es unproblematisch, die Zeitzoneneinstellungen automatisch durch das DBMS zu verwalten. Aber bedenken Sie, dass es auf der Welt Länder wie Mexiko gibt, die mehr als nur eine Zeitzone haben. Bei einem internationalen System, bei dem die Clients über den ganzen Globus verteilt sind, könnte es sinnvoll sein, jedes einzelne DBMS im Cluster auf UTC-0 einzustellen und den Offset durch die Anwendung und die angeschlossenen Clients zu verwalten.
Ein weiteres Problem, das wir lösen müssen, ist die Frage, wie der Datumswert eines einzelnen Datensatzes standardmäßig initialisiert werden soll. Denn Nullwerte sollten vermieden werden. Eine ausführliche Erklärung, warum die Rückgabe von Nullwerten kein guter Programmierstil ist, findet sich in Büchern wie ‘Effective Java’ und ‘Clean Code’. Der Umgang mit Null Pointer Exceptions ist etwas, das ich nicht wirklich brauche. Ein bewährtes Verfahren, das sich für mich bewährt hat, ist die Vorgabe eines Datums- und Zeitwerts durch ‘0000-00-00 00:00:00.0’. Auf diese Weise vermeide ich unerwünschte Veröffentlichungen, und die Bedeutung ist sehr klar – für jeden.
Wie Sie sehen können, gibt es gute Gründe, warum boolesche Datentypen durch Datum ersetzt werden sollten. In diesem kleinen Artikel habe ich gezeigt, wie einfach man mit Datum und Zeitzone in Java und Hibernate umgehen kann. Es sollte auch keine große Sache sein, dieses Beispiel auf andere Programmiersprachen und Frameworks zu übertragen. Wenn Sie eine eigene Lösung haben, können Sie gerne einen Kommentar hinterlassen und diesen Artikel mit Ihren Kollegen und Freunden teilen.
IT-Tage 2022 remote
Refactoring – Eine kurze Geschichte des Scheiterns
Für mein kleines Open Source-Projekt TP-CORE, das Sie auf GitHub finden können, hatte ich die großartige Idee, die iText-Bibliothek für OpenPDF zu ersetzen. Nachdem ich einen Plan gemacht hatte, wie ich mein Ziel erreichen könnte, startete ich alle notwendigen Aktivitäten. Aber im wirklichen Leben sind die Dinge nie so einfach, wie wir es uns ursprünglich vorgestellt haben. In diesem Vortrag erfahren Sie was genau passiert ist. Ich spreche über meine Motivation, warum ich die Änderung wollte und wie mein Plan war, alle Aktivitäten zum Erfolg zu führen. Sie werden erfahren wie es war, als ich den Punkt erreichte bei dem mir klar wurde, dass ich so nicht zum Ziel gelange. Ich erkläre kurz, was ich getan habe, dass dieses kurze Abenteuer den Rest des Projekts nicht beeinflusst hat.
JCON 2022 [2]
Swallowed Exceptions in Java
Exception handling gehört zu den Grundkenntnissen eines Java Entwicklers. Die sichere Verwendung ist nicht so einfach, wie es auf den ersten Blick scheint. Erschwert wird alles noch dadurch, dass viele Bücher die Java Programmierung zum Thema haben, gern auch von der Verwendung von Ausnahmebehandlung wegen schwacher Performanz abraten. Dennoch lassen sich Exceptions im eigenen Code nicht vermeiden. Auch die testgetrieben Entwicklung benötigt Strategien Exceptions effizient zu verarbeiten, um so das Problem auf den Punkt zu bringen. Wie aber setzt man Excetions sinnvoll ein, um auch im Fehlerfall alle wichtigen Informationen beisammen zu haben? Diese Frage behandle ich ausführlich in meinem Vortrag.
Der grüne Punkt – Mythos Wiederverwendung
Als mir im Studium die Vorzüge der objektorientierten Programmierung mit Java schmackhaft gemacht wurden, war ein sehr beliebtes Argument die Wiederverwendung. Dass der Grundsatz „write once use everywhere“ in der Praxis dann doch nicht so leicht umzusetzen ist, wie es die Theorie suggeriert, haben die meisten Entwickler bereits am eigenen Leib erfahren. Woran liegt es also, dass die Idee der Wiederverwendung in realen Projekten so schwer umzusetzen ist? Machen wir also einen gemeinsamen Streifzug durch die Welt der Informatik und betrachten verschiedene Vorhaben aus sicherer Distanz.

(c) 2022 Elmar Dott, Java akuell Ausgabe 2, S.55 – 57
Wenn ich daran denke, wie viel Zeit ich während meines Studiums investiert habe, um eine Präsentationsvorlage für Referate zu erstellen. Voller Motivation habe ich alle erdenklichen Ansichten in weiser Voraussicht erstellt. Selbst rückblickend war das damalige Layout für einen Nichtgrafiker ganz gut gelungen. Trotzdem kam die tolle Vorlage nur wenige Male zum Einsatz und wenn ich im Nachhinein einmal Resümee ziehe, komme ich zu dem Schluss, dass die investierte Arbeitszeit in Bezug auf die tatsächliche Verwendung in keinem Verhältnis gestanden hat. Von den vielen verschiedenen Ansichten habe ich zum Schluss exakt zwei verwendet, das Deckblatt und eine allgemeine Inhaltsseite, mit der alle restlichen Darstellungen umgesetzt wurden. Die restlichen 15 waren halt da, falls man das künftig noch brauchen würde. Nach dieser Erfahrung plane ich keine eventuell zukünftig eintreffenden Anforderungen mehr im Voraus. Denn den wichtigsten Grundsatz in Sachen Wiederverwendung habe ich mit dieser Lektion für mich gelernt: Nichts ist so beständig wie die Änderung.
Diese kleine Anekdote trifft das Thema bereits im Kern. Denn viele Zeilen Code werden genau aus der gleichen Motivation heraus geschrieben. Der Kunde hat es noch nicht beauftragt, doch die Funktion wird er ganz sicher noch brauchen. Wenn wir in diesem Zusammenhang einmal den wirtschaftlichen Kontext ausblenden, gibt es immer noch ausreichend handfeste Gründe, durch die Fachabteilung noch nicht spezifizierte Funktionalität nicht eigenmächtig im Voraus zu implementieren. Für mich ist nicht verwendeter, auf Halde produzierter Code – sogenannter toter Code – in erster Linie ein Sicherheitsrisiko. Zusätzlich verursachen diese Fragmente auch Wartungskosten, da bei Änderungen auch diese Bereiche möglicherweise mit angepasst werden müssen. Schließlich muss die gesamte Codebasis kompilierfähig bleiben. Zu guter Letzt kommt noch hinzu, dass die Kollegen oft nicht wissen, dass bereits eine ähnliche Funktion entwickelt wurde, und diese somit ebenfalls nicht verwenden. Die Arbeit wird also auch noch doppelt ausgeführt. Nicht zu vergessen ist auch das von mir in großen und langjährig entwickelten Applikationen oft beobachtete Phänomen, dass ungenutzte Fragmente aus Angst, etwas Wichtiges zu löschen, über Jahre hinweg mitgeschleppt werden. Damit kommen wir auch schon zum zweiten Axiom der Wiederverwendung: Erstens kommt es anders und zweitens als man denkt.
Über die vielen Jahre, genauer gesagt Jahrzehnte, in denen ich nun verschiedenste IT- beziehungsweise Softwareprojekte begleitet habe, habe ich ein Füllhorn an Geschichten aus der Kategorie „Das hätte ich mir sparen können!“ angesammelt. Virtualisierung ist nicht erst seit Docker [1] auf der Bildfläche erschienen – es ist schon weitaus länger ein beliebtes Thema. Die Menge der von mir erstellten virtuellen Maschinen (VMs) kann ich kaum noch benennen – zumindest waren es sehr viele. Für alle erdenklichen Einsatzszenarien hatte ich etwas zusammengebaut. Auch bei diesen tollen Lösungen erging es mir letztlich nicht viel anders als bei meiner Office-Vorlage. Grundsätzlich gab es zwei Faktoren, die sich negativ ausgewirkt haben. Je mehr VMs erstellt wurden, desto mehr mussten dann auch gewertet werden. Ein Worst-Case-Szenario heutzutage wäre eine VM, die auf Windows 10 basiert, die dann jeweils als eine .NET- und eine Java-Entwicklungsumgebung oder Ähnliches spezialisiert wurde. Allein die Stunden, die man für Updates zubringt, wenn man die Systeme immer mal wieder hochfährt, summieren sich auf beachtliche Größen. Ein Grund für mich zudem, soweit es geht, einen großen Bogen um Windows 10 zu machen. Aus dieser Perspektive können selbsterstellte DockerContainer schnell vom Segen zum Fluch werden.
Dennoch darf man diese Dinge nicht gleich überbewerten, denn diese Aktivitäten können auch als Übung verbucht werden. Wichtig ist, dass solche „Spielereien“ nicht ausarten und man neben den technischen Erfahrungen auch den Blick für tatsächliche Bedürfnisse auf lange Sicht schärft.
Gerade bei Docker bin ich aus persönlicher Erfahrung dazu übergegangen, mir die für mich notwendigen Anpassungen zu notieren und zu archivieren. Komplizierte Skripte mit Docker-Compose spare ich mir in der Regel. Der Grund ist recht einfach: Die einzelnen Komponenten müssen zu oft aktualisiert werden und der Einsatz für jedes Skript findet in meinem Fall genau einmal statt. Bis man nun ein lauffähiges Skript zusammengestellt hat, benötigt man, je nach Erfahrung, mehrere oder weniger Anläufe. Also modifiziere ich das RUN-Kommando für einen Container, bis dieser das tut, was ich von ihm erwarte. Das vollständige Kommando hinterlege ich in einer Textdatei, um es bei Bedarf wiederverwenden zu können. Dieses Vorgehen nutze ich für jeden Dienst, den ich mit Docker virtualisiere. Dadurch habe ich die Möglichkeit, verschiedenste Konstellationen mit minimalen Änderungen nach dem „Klemmbaustein“-Prinzip zu rchestrieren. Wenn sich abzeichnet, dass ein Container sehr oft unter gleichen Bedienungen instanziiert wird, ist es sehr hilfreich, diese Konfiguration zu automatisieren. Nicht ohne Grund gilt für Docker-Container die Regel, möglichst nur einen Dienst pro Container zu virtualisieren.
Aus diesen beiden kleinen Geschichten lässt sich bereits einiges für Implementierungsarbeiten am Code ableiten. Ein klassischer Stolperstein, der mir bei der täglichen Projektarbeit regelmäßig unterkommt, ist, dass man mit der entwickelten Applikation eine eierlegende Wollmilchsau – oder, wie es in Österreich heißt: ein Wunderwutzi – kreieren möchte. Die Teams nehmen sich oft zu viel vor und das Projektmanagement versucht, den Product Owner auch nicht zu bekehren, lieber auf Qualität statt auf Quantität zu setzen. Was ich mit dieser Aussage deutlich machen möchte, lässt sich an einem kleinen Beispiel verständlich machen.
Gehen wir einmal davon aus, dass für eigene Projekte eine kleine Basisbibliothek benötigt wird, in der immer wiederkehrende Problemstellungen zusammengefasst werden – konkret: das Verarbeiten von JSON-Objekten [2]. Nun könnte man versuchen, alle erdenklichen Variationen im Umgang mit JSON abzudecken. Abgesehen davon, dass viel Code produziert wird, erzielt ein solches Vorgehen wenig Nutzen. Denn für so etwas gibt es bereits fertige Lösungen – etwa die freie Bibliothek Jackson [3]. Anstelle sämtlicher denkbarer JSON-Manipulationen ist in Projekten vornehmlich das Serialisieren und das Deserialisieren gefragt. Also eine Möglichkeit, wie man aus einem Java-Objekt einen JSON-String erzeugt, und umgekehrt. Diese beiden Methoden lassen sich leicht über eine Wrapper-Klasse zentralisieren. Erfüllt nun künftig die verwendete JSON-Bibliothek die benötigten Anforderungen nicht mehr, kann sie leichter durch eine besser geeignete Bibliothek ersetzt werden. Ganz nebenbei erhöhen wir mit diesem Vorgehen auch die Kompatibilität [4] unserer Bibliothek für künftige Erweiterungen. Wenn JSON im Projekt eine neu eingeführte Technologie ist, kann durch die Minimal-Implementierung stückweise Wissen aufgebaut werden. Je stärker der JSONWrapper nun in eigenen Projekten zum Einsatz kommt, desto wahrscheinlicher ist es, dass neue Anforderungen hinzukommen, die dann erst umgesetzt werden, wenn sie durch ein Projekt angefragt werden. Denn wer kann schon abschätzen, wie der tatsächliche Bedarf einer Funktionalität ist, wenn so gut wie keine Erfahrungen zu der eingesetzten Technologie vorhanden sind?
Das soeben beschriebene Szenario läuft auf einen einfachen Merksatz hinaus: Eine neue Implementierung möglichst so allgemein wie möglich halten, um sie nach Bedarf immer weiter zu spezialisieren.
Bei komplexen Fachanwendungen hilft uns das Domain-driven Design (DDD) Paradigma, Abgrenzungen zu Domänen ausfindig zu machen. Auch hierfür lässt sich ein leicht verständliches, allgemein gefasstes Beispiel finden. Betrachten wir dazu einmal die Domäne einer Access Control List (ACL). In der ACL wird ein Nutzerkonto benötigt, mit dem Berechtigungen zu verschiedenen Ressourcen verknüpft werden. Nun könnte man auf die Idee kommen, im Account in der ACL sämtliche Benutzerinformationen wie Homepage, Postadresse und Ähnliches abzulegen. Genau dieser Fall würde die Domäne der ACL verletzen, denn das Benutzerkonto benötigt lediglich Informationen, die zur Authentifizierung benötigt werden, um eine entsprechende Autorisierung zu ermöglichen.
Jede Anwendung hat für das Erfassen der benötigten Nutzerinformationen andere Anforderungen, weshalb diese Dinge nicht in eine ACL gehören sollten. Das würde die ACL zu sehr spezialisieren und stetige Änderungen verursachen. Daraus resultiert dann auch, dass die ACL nicht mehr universell einsatzfähig ist.
Man könnte nun auf die Idee kommen, eine sehr generische Lösung für den Speicher zusätzlicher Nutzerinformationen zu entwerfen
und ihn in der ACL zu verwenden. Von diesem Ansatz möchte ich abraten. Ein wichtiger Grund ist, dass diese Lösung die Komplexität der ACL unnötig erhöht. Ich gehe obendrein so weit und möchte behaupten, dass unter ungünstigen Umständen sogar Code-Dubletten entstehen. Die Begründung dafür ist wie folgt: Ich sehe eine generische Lösung zum Speichern von Zusatzinformationen im klassischen Content Management (CMS) verortet. Die Verknüpfung zwischen ACL und CMS erfolgt über die Benutzer-ID aus der ACL. Somit haben wir gleichzeitig auch zwischen den einzelnen Domänen eine lose Kopplung etabliert, die uns bei der Umsetzung einer modularisierten Architektur sehr behilflich sein wird.
Zum Thema Modularisierung möchte ich auch kurz einwerfen, dass Monolithen [5] durchaus auch aus mehreren Modulen bestehen können und sogar sollten. Es ist nicht zwangsläufig eine Microservice-Architektur notwendig. Module können aus unterschiedlichen Blickwinkeln betrachtet werden. Einerseits erlauben sie es einem Team, in einem fest abgegrenzten Bereich ungestört zu arbeiten, zum anderen kann ein Modul mit einer klar abgegrenzten Domäne ohne viele Adaptionen tatsächlich in späteren Projekten wiederverwendet werden.
Nun ergibt sich klarerweise die Fragestellung, was mit dem Übergang von der Generalisierung zur Spezialisierung gemeint ist. Auch hier hilft uns das Beispiel der ACL weiter. Ein erster Entwurf könnte die Anforderung haben, dass, um unerwünschte Berechtigungen falsch konfigurierter Rollen zu vermeiden, die Vererbung von Rechten bestehender Rollen nicht erwünscht ist. Daraus ergibt sich dann der Umstand, dass jedem Nutzer genau eine Rolle zugewiesen werden kann. Nun könnte es sein, dass durch neue Anforderungen der Fachabteilung eine Mandantenfähigkeit eingeführt werden soll. Entsprechend muss nun in der ACL eine Möglichkeit geschaffen werden, um bestehende Rollen und auch Nutzeraccounts einem Mandanten zuzuordnen. Eine Domänen-Erweiterung dieser hinzugekommenen Anforderung ist nun basierend auf der bereits bestehenden Domäne durch das Hinzufügen neuer Tabellenspalten leicht umzusetzen.
Die bisher aufgeführten Beispiele beziehen sich ausschließlich auf die Implementierung der Fachlogik. Viel komplizierter verhält sich das Thema Wiederverwendung beim Punkt der grafischen Benutzerschnittelle (GUI). Das Problem, das sich hier ergibt, ist die Kurzlebigkeit vieler chnologien. Java Swing existiert zwar noch, aber vermutlich würde sich niemand, der heute eine neue Anwendung entwickelt, noch für Java Swing entscheiden. Der Grund liegt in veraltetem Look-and-Feel der Grafikkomponenten. Um eine Applikation auch verkaufen zu können, darf man den Aspekt der Optik nicht außen vor lassen. Denn auch das Auge isst bekanntlich mit. Gerade bei sogenannten Green-Field-Projekten ist der Wunsch, eine moderne, ansprechende Oberfläche anbieten zu können, implizit. Deswegen vertrete ich die Ansicht, dass das Thema Wiederverwendung für GUI – mit wenigen Ausnahmen – keine wirkliche Rolle spielt.
Lessons Learned
Sehr oft habe ich in der Vergangenheit erlebt, wie enthusiastisch bei Kick-off-Meetings die Möglichkeit der Wiederverwendung von Komponenten in Aussicht gestellt wurde. Dass dies bei den verantwortlichen Managern zu einem Glitzern in den Augen geführt hat, ist auch nicht verwunderlich. Als es dann allerdings zu ersten konkreten Anfragen gekommen ist, eine Komponente in einem anderen Projekt einzusetzen, mussten sich alle Beteiligten eingestehen, dass dieses Vorhaben gescheitert war. In den nachfolgenden Retrospektiven sind die Punkte, die ich in diesem Artikel vorgestellt habe, regelmäßig als Ursachen identifiziert worden. Im Übrigen genügt oft schon ein Blick in das Datenbankmodell oder auf die Architektur einer Anwendung, um eine Aussage treffen zu können, wie realistisch eine Wiederverwendung tatsächlich ist. Bei steigendem Komplexitätsgrad sinkt die Wahrscheinlichkeit, auch nur kleinste Segmente erfolgreich für eine Wiederverwendung herauslösen zu können.