WireMock: Externe APIs effektiv simulieren und testen

Bevor Software live gesetzt werden kann, ist es sinnvoll sicherzustellen, dass sie wie erwartet funktioniert und sich keine Fehler eingeschlichen haben. Wenn man für die eigenen Services allerdings Daten mit externen Partnern oder Systemen über deren APIs austauscht, ist es nicht immer einfach, dies sinnvoll vorab zu überprüfen.  Wenn etwa ein Zahlungsdienst angebunden wird, dieser allerdings kein Testsystem zur Verfügung stellt, ist es schwierig, mit dem produktiven System zu testen, da dabei echte Transaktionen ausgelöst werden würden. Außerdem lassen sich Fehlerszenarien nicht immer gezielt simulieren.   Hier kommen Mockserver ins Spiel, mit denen sich das Verhalten eines fremden Servers simulieren lässt, ohne diesen tatsächlich aufzurufen. Die selbst entwickelte Software kann dann statt einem externen System den Mockserver anbinden und ermöglicht so das Verhalten der eigenen Anwendung ohne weitere externe Abhängigkeiten zu überprüfen. Für einfache, statische Antworten lässt sich ein Mockserver recht einfach konfigurieren. Dieser Ansatz lediglich vordefinierte Antworten zu speichern, stößt in der Praxis jedoch schnell an seine Grenzen. Etwa wenn eine dynamische Generierung von Antworten mit variablen Werten erforderlich ist. Außerdem kann eine hohe Anzahl statischer Antworten schnell unübersichtlich werden und zu einem hohen Pflegeaufwand führen.  Eine Alternative dafür ist die dynamische Generierung von Antworten. Dabei werden vordefinierte Felder in einer Antwort während der Laufzeit befüllt. Vorteile sind die Wiederverwendbarkeit der Beispielantworten und ein geringerer Wartungsaufwand.   Dieser zweiteilige Artikel zeigt, wie WireMock diese Anforderungen erfüllt. Im ersten Teil wird erläutert, wie WireMock Standalone für einfache Testszenarien eingerichtet werden kann. Im zweiten Teil wird gezeigt, wie WireMock für komplexere Anwendungsfälle mithilfe eigener Implementierungen und Containerisierung erweitert werden kann. Was ist ein Mockserver? Ein Mockserver ist ein Werkzeug in der Softwarequalitätssicherung, das das Verhalten einer echten API (HTTP/REST) nachahmt. Er empfängt Anfragen von einer Anwendung und liefert vordefinierte Antworten zurück, ohne dass eine Verbindung zum tatsächlichen Backend bestehen muss. Dies ermöglicht isolierte Integrationstests.  WireMock kurz und knapp  WireMock ist ein etablierter Open-Source-Mockserver im Softwaretest und bei Microservices. Er simuliert HTTP-Services, damit Anwendungen ohne Abhängigkeit von echten APIs getestet werden können.   WireMock verwendet Stubs in JSON-Dateien, um definierte Anfragen und Antworten zu organisieren. Diese Dateien beschreiben z. B. HTTP-Methode, URL-Pfad und erwartete Antwort. Zusätzlich kann WireMock weitere statische Dateien einbinden, auf die in den Stubs verwiesen wird. Beim Start lädt WireMock alle Mappings und verarbeitet Anfragen entsprechend der dort definierten Stubs.  Neben der Cloud-Variante bietet WireMock eine Standalone-Version, die als ausführbare JAR-Datei bereitgestellt wird. Diese JAR lässt sich je nach Bedarf betreiben. WireMock Setup Auf der offiziellen Website von WireMock steht das Standalone-JAR zum Download zur Verfügung.   Ausführung:  Als Voraussetzung muss eine Java-Laufzeitumgebung (Version 11 oder höher empfohlen) installiert sein.   Das JAR wird mit folgendem Befehl aufgerufen:  java -jar ./target/wiremock-standalone.jar  Alternativ kann das JAR auch über Docker ausgeführt werden.  Minimaler Testfall  WireMock verwendet zwei zentrale Ordner für die Konfiguration:  mappings/: enthält Stub-Definitionen in JSON (z. B. HTTP-Methode, URL, Antwortcode, Body).  __files/: speichert externe Dateien (z. B. Templates, Binärdateien), die in Stubs referenziert werden.  Die beiden oben genannten Ordner werden bei der Ausführung der WireMock-JAR automatisch im Verzeichnis der JAR erstellt, sofern sie nicht vorhanden sind.  Beispiel für einen Stub (get-users.json) in mappings/:  {   „request“: {     „method“: „GET“,     „url“: „/users“   },   „response“: {     „status“: 200,     „bodyFileName“: „users.json“,     „headers“: {       „Content-Type“: „application/json“     }   } }  Der bodyFileName-Wert (users.json) bezieht sich auf eine Datei im __files/-Ordner. Diese enthält z. B. statische Daten wie:  [   {     „name“: „Julia Schneider“,     „age“: 28,     „location“: „Brussels“,     „profilePicture“: „“   },   {     „name“: „Markus Weber“,     „age“: 41,     „location“: „Berlin“,     „profilePicture“: „“   } ] Statt dem Wert bodyFileName könnte man auch mittels body direkt in der Stub-Definition einen Body für den Response definieren.  Ergebnis:  Wird eine Anfrage an die konfigurierte URL gesendet, gibt WireMock die definierte Antwort zurück:  GET localhost:8080/users  [    {      „name“: „Julia Schneider“,      „age“: 28,      „location“: „Brussels“,      „profilePicture“: „“    },    {      „name“: „Markus Weber“,      „age“: 41,      „location“: „Berlin“,      „profilePicture“: „“    }  ] Fehlerszenarien  Mit Stubs bietet WireMock die Möglichkeit, Fehlerszenarien in der Praxis zu simulieren. Zum Beispiel, wenn die oben genannte Webanwendung versucht, mit dem Zahlungsdienst zu kommunizieren und man simulieren will, wie sich das System verhält, falls dieser langsam antwortet oder vorübergehend nicht erreichbar ist.  In den folgenden Beispielen wird gezeigt, wie WireMock Error-Status-Codes, Timeouts und fehlerhafte Antworten erzeugen kann.  Error-Status-Code:  Das Attribut status in einem Stub liegt fest, welchen Status-Code WireMock bei dieser Antwort zurückliefert: {   „request“: {     „method“: „GET“,     „url“: „/users/error“   },   „response“: {     „status“: 503,     „jsonBody“: {       „error“: „Service temporarily unavailable“     }   } } Wird eine Anfrage an die konfigurierte URL gesendet, gibt WireMock den definierten Status Code und die Antwort zurück: GET localhost:8080/users/error  Status Code: 503 Service Unavailable  {    „error“: „Service temporarily unavailable“  } Timeouts  Ein Timeout tritt auf, wenn eine Anfrage nicht innerhalb der vorgegebenen Zeit beantwortet wird. Um diesen Fall zu simulieren, bietet WireMock die Konfigurationsmöglichkeit, Stubs mit einer Verzögerung zu versehen.  fixedDelayMilliseconds  Mit fixedDelayMilliseconds wird für einen Stub eine Verzögerung mit fester Dauer festgelegt. Als Einheit werden Millisekunden verwendet:  {   „request“: {     „method“: „GET“,     „url“: „/users/delayed“   },   „response“: {     „status“: 200,     „fixedDelayMilliseconds“: 20000   } }  Wenn eine Anfrage an die konfigurierte URL gesendet wird, antwortet WireMock erst nach 20 Sekunden.  Neben Verzögerungen mit fester Dauer gibt es auch die Möglichkeit, Verzögerungen mit zufälliger Dauer zu konfigurieren. Außerdem können anstelle von Verzögerungen für einzelne Stubs auch globale Verzögerungen für alle Stubs konfiguriert werden.   Fehlerhafte Antworten  WireMock bietet auch eine Fault-Enum an, mit deren Optionen fehlerhafte Antworten erzeugt werden können. Beispiele:  EMPTY_RESPONSE: liefert eine komplett leere Antwort.  RANDOM_DATA_THEN_CLOSE: sendet fehlerhafte Daten und schließt danach die Verbindung.  Beispiel, um eine leere Antwort zu erzeugen: {   „request“: {     „method“: „GET“,     „url“: „/fault/empty-response“   },   „response“: {     „fault“: „EMPTY_RESPONSE“   } } Transformer  WireMock unterstützt die dynamische Generierung von Antworten durch vordefinierte Transformer. Diese ermöglichen die Manipulation der ursprünglichen Antworten (z. B. Anpassung des Headers, Setzen des Bodys).   WireMock nutzt Handlebars-Templates, um Antworten dynamisch anhand von Request-Attributen (z. B. Header, Body) zu generieren.   Aktivierung:   Der Transformer response-template wird in den Stub (get-user-message.json) eingefügt: {   „request“: {     „method“: „GET“,     „url“: „/users/message“   },   „response“: {     „status“: 200,     „bodyFileName“: „user-message.json“,     „headers“: {       „Content-Type“: „application/json“     },     „transformers“: [       „response-template“     ]   } } Eine Beispiel-Response (user-message.json) könnte so aussehen: {   „message“: „Hallo, {{request.headers.User-Name}}!“ } Funktionsweise:   Die doppelten Klammern {{…}} folgen der Handlebars-Syntax.  request.headers greift auf Header-Daten der Anfrage zu (z. B. User-Name).  WireMock ersetzt Platzhalter durch Werte aus dem Request.  Flexibilität:  Das request-Objekt enthält URL, Header, Query-Parameter und Body. Damit lassen sich auch komplexe, dynamische Antworten erstellen.  Ergebnis:  Wird eine Anfrage mit dem erwarteten Header an die konfigurierte URL gesendet, gibt WireMock die definierte Antwort mit dem Wert des Headers zurück: GET localhost:8080/users/message  User-Name: Markus Weber  {    „message“: „Hallo, Markus Weber!“  } Fazit  WireMock bietet durch seine leichtgewichtige Konfiguration eine flexible Lösung für Tests mit einem Mockserver. Es eignet sich sowohl für einfache Tests als auch für komplexere Szenarien – insbesondere für die Simulation dynamischer Antworten.  Kernvorteile:  Wiederverwendbare Testumgebungen:Mit Stubs lassen sich Testfälle definieren, die unabhängig von externen Services laufen.  Simulation von Fehlerszenarien:WireMock erlaubt es, gezielt Fehler wie Timeouts, fehlerhafte Antworten oder Error-Status-Codes zu erzeugen, um das Verhalten der Anwendung unter ungünstigen Bedingungen zu testen.  Anpassbare Antworten:Erweiterungen wie Response-Templates ermöglichen die dynamische Generierung von Antworten, die auf variablen Eingaben basieren.  In einem Kundenprojekt haben wir WireMock gezielt

Testen statt hoffen: Wie man mit ArchUnit die Softwarearchitektur nachhaltig in den Griff bekommt 

A worker seen from behind who is adding words to a chart in front of him with a laptop next to him

Softwarearchitektur ist wie ein Bauplan beim Hausbau: Ohne soliden Plan wirkt am Anfang vielleicht alles noch machbar, aber spätestens, wenn mehr Stockwerke dazukommen sollen oder jemand eine neue Tür einbauen will, wird’s kompliziert. Leitungen verlaufen kreuz und quer, Räume sind unlogisch angeordnet – und plötzlich muss man viel mehr umbauen, als nötig wäre. In der Software ist das genauso: Eine gute Architektur sorgt dafür, dass alles sinnvoll aufgebaut ist, gut zusammenpasst und sich später einfach erweitern oder ändern lässt, ohne dass man ständig Wände einreißen muss.  Aber ein Plan ist nur so gut wie seine Umsetzung – und genau da wird’s oft schwierig. In Projekten stehen wir immer wieder vor der Herausforderung, Architekturvorgaben konsequent einzuhalten. Besonders in großen, langjährigen Projekten mit einer gewachsenen Codebasis ist die Komplexität oft hoch und dadurch schwer beherrschbar. Das macht die Entwicklung neuer Funktionalitäten, egal ob klassisch oder mit Coding Assistant, oder auch die Einarbeitung neuer Teammitglieder immer herausfordernder. Missverstandene oder nicht bekannte Architekturvorgaben können dann schnell zu Problemen führen und plötzlich sind Abhängigkeiten oder zusätzliche Aufwände da, die da nie hätten sein sollen. Dabei sind klare Architekturvorgaben kein Selbstzweck: sie helfen uns, sauberen, wartbaren Code zu schreiben und technische Schulden zu vermeiden. Eine Architektur-Dokumentation für ein Projekt ist hilfreich, stellt aber keine korrekte Umsetzung sicher. Wie auch beim Testen von Funktionalität zeigt sich beim manuellen Überprüfen der Architektur, dass dies aufwändig und auf Dauer nicht immer zuverlässig ist – Automatisierung ist im Bereich der fachlichen Tests der Schlüssel, um Qualität nachhaltig sicherzustellen. Warum also nicht auch bei der Architektur?  Hier setzt ArchUnit an – eine Bibliothek, mit der Architekturregeln in Code festgehalten werden können, um diese in Java-Projekten automatisiert zu prüfen. Doch wie genau kann ArchUnit helfen, typische Probleme zu vermeiden? Wir zeigen dies anhand mehrerer Beispiele aus der Praxis.  ArchUnit in a Nutshell  ArchUnit wird einfach via Maven oder Gradle eingebunden  und ermöglicht es, Architekturregeln in Form von Unit-Tests zu definieren. Dabei nutzt es eine Fluent API, um Regeln intuitiv und gut lesbar zu schreiben. Die Regeln können direkt in bestehende Testsuiten integriert und automatisch bei jedem Testlauf überprüft werden. So lassen sich Verstöße gegen Architekturvorgaben frühzeitig erkennen und beheben. Bild: https://www.archunit.org/getting-started#let-the-api-guide-you  Beispiel: Abhängigkeiten zwischen Paketen managen  Bei einer Schichtenarchitektur sind Abhängigkeiten zwischen den Schichten eingeschränkt, es darf nur auf Klassen in der eigenen oder direkt darunter liegenden Schicht zugegriffen werden. In einer typischen 3-Schicht-Architektur mit Controller-, Service- und Repository-Schicht dürfte dann zum Beispiel ein Controller keine direkten Zugriffe auf Repository-Klassen haben sowie Services nur von anderen Services oder Controllern eingebunden werden. Anstatt regelmäßig manuelle Reviews durchzuführen, um diese Vorgaben einzuhalten, können automatisierte ArchUnit-Regeln dafür wie folgt aussehen:  @ArchTest  public static final ArchRule controller_should_not_access_repositories_directly =      noClasses().that().resideInAPackage(„..controller..“).should()         .accessClassesThat().resideInAPackage(„..repository..“);  @ArchTest  public static final ArchRule services_should_only_be_accessed_by_controller_and_service =       classes().that().resideInAPackage(„..service..“).should()    .onlyBeAccessed().byAnyPackage(„..controller..“, „..service..“); Abhängig vom Paket, in dem sich eine Klasse befindet, wird hier festgelegt, aus welchen anderen Paketen ein Zugriff stattfinden darf. Statt einem voll qualifiziertem Paketnamen wird hier mittels Wildcards lediglich auf den Paketnamen an beliebiger Stelle im Projekt gematcht.  Die erste Regel fordert also, dass keine Klassen, die innerhalb eines Pakets „controller“ enthalten sind, Klassen innerhalb eines Pakets „repository“ aufrufen dürfen.   Diese Regeln lassen sich wie andere Unit-Tests ausführen. Einmal definiert, lässt sich so die Einhaltung von Architekturvorgaben bei jeder zukünftigen Ausführung der Tests automatisiert und ohne zusätzlichen Aufwand sicherstellen. Und im Fall einer Regelverletzung wird ein Fehler ausgegeben – ähnlich sprechend wie die Regeldefinition, zum Beispiel:  java.lang.AssertionError: Architecture Violation – Rule ’no classes that reside in a package ‚..controller..‘ should access classes that reside in a package ‚..repository..“ was violated (1 times):  Constructor <de.isento.arch.demo.controller.MyDemoController.<init>()> calls constructor <de.isento.arch.demo.repository.MyDemoRepository.<init>()> in (MyDemoController.java:15)  Migrationen sind ein weiteres Themenfeld, bei dem ArchUnit Unterstützung leisten kann. So lässt sich etwa sicherstellen, dass neuer Code keine unerwarteten Abhängigkeiten zum Bestandscode aufbaut. Eine Regel hierfür könnte, ähnlich wie die Regeln zur Schichtenarchitektur, festlegen, dass Pakete mit neuer Implementierung nicht auf abzulösende Pakete zugreifen dürfen.  Will man nicht nur die Abhängigkeiten einzelner Klassen oder Pakete untereinander, sondern weitreichender die Paketstruktur eines Projektes definieren, ist dies mit einem Abgleich gegen PlantUML-Diagramme möglich. Aus einer reinen Visualisierung einer Architektur in UML wird so ein ausführbarer Test auf die Einhaltung dieser. Ein Beispiel für die Einbindung eines Diagramms sieht wie folgt aus:  static final URL myArchDiagram = MyDemoArchTest.class.getClassLoader().getResource(„myArchDiagram.puml“);@ArchTeststatic final ArchRule uml_diagram_should_be_respected =     classes().should(       adhereToPlantUmlDiagram(myArchDiagram, consideringOnlyDependenciesInAnyPackage(„de.isento..“)));  Beispiel: Einhaltung von Querschnittskonzepten  Ein weiterer Anwendungsfall, für den sich ArchUnit eignet, ist die Sicherstellung der Einhaltung von Querschnittskonzepten. Betrachten wir beispielsweise eine selbstgeschriebene Logging-Bibliothek, welche Logmessages um Kontext (etwa aus dem Request oder Methodenparametern) anreichert. Es soll in diesem Fall hier im Beispiel sichergestellt werden, dass bei jedem Schnittstellenaufruf einer REST-API im Controller – und auch genau nur an dieser Stelle in der Anwendung – die Logging-Bibliothek mittels Annotationen entsprechend eingebunden ist. Ohne ein Tool wie ArchUnit besteht die Gefahr, dass versehentlich die Einbindung ganz vergessen oder die Bibliothek an falscher Stelle oder mehrfach eingebunden wird.  Mit ArchUnit lassen sich gezielt Regeln definieren, die genau dies verhindern. Dies könnte in einem Spring Boot Projekt wie folgt aussehen:  @ArchTest public static final ArchRule all_rest_endpoints_must_have_logging_annotation =     methods().that().areMetaAnnotatedWith(RequestMapping.class)       .should().beAnnotatedWith(MyDemoLoggingAnnotation.class);  @ArchTest public static final ArchRule only_rest_endpoints_must_have_logging_annotation =     methods().that().areAnnotatedWith(MyDemoLoggingAnnotation.class)  .should().beDeclaredInClassesThat().areMetaAnnotatedWith(Controller.class);  Diese Regeln stellen sicher, dass das Logging konsistent eingebunden wird und auch bei zukünftigen Änderungen keine Klasse vergessen wird.   Bestehende Codebasen verbessern mit dem Freeze-Modul  Selbst wenn bestehender Code noch nicht allen gewünschten Regeln entspricht, ist ArchUnit hilfreich. Mit FreezingArchRules lassen sich bestehende Regelverletzungen zunächst festhalten und „einfrieren“. Bei Testläufen danach werden diese Regelverstöße bis zur Behebung toleriert, und lediglich neue Verstöße führen zu einem Fehlschlag des Testlaufs. Damit wird es möglich, dass mit geringem Aufwand neue Regeln eingeführt werden können, ohne dass sofort der gesamte Altbestand bereinigt werden muss. So können Architekturregeln auch in gewachsenen Systemen schrittweise etabliert werden, ohne den Entwicklungsfluss zu stören.  Ein Beispiel für eine „eingefrorene“ Regel sieht folgendermaßen aus:  @AnalyzeClasses(packages = „de.isento“) public class MyArchitectureTest {    @ArchTest     public static final FreezingArchRule frozen_rule =      FreezingArchRule.freeze(     noClasses().that().resideInAPackage(„..controller..“).should()                      .accessClassesThat().resideInAPackage(„..repository..“);         ); }  Fazit: ArchUnit als Bestandteil einer nachhaltigen Softwarearchitektur  Die beschriebenen

Moderne Weiterbildung: Das macht Barcamps so wertvoll

Das Bild beschreibt die Szene eines Barcamps in der Softwareentwicklung. Eine Gruppe Menschen sitzt um einen Tisch herum und diskutiert. Links daneben steht eine Frau, die einen Vortrag hält.

Stell dir vor, du triffst am Wochenende eine Menge Gleichgesinnter, die genauso für Tech brennen wie du. Keine endlosen Folien, keine Frontbeschallung, sondern echte Gespräche, spannende Sessions und jede Menge Spaß. Das ist ein Barcamp. Ein Ort, an dem IT-Begeisterte voneinander lernen, sich vernetzen und Themen entdecken, die sie sonst vielleicht nie auf dem Schirm gehabt hätten.  Gerade die IT-Welt entwickelt sich rasant weiter. Neue Frameworks, Tools und Best Practices tauchen fast wöchentlich auf. Klassische Schulungen und Konferenzen können da oft nicht Schritt halten – zu starr, zu vorgeplant, zu begrenzt. Barcamps bieten hier eine erfrischende Alternative. Sie kombinieren Austausch, Praxisnähe und Selbstbestimmung und sind damit eine der spannendsten Formen moderner Weiterbildung. Was ist ein Barcamp? Ein Barcamp, auch Unkonferenz genannt, ist ein offenes Konferenzformat, das 2005 im Silicon Valley entstanden ist. Die Grundidee: Oft sind es nicht die Vorträge selbst, die den größten Mehrwert bringen, sondern die Gespräche in den Pausen dazwischen, wo Menschen frei diskutieren, Erfahrungen teilen und neue Ideen entwickeln. Aus diesem Gedanken heraus entstand das Konzept, die „Pausengespräche“ einfach ins Zentrum zu stellen. Der Name spielt auf das exklusive „Foo Camp“ an, mit dem Unterschied, dass Barcamps bewusst offen und niedrigschwellig sind. Beim Barcamp gibt es deshalb keine feste Agenda im Vorfeld. Stattdessen schlagen die Teilnehmenden morgens ihre Themen vor, und daraus entsteht ein Sessionplan für den Tag. So wird aus zufälligen Flurgesprächen ein bewusst gestalteter Raum für Austausch, Lernen und Inspiration.   Warum Barcamps so wertvoll sind Lernen auf Augenhöhe Egal ob Junior Developer oder Senior Architect, auf einem Barcamp bringt jede:r nicht nur Wissen, sondern auch Fragen, Erfahrungen und Ideen ein. Jede Perspektive ist wertvoll und wird gehört. Das schafft eine Atmosphäre, in der man sich traut, offen zu diskutieren und Wissen zu teilen.  Vielfältige Formate Barcamps leben von der Abwechslung: kurze Impulspräsentationen, offene Diskussionsrunden, interaktive Workshops oder Fragesessions („Kennt sich hier jemand mit Framework xy aus?“). Diese Vielfalt sorgt dafür, dass alle Teilnehmenden auf ihre Kosten kommen, egal ob sie lieber zuhören, mitdiskutieren oder praktisch ausprobieren.  Aktuelle Themen aus der Community Während klassische Konferenzen lange Vorlaufzeiten haben, spiegeln Barcamps genau das wider, was die Community jetzt gerade bewegt, ob neue KI-Frameworks, DevOps-Tools oder Security-Themen. Aber auch softere Themen wie „Feedback geben“ oder „Zusammenarbeit in internationalen Teams“ sind möglich.  Unerwartetes Wissen („unknown unknowns“) Einer der größten Reize von Barcamps ist die Überraschung: Man stößt auf Themen, von denen man gar nicht wusste, dass man sie lernen sollte. Diese Aha-Momente erweitern den eigenen Horizont und inspirieren dazu, neue Richtungen auszuprobieren.  Vielfalt an Perspektiven In Sessions treffen oft Menschen aus unterschiedlichen Branchen, Erfahrungsleveln und Bereichen der IT zusammen: Entwickler:innen, Scrum Master, UX-Designer:innen, Product Owner. Diese Mischung bringt Denkanstöße, die über die eigene Fachdisziplin hinausgehen.  Selbstbestimmtes Lernen Niemand sitzt „fest“ in einem Thema, das ihn nicht interessiert. Jede:r wählt die Sessions frei und kann jederzeit wechseln. Durch den interaktiven Charakter gestaltet jede:r zudem die Sessions durch Fragen und Erfahrungen mit.  Netzwerken und Spaß Zwischen den Sessions und am Abend geht es nicht nur ums Fachliche: Man kommt locker ins Gespräch, lacht gemeinsam und tauscht Anekdoten aus Projekten aus. Und für gute Verpflegung ist bei Barcamps natürlich auch immer gesorgt. Barcamps bei isento: Von Sponsoring zu Teamtagen Barcamps gibt es inzwischen zu fast jedem Thema von Softwareentwicklung und DevOps bis hin zu Bildung, Nachhaltigkeit oder Design. Eine Übersicht gibt es hier. Diese Vielfalt zeigt, wie gut das Format funktioniert: Motivierte Menschen kommen zusammen, um Wissen zu teilen und voneinander zu lernen. Genau deshalb freuen wir von isento uns, auch in diesem Jahr wieder das Seneca Camp als Sponsor unterstützen zu können. Hier waren wir bereits in den letzten Jahren vertreten und haben auch als Besuchende viel für unsere tägliche Arbeit mitnehmen können. Das Prinzip von Barcamps leben wir auch intern mit unseren Duke Days, unseren großen monatlichen Team-Runden. An diesen Tagen lassen wir bewusst das Tagesgeschäft ruhen, um uns ganz dem Lernen und Austauschen zu widmen. Alle bringen ihre Themen, Ideen oder Fragen ein von neuen Technologien über Lessons Learned aus Projekten bis hin zu Soft-Skill-Workshops oder Verbesserung interner Strukturen. So entsteht ein Tag, an dem wir voneinander und miteinander lernen, gemeinsam diskutieren und als Team noch stärker zusammenwachsen.  Barcamps in der Softwarentwicklung und darüber hinaus Barcamps sind weit mehr als nur eine Weiterbildungsmethode. Sie sind eine Spielwiese für Wissenshungrige. Gerade im IT- und Softwareentwicklungsbereich sind sie unschlagbar, weil man dort nicht nur aktuelle Trends mitnimmt, sondern auch auf Themen stößt, die man nie auf dem Radar gehabt hätte. Und das Beste: Man lernt nicht nur, sondern hat dabei auch noch Spaß und kommt mit neuen Kontakten und Energie zurück in den Alltag.  Die nächsten Barcamps in der Region Nürnberg: 19.-​21.09.2025: https://seneca.camp/  10.10.-12.10.2025: https://devops-camp.de/  Mai 2026: https://swe-camp.de/  Komm vorbei beim Seneca Barcamp und lerne unser Team persönlich kennen! Oder schau vorbei in unseren Stellenanzeigen, wenn dich unsere Art zu Arbeiten und Lernen überzeugt hat und du gerne Teil von isento werden möchtest.

Clean Code – Wie schreibt man guten Code?

Wie schreibt man guten Code, und wenn ja wieviel Austausch braucht es dazu? Ob im Studium, im Hobbyprojekt oder im beruflichen Alltag, als Softwareentwickler:in begegnen wir täglich diesen Fragen: Wie schreibt man guten Code? Was ist eigentlich guter Code? Wann genau ist Code gut? Viele von uns haben ein intuitives Verständnis von gutem Code. Doch diese Intuition zu verbalisieren ist gar nicht so einfach. Eine Googleanfrage zu „what is good code“ zeigt über 6 Millionen Versuche dieses Verständnis greifbar zu machen. Auch bei isento treibt uns dieses Thema um – im Pair Programming, im Code Review und hin und wieder auch am Mittagstisch mit den Kolleg:innen. Da letzterer jedoch vor allem der Pandemie zum Opfer fiel (Home-Office grüßt!), fehlte uns hier eine wichtige Austauschquelle. Allerdings: Not macht erfinderisch, und so kam uns die Idee: Warum gründen wir nicht einen (Remote-)Lesekreis und gehen gemeinsam der Frage auf den Grund: Wann ist Code gut? Ein Lesekreis gründet sich – remote und motiviert Nach über einem Jahr Pandemie waren wir fest erprobt was den Entwicklungsalltag im Home-Office angeht. Dailys, Weeklys, Retros – remote alles kein Problem. Doch ein Online-Lesekreis? Wir geben zu, auch wir waren uns zu Beginn nicht sicher, wohin uns dieses Experiment führen würde. Fest verankert in unserer Vorstellung war das Bild angeregt diskutierender Menschen im Stuhlkreis. Unsicherheit ist für uns aber kein Grund etwas nicht zu tun. Bei isento begeben wir uns auch gerne in unerprobtes Terrain. Da sich der Kontakt mit den Kolleg:innen während Remote-Phasen dann doch überwiegend auf das eigene Team konzentrierte, motivierte uns der Gedanke, nach so langer Zeit wieder den teamübergreifenden Austausch zu pflegen. So entschieden wir uns dazu, das Experiment Lesekreis einfach zu wagen. Zu verlieren hatten wir nichts, zu gewinnen umso mehr: Wir sind breit aufgestellt, von den Entry-Level-Positionen bis hin zu erprobten Lead Developern ist bei uns jeder Erfahrungsschatz vertreten. Eine perfekte Ausgangslage also, um von gegenseitigen Erfahrungen zu profitieren. Mit Uncle Bob auf den Spuren von sauberem Code Wer sich auf die Spuren von gutem Code begibt, kommt um diesen Klassiker nicht herum: „Clean Code: A Handbook of Agile Software Craftsmanship“ (Robert C. Martin, 2008). Von weiten Teilen der internationalen Dev Community als das Standardwerk für guten Code empfohlen, einigten wir uns schnell auf die Lektüre des Buches. Eine wiederkehrende Terminserie in unserem Remote-Tool der Wahl erstellt und dann war es offiziell: Woche um Woche würden wir nun gemeinsam ein Kapitel durcharbeiten. Um für Abwechslung zu sorgen, durfte jeder Teilnehmende die Moderation einer Sitzung übernehmen. Dabei waren die Moderator:innen der Woche frei in ihrer Ausgestaltung – solange sie darauf achteten, eine Diskussion anzustoßen. Tatsächlich stießen sich diese meist von selbst an. Darauf sind wir besonders stolz. 😉 Von- und miteinander lernen Auch wenn es gut tat, nach so einer langen Zeit mal wieder im größeren Kolleg:innenkreis zusammenzufinden – das wahre Herzstück unseres Lesekreises waren eindeutig die lebhaften Diskussionen. In diesen teilten wir unsere Meinungen und Eindrücke zu den gelesenen Buchinhalten, setzten uns kritisch mit diesen auseinander und erarbeiteten gemeinsam alternative Codebeispiele. Seit der Veröffentlichung von Clean Code (2008) sind ja doch einige Jahre ins Land gezogen, in denen sich die Welt der Softwareentwicklung ebenfalls weiterdrehte. Umso wichtiger war es uns, Uncle Bobs Gedanken nicht dogmatisch zu übernehmen, sondern sie als Grundlage weiterer Überlegungen zu betrachten. Dass Dogmatismus und “One fits all”-Ansätze in der Praxis schnell an ihre Grenzen stoßen, stellten wir eindrücklich im Erfahrungsaustausch fest. Was für das eine Team funktionieren mag, entpuppt sich für das Nächste bereits als Hindernis. Grüne Wiese oder Brownfield-Entwicklung, Leerlauf oder Crunch Time – Softwareprojekte kommen mit ihren ganz eigenen Anforderungen. Umso hilfreicher war es für uns von unseren Kolleg:innen zu lernen, mit welchen Best Practices und Konventionen sie teamintern diesen Anforderungen begegnen, um dennoch sauberen Code zu entwickeln. Über sauberen Code zu diskutieren, erweckte auch den Tatendrang in uns. Insbesondere die späteren Kapitel zum Thema Refactoring inspirierten uns dazu, selbst die Ärmel hochzukrempeln. Da wir bei isento neben Auftragssoftware ebenfalls Inhouse-Projekte entwickeln, befanden wir uns in der glücklichen Lage zwei Fliegen mit einer Klappe zu schlagen: unseren neu gewonnen Wissensschatz konnten wir an “echtem” Code anwenden und damit die Codequalität unseres Inhouse-Projektes verbessern. Beyond Clean Code: Das haben wir gelernt Natürlich haben alle ihre eigenen Eindrücke gesammelt und Lektionen mitgenommen. Für uns als Software Developer bei isento steht nun jedoch fest: Guter Code ist sauberer Code, und dieser entsteht iterativ. Das Buch Clean Code empfinden wir als sehr gutes Referenzwerk, raten jedoch davon ab, es unreflektiert und stur zu befolgen. Dogmatismus ist im Entwicklungsalltag fehlplatziert, wie unser Erfahrungsaustausch gezeigt hat. Denn häufig gibt es nicht nur die eine Variante von sauberem Code und nicht jeder Ratschlag ist in jeder Situation zielführend. Einen positiven Nebeneffekt hatte unser Lesekreis dann insbesondere auch für unsere isento-Neuzugänge: Er war eine super Gelegenheit, um teamübergreifende Kontakte zu knüpfen. Ich selbst habe so auch einen Teil meines späteren Teams kennengelernt. 😀 Unser Fazit Ein Lesekreis, noch dazu remote – das war auch für uns Neuland. Motiviert und guter Dinge begaben wir uns in dieses Experiment. Und nun, etliche Wochen später, stehen wir vor der Frage: Hat es sich gelohnt? Wir sagen: Ja, definitiv! Unser Lesekreis war ein voller Erfolg. Mit unterschiedlichen Wissensständen starteten wir, mit einem gemeinschaftlich erarbeiteten Verständnis von sauberem Code kehren wir zurück. Insbesondere der fachliche Austausch mit den Kolleg:innen und die anknüpfenden Diskussionen entpuppten sich als wertvolle Erfahrungsquellen. So dürfte manch einem und einer sicherlich der lebhafte Austausch zum Thema „Unit Tests“ in Erinnerung bleiben. Von Uncle Bob auf 12 Seiten skizziert, diskutierten wir tatsächlich angeregt bis in die Mittagspause hinein. Genau diese offene Diskussionskultur macht unser Experiment zum Erfolg. Unser Lesekreis ist eine wertvolle Erfahrung, die wir gerne wiederholen. Tatsächlich haben wir schon die ein oder andere Idee für das nächste Buch in großer Runde. Fun Fact: Unser Format war sogar so erfolgreich, dass unsere Ressortleiterrunde jetzt auch zusammen ein Buch liest. 😊 Carina Walker Carina war Softwareentwicklerin bei isento

Apache Cassandra – DAS NoSQL-Datenbanksystem

Weiterbildung ist ein zentraler Punkt bei isento. Es ist wichtig auf dem neuesten Stand der technologischen Entwicklung zu sein. Umso besser, wenn man dies sogar im Rahmen eines Kundenprojekts realisieren kann. Unser Kollege Thorsten arbeitet derzeit an einem Benachrichtigungssystem. Wir haben euch bereits über den Einsatz von Apache Kafka in diesem Projekt berichtet. Ein weiter Baustein zur Umsetzung ist die NoSQL Datenbank Apache Cassandra. Diese möchten wir euch heute vorstellen: Die Grundlagen Apache Cassandra ist ein verteiltes NoSQL-Datenbanksystem. Es ist auf hohe Ausfallsicherheit und Skalierbarkeit ausgelegt und ist derzeit die beliebteste spaltenorientierte NoSQL-Datenbank am Markt. Im Gegensatz zu CouchDB und MongoDB(C++) ist diese wie Apache HBase in Java geschrieben. Seit der Version 0.8 wurde die Cassandra Query Language eingeführt, eine SQL-angelehnte Abfragesprache, die als einfache Schnittstelle dienen kann. Ursprünglich wurde Cassandra bei Facebook entwickelt, um das Problem der Inbox Search zu lösen. Nach der Bereitstellung als OpenSource Projekt 2008 haben auch weitere Unternehmen wie Twitter und IBM zum Code beigetragen. Die Architektur von Apache Cassandra Im Gegensatz zu SQL-Datenbanken, werden die Daten bei der NoSQL-Datenbank Cassandra nicht relational, sondern spaltenorientiert gespeichert (bekannt als Wide-Column Stores). Der Betrieb wird in einem Cluster realisiert, der in Knoten unterteilt ist. Es gibt dabei keine zentrale Steuerung. Man spricht von einer Masterless-Architektur. Jeder Knoten ist gleichgestellt und kann prinzipiell alle Anfragen verarbeiten. Die Daten werden im Cluster verteilt auf Knoten, ein Knoten kann dabei eine oder mehrere Partitionen enthalten. Der sogenannte Partition Key eines Datensatzes gibt vor, wo die Daten im Cluster zu finden sind. Je nach Replikations-Faktor werden Daten auf verschiedene Knoten dupliziert, um den Zugriff auf das Cluster auch beim Ausfall einzelner Knoten sicherzustellen, Stichwort Hochverfügbarkeit. Bei dieser Art von Datenbank stehen schnelle Lesezugriffe, also hoher Durchsatz, im Vordergrund. In Cassandra werden dafür Daten query-orientiert modelliert und Datenduplizierungen explizit in Kauf genommen, im Vergleich zu relationalen Datenbanken mit normalisierten Tabellen. Vorteile von Cassandra 1. Problemlose horizontale Skalierung 2. Hochverfügbarkeit dank Masterless-Architektur 3. Hohe Fehlertoleranz durch Datenreplikation 4. Hohe Performance 5. Multi-Data-Center-Implementierung Use Cases Apache Cassandra Durch seine architektonischen Eigenschaften kommt Apache Cassandra sehr oft in Big Data-Projekten zum Einsatz. In Zusammenarbeit mit einem Applikationsserver/Framework kann es aber auch sehr gut bei komplexen Webanwendungen genutzt werden. Unternehmen wie Apple, Twitter, Spotify oder Reddit setzen auf Cassandra. In Spotify zum Beispiel lassen sich über 1,5 Milliarden Playlists in „Echtzeit“ erstellen und verwalten. Auch bei der Nutzung von Nachrichtensystemen wie Chats oder Instant Messaging eignet sich die Datenbank. Neue Nachrichten lassen sich schnell erstellen und lesen und werden nach einer vorgegebenen Zeit wieder gelöscht, um das System nicht zu überlasten. Ein weiterer Einsatzbereich lässt sich im eCommerce finden. So können unter Anderem persönliche Kaufempfehlungen an die Kunden mit Unterstützung von Cassandra erstellt werden. Es wird also deutlich, dass das Datenbanksystem sehr viele Vorteile mit sich bringt und sich mit seinen Funktionen für ein sehr breit gefächertes Einsatzspektrum anbietet. Nicht zu Unrecht ist Apache Cassandra darum derzeit so populär. Anika Danner Anika ist Head of Marketing bei isento

Apache Kafka – Die Streamingplattform

Wir bei isento finden es richtig und wichtig sich immer weiterzubilden und auf dem neuesten Stand der technologischen Entwicklung zu sein. Umso besser, wenn dies sogar in den Rahmen eines Kundenprojekts passt. Unser Kollege Thorsten arbeitet derzeit an einem Benachrichtigungssystem. Nach Prüfung der Möglichkeiten hat man sich für eine Umsetzung mit der Software Apache Kafka und der NoSQL Datenbank Apache Cassandra entschieden. Die Beiden befinden sich momentan in aller Munde und sind ein großes Trendthema in der Softwareentwicklung Oder wie man bei uns intern sagt: „Ein ganz heißer Scheiß auf dem Markt“. 😉 Doch warum genau ist das so? Wir schauen uns die Programme mal näher an und starten heute mit Apache Kafka: Apache Kafka – Einführung Apache Kafka wurde ursprünglich von LinkedIn für die Verarbeitung von rund 1,4 Milliarden Nachrichten pro Tag entwickelt. Der Fokus wurde dort auf die Analyse des Nutzerverhaltens mit einem hohen Durchsatz gelegt. Kafka kann als Datenquelle für Event-Streaming-Anwendungen, als Message Broker und als verteiltes Messaging Log (Event-Sourcing) genutzt werden. Event-Streams können also gespeichert und wiederholt verarbeitet werden. Ebenso kann Kafka als Schnittstelle dienen, um Daten in Drittsysteme zu laden oder zu exportieren. Es ist sozusagen ein Publish-Subscribe System zwischen Sender und Empfänger, welches Nachrichten in hoher Geschwindigkeit verarbeitet und in „Echtzeit“ verfügbar macht. Kafka-Architektur Die hohe Leistung von Kafka ist der Architektur geschuldet und erlaubt mehrere Möglichkeiten bei der Dimensionierung in der Infrastruktur. Die standardmäßige Unterteilung in Cluster mit einzelnen Knoten, den so genannten Brokern, ist möglich. Welches aber dann alle Topics replizieren würde und so einen (unnötigen) höheren Ressourcenverbrauch darstellt. Oftmals sind aber einzelne Topics das Problem, in die einkommende Daten verteilt werden. In Kafka bestehen Topics aus mindestens einer Partition. Diese Anzahl an Partitionen kann erhöht werden, passend zur Anzahl bzw. Performance der Konsumenten, ohne die Redundanz auf anderen Topics zu erhöhen. Ein weiterer Unterschied zu anderen Publish-Subscribe Systemen, sind die Messages die in ein Topic geschrieben werden. Der Aufbau einer Message ist vereinfacht { Key Value }-Paar. Neue Messages im Topic werden auf die bestehenden Partitionen verteilt und immer hinten angehängt, d.h. sie werden in der Reihenfolge gespeichert, in der sie geschrieben wurden. Die Zuordnung an die Partitionen erfolgt über den Key. Gleicher Key führt zu gleicher Partition. Producer, Anwendungen die Daten schreiben, können eine Message in ein Topic stellen (publish), Consumer wiederum können diese aus dem Topic abrufen und lesen (subscribe). Consumer können sich auch als „Consumer Group“ zusammenschließen, um die Daten aus dem Topic zu lesen. Dabei garantiert die „Consumer Group“ bei den Consumern, dass die gleiche Message nicht mehrfach gelesen wird, falls diese von einem Consumer der Gruppe verarbeitet wurde. Innerhalb der Partition wird für die Consumer Group die Position der gelesenen Daten (Offset) gespeichert. Nachrichten in Kafka werden üblicherweise über einen gewissen Zeitraum bereitgestellt, weshalb man auch vom Event-Log bei Kafka spricht. Wird diese so genannte „retention time“ überschritten oder ist der Speicher voll, löscht Kafka alte Nachrichten. Neben diesen normalen Topics gibt es die Möglichkeit der compacted Topics. Hier bleiben die Messages bestehen und unterliegen keiner Limitierung. Die Vorteile von Apache Kafka Die Plattform liefert das Komplettpaket für eine schnelle und effiziente Übertragung und Zwischenspeicherung von Daten und das auf eine vergleichsweise einfache Art und Weise. Das Ganze gepaart mit einer hohen Ausfalltoleranz bedingt durch die extreme Skalierbarkeit, ermöglicht sogar „Echtzeit“-Kommunikation zwischen Producer und Consumer. Anwendung von Kafka Kafka ist gerade im Umfeld von Big Data und Analytics ein geeignetes und immer öfter gesehenes System. Daten sind heutzutage eine wichtige Währung und mit Daten zu arbeiten und sie schnell zu verarbeiten kann einen großen Erfolgsfaktor darstellen. Neben dem Echtzeit-Tracking von Aktivitäten auf Webseiten können auch die Datenkonsolidierung von verteilten Anwendungen oder der Transport von Metriken Anwendungsbeispiele sein. Zunehmend wird Apache Kafka auch beim Maschinellen Lernen genutzt. So können Modelle in Echtzeit trainiert, überwacht und analysiert werden. Es können aber auch kundenspezifische Angebote unter Einbeziehung verschiedener Daten erstellt werden wie Kaufvorlieben, vorherige Käufe, Standort, etc. Die Plattform ist somit eine vielseitige und vielversprechende Option, die es lohnt sich näher anzusehen. Im nächsten Blogbeitrag erfahrt ihr mehr zum Datenbanksystem Cassandra. Anika Danner Anika ist Head of Marketing bei isento

Isento Touch

Wir freuen uns,
Sie kennenzulernen.

Isento Experts

Für Kundenanfragen
Kontakt Vertrieb IT-Service Dienstleistung Softwareentwicklung Nürnberg

Miriam Barthelmes

Für interessierte Bewerber:innen
Auf dem Bild ist eine Frau zu sehen, die kurze braune Haare hat und einen orangenen Blazer trägt.

Christina Kommer