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.

JCON 2022 [1]

Der grüne Punkt – Mythos Wiederverwendung

Als mir im Studium die Vorzüge der OOP mit Java schmackhaft gemacht wurden, war ein sehr beliebtes Argument die Wiederverwendung. Das 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 am eigene Leib erfahren. Woran liegt es also, das die Idee der Wiederverwendung in realen Projekten so schwer umzusetzen ist? Machen wir also einen gemeinsamen Streifzug durch die Welt der Informatik und betracten verschiedene Vorhaben aus einer sicheren Distanz.

Chemnitzer Linux Tage 2022

Eine Einführung in P2P Netzwerke

Wer seine Anwendung nicht als zentralisierte Client / Server Architektur, sondern in einem dezentralisierten P2P Netzwerk betreiben möchte hat einige Herausforderungen zu bewältigen. Nach der Hochzeit von Napster und BitTorrent erleben neuen Medienplattformen wie Odysee und PeerTube mit P2P Technologie eine neue Renaissance. Ohne auf direkte Implementierungsdetails einzugehen bespreche ich in diesem Vortrag wichtige Grundlagen, die für den Einstig in die P2P Welt notwendig sind. Im besonderen Fokus stehen dabei die Vor und Nachteile der verschieden Algorithmen wie sich die einzelnen Peer finden und welche Probleme dabei auftreten können.


Grazer Linux Tage 2022

Heimnetz ohne Werbung mit AdGuard auf dem RaspberryPI

Leider ist von Minute 1:00 bis 2:10 kein Tonmitschnitt vorhanden 🙁 – einfach überspringen

Es gibt viele Projekte die sich für einen Raspberry PI eignen. Aus eigener Anwendung zeige ich wie man im Heimnetzwerk das Tool AdGuard in einem Docker Container zum laufen bringt, um damit die Werbung für alle im Netwerk verbundenen Geräte abstellt.

In diesem kleinen Workshop geht es darum auf einem Raspberry PI 4 mit einem Ubuntu Server Docker zum Laufen zu bekommen. Das ist aber der einfachste Schritt, denn dann geht es ans Eingemachte und wir fühlen den Netzwerkmöglichkeiten von Docker ein wenig auf den Zahn. Ein bischen SSH und Shell, ganiert mit Routerkonfiguration und vielen kleine praktischen Tipps runden den Talk ab.


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.

Referenzen

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.


Sichern & übertragen des Thunderbird-Profil auf einen neuen Computer

Als IT-Dienstleister müssen wir unsere Kunden oft dabei unterstützen, alte Windows-Systeme neu zu installieren. Die häufigste Herausforderung, der wir uns bei dieser Aktivität stellen müssen, besteht darin, alte Dateien zu sichern und sie auf dem neuen System wiederherzustellen. Nicht nur Privatpersonen, auch Unternehmen nutzen den E-Mail-Client Thunderbird. Deshalb haben wir uns entschlossen, diese kurze Anleitung zu veröffentlichen, wie Ihr Thunderbird-Profil gesichert und wiederhergestellt werden kann. Um einem Datenverlust vorzubeugen, sollten Sie regelmäßig Backups erstellen, falls Ihre Hardware oder Ihr Betriebssystem vollständig abgestürzt ist.

Sichern

  1. Einen USB-Stick oder -Festplatte (USB-Medium) an den Rechner anschließen.
  2. Erstellen Sie auf dem USB-Medium ein Verzeichnis Ihrer Wahl, zur Sicherung Ihres Profils. (z. B. 2022-01-19_Thunderbird-profil)
  3. Halten Sie das „Explorer Fenster“ offen und achten Sie darauf, dass das Verzeichnis „aktiv“ ist.
  4. Starten Sie nun Ihren Thunderbird E-Mail Client auf dem Rechner (Quelle) den Sie sichern möchten.
  5. Zum Auffinden Ihres alten Profils klicken Sie auf die „drei Balken“ oben rechts.
  6. In dem Fenster days such deann öffnent klicken Sie auf “Hilfe” (wie in dem Screenshot zu seen) 1️⃣ und dann 2️⃣ gehen Sie auf „weitere Hilfe zur Fehlerbehebung“.
  7. Im nächsten, sich öffnenden Fenster, wählen Sie das Feld „Ordner öffnen“ aus.
  8. Ein neues „Explorer Fenster“ öffnet sich und zeigt Ihnen alle Dateien Ihres Profils an.
  9. Markieren Sie alle Dateien, indem Sie die 1. Datei anklicken, dann die <Shift> Taste auf Ihrer Tastatur gedrückt halten und gleichzeitig die Taste <Pfeil nach unten> solange gedrückt halten bis der graue „Scroll-Balken“ im Fenster ganz unten angekommen ist. Sind alle Dateien ausgewählt (blau markiert), klicken Sie mit der „rechten Maustaste„ auf eine beliebige Datei und wählen den Menüpunkt „Kopieren“ aus
  10. Gehen Sie zurück zu dem „Explorer Fenster“ in dem Sie das USB Medium geöffnet haben und klicken die „rechte Maustaste“ und dann auf „Einfügen“.
  11. Ist der Kopiervorgang abgeschlossen, können Sie den Thunderbird E-Mail Client schließen.

Wiederherstellen

  1. Schließen Sie Ihr USB-Medium an den Ziel-Rechner an.
  2. Öffnen Sie den „Explorer“ und legen Sie folgende Verzeichnisse an: „Daten“ ➡️ „ Thunderbird“ ➡️ „Postamt xxx“ (C:\Data\Thunderbird\Postamt-Office xxx\ xxx müssen Sie mit dem Namen Ihres Thunderbird Profiles ersetzen)
  3. Kopieren Sie nun Ihre Profildaten von Ihrem USB-Medium in das neu erstellte Verzeichnis „C:\Data\Thunderbird\Postamt-Office xxx“.
  4. Nach Abschluss des Kopiervorgangs müssen Sie Ihr neues Profil Verzeichnis noch in der Thunderbird Installtion einrichten.
  5. Drücken Sie auf der Tastatur die Tasten <Windows Key>+<R>. Der Dialog „Ausführen” öffnet sich. Dort geben Sie im Screenshot „rot“ eingerahmten Befehl “thunderbird -p” ein und drücken die auf „OK“.
  6. Im neu geöffneten Fenster „Thunderbird – Benutzerprofil wählen“ klicken Sie auf den Eintrag „Profil erstellen“.
  7. Im 1. Fenster des „Profil-Assistent – Willkommen“ klicken Sie auf „Weiter“.
  8. Im 2. Fenster des „Profil-Assistent – Fertigstellen” tragen Sie unter “1“ den „Profilnamen“ (Postamt xxx) ein. Unter „2“ wählen Sie den Profilpfad durch klicken auf „Ordner wählen“ aus. (C:\Daten\Thunderbird\Postamt xxx).
  9. Zum Abschließen der Einrichtung Ihres Thunderbird Profils, müssen Sie nur noch auf „Fertigstellen“ drücken Sie können ab jetzt Thunderbird normal über die Startleiste starten – alle Ihre e-Mails & Einstellungen sind nun wiederhergestellt.

Wenn Sie Fragen oder Anregungen haben können Sie uns gerne eine E-Mail schreiben oder einen Kommentar hier hinterlassen. Wenn Sie diese kleine Anleitung hilfreich

Fingerfertigkeiten

In den meisten Fällen wird der Aspekt Eingabegeräte für viele bei der Einrichtung von Computerarbeitsplätzen wenige beachtet. Das stundenlange Lesen von Texten auf einem Monitor ermüdet schnell die Augen, so das dies weitaus mehr Beachtung findet, als die Verwendung geeigneter Eingabegeräte. Dabei ist es kein Geheimnis, das die falsche Computertastatur ebenfalls zu gesundheitlichen Problemen führen kann. So gibt es beispielsweise Auflagekissen für den Handballen, damit das Handgelenk nicht stark angewinkelt werden muss. Auch das lange Überspreizen der einzelnen Finger um beim Tippen die Sonderzeichen zu erreichen, kann auf Dauer zu sehr schmerzhaften Sehnenschneidentzündungen führen. Ein Umstand der vor allem für Programmierer mit dem falschen Tastaturlayout zum Tragen kommt. Wird dann die Ursache nicht abgestellt, kann die Entzündung sogar chronisch werden.

Sie sehen schon, es ist durchaus nicht verkehrt sich ein wenig Gedanken über die Wahl der eigenen Tastatur zu machen. Dabei gibt es neben den gesundheitlichen Aspekten auch ein paar praktische Überlegungen, die ich in diesem kleinen Überblick zusammen getragen habe.

Angestöpselt

Einer der ersten Gründe mich etwas intensiver mit dem Thema Tastaturen zu beschäftigen war die Konnektivität. Kabelgebunden oder doch besser Funk? Nun ja wem bereits einmal die Batterien während einer wichtigen Arbeit ausgegangen sind, wird entweder sehr stark darauf achten immer ausreichend Ersatz griffbereit zu haben oder entscheidet sich grundsätzlich für ein Keyboard mit Kabel. Ich persönlich habe mich für die erstere Variante entschieden. Als zusätzliches Sicherheitsnetz habe ich auch ein kabelgebundenes Ersatzgerät im Schrank deponiert. Es wäre für mich nicht das erste Mal, das ich nachdem ich Kaffee zwischen den einzelnen Tasten verteilt habe auf mein Backup zurückgreifen muss, bis ein geeigneter Austausch möglich ist.

In Zeiten von Tablets und Hybridgeräten wie beispielsweise das Surface von Microsoft ist es nicht verkehrt von Beginn an gleich auf ein Bluetooth Gerät zu setzen. Der Grund ist das oft nicht genügend USB Anschlüsse frei sind und das Hantieren mit Verteilern etwas umständlich ist. Bei der Verbindung über Bluetooth bleibt der USB Anschluss für andere Geräte frei. Leider ist es nicht möglich die gleiche Tastatur bei mehreren Geräten gleichzeitig zu registrieren. Die vom Hersteller angebotenen Covertastaturen konnten mich bisher nicht überzeugen, auch wenn diese durchaus ihren praktischen Nutzen haben.

Ein sehr wichtiger Punkt ist für mich auch das die Tasten möglichst beleuchtet sind. Da ich viel auf Reisen bin und nicht immer optimale Lichtverhältnisse habe, sind illuminierte Keybords für mich vornehmlich die erste Wahl. Das trifft natürlich in erster Linie auf Laptoptastaturen zu. Bisher habe ich noch keine kabellose Tastatur mit Beleuchtung ausfindig machen können. Der Grund liegt vermutlich im höheren Stromverbrauch, was die Batterien sehr schnell entleeren würde. Viele argumentieren an dieser Stelle, das man doch blind schrieben kann. Das ist schon richtig, wenn man es kann. Ich zähle leider nicht dazu, auch wenn ich es hin und wieder versucht habe zu erlernen.

Wer wiederum mit einer Dockingstation für den stationären Einsatz arbeitet erspart sich das regelmäßige umständliche Aufbauen des Arbeitsplatzes. Gerade beim Umgang mit Laptops habe ich mir angewöhnt mit einer externen Maus zu arbeiten und das Touchpad rigoros zu deaktivieren. Zu oft passiert es mir während des Schreibens, das bei aktiviertem Touchpad der Courser irgendwo an eine andere Stelle im Text springt und ich dann mühselig alles ausbessern darf. Glücklicherweise haben die meisten Laptops hierfür Funktionstasten, die schnell erreichbar sind, falls doch zurück gewechselt werden muss.

Gefühlsecht

Für so machen ist auch das haptische Gefühl beim Tastenanschlag wichtig. Aus diesem Grund probiere ich meine Tastatur vorher gern aus und bevorzuge den Kauf direkt im Laden. Es sei den ich bestelle ein Ersatz. Während das Sounddesign, wie es bei mechanischen Tastaturen der Fall ist und das richtige “klack” Geräusch für mich eher unwichtig ist. Lieber leiser als laut. Eine zu laute Geräuschkulisse ist auch weniger geeignet, wenn das Büro mit Kollegen geteilt wird. Gerade bei Kundentelefonaten können Tippgeräusche sehr störend wirken.

Ergonomische Tastaturen mit angewinkeltem Layout in V-Form sind auch eher nichts für mich. Vor langer Zeit hatte ich ein solch ein Keyboard von Microsoft, der Tastenanschlag war ein Traum und auch die Handgelenke sind nicht so schnell ermüdet. Auch wenn die Position der Hände durch die Form optimal ist, war der Bruch zwischen den Tasten nicht so leicht zu bewerkstelligen. Die fehlende Beleuchtung war dann das zusätzliche Knockout Kriterium. Genauso ein no go ist eine zu kurz geratene Entertaste. Solche Kleinigkeiten stören meinen Arbeitsfluss ungemein, das ich sehr auf solche Details achte.

Eine sehr spaßige Variante die ich unbedingt einmal Ausprobieren wollte war eine flexible vollständig in Silikon gehüllte und aufrollbare Tastatur. Grundsätzlich keine Schlechte Idee, vor allem in industriellen Einsatz. Zudem würde das meine hin und wieder auftretenden Unfälle mit der Kaffeetasse deutlich entschärfen. Auch wenn das gesamte Design sehr flach gehalten ist, kann ich diese spezielle Variante für den regelmäßigen Gebrauch weniger empfehlen. Der Tastenanschlag ist einfach nicht sensitiv genug und man muss sehr hart drücken, damit die Eingabe auch angenommen wird.

Zeichensalat

Kommen wir nun zum nächsten Punkt, dem Tastaturlayout. Hier haben wir die Wahl der Qual. Welcher Zeichensatz soll es sein? Deutsch oder Englisch? Wer ausschließlich programmiert, wird wegen der leichter erreichbaren Sonderzeichen wie Klammern und Semikolon durchaus seine Präferenz auf das US Layout legen.

Wer aber viel Text zu schreiben hat legt hingegen viel Wert auf die leichte Erreichbarkeit von beispielsweise deutschen Umlauten. Kommen täglich einige Seiten zusammen wird man und auch Frau sich erst einmal bewusst wie viele Umlaute in so einem Text zusammen kommen. Dazu auch eine kleine Anekdote die mir vor vielen Jahren einmal passiert ist.

Auf einer Reise nach Barcelona, zu einer Zeit als es noch keine Smartphones gab, führte mich mein Weg in ein Internet Café um nachzuschauen ob eine wichtige E-Mail eingetroffen ist. Dank Web Access ist das in aller Regel auch kein Problem. Meistens jedenfalls. Als ich auf der spanischen Tastatur nun ein Umlaut für das Passwort eingeben wollte, stand ich vor einem Problem. Die Lösung war in diesem Moment Google mit Copy and Paste.

Es gibt übrigens eine elegantere Methode deutsche Sonderzeichen auf einer englischen Tastatur einzugeben. Als voraussetzungslos muss der Nummernblock eingeschaltet sein. Dann die <ALT> Taste gedrückt halten und den 4 stelligen Zahlencode eingeben. Nachdem Loslassen der <ALT> Taste erscheint dann das Sonderzeichen.

Ä : 0196  ä : 0228  Ö : 0214  ö : 0246  Ü : 0220  ü : 0252  ß : 0223

Auf Android haben die meisten Bildschirmtastaturen die Sonderzeichen hinter den entsprechenden Buchstaben verborgen. Dazu muss man lediglich länger auf den Buchstaben drücken bis eine Auswahl auf geht, die dann Umlaute zur Auswahl anbietet. Falls Sie ein Telefon haben, das diese Möglichkeit nicht unterstützt, gibt es die Möglichkeit beispielsweise das Microsoft SwiftKey Keybord zu installieren.

Eine sehr spannende Lösung, mit der sämtliche Probleme behandelt werden ist das Euro Key Layout von Steffen Brüntjen (https://eurkey.steffen.bruentjen.eu). Dieses Layout richtet sich an Übersetzer und Programmierer. Als Grundlage wurde das englische QUERZ System hergenommen und unter GNU Version 3 veröffentlicht. Laut FAQ gibt es wohl auch eine Unterstützung für Linux Betriebssysteme. Da ich bereits ein Keyboard in Verwendung hatte, das zwischen der <Backspace> und der <Enter> Taste auch eine Zwischentaste eingefügt hatte, kann ich sagen das ich kein geeigneter Kandidat für die Verwendung bin.

Resümee

Als das Thema von Sandra Parsik und Daniel Zenzes in Ihrem Podcast Ready For Review zur Sprache gekommen ist, war dies für mich Anlass auch einmal meine Erfahrungen zu rekapitulieren. Schnell wurde mir bewusst, das ich auch so einiges beitragen kann, was zu diesem Artikel hier geführt hat.

Eins bleibt zu guter Letzt noch aus. Die Gretchen-Frage, welche Tastatur ich selbst nutze. Aktuell ist dies das Wireless Ultra Slim Touche Keyboard von Rapoo. Der Grund für diese Wahl ist recht einfach. Zum einem ist der Stromverbrauch sehr gering und die beiden AA Batterien reichen bei starker Nutzung problemlos bis zu 4 Monate. Ein Andere Aspekt ist das haptische Gefühl beim Tippen und natürlich auch der unschlagbare Preis von knapp 30 €. Großes Manko ist die fehlende Beleuchtung, die ich mit einer sehr hochwertigen Schreibtisch LED wieder ausgeglichen habe. Dafür sind sämtliche Laptops mit beleuchten Tasten ausgestattet.

Als Maus Nutze ich noch die Logitech MX Anwhere 25. Die zeichnet sich insbesondere dadurch aus, das sie auch auf Glasoberflächen funktioniert. Auch die Konnektivität kann sich sehen lassen. Wireless und Bluetooth sind sowohl als auch vorhanden. Die Aufladung erfolgt per USB und ganz wichtig, während des Ladevorgangs kann die Maus auch benutzt werden und die Batterie hält je nach Nutzung zwischen 4-6 Wochen. Als Linux Nutzer kann ich auch bestätigen das die Maus unter Linux einen eigenen Treiber (https://pwr-solaar.github.io/Solaar/) hat und bestens funktioniert.

Das BugFix Bingo

Wenn Sie einen Weg finden möchten, negative Stimmung zwischen Testern und Entwicklern in etwas Positives zu verwandeln, haben wir hier eine tolle Lösung. Die Idee, die ich vorstellen möchte, ist zwar schon recht alt, aber auch heute noch in unserer schönen neuen DevOps-Welt ein Dauerbrenner.

Vor vielen Jahren stieß ich im Internet auf eine PDF-Datei namens „Bug Fix Bingo“. Ein nettes, lustiges Spiel für IT-Profis. Ursprünglich wurde dieses kleine, witzige Spiel von der Softwaretestfirma K. J. Ross & Associates entwickelt. Leider ist die Originalseite längst verschwunden, daher habe ich beschlossen, diese tolle Idee in diesem Blogbeitrag festzuhalten.

Ich kann dieses Spiel auch Leuten empfehlen, die sich nicht so intensiv mit Tests beschäftigen, aber an vielen IT-Meetings teilnehmen müssen. Drucken Sie einfach die Datei aus, bringen Sie ein paar Kopien zum nächsten Meeting mit und freuen Sie sich auf das Geschehen. Ich habe es mehrmals gespielt. Neben dem Spaß, den wir hatten, hat es etwas verändert. Schauen wir uns also das Konzept und die Regeln an.

Bug Fix Bingo basiert auf einem traditionellen Bingo, nur mit ein paar Anpassungen. Jeder kann ohne große Vorbereitung mitmachen, denn es ist ganz einfach. Anstelle von Zahlen werden beim Bingo Aussagen von Entwicklern in Defect-Review-Meetings verwendet, um Felder zu markieren.

Regeln:

  1. Bingo-Felder werden markiert, wenn ein Entwickler während der Fehlerbehebungssitzungen die passende Aussage macht.
  2. Tester müssen sofort „Bingo“ rufen, sobald sie eine Reihe von fünf Feldern horizontal, vertikal oder diagonal vervollständigt haben.
  3. Aussagen, die aufgrund eines Fehlers entstehen, der später als „verzögert“, „wie vorgesehen“ oder „nicht zu beheben“ eingestuft wird, sollten als nicht markiert klassifiziert werden.
  4. Fehler, die nicht in einem Vorfallsbericht gemeldet werden, können nicht verwendet werden.
  5. Aussagen sollten zur späteren Bestätigung zusätzlich zum Fehler im Fehlerverfolgungssystem erfasst werden.
  6. Jeder Tester, der alle 25 Aussagen markiert, erhält umgehend zwei Wochen Stressurlaub.
  7. Jeder Entwickler, der alle 25 Aussagen verwendet, sollte für mindestens sechs Monate zur Umschulung in die Testgruppe abgeordnet werden.
Auf meinem Rechner funktioniert es.”“Wo waren Sie, als das Programm explodierte?”“Warum willst du das auf diese Art machen?”“Sie können diese Version nicht auf Ihrem System verwenden.”“Auch wenn es nicht funktioniert, wie fühlt es sich an?”
“Haben Sie Ihr System auf Viren überprüft?”“Jemand muss meinen Code geändert haben.”“Es funktioniert, wurde aber nicht getestet.”“DAS kann nicht die Quelle dieses Moduls in Wochen sein!”“Ich kann nichts testen!”
“Es ist nur ein unglücklicher Zufall.”“Sie müssen die falsche Version haben.”“Ich habe dieses Modul seit Wochen nicht mehr berührt.”“Irgendetwas stimmt nicht mit Ihren Daten.”“Was hast du falsch eingegeben, dass es abgestürzt ist?”
“Es muss ein Hardwareproblem sein.”“Wie ist das möglich?”“Gestern hat es geklappt.”“Das ist noch nie zuvor passiert.”“Das ist komisch …”
“Dies soll in der nächsten Version behoben werden.”“Ja, wir wussten, dass das passieren würde.”“Vielleicht unterstützen wir diese Plattform einfach nicht.”“Es ist eine Funktion. Wir haben die Spezifikationen lediglich nicht aktualisiert.”“Sicherlich wird niemand das Programm auf diese Weise verwenden.”
Die BuxFix Bingo Spielkarte

Übrigens haben auch Entwickler ein solches Spiel. Sie erhalten jedes Mal Punkte, wenn ein QA-Mitarbeiter versucht, einen Defekt an einer Funktion zu melden, die wie angegeben funktioniert.

Die BuxFix Bingo Spielkarte

Erste Schritte in Docker mit PostgreSQL

Nach einigen Jahren hat das Virtualisierungstool Docker seine Bedeutung für die Softwarebranche unter Beweis gestellt. Wenn man von Virtualisierung hört, könnte man meinen, dass dies nur etwas für Administratoren ist und mich als Entwickler nicht so stark betrifft. Aber Moment mal. Da könntest du falsch liegen. Denn Grundkenntnisse über Docker können Entwicklern im Alltag helfen.

Schritt 1: Erstellen Sie den Container und initialisieren Sie die Datenbank

docker run -d --name pg-dbms --restart=no \
--ip 172.18.0.20 \
-e POSTGRES_PASSWORD=s3cr3t \
-e PGPASSWORD=s3cr3t \
postgres:11

Wenn Sie möchten, dass PostgreSQL nach einem Neustart immer aktiv ist, ändern Sie die Neustartrichtlinie von „nein“ auf „immer“. Nachdem Sie die Instanz „pg-dbms“ Ihres PostgreSQL 11 Docker-Images erstellt haben, überprüfen Sie, ob der Neustart erfolgreich war. Dies gelingt über den Befehl:

docker ps -a

Schritt 2: Kopieren Sie das initialisierte Datenbankverzeichnis in ein lokales Verzeichnis auf Ihrem Hostsystem

docker cp pg-dbms:/var/lib/postgresql/data /home/user/pg

Das größte Problem mit dem aktuellen Container ist, dass beim Löschen alle Daten verloren gehen. Wir müssen also eine Möglichkeit finden, diese Daten dauerhaft zu speichern. Am einfachsten kopieren Sie das Datenverzeichnis Ihres Containers in ein Verzeichnis auf Ihrem Hostsystem. Der Kopierbefehl benötigt die Parameter „Quelle“ und „Ziel“. Geben Sie als Quelle den Container an, aus dem die Dateien stammen sollen. In unserem Fall heißt der Container „pg-dbms“. Das Ziel ist ein PostgreSQL-Ordner im Home-Verzeichnis des Benutzers „ed“. Unter Windows funktioniert es genauso. Passen Sie einfach den Verzeichnispfad an und vermeiden Sie Leerzeichen. Sobald die Dateien im angegebenen Verzeichnis liegen, ist dieser Schritt abgeschlossen.

Schritt 3: Stoppen Sie den aktuellen Container

docker stop pg-dbms

Wenn Sie einen Container starten möchten, ersetzen Sie einfach „Stop“ durch „Start“. Der Container, den wir zum Abrufen der ursprünglichen Dateien für das PostgreSQL-DBMS erstellt haben, wird nicht mehr benötigt. Wir können ihn löschen. Dazu muss jedoch zunächst der laufende Container gestoppt werden.

Schritt 4: Starten Sie den aktuellen Container

docker start pg-dbms

Nachdem der Container gestoppt wurde, können wir ihn löschen.

Schritt 5: Container mit einem externen Volume neu erstellen

docker run -d --name pg-dbms \
--ip 172.18.0.20 \
-e POSTGRES_PASSWORD=s3cr3t \
-e PGPASSWORD=s3cr3t \
-v /home/user/pg:/var/lib/postgresql/data \
postgres:11

Jetzt können wir das Verzeichnis mit der exportierten ursprünglichen Datenbank mit einem neu erstellten PostgreSQL-Container verknüpfen. Das ist alles. Der große Vorteil dieser Vorgehensweise ist, dass sich nun jede in PostgreSQL erstellte Datenbank und deren Daten außerhalb des Docker-Containers auf unserem lokalen Rechner befinden. Dies ermöglicht eine wesentlich einfachere Sicherung und verhindert Informationsverluste bei Containeraktualisierungen.

Wenn Sie anstelle von PostgreSQL andere Images haben, aus denen Sie Dateien zur Wiederverwendung extrahieren müssen, können Sie dieses Tutorial ebenfalls verwenden. Passen Sie es einfach an das Image und die benötigten Pfade an. Die Vorgehensweise ist nahezu identisch. Wenn Sie mehr über Docker erfahren möchten, können Sie sich auch mein Video „Docker-Grundlagen in weniger als 10 Minuten“ ansehen. Wenn Ihnen dieses kurze Tutorial gefällt, teilen Sie es mit Ihren Freunden und Kollegen. Abonnieren Sie meinen Newsletter, um auf dem Laufenden zu bleiben.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.


API 4 Future

Viele Ideen sind auf dem Papier hervorragend. Oft fehlt aber das Wissen wie man brillante Konzepte in den eigenen Alltag einbauen kann. Dieser kleine Workshop soll die Lücke zwischen Theorie und Praxis schließen und zeigt mit welchen Maßnahmen man langfristig zu einer stabile API gelangt.

(c) 2021 Marco Schulz, Java PRO Ausgabe 1, S.31-34

Bei der Entwicklung kommerzieller Software ist vielen Beteiligten oft nicht klar, das die Anwendung für lange Zeit in Benutzung sein wird. Da sich unsere Welt stetig im Wandel befindet, ist es leicht abzusehen, dass im Laufe der Jahre große und kleine Änderungen der Anwendung ausstehen werden. Zu einer richtigen Herausforderung wird das Vorhaben, wenn die zu erweiternde Anwendung nicht für sich isoliert ist, sondern mit anderen Systemkomponenten kommuniziert. Denn das bedeutet für die Konsumenten der eigenen Anwendung in den meisten Fällen, das sie ebenfalls angepasst werden müssen. Ein einzelner Stein wird so schnell zu einer Lawine. Mit einem guten Lawinenschutz lässt sich die Situation dennoch beherrschen. Das gelingt aber nur, wenn man berücksichtigt, das die im nachfolgenden beschriebenen Maßnahmen ausschließlich für eine Prävention gedacht sind. Hat sich die Gewalt aber erst einmal entfesselt, kann ihr kaum noch etwas entgegengesetzt werden. Klären wir deshalb zu erst was eine API ausmacht.

Verhandlungssache

Ein Softwareprojekt besteht aus verschieden Komponenten, denen spezialisierte Aufgaben zuteil werden. Die wichtigsten sind Quelltext, Konfiguration und Persistenz. Wir befassen uns hauptsächlich mit dem Bereich Quelltext. Ich verrate keine Neuigkeiten, wenn ich sage dass stets gegen Interfaces implementiert werden soll. Diese Grundlage bekommt man bereits in der Einführung der Objektorientierten Programmierung vermittelt. Bei meiner täglichen Arbeit sehe ich aber sehr oft, das so manchem Entwickler die Bedeutung der Forderung gegen Interfaces zu Entwickeln, nicht immer ganz klar ist, obwohl bei der Verwendung der Java Standard API, dies die übliche Praxis ist. Das klassische Beispiel hierfür lautet:

List<String> collection = new ArrayList<>();

Diese kurze Zeile nutzt das Interface List, welches als eine ArrayList implementiert wurde. Hier sehen wir auch, das keine Anhängsel in Form eines I die Schnittstelle kennzeichnet. Auch die zugehörige Implementierung trägt kein Impl im Namen. Das ist auch gut so! Besonders bei der Implementierungsklasse könnten ja verschiedene Lösungen erwünscht sein. Dann ist es wichtig diese gut zu kennzeichnen und leicht durch den Namen unterscheidbar zu halten. ListImpl und ListImpl2 sind verständlicherweise nicht so toll wie ArrayList und LinkedList auseinander zu halten. Damit haben wir auch schon den ersten Punk einer stringenten und sprechenden Namenskonvention klären können.

Im nächsten Schritt beschäftigen uns die Programmteile, welche wir möglichst nicht für Konsumenten der Anwendung nach außen geben wollen, da es sich um Hilfsklassen handelt. Ein Teil der Lösung liegt in der Struktur, wie die Packages zu organisieren sind. Ein sehr praktikabler Weg ist:

  • my.package.path.business: enthält sämtliche Interfaces
  • my.package.path.application: enthält die Implementierungen der Interfaces
  • my.package.path.application.hepler: enthält interne Hilfsklassen

Bereits über diese simple Architektur signalisiert man anderen Programmierern, das es keine gute Idee ist Klassen aus dem Package helper zu benutzen. Ab Java 9 gibt es noch weitreichendere Restriktion, das Verwenden interner Hilfsklassen zu unterbinden. Die Modularisierung, welche mit dem Projekt Jingsaw [1] in Java 9 Einzug genommen hat, erlaubt es im Moduldescriptor module-info.java Packages nach außen hin zu verstecken.

Separatisten und ihre Flucht vor der Masse

Schaut man sich die meisten Spezifikationen etwas genauer an, so stellt man fest, das viele Schnittstellen in eigene Bibliotheken ausgelagert wurden. Technologisch betrachtet würde das auf das vorherige Beispiel bezogen bedeuten, dass das Package business welches die Interfaces enthält in eine eigene Bibliothek ausgelagert wird. Die Trennung von API und der zugehörigen Implementierung erlaubt es grundsätzlich Implementierungen leichter gegeneinander auszutauschen. Es gestattet außerdem einem Auftraggeber eine stärkeren Einfluss auf die Umsetzung seines Projektes bei seinem Vertragspartner auszuüben, indem der Hersteller die API durch den Auftraggeber vorgefertigt bekommt. So toll wie die Idee auch ist, damit es dann auch tatsächlich so klappt, wie es ursprünglich gedacht wurde, sind aber ein paar Regeln zu beachten.

Beispiel 1: JDBC. Wir wissen, das die Java Database Connectivity ein Standard ist, um an eine Applikation verschiedenste Datenbanksysteme anbinden zu können. Sehen wir von den Probleme bei der Nutzung von nativem SQL einmal ab, können JDBC Treiber von MySQL nicht ohne weiteres durch postgreSQL oder Oracle ersetzt werden. Schließlich weicht jeder Hersteller bei seiner Implementierung vom Standard mehr oder weniger ab und stellt auch exklusive Funktionalität des eigene Produktes über den Treiber mit zu Verfügung. Entscheidet man sich im eigenen Projekt massiv diese Zusatzfeatures nutzen zu wollen, ist es mit der leichten Austauschbarkeit vorüber.

Beispiel 2: XML. Hier hat man gleich die Wahl zwischen mehreren Standards. Es ist natürlich klar das die APIs von SAX, DOM und StAX nicht zueinander kompatibel sind. Will man beispielsweise wegen einer besseren Performance von DOM zum ereignisbasierten SAX wechseln, kann das unter Umständen umfangreiche Codeänderungen nach sich ziehen.

Beispiel 3: PDF. Zu guter letzt habe ich noch ein Szenario von einem Standard parat, der keinen Standard hat. Das Portable Document Format selbst ist zwar ein Standard wie Dokumentdateien aufgebaut werden, aber bei der Implementierung nutzbarer Programmbibliotheken für die eigene Anwendung, köchelt jeder Hersteller sein eigenes Süppchen.

Die drei kleinen Beispiele zeigen die üblichen Probleme auf die im täglichen Projektgeschäft zu meistern sind. Eine kleine Regel bewirkt schon großes: Nur Fremdbibliotheken nutzen, wenn es wirklich notwendig ist. Schließlich birgt jede verwendete Abhängigkeit auch ein potenzielles Sicherheitsrisiko. Es ist auch nicht notwendig eine Bibliothek von wenigen MB einzubinden um die drei Zeile einzusparen, die benötigt werden um einen String auf leer und null zu prüfen.

Musterknaben

Wenn man sich für eine externe Bibliothek entschieden hat, so ist es immer vorteilhaft sich anfänglich die Arbeit zu machen und die Funktionalität über eine eigene Klasse zu kapseln, welche man dann exzessiv nutzen kann. In meinem persönlichen Projekt TP-CORE auf GitHub [2] habe ich dies an mehreren Stellen getan. Der Logger kapselt die Funktionalität von SLF4J und Logback. Im Vergleich zu den PdfRenderer ist die Signatur der Methoden von den verwendeten Logging Bibliotheken unabhängig und kann somit leichter über eine zentrale Stelle ausgetauscht werden. Um externe Bibliotheken in der eigenen Applikation möglichst zu kapseln, stehen die Entwurfsmuster: Wrapper, Fassade und Proxy zur Verfügung.

Wrapper: auch Adaptor Muster genannt, gehört in die Gruppe der Strukturmuster. Der Wrapper koppelt eine Schnittstelle zu einer anderen, die nicht kompatibel sind.

Fassade: ist ebenfalls ein Strukturmuster und bündelt mehrere Schnittstellen zu einer vereinfachten Schnittstelle.

Proxy: auch Stellvertreter genannt, gehört ebenfalls in die Kategorie der Strukturmuster. Proxies sind eine Verallgemeinerung einer komplexen Schnittstelle. Es kann als Komplementär der Fassade verstanden werden, die mehrere Schnittstellen zu einer einzigen zusammenführt.

Sicher ist es wichtig in der Theorie diese unterschiedlichen Szenarien zu trennen, um sie korrekt beschreiben zu können. In der Praxis ist es aber unkritisch, wenn zur Kapselung externer Funktionalität Mischformen der hier vorgestellten Entwurfsmuster entstehen. Für alle diejenigen die sich intensiver mit Design Pattern auseinander Setzen möchten, dem sei das Buch „Entwurfsmuster von Kopf bis Fuß“ [3] ans Herz gelegt.

Klassentreffen

Ein weiterer Schritt auf dem Weg zu einer stabilen API ist eine ausführliche Dokumentation. Basierend auf den bisher besprochenen Schnittstellen, gibt es eine kleine Bibliothek mit der Methoden basierend der API Version annotiert werden können. Neben Informationen zum Status und der Version, können für Klassen über das Attribute consumers die primäre Implementierungen aufgeführt werden. Um API Gaurdian dem eigenen Projekt zuzufügen sind nur wenige Zeilen der POM hinzuzufügen und die Property ${version} gegen die aktuelle Version zu ersetzen.

  <dependency>
    <groupId>org.apiguardian</groupId>
    <artifactId>apiguardian-api</artifactId>
    <version>${version}</version>
  </dependency>

Die Auszeichnung der Methoden und Klassen ist ebenso leicht. Die Annotation @API hat die Attribute: statussince und consumers. Für Status sind die folgenden Werte möglich:

  • DEPRECATED: Veraltet, sollte nicht weiterverwendet werden.
  • EXPERIMENTAL: Kennzeichnet neue Funktionen, auf die der Hersteller gerne Feedback erhalten würde. Mit Vorsicht verwenden, da hier stets Änderungen erfolgen können.
  • INTERNAL: Nur zur internen Verwendung, kann ohne Vorwarnung entfallen.
  • STABLE: Rückwärts kompatibles Feature, das für die bestehende Major-Version unverändert bleibt.
  • MAINTAINED: Sichert die Rückwärtsstabilität auch für das künftige Major-Release zu.

Nachdem nun sämtliche Interfaces mit diesen nützlichen META Informationen angereichert wurden, stellt sich die Frage wo der Mehrwert zu finden ist. Dazu verweise ich schlicht auf Abbildung 1, welche den Arbeitsalltag demonstriert.

Abbildung 1: Suggestion in Netbeans mit @API Annotation in der JavaDoc

Für Service basierte RESTful APIs, gibt es ein anderes Werkzeug, welches auf den Namen Swagger [4] hört. Auch hier wird der Ansatz aus Annotationen eine API Dokumentation zu erstellen verfolgt. Swagger selbst scannt allerdings Java Webservice Annotationen, anstatt eigene einzuführen. Die Verwendung ist ebenfalls recht leicht umzusetzen. Es ist lediglich das swagger-maven-plugin einzubinden und in der Konfiguration die Packages anzugeben, in denen die Webservices residieren. Anschließend wird bei jedem Build eine Beschreibung in Form einer JSON Datei erstellt, aus der dann Swagger UI eine ausführbare Dokumentation generiert. Swagger UI selbst wiederum ist als Docker Image auf DockerHub [5] verfügbar.

<plugin>
   <groupId>io.swagger.core.v3</groupId>
   <artifactId>swagger-maven-plugin</artifactId>
   <version>${version}</version>
   <configuration>
      <outputFileName>swagger</outputFileName>
      <outputFormat>JSON</outputFormat>
      <resourcePackages>
          <package>org.europa.together.service</package>
      </resourcePackages>
      <outputPath>${project.build.directory}</outputPath>
   </configuration>
</plugin>
Abbildung 2: Swagger UI Dokumentation der TP-ACL RESTful API.

Versionierung ist für APIs ein wichtiger Punkt. Unter Verwendung des Semantic Versioning lässt sich bereits einiges von der Versionsnummer ablesen. Im Bezug auf eine API ist das Major Segment von Bedeutung. Diese erste Ziffer kennzeichnet API Änderungen, die inkompatibel zueinander sind. Eine solche Inkompatibilität ist das Entfernen von Klassen oder Methoden. Aber auch das Ändern bestehender Singnaturen oder der Rückgabewert einer Methode erfordern bei Konsumenten im Rahmen einer Umstellung Anpassungen. Es ist immer eine gute Entscheidung Arbeiten, die Inkompatibilitäten verursachen zu bündeln und eher selten zu veröffentlichen. Dies zeugt von Stabilität im Projekt.

Auch für WebAPIs ist eine Versionierung angeraten. Die geschieht am besten über die URL, in dem eine Versionsnummer eingebaut wird. Bisher habe ich gute Erfahrungen gesammelt, wenn lediglich bei Inkompatibilitäten die Version hochgezählt wird.

Beziehungsstress

Der große Vorteil eines RESTful Service mit „jedem“ gut auszukommen, ist zugleich der größte Fluch. Denn das bedeutet das hier viel Sorgfalt walten muss, da viele Klienten versorgt werden. Da die Schnittstelle eine Ansammlung von URIs darstellt, liegt unser Augenmerk bei den Implementierungsdetails. Dazu nutze ich ein Beispiel aus meinen ebenfalls auf GitHub verfügbaren Projekt TP-ACL.

RolesDO role = rolesDAO.find(roleName);
String json = rolesDAO.serializeAsJson(role);
if (role != null) {
    response = Response.status(Response.Status.OK)
            .type(MediaType.APPLICATION_JSON)
            .entity(json)
            .encoding("UTF-8")
            .build();
} else {
    response = Response.status(Response.Status.NOT_FOUND).build();
}

Der kurze Auszug aus dem try Block der fetchRole Methode die in der Klasse RoleService zu finden ist. Die GET Anfrage liefert für den Fall, das eine Rolle nicht gefunden wird den 404 Fehlercode zurück. Sie ahnen sicherlich schon worauf ich hinaus will.

Bei der Implementierung der einzelnen Aktionen GET, PUT, DELETE etc. einer Resource wie Rolle, genügt es nicht einfach nur den sogenannten HappyPath umzusetzen. Bereits während des Entwurfes sollte berücksichtigt werden, welche Stadien eine solche Aktion annehmen kann. Für die Implementierung eines Konsumenten (Client) ist es schon ein beachtlicher Unterschied ob eine Anfrage, die nicht mit 200 abgeschlossen werden kann gescheitert ist, weil die Ressource nicht existiert (404) oder weil der Zugriff verweigert wurde (403). Hier möchte ich an die vielsagende Windows Meldung mit dem unerwarteten Fehler anspielen.

Fazit

Wenn wir von eine API sprechen, dann bedeutet es, das es sich um eine Schnittstelle handelt, die von anderen Programmen genutzt werden kann. Der Wechsel eine Major Version indiziert Konsumenten der API, das Inkompatibilität zur vorherigen Version vorhanden ist. Weswegen möglicherweise Anpassungen erforderlich sind. Dabei ist es völlig irrelevant um welche Art API es sich handelt oder ob die Verwendung der Anwendung öffentlich beziehungsweise fetchRole Methode, die Unternehmensintern ist. Die daraus resultierenden Konsequenzen sind identisch. Aus diesem Grund sollte man sich mit den nach außen sichtbaren Bereichen seiner Anwendung gewissenhaft auseinandersetzen.

Arbeiten, welche zu einer API Inkompatibilität führen, sollten durch das Release Management gebündelt werden und möglichst nicht mehr als einmal pro Jahr veröffentlicht werden. Auch an dieser Stelle zeigt sich wie wichtig regelmäßige Codeinspektionen für eine stringente Qualität sind.

Resourcen

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.