Our German speaking readers already know from the last post that we contribute to the jQAssistant project. We do so because we use jQAssistant in normal everyday work. There are a bunch of architecture and design rules to keep our projects clean and in shape.

From time to time there is the need to have a more powerful search mechanism than even the awesome “Search Structurally” feature of IntelliJ IDEA provides. Wouldn’t it be nice to have the power of database queries to find classes? The good news is: you have! Today we published our IntelliJ plugin to GitHub. You find it at GitHub It’s licensed under the GPLv3. The bad news is: it’s still an early version, so you don’t find it in the JetBrains Plugin Repository. You have to clone the project an build the plugin yourself. Please follow the instructions in the README file.

Feel free to file issues and send pull requests.

Was ist jQAssistant?

jQAssistant ist ein Werkzeug zur Sicherung der Codequalität. Es scannt die Artifakte des Projekts - Klassen, Property-Dateien, XML-Descriptoren usw. - und speichert die Daten in der Graphendatenbank Neo4J. Auf diesen Daten werden Analysen durchgeführt. Regeln können definiert und deren Einhaltung automatisch geprüft werden. Zum Beispiel können Namenskonventionen für Klassen, die Abhängigkeitsbeziehungen zwischen Paketen oder die Verwendung unerwünschter Klassen (z.B. java.util.Date) geprüft werden.

Die Datenbank kann aber auch als Server gestartet werden. Mit einer Webschnittstelle kann man den Code erforschen oder neue Regeln ausprobieren.

Die Mächtigkeit dieses Ansatzes geht weit über bisherige Werkzeuge dieser Art hinaus. Eine Graphendatenbank ist hervorragend für diesen Zweck geeignet. Über die Neo4j-Abfragesprache “Cypher” ist es leicht möglich, Suchen zu definieren, die in einer IDE nicht möglich sind. Mittels Cypher werden auch die definierten Regeln geprüft. Alle Daten stehen dem Nutzer direkt zur Verfügung.

Entwickelt wird jQAssistant von der Firma Buschmais, ansässig in Dresden. Der initiale Commit auf GitHub erfolgte im März 2013. Auf Maven Central ist der Meilenstein 3 von Version 1.0 publiziert, auf GitHub kann man schon den Snapshot von Meilenstein 4 beziehen. Das Final Release wird nicht mehr lange auf sich warten lassen.

Aktuell gilt die Apache Licence 2.0. Es ist jedoch beabsichtigt, aus Lizenzkompatibilitätsgründen auf die GPL umzusteigen.

Weitere Metriken

Mittels der importierten Standarddaten kann man schon sehr gut strukturelle Prüfungen und Abfragen definieren. Im Buildprozess fallen aber noch eine Reihe weiterer Daten an. Es liegt nahe, auch diese in die jQAssistant-Datenbank zu importierten. Da jQAssistant explizit für Erweiterungen mittels Plugins entworfen wurde, ist das Importieren nicht schwer. Bei Kontext E haben wir deshalb jQAssistant-Plugins für die wichtigsten Testartefakte geschrieben.

Üblicherweise wird die Testabdeckung nach Zeilen und Zweigen für Unit Tests gemessen. Häufig werden damit auch Vorgaben verbunden, deren Verletzung den Buildprozess abbrechen. Wir verwenden jacoco, welches die Ergebnisse als XML exportieren kann. Diese XML-Datei lesen wir mit einem Scanner-Plugin ein. Einige Cypher-Statements stellen die Verbindungen zu den vorhandenen Klassen und Methoden her.

Sehr verbreitet ist die statische Codeanalyse mit FindBugs. Viele Fehlermuster werden damit gefunden. Auch FindBugs schreibt die Ergebnisse als XML, welches wir mit einem zweiten Scanner-Plugin einlesen. Die jQAssistant-Daten werden wieder mittels Cypher mit den FindBugs verbunden.

Als weiteres wertvolles Tool zur statischen Codeanalyse setzen wir Checkstyle ein. Es überrascht nicht, dass dieses eine XML-Datei schreibt, die wir einlesen und die Daten mit den vorhandenen verknüpfen.

Bisher haben wir die von den Werkzeugen ermittelten Metriken jeweils einzeln weiterverarbeitet. Mal mit XSLT, mal mit Groovy-Scripten. Damit wurden aus den Rohdaten Indikatoren gewonnen, die eine sinnvolle Codequalitätssicherung ermöglichen. Der CI-Server bricht den Build ab, wenn die Indikatoren auf eine zu schlechte Codequalität hindeuten.

Jetzt werden die Daten nicht mehr einzeln ausgewertet, sondern sind miteinander verbunden und an die Codestruktur gebunden. Das ermöglicht eine neue Dimension der Auswertung und die Verfeinerung der Indikatoren. Außerdem können neue Indikatoren eingeführt werden, die bisher mangels passender Datenlage nicht möglich waren.

Als Beispiel sei eine Codestelle genannt, die so geschrieben ist, wie eine vorgeschriebene Bibliothek es verlangt. Checkstyle und FindBugs warnen zu recht, aber die Codestelle ist sehr detailliert getestet. Damit wird sie akzeptabel.

Obwohl weder jQAssistant noch unsere Plugins final als 1.0-Version veröffentlich wurde, sind sie aber schon so stabil und funktionsreich, dass sie im täglichen produktiven Einsatz wertvolle Dienste leisten. Wenn der CI-Server sagt, dass an einer Stelle nachgebessert werden muss, dann ist das auch fast immer der Fall.

Stand der Implementierung

Die Plugins sind wie jQAssistant selbst in der Verwendung sehr stabil, aber die Programmierschnittstellen ändern sich noch. Das bezieht sich einerseits auf die Java-API, andererseits aber auch auf das Datenmodell in der Datenbank. Das bedeutet, dass nicht immer die letzten GitHub-Commits von jQAssistant und den Plugins miteinander kompatibel sind. Mit dem Erreichen der finalen Version 1.0 sind diese Probleme dann aber ausgeräumt und man kann beides als normale Dependency im Projekt eintragen.

Lizenz

Für die Kontext E Plugins für jQAssistant wurde noch keine Lizenz deklariert, d.h. vorerst unterliegt die Software dem gesetzlichen Urheberrechtsschutz. Vorgesehen ist aber, dass sie dieselbe Lizenz wie jQAssistant bekommen. Wie oben erwähnt ist die GPL zu erwarten, so dass auch die Plugins unter die GPL gestellt werden.

Beziehen und benutzen

Die Kontext E jQAssistant Plugins werden auf GitHub gehostet. Bis eine offizielle Version über Maven Central beziehbar ist, muss man sich den Quellcode von GitHub besorgen und per gradlew selbst bauen. Voraussetzung ist, dass der aktuelle Snapshot von jQAssistant im lokalen Maven Repository installiert ist.

Im Zielprojekt muss man dann jQAssistant und die Plugins als Dependencies eintragen. jQAssistant selbst kommt mit einer engen Maven-Integration. Kontext E hat einen Kommandozeilen-Runner gespendet. Somit kann man seine Projekte auch per IDE, mit einem Batch-Skript, per ant, gradle oder von anderen Tools und eigenen Projekten aus starten.

Wozu automatische Akzeptanztests?

Die Frage stellt sich heutzutage kaum noch, über Sinn, Zweck und Notwendigkeit von automatisierten Akzeptanztests wurde schon erschöpfend diskutiert. Die wichtigsten Argumente im Überblick:

  • manuell testen ist zu aufwändig, nicht testen ist unprofessionell und kommt nicht in Frage
  • für Continuous Delivery sowieso Voraussetzung
  • in Brownfield-Projekten sind automatische Akzeptanztests leichter nachträglich hinzuzufügen als Unit Tests
  • sie dienen der Anforderungsanalyse und -dokumentation
  • und sind dabei genauer als Prosa
  • sie sind Bestandteil der Testpyramide

Damit ist klar, dass nicht die Frage ob, sondern wie im Vordergrund steht.

State of the art

Aktuell werden eine Reihe von Tools verwendet, z.B. Cucumber, SpecFlow, JBehave oder FitNesse. In einem Artikel auf jaxenter wurde von Lean Modeling berichtet.

Wir haben auch Erfahrungen gesammelt mit Office-Dokumente, die speziell formatierte Tabellen enthalten und auf dem CI-Server in ausführbare Testspezifikationen umgewandelt werden konnten. Der Vorteil ist, dass die Fachabteilung mit bekannten Tools wie Word oder LibreOffice Writer arbeiten kann, Bilder, beschreibende Texte usw. leicht einbindbar sind und damit das Dokument den herkömmlichen Spezifikationsdokumenten sehr ähnlich sind. Die Testerstellung war aufwändig, fehlerträchtig, langwierig und mühselig, weil es kein Syntaxhighlighting, keine Codeverwollständigung, keine Refactoringhilfe usw. gibt.

Allen diesen Ansätzen ist gemein, dass die Formulierung in Text dann als Wiederholung in Code auftritt mit den üblichen Problemen: Verletzung des DRY-Prinzips, Schwierigkeiten beim Refactoring, Verlinkung zwischen den Artefakten etc. Der Text ist nicht ausführbar, der Code hingegen ist nur Programmierern verständlich – egal wie viel Mühe sich Frameworks mit Internen DSLs geben. Sie bleiben an die Syntax der Hostsprache gebunden und “können nur Text”.

Außerdem sind Features zur Verwaltung wie Filterung, Sortierung, Fortschrittsverfolgung etc. keine First Class Citizen. Und von der Einbettung/Verlinkung zu weiteren Artefakten wie z.B. Import-/Export-XML-Dateien, Layoutvorlagen oder Beispieldokumente kann man nur träumen (oder sich eigene IDE-Plugins schreiben).

Kurz zusammengefasst: es gibt keine IDE für Anforderungserfassung, -verwaltung und -testausführung.

Domänenspezifische Sprachen

Spezifikationen werden in Zusammenarbeit erstellt. Das ist bei ausführbaren Spezifikationen nicht anders. Notwendige Voraussetzung ist, dass alle Beteiligten dieselbe Sprache sprechen. Damit ist nicht nur die Landessprache gemeint, sondern in diesem Fall vor allem Begriffe und Notationen aus der Domäne. Keinesfalls ist aber eine Programmiersprache gemeint. Die oben genannten Ansätze haben aber alle gemein, dass sie zur Ausführung eine Interne DSL einer General Purpose Language (GPL) benutzen. Diese gibt die Konkrete Syntax vor, die auf die Fachabteilung eher abschreckend wird.

Besser ist es, sich von der GPL zu lösen und eine Sprache speziell für diese Domäne zu verwenden – die Domänenspezifische Sprache. In dieser erfolgt die Programmierung in der Notation, mit der die Fachabteilung vertraut ist. Die Zusammenarbeit ist viel einfacher, insbesondere wenn die DSL nicht nur Text, sondern auch formale Grafiken und die Einbindung erläuternder Bilder und von Beispieldokumenten erlaubt.

Vorteile

Ein großer Vorteil ist, dass die Anforderungen lesbar wie (Prosa-)Text sind , aber auch direkt ausführbar wie (Unit-) Tests in der IDE. Breakpoints und Stacktraces arbeiten genau so, wie man es von der GPL-Programmierung her kennt.

Die Notation muss in der DSL nicht zwangsläufig aus (unformatiertem) Text bestehen. Es sind auch weitere Darstellungsformen möglich: das (OOSE-)Use Case Formular, die SOPHIST-Form, oder eine Tabelle mit den beiden Spalten “Aktion” und “Erwartete Systemreaktion”.

Falls gewünscht, kann man auch mehrere Editoren/Darstellungsformen für denselben Test erstellen: Übersicht/Details, mit/ohne Metadaten wie Autor, Version, Erfassungsdatum, Stabilität usw. Je nach Projektphase, Aufgabe oder Informationsanfrage wählt man die am besten passende Sicht auf den Datenbestand.

Auch abgeleitete Darstellungen sind leicht integrierbar, z.B. kann ein Use Case Diagramm aus den Use Cases generiert werden.

Wer möchte, kann die Sprachen so gestalten, dass die Verwaltung der Anforderungen genauso First Class Citizen werden wie deren Erfassung. Mittels Annotationen und Metadaten sind Sortier- und Filteroperationen möglich.

Es besteht auch die Möglichkeit, gleich noch den (Java-)Produktivcode in der Language Workbench zu schreiben, wenn sie die verwendete GPL unterstützt. Dann ist es leicht, harte Links zwischen Anforderungen und Code setzen. Die Nachverfolgbarkeit der Umsetzung von Anforderungen im Code und der Verweis vom Code auf die Anforderungen ist somit gegeben. In MPS ist dies mit Java und wenigen Language Extensions möglich, das ebenfalls MPS-basierte mbeddr ermöglicht die C-Programmierung.

Wenn man zum Arzt geht, erwartet man schon, dass man nach dem aktuellen Wissenstand behandelt wird. Ärzte sollte sich immer up to date halten und weiterbilden.

Wenn man zum Konzert geht, erwartet man, dass die Musiker ihre Instrumente beherrschen. Sie sollten jeden Tag üben und die Stücke sauber spielen können.

Und bei uns Softwareentwicklern? Die Kunden erwarten auch, dass wir ihren Produkte nach aktuellem Wissensstand erstellen, dass wir unsere Werkzeuge beherrschen, uns up to date halten, weiterbilden. Und üben? Ja, üben! Oder sollen wir etwa mit dem neuen Framework, der neuen Programmiersprache, der gerade aktuelle durchs Dorf getriebene Sau im kritischen Kundenprojekt experimentieren?

Bei Kontext E haben wir daher vor einiger Zeit Coding Dojos eingeführt. Alle Interessenten treffen sich regelmäßig am ersten Mittwoch im Monat, um gemeinsam zu üben. Die Leitung wandert von Mitarbeiter zu Mitarbeiter. So kommen neue Ideen zum Tragen und man muss nur einmal aller paar Wochen auf den Spaß des Programmierens verzichten. Denn Freude ist bei allen dabei, die einmal im Monat das Alltagsgeschäft hinter sich lassen können, den Dschungel des gewachsenen Codes verlassen und auf der grünen Wiese gefahrlos neue Sachen ausprobieren können.

Inhaltlich wird viel Abwechslung geboten. Ein klassischer Code Retreat mit dem Game of Life war dabei, Katas aus dem Kata-log, Refactoring von Legacy Code bis hin zum Prototypen einer Anwendung. Dabei werden immer die Techniken Test Driven Development und Pair Programming geübt. Je nach Aufgabe kommen weitere hinzu: Verzicht auf liebgewonnene Sachen wie primtive Datentypen, Zuweisungen oder die Maus. Das Kennenlernen einer NoSQL-Database - wir haben Neo4J verwendet. Continuous Integration mit dem TFS, das Kanban-Board, Mock-Frameworks, Pattern - um nur wahllos ein paar herauszugreifen.

Ein spannender Punkt ist auch, dass wir in der täglichen Arbeit in die Java-Guys und die .NET-Frakation getrennt sind. Beim Coding Dojo sitzen wir aber gemeinsam vorm Rechner. Das gibt die Chance, vom anderen Lager zu lernen: die andere Programmiersprache, die andere Kultur, neue IDEs.

Wir verwenden auch andere Formen der Weiterbildung: Lehrgänge, Zertifizierungen, Konferenzbesuche, In-House-vorträge, die gut sortierte Bibliothek, Konferenzvideos. Aber den größten Effekt auf die tägliche Arbeit haben die Coding Dojos. Sie verändern die tägliche Arbeit bei vielen am nachhaltigsten. Die investierte Zeit lohnt sich - Nachahmung ist auf jeden Fall gewünscht!