Aus der Werkzeugkiste, Teil 5: Sebastian Daschner

Sebastian Daschner ist Teil der Expert Groups von JSR 370 und 374 und hilft mit, die nächsten Versionen von Java EE zu spezifizieren. Welche Werkzeuge er tagtäglich bei Kunden nutzt, erzählt er im fünften Teil unserer Tool-Interview-Reihe.

In Pocket speichern vorlesen Druckansicht 8 Kommentare lesen
Aus der Werkzeugkiste, Teil xzz: Sebastian Daschner
Lesezeit: 9 Min.
Von
  • Sebastian Daschner
Inhaltsverzeichnis

Wir bitten in der Werkzeugkasten-Serie bekannte Entwickler, anhand von Kategorien wie Codegenerierung, Editor/IDE, Debugging, Codeanalyse, Unit Testing, Integration Testing, Code Coverage, Building, Deployment und Continuous Integration zu erzählen, welche ihre präferierten Werkzeuge sind. Den Auftakt machten Philip Ackermann, Golo Roden, Oliver Zeigermann und Adam Bien. Nun lassen wir den Java-EE-Experten Sebastian Daschner zu Wort kommen:

Sebastian Daschner

Zur Generierung neuer Projekte verwende ich meistens Maven Archetypes oder sogar eigens geschriebene Shell-Skripte. Dazu muss ich sagen, dass ich generell viel auf der Commandline unterwegs bin. Da bieten sich Skripte an. Bei der Generierung von Java (und anderem) Code setze ich auf die Features der benutzten IDE – in den meisten Fällen IntelliJ IDEA. Die IDE bringt typische Funktionen wie Getter, Setter und Constructors schon mit, und alles weitere lässt sich hinzukonfigurieren.

Das ist ein wichtiger Punkt, den ich empfehlen kann. Entwickler schreiben typischerweise immer wieder die gleichen Codeschnipsel, die sich mit Live-Templates deutlich produktiver erzeugen lassen. Das müssen noch nicht mal komplexe Konstrukte sein. Schon ein paar gesparte Zeichen oder Zeilen, die oft genug getippt werden, machen den Entwickleralltag produktiver.

Als IDE kommt in 95 Prozent der Fälle IntelliJ IDEA in der Ultimate-Version zum Einsatz. Sie bietet meines Erachtens die beste Produktivität und Entwicklereffizienz und sehr mächtige Refactoring-Features. IntelliJ ist eines der Tools, die eine einheitliche und konsequente Tastaturbedienung ermöglichen. Das und das für mich wichtigste Plug-in, IdeaVIM, machen die Entwicklung äußerst produktiv – ich benötige die Maus so gut wie gar nicht.

Ab und zu bestehen Kunden vehement auf ihre eigene IDE-Wahl, die meist auf Eclipse ausfällt. Das Tool habe ich früher viel benutzt, aber irgendwann wurde es mir zu schwerfällig und unflexibel und hat mit der Feature-Fülle von IntelliJ und NetBeans nicht mehr mitgehalten. Neben IntelliJ benutze ich nur noch Vim. Die Lernkurve ist zwar enorm, aber sobald man sich an das Tastaturkonzept gewöhnt hat, will man es nicht mehr missen.

Je nach Projekt habe ich mit allen Java-EE-7-Servern zu tun. Die in meinen Projekten und Workshops meistverwendeten sind Wildfly, Payara beziehungsweise GlassFish und WebSphere Liberty. Wo jedoch alle aktuellen Appserver kurze Start-up- und Deployment-Zeiten bieten, ist die Wahl eher eine persönliche Präferenz. Java EE bewegt sich zunehmend zu nicht nur theoretischer, sondern auch tatsächlich vollständiger Portabilität von Applikationen, was die Wahl des Servers zusätzlich relativiert.

Zum Debuggen von Java-Code kommt ausschließlich die IDE zum Einsatz. Sie bietet alles, um sich einfach zur laufenden JVM zu verbinden – sei es im Main-Programm, JUnit-Test, Application Server oder remote über SSH. Application Server in laufenden Docker-Containern lassen sich übrigens einfach per IDE debuggen, wenn der Debug-Port des Servers von Docker in den Container gemappt und von IntelliJ IDEA angesprochen wird.

In meinen Projekten kommen alle im Java-Umfeld typischen Codeanalyse-Tools zum Einsatz, allen voran SonarQube, Checkstyle und PMD. IntelliJ findet mit seiner Code-Analyse auch schon viele Smells. Wichtiger als das verwendete Tool ist jedoch die gelebte Umsetzung der Codeanalyse. Die Analyse – welches Tool auch immer Verwendung findet – muss Teil der Entwicklungs-Pipeline sein und dementsprechend vom CI-Server angestoßen werden. Die gemeldeten Fehler und Warnungen sind dann zeitnah vom Team zu fixen oder als ungefährlich einzustufen. Jede Anzahl größer als null ist damit als instabiler Build anzusehen. Wenn das nicht so gehandhabt wird, läuft das Projekt langfristig in die Situation, dass neue Warnungen leichtfertig ignoriert werden, das Projekt ist dann eh voll von Warnungen.

Als Unit-Testing-Technik verwende ich immer JUnit. Das Framework ist weitverbreitet und bietet ausreichend Features und eine gute Integration in Build-Tools und CI-Server. Interessant wird die neue Version 5, die es noch einfacher als die aktuellen parametrisierten Tests macht, Tests dynamisch zu erstellen. Da wurde die Benutzung sehr auf die Anforderungen in Projekten optimiert. JUnit 5 lässt sich als Vorabversion schon testen.

Auf komplexere Techniken als JUnit kann für Unit-Tests in den meisten Fällen verzichtet werden. Dynamische JVM-Sprachen und Tools wie Spock kommen zwar mit verlockender Syntax. Jedoch bin ich überzeugt, dass sich mit gut angewandten Handwerksregeln der Softwareentwicklung auch mit Plain-Java- beziehungsweise JUnit-Code lesbare und vor allem wartbare Tests schreiben lassen. Dass für Tests die gleichen, sinnvollen Code-Regeln wie auch für Produktions-Code gelten, ist wichtiger als die Wahl des Test-Frameworks. Businesslogik in Embedded-Containern wie Arquillian zu testen, versuche ich zu vermeiden.

Noch wichtiger als Unit-Tests sind in meinen Augen Integrations- oder Systemtests. Erstere haben schnelles Feedback und einen gezielten Scope auf eine bestimmte Funktion zur Folge, aber simulieren das Verhalten drumherum nur. Daher sollte die Applikation früher oder später auf dieselbe Weise getestet werden, wie sie später auch in Produktion läuft.

Deshalb benutze ich kaum Frameworks auf Applikations-Code-Ebene, sondern lasse die Applikation (im Idealfall) genauso wie in Produktion laufen und teste die Schnittstellen und Integrationen von außen. Docker, WireMock beziehungsweise MockServer und Embedded-Datenbanken sind hier die hilfreichsten Tools. Dadurch können auf Entwicklungs- oder Testumgebungen einfach produktionsnahe Umgebungen getestet werden. Für die eigentlichen Tests verwende ich aus Konsistenzgründen JUnit, zum Beispiel mit JAX-RS-Client, oder seltener Shell-Skripte.

Das Code-Coverage-Werkzeug Jacoco bietet schöne Integrationen in Build- und CI-Tools. Das deckte bisher in Projekten den Bedarf an Testabdeckung-Tools. Die Aussagen von Jacoco, so wie von allen Coverage-Tools, sind meist recht aussagekräftig. Was jedoch vermieden werden soll, ist, blind nach den Testabdeckungswerten zu entwickeln. Abdeckung von zum Beispiel mehr als 80 Prozent klingt erst mal nach gut getesteter Software – viel wichtiger ist jedoch die Qualität der Tests und die Abdeckung der
Assert-Statements. Daher ist Mutations-Testing à la PIT eine sinnvolle Ergänzung.

Zum Zusammenbauen von Java-Anwendungen kommt in meinen Projekten meistens Maven, seltener Gradle zum Einsatz. Für Standard-Enterprise-Anwendungen reichen die Features und Konventionen, die Maven bietet, im Regelfall aus. Gradle bietet zwar deutlich mehr Flexibilität, jedoch ist genau diese Freiheit manchmal sogar kontraproduktiv, wenn sich ein Projekt durchaus gemäß dem Standard mit "Convention over Configuration"-Prinzip bauen lässt, mit denen die meisten Entwickler vertraut sind.

Je nach verwendeter Umgebung kommen für das Deployment meist Skripte auf dem CI-Server zum Einsatz, die zum Beispiel Docker-Container aus den gebauten Images starten. Eine interessante Technik ist das Orchestrierungs-Tool Kubernetes. Jeder, der einmal mit selbstgeschriebenen Skripten Docker-Container verwaltet hat, weiß die Vorteile zu schätzen.

Kubernetes kommt neben Docker in meinen Projekten und Workshops häufig zum Einsatz – entweder nativ oder via OpenShift. Die Vorteile, die Kubernetes und auch Container à la Docker bieten, sind einfach zu groß. Zwar lassen sich die Umgebungen mit Eigenentwicklungen und Automatisierungen deployen. Jedoch ist das mit einigem Aufwand (und nicht zuletzt auch Risiko) verbunden, was einem die vielfach in Produktion laufenden Techniken abnehmen.

Der mit Abstand am häufigsten in meinen Projekten und Workshops eingesetzte CI-Server ist Jenkins. In Hinblick auf Continuous Deployment Pipelines ist er nicht unbedingt die technisch ausgereiftetste – jedoch die verbreitetste – Software. Seit der Version 2 und dem Pipeline-as-Code-Feature deckt Jenkins auch ohne exkzessive Plug-ins die Standardfälle von Continuous Delivery ab. Grovvy als Programmiersprache in den Jenkinsfiles zu verwenden, zeigt sich beim Entwickeln als sinnvoll. Auch ohne allzu tiefe Grovvy-Kenntnisse lassen sich einfach verständliche und wartbare Pipeline-Definitionen als Code schreiben. Dieses Feature ist insofern eines der wichtigsten von Jenkins, da es die manuelle Konfiguration des CI-Servers minimiert. Die Tage, in denen mühevoll die Konfigurationen von Jobs zusammenzuklicken waren, sind damit vorbei.

Als Versionskontrolle kommt fast ausschließlich Git zum Einsatz, Subversion nur noch in Legacy-Projekten.