Why rapid deployments are so important

What's the problem about rare deployments?

If your release cycle is very long your customer will start to ask for things which will make the system very complex. Why? Because your customer want their ideas always as fast as possible implemented. So your customer will start thinking about a system that is completly configurable while running. This new requirements will cause in a complex and less maintainable system.

But... I can't release so often.

No, you can! It's always possible to release in short cycles. Everything you need is the right set up:

  • Continuous integration is the important thing. Without a CI-Server you won't be able to release in short cycles.
  • Test automation. You need unit tests, integration tests and for some cases UI tests.
  • Monitoring. Your development team should always have an eye on the log files. If you don't know your problems in time you will have big trouble later...
  • Automated deployment. If your deployment isn't automated yet and you want to deploy in short cycles you will have no time left to develop software.
  • Code management with GIT. This tool supports your rapid deployments in such an dramatic way; it will blow you away.
  • A very closely collaboration with your customer to manage the requirements. Don't write abstract requirements -- use examples as much as possible.

This is IMHO the minimum set up that you need if you want to have a continuous deployment.

What do you get?

Your customer get what he want much faster. Your developer don't have to create unmaintainable software but they can create awesome features. Developer and customer will love this new way to work. Rapid deployments ends up in a happy collaboration between customer and developer. Not more but also not less.


Refactoring

Auswirkungen von Altlasten auf die Neuentwicklung von Features.

Altlasten in Softwaresystemen sind beinahe immer alte Anforderungen, die von anderen Personen vor längerer Zeit umgesetzt wurden. Trotz Dokumentationen in Form von JIRA-Tickets, WIKI-Einträgen und Testdokumentation ist es sowohl für Softwareentwickler als auch für das Anforderungsmanagement kaum möglich all diese Informationen in adäquater Zeit auszuwerten, um ein neues Feature kostengünstig liefern zu können.

Die in der Praxis gängige Herangehensweise, um dieses Problem zu lösen ist daher einfach nachzuvollziehen: Man versucht möglichst nichts an der bestehenden Funktionalität zu ändern (d.h. der Softwareentwickler versucht bestehenden Code nicht zu verändern) und fügt seine neuen Änderungen einfach hinzu. Dieses Vorgehen funktioniert bei den ersten Änderungsanfragen auch wie gewünscht. Nach einiger Zeit stellt sich jedoch eine Situation ein, die es unabdingbar macht bestehenden Code anzufassen. Spätestens, wenn neue Anforderungen im Widerspruch zu alten stehen. Dies ist der Knackpunkt an dem nun auch alle alten Überlegungen mit bedacht werden müssten, um den Überblick über das System beibehalten zu können. Das Produktrisiko steigt enorm an und die QA-Phase verlängert sich deutlich stärker als nur linear (alte Anforderungen müssen "erforscht" und intensiv nachgetestet werden).
Folge: Die Kosten für Neuentwicklungen steigen rasant an, jedoch sind die eben genannten Punkte den Auftraggebern oft nicht transparent.

Warum man ein System nicht vorab so planen kann, dass es auf alle Eventualitäten erweiterbar ist.

In klassischer Softwareentwicklung ist eine Strategie gegen das Altlastenproblem die Software so zu planen, dass das Altlastenproblem nie entstehen wird. Das heißt, dass die Software ohne Änderung bestehender Softwareteile ewig erweiterbar bleibt. Dass dies ein reiner Wunschgedanke bleibt, ist spätestens mit einer fachlichen Anforderung belegt, die im Widerspruch zu bestehenden, und bereits umgesetzten Anforderungen steht. Aus Geschäftsstrategischer Sicht ist es einleuchtend, dass eine solche Situation in einer schnelllebigen Welt sehr oft eintreten kann. Einen statischen Plan zu entwickeln steht auch im gravierenden Widerspruch zur dynamischen Komplexität, die die geschäftliche Situation hier deutlich besser abbildet (siehe auch "Scaling Lean & Agile Development: Thinking and Organizational Tools for Large-Scale Scrum: Successful Large, Multisite and Offshore Products with Large-scale Scrum", Craig Larmen und Bas Vodde).

Wie man sich von Altlasten befreit und Agilität erreicht.

Wie aus dem ersten Punkt hervorgeht ist es sehr einfach neue Altlasten aufzubauen. Welche Lösungen schlägt nun die Wissenschaft und Praxis vor, um das Altlastenproblem zu lösen?

Die einstimmige Meinung unter agilen Softwareentwicklern ist, sich der Tatsache bewusst zu werden. Wenn man sich im klaren darüber ist, dass Softwaresysteme über die Zeit fehlerhaft und schwergewichtig werden, kann man Maßnahmen umsetzen, die das kontinuierlich abmildern.
Dazu gehören folgende Punkte:

1) Testgetriebene Softwareentwicklung (Test-Driven Development, Jeff Langr, http://pragprog.com/magazines/2011-11/testdriven-development, Practices for Scaling Lean and Agile Development: Large, Multisite, and Offshore Product Development with Large-Scale Scrum, Craig Larmen und Bas Vodde)
2) Spezifikationen anhand von Beispielen (Specification by Example, Gojko Adzic)
3) Kontinuierliche Upgrades von eingebundener Fremdsoftware
4) Die einfachste Lösung umzusetzen, die die Anforderung erfüllt (“You Ain’t Gonna Need It”, http://de.wikipedia.org/wiki/YAGNI)

Wie äußern sich diese Maßnahmen mittel- bzw. langfristig aus monetärer Sicht?

Ad 1) Testgetriebene Softwareentwicklung ist trotz seines Namens nicht gleichzusetzen mit Software zu testen ("Test-first coding is not a testing technique", Ward Cunningham). Vielmehr führt es implizit zu einer jederzeit änderbaren Software, durch das kontinuierliche schreiben von automatischen Tests und dem noch wichtigerem kontinuierlichem Refactoring des neu geschriebenen Codes. Zusammengefasst: Die Kosten für Neuentwicklungen bleiben über die Zeit relativ konstant.

Ad 2) Wenn Anforderungen mit klaren Beispielen dokumentiert sind, werden diese schneller verstanden. Missverständnisse werden reduziert und die rückblickende Information was umgesetzt wurde ist klarer. Ebenso lassen sich Beispiele einfach automatisiert testen, wodurch Anforderungen kontinuierlich qualitativ gesichert werden können, ohne zusätzlichen Kostenaufwand über die Zeit.

Ad 3) Veraltete Fremdsoftware führt langfristig dazu, dass keine Softwareentwickler mehr gefunden werden, die mit diesen Versionen arbeiten können. Das Umsetzen neuer Features wird bei alter Fremdsoftware also verlängert, wodurch die Kosten steigen.

Ad 4) Das Feature wird so umgesetzt wie gefordert, aber auch nicht mehr. Der Aufwand wird auf das nötigste reduziert und Kosten für Planungs-Overhead werden obsolet. Der Return of Investment steigt.

Warum das eine kontinuierliche Tätigkeit bleiben muss

Refactoring ist keine Tätigkeit, die in einem Entwicklungszyklus erledigt werden kann, sondern es ist eine kontinuierliche Tätigkeit. Man kann diese Aufgabe am besten mit der Büroreinigung vergleichen: Würde man das Büro nur einmal im Jahr reinigen, hätte man auch hier einen deutlich höheren Aufwand und das Unbehagen in der übrigen Zeit wäre bei allen Beteiligten nach kurzer Zeit sehr groß.


Tools als Selbstzweck? Oder warum wir Tools nutzen.

Durch den agilen Hype werden immer mehr Tools (hauptsächlich Softwareprogramme) in Frage gestellt, die bisher zum erledigen vieler Aufgaben eingesetzt wurden. Die Frage ist, wieso passiert dieser gedankliche Wandel und was ist die Ursache, die dazu führte?

These: Tools (z.B. Softwareprogramme) haben die Absicht die Arbeit zu beschleunigen.

Meiner Meinung nach ist die grundlegende Idee Tools einzusetzen, wiederkehrende Arbeiten zu beschleunigen. Selbst die Erfindung des Computers war eben dieser Intention entsprungen. Denn Konrad Zuse wollte bestimmte Rechnungen beschleunigen, da diese sehr monoton und mühselig waren.

Dieses initiale Ziel bei der Einführung von beliebigen Tools vergessen wir allzu oft. Häufig werden Tools nicht anhand eines Beschleunigungsvorteils ausgewählt, sondern anhand der Funktionen, die uns das jeweilige Tool bietet; egal ob wir diese Funktion benötigen oder nicht. Daraus ergibt sich meine zweite These:

Ein qualitativ hochwertiges Tool muss den Prozess unterstützen und nicht der Prozess das Tool.

Das heißt im ersten Schritt gilt es die Arbeitsweise und den Prozess zu verbessern. Erst im zweiten Schritt wird diese Arbeitsweise durch ein Tool nochmals beschleunigt. Was allzu oft passiert ist jedoch, dass ein Tool eingesetzt wird in der Hoffnung es würde den Prozess per se beschleunigen. Das Gegenteil ist dann der Fall, d.h. die Arbeit wird dadurch behindert, dass die Arbeitsweise mit dem Tool erst erlernt werden muss. Das jeweilig eingesetzte Tool, ob es nun in Form einer Software oder eines Blatt Papiers und Stift in Erscheinung tritt, darf somit per se kein Selbstzweck sein. Woran sich sofort meine dritte und letzte These anschließt:

Ein Tool muss den gesamten Arbeitsfluss beschleunigen und nicht nur die Arbeit einzelner.

Dieser Punkt ist am schwersten zu evaluieren und auch nur noch anhand eines Beispiels zu erklären.

Angenommen zwei Personen Anton und Berta arbeiten zusammen. Anton wohnt in Europa und Berta in Australien. Falls Anton für sich feststellt, dass er am schnellsten Texte handschriftlich verfasst, die aber von Berta gegen gelesen werden müssen, behindert das Tool "Papier+Stift" möglicherweise den Gesamtfluss. Hier ist nun zu prüfen, ob eine E-Mail den Prozess beschleunigt oder nicht. Für jeden ist einsichtig, dass es sehr wahrscheinlich ist, dass Anton für eine E-Mail kaum um einen derartig großen Faktor länger benötigen wird, dass sich der Einsatz eines PCs als Tool anstelle von Papier und Stift nicht lohnen würde.

Für ein beliebiges Tool eines komplexeren Ablaufs (Prozess) ist eine solche Fragestellung nicht so einfach bzw. so pauschal zu beantworten. Genau in solchen Fällen machen wir gerne den Fehler und suchen ein Tool anhand der Features und nicht anhand unserer Ziele aus. Doch auch hier sollte der Grundsatz "You ain't gonna need it" (YAGNI) beherzigt werden.


Süd-Nord-Gefälle oder doch Nord-Süd-Gefälle?

Wenn man den deutschen IT-Arbeitsmarkt eine Weile beobachtet fällt auf, dass "hippe" Technologien und Start-Ups vermehrt im Norden Deutschlands zu finden sind. Im Süden jedoch ist die Enterprise-Welt zu Hause.

Doch was führt zu dieser örtlichen Trennung und wozu könnte sie langfristig führen?

Gründe

Meine These: der Norden Deutschlands (die Region um Berlin) ist finanziell ein günstigerer Standort verglichen mit dem Süden Deutschlands um München oder Stuttgart.
Dieser einfache Grund führt unweigerlich dazu, dass viele Start-Ups sich im Norden um Berlin niedergelassen haben. Diese These trifft jedoch nicht auf alle nördlichen Regionen zu. Beispielsweise Hamburg. Doch Hamburg verbindet den aufstrebenden Flair Berlins mit dem Klischee der Münchner-High-Society. Diese ausgesprochene Mischung zieht ebenso viele Jungunternehmer in die nördliche Stadt.

Junge IT-Unternehmen können nur bestehen, wenn sie einen sehr hohen Return-of-Investment (ROI) erwirtschaften. Genau auf dieses Prinzip sind alle modernen agilen Projektmanagement-Methoden ausgelegt. Ob die eingesetzte Methodik Scrum oder Kanban genannt wird ist am Ende egal. Doch neben der Methodik haben auch die eingesetzten Technologien einen großen Einfluss auf den Erfolg oder Misserfolg eines IT-Start-Ups. Technologien, mit denen sich per se nicht schnell entwickeln lässt, da sie lange Compilezeiten erfordern oder ein umständlichen Deploymentprozess benötigen, stehen im Widerspruch zu einem hohen ROI. Um auf dem Markt bestehen zu können muss der Nutzen für den Anwender sehr hoch sein und mit geringem Aufwand erreicht werden.

Spezielle (Neue) Technologien und moderne Methoden reduzieren sowohl die Compilezeiten als auch die Aufwände eines Deploymentprozesses. Ruby, Python, JavaScript, PHP etc. sind Beispiele für diese Technologien. Doch auch Objective-C mit der guten Unterstützung von Apple durch XCode zähle ich zu diesen Technologien. Zudem werden moderne Tools benutzt, um die Arbeit zu erleichtern. SVN gehört in Start-Up Kreisen zum alten Eisen. GIT, Mercurial, Jenkins, Bash-Skripts (nicht zuletzt durch den Erfolg von Apple und Linux) sind die Wahl (UPDATE: Warum, Gründe für einen Tooleinsatz). Wer kennt in diesem Zusammenhang nicht die Streitigkeiten zwischen GIT und SVN-Nutzern? Die Antworten auf solche "hippen" technologien aus dem Entersprise-Umfeld hören sich oft so an: "not enterprise ready".

Folgen

Meine These zu den Auswirkungen ist klar: "Motivierte, meist junge, sehr gute Arbeitskräfte wandern in den Norden ab".

Wenn es Bayern und Baden-Württemberg nicht schaffen hippe Start-Ups anzuziehen, werden auch immer mehr sehr gute junge Fachkräfte abwandern. Diese fehlen selbstverständlich auch den sogenannten "Enterprise-Unternehmen". Hier sehe ich definitiv Handlungsbedarf sowohl bei den Unternehmen als auch bei den Landesregierungen, um eine ausgeglichene Gründerszene in Deutschland zu etablieren.


Web development tools

Development-tools are very helpful. I give you a short list with useful web development tools which I use in my daily work:

  • eclipse is one of the greatest development-IDE which I know.
  • aptana plug in. Absolutely necessary for web developer who work with eclipse.
  • JSLint validation plug-in. You want the good parts of JavaScript? Then you need this plug-in!
  • git / svn plug-in. You know why...
  • Build tool: ant. You can also use "make" but I prefer "ant" because it doesn't depend on an operating system.
  • Unit tests: JSTestDriver combined with sinon.js. Awesome! (btw. you should read Test driven JavaScript development.)
  • Acceptance tests: Selenium, Watir. I use Selenium but i read that watir should be a bit better... If you know more about please share your experience in the comments below.
  • Debugging: Firebug-Plug-in and the build-in capabilities in google chrome.
  • Performance: YSlow. Every web developer should know it.
  • Continuous integration: Jenkins.
  • JavaScript/CSS compressor: YUI-compressor

Monitoring in Webapplications

Webanwendungen werden immer häufiger auch genutzt, um near-real-time Daten zu visualisieren. In HTML 5 ist dafür der Websocket definiert. Bis wir diesen nutzen können, müssen wir auf andere Techniken zurückgreifen. Long-Polling oder Bayeux Protocol sind hier die häufigsten. Jedoch ist es nicht immer möglich diese einzusetzten. Eine Alternative wäre eine "Infection" der Webseite mit einer weiteren Technologie, um kein traditionelles Polling nutzen zu müssen.

Das Problem.

Übertragen wir das technische monitoring Problem in ein Beispiel unseres Lebens: Ein Kollege arbeitet gerade an einem Plakat. Sobald es fertig gedruckt ist, sollen wir es abholen. Woher wissen wir, wann wir es holen sollen?

Old school.

Um daten per Ajax auf herkömmlichen Weg zu überwachen erstellt man eine Funktion, die in periodischen Zeitabständen die Daten vom Server holt. Damit bekommt man häufig überhaupt keine Veränderung, muss den Server aber dennoch "stubsen" und verbraucht Bandbreite.
In unserem obigen Beispiel müssten wir in einem bestimmten Zeitintervall, sagen wir alle fünf Minuten, zu unserem Kollgen laufen und ihn fragen, ob wir das Plakat schon mitnehmen können. Wenn nicht, gehen wir unverrichtete Dinge wieder zurück auf unseren Platz.

Long-Polling.

Mit Long-Polling frägt man genauso immer und immer wieder den Server an, jedoch wartet man auf dem Server auf die Antwort.

In unserem obigen Beispiel würden wir also einmal zu unserem Kollegen laufen und dort solange warten, bis er mit dem Plakat fertig ist und wir es mitnehmen können. Anschließend gehen wir erfolgreich zurück zu unserem Platz, legen das Plakat ab und gehen wieder zu unserem Kollegen um wieder auf das nächste Plakat zu warten.

Infect your website.

Mit einer Ifection nutzt man den Umstand, dass auf nahezu allen Clients Plugins installiert sind. Man kann also wählen ob man eine Seite mit Adobe Flash oder einem Websocket oder Silverlight infizieren will. Ich gehe hier von Adobe Flash aus.
Wir starten also eine unsichtbare Flashanwendung, die nur eine Aufgabe hat: Sich mit einem Socket auf dem Server zu verbinden. Sobald Daten auf dem Server vorhanden sind, wird eine kleine Message "data available" an den Clienten verschickt. Dieser startet dann die Ajax-Anfragen. Der Vorteil die Daten nicht über den Socket zu senden, ist keinen Code zu duplizieren und den Dienst bei Bedarf jederzeit weglassen zu können. Sollte kein Flashplugin installiert sein, kann so einfach auf periodisches Polling zurückgegriffen werden. Der Vorteil gegenüber Long-Polling ist, dass kein Prozess blockiert wird und keine Aufwändigen Serveranwendungen wie beim Bayeux Protokoll nötig sind. Nur eine simple Socketanwendung, die die entgegengenommenen Daten verwirft und durch z.B. einem Hook-Up eine "data available" Message verschickt.

In unserem obigen Beispiel würden wir zu unserem Kollegen nicht hingehen, sondern ihn vorher anrufen und diesen Anruf einfach neben uns liegen lassen. Sobald unser Kollege uns übers Telefon Bescheid gibt, dass das Plakat fertig ist, machen wir uns auf den Weg. Wäre unser Telefon einmal kaputt, könnten wir auf jeden Fall ohne Probleme wieder periodisch zu ihm laufen.

Fazit.

Websocket sind die definitiv beste Antwort auf near-real-time monitoring. Doch bis es soweit ist, dass diese Technologie in allen gängigen Browsern verfügbar ist, wird noch etwas Zeit verstreichen. Bis dahin ist eine Alternative zu nutzen. Ist man an bestimmte Servertechnologien gebunden und will trotzdem skalierbar bleiben ist long-polling oft nicht möglich. Eine Alternative bietet hier die "Infection".


Lego oder Playmobil?

Schon in der frühsten Kindheit steht jeder irgendwann vor der Frage: Bin ich ein Anhänger der Legosteine oder liebe ich doch das Spiel mit den Playmobil-Figuren mehr? Die Zeit verrinnt. Wir werden älter. Unser Spielzeug änderte sich. Es wird elektronisch und wir fragen uns mit welcher Programmiersprache wir am liebsten spielen. Objektorientiert, funktional, deklarativ oder doch eher Logikbasiert? Und wieder diese Frage an jeden einzelnen: Will ich kleine, einfache generische Grundelemente oder lieber die großen fertigen Figuren und Objekte, die aus den Fabriken kommen? Ich versuche in der Analogie der Spielzeuge zu bleiben und überlasse es euch die Parallelen zu den Sprachen zu ziehen.

Ich mag Playmobil, aber...

... wenn mir das Seeräuberschiff nicht mehr gefällt, weil sich die Welt und ich verändert haben, ist es schwer daraus ein Haus zu bauen. Natürlich kann ich mich daran machen das ein oder andere Fenster hinein zu bohren. Auch kann ich es im Spielfeld neu arrangieren und mein Bot auf Grund laufen lassen. Doch im Prinzip ist die Spiellogik mit dem Spielzeug viel zu dicht vermascht. Also versuche ich die Logik meines Spiels so weit wie möglich aus meinen Spielsachen zu halten und kaufe nur noch Figuren, die neutral aussehen und mit denen sich letztlich in allen Umgebungen gut spielen lässt. Ändert sich das Spiel, so muss ich mir jetzt keine neuen Spielsachen mehr kaufen. Klasse, oder etwa nicht? Nun, meine Spielsachen haben mittlerweile jegliche Individualität verloren und so versuche ich sie wieder anzupassen. Aus den allzu gleichen Figuren werden Individuen. Die Häuser übernehmen Aufgaben und bekommen einen Anstrich. Doch manches mal ziehen solche Anpassungen weitere Veränderungen nach sich, die ich anfangs gar nicht ins Spiel eingeplant hatte. Irgendwie fängt mir das ganze über den Kopf zu wachsen und ich frage mich: Bin ich noch Herr über mein Spielzeug oder haben sich die vielen Änderungen in meinem Spiel selbstständig gemacht? Wie bekomme ich wieder die schöne heile Welt zurück in der das eine zum anderen passt und alles da ist, wo es hingehört? Und wieso habe ich zuerst alles brav getrennt, wenn ich es nun doch wieder allzu sehr anpasse?

Nun, ich versuche über den Tellerrand zu schauen und versuche das Gute anderer Spiele zu kopieren. Ich finde Legobausteine, die ganz und gar unabhängig sind. Ich kann aus ihnen Spielfiguren erschaffen und Roboter bauen, die mir mein Spielzeug individualisieren. Unglaublich, sie sind total generisch. Es gibt nur wenige verschiedene Fertigteile, die ich aber mit vielen anderen kombinieren kann, wobei das Ergebnis nur von den verschiedenen angedockten Bausteinen abhängt.

...Legosteine sind einfach zu allem zu gebrauchen.

Meine Spiellandschaft wird irgendwie wieder etwas klarer. Da sind einige Figuren und Werkzeuge mit denen ich meine Steine zu neuen Unendlich großen Gebilden zusammen setzten kann. Durch meine neuen kleinen Helfer kann ich keine Änderungen mehr übersehen, denn all die Änderungen, die zusätzliche Auswirkungen haben an die ich bisher nicht gedacht hatte, erlauben mir meine neuen Werkzeuge nicht mehr. Ich behalte also den Überblick. Ich bin wieder Herr meines Spiels.

Und die äußeren Werte zählen doch!

Doch besonders hübsch sieht mein neues Spiel leider noch nicht aus. Aber dafür, ließ ich mir sagen, gibt's Dekoratöre und Designer. Mit denen muss man nur noch abstimmen was sie an wem machen sollen. Total einfach. Fast schon zu banal.

Und wenn ich ständig unterwegs bin und unterschiedliches Spielzeug zu Verfügung habe?

Dann muss ich wohl den Spieler unabhängig von meinem Spiel machen und in den Spielregeln nur noch von den Diensten des Spielers sprechen. Falls ich dann Spielfiguren zur Hand habe, die für ein Spiel passen, kann ich sofort loslegen, ganz egal wo ich bin.

Und die Frage vom Anfang ist jetzt doch ganz einfach zu beantworten, oder? Meine Spielkiste ist jedenfalls mit vielen unterschiedlichen Spielsachen gefüllt, so macht's mir am meisten Spaß!

Am Ende dieses etwas anderen Informatik-Blogs wünsche ich euch allen "a lot of fun" beim spielen!


Proxy-Einstellungen für Windows-Console setzen

Worum es geht

Man ist mit seinem Windows-PC in einem Netzwerk angemeldet, in dem man nur über einen Proxy in das WWW kommt. Für die Webbrowser sind freilich entsprechende Einstellungen leicht durchzuführen, jedoch gelten diese meist nur in dem entsprechendem Programm. Ein Aufruf von ping auf der Console bekommt weiterhin keinen Zugriff auf das Internet.

Lösung

Mit dem in Windows XP vorhandenen Programm proxycfg lassen sich die Einstellungen entweder manuell setzen, oder vom Internet Explorer übernhemen. Beispielsweise werden die IE-Einstellungen durch proxycfg -u übernommen. Anschließend lässt sich auch ein ping auf einen Internet-Computer absetzen.


(Download) Java XSLT 2.0 Transformator

Worum es geht

XSLT ist eine auf XML basierte funktionale Sprache, die zur Umwandlung von XML-Dokumenten in eine andere XML bzw. Plaintextdarstellung dient. XSLT der Version 1.1 hat sich bereits auf breiter Front durchgesetzt und wird vom .Net-Framework 3.5 und Firefox unterstüzt. Die Nachfolgerversion 2.0, die einige nützliche Funktionalitäten bietet, ist bisher noch nicht so verbreitet. Das Framework SAXON B bietet ein, unter der MPL 1.0 stehendes, Framework an, mit dem man die W3C-XSLT 2-Version verwenden kann.

Um nun XML-Dokumente ganz einfach umwandeln zu können biete ich ein einfaches ausführbares JAR-File an, das SAXON B der Version 9.1 verwendet und auf ein XML-Dokument ein XSLT-Dokument anwendet. Continue reading »