Quantcast
Channel: Agilität – codecentric AG Blog
Viewing all 129 articles
Browse latest View live

Fail Fast mit dem Staging Properties Maven Plugin

$
0
0

Für Mule-Applikationen gilt das gleiche wie für Webanwendungen. Sie durchlaufen in der Regel mehrere Deployment Stages bis sie auf dem Produktivsystem angelangt sind.
Etabliert haben sich dabei Stages wie zum Beispiel Dev, Test, Pre-Prod und Prod. Manchmal werden noch zusätzliche Umgebungen eingeführt, um das Risiko eines Fehlers auf dem Produktivsystem noch weiter zu minimieren.

Das Artefakt wird bei einem solchen Stage Durchlauf ein einziges mal vorab erstellt und beginnend mit der Dev-Umgebung auf allen Stages nacheinander deployed. Ein Artefakt wird allerdings erst eine Stage weitergereicht, wenn es das Deployment inklusive Tests auf der Umgebung bestanden hat. Im Falle von fehlgeschlagenen Tests oder Deployments, wird das Artefakt nicht auf die nächste Stufe gebracht.

Von Stage zu Stage wird die Umgebung immer ähnlicher zum Produktivsystem. Während auf der Dev-Umgebung beispielsweise noch mit Mocks und In-Memory-Datenbanken gearbeitet werden könnte, führen auf der Test Stage bereits Fremdsysteme Tests gegen die Applikation aus.

Properties-Dateien

Da sich die Einflussgrößen, wie zum Beispiel Fremdsysteme anstelle von Mocks zu verwenden, von Stage zu Stage unterscheiden, ändern sich dadurch auch Konfigurationen wie die URLs und Ports zu den Systemen. Während auf der Entwicklerumgebung noch auf dem localhost gearbeitet wird, werden auf der Test Umgebung andere Testsysteme eingebunden. Andere umgebungsabhängige Einstellungen sind z.B. User und Passwörter zum Zugriff auf Datenbanken oder APIs.

Solche Konfigurationen lassen sich in Mule in Properties auslagern, sogenannte „Property Placeholder“ (https://docs.mulesoft.com/mule-user-guide/v/3.8/configuring-properties), die Mule aus Spring übernommen hat. Diese Properties lassen sich wiederum in Files zusammenfassen, die üblicherweise die Endung „.properties“ haben. Für verschlüsselte Property-Files bietet Anypoint Enterprise Security zudem die Credentials Vault an, verschlüsselte Property-Files, die sich über einen speziellen Mechanismus laden lassen (https://docs.mulesoft.com/mule-user-guide/v/3.8/mule-credentials-vault). Ein Pattern, um umgebungsabhängige Einstellungen zu verwalten ist, ein (oder mehrere) Property-Files je Umgebung zu definieren, die die Verbindungsinformationen zu anderen Systemen, Datenbanken, Message Brokers oder auch Security Einstellungen beinhalten. Hier ein Beispiel für eine Mule Applikation, die auf den vier Umgebungen Dev, Test, Pre-Prod und Prod deployed wird:

staging-properties

Das Artefakt bleibt wie bereits erwähnt auf allen Stages identisch, folglich bleibt auch die Anzahl der Einträge in den Properties identisch. Schließlich beinhaltet das Artefakt die gleiche Anzahl an Mule flows mit Verbindungen zu anderen Systemen.

Zur Entwicklungszeit muss somit also bereits an alle folgenden Stages gedacht und die Properties-Dateien mit Werten versehen werden. Dabei kann es schnell passieren, dass Einträge vergessen werden. In Mule existiert leider kein Mechanismus, der die Properties-Dateien prüft und auf fehlerhafte oder fehlende Einträge hinweist. So etwas fällt dann im schlimmsten Fall erst beim Deployment auf die jeweilige Stage auf. Je später es auffällt, desto teurer wird die Änderung. Besonders wenn die Deployments nicht mehr in der Hand der Entwickler liegen und Fremdsysteme ab einer bestimmten Stage auch noch (manuell) gegen die Applikation testen. Grundsätzlich gilt, je mehr Leute beteiligt oder betroffen sind, desto teurer wird es.

Maven Plugin to the rescue

Um das zu verhindern haben wir ein Maven Plugin entwickelt, das die Properties-Dateien schon zur Entwicklungszeit prüft und den Maven Build abbricht, sobald die Properties-Dateien nicht konsistent zueinander sind. Wir verwenden das Plugin derzeit für unsere Mule Projekte. Es kann aber z.B. auch in Spring Projekten verwendet werden. Das Konzept der properties gibt es dort auch.

Das Plugin befindet sich auf GitHub und steht unter der Apache-Lizenz. Derzeit steht es in der Version 1.0.2 in Maven Central für jeden zur Verfügung.

Um das Plugin zu verwenden, muss es als plugin unter build -> plugins zur pom.xml hinzugefügt werden.

<build>
  <plugins>
    ...
    <plugin>
      <groupId>de.codecentric</groupId>
      <artifactId>check-staging-properties-maven-plugin</artifactId>
      <version>1.0.2</version>
      <executions>
        <execution>
          <phase>verify</phase>
          <goals>
            <goal>check</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <directory>src/main/resources</directory>
        <groups>
          <group>credentials-(.*).\.properties</group>
          <group>settings-(.*).\.properties</group>
      </groups>
      </configuration>
    </plugin>
    ...
  </plugins>
</build>

Danach ist das Plugin Bestandteil des Builds und prüft, ob die properties konsistent zueinander sind. Genauer gesagt prüft es, ob:

  1. die Anzahl der keys in allen properties übereinstimmt.
  2. die keys identisch sind
  3. zu allen keys auch values vorhanden sind.

In dem gezeigten Beispiel ist das Plugin an die Verify-Phase gebunden. Theoretisch kann das Plugin auch an eine frühere Phase gebunden werden.
Jede Konfiguration ist mit einem Standardwert versehen. Sofern sich die properties in src/main/resources befinden, kann die explizite Angabe des directory also weggelassen werden.

Für die Angabe der groups gilt etwas anderes. Werden sie weggelassen, so werden alle Properties betrachtet und miteinander verglichen. Durch die Angabe von groups in Form von regulären Ausdrücken können Teilmengen gebildet werden, die von dem Plugin separat untersucht werden. Hilfreich ist das bei mehreren verschiedenen Properties. Properties, die mit credentials zu tun haben sollen beispielsweise nicht mit settings properties verglichen werden. Durch das grouping Feature wird das verhindert.

Fazit

Wir haben das Plugin selbst in mehreren unserer Mule-Projekte im Einsatz und können mit dem derzeitigen Feature Set alle unsere Anforderungen abdecken. Falls ihr allerdings Anregungen und Wünschen zu neuen oder bestehenden Features habt, würden wir uns sehr über einen Issue auf GitHub oder einen Kommentar unter diesem Blogpost freuen. Ansonsten wünschen wir viel Spaß mit dem Plugin! 🙂

The post Fail Fast mit dem Staging Properties Maven Plugin appeared first on codecentric AG Blog.


Pull-Requests mit Docker deployen

$
0
0

Die Git-Repositorys in meinem aktuellen Projekt sind auf Bitbucket Cloud gehostet. Änderungen am Code werden nur über Pull-Requests in die Code-Basis eingepflegt. Jenkins baut die Pull-Requests und vergibt entsprechend sein Approval, wenn der Build grün ist. Außerdem wird noch von mindestens einem Teammitglied ein Code-Review durchgeführt. Ein Code-Review erfordert zwar grundsätzlich nicht, dass der Reviewer den Code baut und die Anwendung lokal deployt und testet, aber manchmal möchte man sich das Ergebnis der Änderungen doch anschauen, gerade wenn z. B. CSS/HTML angepasst wurde. Ein visueller Test kann hier helfen, die Änderungen nachzuvollziehen und zu verifizieren.

Um es dem Reviewer möglichst einfach zu machen, sollte ein Weg gefunden werden, einen Pull-Request per Knopfdruck testbar zu machen. Die Anwendung wurde erst kürzlich auf Spring Boot migriert. Momentan bauen wir noch eine War-Datei, die auf einem Tomcat deployt wird. Die War-Datei lässt sich aber auch direkt mit dem embeddeten Tomcat ausführen und damit sehr einfach in ein Docker-Image verpacken.

Als Datenbank kommt MongoDB zum Einsatz. Für die lokale Entwicklung bauen wir dafür ebenfalls ein Docker-Image. Das Besondere daran ist, dass dieses Image bereits Daten enthält. Die Natur unserer Anwendung macht es nötig, dass immer aktuelle Daten in der Datenbank sind. Deshalb gibt es einen Job, der nächtlich Testdaten für die Integrationsinstanz der MongoDB generiert. Jenkins baut nun ebenfalls nächtlich ein Docker-Image für die MongoDB. Dabei wird ein Dump von der Integrationsinstanz gezogen, der dann ins Docker-Image importiert wird. Das Image wird in die Docker-Registry gepusht. Morgens kann man sich dann als Entwickler ein frisches Image pullen.

Unser Jenkins läuft ebenfalls unter Docker, ein Container für den Master und einer für den Slave, der alles baut. Der Docker-Socket des Hosts ist dabei in den Slave gemountet. Wenn nun Jenkins einen Pull-Request baut, erstellt er gleich auch ein Docker-Image davon, das mit der Nummer des Pull-Requests getaggt wird. Über das Build-Pipeline-Plugin wird es nun ermöglicht, einen Pull-Request und dazu eine frische MongoDB-Instanz auf dem Jenkins-Host zu deployen.

PR Pipeline

Der Job zum Bauen des Pull-Requests hat einen manuellen Downstream-Job (Teil des Build-Pipeline-Plugins), der die Anwendung samt Datenbank deployt.

postbuild-1

Ein Pythonskript erzeugt dazu per Docker ein Netzwerk und startet die Container.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from subprocess import Popen, STDOUT, PIPE


def docker(*arguments):
    cmdline = ['docker']
    cmdline.extend(arguments)

    print()
    print(' '.join(arg for arg in cmdline))

    proc = Popen(cmdline, stdout=PIPE, stderr=STDOUT)
    output = []
    while True:
        line = proc.stdout.readline()
        if not line:
            break

        line = line.rstrip()
        print('docker> %s' % line)
        output.append(line)

    proc.wait()
    return output


def start_myproject():
    print('Starting MyProject: %s' % version)

    docker('network', 'create', '-d', 'bridge', network_name)

    docker('run', '-d', '--name', mongo, '--network', network_name, '--network-alias', mongo, '-P', 'myrepo/mongo')

    docker('run', '-d', '--name', myproject, '--network', network_name, '-P', 'myrepo/myproject:%s' % version,
           '--spring.profiles.active=dev', '--database.hosts=%s' % mongo)

    docker('port', mongo)
    docker('port', myproject)


def destroy_myproject():
    print('Destroying MyProject: %s' % version)

    docker('stop', myproject)
    docker('rm', myproject)

    docker('stop', mongo)
    docker('rm', mongo)

    docker('network', 'rm', network_name)


args_parser = ArgumentParser(description='Manages MyProject/Docker dev deployments')
sub_parsers = args_parser.add_subparsers()

start_parser = sub_parsers.add_parser('start', help='Start MyProject and Mongo')
start_parser.add_argument('--version', '-v', required=True, help='The MyProject version to start')
start_parser.set_defaults(func=start_myproject)

destroy_parser = sub_parsers.add_parser('destroy', help='Destroy MyProject and Mongo')
destroy_parser.add_argument('--version', '-v', required=True, help='The MyProject version to destroy')
destroy_parser.set_defaults(func=destroy_myproject)

args = args_parser.parse_args()

version = args.version
network_name = version
mongo = 'mongo_%s' % version
myproject = 'myproject_%s' % version

args.func()

shell-start

Der Port für die Anwendung wird von Docker vergeben. Die URL findet man dann im Log des Jobs, an das man über den Build-Pipeline-View schnell rankommt. Der Job erhält als Parameter die Nummer des Pull-Requests und weiß dadurch, welches Image zu starten ist.

Der Job zum Deployen hat wiederum einen manuellen Downstream-Job, mit dem sich das Deployment wieder zerstören lässt.

postbuild-2

shell-destroy

Damit man sich die Logs der Anwendung anschauen oder auch mal eine Shell auf dem Container öffnen kann, ohne sich per SSH auf den Jenkins-Host zu verbinden, haben wir noch Shipyard installiert. Damit bekommt man einen Überblick über alle laufenden Docker-Container und kann ggf. aufräumen, falls mal ein Deployment vergessen wurde.

Wieso kein Pipeline-Job?

Leider ist das Bitbucket Pull Request Builder Plugin nicht mit den neuen Pipeline-Jobs des Jenkins kompatibel. Es gibt dazu ein Ticket, in dem auf das Bitbucket Branch Source Plugin verwiesen wird, das in unserem Fall aber nicht in Betracht kommt, da es mit Webhooks arbeitet. Für den master-Build verwenden wir allerdings bereits einen Pipeline-Job.

 

The post Pull-Requests mit Docker deployen appeared first on codecentric AG Blog.

Agile2Go mit Mathe-Genies

$
0
0

Mit den Teams „Darkness“, „AgiLeGo“ und „Letzte Reihe“ feierte das diesjährige Agile Software Factory BootCamp sein kleines fünfjähriges Jubiläum. Zwischen dem 07.03. und dem 15.03.2017 stellten sich 15 Masterstudenten der Fachhochschule Aachen (Campus Jülich) im Studiengang Technomathematik, der Herausforderung, ein Projekt mit agilen Praktiken und modernen Software-Entwicklungstools eigenständig durchzuführen.

In einem vorgelagerten viertägigen Theorieblock, wurden hochschulseitig Grundlagen zu Scrum, verteilter Versionsverwaltung, Buildmanagement, Continuous Integration,  emergenter Architekturen, Webanwendungen mit dem Spring Framework und Clean Code vermittelt, um den Einstieg in die praktische Phase schneller bewerkstelligen zu können. Entwickelt und durchgeführt wurde diese Einheit von Prof. Dr. Bodo Kraft und einem seiner Doktoranden Marc Schreiber.

Die anschließende dreitägige Praxisphase greift diese Grundlagen auf, ergänzt und vertieft sie mit Praxiswissen und hilfreichen Tipps aus dem Entwickleralltag. Dabei entwickeln die Studenten über fünf Sprints hinweg eine kleine Beispiel-Webanwendung, die komplett gebaut und mit Hilfe einer CI-Pipeline in Produktion released wird. Beteiligt von Seiten codecentric waren dieses Mal die Kollegen Andreas Houben, René Mjartan,  Simon Norra und Michael Treiling. Die Kollegen unterstützten jeweils ein Team als Product Owner und Coach.

Besonders zu erwähnen ist, dass bei diesem Durchlauf die Studierenden die vermittelten Techniken und Werkzeuge sehr schnell adaptiert haben und bereits von Beginn an User-Stories produktiv setzen konnten.  Auch die Selbstorganisation im Team und die Umsetzung von Verbesserung auf Grund der zu jedem Sprintende im Team durchgeführten Retrospektiven hat bemerkenswert gut geklappt, so dass der aus jedem Team rekrutierte Scrum Master eigentlich wenig aktiv werden brauchte.

Gewonnen haben alle. Die Studenten erhielten die Möglichkeit, Softwareentwicklung state-of-the-art kennen zu lernen, Praxis KnowHow aufzubauen und ihre Teamskills zu verbessern. Die FH erfährt eine Aufwertung des Studiengangs und ein Alleinstellungsmerkmal im Wettbewerb mit anderen Hochschulen.

Die Veranstaltung hat uns viel Spaß gemacht und wir freuen uns auf die nächste Runde in 2018…

O-Töne aus der Evaluation der Veranstaltung:

  • „Interessante, praxisnahe VL mit hohem Lernerfolg“
  • „Techniken und Werkzeuge für die agile SW Entwicklung werden praxisnah vermittelt, wobei die Veranstaltung einen hohen Praxisanteil hat“
  • „Agile Arbeit mit Scrum und hilfreichen Tools in der Theorie und der Praxis“
  • „…Es wurden Interessante Themen behandelt, die auch Relevanz im Arbeitsleben haben. Sehr gute Hilfe bei den Übungen durch den Dozenten und Mitarbeiter“
  • „Gut strukturiert, guter Umgang, hoher Lernerfolg, viel Teamarbeit. Eine der besten VL bisher.“
ASF Bootcamp 2017

The post Agile2Go mit Mathe-Genies appeared first on codecentric AG Blog.

Softwarefehler mit IT Support Teams managen – Teil 1

$
0
0

Welcher IT-Dienstleister kann von sich sagen, eine fehlerfreie Software-Anwendung zu betreiben? Wir alle wissen, dass es trotz intensivster Bemühungen in der Qualitätssicherung unmöglich ist, komplexe Software fehlerfrei zu betreiben. Wir wissen aber auch, dass durch Störungen in Form einer Downtime in unternehmenskritischen Anwendungen in wenigen Minuten mehrere tausend Euro Schaden entstehen können. Umso wichtiger ist es, dass Störungen im laufenden Betrieb in kurzer Zeit kanalisiert, priorisiert und behoben werden.
Doch Kunden erwarten heute noch deutlich mehr.
Ein guter Support gibt Kunden nicht nur eine schnelle und klare Rückmeldung über die eingereichten Störungsmeldungen, sondern informiert sie auch proaktiv, wenn die Probleme gelöst worden sind (Stichwort: Customer Experience).

In diesem ersten Teil der Blogserie werde ich nach einleitender Begriffserklärung über die Notwendigkeit und Aufgaben eines IT Support Teams schreiben. Im zweiten Teil geht es um einen Lösungsansatz für die Schnittstelle des Support Teams zum 3rd-Level Support am Beispiel von Softwareentwicklungs-Teams.

Was ist eine IT Störung?

Hier eine Definition aus Wikipedia:

Unter einer Störung versteht man nach
IT Infrastructure Library (ITIL):
„Ein Ereignis, das nicht zum standardmäßigen Betrieb eines Services
gehört und das tatsächlich oder potenziell eine Unterbrechung dieses
Services oder eine Minderung der vereinbarten Qualität verursacht.“

Störungen in der IT werden in der ITIL-Sprache auch Incidents genannt. Der Begriff “IT-Service” kommt aus der ITIL-Sprache und kann zum Beispiel als Software-Anwendung verstanden werden.

Ein Incident kann an unterschiedlichsten Stellen in der IT auftreten zum Beispiel:

  • bei einem Netzwerkausfall
  • in einem Online Report mit falschen Zahlen
  • durch schlechte Anwendungsperformance

Je umfangreicher, volatiler und komplexer der IT-Service ist, umso höher wird auch die Anzahl der täglich gemeldeten Incidents sein. Der IT-Service hat die Aufgabe, einen Mehrwert für den Kunden zu erbringen. Jede Störung dieses IT-Services bewirkt also erstmal eine Verschlechterung des Mehrwertes.

Zur effizienten Störungsbehebung beschreibt der Best Practice Ansatz von ITIL den Incidentmanagement-Prozess, wie in dem folgenden Aktivitätsdiagramm zu erkennen ist.

Incidentmanagement

Die Organisation eines IT-Supports

Incidents werden mit Hilfe von Trouble Tickets dokumentiert. Für die Entgegennahme und Überwachung der Tickets ist ein Support Team zuständig. Support Teams werden auch oft Help Desk oder Service Desk genannt.

Der IT-Support wird häufig in 1st-Level, 2nd-Level und 3rd-Level Support unterteilt. Der 1st-Level ist der erste Anlaufpunkt für den Kunden zur Erfassung aller Vorfälle. Der 2nd-Level ist in der Regel im IT-Betrieb angesiedelt und beseitigt die Störungen, die durch den 1st-Level nicht behoben werden konnten. Der 2nd-Level ist also für die technisch anspruchsvollen Supportanfragen zuständig. Mit dem 3rd-Level ist der Hersteller der Anwendung gemeint, welcher zum Beispiel der externe Anbieter oder das In-House Software-Entwicklungs-Team sein kann. Der 3rd-Level ist also die letzte “Eskalationsstufe” der Supportanfrage und wird involviert, wenn die vorhergehenden Stufen keine Lösung herbeiführen konnten.

Wer braucht ein Support Team?

Die Hauptgründe für ein Unternehmen ein Support Team einzurichten sind sicherlich die Möglichkeit einer zentralen Anlaufstelle für den Kunden, Effizienz und Kostenoptimierung. Bei einem Volumen von mehreren 100 Tickets in der Woche wird es für ein Software-Entwicklungs- Team nicht mehr wirtschaftlich sein alle Fragen selbst zu beantworten. Es ist kostengünstiger, redundante und einfach zu lösende Anfragen durch den Support bearbeiten zu lassen. Der geschulte Support ist darauf fokussiert, kundenorientiert und zügig zu agieren. Weiterhin lassen störungsbedingte Unterbrechungen die Produktivität der Entwickler rapide sinken. Eine interessante Statistik zu Unterbrechungen am Arbeitsplatz ist hier zu finden.

Es gibt allerdings noch weitere Gründe für ein Support Team, die sich klarer herausstellen lassen. Dazu betrachten wir die Aufgaben eines Support Teams näher.

Aufgaben eines Support Teams

  • Details der Störung herausfinden und schnelle Rückmeldung an den Kunden – innerhalb des Service Level Agreement (SLA)
  • Abgleich mit bekannten Fehlern („known Errors“)
  • Priorisierung und Behebung der Störungen innerhalb des vorgegebenen SLA
  • hohe Erstlösungsquote erzielen im Zweifel durch Workarounds
  • Verkürzung der Mean Time To Repair (MTTR) in enger Zusammenarbeit mit dem 3rd-Level
  • Dokumentation bekannter Lösungswege oder Workarounds

Nicht nur, dass diese vielfältigen Tätigkeiten eine Spezialisierung durch ein Support Team sinnvoll werden lassen. Derartige Aufgaben sind zum Teil sogar gegenläufig zu den Aufgaben eines Entwicklungs-Teams. Während ein Software-Entwickler versucht die Ursache der Störung zu finden und zu beheben, hat der Support zum obersten Ziel die Störung so schnell es geht zu lösen – im Zweifel durch einen Workaround. Über einen längeren Zeitraum würden somit immer mehr Workarounds aufgebaut werden, die den gleichen Effekt wie technische Schulden in Software-Projekten haben.

Es geht auch nicht immer einzig und allein um Geschwindigkeit. Das Support Umfeld ist sehr dynamisch:

  • Prioritäten von Anfragen können sich über den Lebenszyklus ändern.
  • Abhängigkeiten zwischen Störungen entstehen und lösen sich auf.
  • Zuständigkeiten ändern sich.

Insbesondere bei sehr vielen Anfragen gilt es den Überblick zu halten, also keine Anfragen zu übersehen sowie fachlich korrekt und freundlich zu antworten.

Was spricht gegen ein Support Team?

Es gibt neben den genannten Vorteilen für eine Organisationsform mit Support Teams selbstverständlich auch Nachteile.
Jede zusätzliche geschaffene Kommunikationsschnittstelle birgt die Gefahr von Informationsverlust, redundanten Tätigkeiten, Reibungspotential oder Zeitverlust.

Welche detaillierten Herausforderungen die Schnittstelle zwischen Support Teams und Entwicklungs-Teams birgt, welche Lösungsansätze es gibt und inwiefern DevOps die Probleme löst, werde ich im nächsten Teil dieser Blogreihe behandeln.

 

The post Softwarefehler mit IT Support Teams managen – Teil 1 appeared first on codecentric AG Blog.

Agiles Roadmapping mit Produkt-Routen

$
0
0

„Routenplaner (Streckenplaner, Wegplaner, von französisch: route = Weg) sind Computerprogramme, mit deren Hilfe ein Weg zwischen einem Start- und einem Zielort gefunden werden kann. Meistens können auch ein oder mehrere Orte dazwischen („via“) angegeben werden. Es können meistens Wünsche angegeben werden, ob die schnellste, die kürzeste, die wirtschaftlichste (ökonomischste) oder manchmal auch die schönste Route gesucht werden soll.“ (Wikipedia)

Das Bedürfnis nach (Planungs-)Sicherheit ist ein häufig auftretendes Phänomen bei Softwareprojekten. Erst an zweiter Stelle steht das Bedürfnis, etwas Nützliches und Relevantes liefern zu können. Das ist zunächst verwirrend: Sind agile Methoden nicht genau deswegen überhaupt erst eingeführt worden? Weil es eben keine Sicherheit gibt und wir uns daher lieber darauf konzentrieren, sicherzustellen, dass wir immer das Nützlichste und Relevanteste entwickeln?

Wenn es diese Sicherheit gäbe und wir genau vorhersagen könnten, wann wir welchen Umfang liefern können, wären agile Entwicklungsmethoden überflüssig. Warum sollte man also annehmen, man könne die Komplexität von Softwareprojekten planerisch in den Griff bekommen – speziell, wenn alle Studien und Fallbeispiele das Gegenteil beweisen?

Häufig kommen wir in Projekte, in denen die Planungsphase bereits abgeschlossen ist und wir das Ziel hinnehmen müssen, wie es ist. Leider sind diese Pläne meist schlecht. Die Tatsache, dass der Plan bereits geschmiedet ist, sollte aber keine Entschuldigung für uns sein, sie nicht in Frage zu stellen (auch wenn der Kunde das vielleicht lieber hätte). Wenn wir nicht hinterfragen, welche Ziele und Werte hinter dem Plan stehen, was das Ergebnis sein soll, wie eine Veränderung der Verhaltensweise der Kunden (und manchmal auch des Unternehmens) herbeigeführt werden soll, wenn wir nicht lineare Backlogs und unmessbare User Stories kritisieren, dann werden wir unserer Rolle als Berater nicht gerecht. Vielleicht gibt es ja die Chance, dass der Kunde versteht, worum es bei Agilität geht, statt in eine weitere Kostenfalle zu tappen.

Wie können wir Dinge ändern, die ganz offensichtlich schlecht sind oder nachweislich unpassend oder gar falsch, wenn wir nicht aktiv dagegen argumentieren und dafür andere, bessere Wege aufzeigen?

Wir erschließen bessere Wege, Software zu entwickeln, indem wir es selbst tun und anderen dabei helfen. (Agile Manifesto)

Wenn Scheitern zum Standard wird

Man könnte jetzt dem Kunden erklären, dass er einige „schlechte Angewohnheiten“ hat und wir ihm helfen können, diese zu überwinden. Dummerweise hören Kunden nur ungern von externen Beratern oder Entwicklungsteams, dass alles, was sie die letzten 30 Jahre gemacht haben, vollkommen falsch war und dass sie endlich Transparenz und Vertrauen und andere agile Werte fördern sollten. Man darf auch nicht vergessen, dass diese Unternehmen 30 Jahre lang erfolgreich im Geschäft sind und immerhin den Mut haben, sich trotz dieser offensichtlichen Reife Hilfe von außen zu holen!

Trotzdem ist es besser, die Tatsache, dass es keine Sicherheit gibt, zu akzeptieren statt sie zu verleugnen und hinterher überrascht zu sein, wenn das Projekt fehlschlägt. Aber auch wenn es keine Sicherheit gibt, das Bedürfnis nach Sicherheit existiert in jedem Fall. So kommt es, dass in einigen Firmen schon so lange Projektfehlschläge (in Bezug auf den ursprünglichen Plan) passieren, dass jeder es vorher weiß, obwohl es keiner auszusprechen wagt.

Am Ende ist in solchen Firmen keiner überrascht, weil ja jeder damit gerechnet hat, dass das Projekt fehlschlägt und weil es ein „ganz normaler“ Prozess ist, der keinen Grund zur Beunruhigung gibt. Man ist es eben gewohnt, „betrogen“ zu werden. Manchmal wird dies auch ganz gezielt zur Diskreditierung von Personen eingesetzt. Dann rollt eben am Ende des Projektes ein Kopf, und man setzt einen neuen Projektleiter ein, den man sowieso viel besser leiden kann als den Querkopf, der das Projekt im Moment leitet.

Der Ausweg: volle Transparenz

Unser Vorschlag für einen Ausweg aus diesem Dilemma ist, dass wir das Akzeptieren des Bedürfnisses unserer Kunden nach Sicherheit über unser eigenes Bedürfnis stellen, ihm den Umgang mit Komplexität beibringen zu wollen – etwa so, wie wir dem agilen Wert folgen, das

Reagieren auf Veränderungen höher zu schätzen als das Befolgen eines Plans.

Wir könnten damit anfangen, ihm die unterschiedlichen Kompromisse, die er bei der einen oder anderen Methode eingehen müsste, so transparent zu machen, dass er mindestens im vollen Bewusstsein der Konsequenzen seine Entscheidung trifft, diesen Weg zu gehen.

Als nächstes könnten wir den Plan des Kunden als eine erste Version einer agilen Planung betrachten und ihm den Unterschied zwischen klassischer und agiler Planung erklären.

General_of_the_Army_Dwight_D._Eisenhower_1947.jpg

„In preparing for battle I have always found that plans are useless, but planning is indispensable.“ (Dwight D. Eisenhower)

publilius-syrus_Pda8A.jpg

„Malum est consilium quod mutari non potest“ – „Schlecht ist ein Plan, der sich nicht ändern lässt.“ (Publilius Syrus, 85-43 B.C., Römischer Mimen-Autor und Ethiker)

Das wird nicht immer ganz einfach sein, denn der Kunde ist es gewohnt, seine Pläne früh zu kommunizieren und sich darauf festzulegen, und die Empfänger dieser Botschaft sind es gewohnt, dass diese sich bis kurz vor Ende des Projektes nicht ändern. Die Botschaft, die Eisenhower, Publilius Syrus und die Verfasser des Agilen Manifests senden, ist aber: Solange der Inhalt des Plans an den Produkt- oder Projektzielen ausgerichtet ist (oder noch besser: am nächsten vielversprechenden Teilziel) und keine plumpe Ansammlung von versprochenen Features, ist es sehr gut, einen Plan zu haben! Den Kunden nach seinen Zielen zu fragen, mögliche Einflüsse seiner Lösung auf die Anwender zu beleuchten und zu ermitteln, wieviel er auf einen Projekterfolg wetten würde, wird uns nicht umbringen. Aber vielleicht erzeugen diese Fragen neue Erkenntnisse und Änderungen in der Denkweise.

Als nächstes versuchen wir mal, den Plan auf einen Zeitstrahl zu projizieren. Das ist der Kunde gewohnt, und es gibt ihm ein Gefühl von Sicherheit. Natürlich sollte der Plan keine festen Datumsangaben haben, aber vielleicht Produktinkremente, Quartale, Releases oder was auch immer für diesen Kunden sinnvoll ist.

Aber einen Plan zu haben bedeutet mehr, als nur das Ziel zu kennen und eine vage Vorstellung davon, wie man ihm näher kommt. Es bedeutet auch, ein Bauchgefühl dafür zu haben, ob es eher Monate oder Jahre braucht, um dorthin zu gelangen.

Und dann gilt natürlich: Reagieren auf Veränderung steht über dem Befolgen eines Plans. Mit anderen Worten: Habe einen Plan. Folge ihm nicht blind. Wenn der Plan anpassbar ist, ist alles gut. Wenn du nach zwei Wochen feststellst, dass du auf der falschen Fährte bist, z. B. dass die erstellten Features Schrott sind und keiner sie verwendet, dann ist der Rest des Plans wahrscheinlich auch Schrott und sollte überarbeitet werden. Oder anders herum: Wenn du nach zwei Wochen dein Ziel schon erreicht hast, wie wertvoll ist dann der Rest des Plans noch?

Die große Gefahr, die ein statischer Plan mit sich bringt, ist, dass man ihm weiterhin folgt, ohne Feedback-Loops zu berücksichtigen. Agilität bedeutet, das Richtige zu tun und nicht alles zu tun, was geplant war, mit einem Zeitstrahl und soundso vielen möglicherweise benötigten Features, aber ohne den Wert des Produktes zu erhöhen bzw. überschüssigen Kram zu produzieren.

Ein GPS der Agilität

Ein agiler Roadmapping-Prozess ähnelt daher stark einem modernen Navigationssystem: Das Ziel ist ziemlich fest vorgegeben, und üblicherweise will man so schnell wie möglich dorthin gelangen. Oder auf dem Weg die maxi- male Anzahl an Sehenswürdigkeiten erleben, für den Fall, dass man gerade im Urlaub ist. Wenn das System einen Stau feststellt, wird die Route verändert. Nur die Zeit ver- ändert sich etwas, der Optimierungsalgorithmus („schnellst- mögliche Route“) bleibt erhalten. Und natürlich möchte man Zwischenstopps einlegen (zum Tanken, Frühstücken, Sightseeing), während man schon unterwegs ist.

Zu jeder Zeit kann das Navigationssystem vorhersagen, um welche Zeit welcher Zwischenstopp erreicht wird (und tatsächlich sind die meisten Navigationssysteme erstaunlich präzise in ihren Vorhersagen, das haben sie vielleicht einem agilen Roadmapping-Prozess voraus). Aber es gibt keinerlei Garantie dafür, dass man tatsächlich zu diesem Zeitpunkt ankommt, und es zwingt einen umgekehrt auch nicht, zu einem bestimmten geplanten Zeitpunkt an einem bestimmten geplanten Ort anzuhalten. Weicht man etwas vom Plan ab, kalkuliert das System sofort eine neue Route und neue Zeiten. Ein Stau? Vielleicht ist jetzt der längere Weg die bessere Route für den aktuellen Optimierungsalgorithmus! Entscheidend ist: Das System berechnet immer die beste Route, basierend auf den aktuellsten Informationen, die ihm vorliegen. Manche Systeme gehen sogar so weit, dass sie mehrere alternative Routen vorschlagen und dabei Zusatzinformationen (z. B. Verkehrsdichte, Baustellen, Straßensperren) mit anzeigen, so dass der Anwender gut informiert seine eigene Entscheidung treffen kann, welche Route er für die geeignetste hält (s. Abbildung 1).

FullSizeRender-1.jpg

Abb. 1: Der Anwender kann gut informiert seine eigene Entscheidung treffen, welche Route er für die beste hält.

In manchen Fällen muss man sogar das Ziel neu bewerten: Möglicherweise hat man selbst oder das Navigationssystem festgestellt, dass das Ziel in einer Fußgänger- zone liegt – dann muss die Route zum nächstgelegenen Parkplatz und nicht zum Ziel selbst führen. Oder wenn man zu einem Termin spät dran ist, könnte man sich ab einem gewissen Maß der Verspätung dafür entscheiden, den Termin ausfallen zu lassen und direkt weiter zum nächsten zu fahren.

Mir selbst ist es schon häu g passiert, dass ich auf halber Strecke zu einem Termin im Stau stecken geblieben bin und dann bei der nächsten Gelegenheit von der Autobahn abgefahren und wieder nach Hause gefahren bin, weil sich mein Zeitfenster geschlossen hatte.

Manchmal bekommt man auch neue Informationen während der Fahrt, die einige der geplanten Ziele obso- let erscheinen lassen: Wir waren mal mit der Familie auf einer Besichtigungstour französischer Schlösser und Burgen. Wir hatten uns vier bis fünf Schlösser herausgesucht und eine Route ermittelt, die an allen vorbeiführt. Bei der Besichtigung eines der Schlösser haben wir von einem anderen Touristen eine Empfehlung eines weiteren nahegelegenen Schlosses bekommen, also haben wir ein anderes gestrichen und sind lieber der Empfehlung gefolgt.

Wenn man dieses Beispiel noch weiter abstrahiert, kommt man vielleicht sogar zu der Erkenntnis, dass die eigentliche Optimierungsfunktion eine glückliche Familie ist und bricht die Tour einfach ab und geht in ein nettes Bistro nahe dem Schloss, in dem die Kinder je ein großes Eis bekommen, während es sich die Eltern bei einem Glas guten französischen Rotweins gut gehen lassen.

Zusammenfassung

Auf Basis aller dieser offensichtlichen Parallelen schlagen wir vor, sich eine agile Roadmap wie eine Reiseroute vorzustellen. Zum Schluss ein paar Hinweise, die beim Erstellen einer solchen Roadmap hilfreich sein können:

  • Mache das Ziel explizit und richte deine Route so aus, dass sie dorthin führt
  • Bewerte das Ziel nach einem längeren Zeitraum (z. B. ein Jahr) neu, um zu überprüfen, ob es sich inzwischen bewegt hat
  • Finde heraus, was deine Optimierungsfunktion ist. Mögliche Kandidaten sind z. B. Time-to-Market, Qualität, Unique Selling Point etc.
  • Projiziere deinen Plan auf einen Zeitstrahl. Je größer die Organisation ist, desto längerfristig wird die Planung. Typischerweise sollte die Planung sechs bis zwölf Monate in die Zukunft reichen (abhängig vom Projekt/ Produkttyp und dem Marktsegment, in dem du dich befindest)
  • Mache deine Route leicht zugänglich, visuell ansprechend und leicht zu aktualisieren
  • Sorge dafür, dass deine Route gute Vorhersagen für die nahe Zukunft und (absichtlich) eher vage Vorhersagen für die ferne Zukunft macht
  • Stelle sicher, dass du deine Produkt-Route regelmäßig aktualisierst, typischerweise jeden Monat
  • Bedenke, dass ein Stoppen des Projektes zu jedem Zeitpunkt eine deiner Optionen ist. Setze die „Reise“ nicht nur deshalb fort, weil du sie begonnen hast!

The post Agiles Roadmapping mit Produkt-Routen appeared first on codecentric AG Blog.

Stateless CI-Server mit Concourse

$
0
0

Continuous Integration ist einer der wichtigsten Bestandteile der agilen Software-Entwicklung und in den meisten Teams so selbstverständlich wie Versionskontrolle geworden. Trotz der alten und bewährten Werkzeuge wie Jenkins, Bamboo oder TeamCity, ist es immer noch eine große Herausforderung, die Komplexität einer Continuous-Integration-Umgebung zu beherrschen. Das Entwicklungsteam aus der Software-Schmiede Pivotal hat sich vorgenommen, ein neues CI-System mit einer modernen Architektur und zukunftssicheren Technologien aufzubauen. Was vor drei Jahren mit einem eher unbekannten Open-Source-Projekt startete, ist nun eine reife Technologie mit stabilen Release-Zyklen geworden. In diesem Blog stelle ich die Kernkonzepte und die Architektur von Concourse CI vor.

Warum brauchen wir ein neues CI-System?

Einer der wichtigsten Gründe warum ein neues Werkzeug vorteilhaft sein kann, ist die Unabhängigkeit von alten Anforderungen, die über viele Jahre gewachsen sind und immer noch erfüllt werden müssen. Solche Systeme sind meistens stabil und zuverlässig, haben jedoch die Schwierigkeit, sich an die schnelle technologische Entwicklung anzupassen. Die Komplexität eines Build-Servers hat über die letzten Jahre enorm zugenommen, so dass immer mehr Plugins und Konfigurationen verwaltet werden müssen. Weiterhin besteht oft eine Lücke zwischen den Builds auf einem Entwicklungsrechner und auf einem CI-System. Denn die Konfiguration des CI-Servers muss mit jedem Entwicklungsrechner übereinstimmen. Durch zunehmende Komplexität der Build- und Auslieferungsprozesse hat sich auch der Aufbau der Jobs verändert:  von simplen Build- und Test-Jobs bis zu komplexen und langläufigen Pipelines, die den gesamten Prozess von Compile bis Deployment über mehrere Stages wie Integrationstest, Quality-Gates und Blue/Green-Deployments abdecken. Diese Komplexität hemmt eine schnelle Adaption neuer Technologien in bestehenden CI-Systemen, da es sehr oft umständlich ist alte Strukturen aufzubrechen und etwas Neues einzuführen.

Kernkonzepte von Concourse

In Concourse CI wurden neue Technologien und moderne Architekturen bereits beim Design berücksichtigt, wodurch das Plugin-Management und Konfiguration des CI-Systems vereinfacht wird. Das System basiert auf vier grundlegenden Konzepten: Resources, Tasks, Jobs und Pipelines.

Unter einer Resource versteht man eine Entität, die drei Merkmale erfüllen muss:

  • Eine Resource ist versionierbar.
  • Eine Resource wird aus einem anderen System ausgelesen.
  • Eine Resource wird in ein anderes System geschrieben.

Durch diese Abstraktion können viele verschiedene Resources für das CI-System definiert werden, beispielsweise Git Repository, S3 Bucket, Docker Image, NPM Paket oder sogar die Zeit selbst. Resources werden als Inputs oder Outputs für Tasks und Jobs verwendet. Entscheidend ist, dass die Konfiguration für das Lesen und das Schreiben der Resources nicht innerhalb des CI-Systems definiert wird. Concourse stellt viele Adapter für Resources zur Verfügung und lässt dabei die Freiheit eigene Resource-Adapter zu schreiben.

Ein Task ist eine Ausführung eines bestimmten Build-Skripts. Es entspricht dem bekannten Konzept von Steps innerhalb eines Jobs in Jenkins – mit dem entscheidenen Unterschied, dass alle Tasks immer in einem Docker-Container ausgeführt werden. Dadurch wird sichergestellt, dass alle benötigten Abhängigkeiten und Konfigurationen gekapselt und vom CI-System entkoppelt sind. Das Konzept wurde in ähnlicher Form von meinem Kollegen Tobias Flohre in einem Blog-Artikel diskutiert.

Ein Job besteht aus mehreren Tasks und definierten Inputs und Outputs, welche wiederum Resources sind. Wenn sich die Input-Resources ändern, wird der Job ausgelöst, und es werden neue Output-Resources erstellt. Ein Job innerhalb des CI-Systems ist dadurch stateless. In Concourse ist es gar nicht möglich Abhängigkeiten zum CI-Server innerhalb der Jobs aufzubauen. Dadurch kann ein Job auf einem beliebigen Concourse-System ausgeführt werden und wird exakt gleiche Ergebnisse produzieren.

Resources, Tasks und Jobs lassen sich zu einer Pipeline orchestrieren. Änderungen der Input-Resources lösen bestimmte Jobs aus, die wiederum neue Output-Resources erzeugen und dabei andere Jobs auslösen. Mit dieser Verkettung lassen sich beliebig komplexe Strukturen für Auslieferungsprozesse abbilden, wobei Jobs zusätzlich parallelisiert oder aggregiert werden können.

Eine weitere Stärke von Concourse ist die Benutzeroberfläche, in der die Pipelines, Jobs und Resources minimalistisch dargestellt werden. Aufgrund der zunehmenden Komplexität der Build-Pipelines ist es in anderen Systemen oft schwierig, die wesentliche Information möglichst schnell zu finden. Als Beispiel kann die Pipeline von Concourse selbst betrachtet werden.

Abbildung 1: CI-Pipeline von Concourse CI

Die Übersicht bietet eine gesamte Darstellung der Pipeline auf einen Blick und ermöglicht eine schnelle Navigation zu den Details eines Jobs oder Resources. Die grünen Blöcke zeigen die jeweiligen Jobs und ihre Input- und Output-Resourcen und werden je nach Dauer der Jobs skaliert dargestellt. Mit diesem Konzept wird der Aufbau und der Betrieb der Pipeline offen und präzise kommuniziert. Das Wissen über den Auslieferungsprozess sowohl innerhalb eines Entwicklungsteams als auch zwischen verschiedenen Teams kann besser verteilt werden, ohne sich in den Details zu verlieren.

Architektur

In Concourse haben viele Begriffe einen Bezug zur Luftfahrt, wodurch die Architektur und die Zusammensetzung der einzelnen Komponenten besser veranschaulicht wird. Das System ist in mehrere Module unterteilt: ATC, TSA, Workers und Fly. Die Architektur sieht wie folgt aus:


Abbildung 2: Concourse-CI-Architektur

Air Traffic Control (ATC) ist die zentrale Instanz des Systems und bietet eine Benutzeroberfläche zur Darstellung und eine REST API für das Management der Pipelines und deren Ausführung. Transport Security Administration (TSA) ist eine Schnittstelle zwischen ATC und den Workern, wobei die Worker lediglich registriert und an ATC weiter geleitet werden. Die Worker sind unabhängige und einheitliche Server, die als Container für die Ausführung der Jobs verwendet werden. Sie sind stateless, benötigen keine zusätzliche Konfiguration und registrieren sich am TSA als mögliche Laufzeitumgebung für die Pipeline. Wann, wo und wie ein Worker zum Einsatz kommt, wird von ATC gesteuert. Für das optimale Scheduling der Worker melden diese ihren Zustand periodisch an ATC.

Um die Pipelines innerhalb des ATC zu verwalten wird das CLI-Tool Fly verwendet. In Concourse gibt es keine Möglichkeit, eine Pipeline über die Benutzeroberfläche zu erstellen; alle Konfigurationen müssen mit Fly durchgeführt werden. Was im ersten Moment nach einem fehlendem Feature klingt, ist eine bewusste Designentscheidung. Denn oft sind die Entwickler dazu geneigt den Zustand des CI-Systems manuell in der Benutzeroberfläche zu verändern. Diese Änderungen werden über längeren Zeitraum oft vergessen oder nicht dokumentiert. Mit Fly lassen sich Pipelines ebenfalls lokal ausführen, was die Entwicklung der Pipeline stark vereinfacht und die gleiche Funktionalität auf einem CI-Server garantiert. In weiteren Blog-Artikeln werde ich auf die Architektur und das Pipeline-Management in Concourse detailliert eingehen und mögliche Einsatzszenarien diskutieren.

Fazit

Mit Concourse werden viele alte Probleme eines CI-Servers angegangen und elegant gelöst. Die Jobs werden in Docker-Containern ausgeführt, was den Konfigurationsaufwand des CI-Servers reduziert und die Reproduzierbarkeit der Builds garantiert. Die Abstraktion durch Resources, Tasks und Jobs bietet Spielraum für viele Technologien und Orchestrierung komplexer Build-Prozesse. Entwicklungsteams haben die Autonomie über ihre Pipeline und können das Wissen über den Auslieferungsprozess mit einer aufgeräumten Oberfläche besser verteilen.

Komplexe Konfiguration eines CI-Servers ist oft ein Hindernis für kleine Teams, um mit Continuous Integration zu starten. Ein CI-Server wird oft von mehreren Teams mit verschiedenen Plugins und Umgebungsvariablen überladen – das reduziert die Flexibilität der Entwicklung und erhöht den Wartungsaufwand. Concourse CI versucht dieses Problem durch Abstraktion und Container-Einstatz zu vermeiden. Letztlich muss jedes Team für sich selbst entscheiden, ob der Wechsel zu einem neuen CI-System Mehrwert bringt. In der Regel ist die Technologie allein nicht der entscheidende Faktor für den Erfolg eines Projekts.

The post Stateless CI-Server mit Concourse appeared first on codecentric AG Blog.

JUnit Tests implementieren mit Mockito und PowerMock

$
0
0

Please find an English version of this blog post here.


junit „Braucht die Welt wirklich einen weiteren Artikel über JUnit, Mockito und PowerMock?“ Ich hatte da durchaus so meine Zweifel vor dem Schreiben dieses Artikels. Denn es gibt im Netz wirklich eine Unmenge an Artikeln genau zu diesen Themen. Andererseits bringt jeder Artikel auch seine eigene Sichtweise auf das Themengebiet mit und kann so am Ende – zumindest für ein paar Leser – hoffentlich trotzdem hilfreich sein. Aber genug von diesen philosophischen Betrachtungen und hinein in die Welt der JUnit-Tests und der (Power-)Mock-Objekte.

Was ist überhaupt ein Mock-Objekt?

Dieser Absatz behandelt – in aller Kürze – die grundlegenden Konzepte von Mock-Objekten. Wer schon Erfahrungen in diesem Bereich hat – auch aus anderen Programmiersprachen als Java – kann diesen Abschnitt getrost überspringen.

Bei Unit-Tests geht es darum die Methoden einer Klasse isoliert zu testen. Aber unsere Klassen leben gewöhnlich nicht in Isolation. Sie benutzten Services und Methoden von anderen Klassen. Und diese Klassen nutzen ihrerseits wieder Services und Methoden von weiteren Klassen. Diese Klassen nennen wir Collaborator. Dies führt zu zwei grundlegenden Problemen:

  • Externe Services lassen sich in der normalen Entwicklungsumgebung oft gar nicht (fehlerfrei) aufrufen, da diese Zugriff auf die Datenbank oder andere externe Systeme erfordern.
  • JUnit-Tests sollen die Implementierung einer spezifischen Klasse testen. Werden hierbei Aufrufe anderer Klassen unserer Geschäftslogik erlaubt, so kann deren – ggf. fehlerhaftes – Verhalten unsere Ergebnisse beeinflussen. Das ist nicht das was wir wollen.

Hier betreten Mock- und PowerMock-Objekte die Bühne. Diese beiden Werkzeuge erlauben es uns die Collaborator der zu testenden Klasse „zu verstecken“ und durch sogenannte Mock-Objekte zu ersetzen. Hierbei ist Mockito besonders gut geeignet für alle Standard-Fälle während PowerMock für die harten Brocken gebraucht wird. Dies betrifft insbesondere das Mocken von statischen und privaten Methoden. Mehr Informationen zum Thema „Mocking“ findet man hier. Das ist sozusagen DER Standard-Artikel zu diesem Thema.

Mockito im Einsatz

Genug der Vorrede und direkt hinein in ein erstes Beispiel. In unserer fiktiven Beispielsanwendung gibt es eine Klasse ItemService. Diese benutzt die Klasse ItemRepository um Daten aus der Datenbank zu laden. Offensichtlich ist diese Repository-Klasse ein guter Kandidat, um durch einen Mock ersetzt zu werden. In der zu testenden Methode wird ein Element anhand seiner Id geladen. Dann wird das geladene Element noch weiter verarbeitet. Wir wollen nur diese Verarbeitungs-Logik testen, nicht jedoch den Zugriff auf die Datenbank.

public class ItemServiceTest {

    @Mock
    private ItemRepository itemRepository;

    @InjectMocks
    private ItemService itemService;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void getItemNameUpperCase() {

        //
        // Given
        //
        Item mockedItem = new Item("it1", "Item 1", "This is item 1", 2000, true);
        when(itemRepository.findById("it1")).thenReturn(mockedItem);

        //
        // When
        //
        String result = itemService.getItemNameUpperCase("it1");

        //
        // Then
        //
        verify(itemRepository, times(1)).findById("it1");
        assertThat(result, is("ITEM 1"));
    }
}

Viele Projekte nutzen ein Framework zur Dependency Injection. Für die Beispiele in diesem Artikel wird das Spring Framework genutzt. Somit können wir auch die entsprechenden Annotationen von Mockito nutzen. (Diese funktionieren so auch mit anderen Dependency Injection Frameworks.) Mit @Mock können wir Mock-Objekte in unsere JUnit Testklasse markieren. Diese werden der zu testenden Klasse über die @InjectMocks-Annotation injiziert. Zusammen mit der Initialisierung der Mock-Objekte in der setup()-Methode ist es so sehr einfach alles für die eigentlichen Test-Methoden vorzubereiten.

Das gesamte Beispiel-Projekt steht auf GitHub zur Verfügung. Dieses enthält nicht nur die Tests, sondern auch eine kleine Beispiel-Anwendung, welche die zu testende Funktionalität beinhaltet. Dabei werden auch noch weitere Aspekte von Mockito und PowerMock genutzt, die gar nicht alle in diesem Artikel erwähnt werden können. Dies bietet eine gute Möglichkeit Dinge auch selber auszuprobieren.

mockito

Mit unseren Mock-Objekten können wir uns nun daran machen für diese ein bestimmtes – sprich unser erwartetes – Verhalten zu erzeugen. Dies geschieht über eine spezielle Syntax, die auf den ersten Blick ein wenig gewöhnungsbedürftig erscheint:

	wenn-Methodenaufruf-dann-Rückgabe

Übertragen auf unser obiges Beispiel:

	when(itemRepository.findById(“it1”)).thenReturn(mockedItem)

Der Methodenaufruf bezieht sich immer auf eine Methode in einer der genutzten Klassen, deren Verhalten unsere Tests nicht beeinflussen soll. Auch wenn das obige Beispiel ein wenig künstlich erscheint, so hilft es doch ein Gefühl für die benötigte Syntax zu bekommen. Bei Tests für komplexere Klassen und Methoden kann die Menge der benötigten Mock-Aufrufe durchaus entmutigend wirken. Auf der anderen Seite sollte dies auch ein weiterer Anreiz sein, Klassen und Methoden kurz zu halten und Verantwortlichkeiten klar zu trennen.

Zusätzlich zum reinen „Mocken“ von Methoden kann auch geprüft werden, dass Methoden auch tatsächlich aufgerufen wurden. In unserem obigen Beispiel erfolgt dies durch folgenden Aufruf:

	verify(itemRepository, times(1)).findById(“it1”)

Dies ist besonders nützlich, um den Programmablauf der zu testenden Klasse zu prüfen.

Mockito kann aber noch mehr …

… viel mehr als man in einem kurzen Artikel wirklich zeigen kann. Aber neben den grundlegenden Funktionen aus dem vorherigen Abschnitt wollen wir uns hier noch eine weitere sehr nützliche Funktion anschauen. Es geht darum Objekte zu verändern, die als Parameter an Mock-Objekte übergeben wurden. So wie ja auch die echte Implementierung ggf. Objekte verändern würde. Hierzu nutzen wir die doAnswer()-Funktion. Schauen wir uns dies direkt anhand eines Beispiels an.

@Test
public void testPLZAddressCombinationIncludingHostValue() {

    //
    // Given
    //
    Customer customer = new Customer("204", "John Do", "224B Bakerstreet");

    doAnswer(new Answer() {
        @Override
        public Customer answer(InvocationOnMock invocation) throws Throwable {
            Object originalArgument = (invocation.getArguments())[0];
            Customer param = (Customer) originalArgument;
            param.setHostValue("TestHostValue");
            return null;
        }
    }).when(hostService).expand(any(Customer.class));

    when(addressService.getPLZForCustomer(customer)).thenReturn(47891);
    doNothing().when(addressService).updateExternalSystems(customer);

    //
    // When
    //
    String address = customerService.getPLZAddressCombinationIncludingHostValue(customer, true);

    //
    // Then
    //
    Mockito.verify(addressService, times(1)).updateExternalSystems(any(Customer.class));
    assertThat(address, is("47891_224B Bakerstreet_TestHostValue"));
}

Mit den bisher gezeigten Konzepten ist ein großer Teil der „normalen“ Anwendungsfälle abgedeckt. Ein wichtiger Aspekt fehlt jedoch noch: Was tun wir wenn unsere zu testende Klasse z.B. statische Methoden einer anderen Klasse benutzt? Die Antwort auf diese Frage ist vermutlich nicht schwer zu erraten :-).

PowerMock – Das Unmögliche Mocken 🙂

PowerMock bietet Lösungen für die harten Fälle bei denen Mockito an seine Grenzen stösst. Im Allgemeinen bedeutet dies das Mocken von statischen Methoden. Es ist aber auch möglich private Methoden und Constructor-Aufrufe zu mocken. In allen diesen Fällen sollte die erste Frage aber immer lauten, ob nicht etwas an der Implementierung der Anwendung optimiert werden kann. Manchmal sind diese Art Test aber einfach notwendig und dann ist es gut ein Werkzeug wie PowerMock zur Hand zu haben. PowerMock arbeitet mit Manipulation des Byte-Code und nutzt dafür einen eigenen JUnit-Runner. Die zu mockenden Klassen werden dabei über die @PrepareForTest-Annotation angegeben. Am Einfachsten ist wieder der Blick auf ein Beispiel.

@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticService.class})
public class ItemServiceTest {

    @Mock
    private ItemRepository itemRepository;

    @InjectMocks
    private ItemService itemService;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void readItemDescriptionWithoutIOException() throws IOException {

        //
        // Given
        //
        String fileName = "DummyName";

        mockStatic(StaticService.class);
        when(StaticService.readFile(fileName)).thenReturn("Dummy");

        //
        // When
        //
        String value = itemService.readItemDescription(fileName);

        //
        // Then
        //
        verifyStatic(times(1));
        StaticService.readFile(fileName);
        assertThat(value, equalTo("Dummy"));
    }
}

Es ist hier schön zu sehen, dass die Syntax von PowerMock fast identisch ist mit der Syntax von Mockito. Der Grund hierfür liegt in einer speziellen API die PowerMock für das Zusammenspiel mit Mockito bereit stellt. Dies erkennt man auch gut bei einem Blick auf die Maven-Konfiguration des Beispiel-Projekts. Es wird nicht nur PowerMock sondern auch die zugehörige Mockito-API importiert. Dabei ist darauf zu achten, dass die Versionen zusammen passen. Unser Beispiel basiert noch auf der Version 1.6.4 von Mockito und PowerMock. Es macht aber sicherlich auch Sinn einen Blick auf die neue Version 2.0 von Mockito und PowerMock zu werfen.

...

    org.powermock
    powermock-module-junit4
    1.6.4
    test



    org.powermock
    powermock-api-mockito
    1.6.4
    test

...

Statische Methodenaufrufe müssen über die mockStatic()-Methode ge-mocked werden. Auch die Überprüfung eines Methodenaufrufs wird mit PowerMock ein wenig anders gehandhabt. Ansonsten ist die Syntax jedoch identisch.

Natürlich ist es möglich – und manchmal auch nötig – Mockito und PowerMock in ein und demselben JUnit-Test zu verwenden.In so einem Fall ist es sicherlich hilfreich sich im Team abzusprechen, welche Methoden statisch importiert werden (z.B. Mockito-when) und welche voll-qualifiziert genutzt werden (z.B. PowerMockito.when).

Ein nützliches Feature von PowerMock ist die Möglichkeit an einen anderen JUnit-Runner zu delegieren. Dies geschieht mit Hilfe der @PowerMockRunnerDelegate-Annotation. Ein Anwendungsbeispiel zeigt der folgende kurze Code-Schnipsel. Das komplette Beispiel findet sich wieder auf GitHub.

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(Parameterized.class)
@PrepareForTest({StaticService.class})
public class RateServiceTest {
...
}

In diesem Beispiel wird an den Parametrized.class JUnit-Runner delegiert, während gleichzeitig PowerMock genutzt werden kann. Eine anderes Beispiel könnte das Delegieren an den SpringJUnit4ClassRunner.class sein.

Zusammenfassung

Nach einer kurzen Eingewöhnung bietet Mockito eine sehr einfache und lesbare API für die Nutzung von Mock-Objekten in JUnit-Tests. Da PowerMock eine sehr ähnliche API liefert kann es fast genauso wie Mockito selber genutzt werden. Das erleichtert die gleichzeitige Nutzung beider Werkzeuge enorm.

Es ist möglich die Tests sehr lesbar zu schreiben. Dies hängt jedoch – wie immer – zu einem guten Teil von den zu testenden Klassen ab. Ansonsten bleibt hier nicht viel mehr zu sagen als: Happy Mocking 🙂

Dieser Blog-Post ist auch im Softwerker Vol. 9 erschienen. Den Softwerker kostenlos abonnieren: www.dersoftwerker.de.

The post JUnit Tests implementieren mit Mockito und PowerMock appeared first on codecentric AG Blog.

Unbequeme Wahrheiten

$
0
0

Viele Probleme von Unternehmen sind offensichtlich. Manche sind fachlicher Natur, und andere sind rein technisch. Darüber hinaus gibt es aber eine Reihe von Hindernissen, die weniger offensichtlich sind oder gar als normal und völlig selbstverständlich angesehen werden. Die folgende Schimpftirade (neudeutsch auch Rant), beleuchtet einige dieser Themen aus der Perspektive von Consultants, die sich weigern zu akzeptieren, dass diese Probleme unumstößlich sind.

Charles Darwins Theorie der biologischen Evolution, nach der Spezies von Organismen durch die natürliche Selektion von kleinen Variationen entstehen, sich entwickeln und konkurrierend versuchen zu überleben und sich fortzupflanzen, lässt sich analog auf Unternehmen anwenden, die versuchen, sich in Märkten trotz wachsender Globalisierung zu behaupten. Diese Analogie, auch Economic Darwinism genannt, ist die schmerzhafte Realität, in der sich nicht nur Startups des 21. Jahrhunderts wiederfinden, sondern vor allem auch Konzerne, die den einen oder auch den anderen Weltkrieg mit- und überlebt haben.

Gerade solche Konzerne haben gelernt, sich Kriegskassen, nicht für einen Krieg der Nationen, sondern für den Krieg in den Märkten, anzusparen. Aber was ist, wenn das nächste Airbnb, Uber oder Spotify einen Krieg erklärt, den man mit Geld und Ausdauer nicht gewinnen kann, weil ihre Ideen so innovativ sind, dass sie den gesamten Markt neu definieren oder obsolet machen?

Die übliche Antwort auf solche Ängste ist eine vermeintlich radikale Veränderung des Unternehmens. Es werden Consultants eingekauft, die Prozesse verbessern oder sogar eine agile Transformation versprechen. Es werden Verantwortlichkeiten neu sortiert, Strukturen neu formiert, und ab jetzt wird alles anders. Viel zu oft ist das nur der letzte große Aufschrei eines Konzerns, der trotz dieser Bemühungen in die Annalen der vergessenen Konzerne eingeht. Dieser Artikel soll die Bemühungen von Consultants nicht schmälern, sondern Aufmerksamkeit dafür erzeugen, dass es in vielen Unternehmen – so auch in deinem – tabuisierte Themen gibt, deren Lösung sich ein Unternehmen nicht einfach einkaufen kann.

(Fr)Agilität

Aber langsam: Warum scheitern radikale Veränderungen eigentlich, obwohl Consultants selbstbewusst eine bessere Zukunft versprechen? Soll agile Software-Entwicklung nicht sogar 300 Prozent der Produktivität möglich machen? Vielleicht hast du eine agile Transformation in deinem Unternehmen miterlebt, aber ist der versprochene Erfolg wirklich eingetreten?

Agilität scheitert häufig schon am Verständnis. Agilität ist eben nicht das Buzzword für die Ansammlung von Methoden, wie zum Beispiel kurzen Iterationen in der Produktentwicklung oder Inspect and Adapt, die in Summe alles besser machen. Agilität ist Management von Komplexität und wird letztendlich dann erreicht, wenn die Lead Time – also die Zeit für eine Änderung an einem Produkt von der Idee bis zur Auslieferung – maximal kurz ist. Agilität bei der Produktentwicklung ist dennoch nicht ausreichend, denn eine Pivotierung von Geschäftsfeldern in kurzer Zeit wird dadurch nicht ermöglicht. Business Agility – also Agilität auf Marktebene – ermöglicht erst das Survival of the Fittest.

Letztendlich ist es keine radikale Veränderung, wenn Agilität in die Produktentwicklung eingeführt wird, denn Rahmenbedingungen, Unternehmenskultur, (mittleres) Management, Silos, Budget, Ziele, Betriebsrat, Boni und andere Incentives ändern sich dadurch nicht.

Ab hier wird es unangenehm, denn die Wahrheit ist, dass protektionistische, teils auch machiavellistische Strukturen und Fehlervermeidungsstrategien wahre Business Agility verhindern.

Survivorship Bias

Konzerne existieren häufig schon seit Jahrzehnten, und die gesammelte Weisheit des Unternehmens hat sich bewährt. Jeder Fehler, der begangen wurde, konnte durch die Kriegskasse aufgefangen werden. Kommunikationsregeln, Prozesse, Überwachungs- und Bewilligungsgremien und andere Fehlervermeidungsstrategien wurden über die Jahre aufgebaut. Jeder Fehler sorgte in der Vergangenheit für neue Verbote, Regeln und Grenzen. Manche wurden explizit als solche benannt, und andere sind Teil der Kultur. Diese Struktur von Verboten und Geboten hat das Unternehmen also vor seinem Untergang bewahrt, die Kassen gefüllt und den Wert der Marke durch die Decke gehen lassen.

Das ist eine schöne Geschichte, aber die Wahrheit ist nicht so einfach. Andere Unternehmen sind gescheitert, trotz oder vielleicht sogar wegen dieser Kultur. Nicht die Fähigkeit aus Fehlern Sicherheitsmaßnahmen abzuleiten hat diese Unternehmen also gerettet. Den Markt interessiert es reichlich wenig, wie oft Fehler in einem Unternehmen verhindert werden konnten.

Auch wenn wir den Blick zu häufig nur auf Startups werfen und uns von ihrem unerwarteten Erfolg blenden lassen, müssen wir uns auch hier bewusst machen, dass wir dem Survivorship Bias unterliegen, denn nicht jedes Startup ist erfolgreich – im Gegenteil: Die meisten Existenzgründer scheitern mit ihren Unternehmen. Das sind allerdings keine interessanten Erfolgsgeschichten, wie wir sie aus dem Silicon Valley gewohnt sind.

Nur eine Frage der Zeit

Richten wir nun unseren Blick nach vorn: Dein Unternehmen hat sich ja nicht selbst zerstört. Noch nicht. Das nächste Startup könnte dein Geschäftsfeld allerdings innerhalb von Monaten massiv verändern.
Das muss nicht das Ende bedeuten, aber die Gefahr besteht, und gerade die nicht vorhandene Weisheit dieser Startups, also all die Fehlervermeidungsstrategien, die diese Startups nicht haben, könnten einen Weg aufzeigen, der das Ende für dein Unternehmen bedeuten würde. Es ist weniger die Frage, ob das passiert, sondern wann.

Culture eats Strategy for Breakfast

Dieser Spruch ist nicht besonders neu, aber er wird derzeit überall dort, wo über Change Management gesprochen wird, immer wieder in den Raum geworfen. Dein Unternehmen hat eine neue Strategie. Du hast das Budget, um etwas neues zu wagen. Dein Research & Development Team hat ein neues Ziel: Innovation und Disruption des Marktes. Wenn ein Startup einen Markt umkrempeln kann, dann kann es ein Konzern doch erst recht, oder?

Dieses Team beginnt also mit Experimenten, neuen Ideen, es spielt mit dem Gedanken in den Geschäftsfeldern der Konkurrenz zu wildern. Das sieht für eine Weile gut aus, aber dann soll das neue innovative Produkt endlich in den Markt geworfen werden. Nur noch die Anbindung an das alte Abrechnungssystem, das speziell für die Eigenarten dieses Unternehmens entwickelt wurde, fehlt.

Also wird der Experte für das Abrechnungssystem eingeladen, der einen Vortrag über die vielen Funktionen und Spezialfälle, die das System abdeckt, hält. Fantastisch, es gibt sogar schon eine Schnittstelle. Wochen später gibt es noch immer keine Anbindung, denn es stellte sich heraus, dass diese Schnittstelle eine Tabelle in einer Oracle-Datenbank ist, die nur in der Nacht zwischen 3 Uhr und 4 Uhr Mitteleuropäischer Sommerzeit auf Änderungen geprüft wird.

Die Abrechnung muss dem Kunden aber sofort in dem neuen System in der Cloud – in jeder Zeitzone – angezeigt werden. Das ist zu langsam. Eine Zwischenschicht soll das Ganze nun beschleunigen, haben die Architekten aus der IT-Abteilung zumindest empfohlen, und dein Innovationsteam stimmt zu.

Ein neues Team wird gebildet. Nach weiteren Wochen, in denen über die Architektur der Middleware, die zwischen dem neuen Produkt und den Legacy-Systemen vermitteln soll, gesprochen wurde, wird festgestellt, dass die Datenbank sensitive Kundendaten enthält, die auf Grund von Datenschutzregeln der IT-Abteilung nicht an Cloud-Lösungen angebunden werden darf. Diese Regeln sind natürlich unumstößlich, es sei denn das Datenschutzgremium ändere die Regeln, aber dann müssten auch alle bestehenden Anwendungen erneut geprüft werden, da sie sich im selben Netzwerk befinden. Einige Eskalationsgespräche später stellst du die entscheidende Frage: „Wieso ist unser neues Produkt noch nicht auf dem Markt?” Weil deine Strategie von der Unternehmenskultur gefrühstückt wurde.

Die Dyade des Stillstands

Um das Jahr 1900 herum wurden erstmalig Arbeiterausschüsse gesetzlich verankert, aber zunächst nur für den Bergbau. Dreißig Jahre später haben sich diese Interessenvertreter der Arbeitnehmer zu betriebsverfassungsrechtlichen Mitbestimmungsorganen, also Betriebsräten, mit umfassenden Mitbestimmungsrechten für alle Industriezweige weiterentwickelt. Der Betriebsrat hat unter anderem die Aufgabe, den Arbeitnehmern Gehör zu verschaffen und ihre Interessen zu vertreten.

Diese sozialliberale Errungenschaft ist ein wichtiger Bestandteil der Deutschen Wirtschaft, und Betriebsräte haben vielen Arbeitnehmern den Arbeitsplatz gerettet oder das Arbeitsumfeld verbessert. Leider gibt es auch eine Kehrseite.

Umstrukturierungen von Unternehmen, egal ob sinnvoll oder nicht, müssen mit dem Betriebsrat erarbeitet und von ihm genehmigt werden. Dabei werden Kompromisse eingegangen. Arbeitsplätze werden erhalten, obwohl sie nicht mehr in die neue Unternehmensstrategie passen. Wir wollen starke, selbstorganisierte, autonome Teams, also wollen wir die Verantwortungen neu verteilen. Aber Verantwortung heißt häufig auch irgendeine Form von Haftung oder Rechenschaft. Eigenschaften, die nur Vertreter des mittleren Managements haben dürfen. Immerhin bekommen sie dafür Gratifikationen und Dienstwagen. Aus Gründen der Gerechtigkeit wird der Betriebsrat also keine Verantwortung ohne entsprechenden Ausgleich zulassen. Selbst wenn der finanzielle Ausgleich nicht das Problem ist, folgen direkt die nächste Fallstricke: Das Entwicklungsteam soll nun Verantwortung tragen, die zuvor vom mittleren Management getragen wurde.

Letztendlich ist die breite Zwischenschicht unterhalb der Unternehmensführung und oberhalb der Operative dafür zuständig, Kontroll- und Steuerungsmechanismen zu verwenden, um das Unternehmensrisiko zu senken. Sie sorgen mit ihren Rahmenbedingungen dafür, dass die Abteilungen und Teams keine Fehler machen. Sie tragen die Verantwortung. Wollte man nun diese Verantwortung womöglich auf die unteren Ebenen verteilen, was wäre dann noch die Daseinsberechtigung für das mittlere Management?

Es ist daher weder im Interesse des Betriebsrats noch des mittleren Managements, wenn es um Veränderungen von Aufgaben, Verantwortungen oder der Hierarchie geht.

Unscheinbare Zielvereinbarungen

Incentives wie Boni, Prämien, Unternehmensbeteiligungen, Dienstwagen oder Sonderurlaub sind sowohl beim mittleren als auch beim oberen Management sehr beliebt. In der Regel gibt es einen Incentive-Plan, der diese an die Erreichung von persönlichen Zielen knüpft. Diese Zielvereinbarungen unterliegen normalerweise der Geheimhaltung, da sie einen Teil der Gehälter ausmachen. Die daran geknüpften Ziele werden daher auch häufig nicht offengelegt. Die Implikation ist, dass unterschiedliche Äste des Hierarchiebaums verschiedene Ziele verfolgen. Ein Manager wird alles machen, um sein Ziel erreichen, selbst wenn er dabei das Unternehmen zerstört. Viele Manager, die unterschiedliche Ziele haben, die sich womöglich widersprechen oder zumindest die Priorität auf unterschiedliche Themen legen, geben diesem Problem eine weitere Dimension. Selbst wenn es ein Oversight Committee gibt, das die Zielvereinbarungen miteinander abgleicht, wird die Komplexität der unscheinbaren Zielvereinbarungen und die damit verbundenen Implikationen zu groß, um sie mit den kurzfristigen Taktiken und langfristigen Strategien des Unternehmens zu vereinbaren. Incentives, die an Ziele gebunden sind, sind eine geladene Waffe, die sich das Unternehmen an den eigenen Kopf hält.

Real Change

Echte Business Agility wird dadurch ermöglicht, dass das gesamte Unternehmen, von Unternehmensführung über das mittlere Management bis zur Operative, die Implikationen trägt. Es gibt eine Reihe von unangenehmen Wahrheiten:

Wahrheit 1: Ein Unternehmen mit einem Betriebsrat kann nicht die Geschwindigkeit erreichen, die in disruptiven globalen Märkten notwendig ist, um mit Startups mithalten zu können.
Wahrheit 2: Das mittlere Management wird seine Daseinsberechtigung und Macht verteidigen.
Wahrheit 3: Eine bestehende Unternehmenskultur ist ein Immunsystem, das Change-Viren bekämpft.
Wahrheit 4: Change ist notwendig geworden, und man kann sich nicht mehr auf seine Historie verlassen.

Licht am Ende des Tunnels

Werden Consultants in ein Unternehmen geholt, stehen sie vor der unlösbaren Aufgabe, die Organisation zu verändern. Aber die Organisation und ihre Kultur sind miteinander verflochten und lassen sich nicht trennen. Konzernkulturen sind über Jahre organisch gewachsen und lassen sich schwer zu Papier bringen und analysieren. Jedes Unternehmen hat seine eigene Kultur, und das ist auch gut so. Sie sind für sich genommen auch nicht schlecht, denn sie erfüllen das menschliche Bedürfnis nach Sicherheit.

Eine Kultur möchte erhalten werden, denn jede Änderung an diesem Sicherheitsnetz birgt Risiken. Daher überwiegt das Streben nach der Bewahrung des Status Quos dem Wunsch nach Erneuerung. Betriebsräte legen viel Wert darauf, dass Unternehmen nicht zu stark und zu schnell verändert werden, da dadurch Menschen auf der Strecke bleiben können. Das ist mittelfristig gut für den Menschen, denn seine Position und Rolle bleiben erhalten und stabil, aber langfristig könnte der Arbeitsplatz dadurch vollständig verloren gehen.

Effzienz – also Output durch Zeit – lässt sich vorhersagen. Es liegt also nahe, dass Effzienz im Fokus von Managern steht, obwohl Effektivität – also Wert durch Zeit – ein erstrebenswertes Ziel ist. Effektivität variiert und ist schwer zu prognostizieren, da der Markt den Wert definiert und jederzeit neu definieren kann. Dagegen lässt sich Effzienz auch einfordern und belohnen. So entstehen Incentive-Pläne und somit steuern Zahlen das Unternehmen. Diese Pläne sind mittelfristiger Natur und verhindern, dass die taktischen Ziele eines Unternehmens kurzfristig geändert werden können.
Trotz vieler Widrigkeiten gibt es eine erfolgversprechende Strategie, um Licht am Ende des Tunnels unangenehmer Wahrheiten zu sehen: eine Strategie, um der Dyade des Stillstands und der„frühstückenden“ Unternehmenskultur zu entkommen, ohne dabei den Survivorship Bias zu vernachlässigen.

Diese Strategie wurde durch die Lean-Startup-Bewegung stark, und sie klingt fundamental konträr zu vielen etablierten Management-Praktiken. Dennoch hat sie sich bewährt und ist die Basis für viele Gründerzentren im Silicon Valley, aber auch in Deutschland. Darüber hinaus wird diese Strategie auch immer häufiger von Konzernen verfolgt.

Eine vermeintlich disruptive Idee, neben anderen innovativen Ideen, wird dabei jeweils in kleine autonome Einheiten, also Startups mit flacher Hierarchie, ausgelagert oder ausgegründet. Die Betonung liegt auf autonom und dem Plural von Startup. Startups werden dabei explizit nicht mit Ressourcen wie einer Kriegskasse ausgestattet, denn Ressourcenknappheit erzeugt die Not zur Erfindung. Eine Not, die vielmehr als Kraft verstanden werden kann, aus der Kreativität, Lösungsorientierung und der Zwang zur Elimination von jeglichem Overhead erwächst. In dieser Disruptionslotterie brauchen wir mehr als ein Los, und jedes Los muss unabhängig von seinem Mutterkonzern Fehler machen dürfen, die durch Regularien und Gremien, Kultur, mittlerem Management und Betriebsrat sonst kategorisch ausgeschlossen werden. In der Lotterie muss nicht jedes Los ein Gewinn sein. Eines von vielen reicht vollkommen.

Übrigens: Dieser Blog Post erschien ursprünglich in der Spezialausgabe „Digitalisierung“ des codecentric Softwerker-Magazins. Warum ein ganzes Heft zum Thema Digitalisierung? Weil der Umstand, dass die Digitalisierung unsere Wirtschaft in vielen Bereichen verändert kein Märchen, nicht nur „the next big thing“ und kein leeres Buzzword Bingo darstellt.
Jetzt die Ausgabe kostenlos anfordern.

The post Unbequeme Wahrheiten appeared first on codecentric AG Blog.


Probe, Sense, Respond – Mit Rapid Prototyping zum digitalen Produkt

$
0
0

Digitalisierung schafft Chancen. Neue Kundenbedürfnisse entstehen, Märkte öffnen und verändern sich. Gleichzeitig konfrontiert sie Produktmanager mit zunehmender Komplexität und vielen Unbekannten. In diesem Artikel beleuchte ich, welche Rolle Rapid Prototyping als Werkzeug bei der Entwicklung innovativer, digitaler Produkte spielen kann und was es beim Aufbau von Rapid-Prototyping-Kapazitäten zu beachten gilt.

Was hat sich verändert?

In den meisten Unternehmen – Software-Produzenten ausgeschlossen –  ist Software immer primär dazu eingesetzt worden, Geschäftsprozesse zu unterstützen. Entsprechend ist die interne IT ausgeprägt worden: Plantreue, Verlässlichkeit und Kosteneffizienz waren die dominierenden Erfolgsfaktoren. Der von Nicholas G. Carr 2003 im Harvard Business Report veröffentlichte Artikel “IT doesn’t matter” beschreibt die Situation deutlich: IT-Kapazitäten sollten wie jedes andere Infrastruktur-Thema behandelt werden: als nicht-strategische Handelsware.

Knapp neun Jahre später – für eine große Konzern-IT kein langer Zeitraum – sieht die Welt schon fundamental anders aus. Marc Andreessen schreibt im Wall Street Journal unter dem Titel “Why Software is Eating the World” über eine Welt, in der jedes Unternehmen zwangsläufig zu einem Software-Unternehmen werden wird.

Heute – noch einmal sechs Jahre später – zweifelt niemand mehr daran, dass digitalen und software-intensiven Produkten die Zukunft gehört. Das stellt Produktmanager vor große Herausforderungen:

Zum einen haben sich Märkte und Marktteilnehmer verändert. Digitale Kanäle und Produkte erlauben es, neue Zielgruppen zu erschließen und alte Probleme auf ganz neue Weise zu lösen. Das bedeutet aber gleichzeitig, dass das über lange Zeit angeeignete Expertenwissen plötzlich an seine Grenzen stößt. Unbekannte Wirkmechanismen müssen neu erforscht, veränderte Kundenbedürfnisse identifiziert werden. Exponentiell wachsende technische Möglichkeiten und die zunehmend unscharfen Grenzen zwischen Produktkategorien erzeugen zusätzliche Komplexität.

Zum anderen ist der Lebenszyklus digitaler Produkte im Vergleich zu ihren traditionellen Vorgängern um ein Vielfaches schneller. Hybride Produkte erhalten durch Software-Updates ganz neue Funktionen, ohne dass die Hardware-Plattform ausgetauscht werden muss. Reine Software-Produkte können gar mehrfach täglich aktualisiert werden. Dieser Geschwindigkeit kann sich kein Produktmanager auf Dauer verweigern: Die “digital natives” unter den Mitbewerbern haben sie längst für sich als Wettbewerbsvorteil erkannt.

Es entstehen zwei gravierende Verschiebungen: Zum einen stellen neue Produktgenerationen nicht länger eine evolutionäre Weiterentwicklung dar. Stattdessen muss das Produkt von Grund auf neu erfunden werden. Eine solche Neuausrichtung bedeutet aber auch, dass wir im Produktmanagement den komplizierten Problemraum, in dem analytisches, auf Fachwissen basierendes Vorgehen die beste Lösungsstrategie darstellt, verlassen. Immer häufiger finden wir uns im komplexen Problemraum wieder: Kausale Zusammenhänge sind nicht mehr a priori sichtbar, sondern müssen durch gezielte Experimente erst neu identifiziert werden.

Gleichzeitig zwingen uns deutlich kürzere Produktlebenszyklen dazu, diese frühe Phase der Produktentwicklung immer häufiger zu durchlaufen. In Summe bedeutet das, dass Produktmanager digitaler Produkte ihren Werkzeugkoffer an eine Situation anpassen müssen, in der Komplexität und die damit verbundene Unvorhersehbarkeit zum Alltag gehören. Ein mögliches Hilfsmittel dafür möchte ich im Folgenden detaillierter vorstellen.

Prototyping als Handlungsstrategie

Betrachtet man erfolgreiche Handlungsstrategien in komplexen Problemsituationen, so zeigen sich bestimmte Gemeinsamkeiten. An die Stelle von auf Analyseergebnissen fußendem Handeln tritt das vorsichtige Herantasten durch Ausprobieren und Beobachten. Dave Snowden’s Cynefin-Framework fasst dies sehr treffend zusammen: An die Stelle von Erkennen-Analysieren-Reagieren tritt Probieren-Erkennen-Reagieren (“Probe-Sense-Respond”). Prototyping, also die Fertigung von auf den Zweck der Informationsgewinnung ausgelegten Modellen und Testversionen eines Produkts, ist ein Vertreter dieser Handlungsstrategie.

Entsprechend sind heute Low-Fidelity-Prototypen fester Bestandteil der Produktentwicklung. Zusammen mit Interviews und anderen, dem User-Centered Design entstammenden Techniken nutzen wir sie regelmäßig, um Kundenbedürfnisse zu identifizieren und Lösungskonzepte zu validieren. Sie sind einfach, schnell und ohne besondere technische Fähigkeiten herzustellen und damit eine Methode des sogenannten Rapid Prototypings – der durch geeignete Verfahren und Reduzierung auf das Wesentliche stark beschleunigten Modellentwicklung. Damit sind sie ein wertvolles Werkzeug, solange wir mit ihnen dieses Wesentliche unserer Produktidee ausdrücken und erproben können.

Nun verändern sich aber wie bereits geschildert Problem- und Lösungsräume mit zunehmender Digitalisierung erheblich. Im Internet of Things rücken Software und Hardware wieder stärker zusammen. Die Einbindung von und Vernetzung mit bestehenden digitalen Produkten – das Stichwort hier ist API-Ökonomie – ermöglicht bisher undenkbare Funktionsvielfalt. Virtual- und Augmented-Reality-Lösungen rücken mit Projekten wie Google Tango in greifbare Nähe. Sprachbasierte Benutzerschnittstellen wie Amazon Alexa oder Chat-basierte Dienste wie WeChat stellen herkömmliche digitale Mensch-Maschine-Schnittstellen gleich ganz in Frage. Zuletzt machen künstliche Intelligenz und maschinelles Lernen menschliches Eingreifen an vielen Stellen vollständig unnötig.

Es ist leicht ersichtlich, dass Low-Fidelity-Prototyping – so nützlich es bisher gewesen sein mag – schnell an seine Grenzen gerät, wenn das Innovative – und vielleicht Disruptive – unserer Produktidee gerade in der Nutzung dieser neuen technischen Möglichkeiten liegt. Dadurch entsteht eine mit herkömmlichen Methoden schwierig zu schließende Lücke im Produktentwicklungsprozess: Wir können das Problem und seine Wichtigkeit feststellen, also unsere Produktidee theoretisch validieren. Wir haben aber keine einfache Möglichkeit zur Hand, herauszufinden, wie ein marktgängiges Produkt zur Lösung des identifizierten Problems beschaffen sein muss, können also auch nicht mit vertretbaren Risiken mit der Entwicklung einer ersten Produktversion beginnen.

Ansätze wie die Entwicklung eines MVP, also einer ersten, bedingt marktgängigen, nutzbaren Produktversion mit dem minimal erforderlichen Funktionsumfang, helfen zwar, sind in der Praxis aber häufig nur erfolgreich durchzuführen, wenn klar ist, welche Lösung “viable”, also praktikabel aus Entwickler- und Kundensicht ist. Solange wir hier nur auf Hypothesen setzen, sind kostspielige Fehlleistungen vorprogrammiert.


Wenn an dieser Stelle von einem MVP die Rede ist, dann beziehe ich mich hier auf die engere Definition, die ich in der Praxis am häufigsten antreffe: Eine erste Version eines Produkts, die in ihrer Beschaffenheit dem finalen Produkt nahe kommt. Beispiele für diese Art des MVP sind das erste iPhone oder der Tesla Roadster. Beide sind auf die wesentliche Komponente des späteren Produkts reduzierte Versionen, aber keineswegs “halbfertig” und einfach herzustellen.

Dem gegenüber steht die weitere Definition von MVP, die Eric Ries mit seiner Lean-Startup-Methode etabliert hat und deren Fokus der Informationsgewinn ist. Wie man sich dieses Werkzeug als Produktmanager nutzbar machen kann, beschreibt mein Kollege Jan Hölter in seinem Softwerker-Artikel “Do Things That Don’t Scale”.


Rapid High-Fidelity-Prototyping mit Software

Glücklicherweise sind nicht nur die Herausforderungen gewachsen. Sowohl methodisch als auch technisch hat sich im Bereich der Software-Entwicklung viel getan. Agile Methoden, allen voran Scrum, sind im Mainstream angekommen und zeigen, wie man Software ohne schwergewichtige Prozesse in kurzen Entwicklungszyklen entwickeln und ausliefern kann. Entwicklungsframeworks, API- und Komponenten-Ökosysteme sowie Platform-as-a-Service-Angebote mit umfangreichen, leicht nutzbaren Diensten liefern Entwicklungsteams die nötige Produktivität. Damit besitzen wir letztlich alle Zutaten, um das alte Argument gegen High-Fidelity-Prototypen, langwierige und komplizierte Entwicklung, außer Kraft zu setzen.

Hier liegt für Produktmanager digitaler Produkte eine große Chance. Nehmen wir einmal an, es wäre heute möglich, funktionsfähige Prototypen für Produktideen in einer Geschwindigkeit zu entwickeln, die bisher Papier-Prototypen und anderen Low-Fidelity-Methoden vorbehalten war. In diesem Fall könnten wir die oben beschriebene Lücke schließen: Sobald das Problem identifiziert und erste Hypothesen bezüglich des notwendigen Funktionsumfangs einer Lösung aufgestellt sind, können wir die Hypothesen mit gezielten, realistischen Experimenten validieren und auf diese Weise den notwendigen Funktionsumfang – aber auch das Lösungsdesign – für unser MVP empirisch ermitteln, ohne auf die sich heute bietenden technischen Möglichkeiten verzichten zu müssen.

Für innovative, digitale Produkten ist das ein unschätzbarer Vorteil: Ihre Wirkweise und Tauglichkeit ist im buchstäblichen Sinne aufgrund der neu entstandenen technischen und kombinatorischen Möglichkeiten nicht vorstellbar. Wir wissen im Voraus nicht, und können es uns auch ohne es auszuprobieren (“probe”) nicht erschließen, ob unsere Augmented-Reality-App, die dem Servicepersonal die Bestellhistorie der Restaurantgäste anzeigt, tatsächlich zu besserem Service und in Folge besserer Kundenbindung führt – und wie genau solch ein System ausgeprägt sein muss, um in dem spezifischen Nutzungskontext zu funktionieren.

Könnten wir die wichtigsten Aspekte dieser Idee kostengünstig aber realistisch in einem Modellversuch – also mittels eines Prototyps – erproben, könnten wir schnell Risiken identifizieren und in der Praxis nicht tragfähige Ideen verwerfen, bevor wir sie in die potentiell kostspielige und langwierige Entwicklung eines funktional eingeschränkten aber qualitativ hochwertigen MVP überführen.

Das Rapid-Prototyping-Team

Wenn wir davon überzeugt sind, dass Rapid Prototyping in Form von Software für uns ein wertvolles Produktmanagement-Werkzeug sein kann, stellt sich die Frage, wie wir die entsprechenden Kapazitäten aufbauen können. IT-Organisationen sind, wie in der Einleitung angedeutet, üblicherweise nicht auf diese Art von Software-Entwicklung ausgerichtet. Ihre Aufgabe ist, verlässlich qualitativ hochwertige und langlebige Systeme zu entwickeln, häufig nach einem mehr oder weniger stabilen Plan. Wir benötigen eine andere Art von Team: Ein Team, das Software nicht als Endergebnis sieht, sondern als ein sehr spezielles Mittel zum Einholen von Feedback. Entsprechend müssen sich die Optimierungsziele dieses Team verschieben. Es lässt sich argumentieren, dass – sobald es einmal gelungen ist, den Feedback-Zyklus zu schließen, also Prototypen tatsächlich bis zur Testgruppe auszuliefern – nur noch die Minimierung der Zeit und Kosten zwischen Idee und Umsetzung wichtig ist. Im besten Fall möchte ich als Produktmanager die Entstehung und Beschaffenheit des Prototyps unmittelbar – also ohne zwischengelagerte Rituale oder Prozesse – beeinflussen können.

Wenn ich auf die Erfahrung zurückblicke, die ich beim Aufbau eines solchen Teams sammeln konnte, zeichnen sich einige Faktoren ab, die für die erfolgreiche Erbringung von Rapid-Prototyping-Dienstleistungen essentiell sind:

Stabiles, funktionsübergreifendes Team

In der Entwicklung innovativer, digitaler Produkte ist Geschwindigkeit essentiell. Im klassischen, auf Projektarbeit optimierten IT-Organisationen ist es nicht unüblich, Teams gezielt für ein Projekt zusammenzustellen und am Ende des Projekts wieder aufzulösen. Unter dem Gesichtspunkt der Auslastung ist das sinnvoll. Wollen wir aber auf Taktzeit optimieren, können wir es uns nicht leisten, darauf zu warten, dass ein Team sich zusammenfindet und seine internen Abläufe erfindet und optimiert. Entsprechend sollte ein Rapid-Prototyping-Team stabil sein: Einmal ins Leben gerufen, bleibt es über einen langen Zeitraum zusammen. Die Zeit zwischen Einsätzen wird genutzt, um die Werkzeuge und die interne Zusammenarbeit zu verbessern.

Bei der initialen Zusammenstellung müssen wir darauf achten, alle relevanten Rollen abzudecken, ohne das Team unnötig groß werden zu lassen. Neben den offensichtlichen Software-Entwicklungskenntnissen in den relevanten Domänen sind Fähigkeiten in UX- und UI-Design und IT-Operations unerlässlich, um die nötige Autonomie herzustellen. Hat keines der Teammitglieder Erfahrungen im Bereich der Prozessoptimierung, kann ein externer Coach sinnvoll sein.

Stabile, produktivitätssteigernde Werkzeuge

Was für das Team gilt, muss auch für die verwendeten Werkzeuge gelten. Der Schlüssel zu erfolgreichem Prototyping liegt meiner Erfahrung nach darin, einen möglichst flexibel einsetzbaren und gleichzeitig genügend stabilen Satz von Entwicklungswerkzeugen zu wählen und über die Lebenszeit des Teams in diese Werkzeuge zu investieren, anstatt für jeden Prototyp auf spezialisierte und neue Tools zu setzen. Ziel ist es, durch Automatisierung und Extraktion wiederverwendbarer Komponenten den eigentlichen Programmieraufwand immer weiter zu reduzieren und gleichzeitig technische Risiken zu minimieren.

Welche Werkzeuge konkret in Frage kommen, hängt zu stark vom Kontext ab, in dem Produkte prototypisiert werden sollen. Allerdings ist es sinnvoll, nach bestimmten Kriterien auszuwählen:

  • Wie groß ist das Ökosystem an fertigen Komponenten?
  • Wie einfach ist es, eigene Komponenten herzustellen und wiederzuverwenden?
  • Wie gut kann das Werkzeug automatisiert werden?
  • Wie einfach ist der Betrieb von mit den entsprechenden Werkzeugen realisierten Anwendungen?

Wichtig bei dieser Entscheidung: Ob die verwendeten Werkzeuge später für die Entwicklung des echten Produkts in Frage kommen, ist nachrangig. Die Aufgabe des Prototyping-Teams ist nicht, Software zu entwickeln, sondern Ideen zu validieren.

Autonomie

Die durch stabile Besetzung und die richtigen Werkzeuge gewonnene Produktivität kann sich nicht in schnellen Taktzeiten niederschlagen, wenn das Team auf externe Zuarbeit warten muss. Die notwendige Autonomie hat viele Facetten: Zum einen spiegelt sie sich in der schon erwähnten, funktionsübergreifenden Besetzung des Teams wieder. Selbstverständlich fällt darunter auch eine intensive und kontinuierliche Zusammenarbeit mit dem verantwortlichen Produktmanager. Zum anderen ist technische Autonomie erforderlich. Konkret bedeutet das, das Team zu befähigen, alle benötigten Werkzeuge selbst auszuwählen, anzuschaffen und zu betreiben. Einige konkrete Beispiele aus meiner Erfahrung sind:

  • Das Team konnte von Linux-basierten Entwickler-Rechnern auf macOS umsteigen, um für alle mobilen Plattformen Apps prototypisieren zu können.
  • Das Team konnte eigenständig Abonnements für die benötigten Dienste (Laufzeitumgebungen, Continuous-Delivery-Infrastruktur, App Stores, etc.) abschließen.
  • Das Team kann Hardware für Prototypen (IoT-Geräte, mobile Endgeräte, etc.) eigenständig bestellen.
  • Das Team hat vollständige Kontrolle über den eigenen Entwicklungsprozess.

Schlanke Prozesse

Wenn ein Team auf Taktzeit optimieren muss, ergibt sich fast zwangsläufig eine Reduzierung des Umlaufbestandes, also der gleichzeitig bearbeiteten Aufgaben. Soll der Entwicklungsprozess außerdem kontinuierlich verbessert werden, ist eine Messung und Visualisierung von Taktzeiten und Bestand unerlässlich. Meiner Erfahrung nach eignen sich daher Kanban-Systeme mit strikten Work-In-Progress-Beschränkungen am besten. Auf Zeremonien sollte weitestgehend verzichtet werden. Treten unerwünschte Abweichungen auf, sollte sofort reflektiert und reagiert werden. Auch hier wieder ein paar konkrete Beispiele aus der Praxis:

  • Für komplizierte, häufig auftretende und nicht technisch automatisierbare Tätigkeiten hat das Team Protokolle und Checklisten entworfen.
  • Treten unerwünschte Variationen im Prozess auf, werden diese umgehend in einem eigens eingerichteten Chat-Kanal gesammelt. Am Ende jedes Tages wird über die Variationen reflektiert und entschieden, ob ein Eingreifen nötig ist.
  • Treten Probleme auf, die ein Teammitglied daran hindern, effektiv zu arbeiten, wird der ganze Prozess sofort gestoppt, die Ursache ermittelt und behoben (“Stop the Line”).
  • Arbeitsgegenstände werden einzeln durch den gesamten Prozess geführt: Eine vom Produktmanager eingebrachte Idee wird sofort analysiert. Es wird eine Lösung entworfen, realisiert, ausgeliefert und validiert, bevor die nächste Idee angegangen wird.

Was bekommen wir dafür?

Ein Team, das konsequent darauf optimiert, wird mittelfristig in der Lage sein, für den Produktmanager mehrfach täglich und ohne nennenswerte Rüstzeiten Ideen in Form prototypischer Software umzusetzen und damit die Grenze zwischen Low- und High-Fidelity-Prototyping zu verwischen. Die Produktmanagement-Organisation kann diese Kapazitäten anschließend in ganz unterschiedlichen Szenarien einsetzen und erhält so ein insbesondere vor dem Hintergrund der Digitalisierung wertvolles Werkzeug:

  • Unterstützung des Portfolio-Managements durch Validierung kritischer Hypothesen
  • Erprobung unterschiedlicher Lösungsvarianten bei der Herstellung neuer oder der Ergänzung bestehender Produkte
  • Unterstützung bei Machbarkeitsstudien
  • Erstellung von Prototypen zu Demonstrationszwecken (Messen, interne Präsentationen, etc.)
  • Einbindung in die Designphasen herkömmlich arbeitender Teams als Ersatz oder Ergänzung für Low-Fidelity-Prototyping

Ergänzend zu den aufgezählten Szenarien ist durchaus denkbar, Software-MVP und kleinere finale Produkte auch direkt durch ein solches Rapid-Prototyping-Team entwickeln zu lassen. Beispielsweise ließe sich das von Jan Hölter in seinem Artikel “Do Things That Don’t Scale” geschilderte Piecemeal MVP, das bestehende Services ohne eigenen Aufwand nur kombiniert, in einem Rapid-Prototyping-Team aufgrund ähnlicher Ansätze leicht zu einem echten Produkt weiterentwickeln.

In jedem Fall sollte aber Sorge getragen werden, dass die langfristige Weiterentwicklung und der Betrieb gesichert sind. Mein Kollege Harald Schlüter beschreibt entsprechende Maßnahmen in seinem Softwerker-Artikel “Wartungshölle? Nein, danke!”.


Fazit

In dem komplexen Umfeld der Entwicklung innovativer, digitaler Produkte müssen Produktmanager neue Handlungsstrategien finden. Probe-Sense-Respond – beispielsweise in Form des Prototypings – hilft uns, Produktideen zu validieren und geeignete Lösungen zu entdecken. Mit den heute verfügbaren Mitteln ist es möglich geworden, diese Prototypen direkt in Form von Software herzustellen und damit auch komplizierte und technisch anspruchsvolle Produktideen schnell und belastbar zu validieren.

Allerdings ist es unwahrscheinlich, dass entsprechende Kapazitäten über die bestehende IT-Organisation abgebildet werden können, da die Anforderungen deutlich von denen des üblicherweise praktizierten Projektgeschäfts abweichen. Mit der entsprechenden Planung und Disziplin ist es aber durchaus möglich, ein Team aufzubauen, das uns zukünftig die Entdeckung und Entwicklung digitaler Produkte erheblich vereinfachen wird.


Dieser Blog-Post ist erstmalig im Softwerker Spezial: Digitalisierung erschienen. Hier können Sie sich den Artikel auch als PDF herunterladen.

Den Softwerker kostenlos abonnieren

Für weitere Infos zu unserem Angebot schauen Sie bitte auf unserer Seite Digitization Labs.
Kontaktieren Sie uns für einen kostenlosen Workshop!

 

The post Probe, Sense, Respond – Mit Rapid Prototyping zum digitalen Produkt appeared first on codecentric AG Blog.

Wartungshölle? Nein, danke!

$
0
0

Herausforderungen und Lösungsansätze für die Wartung von Individual-Software

Individual-Software löst sehr individuelle Probleme und stellt die IT deshalb schon während ihrer Entwicklung vor besondere Herausforderungen. Alle erfolgreichen – im Sinne von produktiv gesetzten – Individual-Softwareprodukte haben dabei eine entscheidende Gemeinsamkeit: Sie erfordern über einen in der Regel sehr langen Zeitraum kontinuierliche Wartung, Pflege und Weiterentwicklung der entwickelten Software. Leider wird dem Thema Wartung oft nicht rechtzeitig die notwendige Aufmerksamkeit geschenkt, und das Wartungsteam, die Auftraggeber und die Nutzer des Systems landen alle gemeinsam in der Wartungshölle. Generell möchte ich im Folgenden Sie als meine Leser für dieses Thema sensibilisieren. Konkret stelle ich dazu zunächst dar, was eigentlich alles falsch läuft, um im Anschluss daran Lösungsoptionen aufzuzeigen.

Es gibt im Groben zwei unterschiedliche Optionen die Softwarewartung organisatorisch zu gestalten. Im ersten Fall betreuen größere Projektteams die Software dauerhaft selbst. Dies wird dann gerne als “You build it, you run it” bezeichnet. Im zweiten Fall übergeben die Projektteams die Software für die Pflege an Wartungsteams. Teilweise erfolgt dies dann auch von einem IT-Dienstleister an den Auftraggeber oder aber umgekehrt. Insbesondere im zweiten Fall zeigt sich: Wird die Wartung nicht frühzeitig berücksichtigt, ergeben sich immer wieder die gleichen Probleme. Änderungen an der sich im produktiven Betrieb befindlichen Software werden notwendig, und diese Änderungen sind dann häufig gleichzeitig:

  • exorbitant teuer
  • mit sehr hohem Risiko behaftet
  • oder extrem langwierig.

Am Ende machen die Änderungen dann keinem der Beteiligten Spaß. Sie erzeugen Schmerzen und Frust bei Entwicklern, Auftraggebern und Anwendern. Hohe Kosten,  Kündigungen frustrierter Mitarbeiter, Reputationsverluste auf Kundenseite führen zu Umsatzverlusten und können dem Unternehmen nachhaltig schaden.

Aber muss das so sein? Muss das so weh tun? Kann man die Schmerzen und die unangenehmen Folgen lindern oder vielleicht sogar komplett vermeiden?

Stellen wir uns zunächst einmal die Frage: Was läuft eigentlich falsch?

Leider erlebe ich oft genug, dass sich zu Beginn der Produktentwicklung – also zu Beginn des eigentlichen Software-Entwicklungsprojekts –  weder die Auftraggeber noch die Projektdurchführenden intensiv genug Gedanken über die spätere Wartung und Weiterentwicklung machen. Aus diesem Grund berücksichtigten die beteiligten Teams und Stakeholder das Thema nicht in angemessener Weise, und auch die zur Entwicklung der Software verwendeten Prozesse beachten es kaum.

Grafik Software-Produktlebenszyklus

Abb. 1: Software-Produktlebenszyklus

Softwareprodukte folgen in etwa dem im obigen Bild dargestellten Produktlebenszyklus. In der Einführungsphase erstellt das, in der Regel einige Entwickler starke, Projektteam initial die Software. Bis zur Produktivsetzung ist das Team voll fokussiert auf die Fertigstellung des Produkts. Nach der Produktivsetzung übernimmt das Projektteam häufig dann auch zunächst die Wartung und Weiterentwicklung im Übergang in die Wachstumsphase. Früher oder später wird dann aber das Entwicklungsteam vom Produkt abgezogen und die Wartung an eine andere Organisationseinheit und andere Entwickler übergeben. Diese sollen dann in der Reifephase die Wartung, Pflege und Weiterentwicklung übernehmen.

Solange das Projektteam noch die Wartung und Weiterentwicklung übernimmt, treten in der Regel kaum Probleme auf. Da neben der Entwicklung neuer Features auch immer mal wieder Wartungsfälle zu behandeln sind, sinkt naturgemäß die Produktivität etwas. Gut aufgesetzte Prozesse helfen hier zwischen den unterschiedlichen Aufgabentypen zu vermitteln und Reibungsverluste gering zu halten. Das Projektteam kennt die (selbstentwickelte) Software in- und auswendig. Fehler werden schnell gefunden und Risiken bei der Behebung sind bekannt und können adäquat berücksichtigt werden.

Spätestens beim mehr oder weniger geplanten Übergang an ein Wartungsteam fangen dann aber die Probleme an:

  • Die Software ist nicht wirklich wartbar.
  • Es fehlen ausreichende und automatisierte Tests.
  • Die Dokumentation ist nicht geeignet, um den Entwicklern die benötigten Informationen zu liefern.

Die Liste lässt sich fast beliebig fortführen. Nicht zu unterschätzen ist darüber hinaus, dass die Reifephase und somit die Wartung in der Regel einen deutlich längeren Zeiträume umfassen wird, als die beiden vorherigen Phasen. Die Einführungs- und Wachstumsphase der Individualsoftware dauert oft nicht länger als ein bis zwei Jahre. Es ist aber nicht unüblich, die Software im Anschluss an diese Phasen über Jahre hinweg zu verwenden und zu betreiben. Nach ein bis zwei Jahren Spaß bei der Entwicklung der Software soll jetzt also ein deutlich längerer frustrierender Zeitraum der Wartung und Weiterentwicklung folgen? Das muss nicht so sein!

Stellen wir uns also die nächste Frage: Was ist zu tun?

Allgemeingültige Empfehlungen kann es nicht geben. Alles ist individuell:

  • Die zu entwickelnde Software ist per Definition individuell.
  • Die Organisationen, die die Software erstellen und verwenden, sind individuell.
  • Fertigungstiefen und Arten der Zusammenarbeit zwischen Kunden, Fachabteilungen, IT und Dienstleistern sind sehr individuell.

Immer gleich bleibt aber, dass alle Beteiligten schon frühzeitig, also beim Aufsetzen des Software-Entwicklungsprojekts, über Softwarewartung nachdenken sollten. Häufig erlebe ich in Projekten, dass diese Überlegungen ausbleiben. Dies wird von den Verantwortlichen dann damit begründet, dass ja zu diesem frühen Zeitpunkt noch gar nicht absehbar sei, was in ein bis zwei Jahren passieren werde. Auch wenn exakte Prognosen schwierig bis unmöglich sind, sollte dieser Umstand die Kunden, die Auftraggeber und das Projektteam aber nicht davon abhalten unter bestimmten Annahmen zumindest grobe Festlegungen zu treffen. Diese sind dann im Sinne einer agilen Planung fortwährend zu überprüfen und immer wieder anzupassen.

Alle Projektbeteiligten sollten auf jeden Fall folgende Fragestellungen beachten:

  • Welche Änderungshäufigkeit wird erwartet?
    Ist das Umfeld eher stabil oder sind aufgrund von Änderungen an Geschäftsmodellen, Geschäftsprozessen oder aber auch neuen gesetzliche Anforderungen regelmäßige Anpassungen zu erwarten?
  • Wie soll die Wartung organisatorisch aufgesetzt werden?
    “You build it, you run it” durch das Entwicklerteam oder aber ein Übergang an ein Wartungsteam? Vielleicht auch eine Kombination aus beiden Ansätzen? Existiert das für die Wartung vorgesehene Team bereits? Falls nein, wann und wie wird es aufgebaut? Ist ein Übergang in der Verantwortung von einem Dienstleister oder zu einem Dienstleister geplant?
  • Wie kann Wissen erhalten und weitergeben werden?
    Wie kann verhindert werden, dass das Wissen aufgrund eines Wechsels in der Zuständigkeit verloren geht? Welche Dokumentation soll entstehen, um die Software später warten zu können? Wie bleibt diese Dokumentation aktuell?
  • Wie kann die Software “wartungsfreundlich” entwickelt werden?
    Wie können Werkzeuge und Infrastruktur so bereitgestellt werden, dass die Wartung erleichtert wird?
  • Welche Regelungen und Vereinbarungen sollen in Bezug auf Service Level Agreements für den Betrieb getroffen werden?
    Wie wird die Wichtigkeit der Software für das Geschäft des Auftraggebers und wie wird das Nutzungsverhalten der Anwender eingeschätzt? Welche Auswirkungen hat dies auf Organisationsstrukturen und abzuschließende Verträge und bereitzustellende Wartungsbudgets?

Meiner Erfahrung nach hat es sich bewährt, diese Fragestellungen schon beim Aufsetzen der Software-Entwicklungsvorhaben anhand einer Checkliste strukturiert zu prüfen. In diesem Zuge werden dann in Abstimmung zwischen allen Projektbeteiligten erste grobe Annahmen und Festlegungen getroffen. Bei Bedarf werden Maßnahmen und Folgeaktivitäten definiert.

Checkliste codecentric

Abb. 2: Auszug aus einer bei codecentric verwendeten Checkliste

In regelmäßigen Abständen und zu bestimmten Meilensteinen im Produktlebenszyklus, wie zum Beispiel der Produktionseinführung, holt das Projektteam die Checkliste erneut hervor und aktualisiert die Maßnahmen auf Basis der neuen,  mit ziemlicher Sicherheit veränderten Situation. Beim Übergang der Wartungsverwantwortung an ein Wartungsteam erfolgt diese Aktualisierung natürlich zusammen mit eben diesem Wartungsteam.

Und eine letzte Frage: Welche konkreten Maßnahmen können die Projektverantwortlichen festlegen?

Was aber kann Software nun wartbarer machen? Was sorgt dafür, dass Sie der Wartungshölle entgehen oder zumindest die Temperaturen in dieser erträglich halten können? Im Folgenden stelle ich exemplarisch und ohne ins Detail zu gehen ein paar Lösungsansätze für die oben stehenden Fragestellungen dar. Es sei noch einmal betont, dass es aufgrund der hohen Individualität keine allgemeingültigen Best Practices geben kann.

Erzeugen Sie wartbare, gut strukturierte Software:

Beachten Sie bei der Entwicklung der Software die Prinzipien des Softwarecraftmanships. Denken Sie vor allem an regelmäßige Aktualisierungen in Bezug auf Libraries und Tools, an Refactoring und den Abbau beziehungsweise die Kontrolle von technischen Schulden.

Setzen Sie auf Automatisierung:

Versuchen Sie einen hohen Automatisierungsgrad in Bezug auf Tests, Provisionierung von Entwicklungsumgebungen, CI und CD zu erreichen. Setzen Sie auf DevOps-Ansätze und auf flexible und skalierbare Infrastrukturen. Denken Sie rechtzeitig an Applikationsmonitoring in Ergänzung zum in der Regel berücksichtigten Infrastrukturmonitoring.

Sorgen Sie für eine gute Wissensverteilung:

Verteilen Sie Wissen gezielt, und vermeiden Sie Kopfmonopole. Übergeben Sie Wissen nicht über Schulungsveranstaltungen, sondern durch die gemeinsame Bearbeitung konkreter Aufgabenstellungen. Erzeugen sie eine adäquate Dokumentation (“So viel wie nötig, so wenig wie möglich”), und halten Sie diese aktuell.

Definieren Sie klare Zuständigkeiten:

Führen Sie Überlegungen zu Teamstrukturen und Prozessen durch. Setzen Sie dabei aber bitte auf leichtgewichtige und flexible Lösungen. Verwenden Sie zum Beispiel Kanban anstelle von Scrum, um auf kontinuierliche Verbesserung zu setzen.

Erzeugen Sie ein handlungsfähiges und motiviertes Wartungsteam:

Investieren Sie in Ihre Mitarbeiter. Denken Sie an Aus- und Weiterbildung. Setzen Sie auf Mitarbeiter mit hoher Problemlösungsfähigkeit (“T-Shaped People”) und stellen Sie die Verfügbarkeit von Spezialisten zur Lösung von Spezialproblemen sicher.

Fazit

Es gibt  für die Wartung von Individual-Software leider keine allgemeingültigen Best Practices. Dies darf aber nicht als Entschuldigung dafür dienen, das Thema so lange unberücksichtigt zu lassen, bis es zu spät ist und wir uns dann sprichwörtlich in der Wartungshölle wiederfinden. Es geht nicht darum allgemeingültig zu definieren, wie mit dem Thema umgegangen werde soll. Vielmehr ist es wichtig frühzeitig und rechtzeitig erste Überlegungen anzustellen und diese fortwährend zu hinterfragen und zu aktualisieren. Berücksichtigen Sie also die Aspekte der Wartung von Individual-Software rechtzeitig, angemessen und ganzheitlich. Nur so können Sie die Schmerzen und den Frust in der Wartungsphase Ihrer Softwareprodukte verringern. Nur so kann Wartung gelingen und dann sogar Spaß machen.

Übrigens: Dieser Blog Post erschien ursprünglich in der Spezialausgabe „Digitalisierung“ des codecentric Softwerker-Magazins. Warum ein ganzes Heft zum Thema Digitalisierung? Weil der Umstand, dass die Digitalisierung unsere Wirtschaft in vielen Bereichen verändert kein Märchen, nicht nur „the next big thing“ und kein leeres Buzzword Bingo darstellt. 
Jetzt die Ausgabe kostenlos anfordern.

The post Wartungshölle? Nein, danke! appeared first on codecentric AG Blog.

Ansible zaubert Spring Boot Apps auch auf Windows

$
0
0

Manchmal kommt es tatsächlich vor, dass wir unsere Spring Boot Apps auf Windows ausführen müssen, anstatt wie gewohnt auf Linux. Das passiert insbesondere dann, wenn wir native Bibliotheken aufrufen müssen, die Windows voraussetzen. Trotzdem sollten wir dafür nicht auf unsere liebgewonnenen DevOps-Tools wie Ansible verzichten müssen!

Windows? Kein Problem. Aber nicht ohne Ansible!

Es kann doch heute kein Problem mehr darstellen, unsere Anwendungen auf Windows laufen zu lassen – oder?! Das konkrete Betriebssystem sollte nur noch eine untergeordnete Rolle spielen. Viel wichtiger ist, dass wir uns nicht von unseren Prinzipien moderner Softwareentwicklung abbringen lassen – sei es Continuous Integration (CI) und Deployment (CD) oder die Automatisierung von sich wiederholenden Aufgaben im Infrastrukturbereich. Dabei kann es sich z.B. um das Aufsetzen neuer Server oder auch die Provisionierung unserer Anwendungen handeln.

In unserer CI-Pipeline nutzen wir Jenkins um unsere Spring Boot Apps zu bauen und zu testen. Per Ansible provisionieren wir unsere (Linux) Maschinen und lassen unsere Apps auf ihnen laufen. Genau das wollen wir auch für Windows Server, wenn wir schon auf sie angewiesen sind.

Klingt nach Träumereien? Ansible war doch dieses Unixoide DevOps-Tool, dass ohne Agent auf den Servern auskommt und per SSH mit ihnen spricht, oder?! Wie soll das denn mit Windows funktionieren? Und Jenkins läuft auf Linux. Wie soll dieses Toolset in der Lage sein, Windows Umgebungen zu managen??!

windows_is_coming

Die Antwort ist einfach: Seit Version 1.7 ist Ansible in der Lage, auch Windows Server zu provisionieren. Statt SSH kommt hier freilich PowerShell remoting (aka Windows Remote Management WinRM) zum Einsatz. Hört sich gut an? Dann sollten wir das direkt mal ausprobieren!

Startpunkt: eine Windows Vagrant Box

Zu allererst benötigen wir natürlich eine Windows Maschine für unsere ersten Gehversuche mit Ansible. Falls man also gerade keine rumstehen hat, könnte sich ein Abstecher auf die Microsoft developer sites lohnen. Ziemlich überaschend bietet Microsoft dort nämlich ein Vagrant Image zum Download an! Auf der Seite https://developer.microsoft.com/en-us/microsoft-edge/tools/vms wählt man eine virtuelle Machine aus – wie z.B. die Microsoft Edge on Windows 10 Stable (15.xxx) – und klickt auf Vagrant im „Select platform“-Feld. Wichtig: man benötigt eine Vagrant-Installation sowie eine Virtualisierungsoftware auf dem eigenen Rechner. Für eigene Experimente anhand dieses Blogartikels kann das frei verfügbare VirtualBox empfohlen werden.

Nach dem Download kann das MSEdge.Win10.RS2.Vagrant.zip direkt entpackt werden. Damit sind wir fast am Ziel. Da Microsoft der Vagrant Box MSEdge - Win10_preview.box keine Metadaten mit auf den Weg gibt, müssen wir sie selbst hinzufügen. Das ist mit Hilfe eines Vagrantfile kein Problem – so wird die Konfigurationsdatei für Vagrant genannt. Für den schnellen Start liegt in diesem Beispielprojekt auf GitHub schon das fertige Vagrantfile bereit:

Vagrant.configure("2") do |config|
  config.vm.box = "windows10"
  config.vm.guest = :windows

  # Configure Vagrant to use WinRM instead of SSH
  config.vm.communicator = "winrm"

  # Configure WinRM Connectivity
  config.winrm.username = "IEUser"
  config.winrm.password = "Passw0rd!"

  config.vm.provider "virtualbox" do |vb|
     # Display the VirtualBox GUI when booting the machine
     vb.gui = true
   end
end

Weil wir mit Hilfe von Vagrant eine Windows Maschine managen, müssen wir natürlich auch die Konfiguration darauf ausrichten. Per config.vm.communicator = "winrm" wird beispielsweise WinRM statt SSH konfiguriert. Außerdem müssen die korrekten User-Credentials konfiguriert werden, die man etwas versteckt in der Installations-Beschreibung der Microsoft Developer Seite findet. Weitere Konfigurationsoptionen zu Windows finden sich auch in der Vagrant WinRM Dokumentation.

Anschließend müssen wir die Vagrant Box noch der lokalen Vagrant-Installation hinzufügen:

vagrant box add "MSEdge - Win10_preview.box" --name "windows10"

Nach ein paar Sekunden sollte nun ist alles bereit sein, um ein virtuelles Windows 10 per vagrant up auf der Kommandozeile zu starten. Das Importieren der neuen Windows Vagrant Box wird dabei im Hintergrund angestoßen und kann eine Weile dauern. Danach bootet die Windows VM:

Leider vergisst Microsoft bei der eigenen Vagrant Box ein paar grundlegende Dinge, damit diese auch ohne Probleme funktioniert. Denn wie man vielleicht schon bemerkt hat, führt ein unvoreingenommenes vagrant up zu einem „Timed out while waiting for the machine to boot […]“. Das liegt an der Konfiguration der Network List Management Policies, die einen Zugriff per Windows Remote Management (WinRM) verhindern.

Doch dem kann man schnell Abhilfe verschaffen. Dazu einmalig nach dem ersten Start der Vagrant Box in die Local Security Policys gehen und darin in die Network List Management Policies wechseln. Dort auf Network klicken und im Tab Network Location den Location type auf private und die User permissions auf User can change location setzen. Danach noch schnell auf die PowerShell wechseln und winrm quickconfig ausführen. Nun sollte das vagrant up so funktionieren wie gedacht. Es wäre natürlich schön, wenn uns diese Arbeit schon Microsoft abnehmen würde.

Windows für Ansible vorbereiten

Damit Ansible mit der neuen Windows Maschine zusammenarbeiten kann, sind noch ein paar Schritte zu tun. Dabei gilt grundsätzlich: Je aktueller die Windows-Version, desto weniger ist zu tun. Wenn man beispielsweise auf eine ganz junge Version wie die oben genannte Vagrant Box von developer.microsoft.com setzt, muss man sich keine Gedanken machen. Weil Ansible minimal PowerShell 3.0 voraussetzt und Windows 10 mit 5.0 out-of-the-box kommt, muss lediglich das Windows-Konfigurationsskript für Ansible einmalig ausgeführt werden. Dabei werden alle für´s korrekte Powershell remoting notwendigen Konfigurationen aktiviert – inkl. WinRM und entsprechenden Firewallregeln. Am einfachsten läd man das Skript mit folgendem Befehl auf einer PowerShell mit administrativen Rechten herunter, der es nebenbei auch gleich noch ausführt:

iwr https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -UseBasicParsing | iex

Bei älteren Windows-Versionen kann es schwieriger werden. Erfolgreich provisioniert wurden im Kundenprojekt beispielsweise Windows 7 Maschinen. Hier muss evtl. die Ausführung von Skripten erstmal erlaubt werden – z.B. mit Hilfe des Set-ExecutionPolicy PowerShell Commandlets:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

Oder es muss die korrekte PowerShell-Version ab 3.0 installiert werden – hierzu auch die Liste der Windows-Versionen und ihre zugehörigen PowerShell-Versionen. Welche das eigene System anbietet, findet man schnell selbst heraus:

get-host

Ein Updrade-Skript auf PowerShell 3.0 hilft dann, die notwendigen Voraussetzungen für Ansible zu erreichen.

Nicht vergessen sollte man auch die Art der Anmeldung. Man kann z.B. Kerberos einsetzen – allerdings ist dies nur in der aktuellsten Ansible Version zu empfehlen. Für den Start tut es auch ein normaler administrativer Account auf der Windows Maschine.

Ansible mit Windows sprechen lassen…

Damit ist alles vorbereitet, um mit Ansible loszulegen. Das erste sollte immer ein Test der Verbindung per Ansible sein. Dazu benötigt man ein korrekt konfiguriertes Ansible playbook. Das Beispielprojekt auf GitHub enthält alles Notwendige. Im hostsfile sollte die korrekte IP konfiguriert sein – in unserem Fall mit der lokalen Vagrant Box natürlich 127.0.0.1. Die Konfigurationsdatei restexample-windows-dev.yml aus dem Beispielprojekt enthält die notwendigen Parameter für eine erfolgreiche Verbindung von Ansible mit Windows:

ansible_user: IEUser
ansible_password: Passw0rd!
ansible_port: 55986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore

Zusammen mit der laufenden Windows 10 Vagrant Box ist nun alles bereit für einen ersten Verbindungstest. Empfehlenswert ist hier das Ansible Modul win_ping – eines der vielen Ansible Windows Module. Voraussetzung für die Ausführung von Ansible-Befehlen ist natürlich eine lokal lauffähige Version. Idealer Weise handelt es sich um ein möglichst aktuelles Ansible Release. Auf einem Mac erledigt man die Ansible-Installation beispielsweise elegant per homebrew: brew install ansible. Neben dem ebenfalls unproblematischen Linux, stellt Windows als Ansible Host selbst schon ein größeres Problem dar. Hier wird aber sicher das neue Linux-Subsystem gute Hilfestellung leisten können…

Um die Verbindung von Ansible zu Windows dann endlich zu testen, genügt der folgende Befehl innerhalb des zuvor geclonten Beispielprojekts ansible-windows-springboot:

ansible restexample-windows-dev -i hostsfile -m win_ping

Wird man hier direkt mit einem SUCCESS belohnt ist alles in Ordnung:

127.0.0.1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Falls man allerdings mit einem UNREACHABLE! konfrontiert wird, geht die Ursachenforschung los. Und diese kann leider aus der Erfahrung heraus schnell ausarten und für eine Menge Frust sorgen. Neben den erwähnten Voraussetzungen und einer möglichst aktuellen Windows Version hat sich noch ein Tipp bewährt: das (auch gern mehrmalige) Überprüfen der Credentials hilft manchmal Tippfehler zu finden. Falls es zu Timeouts kommt, sollte nochmals ein genauer Blick dem Kapitel Windows für Ansible vorbereiten gelten.

Eine lauffähige Spring Boot App…

Wenn eine Spring Boot App auf Windows zum Laufen gebracht werden soll, braucht man natürlich auch eine solche 🙂 Das ist freilich der einfache Teil. Entweder man legt sich mit ein paar Minuten Zeitaufwand eine eigene an – z.B. mit Hilfe des Spring Initializr und/oder einer der sehr empfehlenswerten Spring Starter Guides. Oder man hat sowieso eine lauffähige Anwendung parat. Falls beides nicht zutrifft, kann auch gern auf die hier verwendete Spring Boot App zurückgegriffen werden: ein zugegebenermaßen simpler REST Service.

Egal welcher Weg gewählt wird: am Ende sollte eine lauffähige Spring Boot jar-Datei bereitstehen, die sich per gewohntem java -jar JarDateiName.jar starten lässt. Im Beispielprojekt erzeugt man das benötigte restexamples-0.0.1-SNAPSHOT.jar per Maven auf der Kommandozeile:

mvn clean package

Empfehlungen für ein unbesorgtes Leben mit Ansible & Windows

Bevor man mit der Erstellung erster eigener playbooks zur Provisionierung von Windows beginnt, hilft es, dabei ein paar Punkte im Hinterkopf zu haben. Auch wenn man bereits Erfahrung mit dem Management von Linux Maschinen per Ansible hat, ist einem das ein oder andere evtl. nicht bewusst:

Auf die neueste Ansible-Version updaten: Der Ansible Windows-Support wird aktuell mit jedem Release massiv ausgebaut und verbessert. Das zeigt sich auch daran, dass viele der Windows Module nur mit der neuesten Ansible Version verfügbar sind.

Die Ansible-Dokumentation für Windows hat leider nicht den gewohnt großen Umfang wie für Linux… Hier soll niemand vor den Kopf gestoßen werden – das Ansible Team leistet großartige Arbeit! Aber man muss sich bewusst sein, dass Ansible zwar schon sehr gut in der Praxis mit Windows nutzbar ist. Aber es kann eben doch an einigen Stellen passieren, dass erstmal viele Wege (und Module!) probiert werden wollen, bis das gewünschte Ergebnis erreicht wird.

Bitte IMMER die Backslashes in den Pfaden per vorangestelltem Backslash escapen Hat man beispielsweise einen Pfad wie C:\temp, dann sollte das im playbook unbedingt so aussehen (auch, wenn die Doku nicht explizit darauf hinweißt):

"C:\\temp"

Pfade wie C:\ProgramFiles (x86)\XYZ werden nicht funktionieren Besonders in unserem Fall ist das sehr wichtig, weil wir ein Java Runtime Environment (JRE) benötigen, um unsere Spring Boot- bzw. Java-Anwendung starten zu können. Falls man hier eine installierte Variante nutzen will, sollte man auf alternative Pfade ausweichen – wie Oracle z.B. nach einer erfolgreichen JRE-Installation auf dem System einrichtet:

"C:\\ProgramData\\Oracle\\Java\\javapath\\java.exe"

Ein vollständiges Beispiel

Das Beispielprojekt dieses Artikels beinhaltet auch ein komplettes Ansible playbook. Es zeigt, wie eine Windows Maschine mit Ansible provisioniert und anschließend eine Spring Boot App darauf deployed und ausgeführt werden kann. Um zu verstehen, wie das im Detail funktioniert, lohnt ein genauerer Blick. Zuerst bereiten wir unsere Windows Vagrant Box vor, damit wir später die Anwendung deployen können:

- hosts: "{{host}}"
  vars:
    spring_boot_app_path: "C:\\spring-boot\\{{spring_boot_app_name}}"
    path_to_java_exe: "C:\\ProgramData\\Oracle\\Java\\javapath\\java.exe"

  tasks:
  - name: Create directory C:\spring-boot\spring_boot_app_name
    win_file: path={{spring_boot_app_path}} state=directory

  - name: Install nssm (non-sucking service manager) via chocolatey
    win_chocolatey:
      name: nssm

Nachdem ein paar benötigte Pfade definiert wurden, erstellen wir ein Verzeichnis für unsere Spring Boot App und installieren den Non-Sucking Service Manager (nssm) mit Hilfe des Windows Package Managers Chocolatey. Beide sind später sehr hilfreich für das Arbeiten mit unserer Windows Maschine.

Chocolatey bringt die Möglichkeiten eines Package Managments in die Windows-Welt, welche man unter Linux und Mac bereits liebgewonnen hat. Und nssm ermöglicht später den Betrieb unserer Spring Boot App als echten Windows Service. Mit all den daraus resultierenden Vorteilen wie z.B. Statusabfrage und automatischen Restarts nach Reboots. Nach einer ganzen Reihe an Experimenten mit verschiedensten Möglichkeiten stellte sich diese Lösung als sehr elegant heraus.

Der Sinn der nächsten Schritte im playbook erschließt sich vielleicht nicht auf den ersten Blick:

  - name: Stop Spring Boot service, if there - so we can extract JRE & other necessary files without Windows file handle problems
    win_service:
      name: "{{spring_boot_app_name}}"
      state: stopped
    ignore_errors: yes

  - name: Install Java Runtime Environment (JRE) 8 via chocolatey
    win_chocolatey:
      name: jre8

  - name: Copy Spring Boot app´s jar-File to directory C:\spring-boot\spring_boot_app_name
    win_copy:
      src: "{{spring_boot_app_jar}}"
      dest: "{{spring_boot_app_path}}\\{{spring_boot_app_name}}.jar"

Das beginnt schon damit, dass wir den Windows Service stoppen, der unsere Spring Boot App managed. Das wirkt sicher erstmal etwas komisch. Aber es hat auch nichts mit der ersten Ausführung des playbooks zu tun – dafür aber mit allen folgenden. Windows bringt nämlich ein äußerst beliebtes Feature namens sharing violation error mit. Wenn ein laufender Prozess ein „handle“ auf eine Datei oder ein Verzeichnis hält, dann lässt Windows nicht zu, dass diese geändert oder entfernt werden. Aber genau das ist ja, was wir tun wollen: Um das JRE zu updaten, müssen wir in der Lage sein, andere Dateien unserer Anwendung zu verändern. Hört sich also ganz nach einer weiteren Empfehlung an: Bevor Dateien geändert oder gelöscht werden sollen, IMMER die Windows-Prozesse oder -Services stoppen!

Wie gesagt trifft dies aber alles nicht auf die erste Ausführung des playbooks zu – diese würde abbrechen, denn der Service existiert ja noch gar nicht. Genau dafür gibt es aber ein nützliches Ansible-Feature: Wir ignorieren einfach einen etwaigen Fehler in der Modul-Ausführung per ignore_errors: yes. Auf diese Weise wird der Service gestopped, falls er bereits installiert ist und wir umgehen den sharing violation error. Oder aber das win_service Modul reagiert mit einem Fehler, den wir geflissentlich ignorieren können, da wohl noch kein Service installiert wurde.

Danach kann dann das JRE heruntergeladen und entpackt werden – bzw. wie in unserem Fall einfach das Chocolatey Paket jre8 installiert werden. Zuletzt wird dann noch die .jar-Datei unserer Spring Boot Anwendung auf die Windows Maschine kopiert.

Installation und Konfiguration des Windows Service

Endlich können wir unsere Spring Boot App als Windows Service installieren und laufen lassen:

  - name: Install Spring Boot app as Windows service (via nssm), if not already there - but remain stopped to configure Application directory
    win_nssm:
      name: "{{spring_boot_app_name}}"
      application: "{{path_to_java_exe}}"
      app_parameters_free_form: "-jar {{spring_boot_app_path}}\\{{spring_boot_app_name}}.jar"
      state: stopped

  - name: Set the Application path for the Spring Boot app to the folder where the needed native libraries reside
    raw: nssm set {{spring_boot_app_name}} AppDirectory {{spring_boot_app_path}}

  - name: Fire up Spring Boot app Windows service
    win_service:
      name: "{{spring_boot_app_name}}"
      state: restarted

Dazu definieren wir einen Windows Service mit Hilfe des zuvor installierten nssm und dem Ansible Modul win_nssm. Wichtig hierbei ist der Pfad zur java.exe in der Option application und das -jar spring-boot-app.jar innerhalb der app_parameters_free_form (vor Ansible 2.3 hat das auch mit den app_parameters funktioniert, was jetzt aber auf einen sehr komischen Data line ‚System.Collections.Hashtable‘ is not in ’name=value‘ format.-Fehler läuft). Den Status setzen wir kurzerhand auf stopped – allerdings nur vorübergehend, da wir noch eine andere nssm Service Option konfigurieren wollen.

Dies tun wir im nächsten Schritt. Die nssm Service Option AppDirectory kann sehr wichtig sein, falls die Spring Boot Anwendung native Bibliotheken wie z.B. dll-Dateien im selben Verzeichnis erwartet, in dem sie läuft. Diese nssm Option kann manuell auf der Kommandozeile per nssm edit servicename konfiguriert werden. Der Befehl öffnet daraufhin einen Konfigurationsdialog:

nssm_startup_directory

Aber wir benötigen diesen Schritt natürlich automatisiert innerhalb unseres Ansible Skripts. Dazu müssten wir an den Wert der Variable Startup Directory herankommen. Doch leider bietet das win_nssm Modul dafür keine Konfigurationsoption, weshalb wir auf das raw Modul ausweichen müssen. Mit dem kaum dokumentierten Befehl nssm set servicename AppDirectory path konfigurieren wir das Startup Directory per Ansible.

Im letzten Schritt nutzen wir dann einfach das Modul win_service um unsere Spring Boot Anwendung als korrekten Windows Service zu starten – und dafür zu sorgen, dass dieser auch nach einem Reboot ebenfalls wieder hochgefahren wird.

Nun ist es so weit: Wir können das playbook selbst auszuprobieren! Vorausgesetzt, die Windows Vagrant Box läuft noch, startet der folgende Befehl unser playbook mit dem eben beschriebenen Ablauf:

ansible-playbook -i hostsfile restexample-windows.yml --extra-vars "spring_boot_app_jar=../restexamples/target/restexamples-0.0.1-SNAPSHOT.jar spring_boot_app_name=restexample-springboot host=restexample-windows-dev"

Das Skript sollte in etwa folgenden Output produzieren:

running_ansible_playbook_windows

Smoketest

Der geneigte Leser hat es vielleicht bemerkt: Wir haben den letzten Schritt des playbooks nicht diskutiert. Doch der ist durchaus wichtig:

  - name: Wait until our Spring Boot app is up & running
    win_uri:
      url: "http://localhost:8080/swagger-ui.html"
      method: GET
    register: result
    until: result.status_code == 200
    retries: 5
    delay: 5

Es hat sich in der Praxis bewährt zuletzt immer noch zu überprüfen, ob die Anwendung auch korrekt läuft. Dazu kann das Ansible Modul win_uri zum Einsatz kommen. Da unsere Beispielanwendung für einen einfachen Zugriff auf die REST Services SpringFox nutzt, können wir auf die entsprechend generierte Weboberfläche einen einfachen HTTP GET ausführen. Manuell kann man das auch im eigenen Browser bei laufender Anwendung auf http://localhost:8080/swagger-ui.html ausprobieren. In unserem playbook gehen wir einfach davon aus, dass unsere Anwendung läuft. Genauso gut kann man aber auch den Spring Boot Actuator Endpoint /health benutzen – dafür sind dann nur die entsprechenden Abhängigkeiten in der pom.xml einzutragen.

Endlose Möglichkeiten

Nun können wir unsere Spring Boot Anwendungen mit Hilfe von Ansible elegant auf Windows Maschinen laufen lassen – und sind bereit, auch weitaus komplexere Szenarien anzugehen – wie sie in der Praxis natürlich häufig vorzufinden sind. Wie wäre es z.B. mit mehreren Microservices auf Basis von Spring Boot und Spring Cloud? Mit Hilfe von Ansible sind wir nun in der Lage, reproduzierbar die kompliziertesten Anforderungen an unsere Infrastruktur abzubilden. Und das auch auf Windows Maschinen – ohne dabei unsere Prinzipien moderner Softwareentwicklung aufzugeben.

The post Ansible zaubert Spring Boot Apps auch auf Windows appeared first on codecentric AG Blog.

Hilfe, mein Container zickt!

$
0
0

Code-Beispiele mit Testinfra: So testen Sie Docker-Images und vermeiden böse Überraschungen in Containern.

Bei Anwendungen, die in Docker-Containern laufen, verlagert sich ein guter Teil des Infrastruktur- und auch des Applikationssetups in die Container. Dieser Part wird oft weder durch Infrastrukturtests noch durch die fachlichen Tests der Anwendung abgedeckt. Dies kann zu bösen Überraschungen führen, wenn ein Fehler im Docker-Image selbst begründet liegt. Die Fehlersuche gestaltet sich oft langwierig und schwierig.

Es ist jedoch durchaus möglich zu testen, ob Images und die aus ihnen erzeugten Container korrekt aufgebaut sind. Im Gegensatz zu Infrastrukturtests, welche den tatsächlichen Status laufender Infrastruktur testen, kann ein Entwickler auf diese Weise Tests bereits zur Entwicklungszeit ausführen. Ebenso können die Tests in den Build-Prozess eines Images integriert werden, und so Regressionen vermeiden.

Damit schließt sich die Lücke zwischen den fachlichen Tests einer containerisierten Anwendung und der Infrastruktur, auf der diese Anwendung läuft.

In diesem Artikel zeige ich anhand von konkreten Code-Beispielen, wie Sie solche Tests mit Hilfe von Testinfra schreiben können. Sie werden lernen, wie Sie

  • Tests gegen einen laufenden Container ausführen,
  • Images zur Test-Zeit bauen und Container programmatisch starten
  • sowie Images testgetrieben entwickeln.

Als Beispiel dient ein Team aus Entwicklerinnen und Entwicklern, welches das offizielle Jenkins-Image testen und an eigene Bedürfnisse anpassen möchte.

Einen laufenden Container testen

Im offiziellen Jenkins-Container startet ein Java-Prozess unter dem Benutzer jenkins. Unser Beispiel-Team möchte sicherstellen, dass es dieses grundlegende Setup nicht durch eigene Anpassungen gefährdet. Das Team nutzt dazu Testinfra, ein Tool zum Testen von Infrastruktur. Es basiert auf der Programmiersprache Python und dem Test-Framework pytest.

Eine Entwicklerin des Teams schreibt die folgenden beiden Testinfra-Tests:

# ./tests/image_test.py
import pytest

def test_current_user_is_jenkins(host):
    assert host.user().name == "jenkins"
    assert host.user().group == "jenkins"

def test_jenkins_is_running(host):
    jenkins = host.process.get(comm="java")
    assert jenkins.args == "java -jar /usr/share/jenkins/jenkins.war"
    assert jenkins.user == "jenkins"

Der erste Test stellt sicher, dass der Benutzer jenkins existiert und dass er als aktueller Benutzer gesetzt ist.
Der zweite Test gewährleistet, dass der Jenkins-Prozess läuft und die korrekte Benutzerkennung hat. Die Tests stellen also sicher, dass das Jenkins-Image sich wie erwartet verhält, und dieses Verhalten durch spätere Anpassungen nicht beeinträchtigt wird.

Die Tests setzen voraus, dass ein Jenkins-Container läuft. Der folgende Befehl startet diesen:

docker run --rm --name=jenkins_test_container jenkins

Anschließend startet testinfra mit dem Connection-Backend docker die Tests. Mit dem --hosts Parameter kann dabei definiert werden, gegen welchen Container die Tests ausgeführt werden:

testinfra --connection docker --hosts=jenkins_test_container

Alternativ kann der zu testende Container über die Variable testinfra_hosts im Test-Modul angegeben werden:

import pytest

testinfra_hosts = ["docker://jenkins_test_container"]

Dadurch ist es möglich, verschiedene Container in unterschiedlichen Modulen zu testen. Die Tests können dann einfach mit dem Kommando testinfra oder pytest gestartet werden.

Container bauen und testen

Praktischer ist es, wenn das Test-Modul den Container programmatisch startet. Dies geht mit Hilfe der Bibliothek docker-py problemlos:

#./tests/image_test.py
import pytest
import docker

testinfra_hosts = ["docker://jenkins_test_container"]

@pytest.fixture(scope="module", autouse=True)
def container():
    client = docker.from_env()
    container = client.containers.run('jenkins', name="jenkins_test_container", detach=True)
    yield container
    container.remove(force=True)

Diese Codezeilen definieren ein Test-Fixture, das vor den Tests einen Container startet und diesen im Nachgang wieder entfernt. Der Parameter scope="module" sorgt dafür, dass nur ein Container für das gesamte Modul gestartet wird. Andernfalls würde jeder einzelne Test einen Container erzeugen und wieder entfernen. autouse=True bewirkt, dass das Fixture erzeugt wird, obwohl die Tests es nicht explizit referenzieren.

Das Team hat mit dieser Test-Suite nun ein gutes Fundament, um ein angepasstes Jenkins-Image zu testen. Einer der Entwickler scheibt folgendes Dockerfile, um ein neues Image auf Basis von jenkins zu definieren:

# ./src/Dockerfile
FROM jenkins
MAINTAINER John Doe 

Das Beispiel nimmt noch keine Anpassungen vor. Im ersten Schritt sollen die bestehenden Tests gegen dieses neue Image laufen. Die Bibliothek docker-py kann das Image zur Laufzeit der Tests bauen. Ein Session-scope Fixture in der Datei conftest.py baut das Image einmalig – vor allen Tests des Projekts:

#./tests/conftest.py
import docker
import pytest

@pytest.fixture(scope="session")
def client():
    return docker.from_env()

@pytest.fixture(scope="session")
def image(client):
    return client.images.build(path='./src')

Das erste Fixture erzeugt zunächst einen Docker-Client, der im zweiten Fixture das Image baut. Die build-Funktion greift dazu auf das Dockerfile im src-Ordner zu.

Das container-Fixture aus dem Test-Modul muss nun natürlich das frisch gebaute Image verwenden:

# ./tests/image_test.py
@pytest.fixture(scope="module", autouse=True)
def container(client, image):
    container = client.containers.run(image.id, name="jenkins_test_container", detach=True)
    yield container
    container.remove(force=True)

Die beiden Fixtures aus conftest.py werden per Namenskonvention in das container-Fixture hinein gereicht. Der Docker-Client startet dort nun einen Container auf Grundlage des zuvor gebauten Images.

Testgetriebene Container-Entwicklung

Die Entwicklerin beginnt nun damit, die Funktionen des Jenkins-Image zu erweitern.
Ganz im Sinne testgetriebener Entwicklung, kann sie die Anforderungen in Form eines Tests abbilden:

# ./tests/image_test.py
def test_maven_is_installed(host):
    assert host.package("maven").is_installed

Da das Team Maven-Projekte bauen möchte, muss Maven installiert sein. Der Test prüft mittels host.package, ob das maven Paket installiert ist. Intern wird dazu die Paketverwaltung des Images verwendet. In diesem Beipiel ist es dpkg. Weil das Jenkins-Image die Anforderung noch nicht erfüllt, schlagen die Tests fehl. Testinfra gibt die Fehlermeldung aus, die im Container aufgetreten ist:

Failed: Unexpected exit code 1 for CommandResult(command="dpkg-query -f '${Status}' -W maven", exit_status=1, stdout=None, stderr='dpkg-query: no packages found matching maven\n')

Um dies zu korrigieren, wechselt das Dockerfile per USER-Instruktion zum root Benutzer und installiert anschließend maven:

# ./src/Dockerfile
USER root
RUN apt update && apt install -y maven

Der neue Test wird jetzt grün, jedoch schlagen die anderen beiden Tests fehl. Das Sicherheitsnetz hat funktioniert und warnt davor, dass nun der Benutzer root Jenkins ausführt!

  def test_jenkins_is_running(host):
        jenkins = host.process.get(comm="java")
        assert jenkins.args == "java -jar /usr/share/jenkins/jenkins.war"
>       assert jenkins.user == "jenkins"
E       assert 'root' == 'jenkins'
E         - root
E         + jenkins

Eine weitere USER-Instruktion nach der Installation korrigiert diesen Fauxpas:

# ./src/Dockerfile
USER root
RUN apt update && apt install -y maven
USER jenkins

Nun laufen alle Tests erfolgreich durch!

tests/image_test.py::test_current_user_is_jenkins[docker://jenkins_test_container] PASSED
tests/image_test.py::test_jenkins_is_running[docker://jenkins_test_container] PASSED
tests/image_test.py::test_maven_is_installed[docker://jenkins_test_container] PASSED

================================== 3 passed in 3.31 seconds ==================================

Ausblick

Mit den gezeigten Beispielen hat das Team ein gutes Basis-Setup und kann nach Bedarf weitere Tests schreiben und das Image an die Anforderungen anpassen. Testinfra ist ein geeignetes Werkzeug, um die Änderungen mit Tests abuzusichern.

Es ist auch möglich eine Reihe von Container-Konfigurationen zu testen, indem verschiedene Test-Module unterschiedliche Container-Fixtures nutzen. Dazu kann docker-py zum Beispiel unterschiedliche Umgebungsvariablen setzen, welche den Aufbau des Containers beeinflussen.
Dabei sollten Test-Autoren jedoch berherzigen, das Verhalten des Dockerfiles und nicht das der containerisierten Anwendung zu testen.

Auch komplexe Setups mit untereinander verlinkten Containern sind denkbar. Zum Beispiel könnte docker-py Mock-Container starten, um den zu testenden Container in eine kontrollierte Umgebung zu isolieren.

Fazit

Mit Testinfra können Teams nicht nur Infrastruktur testen. Auch für Docker-Images ist es ein geeignetes Werkzeug. Tests können mit docker-py Images zur Laufzeit bauen und Container starten. Testinfra bietet eine Reihe von Modulen, die den Aufbau dieser Container überprüfen können. Darüber hinaus stehen Entwicklerinnen und Entwicklern alle Möglichkeiten von pytest offen.

Die Beispiele aus diesem Artikel sind auf Github verfügbar.

Exkurs: Testinfra im Container ausführen
Wenn man ohnehin mit Docker arbeitet liegt es nahe, die Tests ebenfalls im Container auszuführen. Das Image [aveltens/docker-testinfra] enthält alle dazu nötigen Abhängigkeiten. Der Source-Code des Projekts und der Docker-Socket des Hostsystems müssen lediglich über ein Volume in den Container einghängt werden:

docker run --rm -t \
  -v $(pwd):/project \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  aveltens/docker-testinfra

The post Hilfe, mein Container zickt! appeared first on codecentric AG Blog.

Do things that don’t scale: MVP ohne Softwareentwicklung – geht das?

$
0
0

Der Begriff Minimum Viable Product (kurz MVP) ist im Mainstream angekommen und wird  insbesondere im Kontext digitaler Produkte gerne verwendet. Im Umfeld der Softwareentwicklung wird der strategische Spielraum zum Einsatz eines  MVP dabei häufig auf die erste Version eines Softwareprodukts reduziert. In diesem Artikel stelle ich eine mögliche Umsetzung eines MVP jenseits von Softwareentwicklung vor und erörtere, warum diese Formen von MVP elementarer Bestandteil im Werkzeugkasten moderner Produktmanager sein sollten.

Der Aufstieg des MVP

In der Digitalisierung spielt neben der Transformation bestehender Geschäftsmodelle, – prozesse und -strukturen vor allem die Innovation, die Suche nach neuen, digitalen Geschäftsmodellen, eine entscheidende Rolle. Amazon, Airbnb oder Tesla, um nur einige wenige bekannte Beispiele zu nennen, drohen, lange etablierte Märkte in ihren Grundfesten zu erschüttern oder haben es bereits.

Um in diesem Wettbewerb der digitalen Innovationen zu bestehen, orientieren sich Unternehmen zunehmend an den schlanken, kundenzentrierten und datengetriebenen Methoden, die in den letzten Jahren durch eben jene und andere massiv erfolgreiche Startups populär wurden. Allen voran ist hier “The Lean Startup” zu nennen, dessen prominentestes Beispiel für eine Konzern-Adaption “FastWorks” des amerikanischen Giganten General Electric ist. Warum identifizieren sich etablierte Unternehmen aber mit einer Methode, die dem Namen nach offensichtlich für Startups entworfen worden ist? Betrachten wir dazu einmal die Definition des Autors, Eric Ries:

A startup is a human institution designed to deliver a new product or service under conditions of extreme uncertainty.

Diese Definition bezieht sich nicht auf Faktoren, wie die Dauer des Bestehens eines Unternehmens, sondern einzig auf die Umstände, in denen eine Unternehmung oder Institution operiert. Damit sind vor allem etablierte Unternehmen, die sich auf neuen oder unbekannten Märkten bewegen, explizit mit eingeschlossen. Eine Tatsache, die auch Eric Ries selber betont. Was hat es also mit dieser Methode auf sich?

Lean Startup ist inspiriert durch zahlreiche bewährte Ideen und Methoden, wie beispielsweise Design Thinking, Agile Engineering, Lean Production/Management oder Customer Development von Steve Blank. Das wichtigste Kernkonzept ist jedoch angelehnt an die “Wissenschaftliche Methode”:

  1. Beobachte und beschreibe ein Phänomen.
  2. Formuliere eine Hypothese, die das Phänomen erklärt.
  3. Verwendet die Hypothese, um die Ergebnisse weiterer Beobachtungen vorherzusagen.
  4. Messe die Qualität der Hypothese und der resultierenden Vorhersage durch angemessene Experimente.

Die Adaption der Wissenschaftlichen Methode nach Lean Startup ist der sogenannte “Build-Measure-Learn” Zyklus.


Abbildung 1: Build-Measure-Learn Zyklus

Hypothesen bzw. Ideen zu einem Produkt oder Geschäftsmodell werden formuliert, es wird ein Experiment implementiert, um diese Ideen zu validieren, und die resultierenden Ergebnisse werden als Input für die nächste Iteration verwendet.

Dieses Vorgehen trägt der Tatsache Rechnung, dass die Entwicklung von Produkten und Services – sobald man unter den zitierten Bedingungen hoher Unsicherheit operiert – immanent durch Annahmen und nicht durch Wissen getrieben ist. Durch rigoroses Testen dieser Annahmen am Zielmarkt wird dieses Wissen erst erworben. Dadurch erhöht sich die Chance, ein perfekt auf den Markt zugeschnittenes Produkt zu entwickeln (Product-Market-Fit). Oder aber man stellt frühzeitig fest, dass ein Produkt oder ein Geschäftsmodell nicht funktioniert und spart sich weitere kostspielige Fehlinvestitionen (fail fast and smart).

Die hier dargestellte Strategie hat einen guten Grund. Eine Studie von CB Insights mit 101 gescheiterten Startups in 2014 hat ergeben, dass der Hauptgrund für das Scheitern mit 42% ein fehlender Bedarf am Markt war.

Abbildung 2: CB Insights Studie

Ein elementares Werkzeug in der Lean-Startup-Methode, um genau dieses Risiko zu adressieren, ist das Minimum Viable Product. Aus diesem Grund erfreut sich das MVP steigender Aufmerksamkeit und Beliebtheit.

Was vom MVP übrig blieb

Die Bezeichnung Minimum Viable Product wird im Allgemeinen auf Frank Robinson (CEO, SyncDev) zurückgeführt. Maßgeblich geprägt wurde der Begriff jedoch, wie bereits erwähnt,  von Eric Ries in dessen Buch “The Lean Startup”. Eine seiner frühesten Definitionen stammt aus Ries’ Blog “Startup Lessons Learned”, den er überwiegend als Vorlage für sein 2011 erschienenes Werk verwendete:

The minimum viable product is that version of a new product which allows a team to collect the maximum amount of validated learning about customers with the least effort.

In den Hochglanzfolien zur neuen Digitalstrategie – vornehmlich der IT-Abteilungen – zahlreicher Unternehmen wird die Interpretation des Begriffs MVP hingegen oft deutlich enger umrissen. Hier ist in verschiedenen Abwandlungen und Ausprägungen von der “ersten Version einer Software mit minimalem Feature-Set” die Rede, die “iterativ” weiterentwickelt wird. Das klingt zunächst wunderbar einfach und präzise, vor allem aber bekannt. Insbesondere im Kontext agiler Softwareentwicklung drängt sich nämlich die Frage auf, was an diesem Konzept originell, neu und anders sein soll. Man mag argumentieren, dass Eric Ries als Softwareentwickler stark durch die Ideen aus der agilen Softwareentwicklung, insbesondere eXtreme Programming von Kent Beck, geprägt wurde.

Ein Blick auf die zitierte Definition offenbart jedoch eine weitere mögliche Erklärung: Zunächst einmal ist die Abbildung des Begriffes “Produkt” auf “Software” allein bereits eine stark limitierte Interpretation im Sinne der Definition. Entscheidender ist jedoch die Frage, inwiefern eine Software dem Kriterium des “geringsten Aufwands” genügt, der für den maximalen Lernumfang investiert werden soll.

Natürlich ist ein Softwareprodukt durch seine Skalierbarkeit und Reichweite eine valide und sehr wertvolle Möglichkeit die Kernhypothesen eines Geschäftsmodells zu testen und daher ein guter Kandidat für ein MVP. Es ist jedoch wichtig zu wissen, dass es nur eine unter mehreren möglichen Varianten ist. Insbesondere bei komplexen Geschäftsmodellen – beispielsweise bei einer komplexen Wertschöpfungskette, die viele verschiedene Stakeholder umfasst – kann es elegantere, schnellere, wenn auch schlechter skalierende Methoden geben, um zu lernen, ob das Produkt tatsächlich einen Markt hat oder was ihm fehlt, um den Product-Market-Fit zu erreichen.

Joe Gebbia, einer der Gründer der Plattform Airbnb, lässt sich gerne zitieren, dass eine der wichtigsten Lektionen, die ihnen Y-Combinator Gründer Paul Graham mit auf den Weg gegeben hat, folgende gewesen ist: “Do things that don’t scale”. Auf diesen Rat hin hat Airbnb in seinen Anfängen intensiv den persönlichen Kontakt zu seinen ersten Kunden gesucht und dabei gelernt, dass attraktive Fotos der angebotenen Appartements ein Schlüssel für den späteren Erfolg der Plattform und somit ein wichtiger Baustein für den Product-Market-Fit sein sollten.

Tatsächlich wird dieser Ratschlag jedem jungen Gründer im Y-Combinator mit auf den Weg gegeben. Genau diese Prämisse, auch nicht skalierbare “Dinge” zu tun, lässt sich hervorragend auf die Wahl der Strategie für ein MVP anwenden.

In den letzten Jahren hat es zahlreiche Beispiele für junge, digitale Unternehmen gegeben, die ihre Produktidee bereits erfolgreich validieren konnten, bevor sie ein skalierbares Softwareprodukt entwickelt hatten. Aus diesen Beispielen haben Eric Ries und andere Autoren Muster extrahiert, die als Blaupause für das Design eines MVPs verwendet werden können.

MVP-Typen

Ein gängiges Vorurteil über das MVP ist, dass der Begriff nur eine neue, kunstvolle Umschreibung für ein unfertiges und schlechtes Produkt ist.

Sicher ist der Begriff nicht ideal und gibt Anlass zu Diskussionen. Nicht umsonst ist es inzwischen fast zu einem Wettbewerb geworden, Alternativvorschläge oder weitere Abgrenzungen – wie z.B. MSP (Minimum Sellable Product), MMP (Minimum Marketable Product) oder MLP (Minimum Learnable Product) – zu definieren.

Letztlich ist die Bezeichnung MVP aber am weitesten verbreitet und gut genug, wenn klar ist, was ein gutes MVP ausmacht.


Abbildung 3: Attribute eines MVP 1

Ein MVP sollte nicht nur eines der Attribute Machbarkeit, Nützlichkeit, Nutzbarkeit und Attraktivität erfüllen, sondern alle (siehe Abbildung 3). Außerdem sollte es den Zweck erfüllen, die risikoreichsten Hypothesen zum Produkt/Geschäftsmodell zu validieren und idealerweise vom ersten Tag an nachweisen, dass Kunden bereit sind für das Produkt zu zahlen 2. In diesem Sinne umschreibt die deutsche Übersetzung “lebensfähig” für “viable” den Anspruch an ein MVP vermutlich am besten.

Die wichtigste Komponente eines MVPs ist allerdings die Zeit. “The only way to win is to learn faster than anyone else. – Eric Ries”3 Zeit ist der entscheidende Faktor, um ein Produkt erfolgreich vor der Konkurrenz an den Markt zu bringen.

Die Kunst ist daher bei der Wahl des MVP eben dem Kriterium des “geringsten Aufwands” zu genügen, um die Zeit, die bis zur Validierung oder Invalidierung von Hypothesen und damit zum Lernen vergeht, zu minimieren. Die folgenden MVP-Typen sind Beispiele für eine Reduktion des Aufwands durch den gezielten Verzicht auf die Entwicklung von Software.

Dieser Blog-Post ist erstmalig im Softwerker Spezial „Digitalisierung“ unter dem Titel “Do Things That Don’t Scale”  erschienen. Im Artikel werden an dieser Stelle die drei MVP-Typen „Concierge MVP, Wizard of Oz MVP und Piecemeal MVP“ ausführlicher vorgestellt. Um den Umfang des Blogposts nicht zu sehr zu strapazieren, wird hier exemplarisch der Typ „Concierge MVP“ beschrieben.

Um den vollständigen Artikel zu lesen, können Sie den Softwerker hier abonnieren.

 

Concierge MVP

Beim Concierge MVP wird statt eines fertigen Produktes mit automatisierten Prozessen ein Produkt oder Service angeboten, der vollständig manuell ist. Dabei durchläuft der Kunde des Produktes alle Schritte, die er auch in der fertigen Lösung durchlaufen würde. Aus Kundensicht wird also ein vollständig “funktionsfähiges” Produkt angeboten, das lediglich begrenzt skalierbar ist.

Beispiel

Das Düsseldorfer Startup pillbox ist 2016 aus dem ersten Düsseldorfer Startup Sprint hervorgegangen. Die Gründer hatten die Vision, die Sicherheit und Einnahme von Medikamenten durch eine neue Art der Verpackung (Schlauchverblisterung mit Box – siehe Abb. 4) und Wechselwirkungschecks maßgeblich zu verbessern.

Zusätzlich sollten den Kunden digitale Services angeboten werden, die ihnen die Beschaffung von Medikamenten bei der Apotheke nach der ersten Verschreibung oder bei Folgerezepten vollständig abnehmen sollte (siehe Abbildung 5).


Abbildung 4: Die Pillbox

Ein erstes, nutzbares  Softwareprodukt mit diesen Services würde potenziell verschiedene Stakeholder entlang der Wertschöpfungskette mit einer sehr heterogenen Landschaft an IT-Systemen einbinden müssen. Angefangen beim Endnutzer und dessen Smartphone oder anderem Endgerät über den Arzt mit unterschiedlichen Technologien für die Übermittlung der Rezepte und die Apotheke oder einen eigenen angestellten Apotheker bis hin zum Blisterzentrum und letztlich den Logistik-Dienstleistern für die Lieferung. Eine enorme Anfangsinvestition für ein Produkt dessen Bedarf völlig unklar ist.


Abbildung 5: pillbox Serviceangebot

Aus Sicht der Gründer waren die folgenden Annahmen im Geschäftsmodell am risikoreichsten:

  • Würden Kunden einem Startup bei der Dosierung und Lieferung von Medikamenten trauen ?
  • Wären Kunden bereit, für das Produkt inklusive der Services zu bezahlen ?

Um diese Annahmen schnell und kostengünstig zu validieren, entschieden sich die Gründer ein leichtgewichtiges Concierge MVP aufzusetzen.

Über die Kooperation mit einem Ärztezentrum war pillbox in der Lage, die ersten zwanzig Kunden zu akquirieren, die eine monatliche Gebühr für das Produkt bezahlen mussten. Diesen Kunden wurde der vollständige Service von der Abholung der Rezepte über die Einreichung bei einer Partnerapotheke und die Bestellung bei einem Blisterzentrum bis hin zur persönlichen Auslieferung durch die Gründer angeboten.

Pillbox war so in der Lage, die beiden risikoreichsten Annahmen im Geschäftsmodell zu validieren. Es sollte sich herausstellen, dass auch nach  3 Monaten, trotz der monatlichen Gebühr, alle Kunden dem Service treu geblieben sind. Durch den engen Kontakt mit den ersten Kunden konnten die Gründer zudem weitere wichtige Erfahrungen zu ihrem Produkt sammeln. Neben Erkenntnissen zum Onboarding der Nutzer und der Bestätigung darüber, dass über alle Zielgruppen hinweg die Kommunikation über eine App das bevorzugte Mittel ist, lernte das Team vor allem eine entscheidende Lektion: Das eigentliche Produkt war nicht die Box mit den verblisterten Medikamenten, sondern der Wert lag in den angebotenen Services. Die ersten Kunden waren begeistert davon, die Abhängigkeit von den Öffnungszeiten der Ärzte und Apotheken sowie der Vorrätigkeit der Medikamente zu minimieren bzw. loszuwerden. Das Verkaufsversprechen von pillbox, der Mehrwert für den die ersten Kunden bereit waren, Geld zu bezahlen, ist die Ersparnis eines der wertvollsten Güter – Zeit.

Auf Basis der neuen Erkenntnisse zum Wert des Produkts und insbesondere des Prozesses sind die Gründer nun außerdem in der Lage, ihr Produkt deutlich gezielter iterativ zu automatisieren und somit zu skalieren. Es existieren nun Erfahrungen darüber, an welchen Punkten der Wertschöpfungskette eine Automatisierung den größten Mehrwert generiert und wo es sich daher lohnt, damit anzufangen.

Die Gründer konnten also mit der Strategie eines Concierge MVP ihre Kernhypothesen validieren. Darüber hinaus hat der enge Kontakt mit beteiligten Stakeholdern und den ersten Kunden dem Team zu wichtigen qualitativen Erkenntnissen verholfen.

Fazit

Geschwindigkeit ist der Schlüssel, um ein Produkt erfolgreich auf den Markt zu bringen. Der Fokus liegt dabei in der Produktentwicklung auf einer geringen Time-To-Market. In einer Phase, in der jedoch nicht klar ist, ob überhaupt ein Markt für das Produkt existiert, verschiebt sich dieser Fokus. In diesem Fall geht es darum Zeit und Aufwand zu verkürzen, die man benötigt, um zu lernen, ob das Produkt einen Markt hat. Bei neuen, innovativen Produkten kann man daher also eher von einer Time-To-Learning sprechen, die es zu reduzieren gilt. Dazu sind folgende zwei Fragen zu beantworten:

  • Was ist die risikoreichste Annahme über mein Produkt oder Geschäftsmodell?
  • Was ist das kleinste Experiment, mit dem ich diese Annahme validieren kann?

Das MVP ist ein mächtiges Werkzeug, das Produktmanager nutzen können, um diese risikoreichsten Annahmen zu validieren und sollte daher elementarer Bestandteil des Werkzeugkoffers sein. Wir haben jedoch gesehen, dass die Antwort auf die Frage nach dem kleinsten Experiment bei weitem nicht immer “ein Softwareprodukt entwickeln” sein muss. Entscheidend ist hier, wie so oft, die Wahl des richtigen Werkzeugs für diesen Job. Dafür ist es unerlässlich, die Vielfalt der Handlungsoptionen für ein MVP zu kennen, um die richtige Wahl für den eigenen Kontext treffen zu können. Insbesondere durch die drei Varianten – Concierge, Wizard of Oz und Piecemeal (Informationen zu Letzteren gibt es im original Artikel) – ist man in der Lage mit geringem Aufwand ein lebensfähiges Produkt auf den Markt zu bringen. Somit hat man für bestimmte Produkte eine echte Alternative für Experimente bevor man in die Entwicklung von Software investiert.

In seinem Artikel “Probe, Sense, Respond” beschreibt mein Kollege Nils Wloka, wie man ein Rapid Prototyping Team mit den geeigneten Methoden und Werkzeugen in die Lage versetzt, Software Prototypen mit der gleichen Geschwindigkeit zu entwickeln, wie digitale oder Papier Prototypen. Ähnlich dem Piecemeal MVP (siehe original Artikel für weitere Informationen) kann man zu diesem Zweck eine Vielzahl bestehender Services in seine Software integrieren.
Insbesondere für digitale Produkte, deren Mehrwert erst durch die Verwendung von Software entsteht, kann eine ernsthafte Validierung nicht durch andere Methoden erreicht werden. Hier wird also deutlich, in welchem Kontext Softwareentwicklung eine unumgängliche Wahl für ein MVP ist.

Auch in späteren Phasen der Produktentwicklung sollten die Lean-Startup-Prinzipien, insbesondere Build-Measure-Learn, angewendet werden. Das Konzept MVP sollte deshalb keinesfalls als einmaliges Ereignis im Lebenszyklus eines Produktes betrachtet werden. Die hier vorgestellten Muster können auch später, beispielsweise für Experimente zur Validierung einzelner Features, verwendet werden.

Ein spannendes Beispiel dazu stammt aus dem Buch “Sprint”4, in dem das Prinzip des von Google Ventures entwickelten “Design Sprints” beschrieben wird.

Das amerikanische Startup Slack entwickelt einen erfolgreichen Messenger für Teams und Unternehmen. Im Zuge eines Design Sprints wollte das Team den Onboarding-Prozess verbessern, damit neue Nutzer sich schneller in Slack  zurechtfinden. Das Team entwickelte im Sprint die Idee, zu diesem Zweck einen Chatbot zu entwickeln, der die Nutzer in die Benutzung von Slack einführen und eine permanente Anlaufstelle für Rückfragen sein sollte. Um die Akzeptanz bei den Nutzern und die Effektivität des Bots in einem kleinen Experiment zu validieren, erprobte das Team die Idee mit neuen Nutzern, die mit einem Teammitglied kommunizierten, der sich als Bot ausgab. Auf diese Weise war das Team außerdem in der Lage erste Erkenntnisse darüber zu sammeln, wie intelligent der Bot sein musste, um vom Nutzer als hilfreich wahrgenommen zu werden. Inzwischen ist der Slack-Bot ein fast schon ikonischer Bestandteil des Messengers. Der hier beschrieben Test, den das Team durchgeführt hat ist im Wesentlichen ein Wizard of Oz MVP für ein einzelnes Feature.
Der kontinuierliche Einsatz des Konzepts MVP in der Produktentwicklung ist letztlich eine wertvolle Risikovermeidungsstrategie, die die dabei hilft permanent fundiertere Entscheidungen bei der Wahl der nächsten Entwicklungsschritte zu treffen.


Dieser Blog-Post ist erstmalig im Softwerker Spezial: Digitalisierung erschienen. 
Den Softwerker kostenlos abonnieren
Weitere Infos zu unserem Angebot finden Sie auf unserer Seite the black frame.com.


1. Humble, Molesky, O’Reilly: Lean Enterprise S. 77
2. Maurya, Ash: Running Lean”, Part II – Chapter 3
3. Ries, Eric: The Lean Startup, S. 111
4. Knapp, Zeratsky, Kowitz: Sprint, S. 175

The post Do things that don’t scale: MVP ohne Softwareentwicklung – geht das? appeared first on codecentric AG Blog.

Unblocking the Supply Chain with Blockchain

$
0
0

Warum Blockchain in der Supply Chain?

Der Grund für die breite Adaption einer Technologie in einer bestimmten Domäne ist simpel: Sie löst konkrete Probleme oder schafft neue Werte. Wir schauen uns in diesem Blog Post an, warum Blockchain ein guter Kandidat ist, um die Supply Chain IT und auch einige Supply Chain Practices nach und nach zu transformieren. In diesem Artikel sprechen wir oft von Blockchain, dabei sind aber in Wahrheit unterschiedliche Implementierungen gemeint. Ein Großteil der angesprochenen Aspekte findet sich beispielsweise in Ethereum wieder. https://ethereum.org

Im Folgenden gehen wir auf die unterschiedlichsten Aspekte der Supply Chain ein, die unmittelbar durch die Eigenschaften der Blockchain adressiert werden.

Es geht um viele Assets und um viel Geld.

Eine Supply Chain besteht aus vielen unterschiedlichen Teilnehmern, die Waren, Leistungen und Bezahlung untereinander austauschen. Dabei ist es in vielen Fällen wünschenswert, die physischen Assets über digitale zu tracken, um zu wissen, wo sich die Güter befinden, die Besitzrechte zu zertifizieren und beim Güter-Übergang eine entsprechende Zahlung auszulösen.

Die Abbildung von Spiegel-Assets in der Blockchain ist eine neuere Entwicklung, die aber bereits häufiger in Implementierungen aufgegriffen wird. Konkretes Beispiel ist das Start-up Everledger, das Wertgegenstände mit Hilfe der Blockchain trackt. https://www.everledger.io In Bezug auf Finanztransaktionen hat Bitcoin als bekannteste Kryptowährung gezeigt, dass Bezahlungen für einfache Transaktionen ohne Weiteres abbildbar sind. Inzwischen ist es auch möglich, komplexe Transaktionen zu implementieren, die beispielsweise prozentuale Provisionen abbilden oder Mehr-Parteien-Transaktionen ermöglichen.

Viele Teilnehmer, wenig Vertrauen.

Die Supply Chain besteht aus einem Netzwerk von Teilnehmern, die zueinander in beliebig vielen, komplexen Beziehungen stehen. Dabei wird zwar oft von partnerschaftlicher Zusammenarbeit gesprochen. Letztendlich arbeiten hier aber unterschiedliche Organisationen zusammen, die sich nur in begrenztem Umfang vertrauen. Nehmen wir an, die Informationen über den Warenfluss würden von einer zentralisierten Instanz verwaltet werden, dann hätte diese die Möglichkeit, die Daten direkt zu manipulieren oder vorzuenthalten. Behält jeder die Daten selbst, entsteht ein hoher lokaler Aufwand, und die anderen Teilnehmer können nicht ohne Weiteres darauf zugreifen oder den übertragenen Werten vertrauen.

Die Blockchain ermöglicht es, die Daten äquivalent zu einer zentralen Instanz abzulegen. Durch ihren dezentralen Charakter und inhärente Eigenschaften verhindert sie dabei jedoch eine Veränderung von Informationen und Transaktionen.

Wo wenig Vertrauen ist, da gibt es Verträge.

Die Parteien der Supply Chain stehen in einem vertraglichen Verhältnis zueinander. Im einfachsten Falle: Man liefert mir x Stück von Y zu einem Zeitpunkt t und einem Preis p. Die Erbringung der Leistung wird mit den geschlossenen Verträgen gegengeprüft. Konditionen werden errechnet, allerdings häufig mehr schlecht als recht, da man die vielen Verträge und Sourcing-Möglichkeiten international gar nicht korrekt abbilden kann. Heutzutage werden diese Informationen über viele verschiedene Systeme verteilt abgelegt und genutzt.

In der Blockchain können Verträge sowie Programme abgebildet und die Erfüllung automatisiert geprüft werden. Hier wird auch von Smart Contracts gesprochen. Wenn zum Beispiel die Ware beim Wareneingang gescannt wird, geht nicht nur das digitale Spiegel-Asset an den neuen Besitzer über, sondern es kann direkt gegen die im Smart Contract hinterlegten Konditionen geprüft und die Bezahlung innerhalb der Blockchain entsprechend ausgelöst werden. Das ist z.B. eine inhärente Eigenschaft der Ethereum Blockchain: Vertrag und Bezahlung können im gleichen System angelegt und abgewickelt werden. Dies ermöglicht es auch, Themen wie den Zeitpunkt des Besitzübergangs oder besondere Geschäfte wie z.B. Kommissionsgeschäfte abzubilden. Im Smart Contract kann definiert werden, zu welchem Zeitpunkt das digitale Spiegel-Asset den Besitzer wechselt –beispielsweise erst zum Zeitpunkt der Übergabe an den Endkunden. Gleichzeitig wird zu diesem Zeitpunkt die Zahlung an den Hersteller abgeführt, und es werden mögliche Gebühren an die Zwischenhändler bezahlt.

Vermittler verlieren ihren Job

Innerhalb der Supply Chain gibt es verschiedene Vermittler, die an den Transaktionen verdienen. Dies kann auf unterschiedlichsten Ebenen passieren: Aggregation und Verteilen von Produktinformationen, Großhandels-Plattformen für Produktkomponenten oder Produktvertreter, die Produkte vermarkten.

Ähnlich, wie wir es am Beispiel Kryptowährungen im Bereich Banken und Finanzen bereits erahnen können, ist eine direkte vertrauenswürdige Verbindung von Lieferant und Endkunde eine Gefahr für alle Vermittler-Strukturen. Warum sollte in Zukunft nicht der Hersteller seine Produkt-Daten unveränderbar in der Blockchain hinterlegen, und jeder Händler greift direkt auf diese zu?

Tracking und Tracing

Transparenz und Nachverfolgbarkeit sind Teil eines Problemfeldes, an dem seit vielen Jahren in der Supply Chain gearbeitet wird. Bei der Lebensmittelproduktion müssen beispielsweise die genutzten Chargen der Zutaten für Rückrufe eindeutig “End-to-End” rückverfolgbar sein. Idealerweise sind diese Aufzeichnungen auch revisionssicher abgelegt – derzeit eine Mammut-Aufgabe für die Supply Chain.

Eine inhärente Eigenschaft der Blockchain ist, dass alle Daten auf der Blockchain für alle Teilnehmer zugreifbar und unveränderlich sind. Dies ist eine gute Grundlage für Tracking und Tracing Cases aller Art. Eine Herausforderung ist die vertrauenswürdige Verknüpfung der Blockchain mit Events in der physischen Welt. Durch die Nutzung sogenannter Orakel wird dies möglich. Orakel übersetzen Events in der physischen Welt in Transaktionen in der Blockchain. So lassen sich auch Warenbewegungen direkt nachverfolgen. Wie das Konzept von Orakeln funktioniert, kann man beim Startup Reality Keys https://www.realitykeys.com verstehen. Hier werden, statt von IoT Devices gescannten Wareneingängen, Fakten aus der realen Welt in der Blockchain hinterlegt.

Value Adding Services

Als Teil der Supply Chain werden immer öfter Value Adding Services angeboten, wie zum Beispiel das Erstellen von Kits (Produkte in Verpackungen hinzufügen, z.B. USB-Kabel zu einem Drucker), Customizing (die individuelle Anpassung von Produkten, z.B. eine Gravur) oder Bundling (z.B. Zusammenstellung eines Buch-Sets zum Thema Security) .

Diese Services können als Smart Contracts in der Supply Chain abgebildet und direkt abgerechnet werden. Mit dem Konzept der Decentralized Autonomous Organization (DAO) kann hier sogar noch ein Schritt weiter gedacht werden. Eine DAO ist eine in der Blockchain instanziierte, virtuelle, eigenständig agierende Organisation. Eine DAO läuft wie ein Programm, besitzt Geld und verfolgt vorgegebene Ziele.

Für die Supply Chain könnte man sich beispielsweise eine Value Adding Services DAO vorstellen, die zum Beispiel einen Gravur-Roboter besitzt. Die DAO ist so programmiert, dass sie auf verschiedene Parameter hin optimiert: Ertrag, Auslastung, Prestige, …

Mögliche Teilaufgaben der DAO, die im Programm abgedeckt werden, sind z.B.

  • Anwerben von Aufträgen über eine Website
  • Beschäftigung eines Bedieners, der die Werkstücke einlegt
  • Beauftragung von Versanddienstleistungen
  • Bestellung von Reparaturdiensten und Ersatz von Verschleißteilen
  • ein Recruiting-Dienstleister

Die Kombination aus Smart Contracts, Bezahlung und Business-Logik ermöglicht eine neue Art von Entität in der Supply Chain.

Die in diesem Fall beschriebenen, komplexen Services sind noch zu schwer zu implementieren, aber Teile hiervon sind durchaus umsetzbar. Zum Beispiel die Vermietung von Maschinenzeit und das Binden der Gewinne an einen bestimmten Zweck, z.B. gemeinnützige Dienste.

Conclusion

Zusammenfassend kann festgestellt werden, dass viele Funktionen der Blockchain zur Lösung von Problemen in der Supply Chain beitragen können und sogar neue Geschäftsmodelle möglich sind. Die Blockchain-Technologie wird nicht von heute auf morgen die komplette IT-Infrastruktur für die Supply Chain auf den Kopf stellen. Aber wir werden nach und nach in unterschiedlichsten Bereichen Anwendungsfälle sehen, in denen die Blockchain zur Anwendung kommt und vielleicht sogar einigen Akteuren massive Konkurrenz machen wird.

Wir haben die Erfahrungen zu diesem Thema dadurch gesammelt, dass wir an der Umsetzung einiger Use Cases auf Basis von Etherium arbeiten. Unsere Erkenntnisse werden wir über die Zeit in unseren Blog-Posts verarbeiten, Links zu weiteren Artikeln finden sich im Anhang. Wir werden uns weiter in unserem Lab damit beschäftigen, weitere Use Cases und Geschäftsmodelle zu erproben, dazu demnächst mehr.

Weitere Blockchain-Artikel:

Blockchain, the next big thing?  – https://blog.codecentric.de/2017/07/was-ist-blockchain/
Decentralized Autonomous Organizations – stay tuned…

The post Unblocking the Supply Chain with Blockchain appeared first on codecentric AG Blog.

Empathie – Elementare Eigenschaft agiler Entwickler

$
0
0

Ein Software-Entwickler in einem agilen Team muss heute einige Soft Skills mitbringen, die er früher wohl nicht gebraucht hätte. Es wird zum Beispiel erwartet, dass er eigenverantwortlich arbeitet und handelt. Insbesondere für Entwickler, die nicht in einem agilen Umfeld aufgewachsen sind, kann das völlig neu sein. Denn in einem „klassischen“ Entwicklungsumfeld ist es möglich (und wird mitunter sogar erwartet), dass ein Entwickler die ihm zugewiesenen Aufgaben ohne Rück- oder Hinterfragen abarbeitet.

Eine un(?)bequeme Entwicklung

In agilen Teams sieht die Welt anders aus. Die Prinzipien der agilen Softwareentwicklung stellen selbstorganisierte Teams und ein hohes Maß an Abstimmung und Kommunikation in den Mittelpunkt:

Fachexperten und Entwickler müssen während des Projektes täglich zusammenarbeiten.

Die besten Architekturen, Anforderungen und Entwürfe entstehen durch selbstorganisierte Teams.

Zwölf Prinzipien Agiler Softwareentwicklung, Agiles Manifest

Die ehemals konzentrierte Verantwortung geht vom Projektmanager auf das gesamte agile Team über. Das Team ist nun z.B. verantwortlich für:
 

  • Die Qualität des Produkts
  • Die Außenwirkung des Projekts
  • Die Einhaltung von Fristen und die Zielerreichung
  • Die Arbeitsatmosphäre und die Stimmung im Team

Diese Verschiebung der Zuständigkeiten fällt nicht jedem einfach. Dem Projektmanager werden zahlreiche Befugnisse genommen oder seine Rolle entfällt gar komplett, gleichzeitig ist keinesfalls jeder Entwickler davon begeistert, Verantwortung für sich selbst, seine Arbeit und das Projekt zu übernehmen.

Entwickler brauchen neue Fähigkeiten

Doch: Es hilft ja nichts. Entwickler in agilen Teams müssen mit der Zeit aus ihrer reinen Programmierer-Rolle herauswachsen und einige neue (weniger technische als viel mehr menschliche) Fähigkeiten entfalten. Eine dieser Fähigkeiten, die meiner Meinung nach von unschätzbarem Wert ist, ist die Empathie.

Empathie bezeichnet die Fähigkeit und Bereitschaft, Empfindungen, Gedanken, Emotionen, Motive und Persönlichkeitsmerkmale einer anderen Person zu erkennen und zu verstehen.
Wikipedia 🙂

Einerseits hilft uns Empathie, das Handeln anderer Menschen zu verstehen („Wie sieht die Person die Situation?“). Andererseits ist sie auch ein zentrales Mittel der Selbstreflexion („Wie sehen mich andere Menschen?“). Ein Wechsel der Perspektive lässt uns Situationen verstehen, die aus einem anderen Blickwinkel völlig unverständlich sind, und liefert die Erklärung für Reaktionen, mit denen wir auf den ersten Blick nicht einverstanden sind, z.B.
 

  • Mit dieser Reaktion hätte ich niemals gerechnet
  • Wieso freuen sie sich so über diese Kleinigkeit?
  • Sie haben total überreagiert

Und wie soll mir das helfen?

Ein Entwickler in einem agilen Team steht mit Fachexperten, Kunden, Stakeholdern und Kollegen anderer Teams in Kontakt. Diese Personen haben unterschiedliche Interessen, Vorstellungen und Erwartungen, aber auch Hintergründe und Gefühlslagen. Wer sich in sein Gegenüber hineinversetzen und Verständnis aufbauen kann, vermeidet Reibungsverluste, erweitert sein Netzwerk leichter und erreicht seine Ziele mit weniger Mühe. Schauen wir mal, wie ein Perspektivwechsel die Situation verändern kann:

Das neue Teammitglied nervt. Sein einziges Problem scheint die geringe Testabdeckung zu sein.

Wenn ich weiß, dass er früher als Operator nachts wegen unnötiger Bugs aus dem Bett geklingelt wurde, erkenne ich, dass er aus Erfahrung spricht und gute Gründe hat.

Unser Stakeholder möchte ein halbfertiges Feature unbedingt noch diese Woche live nehmen. Das lehne ich mit einem Verweis auf unsere Definition of Done ab.

Unsere Konkurrenz ist auf Zack – Wir verlieren jeden Tag dutzende Kunden, und dieses Feature ist bedeutend. Nehmen wir das nicht ernst, schlittern wir womöglich in massive Probleme.

Ein Kollege schwärmt seit Wochen für eine Technologie XY. Er ist wirklich überzeugt! Das Team möchte den Mehrwert jedoch nicht so richtig einsehen..

Ein alter Bekannter des Kollegen vertreibt das Produkt XY. Ich verstehe, dass er diesem einen Gefallen tun möchte, sehe jedoch auch, dass seine Begeisterung nicht nur dem Produkt entspringt.

Wie lerne ich die Fähigkeit zum Perspektivwechsel?

Zunächst die schlechte Nachricht: Empathie lässt sich nicht ernsthaft durch Lesen oder einen Kurs erlernen, sondern muss aktiv trainiert werden. Doch keine Sorge: Man muss kein besonders „emotionaler“ Mensch sein, um empathischer zu werden. Wer die Einschätzung überwindet, die eigene Wahrnehmung sei die einzig gültige, findet im Alltag ausreichend Trainingsmöglichkeiten. Der erste Schritt ist, sich zwei Dinge zu fragen: „Warum handelt mein Gegenüber genau so?“ und „Wie wirkt unser Handeln auf andere?“.

In agilen Projekten bietet die Retrospektive einen geschützten Raum, Beweggründe und Verhalten anderer Personen zu thematisieren, wobei insbesondere die Schnittstellen des Teams von Interesse sind. Wenn ein Kunde oder Stakeholder nicht wie erwartet reagiert, sollte geklärt werden, wieso. Gleiches gilt für unverständliche Entscheidungen, die getroffen werden. Zusätzlich sollte der Product Owner eine klare Sicht von außen auf das Projekt und das Projektumfeld liefern können, und wissen, warum das Projekt in welche Richtung steuert. Damit liefert er den nötigen Kontext für viele Handlungen.

Nicht immer einfach, aber oft die beste Lösung bleibt das persönliche Gespräch. Erfahrungsgemäß erfüllt es die meisten Menschen mit Freude, wenn man ihnen mit aufrichtigem Interesse begegnet.

In diesem Sinne – Haben Sie sich schon gefragt, warum ich diesen Blog-Artikel geschrieben habe?

The post Empathie – Elementare Eigenschaft agiler Entwickler appeared first on codecentric AG Blog.


Ausrollen von Paketen mit Jenkins und der Cloud-Lösung CenterDevice

$
0
0

Manchmal gibt es Projekte, in denen man nicht die Hoheit über das Produktivsystem des Kunden hat, man also nicht selbständig neue Versionen vollautomatisiert vom Build bis ins Produktivsystem bringen kann. Man muss also einen Weg finden, dem Kunden die neuesten Versionen zur Verfügung zu stellen, ohne dass die Pakete für jedermann zugänglich sind und dennoch gut versioniert werden können. Trotzdem soll natürlich die Sicherheit der Dateien gewährleistet werden.

In einem Kundenprojekt bin ich kürzlich auf diese Situation gestoßen. Abgeschlossenes Produktivsystem, Pakete müssen manuell auf einem Share abgelegt und damit dem Kunden zur Verfügung gestellt werden.

CenterDevice als Share zum Kunden

CenterDevice ist ein Cloud-basiertes, professionelles Dokumentenmanagement- und Online-Collaboration-System, dessen Fokus unter anderem auf dem Teilen von Dokumenten liegt.
Dokumente können über Schlagworte und Sammlungen strukturiert werden, und über die Volltextsuche lässt sich jede Datei schnell wiederfinden. Weitere Details finden Sie hier.

Wir haben uns als Austauschplatform für CenterDevice entschieden, da es mittels öffentlicher Links einen einfachen Weg bietet, die Pakete dem Kunden zur Verfügung zu stellen. Außerdem sind alle Dateien versioniert, sodass auch auf ältere Pakete ohne Probleme zugegriffen werden kann. Der Kunde selbst benötigt dazu keinen eigenen Account.

Jenkins Publisher Plugin nach CenterDevice

Um dennoch einen automatisierten Veröffentlichungsprozess sicherzustellen, fehlt nur noch ein Jenkins Plugin, dass die Pakete in CenterDevice ablegt und auch gleich entsprechend freigibt.

Use Cases

  • Upload beliebiger Dateien nach einem Build nach CenterDevice
  • Upload einzelner Dateien als neue Version bestehender Dateien
  • Sammlungen vergeben, um Pakete eines Produkts zu gruppieren
  • Dateien in Ordner verschieben. Ordner bieten eine weitere Gruppierungsfunktionalität.
  • Öffentlichen Link erzeugen

Konfiguration

Für die Demo wird folgendes benötigt:

  1. Jenkins Installation
  2. Ein Freestyle Job mit einem Batch-Build-Schritt:
    del release.txt
    time /t > release.txt
    date /t >> release.txt
    echo Changelog >> release_notes.txt
  3. Diese Jenkins Plugins:

Nach der Installation des CenterDevice-Plugins muss zunächst ein API RefreshToken in der Systemkonfiguration hinterlegt werden.

Systemkonfiguration

Das Token kann mit einem Tool erzeugt werden. Es wird dafür ein CenterDevice Account benötigt.

Token Jenkins

In unserem Job kann das Plugin nun als Post-Build-Schritt hinzugefügt werden

Postbuild

Der eigentliche Upload-Step sieht nun so aus:

config jenkins

Folgende Optionen können gewählt werden:

  1. Hochzuladene Dateien: Dies ist ein Ant Filepattern, dass die hochzuladenen Dateien beschreibt. Die Dateien werden als neue Dateien in CenterDevice angelegt.
  2. Hochladen als Latest-Version: Diese Option erlaubt es, eine Datei als neue Version einer vorhandenen Datei hochzuladen. Das Pattern „Hochzuladene Dateien“ darf dazu nur genau eine Datei beschreiben. Existiert die Datei noch nicht, wird eine erste neue angelegt.
  3. Name des Dokuments: Der Name des Dokuments, als dessen neue Version die Datei hochgeladen werden soll.
  4. Öffentliche Links erzeugen: Bestimmt, ob für alle hochgeladenen Dateien ein öffentlicher Link erzeugt werden soll.
  5. Öffentliche Links als Variable ‚publiclinks‘ in die Datei ‚publiclinks.prop‘ schreiben: Bestimmt, dass alle öffentlichen Links in eine properties Datei geschrieben werden, damit diese über das EnvInject dem Build zu Verfügung gestellt werden können (siehe unten).
  6. Sammlung: Eine Sammlung, in die die Datei eingefügt werden soll.
  7. Ordner: Ein Ordner Pfad in der Sammlung. Geschachtelte Order werden durch Backslash getrennt.

Post-Build-Schritte

config jenkins

Datei hochladen mit Sammlung und Ordner

 

config jenkins

Upload neue Version, öffentlicher Link und geschachtelte Ordner

 

Mit dieser Konfiguration werden bereits 2 Dateien nach CenterDevice hochgeladen, für Changelog.txt wird zudem ein öffentlicher Link erzeugt.

Öffentliche Links als Job-Variable

Bislang muss man also noch immer manuell eingreifen, um den öffentlichen Link herauszufinden.
Wäre es da nicht schön, wenn das System uns diesen anzeigen würde?

Dazu nutzen wir das Feature „Öffentliche Links als Variable bereitstellen“. Dies erzeugt nach dem Hochladen die nötigen Links und schreibt diese in eine Properties-Datei „publiclinks.prop“. Die Variable heißt dann publiclinks. Mit EnvInject können wir diese Datei laden, um die Variable auch verwenden zu können. Damit dies auch als Post-Build-Schritt klappt, verwenden wir das Flexible Publish Plugin (enthalten im Any Build Step Plugin).

Da potenziell mehrere Links auf diese Weise importiert werden können, werden diese in HTML Absätze verpackt (<p> Tag). Auf diese Weise lässt sich die Variable dann direkt als HTML Inhalt in Emails verwenden.

CenterDevice Jenkins

Als Demo lassen wir uns abschließend den Link in das Build-Log ausgeben. Dies machen wir als Batch-Datei (ebenfalls über Flexible Publish): @echo %PUBLICLINKS%

Das Ergebnis kann sich bereits sehen lassen.

Start publishing files matching 'release.txt' on CenterDevice in collection 'deployment' and folder 'Demo'
Login successful
Searching for collection >deployment<
Found collection >deployment< with id >8ace477b-55be-445f-91b2-cc07be41b7a6<
Searching for folder >Demo<
Found final folder with name >Demo< and id >ca70972c-2c44-441b-a275-cca3b5604fc5<
Uploading file C:\Program Files (x86)\Jenkins\workspace\CenterDevice Publisher Demo\release.txt as release.txt
Start publishing files matching 'release_*' on CenterDevice in collection 'deployment' and folder 'Demo\changelog'
Login successful
Searching for collection >deployment<
Found collection >deployment< with id >8ace477b-55be-445f-91b2-cc07be41b7a6<
Searching for folder >Demo\changelog<
Found final folder with name >changelog< and id >fe4a7865-8671-439f-a70d-9238d2ff6aea<
Retrieving public link for file >Changelog.txt< with id >d37a0a26-df08-4479-868d-fc26355b019f<
Run condition [Always] enabling perform for step [[Inject environment variables, Windows Batch-Datei ausführen]]
[EnvInject] - Injecting environment variables from a build step.
[EnvInject] - Injecting as environment variables the properties file path 'publiclinks.prop'
[EnvInject] - Variables injected successfully.
[CenterDevice Publisher Demo] $ cmd /c call C:\WINDOWS\TEMP\jenkins750722257213274980.bat
Changelog.txt: <p>https://mantest.centerdevice.de:8443/centerdevice-public-link-client/4f09029b-fcb5-43db-b22b-47ab8f3293a6</p>
Changelog

Changelog.txt mit neuer Version

 

Multiple release.txt Dateien

Zusammenfassung

Wir haben nun also ein automatisiertes Verfahren zum Veröffentlichen von Paketen in CenterDevice und dem Zustellen von Links zum Download durch den Kunden.
Auch wenn wir hier den Link nur im Build-Log ausgegeben haben, wäre es natürlich möglich eine Mail mit den Links zu versenden. Das überlasse ich aber dem Leser.

Die aktuelleste Version (1.0.3) des Plugins finden Sie hier.

The post Ausrollen von Paketen mit Jenkins und der Cloud-Lösung CenterDevice appeared first on codecentric AG Blog.

Agile, frisch gebackene Dokumentation – Teil 1: JBake

$
0
0

In Softwareentwicklungsprojekten steht man immer wieder vor der Frage, wie denn das jeweilige Projekt in vollem Umfang dokumentiert werden könnte. In der Regel nimmt man meistens Confluence oder ein anderes Wiki zur Hand. Aber warum entwickeln wir die Dokumentation des Projekts nicht direkt am Code? Zu diesem Zweck möchte ich euch in diesem ersten Teil der Artikelserie JBake ein wenig näher bringen.
JBake ist eigentlich ein Generator für statische Webseiten. Dan Allen, Project Lead des Asciidoctor-Projekts, bezeichnet es als „Jekyll of the JVM“. Anhand von Plugins für Maven und Gradle lässt sich JBake auf relativ einfache Art und Weise in Build Pipelines integrieren.
Ich möchte nun anhand eines Beispiels die Einsatzmöglichkeiten von JBake erläutern. Zu allererst werden wir ein einfaches Gradle-Projekt bauen, um eine Ausgangsbasis für die weiteren Schritte zu schaffen.

group 'de.codecentric.dk.afgd'
version '1.0-SNAPSHOT'

apply plugin: 'groovy'
apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
   mavenCentral()
   jcenter()
}

dependencies {
   compile 'org.codehaus.groovy:groovy-all:2.3.11'
   testCompile group: 'junit', name: 'junit',version: '4.12'
}

Nun wird die Build-File um das Plugin jbake-gradle-plugin erweitert.

plugins {
     id 'org.jbake.site' version '1.0.0'
}

Dadurch erhalten wir nun einen weiteren Task „bake“, der es uns erlaubt, Dokumentation zu „backen“. Desweiteren benötigen wir hierzu noch eine JBake-Basisinstallation innerhalb der Sourcen. Unter dem MacOS-Betriebssystem lässt sich dies leicht mit SDKMAN (

$ sdk install jbake

) oder Homebrew (

$ brew install jbake

) erledigen.

Standardmäßig erwartet das Gradle-Plugin die Dokumentationsquellen unter src/jbake. Mit Parametern im Build-File lässt sich der Quell- und Zielort aber anpassen, wobei das Ziel immer im Build-Ordner liegt. In unserem Fall mit den folgenden Werten:

jbake {
     srcDirName = 'src/documentation'
     destDirName = 'documentation'
}

Da nun JBake installiert ist, kann im Verzeichnis

src/documentation

der Befehl

jbake -i

ausgeführt werden. Die so entstandene Struktur lässt sich nun nach Belieben erweitern und anpassen. Als Inhalt lassen sich im content-Ordner HTML-, Asciidoctor- oder Markdown-Dateien hinterlegen. Im Rahmen des Blogartikels wird die vorhandene Datei about.html durch about.adoc ersetzt und der Inhalt entsprechend angepasst.

= Project documentation
Daniel Kocot
2017-10-03
:jbake-type: page
:jbake-tags: documentation, manual
:jbake-status: published

Innerhalb des Asciidoctor-Dokuments können JBake-Metainformationen hinterlegt werden, wie Seitentyp, Tags und der Status der jeweiligen Seite. Letzterer regelt die Sichbarkeit der Seiten nach dem „Backprozess“. Wem das Standardtemplate nicht gefällt, kann dieses mittels der Templatesprachen Freemaker, Groovy Simple, Groovy Markup, Thymeleaf und Jade seinen Wünschen nach anpassen.
Wenn wir nun zurück auf den Buildprozess schauen, können wir zum Abschluss dieses ersten Teils den Build-Task mit dem Bake-Task verbinden.

build.dependsOn bake

Wenn wir nun den Build-Task ausführen, wird auch die Dokumentation erstellt. Im zweiten Teil werden wir weitere Zutaten für eine agile, frisch gebackene Dokumentation hinzufügen.

Eine Demo findet ihr in meinem Git-Repository agile-fresh-baked-docs.

The post Agile, frisch gebackene Dokumentation – Teil 1: JBake appeared first on codecentric AG Blog.

kibconfig – Wartungstool für Kibana Dashboards

$
0
0

Als wir vor 2 Jahren zu Beginn unseres Projekts damit begannen, unser ELK Logging über Kibana Dashboards zu optimieren, standen wir vor einem Problem: Wie konnten wir unsere für die PP-Umgebung vorbereiteten Dashboards, Visualisierungen und gespeicherten Suchen auf die Produktionsumgebung überführen, ohne den gleichen Konfigurationsaufwand über die Oberfläche nochmal zu treiben? Außerdem wäre es schwierig, beide Umgebungen so synchron zu halten.

Eine Tool-Suche ergab leider nichts, aber es stellte sich heraus, dass alle Oberflächenelemente in einem ElasticSearch Index hinterlegt sind und als JSON exportier- und pflegbar sind. Damit entstand die Idee ein eigenes Tool dafür zu schreiben: kibconfig.

kibconfig erlaubt den Download und Upload der Kibana-Elemente (Dashboard, Visualization, Search, Config, Index-Pattern) in eine lokale Verzeichnisstruktur. Da die in ElasticSearch gespeicherten JSON-Dokumente wiederum als String verpackte JSON-Strukturen enthalten, werden diese dabei „ausgepackt“. Alle Attribute werden außerdem in einer definierten Reihenfolge und Pretty-Printed gespeichert, so dass ein einfaches Diffing und Versionierung – z. B. via Git- möglich ist. Seit der Version 0.2 ist auch ein einfaches „deep copy“ von Dashboards mitsamt Unterstrukturen möglich. Das verwenden wir z. B. zur Erstellung angepasster Dashboards für unterschiedliche Microservices.

Hier ein Beispiel eines unter ./dashboards/Example-Dashboard.json lokal gespeicherten Dashboards:

{
    "id": "Example-Dashboard",
    "title": "Example Dashboard",
    "description": "",
    "hits": 0,
    "timeRestore": false,
    "version": 1,
    "kibanaSavedObjectMeta": {
        "searchSourceJSON": {
            "filter": [
                {
                    "query": {
                        "query_string": {
                            "analyze_wildcard": true,
                            "query": "*"
                        }
                    }
                }
            ]
        }
    },
    "panelsJSON": [
        {
            "id": "Navigation",
            "type": "visualization",
            "col": 1,
            "row": 1,
            "size_x": 2,
            "size_y": 5
        },
        {
            "id": "Example-all-errors",
            "type": "search",
            "col": 3,
            "row": 1,
            "size_x": 10,
            "size_y": 4,
            "columns": [
                "hostname",
                "category",
                "message"
            ],
            "sort": [
                "timestamp",
                "desc"
            ]
        },
        {
            "id": "Example-Log-count-by-level",
            "type": "visualization",
            "col": 3,
            "row": 5,
            "size_x": 10,
            "size_y": 4
        }
    ]
}

Über Profile lassen sich in einer Konfigurationsdatei verschiedene Zielumgebungen ansprechen. Damit ist ein Staging der Konfiguration sehr einfach möglich.

Anwendungsmöglichkeiten

Die Pflege der Dashboards gestaltet sich damit wesentlich einfacher:

  • Kleinere aber oft übergreifende Anpassungen, wie z. B. bei Schema-Änderungen, lassen sich jetzt einfach über Suchen-/Ersetzen in der IDE lösen.
  • Je nach Änderung kann der Entwickler entscheiden, ob die Änderungen zunächst im Repository oder in Kibana vorgenommen werden. Letzteres is insbesondere beim Layouting ratsam.
  • Änderungen können in Branches vorbereitet, und per Merge Request reviewed werden.
  • Die Versionierung erlaubt die einfache Durchführung von Rollbacks.
  • Falls zwischenzeitig doch mal z. B. durch Dritte  manuelle Änderungen an Kibana Boards vorgenommen wurden, lässt sich das einfach über einen erneuten Download und Diff zum Repository-Stand feststellen und beheben.

Anwendungsfall: Migration auf eine neue ELK/Kibana Version

Vor kurzem Stand ein Update unseres ELK Stacks 1.x/Kibana 4 auf ELK 5.x/Kibana 5 an, einhergehend mit einem neuen Index- und Schemakonzept. Die grundlegenden Datenstrukturen haben sich bei Kibana 5 dankenswerterweise kaum geändert. Die aus Kibana 4 exportierten Dateien waren daher problemlos in Kibana 5 importierbar. Es waren daher nur noch folgende Schritte notwendig:

  • Die Schemaänderung bedeutete, dass wir über alle Dateien die Feldnamen um einen Prefix erweitern mussten, was über mehrfaches globales Suchen und Ersetzen in IntelliJ schnell erledigt war.
  • Gleiches galt für den Indexnamen, der überall zu ersetzen war.
  • Die bisherigen Felder wurden teilweise für Aggregationen benutzt. Das ging für numerische und Datumsfelder weiterhin ohne Anpassung, für Textfelder musste allerdings der Feldname um den Postfix .keyword erweitert werden.
  • Das Dashboard-Layout hatte sich leicht geändert. Die Layoutanpassungen haben wir abschließend direkt in Kibana vorgenommen.

Über diesen Weg haben wir alle Dashboards innerhalb eines Tages migrieren können.

kibconfig ist als kostenloses Tool unter der GPL v3 bei GitHub verfügbar. Euer Feedback und Pull Requests werden dankend angenommen.

The post kibconfig – Wartungstool für Kibana Dashboards appeared first on codecentric AG Blog.

Agile, frisch gebackene Dokumentation – Teil 2: PlantUML mit JBake

$
0
0

Nachdem wir uns im ersten Teil mit der Konfiguration von JBake beschäftigt haben, möchte ich in diesem Blogpost das Szenario um PlantUML erweitern.
PlantUML ermöglicht es, UML-Diagramme in einfacher textueller Notation zu beschreiben.

@startuml
start
:Hello world;
stop
@enduml
Result of

Wir wollen nun PlantUML zu allererst in das bestehende Gradle Buildfile integrieren. Hierzu benötigen wir AsciidoctorJ-Diagram als externe Bibliothek für das Buildscript. Die Konfiguration von JBake muss für die Verwendung der asciidoctorj-diagram-Bibliothek angepasst werden. Die Bibliothek AsciidoctorJ-Diagram ermöglicht es nun, PlantUML-Diagramme innerhalb des Asciidoctor-Dokuments zu verwenden.

buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }

    dependencies {
        classpath 'org.asciidoctor:asciidoctorj-diagram:1.5.4.1'
    }
}

plugins {
     id 'org.jbake.site' version '1.0.0'
}

group 'de.codecentric.dk.afgd'
version '1.0-SNAPSHOT'

apply plugin: 'groovy'
apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.3.11'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

jbake {
    srcDirName = 'src/documentation'
    destDirName = 'documentation'
    configuration['asciidoctor.option.requires'] = "asciidoctor-diagram"
    configuration['asciidoctor.attributes'] = [
            "sourceDir=${projectDir}",
            "imagesDir=diagrams",
            "imagesoutdir=${bake.input}/assets/diagrams"
    ]
}

build.dependsOn bake

Nun erstellen wir innerhalb des content-Ordners eine neue Datei architecture.adoc. Der Inhalt der Datei kann dem nachfolgenden Code-Block entnommen werden.

= Architecture documentation
Daniel Kocot
2017-11-20
:jbake-type: page
:jbake-tags: documentation, manual
:jbake-status: published

== First draft

[plantuml, "first_draft", "png"]
----
node "Confluence as content repository" as nodeconf
folder Intranet{
    together {
        node "WordPress Node 1" as nodeiwp1
        node "WordPress Node 2" as nodeiwp2
        node "WordPress Node 3" as nodeiwp3
        node "WordPress Node 4" as nodeiwp4
    }
}
folder Extranet{
    together {
        node "WordPress Node 1" as nodeewp1
        node "WordPress Node 2" as nodeewp2
        node "WordPress Node 3" as nodeewp3
        node "WordPress Node 4" as nodeewp4
    }
}
node "LoadBalancer / nginx Intranet" as lbinginx
node "LoadBalancer / nginx Extranet" as lbenginx
node "Content Delivery Network" as cdn
cloud "Intranet" as intranet
cloud "Extra/Internet" as internet
actor "Internal User" as internal
actor "External User" as external
nodeconf --> nodeiwp1
nodeconf --> nodeiwp2
nodeconf --> nodeiwp3
nodeconf --> nodeiwp4
nodeconf --> nodeewp1
nodeconf --> nodeewp2
nodeconf --> nodeewp3
nodeconf --> nodeewp4
nodeewp1 <--> lbenginx
nodeewp2 <--> lbenginx
nodeewp3 <--> lbenginx
nodeewp4 <--> lbenginx
nodeiwp1 <--> lbinginx
nodeiwp2 <--> lbinginx
nodeiwp3 <--> lbinginx
nodeiwp4 <--> lbinginx
cdn <--> nodeconf
cdn --> nodeewp1
cdn --> nodeewp2
cdn --> nodeewp3
cdn --> nodeewp4
cdn --> nodeiwp1
cdn --> nodeiwp2
cdn --> nodeiwp3
cdn --> nodeiwp4
lbinginx <--> intranet
lbenginx <--> internet
external <--> internet
internal <--> intranet
----

Nachdem wir den ersten Draft für unser Architekturdiagramm in das Dokument geschrieben haben, bleibt nun die Frage, wie aus den Textinhalten nun eine Grafik wird.

Hierzu wird beim Erstellen der gesamten Dokumentation im ersten Schritt per PlantUML nun ein Bild, in unserem Fall im PNG-Format, generiert. Dieses wird im Assets-Ordner mit dem Namen first-draft und der Dateiendung .png gespeichert. In einem zweiten Schritt erstellt JBake nun die entsprechende HTML-Datei auf Basis der Asciidoctor-Datei.

Durch die Integration von PlantUML sind wir in die Lage versetzt, auch die wichtigen Architekturdiagramme nah am Quellcode zu pflegen. Im dritten Teil dieser Reihe werden wir einen Blick auf Testreports und deren Integration in JBake werfen.

Eine Demo findet ihr in meinem Git-Repository agile-fresh-baked-docs.

The post Agile, frisch gebackene Dokumentation – Teil 2: PlantUML mit JBake appeared first on codecentric AG Blog.

Sketchnotes – komplexe Zusammenhänge einfach visualisieren

$
0
0
Sketchnotes mit Marcel und Atilim

Sketchnote von Anke Schaffrek

Zutaten: Papier, Stift und eine Portion Mut

Als Kinder malen wir alles, was uns in den Sinn kommt, egal, ob das gut aussieht oder nur als Gekritzel für uns dient. Wir machen Sketchnotes. Wir erklären jedem, den es interessiert, was wir auf den Bildern festgehalten haben. Für uns haben diese Zeichnungen einen höheren Erinnerungswert als die vielen Fotos, die unsere Eltern schießen. Denn wir geben durch diese unseren eigenen Inhalt wieder, einen Teil von unserem Inneren, von unserer Gedankenwelt.
Hierfür braucht es nicht viel: ein paar gute Stifte und gutes Papier – und eine Prise Spaß dabei. Geschehnisse und Erzählungen werden so lebendig. Bilder haben ihre ganz eigenen Botschaften. Diese können wir für uns und für den Rest der Welt anschaulich bereitstellen.
Mit Sketchnotes ist das möglich. Sketchnotes wecken Interesse für ein Thema, sie ziehen Leser und Hingucker in ihren Bann. Ihr könnt mit einfachen Mitteln über ein Thema informieren, Emotionen wecken.

Wir machen aus einem Wochenendspaß eine ernste Angelegenheit

Es beginnt mit einem harmlosen Wochenendausflug nach Hamburg zu unserer „Kritzelfee“. Das Thema: Handlettering und der Einstieg in Sketchnotes. Voller Tatendrang und ausgerüstet mit Stiften und einem Sketchnote-Buch beginnen fünf Menschen eine zweitägige, entspannte Reise durch die Welt der kleinen Zeichnungen.

Sketchnote-Kurs in Hamburg wird zum Hobby

Sketchnote-Kurs in Hamburg wird zum Hobby

Etwas albern, sehr gut gelaunt und doch auch ein wenig ehrgeizig gehen wir an die Sache ran: Wir wollen nämlich für uns selbst einen Erinnerungswert und für andere einen Erkennungswert schaffen. Das alles mit möglichst wenig Text, dafür aber mit anschaulichen Sketchnotes. Und wir packen noch ein Quäntchen Humor dazu.
Wie sich später herausstellen wird, ist dieser erste Kurs ein immenser Gewinn für uns Kollegen und für alle, denen wir davon erzählen und denen wir unsere Notes zeigen. Was als Wochenendspaß begann, stellt sich als offensichtlich längerfristige Angelegenheit heraus, die uns im Folgenden nicht mehr loslassen möchte.

Gedanken festhalten

In der Schule werden wir getadelt, wenn wir unsere kleinen Gedankenskizzen machen. Oft lernen wir hier, dass dies ein unerwünschtes Verhalten ist. Dann, wenn wir erwachsen werden, sitzen wir manchmal in ewig langen Meetings, Vorträgen und Gesprächen, die sehr interessant sein können. Aber das Zuhören fordert seinen Tribut: Wir werden müde und unaufmerksam, wir folgen einer Erzählung inhaltlich und machen uns unsere eigenen Gedanken.
Doch unsere eigenen Ideen und Gedanken gehen leicht verloren. Wir versuchen sie aufzuschreiben, vielleicht sogar das soeben Erfahrene auf abstrakte Weise mit unserem Buchstabenwerkzeug festzuhalten. Wir tippen auf unserer Tastatur, doch der Kern geht verloren. Tage, Wochen, Monate später ist das Gehörte verschwommen, wir haben kein Bild mehr davon im Kopf.
Wir können durch die Kombination von Text, Bildern und einer Bildstruktur unseren Kreativprozessen Raum geben. Wir können unsere Kernideen verdeutlichen oder sogar weiterentwickeln.
Als Ergebnis erhalten wir eine umfassende Karte im Kopf, auf der alle Informationen detailliert hinterlegt sind.

Was sind Sketchnotes?

Dieses „sinnvolle Gekritzel“ sind Notizen, die man mit Hilfe der Verbindung der drei Elemente Text, Bild und Struktur erstellt.
Der Text wird oft nicht nur als Aneinanderreihung von Buchstaben verwendet:
Der Text kann in Hierarchien, mit Hervorhebungen und Betonungen eingesetzt werden. Wir nutzen hier die Schrift wie ein Bildelement. Wird das Wort „!STARK!“ geschrieben, ist der Effekt stark und kräftig. Ein zartes „schwach“ dagegen wirkt viel zurückhaltender. Mit kurzen Notizen zeichnen wir das Wesentliche statt akribisch zu dokumentieren.

Bilder sagen mehr als 1000 Worte. Eine stilisierte Uhr, die „Viertel nach zwölf“ zeigt, ist schneller zu erfassen als die aufgeschriebene Uhrzeit.
Die Bilder sind so einfach wie möglich, aus den Grundformen Kreis, Dreieck, Viereck und Linien lassen sich die meisten Formen darstellen.

Damit der Information Halt und Ordnung gegeben wird, braucht es Struktur. Ein wichtiges Element sind Container beziehungsweise Rahmen. Diagramme, Pfeile, Textkästen und Trennlinien bieten eine Palette an Möglichkeiten, dem Bild Struktur zu geben. Container fassen zusammen, kategorisieren und geben einer jeden Sketchnote einen feinen Schliff.

Eine Möglichkeit zur Darstellung eines Handlungsstranges sind Assoziationsketten:
Der Begriff, um den sich das Geschehnis dreht, wird in der Mitte eines Blattes platziert, und alle Begriffe, die damit zusammenhängen, gehen davon ab. Untergeordnete Begriffe werden jeweils in Grüppchen um das zugehörige Wort positioniert.

Sketchnotes bestehen aus Bildern, Text und Struktur.

Es braucht nur Mut, Stift & Papier – Bild, Text & Struktur machen die Sketchnote rund.

Das obige Sketching ist ein Beispiel für den Textabschnitt „Was sind Sketchnotes?“

Wozu das Gekritzel ?

Statt langer Notizen findet sich nur das Wesentliche auf einem Blatt Papier. Statt eines Textwustes erscheint die Quintessenz als Skizze. Und es gibt so viele Möglichkeiten, das Aufgenommene darzustellen.
Im Grunde genommen benötigt man für Sketchnotes kein zeichnerisches Talent – allerdings ist die Fähigkeit hilfreich, Ideen mittels Formen, Verbindungen und Text visuell zusammenfassen zu können. Wie schon weise Kunstlehrer sagen: „Mit etwas Technik kann jeder malen.“ Erst die Technik, dann kann die Kreativität frei fliegen.
Mit Hilfe von Sketchnotes kann bereits Gelesenes, Gesehenes oder Gehörtes schnell wieder abrufbar gemacht werden. Ein Thema kann auf einen Blick erschlossen werden und so ein leichterer Einstieg ermöglicht werden. Mit Sketchnotes ist es einfacher, Elemente zu gruppieren und zu hierarchisieren. Diese Vorteile können beim protokollieren von Vorträgen, bei längeren Blog-Artikeln oder Videos hilfreich sein, um das Erfahrene festzuhalten und zu illustrieren.

In der Zeichnung liegt die Würze

Sketchnotes können einige Informationen besser als ein reiner Text liefern.

Ich kann beispielsweise für eine Tour nach Australien die Route folgendermaßen beschreiben:

Berlin-Moskau-Shanghai-Melbourne-Alice Springs-Adelaide-Melbourne-Sydney-Perth-Singapur-Doha-Berlin

Die Sketchnote hierzu gibt uns Betrachtern auf einen Blick eine Orientierung, und es entsteht ein Bild in unseren Köpfen.
Wir ahnen, wo wir uns in etwa räumlich befinden und was uns erwartet (Küste/Meer etc.).

Die Reiseroute wird verbildlicht.

Abstrakter Text wird verbildlicht.

Auch meine Reise mit meinem Freund habe ich in teils witzigen Sketchnotes festgehalten. So erinnern wir uns mehr als nur durch Fotos oder Erzählungen. Die lustigen und einschneidenden Momente können wir uns in einer Bild-Text-Kombi bewahren.

Reisedetails in Bild und Form

Sketchnotes als gemeinsames Erinnerungsmedium

Nicht nur für sich selber, auch anderen kann man seine Sketchnotes zur Verfügung stellen.

 

Privater Spaß  findet Einzug in den beruflichen Alltag

Wir können mit unseren Sketchnotes Zusammenhänge erklären und aufzeigen. Die bildliche, lockere Darstellung erlaubt es uns, über die Sache zu sprechen als etwas Fassbares, als etwas, auf das man zeigen kann. Wir bekommen alle ein ähnliches Bild von einer Erzählung, einer Unterhaltung, eines Meetings oder eines Artikels.

Informativ

Wie wir uns größere Informationsportionen einprägsam und ansprechend merken können, zeigt eine Sketchnote unseres geschätzten Kollegen René Bohrenfeld über den folgenden Artikel: Explaining Agile

Sketch von René Bohrenfeld - Artikel über Agilität

Sketchnote von René Bohrenfeld

Zum einen erleichtert ein Bild die Informationsaufnahme: Mehr als 3/4 der Informationen nehmen wir mit den Augen wahr, Inhalte eines Bildes werden von unserem Gehirn 60.000 mal schneller erfasst als ein einfach geschriebener Text.
Zum anderen erzählt ein Bild eine Geschichte, es ergänzt die Botschaft des (Blog)artikels, die Mitschrift eines Meetings, einer Vorlesung, eines Vortrags.

Mit Hilfe einer bildlichen Darstellung können wir – eher als mit einem Text – unseren Emotionen Ausdruck verleihen, die Essenz des Erlebten wiederspiegeln.

Der erste Praxistest

Vor einigen Monaten habe ich mich bei einer recht konservativen Organisation beworben, bei der bisher Interessenten nur mündlich vorstellig wurden oder aber Powerpointpräsentationen mit bis zu 90 Folien vorführten. Mehr aus revolutionärem Gedanken denn ernsthafter Anwandlung beschloss ich kurz vor meinem Auftritt, mich per Sketchnote vorzustellen. Das Publikum bestand aus 14 Damen und Herren, die nicht den Eindruck erweckten, mich mit offenen Armen empfangen zu wollen.
Ich fertigte nun eine sehr schnelle Skizze an, fotografierte diese und nutzte den Beamer zur Präsentation meiner Vorstellungs-Sketchnote. Den erstaunten Mitgliedern erzählte ich mittels der Bilder meine Geschichte und hatte damit direkt den größten Teil dieser Gruppe für meine Person interessiert: Praxistest bestanden!

Sketchnote für Vorstellung und Lebenslauf

Vorstellung und Lebenslauf Atilim Siegmund

Sketchnote-Kurse

Einige Wochen später wurde ich gefragt, ob ich mir vorstellen könne, bei der OOP-Konferenz einen Sketchnotes-Workshop zu geben. Dieses Angebot konnte und wollte ich nicht ausschlagen, denn mittlerweile hatte mich die Welt der kleinen Skizzen schon in ihren Bann gezogen.
Heute genieße ich jeden Tag, an dem ich anderen zeigen darf, wie einfach man seine Gedankenwelt teilen und kommunizieren kann. Und dabei wird nicht nur Zeichenpraxis erworben, der Aufbau all dieser Fähigkeiten macht ungeheuer Spaß. Der Wunsch, diese Erfahrungen mit anderen teilen zu wollen, erschien daher ganz natürlich.
Und da in letzter Zeit bei den Kollegen immer öfter die Frage aufkam „Wie fange ich mit Sketchnotes an?“ haben wir im Kollegenkreis beschlossen, Sketchnotes weiter zu nutzen, zu üben und zu verfeinern. Und wir haben ein großes Ziel: Einen eigenen Kurs gemeinsam zu entwickeln – sowohl zur firmeninternen als auch zur externen Nutzung.
Wenn ihr also in eurer 20%-Zeit mal an einer Gruppe begeisterter, stifthaltender, spaßhabender Kollegen vorbeikommt, die über Zeichen-Pads gebeugt sind: Das sind wir. Seit 6 Monaten mit Begeisterung dabei, malen, sketchen und entwickeln wir weiter unseren Kurs.

Gemeinsam entdecken wir in unseren Sketchnote-Kursen immer wieder lllustrations-Wunderkinder. Das Talent zur bildlichen Darstellung zeigt sich oft unvermutet und weckt die Lust nach mehr!
Die Teilnehmer bekommen von uns einen Leitfaden zur Verfügung gestellt, durch den sie die eigene Informationsaufnahme und -verarbeitung schulen können. Wir geben praktische und einfach umzusetzende Tipps. Wir zeigen, wie man gliedert und Struktur gibt, wie man Textcontainer erstellt und mit Farben Akzente setzt. Der Einstieg in diese Art der Dokumentation fällt da ganz leicht.

Sketchnotekurse an März 2018 , Terminanfrage: atilim.siegmund@codecentric.de

Sketchnotekurse machen Spaß!

Wir bieten einen Kurs für Einsteiger und einen Fortgeschrittenenkurs an. Wenn Ihr Lust  habt, es auszuprobieren, schreibt an atilim.siegmund@codecentric.de

Ich bedanke mich sehr bei Anke Schaffrek, Marcel Wolf, René Bohrenfeld und Werner Lieblang und freue mich auf unsere weiteren gemeinsamen Workshops.

The post Sketchnotes – komplexe Zusammenhänge einfach visualisieren appeared first on codecentric AG Blog.

Viewing all 129 articles
Browse latest View live




Latest Images