Team-Event für Software-Entwickler: Willkommen im Clean Code Dojo

In Corona-Zeiten sind Team-Events rar geworden und trotz Video-Konferenz eher mäßig beliebt. Sicherlich gibt es hier auch schon einige gute Konzepte - ein weiteres Event-Konzept speziell für Software-EntwicklerInnen habe ich im Urlaub entdeckt: das virtuelle Clean Code Dojo.


Das Clean Code Dojo

Im Buch "The Clean Coder" erklärt Onkel Bob, wie wichtig Training für Software-EntwicklerInnen ist. Teil des Trainings sind natürlich auch alle möglichen Lernkonzepte, wie z.B. Schulungen, Fachbücher, Blogs, Podcasts usw. Er stellt aber auch eine weitere Trainings-Form vor, welche aus dem Kampfsport abgeleitet ist: das "Coding Dojo".

In Onkel Bobs altem Blog gibt es dazu ebenfalls einen Eintrag: http://www.butunclebob.com/
Hier auch noch der Link zum aktuellen Clean Coder Blog: https://blog.cleancoder.com/

Im Coding Dojo führen die trainierenden SchülerInnen Katas aus, so wie ihr es aus Karate kennt: Wikipedia Kata. Nur sind diese Katas keine Tritt- und Schlag-Choreografien, sondern das Programmieren in möglichst perfekter Form.

Coding Katas

Ein Coding Kata ist eine kleine Programmieraufgabe, deren Lösung ein Algorithmus ist. Beim Trainieren des Katas geht es nicht darum, die Lösung zu finden, sondern die Lösung möglichst elegant in sauberem Code zu schreiben und dabei Konzepten wie Test-Driven-Development zu folgen.

Das Bowling Game ist zum Beispiel ein solches Coding Kata. Beim Bowling Game Kata soll die Trainierende einen Algorithmus schreiben, der das Endergebnis einer Bowling-Runde berechnet. Dabei müssen die umgefallen Pins aller Würfe addiert werden, unter Berücksichtigung von Strikes und Spares und den Besonderheiten des letzten Frames. Es ist also kein trivialer Algorithmus.

Den Bowling Game Kata zu trainieren bedeutet also nicht, einmalig den Algorithmus zu lösen, sondern mehrfach. Bei jeder Wiederholung solltet ihr schneller werden, besser die Clean Code Prinzipien (Test-Driven-Development, kleine Methode, gute Namen für Methoden, Variablen usw.) umsetzen und weniger Klicks durch die richtigen Shortcuts in der IDE benötigen. Ihr studiert also, wie beim Karate Kata, eine möglichst perfekte Programmier-Choreografie ein. Ob ihr beim Ersten mal den Bowling Game Algorithmus irgendwo abschreibt oder selbst löst, ist dabei eigentlich egal. Wichtig ist, dass ihr das Kata mehrfach ausführt und versucht immer besser zu werden. Onkel Bob empfiehlt die Ausführung eines Katas als circa 30 minütigen Einstieg in den Arbeitstag.

Bowling Game Kata

Die Regeln der Ergebnis-Berechnung im Bowling Spiel mit einer tollen Choreografie in PowerPoint findet ihr bei Onkel Bob: http://www.butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata

Mein Bowling Game Kata ist in Kotlin geschrieben und mit JUnit 5 getestet. Ich zeige das hier, um euch ein Gefühl dafür zu geben, was bei einem Kata am Ende rauskommen kann. Ihr müsst den hier gezeigten Code nicht unbedingt verstehen, da es hier nur um das generelle Vorgehen geht und nicht die einzelnen Kotlin Kommandos.

Mein Bowling Game Kata besteht aus 2 Klassen und einer JUnit-Testklasse. Die Klasse Frame enthält (außer im letzten Frame) 2 Würfe und zeigt an, ob ein Strike oder Spare geworfen wurde. 
class Frame {
var pinsRolled = mutableListOf<Int>()

fun score() = pinsRolled.sum()

fun isSpare() = pinsRolled.first() < 10 && score() == 10

fun isStrike() = pinsRolled.first() == 10
}
Die Klasse Game bietet Methoden zum Ermitteln der Gesamtpunktzahl (totalScore), zum Prüfen, ob die Bowling-Runde fertig ist (over) und um das Ergebnis eines Wurfes im Spiel zu erfassen (addRoll) an. 
class Game {
private var frames = mutableListOf<Frame>()

private fun lastFrame() = frames.last()

fun addRoll(pins: Int) {
if (pins !in 0..10)
throw IllegalArgumentException(
"Only pin rolls between 0 and 10 are possible")
if (over())
throw IllegalStateException("Game is over")
if (frames.isEmpty() || frames.size < 10 && (
lastFrame().pinsRolled.size == 2 || lastFrame().isStrike()))
frames.add(Frame())
lastFrame().pinsRolled.add(pins)
}

fun totalScore(): Int {
var sum = frames.first().score()
var strikesInRow = false
for (framePair in frames.zipWithNext()) {
sum += framePair.second.score()
if (framePair.first.isSpare() || strikesInRow) {
sum += framePair.second.pinsRolled[0]
strikesInRow = false
}
if (framePair.first.isStrike()) {
sum += framePair.second.pinsRolled[0] +
framePair.second.pinsRolled.getOrElse(1) {0}
strikesInRow = framePair.second.isStrike()
}
}
return sum
}

fun over() = frames.size >= 10 && (lastFrame().pinsRolled.size == 3
|| (lastFrame().pinsRolled.size == 2 &&
!lastFrame().isStrike() && !lastFrame().isSpare()))
}
Getestet habe ich das komplette Programm mit dieser JUnit5-Testklasse:
internal class GameTest {

@ParameterizedTest
@CsvSource("300,10,", "150,5,", "90,9,0", "100,0,10")
fun totalScoreTests(result: Int, firstThrow: Int, secondThrow: Int?) {
val game = Game()
while (!game.over()) {
game.addRoll(firstThrow)
if (!game.over())
secondThrow?.let { game.addRoll(it) }
}
assertEquals(result, game.totalScore())
}

@ParameterizedTest
@ValueSource(ints=[-1, 11, 100000, -999999999])
fun invalidAddRollTests(pins: Int) {
val game = Game()
assertThrows(IllegalArgumentException::class.java) {
game.addRoll(pins) }
}

@Test
fun gameOverTest() {
val game = Game()
for(i in 0..18) {
game.addRoll(3)
assertFalse(game.over())
}
game.addRoll(3)
assertTrue(game.over())
assertThrows(IllegalStateException::class.java) {
game.addRoll(3) }
}

@Test
fun inGameScoreTest() {
val game = Game()
game.addRoll(10)
game.addRoll(7)
game.addRoll(3)
game.addRoll(2)
game.addRoll(0)
assertEquals(34, game.totalScore())
}
}
Um die Testklasse möglichst kompakt zu halten, habe ich parametrisierte Tests verwendet, die ich in diesem Artikel schon vorgestellt hatte: JUnit5andSpringBootTest.html
Außerdem habe ich laut dem Coverage-Check von IntelliJ meinen Sourcecode zu 100% mit dieses JUnit-Tests abgedeckt. Wenn man meine Testklasse aber mit der von Onkel Bob vergleicht, fällt auf, dass ich in Summe weniger Tests habe. Der Grund dafür ist, dass ich keine Testgetriebene Entwicklung angewendet habe - das ist etwas was ich in künftigen Bowling Game Kata-Sessions unbedingt verbessern will (siehe tdd am Beispiel Bowling Game).

Außerdem bin ich sowohl in Kotlin als auch in IntelliJ kein routinierter Entwickler und genau dabei werden mir die Katas aus dem Clean Code Dojo helfen 😀

Mehr Katas

Es gibt natürlich nicht nur das Bowling Game Kata. Weitere Katas, die auch auf anderen Ebenen ansetzen z.B. Architektur, Refactoring oder Agile, findet ihr hier:

Team-Event: Virtuelles Clean Code Dojo

Nach dem Kata stellt Onkel Bob im Buch "The Clean Coder" noch Wasa und Randori vor - diese Begriffe stammen aus dem Kampfsport Jujitsu. 

Wasa - Testgetriebenes Kata für 2

Das Wasa ist sowas wie ein Kata für 2. Die erste Entwicklerin schreibt nur einen, einzigen minimalen JUnit-Test und übergibt dann an den zweiten Entwickler. Dieser muss den JUnit-Test grün machen, indem er die minimal nötige Implementierung vornimmt und auf keinen Fall weiteren zu diesem Zeitpunkt unnötigen Code schreibt. Danach schreibt er einen weiteren JUnit-Test, der dann rot ist und übergibt zurück an die erste Entwicklerin. Sie hat nun die gleiche Aufgabe: JUnit-Tests mit minimalen Erweiterung grün machen und einen weiteren  fehlschlagenden, roten Test schreiben. Dann ist wieder der zweite Entwickler dran und es geht im Wechseln immer weiter bis das Wasa bzw. Kata für 2 abgeschlossen ist.

Randori - Testgetriebenes Kata für ein Team

Beim Randori kann nun das ganze Team mitspielen. Dazu wird entweder reihum übergeben oder per "Freiwillige vor" - wichtig ist natürlich das nach jedem neuen roten JUnit-Test übergeben wird und ein neues Team-Mitglied übernimmt. In einem anderen Blog Artikel über testgetriebene Entwicklung zeige ich Schritt für Schritt den Ablauf, die Übergabe an den nächsten Spieler ist in jedem Zyklus nach der Phase ROT.

Vor Corona war das Randori bei Coding Dojos sehr beliebt. Mittels Beamer wird der Code an der Wand anzeigt und die TeilnehmerInnen sitzen im selben Raum bzw. übergeben sich gegenseitig die Tastatur. Ich denke, ich muss keiner EntwicklerIn erklären, dass ihr bei solchen Events viel von anderen lernt. Wenn euch solche Algorithmen keinen Spaß machen würden, wärt ihr sicherlich auch nicht in der IT gelandet. Daher ist meine Idee, das ganze zu virtualisieren.

Randori per Videokonferenz / WebEx

Aus meiner Sicht eignet sich das zuvor beschriebene Randori perfekt als Team-Event für Software-EntwicklerInnen. Die Entwicklerin die gerade dran ist teil ihren Bildschirm und übergibt dann an den nächsten. Im umständlichen Fall verwenden alle Randori TeilnehmerInnen die eigene IDE und die Übergabe bzw. Synchronisation der einzelnen IDEs geschieht über euer Versionskontrollsystem (z.B. Git). Im Idealfall habt ihr eine Videokonferenz-System bei dem die Kontrolle über Maus und Tastatur übergeben werden kann, so dass ihr nur eine IDE mit dem Code benötigt, wie beim Randori vor Ort im selben Raum. WebEx ist ein beliebtes Videokonferenz-System, welches die Übergabe von Maus und Tastatur unterstützt:

Übergabe von Maus und Tastatur in WebEx

Fazit

Persönlich habe ich großen Spaß am Programmieren und mag daher auch die Katas. Randori ist ein lehrreiches und spaßiges Teamevent, das auch im New Normal möglich ist. Wenn ihr also Teil einer Gruppe von Software-EntwicklerInnen seid, versucht es doch mal und schreib wie es gelaufen ist.

Weitere Ideen für Katas findet man im Internet, z.B. hier: https://ccd-school.de/coding-dojo/

Kommentare

Mani hat gesagt…
helpful article

Beliebte Posts aus diesem Blog

OpenID Connect mit Spring Boot 3

Authentifizierung in Web-Anwendungen mit Spring Security 6

Reaktive REST-Webservices mit Spring WebFlux