Follow my new blog

Donnerstag, 23. Mai 2013

Gleich zu Gleich für Clean Code

Letzten Dienstag habe ich im wöchentlichen Unterrichtsblock der Clean Code Developer School (ccd-school.de) “TDD as if you meant it” anhand der Kata WordWrap vorgestellt. Dann wollten die Teilnehmer es selbst probieren. Als Aufgabe habe ich die Kata ToDictionary vorgeschlagen.

Leider führte die dann nicht in so geradliniger Weise zu “Refactoring-Druck”, wie ich es mir erhofft hatte. Es wollten nicht die schönen Wiederholungsmuster wie bei WordWrap auftreten. Mist.

Jetzt habe ich sie selbst nochmal durchgeführt. Hier ein Zwischenstand:

image

Es gibt ein Muster:

  • Deutliche ist es zu sehen im zweiten Test, wo die Aufteilung einer Zuweisung (z.B. “a=1”) in Key und Value (z.B. “a” und “1”) mit anschließendem Eintrag in das Dictionary zweimal geschieht.
  • Weniger deutlich ist es im ersten Test, wo das auch passiert, aber in etwas anderer Form.

Aber was für ein Refactoring-Druck entsteht dadurch? Sollte ich Split()+Add() in eine eigene Methode rausziehen? Dann würde die Erzeugung des Dictionary zurückbleiben. Hm… das fühlt sich nicht gut an.

Ebenfalls unschön ist, dass die Erzeugung des Dictionary im zweiten Test “weit weg” von seiner Nutzung steht. Mir wäre dies lieber:

image

Wenn früher in Sprachen Deklarationen am Anfang eines Unterprogramms stattfinden mussten, dann hatte das weniger mit sauberem Code zu tun, als vielmehr mit der Notwendigkeit zu simpleren Parsern, würde ich sagen. Heute ist das kein Thema mehr. Also können Deklarationen stehen, wo es für das Verständnis sinnvoll ist. Und das, so scheint mir, ist nahe ihres Gebrauchsortes.

Außerdem sollten Deklarationen nur die kleinstmögliche Reichweite/Sichtbarkeit haben. Das beugt unnötiger/zufälliger Kopplung vor.

Dito sollten die Verwendungen von Variablen nahe beieinander stehen. Sie sind ja natürlich kohäsiv. Deshalb würde ich auch die zweite Eintragung an die erste rücken wollen:

image

Selbiges gilt für den Zugriff auf assignments. Also sollten die Aufteilungen der Zuweisungen in Key und Value beieinander stehen:

image

Und schon sieht die Welt viel musterhafter aus, oder? Hier sind Wiederholungen zu sehen, die nach Zusammenfassung schreien. Mit Linq ist das ganz einfach, ohne neue Methoden erzeugen zu müssen:

image

Das ist dann vielleicht noch nicht so gut zu lesen wie eine weitere Kapselung:

image

Doch mit oder ohne eigene Methoden ist die Zusammenfassungen besser zu lesen. Indem ich Gleich und Gleich sich habe gesellen lassen, statt dem ersten Impuls nach Auslagerung eines Musters zu folgen, ist die Sauberkeit noch größer geworden, würde ich sagen. Nun sind die wesentlichen Aspekte der Problemlösung deutlich zu sehen. Es ist klar, wie die Lösung voranschreitet. Insbesondere bei weiterer Kapselung der Aspekte in Methoden ist ToDictionary() sehr leicht zu lesen.

Kommentare:

Anonym hat gesagt…

Hallo Ralf,

interessanter Denkansatz :)

Btw. wird in dem Screenshot unter "Selbiges gilt für den Zugriff auf assignments. Also sollten die Aufteilungen der Zuweisungen in Key und Value beieinander stehen:"
kvpair nicht überschrieben?

Müsste es hier nicht eher heißen:

[code]
var assignments = config.Split(';');

var kvpair0=assignments[0].Split('=');
var kvpair1=assignments[1].Split('=');

var dict = new Dictionary();
dict.Add(kvpair0[0], kvpair0[1]);
dict.Add(kvpair1[0], kvpair1[1]);
[/code]

Grüße T

Ralf Westphal - One Man Think Tank hat gesagt…

@T: Der Screenshot ist doch nur ein Zwischenstand. Natürlich funktioniert das nicht. Aber es zeigt das Muster. Danach mache ich ja weiter.

anonym hat gesagt…

Warte mal - lese ich das richtig? Du implementierst das ZWEIMAL, nur damit beim zweitenmal endlich das erwartete Verhalten rauskommt?

Ist das ein praxisübliches Pattern? Wir wiederholen das solange, bis die Praxis zur Theorie paßt?

Ralf Westphal - One Man Think Tank hat gesagt…

@Anonym: Ich implementiere nicht zweimal. Aber ich schreibe "Lösungscode" in den Test - dabei kann es vorkommen, dass in zwei Tests Ähnliches steht. Und das ist tatsächlich gewollt. So entstehen Muster über mehrere Tests hinweg. Die refaktorisiere ich natürlich irgendwann raus. So gibt es am Ende eben alles nur einmal. Aber die Muster sollen entstehen. Das ist der Trick bei "TDD as if you meant it". Lies dort nach. Probier es dann aus. In der dotnetpro habe ich darüber in diesem Jahr ausführlicher geschrieben.