17
.
02
.
2025

Praxistipps für lokale Entwicklungsumgebungen: schnell qualitatives Feedback erhalten

Lokale Entwicklungsumgebungen optimieren Feedback und steigern die Qualität – hier sind unsere Praxistipps.

Verfasst von:  

Adrien Wehrung | Software-Architekt

Die Softwarebranche ist ein dynamisches und innovationsgetriebenes Umfeld, in dem kontinuierliche Weiterentwicklung essenziell für den Unternehmenserfolg ist. Eine effektive Produktentwicklung erfordert ein Zusammenspiel aus technischer Präzision und strategischer Ausrichtung. Bestehende Systeme werden optimiert und neue Lösungen geschaffen – stets mit dem Ziel, die Stabilität der bereits bestehenden Software und den Fortschritt durch neue Software in Einklang zu bringen.

Ein zentraler Bestandteil dieses Entwicklungsprozesses ist kontinuierliches Feedback: Läuft die Entwicklung in die richtige Richtung? Dabei lassen sich zwei wesentliche Feedback-Ebenen unterscheiden:

  • Technische Ebene: Erreicht eine Code-Optimierung einen messbaren Performance-Gewinn? Löst eine Implementierung einen bestehenden Fehler? Lässt sich eine neue Idee nahtlos in das System integrieren oder entstehen unerwartete Probleme?
  • Business-Ebene: Verbessert ein neues Feature die Nutzererfahrung und Kundenzufriedenheit? Wie intuitiv ist die Anwendung? Trägt die Entwicklung zur Erreichung strategischer Ziele bei?

Die Antworten auf diese Fragen dienen als Steuerungselement der agilen Entwicklung. Ohne verlässliches Feedback ist eine zielgerichtete Weiterentwicklung nicht möglich. Da viele dieser Fragen eine enge Zusammenarbeit zwischen Entwicklern, Product Ownern und weiteren Stakeholdern erfordern, ist es entscheidend, dass Feedback sowohl technisch als auch organisatorisch effizient eingeholt werden kann.

Ein Schlüsselfaktor für erfolgreiche agile Entwicklung ist die Qualität und Geschwindigkeit des Feedbacks: Je präziser und schneller Antworten auf die oben genannten Fragen vorliegen, desto effizienter kann das Team arbeiten.

Dieser Artikel befasst sich mit der lokalen Laufzeitumgebung des entwickelten Systems und untersucht, welchen Beitrag sie zur Optimierung des Feedback-Prozesses leistet – sowohl auf technischer als auch auf Business-Ebene. Zudem werden Herausforderungen und Grenzen der lokalen Entwicklungsumgebung beleuchtet sowie fundierte Empfehlungen auf Basis unserer Projekterfahrung für eine effektive Nutzung gegeben.

Lokale Entwicklungsumgebungen und Stage Deployment: Die Basis des Entwicklungsprozesses

In modernen Softwareentwicklungsprojekten sind verschiedene Umgebungen entscheidend für die Qualität und den reibungslosen Ablauf der Arbeit. Zwei zentrale Umgebungen, die sowohl Entwicklern (DEV) als auch Product Ownern (PO) und Stakeholdern eine effiziente Zusammenarbeit ermöglichen, sind die lokale Umgebung und das Stage Deployment. Diese Umgebungen spielen eine wichtige Rolle im Entwicklungszyklus und tragen dazu bei, Risiken zu minimieren und die Qualität des Endprodukts zu sichern.

Die lokale Entwicklungsumgebung ist der Ausgangspunkt für Entwickler, um ihren Code zu schreiben und zu testen. Hier arbeiten Entwickler an neuen Features, beheben Bugs und testen ihren Code unter kontrollierten Bedingungen auf ihrer eigenen Maschine. Die lokale Umgebung enthält oft alles, was für die Entwicklung erforderlich ist, wie Datenbanken oder APIs, und ermöglicht es Entwicklern, schnell Änderungen vorzunehmen, ohne die Produktionsumgebung zu gefährden.

Sobald der Code in der lokalen Umgebung entwickelt und getestet wurde, wird er in die Staging-Umgebung überführt. Diese Umgebung dient als nahezu identische Kopie der Produktionsumgebung und stellt sicher, dass der Code unter realistischen Bedingungen getestet wird, bevor er live geht. Für Stakeholder und den PO ist die Staging-Umgebung die Plattform, auf der neue Features überprüft und die Funktionalität vor der Veröffentlichung validiert wird.

Die Rolle von Continuous Integration (CI)-Tools, wie Jenkins oder GitLab CI, ist hierbei zentral. Sie ermöglichen eine automatische Übergabe des Codes von der lokalen Umgebung in die Staging-Umgebung, stellen sicher, dass dieser getestet wird, und verhindern, dass fehlerhafte Versionen in die Produktionsumgebung gelangen. Darüber hinaus bietet AWS als Cloud-Infrastruktur die nötige Skalierbarkeit und Flexibilität für Staging- sowie Produktionsumgebungen.

Tritt ein Fehler (Bug) auf, etwa in der Staging-Umgebung, können Entwickler diesen in ihrer lokalen Umgebung schnell nachstellen, beheben und über den CI-Prozess erneut testen, um sicherzustellen, dass die Korrektur keine weiteren Probleme verursacht. So wird der Code erst dann in die Produktion übernommen, wenn alle Beteiligten sicher sind, dass er stabil und fehlerfrei ist.

Lokale Entwicklungsumgebungen und Stage Deployment: Die Basis des Entwicklungsprozesses

Schnelles und kosteneffizientes Feedback

Eine lokal verfügbare Laufzeitumgebung bietet entscheidende Vorteile für die Softwareentwicklung. Sie ermöglicht maximale Flexibilität, da Tests und Anpassungen unabhängig von zentralen Systemen durchgeführt werden können. Entwickler können unterschiedliche Kombinationen von Komponenten starten, ohne die Stabilität produktiver Umgebungen zu gefährden oder die Arbeit anderer Teammitglieder zu beeinflussen.

Ein weiterer bedeutender Vorteil ist die Geschwindigkeit, mit der Änderungen sichtbar werden. Da Code direkt auf der lokalen Maschine geschrieben, gebaut und ausgeführt wird, ist der Übergang von einer Codeänderung zu deren Wirkung minimal. Abhängig von der verwendeten Technologie kann diese Verzögerung auf unter eine Sekunde reduziert werden.

Auch aus Management-Perspektive ergeben sich klare Vorteile, insbesondere in zwei Bereichen:

  • Kostenreduktion: Durch Tests auf lokalen Maschinen wird der Bedarf an zusätzlichen Cloud-Testumgebungen reduziert. Häufig reichen eine oder zwei geteilte Testumgebungen aus, wenn der Großteil des explorativen Testens lokal stattfindet.
  • Effiziente Abstimmung: Während der Entwicklung können Features frühzeitig überprüft und an die gewünschten Anforderungen angepasst werden. In der Praxis entstehen häufig Unklarheiten oder Missverständnisse bei der Anforderungsformulierung. Eine stabile lokale Laufzeitumgebung trägt dazu bei, solche Probleme frühzeitig zu identifizieren und kostengünstig zu lösen.

Herausforderungen und Grenzen

Der Einsatz einer lokalen Laufzeitumgebung als erste Testinstanz bietet viele Vorteile, erfordert jedoch eine durchdachte Umsetzung, um typische Fallstricke zu vermeiden. Zu den häufigsten Herausforderungen gehören:

1. Komplexe Einrichtung

Mit wachsender Softwarearchitektur steigt die Anzahl der benötigten Komponenten – etwa Datenbanken, Microservices oder Load-Balancer. Eine manuelle Einrichtung reduziert die Produktivität und führt zu inkonsistenten Konfigurationen zwischen Entwicklern. Eine standardisierte und automatisierte Bereitstellung ist daher essenziell.

2. Unrealistische Ersatzkomponenten

Nicht alle Cloud-spezifischen Dienste lassen sich lokal realistisch nachbilden. Beispielsweise erfordert eine Software, die AWS-KMS für Verschlüsselung nutzt, eine alternative Implementierung für lokale Tests. Abweichungen zwischen lokalen und produktiven Umgebungen bergen jedoch das Risiko unerwarteter Fehler, die schwer zu reproduzieren und beheben sind.

3. Lokal-spezifischer Code

Falls sich die lokale Umgebung stark von der produktiven Umgebung unterscheidet, müssen Anwendungen diese Unterschiede durch spezielle Code-Weichen kompensieren. Solche Anpassungen erhöhen die Komplexität und erschweren die Wartung.

4. Ersatz für automatisierte Tests

Eine lokale Laufzeitumgebung kann explorative Tests erleichtern, ersetzt jedoch keine automatisierten Tests. Ohne eine solide Teststrategie ist es kaum möglich, sicherzustellen, dass bestehende Funktionen bei jeder Codeänderung weiterhin korrekt arbeiten.

Bewährte Methoden für eine effiziente lokale Umgebung

Basierend auf unserer Projekterfahrung haben sich folgende Vorgehensweisen als besonders effektiv erwiesen:

Zentrale Verwaltung der Konfiguration mit Docker-Compose

Die Konfiguration der lokalen Umgebung sollte in einem separaten Repository verwaltet werden, das von den verschiedenen Microservices getrennt ist. Docker-Compose bietet sich als Lösung an, insbesondere wenn alle Microservices containerisiert sind. Externe Dienste wie Datenbanken oder Message-Queues, die ebenfalls als Container betrieben werden, können in das Docker-Compose Setup integriert werden. Wenn sich die Anzahl der Dienste erhöht, kann es sinnvoll sein, getrennte Docker-Compose-Dateien für verschiedene Systemteile zu verwenden, sodass einzelne Teile unabhängig hoch- und runtergefahren werden können – am besten entsprechend den Kontexten aus dem Domain Driven Design. Tools wie Tilt oder Portainer können genutzt werden, um die Verwaltung der Umgebung weiter zu vereinfachen.

Automatisiertes Starten und Stoppen der Umgebung

Die gesamte Umgebung sollte mit einem einzigen Befehl gestartet werden können, wenn das Repository für die lokale Umgebung vorhanden ist. Der ideale Befehl hierfür ist docker-compose up. Dabei werden die gebauten Container aus der Projekt-Registry und die öffentlichen Images aus Docker-Hub geladen, und die gesamte Konfiguration erfolgt über Docker-Compose. Diese Vorgehensweise sorgt dafür, dass neue Entwickler die Umgebung schnell und einfach einrichten können und verhindert den „Works-on-my-machine“-Effekt, da sich alle Teammitglieder auf die gleiche, stets aktuelle Konfiguration verlassen können.

Minimierung der Unterschiede zwischen Cloud- und lokaler Umgebung

So weit wie möglich sollte jeder Microservice so konzipiert sein, dass er nicht erkennt, ob er lokal oder in der Cloud läuft. Dazu empfiehlt es sich, Umgebungsvariablen zu verwenden. Im Spring-Boot-Umfeld können beispielsweise Werte für Application-Properties aus Umgebungsvariablen geladen werden, sodass das gleiche Profil sowohl für die Cloud- als auch für die lokale Umgebung genutzt werden kann. Beim Hochfahren werden dann einfach unterschiedliche Umgebungsvariablen geladen, die das Verhalten der Umgebung anpassen, ohne dass der Code geändert werden muss.

Einfache Aktualisierung der Abhängigkeiten

Bei mehreren Entwicklern und Teams, die an einem gemeinsamen Produkt arbeiten, verändert sich der Stand der Software schnell. Daher ist es entscheidend, dass es für alle Entwickler einfach ist, die aktuellste Version zu erhalten. Der Wert des Testens in einer Umgebung sinkt, wenn diese nicht dem neuesten Stand entspricht. Um dies zu gewährleisten, sollten Befehle wie git pull und docker-compose pull verwendet werden (eventuell in einem gemeinsamen Skript zusammengefasst), sodass die Aktualisierung des Stands zur Routine wird und jeder Entwickler stets mit der neuesten Version arbeitet.

Schnelle Integration von Codeänderungen

Auf der Ebene des Microservices, für den ein Feature entwickelt wird, ist es wichtig, dass Änderungen schnell und einfach in die lokale Umgebung integriert werden können. Eine gängige Methode hierfür ist, über das Build-Skript (z. B. mvn clean package oder yarn build) das Artefakt zu bauen und Docker-Volumes zu verwenden, um dieses Artefakt im Container zu ersetzen, ohne den gesamten Container neu zu bauen. Ein Neustart des Containers reicht dann aus, um die Änderungen wirksam zu machen.

Persistente Datenhaltung mit einfachem Reset-Mechanismus

Um die Konsistenz der Tests zu gewährleisten, benötigt die lokale Umgebung eine stabile und glaubwürdige Datenbasis. Daten sind ein wesentlicher Bestandteil vieler Softwareprodukte, und ohne sie kann die Software kaum realistisch getestet werden. Eine gängige Lösung ist die Verwendung von Docker-Volumes und Fixtures. Fixtures liefern vorgefertigte Stamm- und Nutzungsdaten, die beim Hochfahren der Umgebung in die Datenbanken eingespielt werden. Docker-Volumes stellen sicher, dass diese Daten auch bei mehreren Durchläufen der Tests persistent bleiben. Ob die Fixtures für jeden Microservice separat verwaltet oder zentral in der Konfiguration der lokalen Umgebung gesteuert werden, hängt vom Anwendungsfall ab.

Ersatzlösungen für Cloud-Komponenten

Cloud-spezifische Komponenten stellen eine der größten Herausforderungen dar, wenn es darum geht, sie lokal zu ersetzen. Tools wie LocalStack bieten die Möglichkeit, gängige Cloud-Dienste lokal zu simulieren. Dieses Framework stellt in einem Container eine Vielzahl von Cloud-Services zur Verfügung, die es ermöglichen, lokal mit einem Cloud-Ersatz zu arbeiten. Sollte ein benötigter Service nicht vorhanden sein, gibt es grundsätzlich zwei Optionen: Wenn das Interface des Services einfach genug ist, kann eine manuelle Implementierung für die lokale Umgebung erstellt werden. Andernfalls kann die lokale Umgebung so konzipiert werden, dass sie mit der echten Cloud-Komponente interagiert, sodass die Cloud-Kosten gering bleiben und das System trotzdem getestet werden kann.

Fazit

Eine gut durchdachte lokale Entwicklungsumgebung ermöglicht es Teams, schnell und risikofrei an Softwarekomponenten zu arbeiten. Sie reduziert Feedback-Zyklen, fördert innovative Lösungsansätze und hilft dabei, potenzielle Probleme frühzeitig zu erkennen. Wenn die Herausforderungen bekannt sind und bewährte Strategien angewendet werden, kann eine lokale Laufzeitumgebung einen erheblichen Beitrag zur Effizienz und Qualität in agilen Softwareprojekten leisten.