empros gmbh - process & information management services
1009-chatExperience is the hardest kind of teacher.
It gives you the test first and the lesson afterward.

-Susan Ruth

Tell, Don't Ask!

Heuristik

Sagen Sie Ihren Objekten, was zu tun ist, anstatt ihnen Löcher in den Bauch zu fragen.

Erklärung

Diese Faustregel soll uns helfen, das Beck'sche "Put together what changes together" zu beherzigen und Objekte zu vermeiden, die lediglich dumme Datenklumpen sind und selber kein sinnvolles Verhalten zeigen. Objekte exponieren ihre Verhaltensweisen und nicht ihren (internen) Zustand, d.h. wir sind daran interessiert, was ein Objekt tut und nicht, in welchem Zustand es sich befindet.

Gerade in Sprachen wie Java, C++, Delphi oder C# kann es leicht passieren, dass man aufgrund der grossen Ähnlichkeit von herkömmlichen Prozeduren und Methoden die vorliegende Faustregel verletzt. Und so sind die mit Getter und Setter übersäten Klassen in vielen Entwürfen allgegenwärtig; mit drastischen Folgen für die Wartbarkeit der Software.

"Tell, don't ask" soll uns daran erinnern, dass es falsch ist, von ausserhalb eines Objekts Fallunterscheidungen aufgrund dessen internen Zustandes zu fällen. Der Zustand eines Objektes muss uns nicht interessieren, das Objekt soll lediglich tun, was wir ihm sagen. Wenn wir aufgrund des Zustandes eines Objektes entscheiden, was zu tun ist, dann müssen wir uns fragen, warum wir diese Entscheidung nicht dem Objekt selber überlassen. In der Regel lautet die Antwort: Weil wir einen Fehler gemacht haben.

Diese Faustregel hilft uns, schüchternen Code zu schreiben, der dem DRY-Prinzip folgt. Sie sorgt dafür, dass die Funktionen, die auf den Daten wirken, nur einmal umgestzt werden müssen, nämlich in der Klasse, welche die dazugehörigen Daten verwaltet.

"Tell, don't ask" kann durchaus noch verfeinert werden zu: "Tell and don't ask to tell." Denn auch dies ist eine weitverbreitete Unsitte: Der Zustand eines Objektes wird abgefragt, um diesem dann den "richtigen" Befehl zu erteilen. Diese Variante ist fast noch schlimmer als die erste, denn hier wird Logik, die eigentlich zusammengehört ungebührlich verteilt. So sollte z.B. die Anweisung

if (!aConnection.isActive()) aConnection.activate();


besser ersetzt werden durch

aConnection.activate();

Das Connection-Objekt kann nämlich selber entscheiden, ob es diesen Befehl tatsächlich ausführen muss, oder ob dies nicht nötig ist, weil es bereits vorgängig aktiviert worden ist.

Wir sollten der Versuchung, den internen Zustand eines Objektes nach aussen bekannt zu geben, solange wie möglich widerstehen. Wie ein Objekt seine Aufgabe erledigt und welche internen Zustände es hierzu abbilden muss, liegt in der Verantwortung des Objektes selber. Dabei wollen wir dafür sorgen, dass das Systemverhalten ausgewogen auf die einzelnen Klassen im System gemäss dem Single Responsibility Principle verteilt wird. Übrigens bietet die testgetriebene Entwicklung mit Mock-Objekten eine gute Möglichkeit, Schnittstellen zu entwerfen, die dem Grundsatz "Tell, don't ask" folgen.