<![CDATA[Marcelo Emmerich - ]]>http://localhost:2368/Ghost 0.11Tue, 10 Oct 2017 14:25:10 GMT60<![CDATA[Ist Blockchain "the next big thing"?]]>Nein ist sie nicht. Denn sie ist nicht "next", sondern schon mitten unter uns! Und damit meine ich nicht die langweiligen Use-Cases der Bezahlung mit Bitcoin in Online-Shops, sondern die Use-Cases, bei denen die wichtigsten Aspekte der Blockchain-Technologie (Dezentralisierung und Transaktionsintegrität) zum Tragen kommen. Beispielsweise gibt es diverse Ansätze, Flüchtlinge,

]]>
http://localhost:2368/2017/10/10/ist-blockchain-the-next-big-thing/0d815e25-5f0a-499c-91b8-7931efec4200Tue, 10 Oct 2017 14:22:47 GMTNein ist sie nicht. Denn sie ist nicht "next", sondern schon mitten unter uns! Und damit meine ich nicht die langweiligen Use-Cases der Bezahlung mit Bitcoin in Online-Shops, sondern die Use-Cases, bei denen die wichtigsten Aspekte der Blockchain-Technologie (Dezentralisierung und Transaktionsintegrität) zum Tragen kommen. Beispielsweise gibt es diverse Ansätze, Flüchtlinge, die ohne Dokumente um Asyl bitten, mittels Blockchain-Technologie digitale Identitäten anzubieten. Andere Use-Cases gravitieren im Orbit dezentraler Börsen für alles mögliche (Strom zum Beispiel). Wer Google bemüht findet weitere Beispiele.

Aus diesem Grund haben wir uns frühzeitig mit der Blockchain beschäftigt und diese als Zukunftstechnologie identifiziert. Richtig interessant wurde das Thema für uns erst mit dem Erscheinen von Ethereum. Im Gegensatz zu Bitcoin und andere Kryptowährungen ist Ethereum eine Platform für verteile Anwendung auf der Basis von Blockchain-Technologie. Ethereum bietet Programmierschnittstellen, mit denen man auf die Blockchain zugreifen kann. Somit kann man Anwendungen entwickeln, die:

  • sehr hohe Transaktionssicherheit bieten
  • echt Server-less sind
  • immer und für immer laufen können
  • Verträge (smart contracts) implementiert, die eindeutig sind, automatisch ablaufen und fälschungssicher sind

Gehen wir die einzelnen Punkte im Detail durch:

Transaktionssicherheit

Die Transaktionssicherheit in der Blockchain basiert auf 3 Grundtechnologien:

  • Peer-to-peer Netzwerke
  • Starke Kryptographie
  • Redundanz

Peer-to-peer Netzwerke

Die Blockchain basiert auf einem Peer-to-Peer Netzwerk. In diesem Netzwerk kommunizieren sog. Knoten mit benachbarten Knoten. Somit kann ein Blockchain-Netz nicht abgeschaltet oder heruntergefahren werden. Dazu müsste man alle Knoten abschalten, was bei Millionen von Knoten überall auf der Welt nahezu unmöglich ist.

Starke Kryptographie

Divere Aspekte einer Blockchain basieren auf starke kryptographische Verfahren. Am wichtigsten für die Integrität der Blockchain sind Hashing Algorithmen. Die Blockchain, wie der Name schon sagt, ist im Grunde eine Kette von Blöcken. In dieser Kette sind alle Transaktionen gespeichert, die es jemals in der Blockchain gegeben hat. Immer wenn ein neuer Block dazukommt, werden Hashes aus den vorherigen Blöcken errechnet. Somit kann ein Block geprüft werden, indem alle Hashes vom ersten Block an (in Ethereum heiist dieser Block der Genesis-Block) bis zum aktuellen errechnet werden und mit dem des Blocks verglichen werden. Stimmen sie überein, ist der Block valide. Das Verfahren ist in der Praxis etwas komplexer und es gibt Unterschiede zwischen den verschiedenen Blockchain Netzen, das Grundprinzip ist aber immer gleich.

Redundanz

In Blockchain-Netze gibt es keine zentralen Server. Stattdessen gibt es die o.g. Knoten, die eine Kopie der gesamten Blockchain haben. Ja richtig, jeder Benutzer der Blockchain hat eine (mehr oder weniger aktuelle) Kopie der gesamten Blockchain. Somit ist es fast ausgeschlossen, dass ein Angreifer eine veränderte Kopie der Blockchain in Umlauf bringen kann, da es Millionen von Knoten mit "echteren" Versionen gibt, die die eines Angreifers verdrängen würden.
Aber diese Redundanz birgt auch den größten derzeitigen Nachteil der Blockchain-Technologie: Mangel an Skalierbarkeit. Wie oben beschrieben muss jeder Knoten die gesamte Blockchain verarbeiten.

Server-less

Wie oben beschrieben ist ein Blockchain-Netz ein Peer-to-Peer Netzwerk, das ohne zentralen Server auskommt. Damit werden, aus Sicht der Software-Entwicklung, echte Server-less Applikationen möglich. Der Code bzw. die Verträge werden Teil der Blockchain und sind irgandwann auf jedem Knoten repliziert worden.

Run always and forever

Wir haben oben gesehen dass man ein Blockchain-Netz so gut wie nicht ausschalten kann. Somit sind Anwendungen, die auf der Blockchain geschrieben wurden, immer da und laufen auch für immer. (Auch wenn das in der Praxis nur die halbe Wahrheit ist, aber mehr dazu in einem der folgenden Artikel)

Smart Contracts

Das Herzstück der Ethereum-Blockchain-Technologie, aus Entwickler-Sicht zumndest, sind die sog. Smart Contracts. Diese stellen, wie der Name schon sagt, Verträge dar, die als Code in der Blockchain hinterlegt werden. Ethereum Smart Contracts werden in einer JavaScript-ähnlichen Sprache, genannt Solidity entwickelt und können recht komplex werden.

Ausblick

Nach dieser kurzen Einführung werden wir weitere Artikel zu den einzelnen Themen veröffentlichen. Wir werden den Fokus auf die Entwicklung für und mit der Blockchain legen sowie adjazent gelagerte Themen wie die Entwicklung von sog. Oracles und wie man mit den inhärenten Skalierungsproblemen der Blockchain umgehen kann.

]]>
<![CDATA[Warum git-flow hakt]]>Git ist heutzutage als de-facto Standard für Source Code Management kaum noch wegzudenken. Es existieren exzellente Produkte, die die Arbeit mit git vereinfachen, allen voran Github, Bitbucket und Gitlab. Nun stellt git erst einmal "nur" das Werkzeug zur Verfügung. Um damit professionell zu arbeiten, benötigt man auch einen Prozess, der

]]>
http://localhost:2368/2017/06/16/untitled/e849435a-527c-4b40-9541-8cd94348e2c5Fri, 16 Jun 2017 09:07:44 GMTGit ist heutzutage als de-facto Standard für Source Code Management kaum noch wegzudenken. Es existieren exzellente Produkte, die die Arbeit mit git vereinfachen, allen voran Github, Bitbucket und Gitlab. Nun stellt git erst einmal "nur" das Werkzeug zur Verfügung. Um damit professionell zu arbeiten, benötigt man auch einen Prozess, der in die Entwicklung hineingreift und bis zum Continuous Integration und Continuous Deployment geht. Eines der bekanntesten git Workflows ist git-flow. Den Grundlegenden Ablauf von git-flow ist hier zu sehen: git-flow
Man kann anhand des Diagrammes schon sehen, dass ein Szenario mit vielen Entwicklern, Branches, Versionen und Releases schnell komplex werden kann. Trotzdem ist git-flow ziemlich populär, da es eine gewisse Ordnung propagiert und Richtlinien vorgibt. Das ist zumindest die Theorie. In der Praxis macht sich seit geraumer Zeit Kritik breit, die meistens folgendes bemängelt:

  • Merge Konflikte.
  • Feature-Trennung
  • Probleme bei der Release-Planung

Ich werde im Einzelnen auf diese Punkte eingehen. Vorab möchte ich aber festhalten, dass das eigentliche Problem die langlebigen Branches sind. Langlebige Branches entstehen wenn die Arbeit, die in einem Branch erledigt werden soll viel zu umfangreich dimensioniert wurde, so dass der Branch zu lange existiert. Daraus resultieren die o.g. Probleme. Und git-flow neigt dazu, eben diese langlebigen Branches zu produzieren. Auch auf die Gefahr hin, dass ich wieder ins SCRUM-bashing verfalle, aber SCRUM und an SCRUM orienterte Tools erhöhen die Wahrscheinlichkeit von langlebigen Branches. Hier ein Beispiel aus der Praxis.

In Projekt XY wurde der (hervorrangende) Atlassian Stack (Jira, Bitbucket und Confluence) und (das weniger hervorragende) SCRUM eingesetzt. Sprich es gab User Stories, die es umzusetzen galt. Diese wurden im Jira verwaltet. Wenn also ein Entwickler eine User Story umsetzen sollte, wurde der Status der Story im Jira verändert (bspw. von "Ready for Dev" nach "in development"). Nun bietet Jira ein praktisches Feature. Man kann direkt aus der Story heraus ein Branch anlegen, der sich an den Namen der Story anlehnt. So wurde es gehandhabt, und so entstanden etliche langlebige Branches, weil die Entwickler nur in diesen Branch committed haben, bis die Story fertig war. Erst dann wurde gemerged.

Und dann traten die o.g. Problemen auf, auf die ich wie versprochen nun im Detail eingehe:

Merge Konflikte

Das ist glaube ich offensichtlich. Wenn es viele, langlebige Branches gibt, die unabhängig voneinander unterschiedliche Stände haben, und evtl. den gleichen Code verändern, wird es merge Probleme geben. Diese wachsen in Anzahl und Komplexität mit der Anzahl der am gleichen Code arbeitenden Entwickler, und können oft nicht automatisch aufgelöst werden. Das kosten Zeit und Nerven.

Feature-Trennung

Vielleicht kennt das der Eine oder Andere. Der PO fordert unvermittelt ein Release, der aus Business-Gründen Feature XY beinhalten muss. git-flow kennt da den Hotfix als Antwort. Was aber, wenn es Abhängigkeiten zu anderen, langlebigen Branches gibt? Das aufzulösen kann mitunter extrem aufwendig werden.

Probleme bei der Release-Planung

Die o.g. Punkte führen zum dritten und letzten Punkt. Es ist kaum möglich, den Merge-Aufwand für ein bestimmtes Release abzuschätzen. Da jeder Entwickler seit Tagen oder sogar Wochen nur in seinem langlebigen Branch arbeitet, kann keiner sagen, wie groß der Unterschied zwischen dem eigenen Code und der der anderen ist.

Trunk Based Development

Eine Möglichkeit, diese Probleme zu umgehen ist Trunk Based Development. Um die Definition zu bemühen, ist Trunk Based Development:

A source-control branching model, where developers collaborate on code in a single branch called ‘trunk’, resist any pressure to create other long-lived development branches by employing documented techniques, avoid merge hell, do not break the build, and live happily ever after.

Hier das entsprechende Bild dazu:
trunk based dev

In der git Welt würde man statt trunk eher master branch sagen. Ändert aber nichts an der Idee. Amüsant find ich allerdings die Tatsache, dass trunk ein Begriff aus dem alt ehrwürdigem Source Code Management Werkzeug Subversion ist. Amüsant deswegen, weil heutzutage viele Entwickler git für so überlegen halten, dass SVN nur noch mit Mitleid betrachtet wird.

Aber das nur am Rande. Warum ist trunk based dev also besser als git-flow? Hier einige der Gründe:

  • Es wird immer nur vom trunk gebrancht
  • die Branches sind kurzlebig, < 1 Tag
  • es gibt insgesamt weniger Branches
  • es wird daher auch mehrfach am Tag gebaut

Vor allem der letzte Punkt ist hier von großer Bedeutung. Um es hier ganz deutlich zu sagen, wer nicht mindestens täglich einen release-tauglichen Build erzeugt praktiziert kein CI!!. CI ist nicht die Verwendung eines oder mehrerer Tools. Wir machen nicht CI weil wir Jenkins im Einsatz haben. Wir machen CI weil wir mehrmals täglich release-taugliche Builds durch das ständige Mergen in den trunk durch unsere CI pipelines jagen, inklusive automatisierter Tests. Alles andere ist ein Antipattern, bekannt unter dem Namen CI Theater

Wir sehen also, dass die negativen Implikationen einer ohne Reflexion eingeführten Methode recht weitreichend sein können. Es lohnt sich, den eigenen Prozess rund um git und CI auf den Prüfstand zu stellen und ggf. trunk based development in Betracht zu ziehen.

]]>
<![CDATA[Open Source: Fluch oder Segen?]]>Open Source Software (OSS) ist eine gute Sache. Man kann den Source Code einsehen und, falls nötig, diesen selbst erweitern. Getrieben wird die Arbeit oft von der Entwickler-Community, dadurch werden Bugs schneller gefixt und Fragen über Foren und Mailinglisten kurzfristig und unkompliziert beantwortet. Ist das zu wenig, bieten viele Unternehmen

]]>
http://localhost:2368/2017/05/31/open-source-fluch-oder-segen/edee7049-6c2a-4a1c-a37a-858f773b8786Wed, 31 May 2017 19:15:25 GMTOpen Source Software (OSS) ist eine gute Sache. Man kann den Source Code einsehen und, falls nötig, diesen selbst erweitern. Getrieben wird die Arbeit oft von der Entwickler-Community, dadurch werden Bugs schneller gefixt und Fragen über Foren und Mailinglisten kurzfristig und unkompliziert beantwortet. Ist das zu wenig, bieten viele Unternehmen auch kommerziellen Support an.

Soweit die positiven Seiten von OSS. Die meisten negativen Seiten sind, so glaube ich, bekannt;

  • uneinheitlicher, oft schlecht dokumentierter Code
  • komplizierte Abhängigkeiten zu anderen Projekten
  • mangelnder cross-plattform-support
  • keine Installer, komplexer Buildvorgang

Eine etwas subtilere Problematik hat sich im Rahmen eines Kundenprojektes gezeigt. Unsere Erfahrungen möchte ich hier anekdotisch festhalten.

Technologisch gesehen ging es um die Implementierung von Audio- und Video-Streaming auf der Basis der Bibliotheken von https://www.ffmpeg.org/. Zur Einordnung falls nicht bekannt, ffmpeg wird als das "Schweizer Taschenmesser" der Videobearbeitung bezeichnet und ist ein Open Source Projekt. Es besteht zum Einen aus ein Paar Kommandozeilentools zum bearbeiten, konvertieren, streamen, analysieren und wiedergeben von Mediendaten, zum Anderen gibt es eine Handvoll Bibliotheken, die von Entwicklern in eigene Software integriert werden können, um die o.g. Funktionen flexibel einbauen zu können. Ein weiterer, wichtiger Aspekt ist, dass ffmpeg für fast alle Plattformen und Betriebssysteme verfügbar ist.

Wir sollten mit Windows anfangen, also war der Plan, eine DLL zu erstellen, die die ffmpeg Funktionen kapselt, so dass Konsumenten einfache Methoden wie startStreaming, stopStreaming usw. aufrufen können.

Als erstes wollten wir die richtige Version von ffmpeg auswählen. Dazu besuchten wir die ffmpeg Website und stellten fest, dass es dort nur entweder den Source Code oder die Kommandozeilentools gibt. Nicht aber die vorkompilierten Bibliotheken für Entwickler. Glücklicherweise fanden wir die Seite von http://ffmpeg.zeranoe.com/builds/, der aktuelle Builds anbietet.

Allerdings stellten wir als nächstes fest, dass unsere erste, einfache Implementierung sich nicht mit dem aktuellen Zeranoe Build bauen lässt. Offensichtlich hat sich die API an wesentlichen Stellen geändert. Interessant dabei ist, dass selbst die Beispiele aus der aktuellen Codebasis nicht mit der aktuellen Bibliothek kompilierbar sind.

Also gingen wir wieder auf die Suche (sprich Google, Stackoverflow, etc.) und fanden zuerst eine gut versteckte und schlecht dokumentierte Deprecation-Liste von ffmpeg, in der die alten Methoden stehen, die nicht mehr verfügbar sind und ein Paar kryptische Hinweise auf die neuen Methoden. Weiter fanden wir einen Blog-Eintrag eines ffmpeg Entwicklers, der beschreibt, wie man die wichtigsten Methoden nutzen kann. Nun konnten wir weiter arbeiten.

Die Freude währte aber nicht lange. Als wir anfingen, ernsthaft Features umzusetzen, insbesondere was den Support bestimmer Codecs anbelangt, bekamen wir erneut Probleme. Grund dafür war, dass der Zeranoe-Build nicht alle Codecs beinhaltete, die wir benötigten. Also mussten wir unsere eigene ffmpeg Version für Windows bauen. Um diese Geschichte abzukürzen, mehrere Tage später hatten wir nun unsere eigene Version gebaut und unsere Implementierung lief.

Naja, halbwegs zumindest. Wir waren weit davon entfernt, Video und Audio in ordentlicher Qualität in so etwas wie echtzeit übertragen zu können. Audio und Video hingen extrem hinterher und waren komplett unsynchronisiert, sprich es gab mehrere Sekunden Versatz zwischen Audio und Video.

Ich möchte hier nicht auf die Enzelheiten der Implementierung einer eigenen Videostreaming-Lösung eingehen, das würde den Rahmen sprengen. Nur so viel sei gesagt, es ist alles andere als banal, auch wenn man, wie bei uns der Fall, über Vorkenntnisse in relevante Bereiche (Videostreaming, GStreamer, mpeg2 Decoding mit JS) verfügt. Vor diesem Hintergrund verwundert es ein wenig, dass es genau zu dem Thema keine funktionierenden Beispiele oder Anleitungen gibt, weder von ffmpeg noch sonst von der Community.

Nach vielen Versuchen und durch extensives Studieren des Source Codes kamen wir der Sache zwar näher, hatten aber bei ein Paar Themen noch immer keine befriedigende Lösung. Also dachten wir, es sei an der Zeit kommerziellen Support für diese spezifischen Themen in Anspruch zu nehmen. Auf der Website von ffmpeg gibt es die passende Seite mit einer Handvoll namentlich genannter Entwickler, die je nach Schwerpunkt kommerziellen Support anbieten.

Wir schrieben einige an und schilderten unsere Problemstellung. Ungefähr die Hälfte meldete sich nicht zurück. Einer meldete sich sofort zurück und gab an, dass es nicht sein Spezialgebiet wäre und wir sollten doch Entwickler A und B ansprechen. Das hatten wir schon. Entwickler A versuchte zuerst, uns auf all die schlechten, veralteten Beispiele zu verweisen, die wir mittlerweile auswendig im Schlaf rückwärts rezitieren konnten. Nach langem hin-und-her bekamen wir folgendes Angebot, frei übersetzt klang das in etwa so: "mein Kumpel hat nach der Arbeit an 2 Tagen in der Woche jeweil 3 Stunden Zeit und kann das für EUR 200 die Stunde in einem Zeitraum von 3 Monaten erledigen". Damit war das für uns schon mal gestorben. Mit Entwickler B kamen wir etwas weiter, auch wenn dieser manchmal fast zwei Wochen brauchte, um zu antworten. Als wir dann sagten, dass wir keinen Rewrite der Software, sondern nur eine Beratung zu punktuellen Themen benötigen, hieß es hier sinngemäß: "das ist dann für mich nicht mehr (finanziell) interessant. Viel Erfolg.".

Es gab noch einen Entwickler C, der auch nach sehr langer Zeit reagierte, als es aber soweit war hatten wir die Probleme bereits selbst gelöst.

Das mag vielleicht ein extremes Beispiel gewesen sein. Open Source Projekte, hinter denen ein kommerzielles Unternehmen steht sind meist anders aufgestellt. Allerdings ist die Software-Branche nach wie vor auch auf den Einsatz von Open Source Software angewiesen, die "nur" von der Community betreut wird. Ich glaube es macht Sinn, sich bei der Auswahl der Tools und Bibliotheken dieser Aspekte zumindest bewusst zu sein.

]]>
<![CDATA[Post-Agil]]>Vor über 15 Jahren wurde das Agile Manifesto aufgeschrieben und hat damit den Grundstein für eine Idee gelegt, die eine ganze Generation geprägt hat. Doch was ist heute noch von der ursprünglichen Idee übrig? Auf der einen Seite haben wir die stark kommerzialisierte SCRUM Fraktion, auf der anderen eine Vielzahl

]]>
http://localhost:2368/2017/04/25/post-agile/d1521377-baff-4381-81b2-ecffaa220da3Tue, 25 Apr 2017 11:34:02 GMTVor über 15 Jahren wurde das Agile Manifesto aufgeschrieben und hat damit den Grundstein für eine Idee gelegt, die eine ganze Generation geprägt hat. Doch was ist heute noch von der ursprünglichen Idee übrig? Auf der einen Seite haben wir die stark kommerzialisierte SCRUM Fraktion, auf der anderen eine Vielzahl mehr oder weniger ernst zu nehmenden Derivaten, Erweiterungen und verwandten Methodologien. Einige davon werden teilweise als "post-agil" bezeichnet.
Viele Unternehmen spüren die Notwendigkeit, ihre Prozesse effektiver zu gestalten und versprechen sich von agilen Methoden die entsprechende Verbesserung. Allerdings ist es vor dem Hintergrund der o.g. Aspekte nicht trivial, die richtige Methode zu ermitteln.
Wir helfen unsere Kunden dabei, wirklich agil zu werden. Dabei gehen wir unvoreingenommen in die Bedarfsanalyse und beziehen nicht nur die IT in unserer Empfehlung. Nicht selten schlagen wir dabei ein post-agiles Verfahren vor.

Was ist post-agil eigentlich?

Um die Frage beantworten zu können man sich den geschichtlichen Kontext vor Augen führen. Die agile Bewegung wurden zu einer Zeit ins Leben gerufen, als es Gang und Gebe war, Software-Projekte nach dem Wasserfall Prinzip durchzufühen. Oft vergingen Monate, in denen keine einzige Zeile Code geschrieben wurde, sondern "nur" am Design und Architektur der Anwendung gefeilt wurde. Dies ist heute als BUFD (Big Up-Front Design) bekannt. Damals war der Ansatz, Software in kleinen Inkrementen und kurzen Zyklen zu liefern geradezu revolutionär. Insbesondere der Anspruch der XP-Bewegung (Extrem Programming), zu jeder Zeit ein lieferbares Produkt zu haben, stellte in Paradigmenwechsel dar. Aber wie gesagt, das war vor 15 Jahren. In der Zwischenzeit hat sich einiges getan, was zum Aufkommen des Begriffes "post-agil" geführt hat:

  • Kommerzialisierung. Agile Entwicklung ist heute ein Wirtschaftsfaktor. Man muss immer sehr genau hinschauen, gerade wenn große Consulting-Häuser pauschal SCRUM vorschlagen. Oft sind finanzielle Interessen dahinter. Schließlich kann man gut von SCRUM Zertifizierungen, Workshops, Bücher und Tools leben.
  • Begrifflichkeit. In einem anderen Artikel habe ich schon darüber geschrieben. Wenn vor die Wahl gestellt, wer wird sich schon dafür entscheiden, nicht "agil" sein zu wollen. Das Wort alleine impliziert schon eine Verbesserung, ohne die Tragweite des Commitments erkennbar zu machen.
  • Soziale Aspekte. Die Kritik vor allem an SCRUM als führende agile Methode hat auch eine Konnotation, die stark mit der sozialen Entwicklung der Software-Entwickler verwurzelt ist. Vor 15 Jahren waren Software-Entwickler noch mit dem Image des sozial gehandicapten Nerd verbunden, der das Sonnenlicht meidet und sich nur von Pizza und Cola ernährt. Dieses Bild hat sich gewandelt. Software-Entwickler heute sind meist gut situiert, integriert und sie sind, im Gegensatz zur Jahrtausendwende, recht viele. Es ist gesellschaftlich anerkannt, dass ohne uns nichts mehr funktionieren würde. Ohne Software würde kein modernes Auto fahren, kein Licht angehen, keine Heizung heizen, usw. Diese Macht und die Wahrnehmung in der Gesellschaft verändert auch das Selbstbewusstsein in der Branche. Vor diesem Hintergrund kann man vielleicht gut nachvollziehen, dass Programmierer heute Methoden in Frage stellen, die sie zwingen, mit Spielkarten und fiktiven Punkten zu "spielen", um Aufwende abzuschätzen, oder täglich die gleich klingende Formel des Daily Scrums zu rezitieren.
  • Reife des Berufes. Mit der oben beschriebenen Macht und der gesellschaftlichen Anerkennung kommt aber auch eine größere Verantwortung. Und das ist meiner Meinung nach der entscheidende Scheidepunkt, an dem wir heute stehen. Wir sind Teil einer mächtigen, globalen, wirtschaftlich starken und gesellschaftlich anerkannten Industrie. Es wird Zeit dass wir uns entsprechend verhalten. Die Art und Weise wie heute agile Methoden eingesetzt werden, spiegelt diese Werte nicht wider. Es ist nach wie vor möglich, sich nach den Regeln von bspw. SCRUM absolut korrekt zu verhalten und trotzdem keinen entsprechenden Wert zu erzeugen und die Verantwortung nicht zu übernehmen.

Aus diesen Gründen wird der Ruf nach einem "post-agilen" Ansatz immer lauter.

Post-agil: Definitionen

Um es vorweg klar zu stellen, es gibt keine eindeutige Definition des Begriffes "post-agil". Für einige ist "post-agil" lediglich die Anwendung der urspünglichen agilen Werte, wie sie im agilen Manifesto stehen. Dort wiegen:

  • Individuen und Interaktionen mehr als Prozesse und Werkzeuge
  • Funktionierende Software mehr als umfassende Dokumentation
  • Zusammenarbeit mit dem Kunden mehr als Vertragsverhandlung
  • Reagieren auf Veränderung mehr als das Befolgen eines Plans

Andere wiederum haben ein "post-agiles Manifesto" erarbeitet, dieser lautet, vereinfacht ausgedrückt: wenn es funktioniert, tu es. Wenn es nicht funktioniert, lass es. Und dann gibt es wieder Tendenzen, die Idee von post-agil zu kommerzialisieren, wie z.B. Modern Agile. Dabei wird das Konzept auf mehr als nur die Softwareentwicklung ausgeweitet.

The conventic way

Wir glauben, dass es keine "one-size-fits-all" Methode gibt. SCRUM ist nicht die pauschale Lösung für alle Software-Projekte. Jeder Kunde und jedes Projekt hat eine eigene Historie und steht an einer anderen Ausgangsposition. Für ein Unternehmen, das aus einem Wasserfall-Prozess hinauswachsen möchte mag SCRUM die richtige Wahl sein. Für andere, die schon 5 Jahre SCRUM oder Kanban machen mag Programmer Anarchy, Mob Programming oder Extreme Programming eine Alternative bzw. eine Ergänzung sein. Daher lautet unser Credo:

Context over Convention

Wir analysieren den Kontext des Projektes in der Organisation, um darauf aufbauend die richtige Methode vorzuschlagen. Wir führen dieses Prinzip übrigens konsequent auch bis in die Entwicklung weiter. Somit scheuen wir auch nicht die Diskussion über "religiöse" Themen, wie z.B. "muss ich immer einen Test schreiben bevor ich den eigentlichen Code schreibe?" oder "brauchen wir wirklich eine MicroServices Architektur?". Es ist alles eine Frage des Kontextes, egal welche Konventionen gerade "in" sind.

]]>
<![CDATA[Vom Monolithen zum Microservice]]>Einführung

Microservices sind in aller Munde, das Thema hat Hochkonjunktur. Überall kann man lesen, wie man Microservices Architekturen aufbauen kann und welche Tools dafür notwendig sind. Wer heute ein neues Projekt als Monolith designt gilt als old-school. Das ist zwar ein grober Fehler, mit einen Monolithen zu starten ist in

]]>
http://localhost:2368/2016/10/25/vom-monolithen-zum-microservice/30737aa9-7b59-4354-ad24-ca802f73eda9Tue, 25 Oct 2016 11:03:57 GMTEinführung

Microservices sind in aller Munde, das Thema hat Hochkonjunktur. Überall kann man lesen, wie man Microservices Architekturen aufbauen kann und welche Tools dafür notwendig sind. Wer heute ein neues Projekt als Monolith designt gilt als old-school. Das ist zwar ein grober Fehler, mit einen Monolithen zu starten ist in vielen Fällen die besere Alternative, das ist aber nicht unser Thema heute. Ich möchte heute auf ein Thema eingehen, das uns vermutlich die nächsten Jahre beschäftigen wird. Wie können wir eine existierende, Monolithische Anwendung in eine Microservices Architektur überführen?

In diesem Artikel werde ich auf einige Strategien und Muster eingehen, die wir in vergangenen Projekten angewendet haben, um monolithische Applikationen in eine Microservices Architektur zu überführen. Ich werde explizit weder auf die Definition von Microservices eingehen noch bestimmte Tools erwähnen, das kann man woanders in ausreichender Tiefe und Breite lesen.

Ansatzpunkte

Bei allen Fällen die ich erlebt habe, stellte sich erst einmal die Frage, wo man ansetzen soll. Wie kann man sich der Thematik annähern? Betrachten wir zuerst die möglichen Ausgangslagen. Der gemeinsame Nenner ist meistens, dass es eine monolithische Anwendung gibt, mit der es Probleme gibt. Hier findet sich meistens schon der erste Hinweis darauf, ob eine Überführung in eine Microservice Architektur überhaupt Sinn macht. Schauen wir uns diese Gründe an:

  • Die Applikation ist schlecht oder gar nicht mehr wartbar
  • Die Applikation lässt sich nicht in akzeptabler Zeit bzw. automatisiert deployen
  • Das Deployment der Applikation ist immer mit Downtime verbunden
  • Fehler in bestimmten Teilen der Applikation führen zu einem Totalausfall der Anwendung
  • Die Applikation skaliert schlecht oder gar nicht
  • Die Applikation lässt sich nicht mit vertretbarem Aufwand erweitern
  • Teile der Applikation lassen sich nicht ohne extrem negativen Auswirkungen auf das Gesamtsystem austauschen

Können mehrere dieser Gründe herangezogen werden, so ist es zumindest empfehlenswert, weiter zu untersuchen, ob eine Microservices Architektur besser geeignet wäre.

Erste Annäherungsversuche

UI Trennung

Ein erster Ansatzpunkt kann sein, zu untersuchen ob die UI - sofern die Applikation überhaupt eine hat - vom Rest getrennt werden kann. Je nach Art der Applikation kann die Präsentationsschicht recht umfangreich sein. Umso mehr lohnt es sich, diese zu extrahieren. Allerdings muss hier evtl. ein Zwischenschritt eingeführt werden. Ist die Präsentationsschicht zu komplex, ist es ratsam, diese erst als einen zweiten Monolithen zu extrahieren und zwischen dem Frontend-Monolithen und dem Backend-Monolithen eine Schnittstelle einzuziehen. Erst im nächsten Schritt kann dann damit begonnen werden, diese millerweile kleineren Monolithen in Services aufzulösen.

UI Trennung

Monolithen Modularisieren (Orthogonale Transformation)

Viele monolithische Anwendungen sind logisch nach einem Schichtenmodell segmentiert. Stark vereinfacht sind diese Segmente von unten nach oben: Persistenzschicht, Domänenschicht, Anwendungsschicht und Präsentationsschicht. Grafisch dargestellt kann diese Architektur als übereinander gestapelte Rechtecke dargestellt werden. Bei komplexen Anwendungen kann es sinnvoll sein, die Architektur des Monolithen erst einmal orthogonal zu transformieren, indem man innerhalb des Monolithen modularisiert. Die Darstellung der resultierenden Architektur besteht dann aus nebeneinander stehenden Boxen. Ein solcher Monolith lässt sich einfacher in eine Microservices Architektur übertragen.

Orthogonale Transformation

Cross Cutting Concerns

Ein weiterer, vorbereitender Punkt kann sein, die sog. Cross Cutting Concerns zu extrahieren. Kandidaten hierfür können, je nach Art der Anwendung, sein: Logging, Encryption, Authentication, Messaging, usw. Diese Themen sind oft technisch gut kapselbar, so dass sich hieraus einfacher Services extrahieren lassen, die dann über eine definierte Schnittstelle angebunden werden können.

Cross Cutting Concerns

Produkte extrahieren

Während sich die o.g. cross cutting concerns eher auf einer technischen Ebene bewegen, haben komplexe Anwendungen auch eine ganze Reihe an fachlichen Komponenten. Viele dieser Komponenten sind fertige Lösungen, die irgendwann in den Monolithen, mal mehr mal weniger gut gekapselt, integriert worden sind. Diese sind ebenfalls Kandidaten für eine einfache Extraktion zu einem Service. Beispiele hierfür sind: Workflow Engines, Search Engines, Affiliate Marketing, Recommendation Engines, CMS, usw.

Zweite Iteration, eine Ebene tiefer

Im vorherigen Abschnitt habe ich die "Low Hanging Fruits" der Microservices Extraktion aufgeführt. Nun bleibt der harte Kern des alten Monolithen übrig. Hier kann man nicht nach Schema F vorgehen, da die Herangehensweise zu stark von der vorliegenden Software abhängt. Trotzdem haben wir Muster identifiziert, die sich in den letzten Projekten wiederholt haben. Diese bespreche ich im folgenden Abschnitt.

Asynchrone Verarbeitung

Oben hatte ich bereits aufgeführt, dass z.B. Messaging ausgegliedert werden kann. Nun bietet es sich an, sich die Komponenten im Monolithen anzuschauen, die asynchron, evtl. über Messaging, kommunizieren. Da hier erfahrungsgemäß die Kopplung geringer ist, bieten sich solche Komponenten an.

Asynchrone Verarbeitung

Datenhaltungsparadigmen

In vielen Anwendungen sieht man eine polyglotte Datenhaltung. D.h. es werden unterschiedliche Datenhaltungen für unterschiedliche fachliche oder technische Anforderungen verwendet. Ich empfehle diese Datenhaltungen sowie die Komponenten, die diese verwenden, zu untersuchen. Oft können diese Kandidaten für eine Extraktion sein.

Datenhaltungsparadigmen

Threads

Threads sind in manchen Fällen ebenfalls lohnenswerte Einstiegspunkte. In vielen Anwendungen werden Threads verwendet, um sehr spezifische Aufgaben auszuführen. Da ein Thread von Natur aus eine lose Kopplung und eine hohe Kohärenz zum Gesamtsystem haben sollte, bietet es sich an, diese auf ihre Extraktionsfähigkeit zu untersuchen.

Algorithmen

Algorithmen bestehen oft aus vielen Klassen oder Modulen, die nur zur Erfüllung der Aufgabe des Algorithmus da sind. Diese sind ebenfalls Kandidaten, um extrahiert zu werden, da hier auch eine lose Kopplung mit einer hohen Kohärenz gegeben ist.

Zusammenfassung und Ausblick

Die o.g. Ansätze sind aus unseren Erfahrungen in Projekten verschiedener Größe entstanden. Wir gehen fest davon aus, dass dieses Thema in den kommenden Jahren immer wieder auftauchen wird. Wir freuen uns auf den regen Austausch mit Kunden, Partnern und der Community, um Ideen und Erfahrungen auszutauschen.

]]>
<![CDATA[X11 App aus nativem Docker Container auf dem Mac ausführen]]>Seit geraumer Zeit steht eine Beta Version eines nativen Docker Clients für Mac zur Verfügung, der den Umweg über boot2docker oder sonstige Linux VMs überflüssig macht. Wir nutzen Docker auch, um grafische Anwendungen zu entwickeln. Nun stellt sich die Frage, wie wir eine Anwendung, die einen X11 Server benötigt, von

]]>
http://localhost:2368/2016/06/03/x11-app-aus-nativem-docker-container-auf-dem-mac-ausfuhren/a41fa43d-c888-4359-a1ab-df8d715c7f08Fri, 03 Jun 2016 08:21:49 GMTSeit geraumer Zeit steht eine Beta Version eines nativen Docker Clients für Mac zur Verfügung, der den Umweg über boot2docker oder sonstige Linux VMs überflüssig macht. Wir nutzen Docker auch, um grafische Anwendungen zu entwickeln. Nun stellt sich die Frage, wie wir eine Anwendung, die einen X11 Server benötigt, von einem nativen Docker Container auf dem Mac darstellen können. In der Vergangenheit haben wir diverse Variationen dieser Aufgabenstellung umgesetzt:

  • Lokale X11 Linux VM, Display auf MacOS oder lokal in der VM
  • Lokale Headless Linux VM, Display auf MacOS
  • Remote Headless Linux VM, Display auf MacOS
  • Remote Headless Linux VM, Display auf Windows 10
  • ...

Nun kommt eine neue Variante dazu:

  • Lokaler native Docker Container, Display auf MacOS

Aus den Erfahrungen der anderen Varianten haben wir gemutmaßt, daß es reichen könnte XQuartz auszuführen und die DISPLAY Umgebungsvariable zu übergeben. Leider wird das mit einem Fehler quittiert, da der Docker Client nicht auf den XQuartz Socket zugreifen kann:

$ docker run --rm -it --net=host -e DISPLAY test/xterm
xterm: Xt error: Can't open display: /private/tmp/com.apple.launchd.TFUw2s0Mer/org.macosforge.xquartz:0  

Auch andere Versuche, den XQuartz Socket als Unix X-Socket über ein Volume Mount einzubinden sind fehlgeschlagen. Also haben wir und für einen Umweg entschieden, bis wir eine bessere Lösung finden oder seitens Docker oder XQuartz entsprechende Änderungen implementiert werden: wir nutzen das Tool socat, um den XQuartz Socket über den X11 Default-Port umzuleiten. Dem Docker Container reicht dann die DISPLAY Umgebungsvariable, um X11 Anwendungen anzeigen zu können. Die Lösung sieht wie folgt aus (Annahme: XQuartz läuft schon):

$ brew install socat
...
$ socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" &
$ docker run --rm -it --net=host -e DISPLAY=192.168.178.20:0 test/xterm

Wobei 192.168.178.20 meine aktuelle IP im internen Netz ist.

]]>
<![CDATA[Node.js Module mit JSDoc dokumentieren]]>Das Revealing Module Pattern ist eine bewährte Methode, um JavaScript-Code zu kapseln und eine private Implementierung hinter einer definierten öffentlichen Schnittstelle zu verbergen. In diesem Artikel werde ich zeigen, wie man das Revealing Module Pattern in Node.js verwendet und wie man so ein Modul mit http://usejsdoc.org/.

Als

]]>
http://localhost:2368/2016/05/24/node-js-module-mit-jsdoc-dokumentieren/6772fa6c-1640-476b-8fe9-bd09cd5fd4faTue, 24 May 2016 19:02:24 GMTDas Revealing Module Pattern ist eine bewährte Methode, um JavaScript-Code zu kapseln und eine private Implementierung hinter einer definierten öffentlichen Schnittstelle zu verbergen. In diesem Artikel werde ich zeigen, wie man das Revealing Module Pattern in Node.js verwendet und wie man so ein Modul mit http://usejsdoc.org/.

Als ersten Schritt implementieren wir ein generisches Modul nach den Richtlinien des Revealing Module Pattern:

var katzenModul = (function () {  
    var privaterName = 'kitty';

    function publicGetName(){
        return privaterName;
    }

    return {
        getName : publicGetName
    };
})();

katzenModul.getName();  

Dieses Modul definiert eine Funktion publicGetName(), die nach aussen als getName deklariert wird. Der Name der Katze ist privat und kann nicht von aussen zugegriffen werden, wie die entsprechenden Tests beweisen:

describe('katzenModul', function() {

  it('should return the name of the cat', function() {
      var name = katzenModul.getName();
      assert.equal(name, 'kitty');
  });

  it('should not allow access to private variables', function() {
      assert.equal( undefined, katzenModul.privaterName );
  });

  it('should not allow access to private functions', function() {
      assert.equal( undefined, katzenModul.publicGetName );
  });
});

Als nächstes machen wir aus unserem generischen Modul ein Node-Modul:

var katzenModul = (function () {  
    var privaterName = 'kitty';

    function publicGetName(){
        return privaterName;
    }

    return {
        getName : publicGetName
    };
})();
module.exports = katzenModul;  

Durch die letzte Zeile module.exports = katzenModul; haben wir unser Modul Node.js bekannt gemacht. Nun können wir das Modul z.B. wie folgt verwenden:

var katzenModul = require('./katzenModul');

console.log( katzenModul.getName() );  

Ein weiterer Vorteil des Revealing Module Pattern ist, dass es sich sehr gut eignet, um Dokumentation zu schreiben, ohne die Lesbarkeit des Codes zu beeinträchtigen. Der Grund dafür ist, dass die Dokumentation der "öffentlichen" Schnittstelle eines solchen Moduls am Ende der Datei steht und nicht den eigentlichen Code "verunreinigt". So sieht z.B. eine dokumentierte Version von katzenModul aus:

/**
 * @description Dieses Module liefert Katzennamen
 * @module katzenModul
 * @author Marcelo Emmerich
 */
var katzenModul = (function () {  
    var privaterName = 'kitty';

    function publicGetName(){
        return privaterName;
    }

    return {
        /**
         * @function
         * @description Liefert den Namen der Katze
         * @memberof module:katzenModul
         * @returns {String} Den Namen der Katze als String
         */
        getName : publicGetName
    };
})();
module.exports = katzenModul;  

Zuerst habe ich das Modul als solches mit dem JSDoc Tag @module definiert, um es später referenzieren zu können. @author und @description sind vermutlich selbst erklärend, also schauen wir uns die interessanteren Tags an. Die Funktion getName ist mit @function markiert. Das ist deswegen notwendig, weil der JSDoc Parser sonst nicht mit der Syntax des Revealing Module Pattern klar kommt und die Funktion nicht als solche erkennt. Weiter müssen wir JSDoc auch damit auf die Sprünge helfen, die Funktion getName als zum Modul katzenModul zugehörig anzuerkennen. Das erreichen wir mit dem @memberof module:<Modulname> Tag. Wenn wir nun mit JSDoc die Dokumentation erzeugen, wird unser Modul als solches aufgeführt und die Funktion getName korrekt referenziert.

]]>
<![CDATA[Agil, Extrem oder doch Anarchisch?]]>In einen Interview von 2015 16: Kent Beck - Tiny Decisions and Emergent Design bin ich auf eine sehr interessante Aussage von Kent Beck (Extreme Programming Erfinder, Mitunterzeichner des Agilen Manifests und Autor von JUnit) gestossen. Er erklärte, dass er damals, als die Agile Bewegung begann, mit dem Begriff "agil"

]]>
http://localhost:2368/2016/04/09/agil-extrem-oder-doch-anarchisch/9693e71f-6030-491c-a12a-6558532725a1Sat, 09 Apr 2016 09:31:11 GMTIn einen Interview von 2015 16: Kent Beck - Tiny Decisions and Emergent Design bin ich auf eine sehr interessante Aussage von Kent Beck (Extreme Programming Erfinder, Mitunterzeichner des Agilen Manifests und Autor von JUnit) gestossen. Er erklärte, dass er damals, als die Agile Bewegung begann, mit dem Begriff "agil" nicht glücklich gewesen sei, denn dieser sei zu gefällig. Wer kann denn schon (im generischen Sinne des Wortes) nicht agil sein wollen? Das Wort sei schliesslich nur positiv belegt.

Das ist sicher einer der Faktoren, die dazu geführt haben, dass so viele Organisationen auf den agilen Zug aufgesprungen sind, ohne wirklich hinter der Idee zu stehen. Deswegen sehen wir in der täglichen Praxis so viele Projekte, die nach "WaterScrumFall" durchgeführt werden. Hauptsache man ist agil.

Kent Beck wählte den Begriff "Extreme Programming" für seinen agilen Ansatz. Er argumentiert, dass nicht jeder automatisch "extrem" sein möchte. Das führt dazu, dass die Wahrscheinlichkeit höher ist, dass man entweder ganz oder gar nicht hinter der Sache steht.

In letzter Zeit beschäftigen wir uns bei der Pulsar mit post-agilen Ansätzen. Einer dieser Ansätze, der maßgeblich von Fred George geprägt wurde, ist Programmer Anarchy. Hier findet sich schon im Namen das, was Kent Beck damals angemerkt hatte. Nicht jeder assoziiert "anarchisch" mit etwas positivem. Das erhöht die Wahrscheinlichkeit, dass man wirklich dahinter steht, sollte man sich für diesen Weg entscheiden.

Wir werden uns weiter mit Programmer Anarchy und anderen post-agilen Ansätzen beschäftigen und unsere Erkenntnisse hier posten.

]]>
<![CDATA[Scrum ist nicht agil]]>Zugegeben, der Titel ist ein wenig provokant. Das soll es aber auch, denn ich möchte damit ein Gefühl zum Ausdruck bringen, das mich schon lange beschleicht. Der Ausschlag gebende Anstoß für diesen Artikel kam, als ich mich selbst in folgender Situation befand: Wir waren mitten im Sprint und der Kunde

]]>
http://localhost:2368/2016/03/17/scrum-ist-nicht-agil/f5bd2652-4744-4bd3-875c-d399a3efee04Thu, 17 Mar 2016 18:49:35 GMTZugegeben, der Titel ist ein wenig provokant. Das soll es aber auch, denn ich möchte damit ein Gefühl zum Ausdruck bringen, das mich schon lange beschleicht. Der Ausschlag gebende Anstoß für diesen Artikel kam, als ich mich selbst in folgender Situation befand: Wir waren mitten im Sprint und der Kunde wünschte dringend die Umsetzung einer bestimmten Funktionalität. Meine fast schon automatische Antwort darauf war:

wir sind mitten im Sprint. Während des Sprints ändert sich der Scope nicht. Gerne nehmen wir die Anforderung auf und priorisieren diese im kommenden Sprint entsprechend.

Ich fühlte mich schlecht dabei, wusste aber in diesem Moment nicht genau warum. Erst später kam ich darauf: ich hatte den Prozess höher gewertet als den Kunden und unsere Interaktion. Ich hatte eine wichtige Anforderung künstlich um 2 Wochen verzögert, nur weil der Prozess es so will. Immerhin sind wir in der Lage, Änderungen innerhalb von 10 Minuten auf Produktion zu deployen. Mir wurde schlagartig klar, dass das nur die Spitze des Eisbergs war. Immer mehr Episoden dieser Art aus vergangenen Projekten schossen mir auf einmal durch den Kopf, so dass mir letzendlich klar wurde, Scrum ist nicht agil.

Selbstverständlich kann ich eine solche Aussage nicht lediglich auf der Basis eines Gefühls oder eines einzelnen Beispieles postulieren. Glücklicherweise können wir bei Pulsar Solutions auf eine recht umfangreiche Projekt-Historie zurückgreifen. Hier finden sich hauptsächlich Projekte, die nach Scrum entwickelt worden sind. Mit anderen Worten, die hier vorgestellten Erkenntnissen basieren auf empirische Daten, gesammelt aus den Erfahrungen von ca. 10 Jahren Projektgeschäft.

Bevor ich erkläre, warum Scrum nicht agil ist, sollten wir definieren, was agil ist. Aus unserer Sicht ist ein Team (oder eine Organisation) dann agil, wenn es sich an die Werteverteilung hält, die im Agilen Manifest beschrieben worden ist. Hier die Werte des Agilen Manifests:

Wir erschließen bessere Wege, Software zu entwickeln, indem wir es selbst tun und anderen dabei helfen. Durch diese Tätigkeit haben wir diese Werte zu schätzen gelernt:

  • Individuen und Interaktionen mehr als Prozesse und Werkzeuge
  • Funktionierende Software mehr als umfassende Dokumentation
  • Zusammenarbeit mit dem Kunden mehr als Vertragsverhandlung
  • Reagieren auf Veränderung mehr als das Befolgen eines Plans

Das heißt, obwohl wir die Werte auf der rechten Seite wichtig finden, schätzen wir die Werte auf der linken Seite höher ein.

Gehen wir die einzelnen Werte der Reihe nach durch und schauen wir, ob diese in der Praxis so gelebt werden oder nicht:

Individuen und Interaktionen mehr als Prozesse und Werkzeuge

Leider ist unsere Erfahrung, dass in der Praxis das Gegenteil der Fall ist. Insbesondere das Thema Prozesse hat einen extrem hohen Wert gegenüber Individuen und Interaktionen. Ohne Rücksicht auf Verluste muss der Prozess eingehalten werden. Dafür ist der Scrum Master schliesslich da, um den Prozess einzuhalten... Aber woher kommt diese Verschiebung der Werte? Aus unserer Erfahrung gibt es dafür zwei Gründe. Zum Einen geht es bei Scrum um viel Geld. Es werden Zertifizierungen verkauft. Es werden zertifizierte Mitarbeiter - entschuldigung: Consultants - verkauft. Es werden Tools, Schulungen, usw. verkauft. Dass diese Zertifizierungen meistens das Papier nicht Wert sind, auf das Sie gedruckt sind, weil sie nach einem 2-Tages-Workshop vergeben werden, interessiert offenbar niemand.
Der andere Grund, warum der Prozess meistens so vehement umgesetzt wird, hat mit Conway's Gesetzt zu tun. Dieses besagt:

Organisationen, die Systeme entwerfen, […] sind auf Entwürfe festgelegt, welche die Kommunikationsstrukturen dieser Organisationen abbilden.

Nun sehen sich solche Unternehmen aber in einem Konflikt, weil es zwei Kräfte gibt, die an diesen Strukturen rütteln. Zum Einen wollen die meisten Mitarbeiter von IT Abteilungen nach modernen Methoden arbeiten. Es gibt also Druck von unten. Zum Anderen wird solchen Unternehmen verkauft, dass man mit agilen Methoden viel Geld sparen kann. Wie können diese Unternehmen also die Vorteile nutzen, ohne das Unternehmen selbst in eine agile Organisationsform umzugestalten? Das würde ja den Verlust von Kontrolle und Hierarchien bedeuten. Zum Glück gibt es Scrum! In der Organisation kann alles beim Alten bleiben, an der Grenze zur "agilen" IT steht ja ein Product Owner der als Schnittstelle zwischen Entwicklung und Stakeholder steht und übersetzen muss. Und zum Glück gibt es ein Backlog mit 500 User Stories, die schon vor Projektbeginn in einer Initialbefüllung für eine Aufwandsabschätzung herangezogen wurden. Man möchte ja wissen was der Spaß kosten wird, agil hin oder her.
Ich könnte die ironischen Spitzen immer weiter treiben, aber ich glaube die Idee ist klar geworden. Scrum ist mittlerweile nur noch ein Vehikel, um nicht agilen Unternehmen einen Prozess zu verkaufen, der zwar auch nicht wirklich agil ist, aber so klingt und mit dem man Ausgaben rechtfertigen kann.

Funktionierende Software mehr als umfassende Dokumentation

Ursprünglich bezog sich dieser Satz darauf, dass Entwickler zu viel Zeit mit der Erstellung von Dokumentation verbracht haben, anstatt zu entwickeln. Dieser Umstand hat sich heute etwas verändert, aber auch hier hat Scrum dazu geführt, dass sich die Werteverteilung umgekehrt hat. In Scrum-Projekten ist es mittlerweile Usus, dass die ersten Sprints nichts brauchbares Produzieren und dazu dienen, die "Werte" einzupendeln. Mit Werte sind hier Metriken gemeint, die gerne in KPI Dashboards Management-gerecht auf Knopfdruck generiert werden können. Velocity, Burn Down Chart, Defect Fix Rate und etliche mehr. Weiter wird meistens ein Wiki aufgesetzt, wo sich Definition of Done befinden, Richtlinien für die Nutzung der Sourcecode-Verwaltung, Leitfaden für effektive Stand-up Meetings, Ablaufplan des Sprint Reviews, der Grooming Session, der Retrospektive, des Sprint-Pre-Plannings usw. Weiter werden die Ergebnisse, Protokolle und Notizen dieser Meetings fest gehalten. Das ist alles Dokumentation. Und in all der Zeit, die damit verbracht wird, wird keine eizige Zeile Code geschrieben und an den Kunden ausgeliefert.

Zusammenarbeit mit dem Kunden mehr als Vertragsverhandlung

Sprints bzw. die für einen Sprint zugesicherten Story Points, die Velocity, das (hoffentlich) als Business-Value formulierte Sprint-Ziel sowie die Capacity der Teammitglieder während eines Sprints. Das sind alles Verträge. Nicht im klassischem Sinne, aber dennoch Verträge. Je größer die Organisation um so mehr wird auf diese Indikatoren geachtet, mit dem Resultat, dass wir an Agilität verlieren. Die folgende Situation dürfte jedem bekannt vorkommen, der schon mal in einem Scrum Team gearbeitet hat. Mittem im Sprint taucht ein Problem auf, der eigentlich erfordern würde, dass die Arbeit sofort gestoppt wird und erstmal mit dem Kunden Rücksprache gehalten wird. Selbst wenn der Impuls da ist, sitzen einem dann automatisch die Scrum-Teufelchen auf der Schulter, die sagen: "wenn du jetzt nicht weitermachst wird die Velocity sinken" oder "mach einfach weiter, sonst schaffst du nicht die von dir zugesicherten Story Points". Das Problem wird also erstmal ignoriert, kommt aber erfahrungsgemäss trotzdem raus. Dann gibt es Diskussionen mit dem Kunden darüber, ob die Story angenommen werden kann oder nicht, wie viel zusätzlicher Aufwand das beim nächsten Sprint generiert, usw. Also Vertragsverhandlungen anstelle von Zusammenarbeit mit dem Kunden.

Reagieren auf Veränderung mehr als das Befolgen eines Plans

In Scrum muss der Plan befolgt werden. Wenn die Arbeit für die nächsten 2, 3 oder 4 Wochen fest steht, werden Veränderungen entweder ausgeblendet oder auf den nächsten Sprint geschoben. Auch hier gilt, nur die Definition dessen was ein Plan ist, hat sich verändert seitdem das Manifest geschrieben wurde. Die Werte aber sind geblieben. Ein Sprint ist ein Plan. Zwar nicht für 3 Jahre, sonder nur für 3 Wochen, aber trotzdem ein Plan. Stellen wir diesen Plan über die Fähigkeit, auf Änderungen zu reagieren, sind wir nicht agil.

Und was nun?

Die Frage ist an dieser Stelle natürlich mehr als berechtigt. Was sollen wir statt dessen tun? Die Antwort darauf ist ein klares "kommt darauf an". Jede Organisation und jedes Team ist anders. Für manche Organisationen ist Scrum mit all den Problemen, auf die ich hier aufmerksam gemacht habe, trotzdem besser als das was davor praktiziert wurde. Andere wiederum würden extrem davon profitieren, sich von Scrum zu lösen. Auf verschiedene Fälle, die wir beobachtet haben, werden wir in kommenden Artikel detaillierter eingehen. Grundsätzlich ist es aber sicher nicht verkehrt, bei der täglichen Arbeit im Rahmen von Scrum (oder anderen agilen Methoden) sich einfach die Werte des Agilen Manifests bewusst zu sein und ggf. Dinge zu hinterfragen, wenn die Vermutung nahe liegt, dass eine Werteumkehrung statt findet.

]]>
<![CDATA[libVLC Entwicklungsumgebung als Docker Container ohne Qt4]]>Entwickler komplexer Projekte müssen oft Open-Source Bibliotheken einbinden. Insbesondere in der nativen Entwicklung können diese Bibliotheken eine hohe Anzahl an Abhängigkeiten haben. Diese Abhängigkeiten können sowohl in Form von weiteren Bibliotheken, Tools oder sogar ganze Programmiersprachen auftreten. Ein gutes Beispiel hierfür ist libVLC. libVLC ist die Bibliothek, auf die der

]]>
http://localhost:2368/2016/01/18/libvlc-entwicklungsumgebung-als-docker-container-ohne-qt4/ab96888d-774e-4205-8d73-8cde58fbb4e9Mon, 18 Jan 2016 21:51:07 GMTEntwickler komplexer Projekte müssen oft Open-Source Bibliotheken einbinden. Insbesondere in der nativen Entwicklung können diese Bibliotheken eine hohe Anzahl an Abhängigkeiten haben. Diese Abhängigkeiten können sowohl in Form von weiteren Bibliotheken, Tools oder sogar ganze Programmiersprachen auftreten. Ein gutes Beispiel hierfür ist libVLC. libVLC ist die Bibliothek, auf die der populäre VLC Player aufgebaut ist. Als Entwickler kann man libVLC nutzen, um Audio und Video in eigenen Anwendungen abzuspielen.

Wichtig! Die folgenden Ausführungen setzen ein voll funktionsfähiges Linux mit X-Server und aktueller Docker (v1.9.1) Installation voraus.

In einem aktuellen Projekt hatten wir die Aufgabe, eine reproduzierbare Entwicklungsumgebung zu schaffen, auf deren Basis wir eine komplexe Qt5 Anwendung unter Linux implementieren wollten, die unter anderem Videos abspielen sollte. Das stellte uns vor zwei Herausforderungen:

  • wie können wir eine reproduzierbare Entwicklungsumgebung mit einer definierten Version von libVLC schaffen, und trotzdem den Entwicklern die Freiheit lassen, mit ihren bevorzugten Tools und Editoren zu arbeiten?
  • libVLC bindet Qt4 ein. Wir nutzen Qt5. Es ist bekannt, dass sich Qt4 und Qt5 im selben Projekt nicht nebeneinander ausführen lassen, ohne dass es Probleme zur Laufzeit gibt. Wie können wir also eine libVLC Version ohne Qt4 bauen?

Für die erste Herausforderung war eine Lösung relativ schnell gefunden. Wir haben ein Docker Image erstellt, das eine Basis Ubuntu Distribution mit der zu diesem Zeitpunkt aktuellen Version 2.2.1 von libVLC und allen nötigen Tools und Abhängigkeiten enthält. Die Idee ist, dass man als Entwickler den entsprechenden Container lokal ausführt und über einen Volume Mount sein Sourcecode mit dem Container teilt und baut. Somit kann das Editieren des Codes und das Arbeiten mit git und anderen Tools wie gewohnt auf dem lokalen Rechner statt finden. Nur zum Bauen muss der Container bemüht werden.

Das Qt4 Problem haben wir gelöst, indem wir einen Patch in libVLC während der Erstellung des Docker Images eingebaut haben, der zu einer Version von libVLC ohne Qt4 führt. Entgegen anfänglicher Bedenken ist das unproblematisch, weil Qt4 hauptsächlich für Benutzeroberflächen von Plugin-Einstellungen und ähnliches verwendet wird. Da wir libVLC lediglich einbinden und unsere eigene UI entwickelt haben, ist es für uns kein Problem, auf diese Funktionen zu verzichten.

Im Folgenden werde ich zeigen, wie man ein minimales C Programm, das eine Mediendatei mit libVLC wiedergibt, mit dem Image kompilieren und linken kann.

Das Image befindet sich auf unserem öffentlichen Repository, von dort können wir es erst einmal mittels pull auf unserem lokalen Rechner ziehen:

docker pull pulsarsolutions/libvlc_no_qt:2.2.1  

Und dann interaktiv ausführen:

docker run --rm -it pulsarsolutions/libvlc_no_qt:2.2.1 bash  

Nach dem o.g. Befehl sollte man sich in einer bash Shell im Container befinden. Damit kann man allerdings noch nicht viel anfangen, da es gar keinen Sourcecode zum kompilieren gibt. Das ändern wir jetzt. Wir gehen wieder aus dem laufendem Container indem wir

exit  

eingeben. Als nächstes legen wir ein neues Verzeichnis an

mkdir /home/marcelo/projects/vlc_minimal_sample  

und erzeugen dort eine neue C-Quelldatei test.c mit folgendem Inhalt:

#include <stdio.h>
#include <stdlib.h>

#include <vlc/vlc.h>

int main(int argc, char **argv)  
{
    libvlc_instance_t *inst;
    libvlc_media_player_t *mp;
    libvlc_media_t *m;

    // load the vlc engine
    inst = libvlc_new(0, NULL);

    // create a new item
    m = libvlc_media_new_location(inst, "http://www.sample-videos.com/video/mp4/360/big_buck_bunny_360p_5mb.mp4");

    // create a media play playing environment
    mp = libvlc_media_player_new_from_media(m);

    // no need to keep the media now
    libvlc_media_release(m);

    // play the media_player
    libvlc_media_player_play(mp);

    getchar();

    // stop playing
    libvlc_media_player_stop(mp);

    // free the media_player
    libvlc_media_player_release(mp);

    libvlc_release(inst);


    return 0;
}

Das Programm ist eine minimalistische Implementierung einer Videowiedergabe mit libVLC. Das Video wird direkt aus dem Internet abgespielt, daher sollte der Host, also die Maschine auf der der Container gestartet wird, auch mit dem Internet verbunden sein.

Unser Ziel ist es, diese Datei nun im laufenden Container zu kompilieren und zu linken, denn nur im Container sind die dafür nötigen Tools, Bibliotheken und Abhängigkeiten installiert. Um die Datei dem Container bereitzustellen verwenden wir einen sog. Volume Mount. Das bedeutet, dass ein lokales Verzeichnis (Volume) in ein Verzeichnis im Container gemounted wird. Damit sieht unser docker Aufruf jetzt so aus:

docker run --rm -it -v /home/marcelo/projects/vlc_minimal_sample/:/home/developer/src pulsarsolutions/libvlc_no_qt:2.2.1  

Damit wird das lokale Verzeichnis /home/marcelo/projects/vlcminimalsample auf das Verzeichnis /home/developer/src im Container gemounted. An dieser Stelle sei darauf hingewiesen, dass der Container einen Default-Benutzer namens developer anlegt. Dieser Benutzer hat die id 1000 und gehört einer Gruppe die ebenfalls die id 1000 hat. Wenn der lokale Benutzer auf dem Host eine andere Kombination von uid:gid hat, kann es zu einem Rechteproblem kommen. In einem zukünftigen Artikel werde ich beschreiben, wie man damit umgehen kann.

Nachdem wir den o.g. Befehl ausgeführt haben, können wir cd src im Container in das Verzeichnis wechseln, in das unsere Quelldatei liegt. Nun können wir diese wie folgt übersetzen:

gcc $(pkg-config --cflags libvlc) -c test.c -o test.o  
gcc test.o -o test $(pkg-config --libs libvlc)  

Im Anschluss daran sollte eine ausführbare Datei test im aktuellen Verzeichnis liegen. Mit

./test

kann die Datei ausgeführt werden. Da wir uns in der Kommandozeile befinden werden wir aber nicht viel zu sehen bekommen, die Shell wird höchstens versuchen, das Video im Text-Modus zu rendern. Als letzten Schritt in diesem Artikel werden wir nun die Ausgabe des Containers auf den lokalen X-Server im Host umleiten, so dass wir das Video-Fenster auch sehen können.

Das geschieht mit einem weiteren Volume Mount und der Übergabe der DISPLAY Umgebungsvariable und sieht dann so aus:

docker run --rm \  
  -v --net=host \
  -e DISPLAY -v \ /home/marcelo/projects/vlc_minimal_sample/:/home/developer/src \
  -it pulsarsolutions/libvlc_no_qt:2.2.1 bash

Indem wir die DISPLAY Umgebungsvariable sowie die Option --net=host verwenden, kann der Docker Container auf den X Server und somit auf das Display zugreifen.

Die Option --net=host stellt auf Produktivsystemen ein Sicherheitsrisiko dar, da es im Grunde das Netzwerk des Containers nicht kapselt. Daher sollte diese Option nur für lokale Umgebungen verwendet werden, die man selber kontrolliert.

Wenn wir nun

./test

ausführen, sollte das Video in einem neuen Fenster im Host abgespielt werden.

Das war nur ein kurzer Einblick in die Möglichkeiten die Docker bietet, um reproduzierbare Entwicklungsumgebungen bereit zu stellen. Aus Platzgründen sind hier viele Themen nicht erwähnt worden, wie z.B. Audio oder IDEs. Das wird dann Gegenstand zukünftiger Artikel sein.

]]>
<![CDATA[Leserliche require Anweisungen für mocha Unit Tests in Clean Architecture Node Applications]]>Bei Pulsar Solutions versuchen wir die Richtlinien von Clean Architecture zu befolgen, um Code zu produzieren, der testbar ist und unabhängig von Frameworks, UI, Datenbanken und sogar das Web. Gleichzeitig sollte der Zweck der Applikation offensichtlich werden, indem man sich die Dateistruktur ansieht. Das resultiert allerdings oft in einem weit

]]>
http://localhost:2368/2016/01/13/readable-require-statements-for-mocha-unit-tests-in-clean-architected-node-applications/50c71325-4fda-405b-956a-335b831c163bWed, 13 Jan 2016 21:33:17 GMTBei Pulsar Solutions versuchen wir die Richtlinien von Clean Architecture zu befolgen, um Code zu produzieren, der testbar ist und unabhängig von Frameworks, UI, Datenbanken und sogar das Web. Gleichzeitig sollte der Zweck der Applikation offensichtlich werden, indem man sich die Dateistruktur ansieht. Das resultiert allerdings oft in einem weit verzweigten Dateibaum, was zu unleserlichen und schwer wartbaren require Anweisungen führt.

In diesem Artikel liegt der Fokus darin, leserliche und wartbare require Anweisungen für die Unit Tests einer Anwendung zu ermöglichen. Der Einfachheit halber setze ich voraus, dass mocha als Testing Framework eingesetzt wird. Für andere beliebte Frameworks kann ein ähnlicher Ansatz verwendet werden.

Gehen wir von der folgenden Verzeichnisstruktur aus:

-- root
  -- node_modules
  -- src
    -- 0_externals
    -- 1_controllers_gateways_presenters
    -- 2_use_cases
      -- searchCats.js
    -- 3_entities
  -- tests
    -- ...
    -- 2_use_cases
      -- searchCatsTest.js
    -- ...
  -- ...

Dem entsprechend soll searchCatsTest.js den Code in searchCats.js testen. Mit mocha und der oben gezeigten Struktur würde die require Anweisung so aussehen:

var searchCats = require('../../../src/2_use_cases/searchCats');  

für einen Node Modul mit dieser Definition:

module.exports = searchCats;  

Das ist offensichtlich schlecht. Es ist unleserlich und, sollte sich die Verzeichnisstruktur aus irgend einem Grund nach einigen Monaten Entwicklung verändern, müssten alle require Anweisungen angepasst werden.

Wäre es nicht besser wenn wir schreiben könnten

var searchCats = require('2_use_cases/searchCats');  

und wir könnten das Root Verzeichnis global setzen? Leider funktioniert die o.g. Syntax nicht out-of-the-box, da require nicht weiss wo die Datei searchCats.js liegt.

Bevor wir weitermachen sollten wir einen Blick darauf werfen, wie mocha in der Kommandozeile aufgerufen wird:

mocha -R spec -u bdd ./tests  

Dieser Aufruf teilt mocha mit, dass alle Tests im Verzeichnis ./tests rekursiv auszuführen sind, dass der BDD Style verwendet werden soll und dass der Fortschritt im spec Format erfolgen soll. Da wir aber diesen Aufruf aus dem Root-Verzeichnis ausführen, überrascht es nicht, dass searchCats.js nicht gefunden wird. Wir kriegen eine Exception.

Googelt man ein wenig gelangt man schnell zu dieser interessanten Sammlung von Lösungen für ein ähnliches Problem aus der Node.js Welt: (Better local require() paths for Node.js) Ich bevorzuge Lösung Nummer 7, den globalen Wrapper um require. Aber wie können wir diese Technik auf unsere Mocha Tests anwenden? Klar ist, dass es nicht funktionieren wird, wenn mocha weiterhin mit dem o.g. Aufruf gestartet wird. Glücklicherweise kann man einen eigenen Mocha Runner als minimalistische Node.js Anwendung implementieren. Wie der Zufall so will hat das jemand bereits getan: (Starting Mocha Tests Programmically With Runner.js).

Alles was wir jetzt tun müssen, ist den Wrapper um require herum am Anfang des Runners einzubauen. Der Runner sieht dann so aus:

var fs = require('fs'),  
    Mocha = require("mocha"),
    path = require('path');

global.rootRequire = function (name) {  
    return require(__dirname + '/src/' + name);
}

// Our Mocha runner
var mocha = new Mocha({  
    ui: "bdd",
    reporter: "spec",
    timeout: 60000,
    slow: 10000
});

// Files which need to be ignored
var avoided = [  
    "node_modules"
];

// Add the tests to the Mocha instance
(addFiles = function (dir) {
    fs.readdirSync(dir).filter(function (file) {
        if (!~avoided.indexOf(file)) {
            if (fs.statSync(dir + '/' + file).isDirectory()) {
                addFiles(dir + '/' + file);
            }
            return file.substr(-3) === '.js';
        }
    }).forEach(function (file) {
        mocha.addFile(dir + '/' + file);
    });
})(path.join(process.cwd(), process.argv[2] || "."));

// Run the files in Mocha
mocha.run(function (failures) {  
    process.exit(failures);
});

Damit sieht jetzt die require Anweisung so aus:

var searchCats = rootRequire('2_use_cases/searchCats');  

und der Aufruf von Mocha sieht so aus:

node runner.js tests  

Viel besser oder?

]]>