How to format your project’s Java code with git hooks and finally get rid of annoying IDE specifics

In most of our projects, every developer can use the IDE of their choice which quickly leads to quite some issues with code formatting. Therefore, we needed a solution to automatically format the code before a commit is pushed to the central git repository. For JavaScript we already implemented that a long time ago and the feedback was great. There’s no more discussion about formatting in code reviews (some exceptions if a //doNotFormat comment is used) anymore, it’s not necessary to create checks on CI level etc. We also added some linting that prevents the commit if there’s a violation detected and even the critics started to like this approach :)
Now, it was time to have a look at some non-JavaScript: Some Java using maven…

Solution

Formatter

At first, we looked for a maven plugin that is able to format the files with a standard Eclipse formatter configuration. We decided for spotless for the time being:

...
<spotless.include></spotless.include>
...
<plugin>
   <groupId>com.diffplug.spotless</groupId>
   <artifactId>spotless-maven-plugin</artifactId>
   <version>1.15.0</version>
   <configuration>
      <java>
         <excludes>
            <!-- excluding some auto generated files -->
            <exclude>com/client/something/*.java</exclude>
         </excludes>
         <includes>
            <include>${spotless.include}</include>
         </includes>
         <eclipse>
            <file>${basedir}/java-formatter-config.xml</file>
         </eclipse>
         <encoding>UTF-8</encoding>
         <removeUnusedImports/>
      </java>
   </configuration>
</plugin>
...
  • java-formatter-config.xml is an Eclipse formatter configuration and can also be imported into most IDEs.
  • spotless.include is a glob pattern that defines which files should be formatted. Since we only want to format the files touched in a commit, it’s necessary to define these precisely when calling mvn spotless:apply.
  • One downside of spotless is its performance. Currently, it runs for about 3-4 seconds, so we might switch to something else at some point in the future. For the time being, it’s okay.

Calling it as a pre-commit hook

Our key requirement is that it shouldn’t be necessary to set up the git hooks manually for each developer. In the JavaScript parts, we’re using lint-staged with husky to achieve this, which is working fine for us. Thanks to a colleague, I was made aware of frontend-maven-plugin, which is capable of installing node+npm and execute a npm install afterwards. So we added the following pluing to our pom.xml:

...
<plugin>
   <groupId>com.github.eirslett</groupId>
   <artifactId>frontend-maven-plugin</artifactId>
   <version>1.6</version>
   <executions>
      <execution>
         <id>install node and npm</id>
         <goals>
            <goal>install-node-and-npm</goal>
         </goals>
      </execution>
      <execution>
         <id>npm install</id>
         <goals>
            <goal>npm</goal>
         </goals>
      </execution>
   </executions>
   <configuration>
      <nodeVersion>v10.12.0</nodeVersion>
   </configuration>
</plugin>
...

So once a user calls mvn generate-source, node+npm will be installed locally into the project. To install lint-staged and husky and configure them, we added a minimal package.json:

{
  "name": "ClientProject",
  "private": true,
  "version": "1.0.0",
  "description": "ClientProject",
  "scripts": {
    "precommit": "lint-staged"
  },
  "author": "",
  "license": "UNLICENSED",
  "devDependencies": {
    "husky": "0.14.3",
    "lint-staged": "7.1.3"
  },
  "lint-staged": {
    "linters": {
      "*.java": [
        "./formatter.sh",
        "git add"
      ]
    }
  }
}

This defines that lint-staged is called as a precommit hook, which checks if .java files were changed. If yes, it passes the changed files as a parameter to the formatter.sh as well as the git add afterwards. The workaround through the formatter.sh is required, as the plugin passes the full path of the files as arguments, while spotless requires the files to be formatted as a single comma-separated string relative to the location of the project root.

formatter.sh:

#!/bin/sh

function join_by {
  local IFS="$1";
  shift;
  echo "$*";
}

PROJECT_DIR="$(pwd)"
FILES=$(join_by "," "$@")

mvn spotless:apply -f $PROJECT_DIR/pom.xml -Dspotless.include=${FILES//$PROJECT_DIR/}

Workarounds

In case you don’t want your commit to be formatted, just run git commit with –no-verify, or disable the “run git hooks” in the respective IntelliJ pop-up. But be aware that you might be approached by the other developers ;)

Conclusion

Now, when committing any .java file, it is automatically formatted according to rules in java-formatter-config.xml without the user having to take care of this.

By the way, if you want to be notified for new posts, just sign up with your email address on the right and/or like my Facebook-Page :)

Fazit letzte Formchecks: Läuft :)

Chiemsee MD

Am Sonntag stand der letzte Formcheck auf dem Programm: Mitteldistanz beim Eberl Chiemsee Triathlon. Plan war das Material und natürlich den Trainingsstand auszutesten. Also nicht überpacen, alles im LD Tempo… Bla bla :P

Schwimmen lief “okay”. Irgendwie brauche ich immer länger um meinen Rhythmus zu finden, aber nach 1km war er dann da. Der 2. ging dann viel lockerer :)
Auf dem Rad habe ich mich dann großteils zusammen reißen können und bin 2 solide Runden à ~41,5km mit 300HM mit einem guten 32er Schnitt gefahren. Danach fühlte ich mich zwar nicht ausgeruht aber vom Limit war ich noch einiges entfernt!
Die Laufstrecke galt es dann gleich 4 mal zu bewältigen, um auf die angesagten 20km zu kommen. Hier hat es mich dann allerdings gepackt und ich habe meine Beine “laufen lassen”. Raus kam eine Pace von 4:35min/km, wobei es gegen Ende doch anstrengend wurde. Nun gut, das ist auch deutlich schneller als ich für die LD im Auge habe :D

Auch der Magen hat die ganze Zeit gehalten und ich konnte mich auf dem Rad brauchbar gut verpflegen. Beim Laufen habe ich allerdings komplett auf Gels etc verzichtet. Da werde ich in den nächsten 2-3 Wochen doch noch mal etwas testen müssen!

Insgesamt stand am Ende eine solide 4h50 auf der Uhr, mit der ich gut zufrieden bin :)

Garmin Activity, Strava #1, Strava #2

Bad Tölz OD

Schon vor 2 Wochen war ich beim Bad Tölz Triahtlon am Start. Auch hier war der Plan die Form und das Material zu testen und ein wenig mit der Verpflegung zu experimentieren.

Das Schwimmen im Kirchsee war interessant. Ich glaube ich war noch nie in einem so dunklen Gewässer unterwegs. Die eigenen Hände unter Wasser quasi nicht mehr zu sehen ist ein komisches Gefühl! Die Zeit war mit einer 2min/100m Pace okay. Hier ist definitiv eine meiner größten Stellschrauben.
Auf dem Rad ging es dann etwas mehr zur Sache, vor allem, weil in der Gegend doch ein paar Hügel verbaut sind. Insgesamt habe ich die ~40km und gut 450HM in 1h12 durchgebracht, also ein guter 32er Schnitt.
Das Gemeinste kam allerdings beim Laufen. Es standen 2 Runden à ~5km auf dem Programm mit etwa 150HM. Das ist erstmal nicht sonderlich viel, allerdings ging es großteils über Schotterpisten mit trockenen Rinnsalen und Waldwege. Nur kurz vor und nach der Wende gab es ~500m Asphalt. Die Beine waren aber noch in einem brauchbaren Zustand und mit einer 4:25min/km Pace war der Spuk auch schnell genug vorbei ;)

Summa summarum standen also 2h29 auf der Uhr und ich war gut zufrieden, v.a. dafür, dass ich nie am Limit unterwegs war :)

Garmin Activity

Kleiner Ausblick

Die Vorbereitung läuft also ganz gut und die Wehwehchen halten sich bisher im Rahmen. Jetzt heißt es noch einmal einen Belastungsblock durchbringen und dann geht es schon ans Tapering für Hamburg. Ein wenig Nervosität kommt bei dem Gedanken bereits auf. Hauptsache ich kann das kontrollieren und am Ende in Leistung umsetzen!!

Übrigens, wenn Du über neue Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

Ein Hermann zum Ende des Trainingslagers

Lange habe ich nichts mehr gepostet. Zu lange. Eigentlich ist schon einiges passiert, nur irgendwie haben es die Infos nur auf meine Facebook-Seite geschafft ;)

Heute stand auf jeden Fall mal wieder ein Wettkampf auf dem Plan. Nachdem ich mich seit Anfang des Jahres auf den IM Hamburg vorbereite, habe ich die letzten 2 Wochen im “heimischen Trainingslager” verbracht. Und wie kann man das besser beenden als mit einem schönen Lauf? Gar nicht! Also habe ich mich zum Hermannslauf angemeldet – einem 31km Traillauf (~550HM) vom Hermannsdenkmal in Detmold zur Sparrenburg nach Bielefeld. Nach einigen Berichten von Freunden und Bekannten habe ich mich lange zurückgehalten und bin bis ~KM25 – mit Ausnahme einiger bergab Passagen ;) – mit angezogener Bremse unterwegs gewesen. Dann bin ich allerdings noch mal ordentlich aufs Gas gestiegen und habe die Trails unter meinen Füßen glühen lassen :D

Insgesamt war ich nach 2:26:57h im Ziel und bin damit 57. meiner AK geworden (Strava Activity). Nicht schlecht für einen Lauf am Ende eines 2-wöchigen Trainingslagers, ohne spezielle Vorbereitung und Tapering. Gerade spiele ich mit dem Gedanken wieder zu kommen und das Gerät noch mal ausgeruht und vorbereitet mit Vollgas anzugehen. Mal sehen… :P

Übrigens, wenn Du über meine neuen Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

Frankfurt Marathon – Neue PB und… :D

Was für ein Tag!

Am Samstag ging es mit dem Zug nach Frankfurt zum Marathon. Einquartiert war ich im Marriott direkt neben dem Start. Sehr praktisch und mittlerweile haben sie das mit dem Marathon dort auch auf dem Schirm und bieten einen Haufen Nettigkeiten für die Teilnehmer an, z.B. anschließende Duschen.
Dank einer lieben Freundin musste ich mich um fast nichts kümmern. Meine Startunterlagen hatte sie schon abgeholt und auch beim Italiener war reserviert. Perfekt! Lieben Dank an dieser Stelle, Katharina :)
Nachdem die Woche über das linke Bein etwas gezwickt hat und ich mich auch nicht immer 100% wohl gefühlt habe, hatte ich mein Ziel einer neuen PB innerlich eigentlich schon abgeschrieben. Die Wettervorhersage mit viel Wind legte da dann noch einen drauf.
45min vorm Start am Morgen dann der erste kleine Schock: Timing-Chip vergessen… Zum Glück gibt es Leihchips, aber 45min vor dem Start möchte man sich darum eigentlich nicht kümmern müssen!
Endlich in der Aufstellung ging es um kurz nach 10 auf die Strecke und der Wetterbericht hatte nicht gelogen. In Frankfurts Hochhausschluchten blies der Wind ordentlich. Egal. Wir hielten am 4:30min/km Plan fest. Es lief sogar unerwartet gut! Die Beine hielten und auch nach 20km war die Erschöpfung gering. Mit knapp 1:34h hatte ich an der HM Marke sogar leichten Vorsprung auf den Plan. Perfekt und die Beine hielten!
Zurück in den Häuserschluchten hat mich dann allerdings mein Magen im Stich gelassen. So sehr, dass ich bei km39 kurz stehen blieb, etwa 500m gehen musste und danach nicht mehr über einen 5:15min/km Schnitt hinaus kam. Die gesamte Aktion hat mich auf den letzten 3km gute 5min gekostet. Trotzdem habe ich mit 3:14:51h eine deutliche neue persönliche Bestleistung abrufen können :D (Garmin Connect)

Auf dem Weg zum Zug ereilte mich dann noch eine Nachricht mit der ich beim besten Willen nicht gerechnet hatte: Mit der Mannschaft haben wir den 3. Platz in der AK35 der deutschen Meisterschaft gemacht! Geil!!! Die Siegerehrung hatte ich natürlich verpasst… Egal! Neben der normalen Finishermedaille habe ich jetzt also auch mal eine “besondere” und offizielle DLV Urkunde :P

Vielen Dank auch an Ingo für die Bilder! Noch mehr findet ihr auf tiefenschaerfen.de :)

Übrigens, wenn Du über meine neuen Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

Tegernsee Triathlon 2017

Heute war ich auch mal “Erster” ;)

Beim Tegernsee Triathlon mit der Startnummer 1 am Start ging es bei mäßigem Wetter (15C und Regen) ganz okay im Tegernsee los. Beim Schwimmen merkte man das Sch***wetter zum Glück nicht und mit knapp 20C war der See sehr wohl temperiert :D 31min haben mich die 1,6km gekostet. Das ist zwar nicht berauschend, allerdings immerhin 3min schneller als 2016. Auf dem Rad habe ich dann den Trainingsrückstand nach 6 Wochen verletzungsbedingter Pause deutlich gemerkt. Sage und schreibe 3km/h war ich im Schnitt langsamer als 2016. Da waren dann einfach mal fast 10min futsch. Beim Laufen ging es hingegen wieder gut. Die 10km quer durch die Landschaft flogen nur so vorbei und trotz der 150HM, standen am Ende 45min auf der Uhr.
Insgesamt wäre immer noch eine passable Zeit im Bereich von 2016 rausgekommen, allerdings habe ich die Wechsel gehörig versaut. Dem Wetter geschuldet hatte ich mich entschieden beim Radfahren Armlinge anzuziehen und die wollten einfach nicht auf meine nassen & kalten Arme. Beim Laufen hatte ich frische Socken in die Schuhe gelegt, was sich beim Wechsel als Katastrophe herausstellte – die wollten nämlich nicht über meine eiskalten Zehen. Allerdings war das Laufen in trockenen Schuhen & Socken die Qual des Wechsels wert :P

Alles in allem bin ich gut zufrieden mit meinem ersten Triathlon 2017 und meiner 2:40:06h :)

Ein paar Bilder folgen bald!

Übrigens, wenn Du über meine neuen Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

Ein “kleiner” Transalp Test :)

Gestern Morgen um 4h habe ich mich aufs Rad gesetzt, um rauszufinden wie weit ich gehen kann. Knapp 14 Stunden Fahrtzeit, 332km und 3028hm später wusste ich es :)
Ich war in Hammelburg und Beine und Kopf waren durch. So richtig.
Heute Morgen um 6:30h saß ich dann schon wieder im Sattel, weiter Richtung Hamm. Schnell wurde allerdings klar, dass meine Beine das heute nicht noch mal schaffen und ich das Ruhrgebiet aus eigener Kraft an nur einem weiteren Tag nicht erreichen würde. Also habe ich meinen Plan angepasst und sitze nun in Fulda am Bahnhof.
Viel Zeit zum Nachdenken und eins ist sicher: Ich habe allein und ohne Windschatten gestern verfluchte 332km + 3028hm geschafft! Damn! Wenn der Körper danach sagt es geht nicht mehr, höre ich besser zu und drehe am Wochenende noch mal 1-2 “kleine” Runden :)
Die Transalp kann kommen! :D

MacOS Context Switches mit ControlPlane

Täglich bewege ich mich mit meinem Laptop zwischen mehreren Orten hin und her. Im einen muss das WiFi an sein, im anderen aus. In manchen brauche ich eine VPN Verbindung, in anderen sollen alle bestehenden VPN-Verbindungen getrennt werden. Außerdem denke ich viel zu selten daran die PGP-Keys zu updaten. Gedruckt werden muss auch manchmal, aber welcher Drucker war es jetzt gerade noch in der Beta und welcher in der Lindenschmit? *nerv*

Beim Kunden und auch in diversen Workshops bei TNG hisse ich immer wieder die Flagge der Automatisierung wiederkehrender Aufgaben und was wäre ich für ein TNGler/Nerd/Consultant, wenn ich obiges "Problem" nicht automatisiert löse? ;)
Nach einigen Jahren verschiedenen Ideen/Tools bin ich nun seit einiger Zeit sehr zufrieden mit einer Kombination aus ControlPlane und “Otto – dem Automator” unterwegs.

ControlPlane

Mit Hilfe von ControlPlane erstellt man sehr einfach Regeln+Gewichtung für verschiedene Contexte:

Diese werden in regelmäßigen Abständen überprüft und der Context bei Bedarf gewechselt. In Prozent ist hier angegeben, wie sicher ControlPlane ist, dass man sich imm Context befindet. Das ist v.a. hilfreich, wenn man an den Slidern rumspielt, um verschiedene Contexte besser unterscheiden zu können.

Soweit so nett. Was jetzt allerdings der eigentlich wichtige Teil ist, dass man in ControlPlane definieren kann, was "on arrival" oder "on departure" eines Contexts passieren soll:

Hier kann man auf diverse vorkonfigurierte Actions zurückgreifen, die über das Ausführen von Applikationen oder Shellscripts auch Dinge anbieten wie z.B. Radios aus- und einzuschalten. Leider umfasst das natürlich nicht jede beliebige Operation…

Otto – der Automator

So kommt man schnell zu "Otto – dem Automator". Mit Otto lassen sich nahezu beliebige Aktionen zusammenbauen und als Applikation speichern, die dann wiederum von ControlPlane ausgeführt werden kann. Ein einfaches Beispiel ist z.B. das Ausführen der keysync.sh:

So wird jetzt jedes mal ein Keysync getriggert, wenn ich meinen Laptop in der Beta an meinem Schreibtisch anschließe und ich muss nicht mehr daran denken :P

Übrigens, wenn Du über meine neuen Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

Westparklauf 2017

Heute stand eine für mich ungewöhnlich kurze Distanz auf dem Programm: 5km beim Westparklauf! Bisher bin ich nur ein Rennen über 5km gelaufen und das war 2014. Dementsprechend war ich etwas nervöser als sonst. Eine neue persönliche Bestzeit sollte auf jeden Fall klappen, aber wie schnell geht es tatsächlich? Fairer Weise muss ich hier erwähnen, dass die Strecke durchaus wellig ist und besonders die Überquerung des Rings hat es insich ;)

Am Ende stand 18:35min auf der Zieluhr und wie man auf den Bildern sehen kann, war es anstrengend! Aber auch sehr geil :mrgreen:

Neue PB und etwa genau so hatte ich mir das vorgestellt. Damit bin ich immerhin auf Platz 16 gesamt und 4 meiner AK gelaufen :P

Übrigens, wenn Du über meine neuen Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

Let the games begin ;)

Meine neuen :)

Passend zur neuen Saison musste auch im Schuhschrank was neues her – die “alten” haben schon ein paar Kilometer auf dem Buckel!

Früher bin ich schon viel Brooks gelaufen und der Launch3 läuft sich echt super. Ein paar Kilometer hat er in der Zwischenzeit schon gesammelt und ich bin begeistert :)

Außerdem gibt es eine echte Premiere: Mein erster Asics Laufschuh überhaupt: Gel-noosa Tri 11. Schön bunt ist er und anfühlen tut er sich auch top :D

Übrigens, wenn Du über meine neuen Posts benachrichtigt werden möchtest, einfach rechts Deine Emailadresse eintragen und/oder meine Facebook-Seite liken :)

2016 was a good (athletic) one :)

In January, I summed up 2015 a little and outlined some plans for the rest of the year. Now it is over and (athletic wise) it’s been an amazing one!

I had tons of fun practicing and met a lot of cool&nice people that I really enjoyed spending time/practicing with. You guys made me keep on going when my calfs hurt and gave me useful tips for my swimming technique (I’m still working on it! Promised!). Thanks for that and I hope we’ll be able to spend some more time together :)

A few athletic dates: Ironman 70.3 finish, personal best on half marathon distance and new personal bests at Tegernsee OD and Erlangen MD. Of course, this didn’t come out of nowhere. I’ve been trying to improve my race preparation as well as my training sessions in both: quantity and quality. I added some more alternative sessions and added a little strength workouts as well. Seems like it paid off :mrgreen:

Sport Activities* Distance* Time*
Combined 408 (271) 4.911,69km (4359,73km) 383:41:46h (291:56:54h)
Running 143 (105) 1.460,82km (1096,91km) 119:48:44h (97:10:03h)
Cycling 136 (99) 2.967,20mk (2933,78km) 116:50:19h (122:57:57h)
Swimming 51 (42) 79,31km (64,29km) 32:30:42h (26:51:14h)
Multi-Sport 15 (5) 718,34km (325,32km) 38:55:47h (15:53:50h)
Other 56 (20) (*) 106:19:18h (*)

*2015 numbers are shown in brackets.

Compared to the time and distance some others spend, ~1h day on 1,1 workouts is still not a lot. So I assume there’s some potential left if I keep going this direction! Let’s see what 2017 brings ;)

1 2 3 52