Montag, Dezember 10, 2012

Brauchbare Klassendiagramme

Mich überrascht immer wieder, wie sehr Klassendiagramme in einer undefinierten Grauzone schweben zwischen Modellbeschreibung einer Problemdomäne und Dokumentation der Implementierung. Das ist nicht nur ein "Problem" von Studierenden, sondern auch von Profis.

Ein Klassendiagramm kann zwei Zwecken dienen, die sich an zwei Fragen festmachen lassen:

Dient das Klassendiagramm zur Erfassung einer gedanklichen, logischen Zerlegung einer fachlichen Problemdomäne (Modellierung)? Oder dient es zur Dokumentation der Klassenbezüge im Code einer Implementierungssprache (Realisierung).

Meist "hängt" ein Klassendiagramm genau zwischen diesen Welten und ist am Ende weder ein ausdrucksstarkes Modell (da es Ausdrucksmittel der UML ungenutzt lässt), noch eine korrekte Beschreibung der Realisierung, die in aller Regel das Klassendiagramm nicht einmal sauber umsetzt.

Um es konkreter zu machen:

Oftmals wird in Klassendiagrammen keine Mehrfachvererbung verwendet, obwohl sie bisweilen sehr elegante Zerlegungen und Wiederverwendungen von Modellanteilen erlaubt. Warum? Weil die Implementierungssprache (z.B. Java, C#) Mehrfachvererbung nicht kennt. -- Das sollte zwar kein Grund sein, sich in den Ausdrucksmöglichkeiten zurück zu halten, ist es aber faktisch immer wieder! Interessanterweise eben genau bei dem Thema "Mehrfachvererbung".

Andererseits sehe ich sehr oft, wie die Komposition und bisweilen auch die Aggregation in Klassendiagrammen verwendet wird. Dabei bietet keine mir geläufige OO-Sprache ein Sprachkonstrukt für die Komposition/Aggregation an -- vom Hörensagen ist eventuell Eiffel die große Ausnahme. Merkwürdigerweise scheint das Fehlen von Komposition und Aggregation in der Zielsprache den wenigsten Modellierer(inne)n Sorgen zu machen, ganz im Gegensatz zur Mehrfachvererbung. Dabei habe ich -- und das ist das Kuriose daran -- (fast) noch nie Implementierungscode gesehen, der die Komposition oder Aggregation korrekt umsetzt. Die wenigsten Programmierer(innen) wissen, wie Komposition in Code geht, und auch die gängigen Modellierungswerkzeuge versagen mit ihren Code-Generatoren an dieser Stelle oftmals kläglich.

Damit sind Klassendiagramme merkwürdige Artefakte: Sie sind oft halbherzige Modellbeschreibungen mit einem sehr implementierungszentrischen Blick. Und gleichzeitig versagen sie als Dokumentation des Programmcodes, der die vom Klassendiagramm geforderten Strukturbeziehungen nicht wirklich einlöst.

Darum halte ich es für sinnvoll, sauber und klar in zwei Klassendiagrammen zu denken, die den Unterschied zwischen fachlichem Modell und Implementierungsdokumentation offen legen und bewusst machen, statt ein Klassendiagramm mit unklarem Bezug und fraglichem Nutzen zu erstellen. Da viele IDEs wie z.B. Eclipe immerhin einfache Klassendiagramme aus der Implementierung abzuleiten vermögen, sollte der Fokus auf zwei Punkten liegen:

  1. Gute Klassendiagramme zu entwerfen, die die Problemdomäne versuchen ausdrucksstark zu modellieren -- ohne auf die Implementierungssprache zu schielen.
  2. Zu dokumentieren, wie das Klassendiagramm in die Zielsprache übertragen wird, so dass deutlich ist, wo Programmierdisziplin mit Blick auf das Modell eingefordert werden muss, und wo der Programmcode das Modell sauber umsetzt.


Kommentare:

Lars hat gesagt…

Prinzipiell alles richtig. Aber das Dilemma fängt für mich schon bei der Metasprache des Diagramms an, die formal nicht mit unserer Umgangssprache übereinstimmt.

Gerade die Semantik des Vererbungsbegriffs inkl. Lebenszyklus ist im Umgangssprachlichen in seiner Bedeutung so unklar, dass in der Praxis meist gar keinen Sinn macht, sich auf Diskussionen mit Fachexperten einzulassen, um ein fachlich orientiertes Modell völlig frei eines bestimmten Lösungsraums (Programmiersprache etc.) aufzubauen.

Aber es geht ja auch anders: In den Beschreibungslogiken, die ja auch dem Semantic Web zu Grunde liegen (OWL, etc.) gibt es Mehrfachklassifikation in einem eher an die Mengenlehre angelehnten Denken. Dort ist es im System inbegriffen, über die Definition zu einer Klassenzugehörigkeit von Instanzen zu gelangen. Damit sehen für Experten aus diesem Bereich auch die "konzeptionellen Entwürfe einer Lösung" (zu denen ich ein Klassendiagramm auch zähle) eben ganz anders aus.

Ganz pragmatisch gehört es IMHO aber zur Aufgabe eines Lösungslieferanten, die Anforderungen eines Stakeholders so aufzubereiten, dass sie technisch realisierbar sind. Dazu gehört eben typischerweise auch eine frühe Unterscheidung in Klassen (direkt gekopppelt an Verhalten und in typischen Sprachen nicht dynamisch änderbar) und Assoziationen (dynamisch änderbar).

dh hat gesagt…

Danke für die schönen, ergänzenden Gedanken, Lars! Die Anmerkung zu den Beschreibungslogiken finde ich sehr gut.

Übrigens orientiert sich das Klassenmodell von Factor mehr an der Mengenlehre als ich es von irgendeiner anderen OO-Sprache her kenne. Da gibt es "Vereinigungsklassen" und "Schnittmengenklassen". Das ist vollkommen logisch und konsistent.

http://docs.factorcode.org/content/article-classes.html