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

Beispiel: Schneiden von User Stories

$
0
0

In der Rolle des Product Owners steht man immer wieder vor der Aufgabe, eine Softwareanforderung (eine große User Story oder ein Epic) in mehrere kleinere zu schneiden. Dabei sollten diese kleineren Funktionspakete, wenn sie einzeln umgesetzt werden, immer noch sinnvoll nutzbar sein. Unerfahrene Product Owner und Teams haben aber oft keine Idee, wie sie dies bei ihren Anforderungen umsetzen können.

Daher möchte ich das an einem konkreten Beispiel, das ich aus einem Kundenprojekt entlehnt habe, zeigen.

Als Mitarbeiter möchte ich einen Konferenzraum im Intranet buchen, um dort eine Besprechung abzuhalten.

Diese User Story ist ein Platzhalter für einen ganze Gruppe an Funktionalität, die sich um das Thema Raumbuchungen dreht. Neben der direkten Buchungsfunktionalität soll es auch möglich sein, die hauseigene Bewirtung oder mobile Raumausstattung, wie Flipcharts oder Metaplanwände, zu bestellen. Die meisten Räume können, wenn sie noch frei sind, direkt gebucht werden, aber einige werden von Raumverantwortlichen verwaltet, die eine Buchung erst bestätigen müssen (z.B. Konferenzräume in der Vorstandsetage). Viele Raumbuchungen und Bewirtungsbestellungen werden nicht storniert, obwohl die Besprechung gar nicht stattfindet. So fallen unnötige Kosten durch die Bewirtung an und Besprechungsräume bleiben ungenutzt, obwohl andere Mitarbeiter Räume benötigen. Daher sollen die Buchenden vorab noch einmal an ihre Reservierung erinnert werden.

Dies alles als eine einzige User Story umzusetzen ist im agilen Umfeld keine Option, da die Umsetzungsdauer sehr lang ist und damit kein frühzeitiges fachliches Feedback möglich ist. Daher sollte diese große Story in mehrere kleinere User Stories herunter gebrochen werden.

Im ersten Schritt kann man mittelgroße Pakete rund um zusammenhängende Funktionalität bilden:

Funktionalität

User Story

Raumbuchung

Als Mitarbeiter möchte ich einen Raum buchen.

Bewirtung

Als Mitarbeiter möchte zu einer Buchung Bewirtung bestellen.

Ausstattung

Als Mitarbeiter möchte ich zusätzliche Ausstattung bestellen.

Freigabe/Verwaltete Räume

Als Raumbetreuer möchte ich eine Buchungsanfrage freigeben.

Serientermin

Als Mitarbeiter möchte für eine Terminserie einen Raum buchen.

Administration

Als Administrator möchte ich einen Raum in die Verwaltung aufnehmen.

Aber selbst diese User Stories sind noch groß und unhandlich. So lassen sie sich in kleinere Stories aufteilen:

Raumbuchung

In diesem Thema befinden sich neben der grundlegenden Funktionalität auch einige “Komfort”-Features. Die Basisfunktionalität wird durch folgende User Stories abgedeckt:

 Als Mitarbeiter möchte ich mich über die Räume und die Buchungsregeln im Intranet informieren.

Als Mitarbeiter möchte ich die bestehenden Buchungen für einen gegebenen Raum (in einer Kalenderdarstellung) ansehen.

Als Mitarbeiter möchte ich für einen bestimmten Zeitraum und Raum eine Buchung tätigen.

Als Mitarbeiter möchte ich eine von mir getätigte Buchung stornieren, um den nicht mehr benötigten Raum wieder für andere verfügbar zu machen.

Jeder dieser Stories kann einzeln umgesetzt und so schon ein Feedback zur Umsetzung eingeholt werden. Aber erst wenn alle Stories umgesetzt sind ist die Funktionalität zwar rudimentär aber sinnvoll  nutzbar.

Als Mitarbeiter möchte ich an eine getätigte Buchung erinnert werden, um sie ggf. zu stornieren.

Als Mitarbeiter möchte ich eine von mir getätigte Buchung ändern um sie nicht erst zu stornieren und dann neu zu buchen.

Als Mitarbeiter möchte ich für einen bestimmten Tag die Buchungen aller Räume sehen, um ggf. zu fragen, ob bereits getätigte Buchungen verschoben werden könnten, so dass noch ein passender Raum frei wird.

Als Mitarbeiter möchte ich alle von mir getätigten Buchungen sehen, um schnell zu meinen Buchungen zu navigieren.

Als Mitarbeiter möchte ich für einen bestimmten Zeitraum nach freien Räumen suchen, um für eine schon angesetzte Besprechung einen Raum zu reservieren.

Als Mitarbeiter möchte ich für einen bestimmten Raum in einem gegeben Zeitraum freie Zeiten suchen, um zu sehen, welche Termine für eine Besprechung möglich sind.

Als Mitarbeiter möchte ich in einem gegebenen Zeitraum nach freien Zeiten und freien Räumen suchen.

Bewirtung

Als Mitarbeiter möchte ich bei der Buchung eines Raums eine Bewirtung mitbestellen.

Die Bestellung von Bewirtungen erfolgt nicht über ein technisches System, sondern durch Versenden eines ausgefüllten Formulars an die Kantine, daher erfordert die erste Story im Grunde keine Persistenz der Bestellung.

Als Mitarbeiter möchte ich zu einer getätigten Buchung eine Bewirtung bestellen.

Als Besteller einer Bewirtung möchte ich diese stornieren.

Bei diesen beiden Stories sollte man sich merken, ob für eine Buchung schon eine Bewirtung bestellt wurde oder nicht.

Als Besteller einer Bewirtung möchte ich diese ändern.

Erst für diese Story ist es sinnvoll, die Daten einer Bestellung zu persistieren.

Ausstattung

Bei der Ausstattung ist eine ähnliche Aufteilung wie bei der Bewirtung möglich, sie unterscheiden sich nur in der inhaltlichen Ausgestaltung der erfassten Daten und den Empfängern der Bestellung.

Als Mitarbeiter möchte ich bei der Buchung eines Raums zusätzliche Raumausstattung mitbestellen.

Als Mitarbeiter möchte ich zu einer getätigten Buchung zusätzliche Raumausstattung bestellen.

Als Besteller von zusätzlicher Raumausstattung möchte ich diese stornieren.

Als Besteller von zusätzlicher Raumausstattung möchte ich diese ändern.

Freigabe/Verwaltete Räume

Die Aufteilung hier erfolgt entlang der Schritte im Freigabeprozess.

Als Mitarbeiter möchte ich eine Buchungsanfrage für einen verwalteten Raum stellen.

Auf den ersten Blick hat es dadurch den Anschein, dass nur wenn alle Schritte abgedeckt sind ein produktiver Einsatz sinnvoll ist. Aber diese Story lässt sich auch so umsetzen, dass sie alleine produktiv funktioniert. So könnte man nur den Raumverantwortlichen ermöglichen, den jeweiligen Raum zu buchen (bisherige Funktionalität) und die Buchungsanfrage erzeugt nur eine Nachricht an den jeweiligen Raumverantwortlichen. Alle weiteren Prozessschritte erfolgen dann außerhalb der Lösung. In dem man die (noch) nicht umgesetzten Schritte durch Kommunikation außerhalb der Anwendung löst, kann man auch die weiteren Stories einzeln umsetzen.

Als Raumverantwortlicher möchte ich alle offenen Buchungsanfragen für den verwalteten Raum sehen.

Als Raumverantwortlicher möchte ich eine Buchungsanfrage bestätigen oder ablehnen.

Als Mitarbeiter möchte ich alle meine noch offenen Buchungsanfragen sehen.

Als Mitarbeiter möchte ich eine offene Buchungsanfrage zurückziehen.

Serientermine

Als Mitarbeiter möchte ich für eine Terminserie einen Raum buchen.

Als Mitarbeiter möchte ich eine von mir erzeugte Serienbuchung stornieren.

Als Mitarbeiter möchte ich eine von mir erzeugte Serienbuchung ändern.

Die Einführung der Terminserien erweitert implizit auch alle anderen User Stories. So muss die Bewirtungsfunktionalität auch mit Serien funktionieren. Sollte diese schon implementiert sein, wäre sie anzupassen. Diese Anpassungen können aber (falls sie zu aufwendig sind) in eine weitere Story verlagert werden.

Als Mitarbeiter möchte ich eine einzelne Buchung einer von mir erzeugten Serie stornieren.

Als Mitarbeiter möchte ich eine einzelne Buchung einer von mir erzeugten Serie ändern.

Je nach Umsetzung der Serientermine sind die Stories bzgl. einzelner Buchungen einer Serie gar nicht notwendig.

Administration

Unter der Administration kann man sich natürlich noch viele weitere Stories ausdenken. Darunter fallen alle möglichen Konfigurationen (Raumverantwortliche, Bewirtungsoptionen, Erinnerungszeitraum, Beschreibung der Räume, …), die aber selten verändert werden und damit auch von einem technischen Administrator vorgenommen werden können. Als Beispiel sind hier zwei Stories aufgelistet.

Als Intranetadministrator möchte ich einen weiteren Raum für Buchungen verfügbar machen, da dieser Raum in einen Besprechungsraum umgebaut wurde.

Als Intranetadministrator möchte ich einen Raum aus dem Intranet löschen, da er nicht mehr als Besprechungsraum zur Verfügung steht.

Fazit

Aus der einen epischen User Story sind jetzt über dreißig kleine User Stories entstanden. Diese können jetzt von einem Team jeweils in akzeptabler Zeit (mehrere pro Iteration möglich oder eine geringe Cycle Time in ein kontinuierlichem Vorgehen) umgesetzt werden. So besteht die Möglichkeit, schon kurzfristig fachliches Feedback zu den einzelnen Punkten zu erhalten.

Weiterhin ermöglicht eine solche feine Aufteilung, die einzelnen Punkte unabhängig zu priorisieren, sowohl untereinander als auch in Bezug auf andere Anforderungen, die nichts mit dem Thema “Raumbuchungen” zu tun haben. Dies ermöglicht ggf. auch, mit einer nicht vollständigen Funktionalität produktiv zu starten.

Diese Zerteilung berücksichtigt keine technischen Aspekte, sondern basiert auf einem fachlich sinnvollen Funktionsschnitt. Bis auf einen initialen Satz an Stories (MVP) kann (bei einer sinnvollen Reihenfolge) nach jeder Story ein fachlich sinnvoller Produktstand erreicht werden.

Ich hoffe, dieses Beispiel hilft, Ideen zum Zerschneiden von Epics und großen User Stories zu entwickeln.

The post Beispiel: Schneiden von User Stories appeared first on codecentric Blog.


Lean Startups are eating the world!

$
0
0

Angelehnt an den Artikel von Mark Andreessen Software is eating the world zeigt der Vortrag wie sich Märkte durch neue Geschäftsmodelle in kurzer Zeit verändern können. Beispielsweise verändert das Startup MyTaxi den Markt für die Taxi Unternehmer und Taxi Zentralen enorm. Innerhalb weniger Jahre können fast die Hälfte der Taxen in Deutschland über die App von MyTaxi bestellt werden. Ähnliches macht AirBnB im Hotel Markt und es werden Innovationen durch Lean Startups in allen Bereichen folgen oder sind schon passiert. Der Vortrag zeigt deshalb auf, wie man auf das Innovators Dilemma reagieren und z.B. durch Continuous Delivery seine geschäftskritischen Anwendungen schneller ausliefern kann.

Der Vortrag wurde auf der Continuous Lifecycle 2013 als Keynote gehalten.

The post Lean Startups are eating the world! appeared first on codecentric Blog.

Warum Innovation in der IT jetzt wichtiger ist als Optimierung

$
0
0

Das Buch The Innovators Dilemma beschreibt das Problem, warum Unternehmen, die nach den klassischen BWL-Theorien alles richtig machen, trotzdem große Marktanteile verlieren oder komplett vom Markt verschwinden. Dies passiert dann, wenn so genannte „Disruptive Technologien“ im Spiel sind – Technologien/ Innovationen, die das Potenzial haben, eine bestehende Technologie oder Produkte vollständig zu verdrängen. Ein populäres Beispiel ist die digitale Fotografie, die die analoge, klassische Kleinbildfotografie komplett verdrängt hat. Einer der Marktführer, Agfa, setzte beispielsweise im Jahr 2000 noch 1,25 Milliarden Euro mit der Fotosparte um. Im Jahr 2004 waren es nur noch 693 Millionen Euro. Im Mai 2005 meldete die AgfaPhoto GmbH Insolvenz beim Amtsgericht Köln an. Innerhalb von fünf Jahren wurde also ein Milliardenmarkt von digitalen Kameras überrollt.

Waren die Zyklen für disruptive Technologien in der Vergangenheit noch relativ lang, werden sie jetzt immer kürzer. Globale Technologiemegatrends wie Smartphones, soziale Netzwerke oder Cloud Computing, die erst durch ein (mobiles) Breitbandinternet möglich wurden, ermöglichen disruptive Innovationen am Fließband. Nach Ansicht des Autors werden diese Technologien alle Wirtschaftsbereiche ähnlich nachhaltig verändern wie beispielsweise die Industrialisierung. Nur in einer viel höheren Geschwindigkeit. Der Artikel zeigt wie sich Unternehmen in der IT aufstellen müssen, um diesem Druck standhalten zu können.

The post Warum Innovation in der IT jetzt wichtiger ist als Optimierung appeared first on codecentric Blog.

Jenkins for Enterprise

$
0
0

Zusammen mit mehreren Kollegen habe ich in einem Training über die Jenkins Enterprise bei Cloudbees sehr interessante Features kennengelernt, die ich mir in den letzten Jahren bei der Arbeit mit Jenkins schon oft gewünscht habe!

Gegenüber der Community Version enthält diese Variante weitere Plugins, die alle dazu dienen, größere Installationen besser managen zu können, und das System insgesamt etwas schneller und stabiler zu machen: Mit den Enterprise Plugins wird das Arbeiten und Konfigurieren von Jenkins effizienter, also einfacher und schneller! Einige Highlights:

  • Wiederholte Konfigurationsteile können als “Templates” herausgezogen und zentral gepflegt werden (siehe nächster Abschnitt)
  • Für größere Organisationen existiert ein ausgeklügeltes Rollen- und Berechtigungssystem
  • Für High Availability kann ein Backup-Server beim Ausfall des Masters einspringen, und die abgebrochenen Jobs werden automatisch wieder aufgesetzt!
  • Mit “Validated Merge” gibt es jetzt eine Art Pre-Commit Build Step. Jenkins fungiert als “Gate”, und lässt das Einchecken von Änderungen nur zu, wenn es einen erfolgreichen Build gab. Damit erhält man immer einen sauberen Stand im Repository!
  • Im Custom Update Center kann eine eingeschränkte Liste an Plugins freigeben werden. Dabei können in bestimmten Versionen festgelegt werden. Damit kann verhindert werden, dass unkontrollierte Plugin-Versionen beim Update zu ungewünschten Nebeneffekten und Fehlern führen. Außerdem kann damit die Liste auf eine übersichtliche Menge reduziert. Das erleichtert das Aufsetzen und starten eines anderen, neuen Jenkins Masters mit genau definierten Plugins.
  • Es gibt viele weitere Verbesserungen. So wird der normale Artifact Archiver durch den Fast Archiver ersetzt, der wie rsync differenziell, also sehr schnell arbeitet.
  • Für Interessierte: man kann eine 60 (!) Tage lauffähige Evaluation Version bei cloudbees.com downloaden.

In diesem Blog stelle ich das Cloudbees Templates Plugin vor, weil es eine sehr effektive Konfiguration ermöglicht, was sehr viel Zeit sparen kann!

Cloudbees Templates Plugin

Häufig werden ähnliche Build Jobs angelegt. Sie unterscheiden sich oft nur in wenigen Details innerhalb der Build Steps. Müssen dabei Build Skripte angepasst werden, so heißt es, dass viele Jobs konfiguriert werden müssen, was aufwendig und fehleranfällig ist.

Es wäre also prima, wenn man alle gleichzeitig mit einer einzelnen Anpassung ändern könnte!

Hier hilft das Templates Plugin, weil es ermöglicht, einen Build Step zu definieren, der an einer zentrallen Stelle für alle Jobs gleichzeitig angepasst werden kann!

Neue Build Steps

Mit wenigen Schritten wird ein Builder Template angelegt. Es können auch Parameter definiert werden!

NewTemplateDeployWebapp

Dieser einfache Beispiel Build Step soll eine Web Applikation unter Windows zu einem Tomcat Server deployen. Wir benötigen dazu nur den Dateipfad zur war Datei

  • Dieser Pfad wird dann ins Windows Format umgewandelt
  • Per xcopy wird diese Datei auf den Test Server kopiert
configure Deploy Webapp Template Dialog

configure Deploy Webapp Template

Hier wird per Groovy Skript eine Variable gesetzt, die dann einfach im Batch Skript verwendet wird. Sehr einfach kann nun der neue Build Step benutzt werden:

Added a Custom "Deploy" Build Step

Added Custom “Deploy” Build Step

Die Konsolenausgabe sieht dann zum Beispiel so aus
Build Run Konsole

Build Run Konsole

Neue Jobs

Oft gibt es gleichartige Jobs für ähnliche Projekte, die sich im wesentlichen nur durch einige Parameter wie Projektname und Pfad ins Repository unterscheiden. Ein typisches Beispiel sind die Build-Jobs aller Jenkins Plugins. 

Wer solch eine Liste mit zum Beispiel mehr als 30 ähnlichen Jobs anpassen musste, der weis wie aufwendig es ist, und wünscht sich, die Konfiguration nur an einer Stelle pflegen zu können.

Dabei hilft das Cloudbees Template Plugin: Man definiert einen einzigen “Basis Job” mit Parametern, auf dem dann die gleichartigen Jobs basieren.

Am einfachsten gelingt es in zwei Schritten:

  • Zuerst legt man sich wie üblich einen “Beispiel Job” (hier: GenericPluginBuildJob) an, den man später natürlich “deaktiviert”, damit er nicht irrtümlich gestartet wird.
  • Dann erzeugt man daraus die Schablone für die anderen Jobs, indem man die gewünschten Parameter einfügt.
Configure Job Template

Configure Job Template – Teil 1

Hier wurde die Konfiguration des ersten Jobs geladen, und so angepasst, dass folgende Parameter eingesetzt werden:

Mit dem Namen wir hier der Github SCM Pfad erzeugt (siehe Hervorhebung)

NewTemplateBuildJenkPlugin-Job

NewTemplateBuildJenkPlugin-Job

Der neue Job wird dann basierend auf diesem Template erzeugt

Create Plugin Build Job

Create Plugin Build Job

und automatisch konfiguriert. Das Ergebnis nach einem Build Lauf

CreatedAndRunJenkinsPluginJob

Der Vorteil ist nun, dass sich Änderungen im Template sofort auf den nächsten gestarteten Build auswirkt!

Das Templates Plugin hilft somit, vor allem viel Zeit bei der Konfiguration einzusparen.

Eine Übersicht und viele weitere interessante Details über alle Enterprise Plugins findet man auf der Cloudbees Website.

The post Jenkins for Enterprise appeared first on codecentric Blog.

Agile Skaliert – Teil 1

$
0
0

Vor 19 Jahren wurde Scrum als neuer Entwicklungsprozess von Ken Schwaber und Jeff Sutherland auf der OOPSLA (Object-Oriented Programming, Systems, Languages & Applications) vorgestellt. Gleichzeitig erschien auch die erste Beschreibung des “Scrum Development Process“. 6 Jahre später folgte das agile Manifest, das mit seinen 4 Werten und 12 Prinzipien die Grundlage für eine andere Art und Weise der Zusammenarbeit innerhalb von Firmen und auch darüber hinaus legte.

Agile Vorgehensweisen sind mittlerweile im Mainstream angekommen; die Phase der „Early Adopters“ haben wir hinter uns gelassen und immer größere Unternehmen wollen von den Vorteilen dieser Art der Zusammenarbeit profitieren. Nicht zuletzt, weil der Marktdruck mit immer kürzeren Innovationszyklen ein dazu passendes Vorgehen unabkömmlich macht, um am Markt bestehen zu können. Als populärster Vertreter eines agilen Vorgehens wird dabei häufig Scrum eingesetzt.

Doch die Einführung von agilen Vorgehensweisen (z.B. Scrum) in großen Organisationen stellt diese vor völlig anderen Herausforderungen als dies noch beim Etablieren in kleinen Teams der Fall war. Dazu gehören beispielsweise:

  • Wie wird die Unternehmensidee (Vision) auf kleine, in Sprints umsetzbare Inkremente herunter gebrochen?
  • Wie behält das Unternehmen trotz der Umsetzung von sehr kleinteiligen Artefakten das große Ganze im Auge?
  • Wie kann eine notwendige Kommunikation zwischen den Kollegen zum richtigen Zeitpunkt sichergestellt werden? Wie vermeidet man zu viel unnötige Kommunikation?
  • Müssen bisherige Strukturen, Hierarchien und Rollen berücksichtigt werden? Wenn ja, wie?

Glücklicherweise können bereits einige Hilfestellungen zu diesem komplexen Thema gefunden werden:

  1. Ken Schwaber selbst hat (natürlich) dazu seine Ansichten veröffentlicht: „The Enterprise And Scrum
  2. Von Dean Leffingwell stammt das aktuell viel diskutierte „Scaled Agile Framework
  3. Craig Larman und Bas Vodde haben sich bereits vor einigen Jahren ihre Gedanken dazu gemacht: „Scaling Agile Development
  4. Der Erfahrungsbericht von Henrik Kniberg, wie Agile bei Spotify gelebt wird

Dies ist der 1. Teil einer Blogserie in der ich einen Überblick über diese Ideen und Vorgehensweisen gebe sowie die Vor- und Nachteile, die aus meiner Sicht damit jeweils einhergehen.

Ken Schwaber: „The Enterprise And Scrum“

Als Miterfinder von Scrum verfolgt Ken Schwaber einen sehr puristischen Ansatz beim Skalieren von Scrum in großen Unternehmen. Alle Rollen, Meetings und Artefakte von Scrum werden beibehalten. Übergreifende Abhängigkeiten der Teams und auch über Abteilungen hinweg werden über Backlogs gesteuert. Dies geht über das bekannte Product Backlog hinaus zu Backlogs zur Steuerung der Arbeit von den an der Transition beauftragten Teams, dem Produktmanagement und weiteren notwendigen Abteilungen. Als Hilfsmittel für jegliche Planungsaktivitäten werden auf jeder Ebene (Sprint, Release, Produkt, etc.) des Unternehmens jeweils Burndown-Charts genutzt.

 

Schwaber legt sehr viel Wert darauf, dass die Werte von Scrum auch bei großen Unternehmen nicht verfälscht werden. Weitere Rollen als die bekannten Scrum-Rollen sind nicht vorgesehen und seines Erachtens auch nicht notwendig. Er warnt davor, bei der Nutzung von Scrum bisherige Management-Rollen beizubehalten oder „Extra Manager“ sogar einzuführen. Alte hierarchische Strukturen lassen sich nicht mit der Nutzung von Scrum vereinbaren.

Ein Auszug aus seinem Buch dazu:

„I visited several Wingtip, Inc. teams at their Sprint Planning Meetings. Strangely, their managers were in attendance. The team members sat in silence, while the managers investigated the work, asked questions of the team members, committed the team to the Sprint goal, and then broke down and assigned the work. No self-management occurred. The productivity and joy of teamwork was forgone.
I investigated and found that 18 first- and second-level managers were still unassigned.“

Scrum Teams organisieren sich selbst und benötigen niemanden, der die Aufgaben vorgibt die zu erledigen sind. Stattdessen benötigen sie Ziele. Die Scrum Teams organisieren sich dann ihr Product Backlog selbst um diese Ziele zu erreichen. Ob diese Ziele erreicht wurden wird (spätestens) im Sprint Review überprüft. Aufbauend auf dieser Inspektion von erreichten Ergebnissen können dann auch notwendige Anpassungen vorgenommen werden. (Prinzip von “Inspect and Adapt” in Verbindung des „Fail Fast“.)

Die Strategie von Schwaber für eine Skalierung sieht vor, dass der Start mit Scrum mit einem Team erfolgt. Wenn neue Scrum Teams hinzugefügt werden, soll ein Teammitglied des bisherigen Teams (d.h. in der Abbildung aus 1) in die neuen Teams (1.1 bis 1.3) wandern. Das bisherige Scrum Team wird nun zum Integration Scrum Team und ist für die erfolgreiche Integration der Arbeit der anderen Teams in ein qualitativ hochwertiges Produkt verantwortlich. Dazu entwirft das Integration Scrum Team eine tragfähige Architektur, die Coding-Standards und verantwortet weitere notwendige Dinge die natürlich jeweils von dem Produkt abhängig sind.

Schwaber_Example_Activity-Level

Bei weiterem Wachstum der Organisation kann eine Skalierung von Scrum mit weiteren Ebenen so aussehen:

Schwaber_Enterprise_Work

Zu beachten ist dabei, dass das Produkt mit fortschreitender Skalierung in immer feinere Ebenen (Product – Function – Activity – Task) auf die Scrum-Teams herunter gebrochen wird.

Zusammenfassung

Schwaber verwendet alle Methoden und Artefakte von Scrum auch bei der Skalierung innerhalb von großen Organisationen. Es werden keine zusätzlichen Rollen oder Artefakte eingeführt. Stattdessen setzt er sehr stark auf die Selbstorganisation der Teams und der Vorgabe von Leitplanken, in dem jedes Team und jeder Einzelne einen sehr großen Handlungsspielraum hat, um die tägliche Arbeit zur Erreichung des Ziels (Produktvision, etc.) zu Planen und zu Organisieren.

Beim Skalieren von Scrum verwendet Schwaber ein initiales Scrum-Team, welches quasi als Keimzelle für einen Ausbau mit weiteren Teams dient.

Auch wenn es Schwaber explizit nicht nennt: Eine Reflektion über das Vorgehen und ggf. Adaption der Zusammenarbeit ist notwendig. Dazu dienen natürlich die Retrospektiven die zu diesem Zweck auch teamübergreifend stattfinden.

Bewertung

Der sehr gradlinige Ansatz von Schwaber beim Skalieren von Scrum ist für alle „Scrum-Puristen“ sicherlich sehr reizvoll. Große Unternehmen werden aber ein Problem damit bekommen, die sehr rigide Vorgehensweise 1:1 umzusetzen. Da Schwaber sehr wenige explizite Vorgaben macht und auf die Selbstorganisation der verantwortlichen Teams setzt, muss eine Skalierung von Mitarbeitern mit sehr viel Scrum-Erfahrung begeleitet werden.

Schwaber zerteilt das Produkt in mehrere Ebenen um den Entwicklungsteams die Möglichkeit zu geben die Product Backlog Items selbstorganisiert und eigenverantwortlich umzusetzen. Auch bei skalierten Scrum soll ein Scrum-Team selbständig die Product Backlog Items umsetzen können (Feature-Teams). Dieser Ansatz stößt meines Erachtens bei großen Produkten irgendwann an seine Grenze da ein Scrum-Team mit 7-9 Personen nicht mehr nicht mehr das notwendige Knowhow besitzen kann.

 

Ich möchte mich gerne zu Euren Erfahrungen bei dem Einsatz von Scrum in großen Unternehmen austauschen. Welche Probleme traten beim Umdenken von „Command & Control“ hin zu (mehr) Selbstorganisation und Verantwortung auf? Wie wurden die jeweiligen Abhängigkeiten der Teams untereinander festgehalten und geplant? Welche Probleme traten bei der Verbindung zu anderen Teams die nicht Scrum nutzen auf und wie wurden diese gelöst?

Kommentare Willkommen!

 

Dies war Teil 1 der Serie „Skalieren von agilen Vorgehen“ mit den Ideen von Ken Schwaber. Im zweiten Teil wenden wir uns dem derzeit sehr bekannten „Scaled Agile Framework“ (SAFe) von den Erfindern des Rational Unified Process (RUP) zu.

 

The post Agile Skaliert – Teil 1 appeared first on codecentric Blog.

Agile Skaliert – Teil 2

$
0
0

Im ersten Teil der Blogserie habe ich die Ideen von Ken Schwaber zu skalierten agilen Vorgehen dargestellt. In diesem Teil sehen wir uns nun das derzeit recht populäre Scaled Agile Framework (SAFe™) an.
SAFe_Big_Picture
Auf den ersten Blick fällt auf, dass bei diesem Framework die Produktentwicklung (bzw. das Projekt) in drei Ebenen aufgeteilt wird.

  • Portfolio
  • Program
  • Team

Portfolio Ebene

Auf dieser Ebene werden von einem sog. „Program Portfolio Management“ anhand der Unternehmensstrategie die Programme abgeleitet und verabschiedet. Hier entstehen die Epics, und zwar zwei Arten davon: die Business Epics und die Architectural Epics. Die Business Epics sind von der zeitlichen Dimension her so beschaffen, dass mehrere Releases benötigt werden um diese umzusetzen. Dies können mehrere Monate bis zu Jahren sein! Für die Erzeugung dieser Business Epics sieht SAFe ein Kanban System vor, um die notwendigen Schritte zur Analyse und Genehmigung bzw. Ablehnung der Epics durchzuführen. business_epic_kanban_system

Funnel: Dies ist der Ideenpool der Organisation. Hier können alle Ideen für die weitere Entwicklung des Produktes / des Unternehmens platziert werden. Da jede Idee willkommen ist, gibt in dieser Stufe keinen Beschränkung hinsichtlich Anzahl. (Kein Limit des Work in Progress.)

Backlog: Um den Grund und den Wertbeitrag des Epics darzulegen, wird ein „Value Statement“ formuliert. In dieser Bearbeitungsstufe wird das Epic auch grob geschätzt. Außerdem wird ein „Epic Owner“ festgelegt, der die weitere Bearbeitung des Epics begleitet.

Analysis: In dieser Bearbeitungsstufe werden Workshops durchgeführt, um aus Sicht der Fachbereiche und des Managements die wirtschaftliche Betrachtung und die Erfolgskriterien durchzuführen und festzulegen. Um den Implementierungsaufwand und Auswirkungen auf bestehende Systeme abzuschätzen, werden sog. „System Architects and Agile Team Leads“ heran gezogen. Am Ende dieses Bearbeitungsschrittes steht die Go/No-Go-Entscheidung.

Implementation: Das Epic wird nun in das Portfolio Backlog eingetragen und wartet dort, bis die Implementierung starten kann. Der Epic Owner muss gemeinsam mit Product Managern und System Architects das Epic kleiner schneiden: in Sub-Epics und Features. Diese Ergebnisse werden dann für die weitere Bearbeitung auf die individuellen Program Backlogs verteilt.

Program Ebene

Während der Planungshorizont der Portfolio Ebene mehrere Monate umfassen kann, arbeitet die Program Ebene mit Zyklen von ca. 8-10 Wochen. Der Fokus liegt hier auf dem Feedback der Kunden und der Fachbereiche. Die entwickelten Softwareartefakte werden dabei mit Hilfe des „Release Train“-Prinzips (http://scalingsoftwareagilityblog.com/wp-content/uploads/2009/03/whitepaper_systems-of-systems-and-the-agile-release-train2.pdf) ausgeliefert. Der Release Train fast die Ergebnisse von 5-15 Entwicklungsteams zusammen. Auf dieser Ebene des SAFe ist ein „System Team“ für den Zusammenbau der gelieferten Softwareartefakte und ggf. End-To-End-Tests verantwortlich. Unterstützt wird dieses Team bei Bedarf von einem „Release Management Team“. Die Produktsicht, d.h. die letztendliche Entscheidung welche Features geliefert werden, wird von einem „Product Management“ vertreten.

Team Ebene

Die vollständige Umsetzung der Anforderungen aus den jeweiligen Team Backlogs liegt in der Verantwortung der „Agile Teams“. Mit Hilfe von Scrum und XP arbeiten alle Teams selbstverantwortlich an der Umsetzung ihrer Backlog Items – natürlich mit Blick auf das gemeinsame Ziel auf Program Ebene. Wie im Konzept des Release Train beinhaltet schlägt SAFe zusätzlich zu den reinen Entwicklungsiterationen spezielle HIP-Iterationen vor (Hardening, Innovation, Planning) die auch als Planungspuffer dienen können. Ansonsten werden die meisten Praktiken von Scrum übernommen:

  • Rollen: Scrum Master, Product Owner, Developers und Tester
  • Meetings: Daily Standup, Planning, Team Demo (Review), Retrospective (auf Ebene der einzelnen Teams)
  • Metriken: Burndown-Charts, relatives Schätzen mit normalisierten (!) Story Points

Zusammenfassung

Das SAFe beinhaltet auf der Teamebene viele Elemente von Scrum die mit weiteren Konzepten, z.B. dem „Agile Release Train“ ergänzt werden. Um die Komplexität großer Organisationen in den Griff zu bekommen wird eine hierarchische Struktur mit zwei weiteren Ebenen (Program, Portfolio) eingeführt. Für die Softwareentwicklung wird zwar Scrum vorgeschlagen, dabei sind aber wichtige Zuständigkeiten wie UX, Architektur, Delivery aus den Scrum Teams extrahiert und an dedizierte Rollen abgegeben.

Bewertung

Für eine Einschätzung des SAFe schauen wir uns einmal die Wertepaare des agilen Manifests an:

Individuals and interactions over processes and tools

Damit eine Idee für eine neue Funktionalität den Weg in den Programcode findet, müssen einige Stationen passiert werden: Über die Portfolio Vision mit dem Epic Owner durch das Program Portfolio Management in die Roadmap und das Program Backlog. Dann folgt das Product Management und Release Management welches das Program Backlog in die Team Backlogs überführt. Dabei bringen sich dann noch Business Owner, UX-Experten, Architekten und der Release Train Engineer mit ein. Im Anschluss kümmert sich dann der Product Owner über die korrekte Umsetzung des ihm übertragenen Team Backlogs.

Bei diesen Entscheidungswegen werden die Scrum Teams nur noch als Werkbank zur Umsetzung der von den diversen Management Teams beschlossenen Ideen verwendet. Eine gemeinsame und übergreifende Zusammenarbeit zur Findung neuer Ideen und Weiterentwicklung des Produktes kann m.E. bei diesem Setup nur schwer stattfinden. Abteilungsübergreifende Rückkopplungsschleifen, sei es nun zu dem Produkt oder dem Prozess konnte ich im SAFe nicht finden. Doch gerade die Möglichkeit der ständigen Anpassung an neue Gegebenheiten ist ja eines der wichtigsten Aspekte bei agilen Vorgehensweisen bzw. Scrum.

Working software over comprehensive documentation

Bei dieser starken Trennung der Zuständigkeiten (Architektur, UX, Deployment) besteht die große Gefahr, dass die Teams wieder in alte Verhaltensmuster von phasenorientierten Vorgehensweisen zurückfallen und nur noch die genau zugewiesenen Aufgaben ausführen, ohne nach links oder rechts zu schauen. Ich sehe hier schon ausführliche UI-Dokumentationen oder riesige bunte Architekturbilder vor meinem geistigen Auge…

Customer collaboration over contract negotiation

Die Einbindung des wichtigsten Personenkreises -den Kunden- findet durch das Product Management, den Business Ownern und den Product Ownern statt. Wie mit dieser Konstellation eine enge Zusammenarbeit mit den Kunden möglich ist, erschließt sich mir nicht. Für mich besteht hier eher die Gefahr, dass Kundeninteressen auf der Strecke bleiben da hier klare Zuständigkeiten nicht zu erkennen sind.

Responding to change over following a plan

Die vielen zuständigen Teams (Program Portfolio Management, Product Management, Release Management, Architect, UX-Experte, Product Owner) bedingen natürlich entsprechende Entscheidungswege und Planungen. Nehmen wir einmal an, in einem Sprint Review hat ein Entwickler eine Idee für ein neues Feature. Es wird einige Zeit dauern, bis diese Idee dann durch alle Gremien gewandert ist und Berücksichtigung in der Portfolio Vision, der Roadmap, dem Program Backlog, den Team Backlogs und letztendlich in der Entwicklung findet.Bis dahin wird natürlich der ursprüngliche Plan weiter verfolgt, d.h. eine schnelle Reaktion auf geänderte Marktanforderungen ist nicht möglich.

Das SAFe bietet auf den ersten Blick ein vollständiges Bild über die Durchführung agiler Softwareentwicklung in großen Organisationen mit einer großen Anzahl von definierten Rollen und klaren Zuweisungen der jeweiligen Aufgabenbereiche. Diese detaillierte Darstellung macht die Transition zu „Agile“ natürlich auf den ersten Blick leichter; man muss ja nur diesen genauen Vorgaben von SAFe folgen.

Doch meines Erachtens liegt genau hier die Gefahr bei der Anwendung von SAFe. Gerade dadurch dass das Vorgehen mit allen Rollen und Zuständigkeiten bereits feststeht und ausführlich beschrieben ist, wird dem Unterbleiben der notwendigen Inspektion und Adaption auf die speziellen Bedürfnisse der Organisation Vorschub geleistet. Doch gerade dieses ständige Reflektieren und Anpassen / Verbessern der täglichen Arbeit, der Prozesse und damit der gesamten Organisation ist das Herz von agilem Vorgehen.

Die großen Vorteile agiler Vorgehensweisen zum Beispiel die intensivere Einbindung aller Beteiligten, die schnelle Reaktion auf Änderungen, die Zufriedenheit der Kunden und auch der größere Spaß bei der gemeinsamen (!) Arbeit um nur ein paar zu nennen gehen meines Erachtens bei der Anwendung von SAFe verloren oder können zumindest nicht die volle Wirkung entfalten.

Anregungen, Erfahrungen, Hinweise? Kommentare willkommen.

Dies war Teil zwei der Serie „Skalieren von agilen Vorgehen“ mit dem Scaled Agile Framework von Dean Leffingwell. Im dritten Teil sehen wir uns die Ideen von Craig Larman und Bas Vodde an.

The post Agile Skaliert – Teil 2 appeared first on codecentric Blog.

Scrum for Developers – ein ASF BootCamp mit Masterstudenten der FH Aachen

$
0
0

Nach erfolgreichem Auftakt dieses Formates in 2013 ging das ASF BootCamp nun vom 04. bis 12. März 2014  in die zweite Runde. Teilnehmer waren 17 Masterstudenten der Fachhochschule Aachen (Campus Jülich). Die Teilnehmer sind Studenten des Masterstudiengangs “Technomathematik” und haben vorab ein Duales Studium (Math.Techn. SW-Entwickler plus Bachelor of Science) an der FH Aachen absolviert.

ASF steht für Agile Software Factory und  repräsentiert als Label einen agilen Software-Entwicklungsprozess unter Einsatz führender Tools und Technologien und Verwendung von Best-Practice-Ansätzen. Zusammen mit Prof. Dr. Bodo Kraft und Marc Schreiber von der Hochschule haben wir das Format zum Vorjahr hin leicht modifiziert und zeitlich gestrafft, das Ziel ist gleich geblieben, nämlich Studenten die Möglichkeit zu geben, agile Methoden und Praktiken in Kombination mit modernen Entwicklungswerkzeugen in einen Workshop-Format kennen zu lernen.

In einem vorgelagerten viertägigen Theorieblock wurden Grundlagen vermittelt , um den Einstieg in die praktische Phase schneller bewerkstelligen zu können. Thematisch behandelt wurden: Scrum Basics (mittels Lego4Scrum), Versionsverwaltung (Git), Buildmanagement (Maven) , emergente Architekturen, SOLID-Prinzipien, Continuous Integration/Deployment und Grundlagen zu Spring DI/MVC.

Mit Hilfe dieses umfangreicheren Vorbaus waren die Studenten in diesem Jahr dann auch wesentlich schneller im Thema und in der Lage, in der anschließenden dreitägigen Praxisphase fünf Sprints komplett zu durchlaufen. Begleitet wurde das Format von Seiten codecentric durch Michael Lex, Ben Ripkens und Michael Treiling. Michael Lex und Ben Ripkens als Trainer und Betreuer, die u.a. in den Rollen Scrum Master bzw. Product Owner die vier Teams (Duplo, Oecher, Jatse, O) durch die Sprints begleitet haben. Zusätzlich wurde jeder Tag durch eine kleine Theorieeinheit ergänzt, um weitergehende Konzepte ( Release Management, Testdriven Development, Akzeptanztestgetriebene Entwicklung, Softwarequalität) zu vermitteln, die in den folgenden Sprints dann sofort praktisch umgesetzt werden mussten.

Den Abschluss der Veranstaltung bildete eine Retrospektive aller Teams über die Gesamtveranstaltung. Hier gingen die Studenten sehr selbstkritisch mit sich ins Gericht, visualisierten ihre Ergebnisse, reflektierten die Teamprozesse und benannten Verbesserungspunkte.

Es hat allen Teilnehmern viel Spaß gemacht, alle Teams haben über die Sprints hinweg ihre Velocity steigern können und durch die gute Vorbereitung waren die Teams schnell arbeitsfähig. Hervorzuheben ist noch die hohe Motivation, mit der die Aufgaben angegangen wurden. Alles in allem eine gelungene Veranstaltung, die auch in 2015 fortgesetzt werden wird…

05 10 15 20 25 30 32 33 35 40 45 50 52 55 60 62 65758090929570     85  93 94  97 100 105 110 115 120

The post Scrum for Developers – ein ASF BootCamp mit Masterstudenten der FH Aachen appeared first on codecentric Blog.

Anforderungen in agiler Softwareentwicklung – ein kurzer Überblick

$
0
0

Aktuell existieren verschiedene Techniken und Methoden für agiler Anforderungssammlung und Anforderungsmanagement.

Zu ihnen gehören Anwendungsfälle oder Use Cases, Anwendererzählungen oder User Stories, Innovation Games, Color Modeling, User Story Mapping und als eine der neuesten Techniken Impact Mapping.
Alle diese Techniken adressieren unterschiedliche Probleme, haben unterschiedliche Ziele und werden deswegen folgerichtig auch unterschiedlich verwendet.


Use Cases gehören heutzutage zu den klassischen Techniken für die Sammlung und das Management von Anforderungen. Diese können sowohl im klassischen, wasserfallorientierten als auch im agilen Umfeld verwendet werden – Alistair Cockburn, einer der Unterzeichner des Agilen Manifests, ist auch weltberühmter weltweit anerkannter Experte für Use Cases.

User Stories beantworten die Frage: „Wie können wir die Anforderungen so teilen, dass wir diese unabhängig voneinander priorisieren, planen und liefern kann?“
User Stories werden oft als bestehend aus Karte, Konversation und Konfirmation beschrieben (im Englischen abgekürzt als 3C. Sie dienen als Platzhalter für sowohl Planung als auch Diskussionen (Konversationen), die im Rahmen der Klärung und Implementierung des Inhaltes der Karte durchgeführt werden. Der Unterschied zwischen Anwendungsfällen und User Stories wird von Alistair Cockburn treffend beschrieben: “Eine User Story ist der Titel eines Szenarios und ein Anwendungsfall ist der Inhalt mehrerer Szenarien“.

Innovation Games wurden für die Erstellung und Weiterentwicklung von Ideen für die Entwicklung neuer Produkte erschafft. Sie basieren auf der Feststellung, dass es für einen Mensch leichter ist, sich während eines Spiels zu äußern als in der im Vergleich ernsteren Atmosphäre eines Geschäfts-Meetings. Die beste Zeit für ein Innovation Game ist hierbei der Anfang der neuen Produkteentwicklung.

Color Modeling ist eine leichtgewichtige Technik aus dem Feature Driven Development (kurz FDD). Das Ziel ist die schnelle Erstellung eines Domänenmodell fokussiert auf signifikanten Ereignissen, Menschen und Organisationen (Parteien), die an diesen Ereignissen teilnehmen, sowie den zugehörigen Rollen. Diese Technik wird interessanterweise für Projekte unterschiedlichster Größe verwendet, von 20 Personentagen bis zu 1.000 Personenmonaten.

User Story Maps sind aus den Schwierigkeiten entstanden, eine sinnvolle Organisation der in vielen Fällen großen Menge von User Stories zu finden. User Story Maps beantworten die Frage: „Was ist der minimal verwendbare Umfang, den wir realisieren müssen, um einen Wert für den Kunden zu liefern?“ Eine User Story Map arrangiert User Stories zu einem Modell, das sehr hilfreich ist, um die Funktionalität des Systems zu verstehen, Lücken in einem Backlog zu erkennen und eine effiziente Releaseplanung durchzuführen, damit die Benutzer mit jedem Release einen Mehrwert erhalten. User Story Mapping ermöglicht einen Plan für ein vollständiges Produkt zu erstellen, der sich in sinnvolle Releases teilen lässt

Impact Mapping wurde von Gojko Adzic entwickelt und hat seine Wurzeln im Bereich der User Experience (kurz UX). Impact Mapping basiert auf der dort entwickelten „Effect Mapping“ Methode. Die Idee des Impact Mappings ist es, die Anforderungen auf einem visuellen Weg zu beschreiben. Dieser Weg verbindet Ziele, Aktoren und Auswirkungen, die erreicht werden sollen. Damit stellt Impact Mapping ein gutes Werkzeug dar, um die Verbindungen zwischen Geschäftszielen und neu zu entwickelnder Funktionalität zu erreichen. Deshalb ist Impact Mapping sehr gut für die Planung von Releases geeignet.

Haben sie schon Erfahrung mit Methoden für agilen Anforderungsermittlung und Management? Möchten sie die Erfahrungen austauschen oder mehr über Impact Mapping lernen? Dann freuen wir uns auf ihre Teilnahme beim Agilen Stammtisch Frankfurt. Das Thema des Lightning Talks des nächsten Stammtisches wird „Impact Mapping“ sein.

10. Agiler Stammtisch Frankfurt findet an 3. April um 19:00 an „die Zentrale“ statt. Kostenlose Registrierung über XING.

The post Anforderungen in agiler Softwareentwicklung – ein kurzer Überblick appeared first on codecentric Blog.


Neue Arbeitsplatzkonzepte für agile Unternehmen

$
0
0

Dies ist kein Plädoyer für den Großraum und es ist auch keines dagegen. Es ist der Versuch, die Anforderungen moderner Arbeitsplatzgestaltung mit den Vorstellungen derer in Einklang zu bringen, die in ihnen arbeiten.

Kaum ein Thema kann so kontrovers diskutiert werden wie die verschiedenen Arbeitsplatzkonzepte, da jede Generation von Arbeitnehmern unterschiedliche Ansprüche an Arbeitsplatz und Arbeitsort stellt. Auch wenn aktuell noch gut 40% der Erwerbstätigen in Deutschland einen traditionellen Büroarbeitsplatz nutzen und sich mit dieser Form von “Territorialität” mit “ihrem Arbeitsplatz” identifizieren, stellt heute insbesondere die Generation Y ganz andere Ansprüche an die Arbeitsplatzgestaltung. Die Grenzen verschwimmen. Um Kreativität, Spontanität, Kollaboration und Wissenstransfer wirkungsvoll zu unterstützen, werden zukünftig immer stärker mobile und flexible Arbeitsmöglichkeiten geschaffen werden müssen. Dies wird zur Reduktion fester Arbeitsplätze in Deutschland führen (7,9 feste Arbeitsplätze auf 10 Mitarbeiter bis 2020 (Workplace of the Future Report, Citrix 2014)). Als Folge davon lassen sich in hohem Umfang Arbeitsplatzkosten einsparen und Wettbewerbsfähigkeit und Arbeitgeberattraktivität steigern.

Räume transportieren das Selbstverständnis ihrer Nutzer und fördern Identifikation und Bindung. Die Arbeitsumgebung beeinflusst ganz wesentlich Motivation, Wohlbefinden und Leistungsbereitschaft von Mitarbeitern:

  • Forschung und Unternehmenspraxis bestätigen dabei den hohen Zusammenhang zwischen der Innovationskraft eines Unternehmens und dem Maß persönlicher Interaktion, räumlicher Nähe und persönlicher Zusammenarbeit (“Stepstone Report”, Fraunhofer Institut für Arbeitswirtschaft und Organisation, 2014).
  • Diese Innovationskraft ist umso größer, je mehr die Arbeitsplatzgestaltung der Kultur, dem Tätigkeitsschwerpunkt des Unternehmens und dem Selbstverständnis der Mitarbeiter entspricht. Das gilt meiner Meinung nach insbesondere für agil aufgestellte Unternehmen mit einem hohen Kommunikations- und Feedbackaufkommen.
  • Die informations- und kommunikationstechnische Infrastruktur (schnell, sicher, stabil und zuverlässig) ist dabei DAS zentrale Instrument für zeit- und ortsunabhängiges Arbeiten.
  • Ein transparentes und offenes Raumkonzept auf Makro- (Gebäude) und Mikroebene (Raumzonen) fördert die gegenseitige Wahrnehmung und Kommunikation im Sinne kreativen Austauschs, vernetzten Arbeitens und hoher Informationsbreite.

Unsere Arbeitswelt ist einem permanenten Wandel unterworfen. Auch die Gestaltung unserer Arbeitsorte ist davon betroffen. Das das mitunter zum Spagat mit den Vorstellungen traditioneller Bürokonzepte wird, liegt auf der Hand. Die Lösung liegt in einem ausgewogenen Mix verschiedener Raumkonzepte:

  • Workspace mit Zonenkonzept (kleine räumliche Einheiten in Kombination mit Gemeinschafts-, Team-, Projekt- und Einzeleinheiten, s. Abbildung)
  • Diese Zonen unterstützen verschiedene Arbeitsstile (konzentriertes Arbeiten, kommunikativer/kreativer Austausch, Besprechung, Teamarbeit (Co-Working), Wissenstransfer, (soziale) Vernetzung, etc.)
  • Barrierefreiheit
  • Zonenspezifische Klimatisierung, Farbgebung, Beleuchtung und Schallschutz
  • Nutzung der Zonen in Selbstorganisation
  • Weitgehende Autonomie der Mitarbeiter bei der Wahl von Arbeitsplatz und Arbeitsform

Im Bereich der Arbeitsplatzkonzepte erleben wir zurzeit einen Wandel weg von der reinen “Präsenzkultur” hin zur “Ergebnis- und Vertrauenskultur”. Ein mehrgestaltiges Raumkonzept auf Makro- und Mikroebene unterstützt ganz wesentlich diesen Transformationsprozess und spiegelt das Image und Selbstverständnis einer Unternehmung.

Blogartikel _Arbeitsplatzkonzepte_Bild

The post Neue Arbeitsplatzkonzepte für agile Unternehmen appeared first on codecentric Blog.

Maven Project Properties in Jenkins Jobs verwenden

$
0
0

Manchmal ist es hilfreich, wenn man in einem Jenkins Job Zugriff auf Maven Projekt Properties wie project.artifactId oder project.version hat. Beispielsweise lässt sich so die nächst höhere Versionsnummer in einem Release Job ermitteln und setzen. Ein anderer Use Case, den ich vor kurzem in einem Projekt hatte, ist das Kopieren von Build Ergebnissen auf ein Netzlaufwerk mittels eines Shell Skripts. Damit dies funktioniert, muss dem Shell Skript der Name des zu kopierenden Artefakts übergeben werden. Aber wie soll das funktionieren, wenn sich der Artefaktname ständig ändert, weil die Version in der pom hochgezählt wird? Glücklicherweise gibt es in Jenkins eine einfache Möglichkeit auf diese Informationen zuzugreifen.

Gemappete maven Properties in Jenkins

Jenkins stellt allgemeine maven Projekt Properties als Umgebungsvariablen zur Verfügung. Natürlich funktioniert dies nur bei maven Build Jobs aber nicht bei Freestyle Jobs, welche nur maven Goals aufrufen. Dieses Feature wurde vor einer Weile implementiert, aber überraschender Weise ist es bisher noch nicht sonderlich gut dokumentiert. Die folgende Tabelle listet alle maven Projekt properties auf, welche auf Jenkins Umgebungsvariablen gemappt werden:

maven Projekt Property Jenkins Umgebungsvariable
project.displayName POM_DISPLAYNAME
project.version POM_VERSION
project.groupId POM_GROUPID
project.artifactId POM_ARTIFACTID
project.packaging POM_PACKAGING
project.relativePath POM_RELATIVEPATH

Beispiel

In meinem Projekt verwende ich ein gemanagetes Skript um die Ergebnisse eines maven Webstart Builds auf ein Windows Netzlaufwerk zu extrahieren. Das Build Ergebnis liegt als Zip Archiv vor. Da ich vom trunk deploye und sich die Versionsnummer dort häufig ändert (nach jedem Produktionsdeployment), muss ich den Namen des Archivs herausfinden und an das Skript übergeben. Mein Deployskript sieht in etwa so aus:

DEPLOY_PATH=/mnt/webstart_deploy
rm -rf $DEPLOY_PATH/*
unzip target/$1 -d $DEPLOY_PATH

Das einzige, was ich jetzt noch machen muss, ist den Namen des Archivs als Parameter an das Skript übergeben: $POM_ARTIFACTID-$POM_VERSION.zip.

Sofern sie dies in ihrem Projekt ausprobieren: Ich hatte Schwierigkeiten die Windows Freigabe, auf die ich deployen will, richtig zu mounten. Man sollte deshalb sicher stellen, dass der User, welcher Jenkins ausführt, Schreibrechte in dem gemounteten Pfad hat. Wenn Jenkins als Service ausgeführt wird, ist der user “jenkins”. Die einzige Möglichkeit, um die Berechtigungen in meiner Umgebung richtig hinzubekommen, war beim Mounten die UID vom Jenkins User zu übergeben und diesen somit zum Besitzer des gemounteten Ordners zu machen. Außerdem benötigt man einen User in der Windows Domäne, welcher Zugriff auf die Freigabe hat:

su root
JENKINS_UID = id -u jenkins
mount -t cifs -o user=<domain-user>,password=<domain-users-pw>,uid=$JENKINS_UID //remote_host/remote_dir /mnt/mount_point

Eine Alternative zur hier gezeigten Lösung ist die Verwendung des maven-antrun-plugins. Ich persönlich mag aber die Ant Syntax zur Beschreibung dieser Schritte nicht.

The post Maven Project Properties in Jenkins Jobs verwenden appeared first on codecentric Blog.

Vier Wege in den Docker Container

$
0
0

In vorherigen Artikeln [1,2,3] hat Lukas Pustina die System-Level Virtualisierung mit Docker vorgestellt. Im vorliegenden Post diskutiere ich vier verschiedene Möglichkeiten, um sich mit einem laufenden Docker Container zu verbinden und mit diesem zu interagieren. Alle Codebeispiele sind zum Ausprobieren auf GitHub verfügbar.

nsenter

Das Tool nsenter wird mit dem Paket util-linux ab Version 2.23 ausgeliefert. Es bietet die Möglichkeit, sich in den Namespace eines anderen Prozesses einzuklinken. Dafür sind root Rechte notwendig. Leider wird mit der aktuellen Ubuntu Version 14.04 das Paket util-linux noch in der etwas älteren Version 2.20 ausgeliefert. Um die neueste Version (2.24) zu installieren, sind folgende Schritte nötig:

cd /tmp
curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-
cd util-linux-2.24
./configure --without-ncurses
make nsenter
cp nsenter /usr/local/bin

Um sich nun mit einem Container zu verbinden, wird die PID des ersten Prozesses im Container benötigt. Diese lässt sich wie folgt herausfinden:

docker inspect --format "{{ .State.Pid }}"

Mit Hilfe dieser PID kann man sich nun mit dem Container verbinden:

nsenter --target $PID --mount --uts --ipc --net --pid

nsinit

Seit Version 0.9 bietet Docker eine eigene Bibliothek zur Verwaltung von Containern namens libcontainer. nsinit ist Bestandteil des libcontainers und erlaubt den direkten Zugriff auf die Linux Namespace und cgroup Kernel Features. Um es installieren zu können, muss zunächst in einem ersten Schritt die Go Laufzeitumgebung installiert werden:

apt-get install git golang-go
 
mkdir -p $HOME/go-dev/bin
mkdir -p $HOME/go-dev/src
 
echo "export GOPATH=\$HOME/go-dev" >> ~/.profile
echo "PATH=\$PATH:\$GOPATH/bin" >> ~/.profile
source ~/.profile

Im zweiten Schritt wird nsinit installiert:

mkdir -p $GOPATH/src/github.com/dotcloud
cd $GOPATH/src/github.com/dotcloud
 
git clone https://github.com/dotcloud/docker.git
cd $GOPATH/src/github.com/dotcloud/docker
 
/usr/bin/go get -v github.com/dotcloud/docker/vendor/src/github.com/docker/libcontainer/nsinit

nsinit liest die Konfigurationsdaten direkt aus dem Verzeichnis des Containers aus. Dieses befindet sich in /var/lib/docker/execdriver/native/<container-id>. Um nsinit nutzen zu können, wird zunächst in das passende Container Verzeichnis gewechselt. Hierfür werden wieder root Rechte benötigt, da das Verzeichnis /var/lib/docker nur für root lesbar ist. Die Container ID lässt sich mit Hilfe von docker ps ermitteln. Im oben genannten Verzeichnis stehend, kann dann eine Verbindung mit dem Container hergestellt werden:

nsinit exec /bin/bash

lxc(-attach)

Bis einschließlich Version 0.8.1 war LXC die Grundlage für Docker zur Verwaltung von Containern, die auch weiterhin unterstützt wird. Seit Version 0.9.0 verwendet Docker jedoch standardmäßig die eigene Bibliothek libcontainer, wodurch keine Abhängigkeit mehr zu LXC besteht. Deshalb kann auch nicht mehr lxc-attach standardmäßig verwendet werden.

Soll lxc-attach dennoch benutzt werden, muss der Docker Prozess mit der Option -e lxc neu gestartet werden. Mit dieser Option wird LXC als Container Bibliothek aktiviert – vorausgesetzt LXC ist auf dem System installiert. Der einfachste Weg besteht darin, die Datei /etc/default/docker zu erzeugen, falls sie noch nicht existiert und folgende Zeile hinzuzufügen:

DOCKER_OPTS=”-e lxc”

Anschließend muss der Docker Daemon neu gestartet werden. Um sich mit einem Container zu verbinden, muss zunächst die vollständige Container ID ermittelt werden:

docker ps --no-trunc

Nun kann man sich mit dem Container verbinden. Auch hierfür werden wieder root Rechte benötigt:

lxc-attach -n  -- /bin/bash

sshd

Die drei bisherigen Verfahren benötigen root Rechte auf dem Hostsystem. Ist dies keine Option und soll ggf. das Verbinden zu einem Container über das Netzwerk möglich sein, steht SSH als alternativer Weg zur Verfügung.

Zunächst muss der Container dafür vorbereitet werden. Dies erfordert ein eigenes Base Image, in dem ein SSH Daemon gestartet werden kann. Jedoch tritt an dieser Stelle das Problem auf, dass mit dem Docker Kommando CMD bzw. ENTRYPOINT nur ein Startbefehl angegeben werden kann. Wäre dies der sshd Prozess, gäbe es keine Möglichkeit mehr, einen weiteren Prozess des Containers zu starten. Mögliche Lösungen dafür sind ein eigenes Skript, welches dann weitere  Prozesse startet oder ein Prozessmanagement Tool wie supervisord. Für die Benutzung von supervisord existiert eine ausführliche Dokumentation auf der Docker Homepage. Sobald ein Container mit dem sshd Prozess gestartet wurde, lässt er sich wie gewohnt  mit einem ssh Client erreichen.

Fazit

Der sshd Ansatz ist wahrscheinlich am einfachsten umzusetzen und die meisten Benutzer sind gewohnt, sich per ssh mit einer virtuellen Maschine zu verbinden. Des Weiteren erfordert dieser Weg keine root Berechtigung um sich mit dem Container zu verbinden. Allerdings gibt es zurzeit sehr viele Meinungen [1,2] darüber, ob ein Container mehr als einen Prozess verwalten sollte oder nicht. Im Endeffekt erhält man pro Container einen weiteren sshd Prozess, was im Grunde nicht der Idee der Prozessvirtualisierung entspricht.

Bei den anderen 3 Möglichkeiten werden root Rechte benötigt, um sie nutzen zu können. Docker hatte bis Version 0.8.1 LXC verwendet um Container zu verwalten. Aus diesem Grund war es ziemlich einfach lxc-attach für Docker Container zu verwenden. Ab Version 0.9.0 muss der Docker Daemon mit der Option -e lxc gestartet werden, damit LXC weiterhin verwendet wird. Wenn Docker jedoch wieder LXC verwendet gilt zu beachten, dass es erneut von einer externen Komponente abhängig ist, um einwandfrei zu funktionieren.

Die Tools nsenter und nsinit sind grundsätzlich gleichwertig. Der wesentliche Unterschied zwischen den beiden Tools liegt darin, dass nsinit einen neuen Prozess im Container erzeugt und nsenter sich nur in den Namespace einklingt. Jerome Petazzoni hat dies sehr gut im Docker Blog beschrieben.

The post Vier Wege in den Docker Container appeared first on codecentric Blog.

Agiles Testen von JIRA Plugins

$
0
0

Für die JIRA Plugin-Entwickung existiert eine beeindruckende Infrastruktur, und normalerweise finden Entwickler die Antworten auf die meisten ihrer Fragen. Das Ganze sieht etwas anders aus, wenn es um das agile, d.h. automatisierte und durch Entwickler getriebene, Testen geht. Mit dieser Artikelserie möchten wir – das sind Raimar Falke und ich – Entwicklern, die die ersten Erfahrungen mit der Plugin-Entwicklung für JIRA sammeln, mit den Möglichkeiten des agilen Testens von Plugins vertraut machen, ihnen helfen, die richtigen Testarten auszuwählen und die notwendigen Schritte bis zum laufenden Test zu verstehen. In diesem ersten Artikel möchten wir zunächst eine Einführung in die Thematik geben, die verschiedenen Testarten im Kontext von JIRA im Allgemeinen vorstellen und abschließend Unittests als erste Art genauer unter die Lupe nehmen.

JIRA und Plugins

JIRA ist ein Projektverfolgungstool der Firma Atlassian, welches sich durch umfangreiche Funktionen und höchste Anpassbarkeit auszeichnet. Es wird weltweit von einer großen Zahl an Unternehmen, Organisationen und Projektteams eingesetzt. Plugins, manchmal auch als Add-Ons bezeichnet, sind eine Möglichkeit, JIRA noch stärker anzupassen oder zu erweitern. Auch wenn Atlassian bereits eine Vielzahl an Plugins auf dem Marktplatz bereitstellt, kann es Situationen geben, in denen eine maßgeschneiderte Eigenentwicklung die einzige Lösung ist. Glücklicherweise stellt Atlassian ein SDK zur Entwicklung eigener Erweiterungen für ihre Produkte, sowie ein breites Spektrum an Dokumentation und eine Community-getriebene Fragen-und-Antworten-Seite bereit. Ein zentraler Bestandteil jedes Softwareprojekts – und die Erstellung eines JIRA Plugins ist ein Projekt – ist der Test der Software. Doch obwohl Atlassian Dokumentation und Beispiele für die meisten Testszenarien bereitstellt, ist nicht immer klar, welche Technologie oder Methode genutzt werden kann und sollte (oder auch nicht) vor allem, da sich die Tests und Testerstellung so nahtlos wie möglich in die üblichen Entwicklungsprozesse integrieren sollten.

Relevante und verwandte Technologien und Begrifflichkeiten

Atlassian Produkte im Allgemeinen und JIRA im Speziellen setzen eine Reihe von Technologien ein, die nicht unbedingt allgemein bekannt sind. Daher werden wir im Folgenden kurz auf diejenigen eingehen, die wir im Kontext dieser Artikel für relevant halten.

Maven

Maven ist das Buildmanagementwerkzeug für alle Atlassian Produkte und deren Erweiterungen. Es ist in der Lage, extrem modulare Projekte inklusive ihrer internen und externen Abhängigkeiten, den Buildprozess und die Erstellung von Reports zu verwalten und kann auf einfachste Weise in Continuous Integration (CI) Systeme integriert werden. Atlassian stellt Wrapper für eine Vielzahl an Maven Kommandos bereit, um übliche Entwicklungsschritte zu vereinfachen (siehe Atlassian Maven Befehle).

OSGi

OSGi ist sowohl ein Konsortium als auch eine Spezifikation für modulare Java Softwaresysteme. Atlassian, wie auch z.B. Eclipse, benutzt einen OSGi Container als Grundlage für alle ihre Produkte, und alle Plugins sind im Prinzip OSGi Bundles. Daraus ergeben sich gewisse Einschränkungen und Best Practises, die man während der Entwicklung – und fast noch wichtiger: beim Testen – berücksichtigen muss. Wenn wir im Folgenden von einem Container sprechen, beziehen wir uns i.d.R. auf den OSGi Container.

Host Application

Die Anwendung, z.B. JIRA oder Confluence , in der das zu entwickelnde Plugin eingesetzt wird.

Active Objects

Active Objects ist eine ORM Schicht für Atlassian Produkte. Da es das empfohlene Verfahren für das Speichern und den Zugriff auf Daten ist, spielt es beim Test auch eine Rolle.

FastDev

Der Test (automatisiert oder auch manuell) eines Plugins, welches in einem Container läuft, z.B. für Oberflächentests, ist mühselig, wenn Container und JIRA immer wieder neu gestartet werden müssen, und anschließend das Plugin in der aktuellen Version installiert wird. Da allein der Start von JIRA ca. 3 Minuten dauert, kann sich die Wartezeit schnell zu einem beträchtlichen Teil des Tages aufsummieren, auch wenn jedes Mal nur kleine Anpassungen am Plugin vorgenommen wurden. FastDev (was selbst ein Plugin ist) stellt eine Möglichkeit zur Verfügung, sowohl Änderungen am Quellcode des Plugins aus dem laufenden JIRA heraus zu erkennen als auch das Plugin anschließend neu zu bauen und zu laden, ohne die Host Application neu starten müssen, was den Entwicklungszyklus erheblich beschleunigt.

Atlassian Maven Befehle

Die folgende Tabelle stellt einen Teil der Atlassian Befehle für typische Entwicklungsaufgaben sowie ihre entsprechenden Maven Befehle vor.

Befehl Maven Entsprechung Beschreibung
atlas-clean mvn clean Räumt das Projekt auf (d.h. löscht den target-Ordner).
atlas-unit-test mvn test Baut das Projekt und führt die Unittests aus.
atlas-integration-test mvn integration-test Baut das Projekt, führt die Unittests aus, startet eine JIRA Instanz, installiert das Plugin und führt Integrationstests in der/gegen die Instanz aus.
atlas-run mvn jira:run Baut das Projekt, führt die Unittests aus, startet eine JIRA Instanz und installiert das Plugin. Sinnvoll, um eine laufende Instanz während der Entwicklung wiederzuverwenden, um bspw. Start- und Stopzeiten zu sparen. Um nicht die aktuellste, sondern eine spezifische Version zu starten, kann man die Version als Parameter übergeben.
atlas-debug mvn jira:debug Baut das Projekt, führt die Unittests aus, startet eine JIRA Instanz und installiert das Plugin. Zusätzlich zum run-Befehl wird hier noch ein Port zum Remote-Debugging geöffnet.
atlas-install-plugin mvn jira:install Installiert das Plugin in eine laufende JIRA Instanz. Das Plugin muss vorher gebaut worden sein.
atlas-remote-test mvn jira:remote-test Baut das Projekt, führt die Unittests aus, installiert das Plugin in eine laufende JIRA Instanz und führt Integrationstests in der/gegen die Instanz aus.
atlas-update mvn amps:update Aktualisiert das SDK.

Einrichten der Infrastruktur

Atlassian Produkte sind im Prinzip Java (Web-)Anwendungen, die mittels Maven gebaut werden. Bei der Installation des SDK wird eine eigene Maven Distribution, eine settings.xml, ein lokales Maven Repository und eine Reihe von Shell-Skripten (die oben erwähnten Atlassian Befehle) eingerichtet. Ein JDK hingegen wird als installiert vorausgesetzt. Unsere Versuche haben ergeben, dass JIRA bis zur Version 6.2.6 nicht startet, wenn man ein JDK 8 verwendet. Wir empfehlen daher, ein JDK 7 zu verwenden, da es ein Problem mit Type Inference behebt, welches mit JDK 6 besteht und das zumindest den Umgang mit Hamcrest erschwert. Auch wenn ein JDK 7 eingesetzt wird, müssen Source- und Bytecode auf Version 1.6 gesetzt werden. Es wird zwar nirgendwo explizit erklärt, man findet es aber in den meisten Beispielen von Atlassian. Während der Arbeit an unserem Projekt wurde die aktuelle Version des SDK (zu dem Zeitpunkt: 4.2.20) noch mit Maven 2.1.0 ausgeliefert, was leider zu Problemen mit einigen Maven Plugins, die wir aber als ziemlich wichtig erachten, führt. So benötigt z.B. FindBugs Maven in einer Version von mindestens 2.2.1 und auch Sonar benötigt mindestens Maven 2.2. Zum Glück gibt es aber mindestens zwei Wege, wie man das SDK dazu bringen kann, mit einer neueren Maven Version zu arbeiten.

  • Setzen der Umgebungsvariable ATLAS_MVN (eine Beschreibung findet sich hier)
  • Der Wert der Variablen muss auf die ausführbare Datei der Maven Installation (unter Windows mvn.bat) zeigen. Alle atlas-* Befehle nutzen dann diese Variable anstelle der Mitgebrachten, um die eigentlichen Kommandos auszuführen, sodass effektiv die alternative Maven Installation genutzt wird. Der Nachteil dieses Vorgehens ist, dass man immer noch die atlas-* Befehle nutzen muss, was von einigen Tools nicht unterstützt wird.
  • Kopieren der settings.xml, die mit dem SDK kam, in die gewünschte Maven Installation oder die Benutzereinstellungen
  • Dieses Vorgehen löst eine Reihe von Problemen, inklusive einigen Buildproblemen mit FastDev. Der größte Vorteil ist die Möglichkeit, ab sofort “Standard” Maven Kommandos zu benutzen, also bspw. “mvn clean” statt “atlas-clean”, was die Integration mit anderen Tools oft vereinfacht. So ist bspw. die Integration in die meisten IDEs so ein Kinderspiel. Es muss jedoch beachtet werden, dass bei der Übernahme der settings.xml eine ggfs. bestehende Konfiguration nicht einfach gelöscht wird, und alle Änderungen, die das SDK erfordert, müssen von Hand nachgetragen werden. Ein weiterer Nachteil ist, dass diese globale Anpassung auch andere Projekte beeinflussen kann, auch wenn es sich nicht um JIRA Plugins handelt. Eine mögliche Alternative ist die Bereitstellung verschiedener Maven Installationen (für die gleiche Maven Version), wobei in einer die Änderungen für Atlassian integriert werden und in der anderen nicht. Auf diese Weise kann man durch Setzen des Pfades (PATH Umgebungsvariable) zwischen den Installationen wechseln.

Es gibt jedoch Einschränkungen, welche alternativen Maven Versionen eingesetzt werden können. Unsere Versuche haben ergeben, dass sowohl Versionen 3.1.* als auch 3.2.* nicht einsetzbar sind, da es eine inkompatible Änderung in der API des Felix Plugins gab, welches vom Atlassian SDK benötigt wird. Eine typische Fehlermeldung für einen derartigen Fall war beispielsweise:

[ERROR] Failed to execute goal com.atlassian.maven.plugins:maven-jira-plugin:4.2.20:copy-bundled-dependencies (default-copy-bundled-dependencies) on project test: Execution default-copy-bundled-dependencies of goal com.atlassian.maven.plugins:maven-jira-plugin:4.2.20:copy-bundled-dependencies failed: An API incompatibility was encountered while executing com.atlassian.maven.plugins:maven-jira-plugin:4.2.20:copy-bundled-dependencies: java.lang.NoSuchMethodError: org.apache.maven.execution.MavenSession.getRepositorySession()Lorg/sonatype/aether/RepositorySystemSession;
[ERROR] -----------------------------------------------------
[ERROR] realm = plugin&gt;com.atlassian.maven.plugins:maven-jira-plugin:4.2.20
[ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
[ERROR] urls[0] = file:/C:/user/.m2/repository/com/atlassian/maven/plugins/maven-jira-plugin/4.2.20/maven-jira-plugin-4.2.20.jar

Maven 3.0.* funktioniert hingegen ohne Probleme, weshalb wir den Einsatz auch empfehlen.

Wie Entwickler testen wollen

Es gibt zwei typische Wege, wie Tests durchgeführt werden: während der Entwicklung und im Rahmen der Continuous Integration. Ersteres hilft dem Entwickler, seine eigenen Anpassungen im (testgetriebenen) Prozess zu testen, während der zweite Weg dazu dient sicherzustellen, dass die Anpassungen keine Auswirkungen auf andere Funktionalitäten hatten. Während kurze Ausführungszeiten generell wichtig sind, werden Tests aus der IDE heraus öfter ausgeführt, sodass die Geschwindigkeit hier noch kritischer ist. Außerdem ist es bei der Ausführung aus der IDE wichtig, genau auswählen zu können, welche Tests – eingeschränkt auf einzelne Klassen oder sogar Methoden – auszuführen sind, um Zeit zu sparen. Für die Ausführung auf einem CI Server ist es hingegen wichtig, dass die Tests stabil laufen (können auf allen Build-Agents laufen, keine Wackeltests, die den Build abbrechen lassen, o.ä.) und dass sie reproduzierbar sind, d.h. der Kontext (Betriebssystem, Leistungsfähigkeit, andere Softwareinfrastruktur) ist vorgegeben und kann bei Bedarf wiederhergestellt werden. Darüber hinaus werden auf einem CI Server die Tests i.d.R. zusammen, alle nacheinander oder parallel, ausgeführt, während in der IDE Tests einzeln bzw. sequentiell gestartet werden.

Bei der Frage, was für Tests eingesetzt werden sollten, gibt die Test Pyramide üblicherweise die Empfehlung für drei Arten von Tests:

  1. Unittests sind dazu da, eine Komponente (das Testsubjekt) isoliert zu testen. Dazu wird die Interaktion mit anderen Komponenten (Abhängigkeiten) durch den Test gesteuert. Am besten eignen sich dazu “Mocks”, die die Schnittstelle und das Verhalten einer Abhängigkeit nachbilden. Es gibt viele Gründe, die für den Einsatz von Mocks sprechen: sie erlauben eine exakte Kontrolle des Verhaltens und ermöglichen es, auch ungewöhnliche Situationen zu simulieren. Außerdem erlauben sie die Entkopplung von externen Ressourcen, wie beispielsweise Netzwerken, Datenbanken oder dem Dateisystem, die teilweise zu langsam für einen häufig ausgeführten Test oder schwierig in einen definierten Zustand zu versetzen sind.
  2. Servicetests sind End-to-End Tests ohne die zusätzliche Komplexität der Benutzerschnittstelle.
  3. Oberflächentests testen zusätzlich noch die Benutzeroberfläche.

JIRA Plugins bestehen häufig aus JavaScript, welches im Browser läuft, und mit dem Java Teil des Plugins auf dem Server mittels REST kommuniziert. Servicetests sind daher größtenteils REST Tests. Oberflächentests testen dann zusätzlich auch das JavaScript und den HTML Code.

Verfügbare Test in JIRA

Die folgende Tabelle stellt die Arten von Tests für JIRA Plugins vor, die wir identifiziert haben. Ein besonderer Aspekt, den wir betrachtet haben, ist die Frage, wo Testcode und Testsubjekt ausgeführt werden. Normalerweise wird der Test in der Original-VM (durch die IDE oder den CI Server gestartet) ausgeführt. Im Rahmen der Tests von JIRA Plugins gibt es jedoch auch auch eine Art von Tests, die direkt in der Host Application durchgeführt werden. Die gleiche Unterscheidung trifft auch bei Oberflächentests mit Selenium zu: der Testcode läuft in der lokalen VM, während das Testsubjekt in einer anderen VM ausgeführt wird.

Testtyp Testcode läuft in Testsubjekt läuft in
Unittest Original VM Original VM
Integrationstest Original VM Original VM
“Traditioneller Integrationtest” (nach Atlassian)
  • Servicetest
  • Oberflächentest
Original VM Host Application
“Wired Tests” (nach Atlassian) Host Application Host Application

Unittest

Bei der Entwicklung von Unittests wird von Atlassian empfohlen, diese in Packages mit dem Präfix ut.* (ut steht für Unittests) abzulegen. Dies ist nicht absolut notwendig, dient aber dazu, sie von Integrationstests (für die es notwendig ist, sie in einem Package mit Präfix it.* für Integrationstests abzulegen) und normalen Hilfsklassen zu unterscheiden. Wie bereits oben erwähnt, dienen Unittests dazu, einen Aspekt des Systems isoliert zu testen. Um diese Isolation zu erreichen, ist es notwendig, entweder extrem lose gekoppelte und unabhängige Komponenten zu entwickeln, oder Mock Frameworks einzusetzen. Da die lose Kopplung hier nicht nicht im Vordergrund steht, demonstrieren wir im Folgenden den Einsatz von Mock Frameworks.

Abhängigkeiten

Um Unittests zu erstellen, müssen mindestens die folgenden Abhängigkeiten eingebunden werden. Unter anderem werden so eine Menge Mockobjekte, die von Atlassian bereitgestellt werden, sowie mockito eingebunden.

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.atlassian.jira</groupId>
    <artifactId>jira-tests</artifactId>
    <version>${jira.version}</version>
    <scope>provided</scope>
</dependency>

Erzeugung von Mocks

Im Rahmen der Unittests können Mocks auf die übliche Weise erzeugt werden (die statischen Imports stammen aus Mockito):

MutableIssue issue = mock(MutableIssue.class);
Project project = mock(Project.class);
when(issue.getProjectObject()).thenReturn(project);
when(issueManager.getIssueObject(1)).thenReturn(issue);

Eine Besonderheit von OSGi ist die Umsetzung von Dependency Injection durch den Komponentenkonstruktur. Der Effekt davon ist, dass die meisten JIRA Komponenten Konstruktoren mit vielen Parametern haben. Um derartige Komponenten zu testen, müssen natürlich alle diese Abhängigkeiten gemockt werden (FooBar ist die zu testende Komponente):

I18nHelper i18nHelper = mock(I18nHelper.class);
PermissionManager permissionManager = mock(PermissionManager.class);
IssueManager issueManager = mock(IssueManager.class);
FooBar foo = new FooBar(i18nHelper, permissionManager, issueManager);

Eine Alternative zu dieser Art von Dependency Injection ist der Einsatz des ComponentAccessor. Doch auch wenn es scheinbar hilft, die Komponente aufzuräumen und unnötige Parameter zu entfernen, hat es einige Nachteile, vor allem was die Testbarkeit betrifft. So ist während eines Unittests das System eigentlich gar nicht komplett gestartet und der ComponentAccessor nicht initialisiert, was zu entsprechenden Fehlermeldungen führt. Eine Lösung hierfür stellt der Einsatz des MockComponentWorker dar, welcher dem ComponentAccessor die benötigten Komponenten liefert (die verwendeten Mocks sind die gleichen wie im vorigen Beispiel):

new MockComponentWorker()
    .addMock(PermissionManager.class, permissionManager)
    .addMock(I18nHelper.class, i18nHelper)
    .addMock(IssueManager.class, issueManager).init();

Trotz dieser Möglichkeit empfehlen wir jedoch, die Dependency Injection über den Konstruktor zu wählen und nicht den ComponentAccessor/MockComponentWorker Ansatz zu verwenden. Ein Vorteil ist, dass man so an einer Stelle alle Abhängigkeiten einer Komponente sieht. Ansonsten muss man den gesamten Code nach Referenzen auf den ComponentAccessor durchsuchen oder durch herumprobieren herausfinden, welche Komponenten benutzt werden.

Test von Active Objects

Um Persistenzmechanismen mit Active Objects zu testen, benötigt man weitere Abhängigkeiten im Projekt. Um die Versionen zwischen dem System und den Testartefakten konsistent zu halten, empfehlen wir den Einsatz einer Maven Property (hier: ao.version), die man dann ebenso bei der Definition der Abhängigkeit auf Active Objects selbst einsetzt:

<dependency>
    <groupId>net.java.dev.activeobjects</groupId>
    <artifactId>activeobjects-test</artifactId>
    <version>${ao.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.atlassian.activeobjects</groupId>
    <artifactId>activeobjects-test</artifactId>
    <version>${ao.version}</version>
    <scope>test</scope>
</dependency>

Die Tests selbst sind dann normale JUnit Tests, denen einige spezifische Annotationen hinzugefügt werden (siehe auch das Beispiel weiter unten):

  1. Active Objects Tests benötigen einen speziellen Testrunner.
  2. Es muss angegeben werden, welche (Art von) Datenbank zum Test verwendet werden soll.
  3. Eine Klasse, die die Datenbank vorbereitet, muss angegeben werden.

Für den letzten Punkt ist es notwendig, eine Implementierung des Interface DatabaseUpdater zu erstellen. Laut Dokumentation wird diese Implementierung einmal pro Klasse aufgerufen (sie kann aber auch für mehrere Klassen genutzt werden, wenn sie öffentlich ist). In ihrer update Methode muss sie dem Entity Manager anweisen, alle für den Test relevanten Entitäten zu migrieren, d.h. die Datenbank für ihre Nutzung vorzubereiten:

public class TestDatabaseUpdater implements DatabaseUpdater {
 
    @Override
    public void update(EntityManager entityManager) throws Exception {
        entityManager.migrate(Foo.class, Bar.class);
    }
}

Active Objects unterstützt (auch im Test) ein breites Spektrum an Datenbankservern, z.B. HSQL (als In-Memory und Dateisystem Variante), MySQL, Postgres und Derby. Standardmäßig wird jeder Test in seiner eigenen Transaktion durchgeführt, die anschließend zurückgerollt wird. Das funktioniert jedoch nur, wenn die zu testende Klasse die Transaktionsverwaltung dem Container überlässt (wie in der zweiten Hälfte dieses Artikels beschrieben). Hat man sich jedoch für die Variante entschieden, die in der ersten Hälfte des Artikels beschrieben ist, übernimmt also die Komponente die Transaktionsverwaltung, muss jeder Test mit @NonTransactional annotiert werden. Das folgende Beispiel ist ein solcher Test (der den oben gezeigten DatabaseUpdater verwendet):

@RunWith(ActiveObjectsJUnitRunner.class)
@Data(TestDatabaseUpdater.class)
@Jdbc(Hsql.class)
public class FooRepositoryTest {
 
    // gets injected by the ActiveObjectsJUnitRunner
    private EntityManager entityManager;
 
    // AO repository under test
    private FooRepository fooRepository;
 
    @Before
    public void setup() {
        this.fooRepository = new FooRepositoryImpl(new TestActiveObjects(entityManager));
    }
 
    @Test
    @NonTransactional
    public void test_that_saved_value_can_be_retrieved() {
        Foo foo = new Foo("test");
        this.fooRepository.save(foo);
        List<Foo> foos = this.fooRepository.findAll();
        assertThat(foos, hasItem(
            Matchers.<Foo> hasProperty("name", is("test"))));
    }
}

Ausführen von Unittests

Der von Atlassian vorgesehene Weg, um Unittests auszuführen ist das Kommando “atlas-unit-test”. Hat man aber die Umgebung wie oben beschrieben eingerichtet, können Unittests auch mit dem Kommando “mvn test” oder aus der IDE heraus mit dem Unittest-Starter ausgeführt werden.

Zusammengefasst

Es gibt einige Stolpersteine auf dem Weg zum erfolgreichen Test eines JIRA Plugins. Die ersten sollte man mit Hilfe dieses Artikels bewältigen können. Hat man die Umgebung erst einmal passend eingerichtet, ist die Implementierung und die Ausführung von Unittests vergleichsweise einfach. Im nächsten Artikel werden wir uns “Wired Tests” – was sie sind und wie sie dem Entwickler helfen können – genauer anschauen.

Andere Teile dieser Serie

Part 2 of Agile testing of JIRA plugins: Wired Tests (bislang nur Englisch)

Part 3 of Agile testing of JIRA plugins: System tests (bislang nur Englisch)

The post Agiles Testen von JIRA Plugins appeared first on codecentric Blog.

Agile Entwicklungspraktiken: der Ursprung

$
0
0

Agile Entwicklungspraktiken gehören zu den wichtigsten Grundlagen für erfolgreiche Umsetzung der Agilen Softwareentwicklung.

Scrum ist aktuell die populärste agile Projektmanagementmethode.

Allerdings gibt es keine spezifischen Empfehlungen über Entwicklungspraktiken in Scrum, da sich Scrum ausschließlich auf Projektmanagement beschränkt. Es wird nur empfohlen, gute Entwicklungspraktiken einzuführen.

Der Ursprung der Agile Entwicklungspraktiken

Es gibt zwei agile Methoden, die im Unterschied zu Scrum gut definierten Entwicklungspraktiken haben. Diese Methoden sind Extreme Programming und Feature Driven Development oder FDD (eigenschaftenbasierte Entwicklung). Diese Methoden haben einen unterschiedlichen Hintergrund und fokussieren deshalb auf unterschiedliche Schwerpunkte.

In diesem Blogpost machen wir folgenden Unterschied zwischen Methoden und Praktiken.

Eine Methode beschreibt gemeinsame Rahmen, wie man die Software-Entwicklung durchführen soll (d.h. typische Rollen, erforderliche Meetings, Artefakte, usw.) und kann (aber muss nicht) auch die Menge der empfohlenen Engineering-und Management-Praktiken enthalten, die man verwenden soll, wenn diese Methode auf das Projekt angewendet wird.
Zu den agilen Methoden gehören Scrum, Kanban, XP und andere.

Einige Methoden haben nur Projektmanagementteile. Zu diesen gehören z.B. Scrum und Kanban. Es gibt auch Methoden, die sowohl Projektmanagement- als auch Entwicklungsanteile haben. Dies ist z.B. Extreme Programming, FDD und Tracer Bullet Development.

Extreme Programming (XP)

Die Erfinder von XP haben Smalltalk als ihre Hauptentwicklungssprache benutzt. Smalltalk war eine der ersten objektorientierten dynamischen Programmiersprachen. Die Produktivität der Entwickler auf Smalltalk war dabei im Vergleich zur damaligen Hauptkonkurrenz C++ deutlich höher.

Aufgrund der Natur der Sprache war die Ausführung der primäre Weg, um die Korrektheit des Codes festzustellen. Deshalb war die Überprüfung großer Teile des Codes mühsam und fehlerhaft. Die Lösung, die für dieses Problem gefunden wurde, war eine Menge an Unit-Tests schreiben.

Wenn man in einer dynamische Sprache entwickelt, dann ist der Einsatz von Pair-Programming gut begründet. Viele Fehler, kleine und große, werden bereits beim Entwickeln festgestellt. Dadurch wird viel Zeit durch Verringerung der Anzahl der Wiederausführungs- /Fehlerbehebungs- Zyklen gespart.

Zu den Entwicklungspraktiken des Extreme Programming gehören:

  • Pair-Programming
  • Testgetriebene Entwicklung/Unit Tests
  • Kontinuierliche Integration
  • Refactoring
  • Akzeptanztest
  • Kleine Releases

XP hat auch Praktiken für die Erzeugung und Aufrechterhaltung eines gemeinsamen Verständnisses:

  • Einfaches Design
  • Coding-Standards
  • Metapher
  • Kollektives Code Eigentum

Feature Driven Development

Feature-Driven Development wurde für ganz andere Art von Projekten entwickelt. Die erste Anwendung war ein Festpreisprojekt mit fünfzig Entwicklern und einer Zeitspanne von zwei Jahren. Im Rahmen eines Festpreisprojektes können Refactoring und Nacharbeit sehr nachteilig sein, da sie Investitionen in eine Zukunft darstellen, die nicht notwendigerweise durch den Festpreisrahmen abgedeckt ist.

Die erste Phase eines FDD-Projekts ist eine leichtgewichtige Modellierung der Problemdomäne. Dadurch werden mehrere Ziele erreicht:

  • Fixierung des groben Projekt-Umfangs
  • Minimierung des Refactorings auf Modell-Ebene (dies passiert mit Hilfe einer speziellen Modellierungstechnik, die man Color Modeling nennt)
  • Schätzung des Zeitaufwandes
  • .

Ein Ergebnismodell ist dann für die ganze Zeitdauer des Projektes gültig. Das Modell erlaubt dabei die Koordination aller Entwicklungs-und Reporting-Aktivitäten.
Zu den Entwicklungspraktiken von FDD gehören:

  • Domain Object Modeling
  • Entwickeln pro Feature
  • Individuelle Eigentum von Code auf Klassenebene
  • Inspektionen
  • Regelmäßige Builds
  • Configuration Management

Im Unterschied zu XP wird bei FDD gefordert, dass Builds mindestens einmal pro Tag gemacht werden.

Jede Klasse in dem Domain Modell wird einem individuellen Entwickler zugewiesen. Er ist dann verantwortlich für die Wartung dieser Klasse während des Laufes des ganzen Projekts. Für jedes Feature werden die Klassen, welche voraussichtlich von der Implementierung dieser Features betroffen sind, bestimmt. Danach wird ein Feature Team aus den Klassenverantwortlichen gebildet.

Der Prozess der Entwicklung pro Feature ist in FDD gut definiert. Der Chefprogrammierer trifft hierbei die Entscheidung, ob optionale Schritte durchgeführt oder übersprungen werden. Die Umsetzungphase des FDD Projekts enthält zwei Prozesse. Diese sind “Entwurf pro Feature” (Design by Feature) und “Implementierung pro Feature” (Build by Feature).

Während des “Entwurf pro Feature”-Schrittes führt das verantwortliche Feature-Team gemeinsam ein kollaborativen Design durch.

Die Phase “Implementierung pro Feature” enthält Implementierung, Codeinspektion, Unit Test und Freigabe des Codes. Formale Inspektionen, in Unterschied zu Extreme Programming, sind das primäre Mittel, um Qualität zu erreichen. Diese werden beim Entwickeln auf verschiedenen Ebenen durchgeführt: zuerst auf dem Modell, dann auf dem Design und schließlich auf dem Code. Unit Tests werden zwar gleichfalls als sehr wichtig betrachtet, sind aber nicht das „Nummer Eins“ Werkzeug.

The post Agile Entwicklungspraktiken: der Ursprung appeared first on codecentric Blog.

Agile Entwicklungspraktiken: die zweite Generation

$
0
0

Die Welt steht nicht still. Nach dem initialen Erfolg der agilen Methoden zwischen Ende neunziger und Anfang 2000 ist ihre Verwendung stark gewachsen, und ihre Anwendungsbereiche haben sich auch weit über ursprüngliche Sweet-Spots erweitert.

Eine der Erweiterungen ist die Verwendung der agilen Praktiken für die Arbeit mit Datenbanken. Dies beinhaltet Arbeit an der Automatisierung von Änderungen der Datenbankschemata und auch Testen und Refactoring von Datenbanken.

Domain Modeling

Der FDD Ansatz für die Erstellung des Domain Models hat seine Weiterentwicklung durch Domain Driven Design (oder kurz DDD) gefunden. Man zwar kann nicht behaupten, dass DDD ein direkter Nachfolger der Color Modeling/Streamlined Object Modeling Ansatz ist, aber Streamlined Object Modeling ist in DDD Gemeinschaft weithin anerkannt und hoch angesehen.

Unit- und Akzeptanztests


Testgetriebene Entwicklung hat sich zu Behavior Driven Development oder BDD (verhaltensgetriebene Softwareentwicklung) weiterentwickelt. Der Hauptunterschied zwischen beiden liegt in der Sprache, die man für den Ausdruck der Anforderungen benutzt. Diese Sprache ist hilfreich, lesbarere Spezifikationen zu erzeugen.

Zwei verschieden Varianten des Unit Tests haben sich kristallisiert. Diese sind zustandbasiertes Testen und interaktionsbasiertes Testen. In der zweiten Variante wird sehr stark Mocking verwendet.

Die Gemeinschaft experimentiert aktuell mit weiteren Varianten des Unit-Tests. Eine dieser Varianten ist eigenschaftsbasierte Testen (property-based Testing auf Englisch), das seine Wurzeln in Haskells QuickCheck-Framework hat. Im eigenschaftsbasierten Testen wird der gleiche Test mit verschiedenen generierten Eingabewerten mehrfach ausgeführt .

Eine andere Entwicklung ist die Adaption der agilen Entwicklungspraktiken für die Arbeit mit Legacy-Code. Dies hat zum Verständnis geführt, dass Unit-Testen in bestimmten Szenarien sehr kompliziert ist. Drei solcher Szenarien sind Unit-Tests für Legacy-Code, Unit-Tests für Oberflachen (GUI) und Testen von asynchronem Code.

Die Techniken des automatisierten Akzeptanztestens haben sich gleichfalls weiterentwickelt. Diese wurden weiter als “Spezifikation durch Beispiel” verfeinert. Viele verschiedene Akzeptanz-Test-Frameworks wurden neben dem Original Fit & Fitnesse entwickelt. Gleichzeitig bleibt diese Praxis nach wie vor eine der umstrittensten in der agilen Software-Entwicklung. Die Nachteile des automatisierten Akzeptanztestens werden aktuell allerdings deutlich besser verstanden. Deshalb hat manuelles Testen sein Comeback in Form von explorativem Testen.

Code Reviews und Statische Code Checks

Mehrere gute Software-Systeme wurden zur Durchführung verteilter Code-Reviews entwickelt. Zu diesen gehören Code Collaborator, Crucible, Review Board und andere. Sie haben den Aufwand der schwergewichtigen formalen Inspektionen reduziert.

Aber auch die Verwendung statischer Code-Checks trägt sehr stark zur Code Qualität bei. Und auch hier wurden einige Plattformen entwickelt, die die Ergebnisse von verschiedenen Code-Check-Systemen zu einem Dashboard zusammenfassen. Man kann im Dashboard mit Hilfe eines Drill-Downs weitere Details erkunden. Dies ermöglicht laufende Qualitätsüberwachung des Quelltexts. Ein Beispiel für solches System ist SonarQube.

Kontinuierliches Testen

Die Erfahrung hat gezeigt, dass kontinuierliche Integration eine der wertvollsten agilen Praktiken ist. Diese wurde in zwei Richtungen erweitert.

Zum einen ist die Praxis der Testausführung vor jedem Commit, die ursprünglich die Verantwortung des einzelnen Entwicklers war, durch Werkzeuge für kontinuierliches Testen verallgemeinert worden, was es erlaubt, Tests und statische Checks bei jeder Speicheroperation des Entwicklers automatisch durchzuführen.

Continuous Deployment und Continuous Delivery

Die zweite Richtung der Erweiterung sind Continuous Deployment und Continuous Delivery.

Wenn man den Gedanken häufiger Releases bis zum konsequenten Ende durchdenkt, dann muss man über kontinuierliche Integration hinausgehen. Im idealen Fall sollte ein Release in eine beliebige Umgebung (Stage) eine Operation mit minimaler manueller Arbeit sein, im besten Fall eine „Ein-Klick“-Operation. Um dies hinzubekommen, muss deutlich mehr gemacht werden als für Continuous Integration, und vor allem müssen auch die verschiedenen Umgebungen genau wie die Skripte, die für das Deployment verwendet werden, automatisch aufgesetzt und verwaltet werden. Deshalb wurde Deployment-Automatisierung geboren.

Deployment-Automatisierung ist eng mit der Notwendigkeit gekoppelt, Umgebungen leicht zu reproduzieren und Software auf mehreren identischen Knoten bereitzustellen. Insbesondere in Cloud-Umgebungen ist dies eine Notwendigkeit. Dies hat zu der Verbreitung von Werkzeugen für die Virtualisierung, automatisierte Bereitstellung und Konfigurierung von virtuellen Maschinen geführt. In Folge muss es natürlich notwendig sein, diese vielen Umgebungen zu überwachen, um Probleme sehr schnell festzustellen. Dies führt zu einem stark gesteigerten Interesse an Werkzeugen zur Echtzeitüberwachung.

Die kürzer werdenden Zyklen von Entwicklung bis zur Produktion sorgen in Folge für einen deutlich erhöhten Bedarf an Testautomatisierung auf allen Ebenen, von Unit-Tests über Integrations- und Lasttests bis zur Automatisierung von Akzeptanz- und GUI-Tests.

Die Sammlung der miteinander verknüpften Praktiken für die automatisierte Deployment, Umgebung Erstellung, Provisioning, Konfiguration und Überwachung werden unter dem Begriff „Continuous Deployment“ vereint.

Soziale Aspekte

Unsere Übersicht wäre nicht vollständig ohne eine Erwähnung der sozialen Aspekte der Softwareentwicklung.
Der inhärente Wunsch, qualitativ gute Ergebnisse zu liefern und am Abend eines jeden Tages mit einem guten Gefühl nach Hause gehen zu können, hat zur Software-Craftmanship-Bewegung geführt, die mehr und mehr Schwung bekommt.

Die Umsetzung des Continuous Deployments besteht aus zwei Teilen, dem technischen, der beherrschbar ist, und dem sozialen, der einen Prozess des Umdenkens bei jedem Einzelnen erfordert. Dies erfordert häufige Interaktion, Zusammenarbeit und Integration von Entwicklern und Mitarbeitern des Betriebs, die ihre verschiedenen Ziele verstehen und in Übereinstimmung bringen müssen. Die zugehörige Bewegung „DevOps“ hat das Ziel, die Fertigstellung von Software und ihre Inbetriebnahme so effizient und zuverlässig wie möglich zu machen, ohne dabei die längerfristigen Ziele des Betriebs aus den Augen zu verlieren.

Wollen Sie mehr über Agilität erfahren? Oder vielleicht wollen Sie ihre Erfahrungen tauschen? Dann freuen wir uns auf ihre Teilnahme beim Agilen Stammtisch Frankfurt. Das Thema des Lightning Talks des nächsten Stammtisches ist „Agility und Datenbanken“.

14. Agiler Stammtisch Frankfurt findet an 4. September um 19:00 an „die Zentrale“ statt. Kostenlose Registrierung über XING.

The post Agile Entwicklungspraktiken: die zweite Generation appeared first on codecentric Blog.

Agiles Testen von JIRA Plugins (Teil 2): Wired Tests

$
0
0

Im letzten Beitrag haben wir – das sind Raimar Falke und ich – einen Blick auf das Setup eines JIRA Plugin Projektes geworfen und wie man dafür Unittests aufsetzt und ausführt. In diesem Beitrag werden wir uns nun “Wired Tests”, einer weiteren Testart, widmen.

Wired Test

Atlassian bezeichnet mit dem Begriff “Wired Test” einen Test, welcher innerhalb der laufenden Host Application, in unserem Fall also JIRA, ausgeführt wird. Technisch gesehen werden die Testklassen als separates Test-Plugin zusammengefasst und in die laufende Host Application geladen. Ein spezieller Testrunner (AtlassianPluginsTestRunner) wird dann benötigt, welcher aus der VM heraus, in der JUnit läuft, das Test-Plugin aufruft und die Ausführung der Tests startet. Die Ergebnisse des Tests werden dann wieder an die JUnit-VM geschickt.Dieser Ansatz hat einige Vor- aber auch Nachteile. Zunächst die Vorteile:

  • Die Tests laufen in einer Umgebung, die sehr ähnlich dem späteren Produktionssystem ist.
  • Alle Abhängigkeiten können durch den Konstruktor der Testklasse einfach bereitgestellt werden.
  • Im Fehlerfall erhält man einen aussagekräftigen Stacktrace.

Es gibt jedoch auch einige Nachteile:

  • Der Start einer JIRA Instanz ist sehr langsam. Auf einem etwas schwächeren CI Server kann die Durchführung auch einfacher Tests durchaus 10 Minuten und mehr dauern.
  • Der Testrunner führt immer alle Tests der Testklasse aus, auch wenn man nur gezielt einen einzelnen Test ausführen will.
  • Wired Tests tragen nicht zur Code Coverage bei – zumindest nicht ohne einigen Aufwand. Das Thema Code Coverage werden wir in einem späteren Beitrag noch anreißen.
  • Man ist in der Wahl der Test-Abhängigkeiten nicht völlig frei. So muss man beispielsweise die mitgelieferte JUnit version (4.10) benutzen. Selbst wenn man explizit eine andere Version vorgibt, wird diese nicht in das Test-Plugin übernommen.
  • Im Normalfall wird die Host Application für mehr als einen Test benutzt. Das bedeutet natürlich, dass man besonders sorgfältig darauf achten muss, dass man den globalen Zustand (z.B. statische Variablen) nicht unabsichtlich verändert, und dass Tests mit Daten aus früheren Testläufen oder vorher gelaufenen Tests umgehen müssen.
  • Es gibt keine Möglichkeit, Abhängigkeiten für einen Test gezielt zu verändern (was ja bei Unittests mit Mocks möglich ist), sodass bspw. ausgehende Emails statt versandt zu werden, in einem Event-Log landen. Insofern sind Wired Tests mehr System- als Integrationstests.
  • Da die Tests als eigenes Plugin im OSGi Container laufen, können sie nur die tatsächlich exportierten Methoden des zu testendenen Plugins testen. Das bedeutet einerseits, dass die zu testende Komponente ein Interface implementieren muss, gegen das der Test läuft, und andererseits müssen auch alle Klassen, die im Interface referenziert werden, exportiert werden, da der OSGi ClassLoader sie sonst nicht kennt. Da dieser Export für die normale Interaktion innerhalb des Plugins nicht benötigt wird, benötigt das einen Eingriff in die Konfiguration des Plugins, die nur für den Test notwendig ist, aber global definiert wird

Außerdem gilt:

  • Es wird eine laufende JIRA Instanz benötigt. Wenn der Test in der Integrationstestphase durch Maven ausgeführt wird, geschehen Start und Stop der Instanz automatisch. Alternativ kann man die Instanz auch mittels “atlas-run” manuell gestartet werden. Die Verwendung einer normalen JIRA Installation ist nicht möglich, da diese einige Entwickler-Plugins nicht enthält.
  • Wenn man die Standardkonfiguration verwendet, müssen alle Wired Tests in einem Package mit Präfix it.* (it steht dabei für Integrationstest) liegen, damit die Atlassian Plugins sie korrekt ausführen.

Unsere Meinung

Die Liste der Nachteile scheint lang, was aber für einen derartig tief eingreifenden Test verständlich ist. Die wichtigere Frage ist aus unserer Sicht jedoch, wozu man Wired Tests benötigt. Wir vermuten, dass die Notwendigkeit aus der Tatsache entstand, dass ein Unittest sehr stark in der Interaktion mit anderen Komponenten eingeschränkt ist, wenn nicht die gesamte Host Application gestartet wurde. Ein zweiter Grund kann die Testbarkeit von Services sein, welche keine REST Schnittstelle bereitstellen, und daher nicht “von außen” getestet werden können. Eine Möglichkeit, die Geschäftslogik auch ohne die oben genannten Nachteile zu testen, besteht in der Erstellung einer Fassade, die die benutzten JIRA Funktionen kapselt, und dem Test der Geschäftslogik gegen einen Mock der Fassade. Auf diese Weise benötigt man keinen Wired Test. Trotzdem gibt es Fälle, in denen Wired Tests die beste Wahl sind.

Beispiel für einen Wired Test

Um Wired Tests auszuführen, ist es notwendig einen Plugin Descriptor für das Test-Plugin zu erstellen (src/test/resources/atlassian-plugin.xml). Wenn man die Atlassian Befehle zum Hinzufügen von Komponenten und Ressourcen verwendet, wird der Descriptor für das Test Plugin automatisch erstellt bzw. um die neuen Elemente ergänzt; ansonsten müssen diese Komponenten manuell nachgetragen werden.

Ein Beispiel für einen Plugin Descriptor könnte so aussehen (Foo ist das Interface der zu testenden Komponente):

<atlassian-plugin key="${project.groupId}.${project.artifactId}-tests" 
  name="${project.name}" plugins-version="2">
  <plugin-info>
    <description>${project.description}</description>
    <version>${project.version}</version>
    <vendor name="${project.organization.name}" url="${project.organization.url}"/>
  </plugin-info>
 
  <!-- from the product container -->
  <component-import key="applicationProperties" 
    interface="com.atlassian.sal.api.ApplicationProperties"/>
 
  <!-- from the plugin under test -->
  <component-import key="foo-component" interface="com.example.Foo"/>
</atlassian-plugin>

Der Test selbst ist dann quasi ein Unittest, mit dem Unterschied, dass dem Konstruktor alle Abhängigkeiten als Parameter übergeben werden und die Klasse mit dem erwähnten Testrunner annotiert wird:

@RunWith(AtlassianPluginsTestRunner.class)
 
public class FooWiredTest {
  private Foo component;
 
  public FooWiredTest(Foo component) {
    this.component = component;
  }
 
  @Test
  public void test_foo_saves() {
    component.setValue("myTestValue");
    assertEquals("myTestValue", component.getValue());
  }
}

Ausführen von Wired Tests

Wired Tests können als Teil des normalen Builds mit dem Kommando “atlas-integration-test” gestartet werden. Alternativ können auch normale Maven Befehle benutzt werden, die die Integrationstests anstoßen, bspw. “mvn integration-test” oder “mvn verify”. In diesen Fällen wird immer eine neue JIRA Instanz gestartet und Plugin sowie Test Plugin dort installiert.

Darüber hinaus können Wired Tests auch gegen eine bereits laufende JIRA Instanz ausgeführt werden, indem das Kommando “atlas-remote-test” benutzt wird. Dieses benötigt jedoch Parameter, die beschreiben, wo der Server läuft, gegen den getestet wird. Wenn man das Standard-Setup von JIRA verwendet, lautet das Kommando z.B. “atlas-remote-test –server localhost –http-port 2990 –context-path /jira”.

Um Wired Tests aus der IDE zu starten, muss ebenfalls zunächst eine JIRA Instanz gestartet werden (z.B. “atlas-run” oder “mvn jira:run”). Dies lädt auch gleich die aktuelle Version von Plugin und Test Plugin in die Testinstanz. Zusätzlich ist es notwendig, dem Test beim Start die System Property “baseurl” zu setzen, z.B. “-Dbaseurl=http://localhost:2990/jira”. Bei der Verwendung der Maven oder Atlassian Befehle wird diese Property automatisch durch das Atlassian SDK gesetzt.

Bei der Ausführung von Tests aus der IDE heraus muss man jedoch immer bedenken, dass die Tests in der laufenden JIRA Instanz und nicht der JVM der IDE ausgeführt werden. Alle Änderungen am Test (oder dem Plugin) müssen daher zunächst in die JIRA Testinstanz deployt werden, bevor die Tests wiederholt werden. Diese Aktualiserung kann durch das Kommando “atlas-install-plugin” erreicht werden, wodurch das eigentliche Plugin neu geladen wird, oder mittels “mvn package jira:install jira:test-install”, wodurch sowohl das Plugin als auch das Test Plugin neu geladen werden.

Zusammenfassung

Auch wenn das Konzept, Tests innerhalb der Host Application laufen zu lassen, theoretisch sehr verlockend ist, hat es uns in der Praxis nicht wirklich überzeugen können. Die schwerwiegendsten Nachteile sind dabei die Tatsache, dass die Tests nicht wirklich so unabhängig vom regulären Code sind, wie sie sein sollten, und dass das Einspielen neuer Plugin- bzw. Test-Plugin-Versionen nicht wirklich schnell oder einfach möglich sind.

Der nächste Beitrag wird sich jedoch zunächst den Frontend-Tests widmen.

The post Agiles Testen von JIRA Plugins (Teil 2): Wired Tests appeared first on codecentric Blog.


Immutable Infrastructure & Micro Services mit CoreOs, Docker und Dropwizard Part 1

$
0
0

Im ersten Blog Post in der Serie über Immutable Infrastructure & Micro Services mit CoreOs, Docker und Dropwizard möchte ich den Micro Service und Immutable Infrastructure Architekturansatz vorstellen. Dazu werden wir uns anschauen, warum Micro Services im Umfeld von hochverfügbaren Infrastruktur-Lösungen ein nicht nur interessanter, sondern auch gangbarer Weg ist seine Software zu bauen.
Wir werden uns dazu Vor- bzw. Nachteile von Micro Services und im Bereich der Infrastruktur das Immutable Server Pattern anschauen. Am Ende des ersten Posts werden wir einen ersten Blick auf einige Tools werfen, mit denen Micro Services und Immutable Server umgesetzt werden können. Im zweiten Teil der Serie werde ich dann zeigen, wie Immutable Infrastructure & Micro Services mit CoreOs, Docker und Dropwizard umgesetzt werden können.

Das Ablösen von Altanwendungen hat in den letzten 10 Jahren auf Grund der Komplexität der vorhandenen Anwendungen viel Geld gekostet. Hinzu kommt, dass viele Firmen sich bis heute, aufgrund unüberschaubarer Risiken, nicht trauen alte Anwendungen abzulösen. Dies wiederum führt zur künstlichen Verlängerung des Software-Lebenszyklus, obwohl die Systeme längst veraltet und buchhalterisch abgeschrieben sind.
Ein aktueller Ansatz um in Zukunft vergleichbare Probleme zu vermeiden ist die Zerteilung von Anwendungen in viele Micro Services die unabhängig voneinander weiterentwickelt werden können. Da jeder einzelne Service klein ist, sind die Risiken bei der Weiterentwicklung in diesem Paradigma überschaubar [1][4].

Micro Service haben eine Reihe von Eigenschaften. Diese sind:

  • Werden nach dem “rewrite first” Paradigma geschrieben. (Neu schreiben statt anpassen).
  • Übernehmen genau eine Aufgabe (Ähnlich einem Linux Service).
  • Sind klein (Klein genug für einen Sprint).
  • Bringen alles mit um eigenständig lauffähig zu sein.
    • Bringen eigene Oberflächenelemente mit. Ein Beispiel hierfür wäre eine Tabelle welche alle Kunden innerhalb einer Kundenverwaltung ausgeben oder ein Formular mit dem ein Kunde angelegt werden kann. Diese Oberflächenelemente können dann innerhalb von Client Anwendungen per Web Service Aufruf eingebunden werden.
    • Haben ein eigenes Datenmanagement.
  • Sind individuell skalierbar, werden mit einer hohen Testabdeckung entwickelt und sind individuell deploybar.

Hinzu kommt, dass es egal ist, in welcher Sprache die Micro Services geschrieben werden, da sie mit dem Uniform Interface Ansatz (REST) entwickelt werden [7]. Der Uniform Interface Ansatz besteht aus vier Prinzipien, diese sind:

  • Identifizieren von Ressourcen – Individuelle Ressourcen werden durch eindeutige bspw. Uniform Resource Identifier (URI) repräsentiert. Die Server Interne Ressource wird bspw. durch HTML, XML oder JSON repräsentiert.
  • Manipulation der Ressourcen – Geschieht über die gesendeten HTLM, XML oder JSON Ressourcen
  • Selbstbeschreibende Nachrichten – Eine gesendete Ressource beinhaltet genügend Information um sowohl vom Server als auch vom Client weiter verarbeitet zu werden. Nachrichten sind also Zustandslos.
  • Hypermedia as the engine of application state (A.K.A. HATEOAS) – Ein Client navigiert über Hypermedia auf zuvor vom Server dynamisch bereitgestellten Schnittstellen. HATEOAS soll lose Bindungen gewährleisten und es so ermöglichen Schnittstellen zu ändern.

Dies ermöglicht es, verschiedenste Micro Service mit verschiedensten Technologien zu entwickeln. Da jedes Team in unterschiedlichsten Technologien verschiedene Fähigkeiten aufweißt, kann somit der volle Umfang der teaminternen Fähigkeiten ausgeschöpft werden. Dabei wird auf HTTP request-response mit Resourcen API’s (REST) und leichtgewichtigem Messaging gesetzt und nicht auf komplexe Protokolle wie WS-Choreography, BPEL oder sonst einer Orchestrierung durch ein zentrales Tool.

Ein Nachteil der Micro Service Architektur ist sicherlich die verhältnismäßig große Verteilung verschiedenster Anwendungen. Dies führt dazu, dass immer davon ausgegangen werden muss, dass ein anderer Micro Service keine Antwort liefert oder aktuell nicht vorhanden ist. Es entsteht also eine zusätzliche Komplexität: Das Erstellen einer Anwendung in einer verteilten Umgebung. Es müssen hierfür Strategien entwickelt werden, wie die einzelnen Micro Services untereinander kommunizieren, was bei einer ausbleibenden Antwort geschieht und wie mit verteilten Transaktionen umgegangen wird. Für die IT-Betriebsmannschaft kommt hinzu, dass Sie plötzlich anstatt ein paar Anwendungen eine ganze Armada von Anwendungen zu starten, überwachen und warten haben. Dies ist nur mit einer hohen Automatisierung in diesem Bereich möglich. Ein Grund mehr warum wir uns Immutable Infrastruktur mit CoreOs und Docker genauer anschauen werden.

Einigen der beschriebenen Probleme wird durch ein ausgeprägtes Real-Time Monitoring der einzelnen Micro Service begegnet. Solch ein Monitoring könnte bspw. folgende Auswertungen liefern:

  • Service Monitoring: Ist der Service generell erreichbar
  • Architektur Monitoring: Wie viele Anfragen pro Sekunde gehen auf die Datenbank
  • Business Monitoring: Wie viele Bestellungen werden pro Minute verarbeitet
  • Semantic Monitoring: Verhaltens Monitoring um Fehler schon im Voraus zu erkennen

Fassen wir Micro Service zusammen: Micro Services sind leichtgewichtig (im Sinne der Entwicklungszeit und der eingesetzten Tools), eigenständig (Auf allen Ebenen) und ermöglichen individuelles Tooling für jedes Team, egal über welche technologischen Fähigkeiten das Team verfügt.

Um die Betriebsmannschaft zu unterstützen schauen wir uns jetzt ein unterstützendes Muster an um die höhere Komplexität der Infrastruktur, die bei vielen Micro Services anfällt, in den Griff zu bekommen. Martin Fowler hat neben dem Micro Service auch den so genannten Phoenix Server beschrieben [2]. Ein Phoenix Server zeichnet sich dadurch aus, dass er bei jeder Änderung komplett zerstört und neu aufgebaut wird – wie ein Phönix aus der Asche. Um einen solchen Phoenix Server bspw. innerhalb einer Continuous Deployment (CD) Pipeline einzusetzen, kommt das Immutable Server Pattern zum Einsatz [3]. Betrachten wir die CD-Pipeline in Abb. 1, so sehen wir, dass im Schritt “Konfiguriere Infrastruktur” ein bereits installierter und konfigurierter Server erneut konfiguriert wird. Führt man das Immutable Server Pattern ein, so wird (wie in Abb. 2 gezeigt) in diesem Schritt der Server vollständig neu provisioniert. Dies führt dazu, dass auch kleinste Änderungen sowohl an der Infrastruktur als auch am Code der Anwendung zu einer neuen Provisionierung des Servers führen. Server sind also unveränderlich und bleiben damit über alle Umgebungen gleich. Dies hat zum Vorteil, dass ein Auseinanderdriften der Konfiguration (engl. Configuration Drifts [1]), also bspw. dem Entstehen von Unterschieden zwischen der Infrastruktur in Entwicklung, Test und Produktion verhindert wird.

CD-Pipeline1

 

 

 

 

 

 
 
Abb. 1: Die herkömmliche CD-Pipeline bietet viele Gefahren für Configuration Drifts.

CD-Pipeline2

 

 

 

 

 

 

 

 
 
Abb. 2: Die überarbeitete CD-Pipeline provisioniert den Server immer neu.

Um Micro Services zu erstellen und Server ohne viel Aufwand immer wieder aus der Asche heben zu können, benötigen wir verschiedene Werkzeuge. Dazu werde ich im nächsten Blog Post CoreOs, Docker und Dropwizard nutzen. In diesem Post möchte ich die Werkzeuge kurz vorstellen.

Docker hat zum Ziel, das Deployment von Anwendungen in Container zu automatisieren. Dazu  nutzt Docker Container Virtualisierung. Container Virtualisierung wiederum baut auf den vorhandenen Linux Kernel auf und wird deshalb oft auch System-Level-Virtualisierung genannt (siehe Abb. 3). Docker schafft es so, sehr schnell und leichtgewichtig Anwendungen zu bauen, zu transportieren und auszuführen. Für einen sehr guten Einstieg in Docker empfehle ich die folgenden Blog Post [8][9][10][11][12]. In unserem Fall, der Immutable Infrastruktur, bildet der Docker Container den Server ab, der bei jeder Änderung immer neu zu provisionieren ist.

Docker

 

 

 

 

 

 
Abb. 3: Aufbau von Containern (Quelle: http://xebia.github.io/docker-introduction/slides/img/docker-filesystems-busyboxrw.png)

CoreOS ist eine leichtgewichtige Linux-Distribution zum schnellen aufsetzen von Clustern und darauf spezialisiert, Docker Container zu verwalten (siehe Abb. 4). Unter CoreOs kann sich Docker wie ein Paketmanager vorgestellt werden.

Docker und CoreOs

 

 

 

 

 

 
Abb. 4: Docker Container innerhalb eines CoreOS Host

Dazu werden verschiedenste Docker Container, welche über ein Repository bereit gestellt werden können, über systemd beschrieben und mit fleet auf dem Cluster verteilt. Systemd ist ein Daemon, welcher das Starten, Stoppen und Überwachen weitere Prozesse kontrolliert. Innerhalb von CoreOs werden sogenannte Unit Files (siehe Listing 1) für die einzelnen Docker Container bereitgestellt. Fleet agiert für systemd als Cluster Manager und erlaubt so das verteilen eines Containers innerhalb des Clusters [5]. Zu guter letzt nutzt CoreOS etcd als verteilten Schlüssel-Wert Speicher. Etcd ermöglicht das nutzen von einer gemeinsamen Konfiguration und das Erkennen von Services innerhalb des Clusters. Etcd läuft dazu auf jedem Knoten im Cluster und hilft zudem bei der Auswahl des Master bei der Netzwerkpartitionierung und wenn der aktuelle Master ausfällt (siehe Abb. 5).

Etcd

 

 

 

 

 

 
Abb 5. Der Master und seine Follower innerhalb eines CoreOs Clusters.

Wir werden uns die genannten Tools innerhalb von CoreOs im Zuge des nächsten Blog-Posts noch im Detail anschauen.

Listing 1:

[Unit]
Description=MyApp
After=docker.service
Requires=docker.service
 
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill busybox1
ExecStartPre=-/usr/bin/docker rm busybox1
ExecStartPre=/usr/bin/docker pull busybox
ExecStart=/usr/bin/docker run --name busybox1 busybox /bin/sh -c "while true; do echo Hello World; sleep 1; done"
ExecStop=/usr/bin/docker stop busybox1

Dorpwizard ist wie bspw. auch Spring Boot ein Framework, mit dem sich Micro Service erstellen lassen [6]. Dropwizard packt dazu verschiedenste bewährte und produktionsreife Bibliotheken aus der Java Welt zusammen und bietet zusätzlich einige selbstentwickelte Einstiegspunkte für die Entwicklung von Micro Services.
Grundsätlzich werden in Dropwizard folgenden Bibliotheken genutzt:

  • Jetty als HTTP-Server.
  • Jersey ist die JAX-RS Referenz-Implementierung um REST Anwendungen zu schreiben.
  • Jackson um mit JSON zu arbeiten.
  • Metrics zum erstellen von Metriken.
  • Guava stellt viele Klassen bereit, welche das schreiben von Code beschleunigen.
  • Logback and slf4j für das Logging innerhalb der Anwendung .
  • Hibernate Validator zum Validieren von Benutzereingaben.
  • Der Apache HttpClient und die Jersey Client Bibliothek erlauben die Interaktion mit Web Servicen.
  • JDBI erleichtert den Zugriff auf relationale Datenbanken in Java.
  • Liquibase ermöglicht das Beschreiben von Datenbankschemata.
  • Mit Freemarker und Mustache können Templates für die Oberflächengestaltung erstellt werden.
  • Joda Time, eine ausgereifte Bibliothek rund um das Thema Datum und Zeit.

Ich hoffe ihr konntet einen guten Eindruck gewinnen wieso Micro Services und Immutable Infrastruktur hilfreich sein können und was die grundsätzlichen Ideen dahinter sind. Für alle Freunde des praktischen Einstiegs kann ich getrost sagen, dass wir uns im nächsten Blog Post genug austoben werden. Ich hoffe die Erklärungen und die Zusammenstellung der Tools hat euch gefallen und ihr beschäftigt euch schon ein bisschen mit den genannten Tools bevor wir im nächsten Post an die Umsetzung gehen. Ich freue mich natürlich auch über jedes Feedback.

Weiter unten habe ich noch ein Reihe von Tools gelistet die ebenfalls beachtenswert sind.

[1] http://martinfowler.com/articles/microservices.html

[2] http://martinfowler.com/bliki/ImmutableServer.html

[3] http://martinfowler.com/bliki/PhoenixServer.html

[4] http://martinfowler.com/articles/microservices.html#AreMicroservicesTheFuture

[5] https://coreos.com/docs/launching-containers/launching/launching-containers-fleet/

[6] https://dropwizard.github.io/dropwizard/

[7] http://en.wikipedia.org/wiki/Representational_state_transfer#Uniform_interface

[8] https://blog.codecentric.de/2014/01/leichtgewichtige-virtuelle-maschinen-mit-docker-oder-wie-man-100-vms-laufen/

[9] https://blog.codecentric.de/2014/07/vier-wege-in-den-docker-container/

[10] https://blog.codecentric.de/en/2014/01/docker-networking-made-simple-3-ways-connect-lxc-containers/

[11] https://blog.codecentric.de/en/2014/08/docker-dock-development-environment/

[12] https://blog.codecentric.de/en/2014/02/docker-registry-run-private-docker-image-repository/


Weitere Links zu stöbern:

http://martinfowler.com/bliki/MicroservicePrerequisites.html

http://martinfowler.com/bliki/SnowflakeServer.html

http://kief.com/configuration-drift.html

http://martinfowler.com/articles/enterpriseREST.html#versioning

http://netflix.github.io/#repo

 

Weitere Tools zum stöbern:

Vagrant

https://www.vagrantup.com/

Terraform

http://www.terraform.io/

Packer

http://www.packer.io/intro

Packer vs Vagrant

https://groups.google.com/forum/#!msg/packer-tool/4lB4OqhILF8/NPoMYeew0sEJ

Docker with Puppet

http://puppetlabs.com/blog/building-puppet-based-applications-inside-docker

Packer and Docker

http://www.packer.io/docs/builders/docker.html

Packer builds Docker containers without the use of Dockerfiles. By not using Dockerfiles, Packer is able to provision containers with portable scripts or configuration management systems that are not tied to Docker in any way. It also has a simpler mental model: you provision containers much the same way you provision a normal virtualized or dedicated server. For more information, read the section on Dockerfiles.

Boxen

https://boxen.github.com/

Immutable Server Pattern auf die Spitze Treiben siehe Netflix Chaos Monkey

http://techblog.netflix.com/2011/07/netflix-simian-army.html

 

The post Immutable Infrastructure & Micro Services mit CoreOs, Docker und Dropwizard Part 1 appeared first on codecentric Blog.

Agiles Testen von JIRA Plugins (Teil 3): Systemtests

$
0
0

Nach Unit- and Wired Tests stellen Systemtests einen weiteren Testtyp der Testpyramide dar, den wir im Kontext der Plugin Entwicklung für JIRA betrachten wollen. In diesem Artikel werden wir – d.h. Raimar Falke und ich – zwei weitere Testarten vorstellen, die die gesamte bzw. nahezu die gesamte Applikation testen: Tests der Weboberfläche und REST-API Tests.

Testen der Weboberfläche

Atlassian stellt eine Reihe von Tools bereit, die die Erstellung von End-to-End Tests für ihre Produkte vereinfacht. Die wichtigsten darunter sind TestKit, welches die Erstellung eines “Backdoor” vornimmt, welcher für die Durchführung administrativer Aufgaben oder das Einspielen von Testdaten genutzt werden kann, sowie eine große Zahl an Pageobjects für alle Applikationen. Auch wenn TestKit nicht genutzt werden muss, ist die Verwendung sehr zu empfehlen, da es viele Aufgaben, wie bspw. das Erzeugen eines definierten Zustands der zu testenden Instanz zum Kinderspiel macht. Ein weiteres Tool für die Entwicklung von End-to-End Tests, welches TestKit stark ähnelt, ist FuncTest. Der wichtigste Unterschied ist, dass FuncTest Selenium für die Ausführung administrativer Aufgaben nutzt, während TestKit dies über eine REST-API erledigt.

Setup

Die Definition der benötigten Dependencies ist einfach und sieht typischerweise so aus:

<dependency>
  <groupId>com.atlassian.jira.tests</groupId>
  <artifactId>jira-testkit-client</artifactId>
  <version>${testkit.version}</version>
  <scope>test</scope>
</dependency>
 
<dependency>
  <groupId>com.atlassian.jira</groupId>
  <artifactId>atlassian-jira-pageobjects</artifactId>
  <version>${jira.version}</version>
  <scope>test</scope>
  <exclusions>
    <!-- excluded due to clash with other SLF implementation -->
    <exclusion>
      <artifactId>slf4j-simple</artifactId>
      <groupId>org.slf4j</groupId>
    </exclusion>
  </exclusions>
</dependency>

Beim Versuch, Seleniumtests auf einem System mit einem 64-Bit Linux, z.B. einem CI Server in einer AWS EC2 Instanz, auszuführen, wird man jedoch Probleme bekommen. Der Grund dafür ist, dass das SDK seine eigenen Browser mitbringt, unter anderem einen Firefox 12. Dieser hat jedoch ein bekanntes Problem auf 64-Bit Linux Systemen. Die Lösung besteht darin, explizit eine neuere Version von Selenium inklusive der zugehörigen Atlassian Browser als Dependency zu benutzen:

<!-- the following dependencies are needed only for running on 64bit Linux, 
     since the default Firefox 12 has problems -->
<dependency>
  <groupId>com.atlassian.browsers</groupId>
  <artifactId>atlassian-browsers-auto</artifactId>
  <version>2.3.2</version>
  <scope>test</scope>
</dependency>
 
<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-java</artifactId>
  <version>2.25.0</version>
  <scope>test</scope>
</dependency>

Der letzte Schritt bei der Vorbereitung der Projekts besteht darin, das TestKit Plugin in der JIRA-Testinstanz zu aktivieren. Dies kann man entweder durch eine Property in der POM oder durch Hinzufügen des Plugins in der Konfiguration des JIRA Builds erreichen.

  • Als Property:
<prroperties>
  ...
  <plugins>com.atlassian.jira.tests:jira-testkit-plugin:${testkit.version}</plugins>
  ...
</properties>
  • Als Plugin Artefakt in der AMPS Plugin Konfiguration:
<plugin>
  <groupId>com.atlassian.maven.plugins</groupId>
  <artifactId>maven-jira-plugin</artifactId>
  <version>${amps.version}</version>
  <extensions>true</extensions>
  <configuration>
    ...
    <pluginArtifacts>
      ...
      <pluginArtifact>
        <groupId>com.atlassian.jira.tests</groupId>
        <artifactId>jira-testkit-plugin</artifactId>
        <version>${testkit.version}</version>
      </pluginArtifact>
    </pluginArtifacts>
  </configuration>
</plugin>

Tests schreiben

Das Artefakt für die JIRA Pageobjects stellt verschiedene Mittel bereit, die eine effektive Implementierung von UI Tests unterstützen. Zunächst stellt es eine abstrakte Klasse (AbstractJiraPage) für alle (eigenen) Pageobjects bereit, die ein Grundgerüst für die Implementierung bietet. Wenn man die Klasse erweitert, müssen die Methoden getUrl() und isAt() implementiert werden: getUrl() liefert die URL zurück, zu der navigiert werden muss, um die Seite zu laden, die durch das Pageobject repräsentiert wird; isAt() prüft, ob die Seite auch korrekt geladen ist (bspw. durch Prüfung, dass ein bekanntes Element sichtbar ist). Dabei wird grundsätzlich angenommen, dass ein Element nicht unbedingt sofort verfügbar ist. Zusätzlich stellt die abstrakte Klasse eine PageBinder-Instanz bereit, die es ermöglicht, die aktuell geladene Seite an ein Pageobject zu binden, inklusive der auf der Seite enthaltenen Elemente. Ein Beispiel für ein Pageobject kann also folgendermaßen aussehen:

package pages;
 
import com.atlassian.jira.pageobjects.pages.AbstractJiraPage;
import com.atlassian.pageobjects.elements.ElementBy;
import com.atlassian.pageobjects.elements.PageElement;
import com.atlassian.pageobjects.elements.query.TimedCondition;
 
public class FooBarPage extends AbstractJiraPage {
  @ElementBy(id ="save") private PageElement saveButton;
  @ElementBy(id ="some-input") private PageElement someInput; 
 
  @Override
  public String getUrl() {
    return"/secure/admin/foo-bar.jspa";
  }
 
  @Override
  public TimedCondition isAt() {
    return someInput.timed().isVisible();
  }
 
  public FooBarPage save() {
    saveButton.click();
    return pageBinder.bind(FooBarPage.class);
  }
 
  public void setSomeInput(String input) {
    someInput.type(input);
  }
 
  public String getSomeInput() {
    return someInput.getValue();
  }
}

Die eigentlichen UI Tests müssen in einem Package mit Präfix it.* liegen, da sie als Integrationstests eine laufende JIRA Instanz benötigen. Ein Beispiel für einen Test, der FuncTest benutzt, sieht folgendermaßen aus:

package it.foo.bar;
 
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import pages.FooBarPage;
import com.atlassian.jira.functest.framework.FuncTestCase;
import com.atlassian.jira.pageobjects.JiraTestedProduct;
import com.atlassian.jira.pageobjects.config.EnvironmentBasedProductInstance;
import com.atlassian.jira.testkit.client.Backdoor;
import com.atlassian.jira.testkit.client.util.TestKitLocalEnvironmentData;
 
public class FooBarPageTest extends FuncTestCase {
  // the setupUpTest() method sets this
  private JiraTestedProduct jira;
 
  @Override
  protected void setUpTest() {
    super.setUpTest();
    Backdoor backdoor = new Backdoor(new TestKitLocalEnvironmentData());
    backdoor.restoreBlankInstance();
    jira = new JiraTestedProduct(new EnvironmentBasedProductInstance());
  }
 
  @Test
  public void test_that_save_works() {
    FooBarPage page = jira.gotoLoginPage().loginAsSysAdmin(FooBarPage.class);
 
    page.setSomeInput("my input");
    page.save();
 
    jira.gotoHomePage();
    page = jira.goTo(FooBarPage.class)
    assertThat(page.getSomeInput(),is("my input"));
  }
}

Tests ausführen

Frontend Tests werden ganz normal als Integrationstests betrachtet und ausgeführt. Wenn man jedoch wie im obigen Beispiel FuncTest benutzt, muss man mit einer kleinen Überraschung rechnen: die Tests scheitern, wenn man nicht ein (leeres) Verzeichnis src/test/xml im Projekt angelegt hat. Eine Alternative (die wir auch empfehlen), ist auf die Verwendung von FuncTest zu verzichten. Der Test erweitert dann keine Klasse mehr (sieht man von der impliziten Vererbung von java.lang.Object ab) und die Methode setUpTest aus dem Beispiel ist folgendermaßen umzuschreiben:

@Before
public void setUp() {
  jira = TestedProductFactory.create(JiraTestedProduct.class);
  Backdoor backdoor = new Backdoor(
    new ProductInstanceBasedEnvironmentData(jira.getProductInstance()));
  backdoor.restoreBlankInstance();
}

REST-API Tests

Auch wenn UI Tests sowohl den Java-Code des Servers als auch den Javascript (und HTML) Code auf dem Client testet, sind sie für ihren hohen Implementierungs- und Wartungsaufwand und die lange Ausführungsdauer (im Vergleich zu anderen Testarten) bekannt. Eine Alternative für den Test der Serverseite stellen Tests der vom Server bereitgestellten API dar. Im Fall von JIRA ist das eine REST-API. Wie sich herausstellt, gibt es bei der Implementierung von REST-API Tests für JIRA keine großen Besonderheiten zu beachten. Da es sich ebenfalls um Integrationstests handelt, müssen sie wie UI Tests in einem Package mit Präfix it.* liegen. Das Framework für die Entwicklung der Tests kann frei gewählt werden. Aus unserer Erfahrung können wir den Einsatz von REST Assured empfehlen. Danach gibt es nur zwei Dinge, die zu erwähnen sind:

  1. Wird der Test im Rahmen des Maven-Builds ausgeführt, wird durch das SDK eine System-Property “baseurl” gesetzt, die auf die laufende Testinstanz verweist. Startet man den Test jedoch aus der IDE, ist die Property nicht gesetzt. Als Fallback sollte man sie daher im Test selbst setzen, bspw. auf “http://localhost:2990/jira”.
  2. Die Authentifizierungsmethode sollte auf präemptiv gesetzt werden, da JIRA statt Statuscode 401 (Unauthorized) den Code 200 (Ok) zurücksendet, auch wenn eine Authentifizierung benötigt wird. Aus diesem Grund kann die automatische Authentifizierung im Fehlerfall, wie sie üblich ist, nicht verwendet werden.

Ein Teil eines Testsetups könnte daher folgendermaßen aussehen:

  String urlPrefix = System.getProperty("baseurl", "http://localhost:2990/jira");
  RestAssured.baseURI = urlPrefix + urlSuffix;
 
  PreemptiveBasicAuthScheme authScheme = new PreemptiveBasicAuthScheme();
  authScheme.setUserName(username);
  authScheme.setPassword(password);
  RestAssured.authentication = authScheme;

Zusammenfassung

Die Implementierung von seleniumbasierten Frontendtests benötigt nur wenige spezifische Anpassungen an JIRA und auch die lokale Ausführung der Tests ist einfach. Das Ganze sieht etwas anders aus, wenn man die Tests auf einem CI Server ausführen möchte. Tests der REST-API sind im Gegensatz dazu weniger problematisch, sind einfacher zu implementieren und laufen auch schneller. Wir empfehlen sie daher als zweite Testart nach Unittests. Hat das Projekt einen große Menge an eigenem Javascript oder muss eine breites Spektrum an Browsern oder Betriebssystemen zuverlässig bedient werden, lohnt sich evtl. auch die Investition in die Entwicklung von Oberflächentests.

Im nächsten Artikel dieser Serie werfen wir einen Blick auf die Besonderheiten, die bei der Auführung von Tests in einem CI Server eine Rolle spielen.

The post Agiles Testen von JIRA Plugins (Teil 3): Systemtests appeared first on codecentric Blog.

Agiles Projektmanagement – Ein Antagonismus?

$
0
0

Wohin ich auch sehe: ich bekomme den Eindruck, dass nahezu alle Projekte agil durchgeführt werden. Insbesondere große Organisationen wenden nun auch agile Vorgehensweisen (i.d.R. Scrum) an.
 
Dadurch entstehen zahlreiche Diskussionen, wie man das klassische Projektmanagement mit agilen Vorgehensweisen verbinden kann oder ob dies überhaupt möglich ist. Große Organisationen mit einem meist höheren Bedarf an Formalismen müssen nach wie vor gewisse Unternehmensstandards erfüllen, auch wenn diese agile Methoden für Projekte oder Produktentwicklungen einsetzen. Die Erfüllung dieser Anforderungen an die IT-Governance wurden „früher“ durch die sogenannten IT-Projektleiter bzw. IT-Projektmanager sichergestellt. Wo ist nun der Platz dieser Mitarbeiter in der agilen Welt und wie werden diese Anforderungen erfüllt? Wie kann ein agiles Projektmanagement aussehen und kann es so etwas überhaupt geben?
 
Zu Beginn eine kurze Begriffsklärung: Was bedeutet eigentlich das Wort „Manager“?
 

„Aus www.vocabulary.com:
The probable origin of the word manager comes from the Latin manus, meaning “hand.” A good manager provides the necessary “hand,” guiding others.
The Italian maneggiare means “to control,” and was especially used with reference to training horses, a job for which certain managers you’ve worked for might be better suited.“

Nun kann jeder selbst entscheiden, ob der lateinische Ursprung oder der aus dem Italienischen passender und für alle Beteiligten angenehmer ist. Ich wähle einmal den Ersteren …

Das „klassische“ Projektmanagement

Die größten Organisationen für Projektmanagement (IPMA/GPM: International Project Management Association/Deutsche Gesellschaft für Projektmanagement und PMI: Project Management Institute) sehen für einen Projektmanager beispielsweise folgende Aufgabengebiete vor:
 

Zielplanung Stakeholderanalyse
Umfeldanalyse Risikomanagement
Ablaufplanung (Netzplan, Balkenplan) Terminplanung
Konfigurations- und Änderungsmanagement Mitarbeitereinsatzplanung
Einsatzmittelplanung Kostenplanung
Dokumentationsmanagement Änderungsmanagement
Qualitätsmanagement Projektcontrolling / Projektsteuerung

 
Auch wenn diese Aufstellung für kleinere Vorhaben auf den ersten Blick sehr umfangreich erscheint; die darin enthaltenen Aufgaben müssen bei jeder Art von Projekten in einer gewissen (und zwar in einer angemessenen) Art und Weise erledigt werden. Vorgehensmodelle für die Projektdurchführung wie das V-Modell XT oder der Rational Unified Process adressieren diese Anforderungen. Dazu passend gibt es beispielsweise beim V-Modell XT eine Softwareunterstützung, die eine komplette Projektstruktur inklusive Meilensteinplan und zu erstellenden Artefakten auf Knopfdruck erzeugt. Sehr leicht bedienbar und übersichtlich; schon hat man einen kompletten Meilensteinplan und diesen sogar in MSProject importierbar … !
 
V-Modell XT-Projektassistent-Bild_1
 
Die Gefahr liegt meines Erachtens nun darin, dass kein Hinterfragen auf die Sinnhaftigkeit der Aufgaben im konkreten Projektzusammenhang erfolgt. Es werden dann Dinge erledigt und Dokumente oder andere Artefakte erzeugt, die in diesem Umfang und in dem Projektkontext gar nicht benötigt werden. Schnell wird der Projektmanager dabei zu einem Verwalter von Checklisten und befolgt gebetsmühlenartig die vorab festgelegten Pläne.
 
Dazu ein Erfahrungsbricht aus einem Festpreisprojekt:
 

„Unsere Firma hatte ein Projekt als Werkvertrag unter Verwendung des V-Modells XT durchgeführt. Der Go-Live-Termin, und damit die größte Abschlagszahlung, stand kurz bevor. Alle relevanten Tests und Vorbereitungen waren (mehr oder weniger gut) abgeschlossen. Zumindest so gut, dass wir nächste Woche den Rollout starten konnten.

Doch dann kam der Tag, an dem der Projektmanager des Kunden auf die Idee kam, einmal in das Projektmodell des V-Modells hinein zu schauen um festzustellen, dass eine Vielzahl von Dokumenten von unseren Leuten gar nicht erstellt wurden. Diese wurden nach Meinung der Projektteams auch gar nicht benötigt. Geschrieben wurden diese dann doch noch, und zwar in zahlreichen Nachtschichten, denn das Modell sah dies ja nun mal vor. Reingesehen hat in die Dokumente später niemand mehr.“

 
Abgesehen davon, dass es nicht besonders sinnvoll ist, ohne Reflexion über die aktuellen Gegebenheiten auf die strikte Einhaltung von Verträgen zu pochen (s.a. 3. Wertepaar des agilen Manifests) neigen Projektmanager (und natürlich auch andere Beteiligte) dann dazu, komplexe Problemstellungen immer mit derselben Herangehensweise zu lösen, nämlich so wie es das Modell will. Dies kann nicht funktionieren, denn bei komplexen Problemen müssen emergente Strategien zu deren Lösung angewandt werden. Dies wird beispielsweise von Dave Snowden mit seinem Cynefin-Framework oder auch Ralph Stacey in seinem Modell erläutert.
 

Und Agile?

Bei verhältnismäßig einfachen und kleinen Projekten mit entsprechend kleinen und lokalen „On-Site“-Teams sind agile Methoden noch einfach anwendbar. Die Wege sind kurz, die Anzahl der Kommunikationskanäle gering und ein regelmäßiger Austausch der Projektteilnehmer ist leicht möglich.
 
Doch nun sollen auch Projekte mit verteilten Teams und Hunderten von Projektteilnehmern agil durchgeführt werden. Damit stößt so manche Projektorganisation an ihre Grenzen, denn die strikte Anwendung des Scrum-Guide (als Beispiel des bekanntesten agilen Vorgehensmodells) reicht dann u.U. nicht mehr aus. Hier gibt es erst einmal nur die drei Rollen Product Owner, Scrum Master und Entwicklungsteam.
 
Siehe dazu auch ein Interview mit Alistair Cockburn vom Juli 2014: “Interview mit Dr. Cockburn”
 
Fragt man einen Scrum-Evangelisten darüber, wer denn künftig die Projektmanagementaufgaben wahrnehmen soll, zaubert man entweder Fragezeichen in das Gesicht des Gegenüber oder erhält so eine oder ähnliche Antwort:
 
„Die operative Projektplanung liegt bei dem Entwicklungsteam während die strategische Projektplanung durch den Product Owner (PO) durchgeführt wird.“
 
Dabei stellt sich dann die Frage, welche der über ein Dutzend oben genannter Aufgabenfelder der operativen, und welche der strategischen Planung zuzuordnen sind, und wer überhaupt die Ausbildung und Erfahrung hat, diese Aufgaben zu erfüllen. Und natürlich wo genau im Scrum Guide eigentlich steht, dass dies gemacht werden muss … Das Entwicklungsteam sollte doch eigentlich Code produzieren; der PO hat sich um die Produktvision und den ROI der beauftragten Softwareartefakte zu kümmern … keine Zeit für die anderen Dinge …
 
Das Problem hierbei: Wichtige Tätigkeiten werden weggelassen und führen insbesondere bei großen Vorhaben zu vielfältigen Problemen. Agile Vorgehensweisen kommen dadurch in Verruf; wer hat nicht schon einmal das Vorurteil gehört: „Agile Projekte? Ach ja, das sind die Projekte in denen nichts mehr dokumentiert wird … .“
 
Doch auch bei der Anwendung von agilen Vorgehensweisen müssen alle Beteiligten genauso die Sinnhaftigkeit bzgl. der Abbildung von Projektmanagementaufgaben hinterfragen wie bei den bisherigen Methoden.
 
Dabei sieht Scrum diesen Inspect and Adapt-Zyklus sogar zwingend vor! Leider habe ich aber die Erfahrung gemacht, dass dieser in den Scrum-Teams „stecken bleibt“ und nicht auf den weiteren Ebenen der Organisation angewendet wird. Eine regelmäßige Retrospektive von Abteilungsleitern bis C-Level (je nach Projektgröße) könnte da sicherlich wahre Wunder bewirken.

Wieder mehr Formalismus?

Viele Organisationen haben keine guten Erfahrungen mit der Anwendung agiler Vorgehensweisen gemacht und sind auf der Suche nach Modellen, die den Bedarf an mehr Formalismus unter Beibehaltung einer gewissen „Agilität“ bedient.
Und so kommen wir zu eher strikten Modellen wie beispielsweise dem Scaled Agile Framework (SAFe). Und auch hier sehe ich genauso wie bei dem zuvor gezeigten V-Modell XT die Gefahr, dass ohne Nachzudenken Tätigkeiten durchgeführt und Artefakte erzeugt werden, nur weil es im Modell so gefordert wird.

Und nun?

Während das strikte unreflektierte Befolgen von vorab festgelegten Anweisungen in der Vergangenheit oft nicht von Erfolg gekrönt war, ist es ebenso gefährlich sämtliche Ideen der letzten Jahrzehnte zum (IT-)Projektmanagement mit der Begründung über Bord zu werfen, dass man nun agil sei. Besonders gefährlich wird es meines Erachtens, wenn Agilisten oder agile Coaches ohne Erfahrung in der Leitung von IT-Projekten versuchen, große Projekte agil durchzuführen.
 
Denn ohne langjährige Praxiserfahrung kann, beispielsweise in einem Scrum-Projekt, nichts anderes getan werden, als die Vorgaben des Scrum Guide eins zu eins umzusetzen („Ein Standup darf genau 15 Minuten dauern!“ :-)). Und da sind wir dann wieder bei derselben Gebetsmühle wie der Projektleiter zuvor mit seinen durch das V-Modell XT vorgegebenen Tätigkeiten.
 
gebetsmühle_1828838009_36cd6dc6f8_z

Agiles Projektmanagement ist kein Solospiel mehr

Die Aufgaben des Projektmanagements fallen nicht einfach weg, nur weil man plötzlich agil ist. Stattdessen ist es wichtig, dass die Dinge zur richtigen Zeit an die richtigen Personen adressiert werden. Dazu braucht es vor allem viel Erfahrung und gute Teammitglieder die bereit sind, ihren Beitrag zu einem Projekt nicht nur auf ein vorab genau beschriebenes Aufgabengebiet zu beschränken, sondern sich zu allen Problemstellungen die auf dem Weg auftreten, einzubringen und mitzumachen.
 
Jeder Projektbeteiligte kann und muss künftig seinen Beitrag dazu leisten, sei es nun für eine Stakeholderanalyse, einer Risikobetrachtung und so weiter. Wer diese Themen zur Sprache bringt ist dabei egal, es muss nur sichergestellt sein, dass es passiert!
 
Ich bin der Meinung, dass ein ehemaliger Projektleiter/-manager aufgrund seiner Ausbildung und Erfahrung dafür gut geeignet ist. Wie diese Rolle dabei künftig genannt wird, sei dann der Phantasie des Unternehmens überlassen. Denn gerade in großen Organisationen reicht es nicht mehr aus, alle Aufgaben beim Product Owner abzuladen. Voraussetzung ist dabei natürlich, dass der ehemalige Projektleiter/-manager die Werte und Prinzipien agiler Vorgehensweisen verinnerlicht hat.
 
Dabei fällt mir auch gleich der erste Satz des agilen Manifests ein:
 

„We are uncovering better ways of developing
software by doing it and helping others do it.“

Dies passt dann auch wieder gut zum (lateinischen) Ursprung des Wortes „Manager“!
 
Wie ist Eure Erfahrung mit dem „agilen Projektmanagement“ insbesondere bei großen Projekten?
 
Falls jemand auf der Manage Agile ist: Ich freue mich auf einen Besuch bei meinem Talk zu dem Thema!

The post Agiles Projektmanagement – Ein Antagonismus? appeared first on codecentric Blog.

Agiles Testen von JIRA Plugins (Teil 4): CI Server Integration und Code Coverage

$
0
0

In den letzten drei Artikeln der Serie haben wir – das sind Raimar Falke und ich – uns auf das Schreiben von verschiedenen Arten von Tests konzentriert und dabei auch gezeigt, wie man sie ausführt. Tests in der lokalen Entwicklungsumgebung auszuführen ist aber nur der erste Schritt. Der wichtigere besteht darin, sie automatisch und regelmäßig in einem Continuous Integration (CI) Server laufen zu lassen. Dieser Artikel beschäftigt sich nun mit der Frage, was dabei zu beachten ist.

CI Server und das Atlassian SDK

Es gibt eine Vielzahl von CI Servern, aus denen man wählen kann. Zwei Berichten zufolge sind Jenkins (+Hudson), Bamboo und TeamCity die populärsten darunter. Während Jenkins und Hudson Open Source sind, sind Bamboo und TeamCity kommerzielle Produkte. Allen gemeinsam ist, dass sie Webapplikationen sind, die man selbst betreiben kann. Es existieren jedoch auch zahlreiche Unterschiede, beispielsweise bei den unterstützten SCM- und Buildsystemen. Große Unterschiede liegen auch in der Benutzeroberfläche.

Da bei JIRA Maven als Buildsystem zum Einsatz kommt, ist die Unterstützung von Maven die wichtigste Anforderung an den CI Server. Glücklicherweise ist das bei allen vier betrachteten Produkten der Fall.

Das Atlassian SDK in den 4.* Versionen benutzt allerdings Maven 2.1. Diese Version ist stark veraltet und einige der von uns genutzten Build-Plugins benötigen eine neuere Maven Version. Der Einsatz einer neueren Version ist zum Glück möglich (wir hatten das im ersten Artikel geschildert), aber nicht ganz einfach. Mittlerweile hat Atlassian jedoch die Version 5 des SDK veröffentlicht (im Juli 2014), die mit Maven in der Version 3.2.1 ausgeliefert wird. Dies vereinfacht die Einrichtung des Projektes im CI Server dramatisch, trotzdem bleibt die Konfiguration von Maven die größte Aufgabe.

Bamboo

Bei Bamboo gibt es verschiedene Wege, Maven für ein JIRA Projekt einzurichten:

  1. Man erstellt eine Konfiguration für ein Maven-Executable und gibt den Pfad auf die dem SDK beiliegende Maven-Installation an (z.B. …/atlassian-plugin-sdk-5.0.3/apache-maven-3.2.1). Zusätzlich ist es notwendig, die Umgebungsvariable ATLAS_HOME an die Build-Task Konfiguration zu übergeben und auf das Atlassian SDK (…/atlassian-plugin-sdk-5.0.3/) zeigen zu lassen.
  2. Da Bamboo das mvn Executable ausführt, welches selbst nur ein Shell-Skript ist, ist es auch möglich, das Skript anzupassen, sodass die Umgebungsvariable dort gesetzt wird, indem man die Zeile “export ATLAS_HOME=…/atlassian-plugin-sdk-5.0.3/” einfügt. Damit entfällt das Setzen der Umgebungsvariable in der Build-Task in der vorigen Variante.
  3. Es ist außerdem möglich, das vom SDK gelieferte atlas-mvn als mvn Executable zu verwenden. Dazu muss ein Verzeichnis erstellt werden (z.B. …/wrapper/), welches ein Verzeichnis bin erhält, in dem ein symbolischer Link namens mvn erzeugt wird, der auf das atlas-mvn Kommando verweist, z.B. …/atlassian-plugin-sdk-5.0.3/bin/atlas-mvn. In Bamboo muss dann ein Maven-Executable erstellt werden, dass auf den neuen Pfad (…/wrapper) verweist.

Bamboo

Jenkins

Jenkins benutzt nicht das mvn Executable, um den Maven Build auszuführen. Daher ist von den bei Bamboo vorgestellten Varianten nur die erste umsetzbar. Dazu muss zunächst die Umgebungsvariable ATLAS_HOME in der globalen Konfiguration mit dem Wert …/atlassian-plugin-sdk-5.0.3/ eingetragen werden. Zusätzlich muss eine Maven Installation konfiguriert werden, deren MAVEN_HOME auf das Verzeichnis …/atlassian-plugin-sdk-5.0.3/apache-maven-3.2.1/ verweist. Leider ist es nicht möglich, das EnvInject Plugin zu nutzen, um die global definierte Variable ATLAS_HOME in die einzelnen Builds zu übernehmen (siehe auch https://issues.jenkins-ci.org/browse/JENKINS-17620 bzw. https://issues.jenkins-ci.org/browse/JENKINS-18234).

Jenkins

TeamCity

TeamCity benutzt ebenso wie Jenkins nicht das mvn Executable. Die Umgebungsvariable ATLAS_HOME kann entweder auf Projekt- oder Buildebene konfiguriert werden. Im Maven Buildschritt muss die “Custom” Maven Option gewählt werden und der Pfad …/atlassian-plugin-sdk-5.0.3 übergeben werden.

teamcity

Eine bessere Lösung?!

Es gibt verschiedene weitere Lösungen, wie man Maven und das Atlassian SDK in einem CI Server zusammenbringen kann. Dies sind:

  1. Die Umgebungsvariable ATLAS_HOME kann vor dem Start des CI Servers gesetzt werden. Dies hat den Nachteil, dass einige zusätzliche Schritte notwendig sind, wenn man eine andere Version des SDK im gleichen CI Server benutzen will (Stop/Anpassen/Start), d.h. es ist nicht mehr einfach möglich, den gleichen Test mit verschiedenen SDK Versionen laufen zu lassen.
  2. Die Umgebungsvariable ATLAS_HOME ist im Prinzip nur notwendig, um in den mitgelieferten Maven Einstellungen (…/atlassian-plugin-sdk-5.0.3/apache-maven-3.2.1/conf/settings.xml) die Referenz auf das mitgebrachte Repository (…/atlassian-plugin-sdk-5.0.3/repository/) aufzulösen. Eine Möglichkeit wäre daher, die Referenz in den Einstellungen explizit aufzulösen. Danach wird die Variable nicht mehr benötigt.

Allgemein empfehlen wir die zweite Variante. Am sichersten ist es dabei, eine Kopie des SDK anzulegen, in dem man die Variable expandiert. Auf diese Weise hat man das “Original” immer noch zur Hand, wenn man auf Probleme stößt.

Sonst noch was?

Ja, leider gibt es noch einige weitere Punkte, die man berücksichtigen sollte.

Schwache CI Server

Auf einer Maschine, die erheblich weniger Rechenleistung hat als eine übliche Developer-Workstation (bspw. eine AWS Instanz), kann es sein, dass der Start von JIRA (für die Integrationstests) zu lange dauert und das System in einen Timeout läuft. Hier hilft es, den Wert der Einstellung atlassian.plugins.enable.wait hochzusetzen:

<plugin>
  <groupId>com.atlassian.maven.plugins</groupId>
  <artifactId>maven-jira-plugin</artifactId>
  <version>${amps.version}</version>
  <extensions>true</extensions>
  <configuration>
    <jvmArgs>-Datlassian.plugins.enable.wait=1000</jvmArgs></configuration></plugin>

Hinweis: Diese Einstellung führt zu Warnungen im Log, die darauf hinweisen, dass die Plugins nicht mit einem derartigen Timeout konfiguriert wurden. Diese Warnungen können natürlich ignoriert werden, da die Einstellung nur im Rahmen der Integrationstests und nicht im ausgelieferten Plugin gesetzt ist.

Ausführen von WebUI Tests

Die Integration von WebUI Tests in einem CI Server ist aufwändiger als bei anderen Testtypen. Das liegt vor allem daran, dass durch bzw. für den Test zusätzlich ein Browser gestartet und gesteuert werden muss. Und auf einem CI Server, der unter Linux läuft, bedeutet das, es muss ein X11 Server laufen. Da Linux Server normalerweise headless (also ohne GUI) laufen, wird üblicherweise ein virtuelles Ausgabegerät (virtual framebuffer, Xvfb) benutzt.

Obwohl AMPS die Option anbietet, den Xvfb für WebUI Tests automatisch zu starten, ist es uns nicht gelungen, dies auf unserem CI Server zum Laufen zu bringen. Die Alternative, die man hier wählen kann, besteht darin, Xvfb vorher zu starten (z.B. beim Systemstart im Rahmen eines Startskriptes) und beim Test zu benutzen. Für die Tests sollte dann auch die Umgebungsvariable DISPLAY gesetzt werden, bspw. auf “:1.0”.

Und was ist mit Code Coverage?

Wir benutzen Sonar als zentrales Dashboard für die Qualität des Quellcodes. Besonders, wenn man Legacy Code übernommen hat, ist es wichtig zu wissen, welche Klassen eigentlich wie gut getestet sind. Code Coverage kann hier als ein Indikator dienen. Trotzdem ist es natürlich auch wichtig sich die Tests anzuschauen, bspw. ob die vorgenommenen Prüfungen auch die funktionalen Anforderungen abbilden.

Im SDK wird bereits Clover, ein kommerzielles Code Coverage Tool von Atlassian, mitgeliefert. Als Ausgangspunkt für die eigene Arbeit kann das Kommanso atlas-clover dienen, welches von der Kommandozeile aus gestartet werden kann. Es instrumentiert zunächst den Quellcode des Plugins, führt Unit- und Integrationstests aus und erzeugt einen kurzen Überblick sowie einen HTML-Bericht in target/site/clover. Dazu benutzt es normale Maven Kommandos sowie zwei zusätzliche Clover spezifische Goals vor bzw. nach der Testausführung: clover2:setup und clover2:clover. Sonar selbst benutzt ebenfalls zwei Schritte für die Ausführung, was sehr gut passt. Am Ende haben wir zwei Builds im CI Server definiert, die nacheinander ausgeführt werden:

clean clover2:setup verify

und

clover2:clover sonar:sonar

Dadurch ist es möglich, die Code Coverage sowohl von Unit- als auch Integrationstests zu ermitteln. Andere Tools, wie bspw. JaCoCo und Cobertura liefern ebenfalls die Coverage von Unittests, scheiterten jedoch bei unseren Bemühungen, die Code Coverage der Integrationstests ebenfalls zu ermitteln.

Zusammenfassung

Wie man sieht, schreiben wir gern Tests und wir betrachten (automatisierte) Tests als wichtigen Bestandteil der Softwareentwicklung. Wir haben aber auch festgestellt, dass das Testen von JIRA Plugins manchmal umständlicher oder komplizierter ist, als es sein sollte. Ausgestattet mit den Informationen und Hinweisen aus diesen Artikeln gibt es eigentlich keine Ausrede mehr keinen CI Server für den Test eines JIRA Plugins einzusetzen.

Da wir aktuell keine weiteren offenen Themen bzgl. des Testens von JIRA Plugins haben, schließen wir mit diesem Artikel unsere Serie ab.

Wir hoffen, wir konnten helfen und sind bei Fragen und Problemen gern da. Über Anregungen und Ergänzungen würden wir uns ebenso freuen.

The post Agiles Testen von JIRA Plugins (Teil 4): CI Server Integration und Code Coverage appeared first on codecentric Blog.

Docker basiertes “Runtime Environment for Developers”

$
0
0

Verteilte, skalierbare, cloudfähige Anwendungen sind die Zukunft der Softwareentwicklung. Moderne Softwareprojekte basieren auf einer Vielzahl von Komponenten, um die fachliche Funktionalität schnell zu implementieren. Dies sind zum Beispiel verschiedene Datenbank- sowie Messaging-Systeme, Suchmaschinen und vieles mehr. Darüber hinaus werden Anwendung zunehmend verteilt betrieben, um Anforderungen an Antwortzeiten, Skalierbarkeit und Ausfallsicherheit gerecht zu werden. Dies stellt Softwareentwickler vor die Herausforderung, alle benötigten Komponenten auf ihrem Entwicklungssystem installieren und konfigurieren zu müssen, um so stets eine aktuelle und produktionsnahe Entwicklungsumgebung zu nutzen zu können. Eine ähnliche Herausforderung stellt sich dem Betriebsteam für die Pflege der Produktionsumgebung.

Für CenterDevice haben wir dazu eine Docker basierte Entwicklungsumgebung geschaffen, die den Entwicklern diese Arbeit abnimmt. In diesem Artikel stelle ich diese Entwicklungsumgebung vor.

Docker wurde bereits in den Artikeln 1, 2, 3, 4 und 5 vorgestellt. Der wesentliche Vorteil von Docker ist, dass Docker Images eigenständige Laufzeitumgebungen darstellen, die sowohl von Entwicklern als auch vom Betrieb in der Produktion eingesetzt werden können. Mein Kollege Alexander Berresch und ich haben uns diese Eigenschaft von Docker zunutze gemacht und eine Entwicklungsumgebung für die CenterDevice geschaffen, die vollständig auf Docker Images basiert.

Wir nennen diese Entwicklungsumgebung Runtime Environment for Development (RED) und setzten sie seit einem Jahr erfolgreich bei der Entwicklung von CenterDevice ein.

RED bei CenterDevice

Der Artikel CenterDevice Cloud Architecture gibt einen Überblick über die Softwarearchitektur von CenterDevice und stellt die externen Komponenten wie MongoDB, RabbitMQ, ElasticSearch und Tomcat vor. Diese externen Komponenten werden in RED als Docker Images zentral gepflegt. Damit müssen unsere Entwickler für die täglich Arbeit lediglich aktualisierte Docker Images aus unserer zentralen private Docker Registry (siehe auch 3 und docker-registry) laden und können arbeiten, ohne zeitaufwendig ihre Entwicklungsumgebung zu pflegen.

Die eigenen Software Komponenten werden ebenfalls als Docker Images verpackt und anschließen als Container in RED gestartet. Es ist aber auch möglich, Komponenten in einem hybriden Modus zu starten, sodass die gerade zu entwickelnden Komponenten in der IDE und alle externen Komponenten in Docker Containern laufen.

Durch die Containerisierung aller Komponenten lässt sich eine produktionsnahe Entwicklungsumgebung schaffen, die Sharding und Replication von Datenbanken beinhaltet und in der Produktion eingesetzt werden kann. Des Weiteren bietet dieser Ansatz den Vorteil, dass neue Teammitglieder schnell eine vollständige Entwicklungsumgebung auf ihren Rechnern aufsetzen und somit schneller produktiv arbeiten können.

Technische Umsetzung

RED wurde speziell für CenterDevice von uns entwickelt. Die Prinzipien und die grundlegende technische Umsetzung können jedoch verallgemeinert und auf beliebige Projekte angewendet werden. Die Grundlagen für RED sind VirtualBox, Vagrant und Docker.

VirtualBox wird zur Virtualisierung genutzt, sodass RED betriebssystemunabhängig auf allen gängigen Betriebsystemen von Entwicklern eingesetzt werden kann. Vargant automatisiert den Umgang mit VirtualBox, sodass die Virtualisierung “head less” auf den Entwicklersystemen laufen kann. Docker erlaubt ein einfaches Deployment von Abhängigkeiten in Form von externen Komponenten sowie die Bündlung von Artefakten und Konfigurationen — siehe Abbildung 1.

7734A6C5-1684-4AD9-B775-11BAC4556A8F

Abbildung 1 zeigt eine Übersicht über die in RED eingesetzten Technologien.

Zukunft

Zur Zeit werden die Docker Images noch von den CenterDevice Entwicklern selbst gebaut und in unsere private Docker Registry geladen. In Zukunft möchten wir diesen Schritt in unsere Continuous Integration Pipeline einbauen und von Jenkins automatisch erledigen lassen. So können wir unsere Integrationstest ebenfalls auf Docker Images umstellen und damit eine bessere Isolation der Tests ermöglichen.

Es gibt noch mehr

Alexander Berresch wird in einem weiteren Artikel nächste Woche die technische Umsetzung genauer beschreiben und dazu ein kleines Beispiel auf GitHub veröffentlichen, so dass Ihr selbst ein RED für Eure eigenen Projekte aufsetzen könnt. Also bleibt dran und meldet Euch bei uns, falls Ihr Fragen oder Anregungen habt.

The post Docker basiertes “Runtime Environment for Developers” appeared first on codecentric Blog.

Viewing all 129 articles
Browse latest View live