Freitag, 7. November 2014

Einfachheit der Struktur - Kohäsion

Im vorherigen Artikel haben wir uns mit dem Unterschied tatsächlich realisierter System-Strukturen und möglicher System-Strukturen beschäftigt. Wir haben festgestellt, dass beide Aspekte einen Einfluss auf die Einfachheit eines Systems haben:
  • Je mehr tatsächlich realisierte (aktuale) Elemente und Relationen ein System aufweist, desto weniger einfach ist es.
  • Je weniger ein System die Anzahl der möglichen (potentiellen) Elemente und Relationen einschränkt, desto weniger einfach ist es.
In diesem Artikel werden wir uns nun mit dem Zusammenhang zwischen Einfachheit und Kohäsion beschäftigen.

1. Kohäsion im strukturierten Design

In der spezifischen Terminologie des strukturierten Designs von Edward Yourdon und Larry L. Constantine bezeichnet Kohäsion den Grad, in dem die Elemente eines Moduls zusammengehören (engl. "the degree to which the elements of a module belong together" [Yourdon1979]). In dieser Terminologie ist noch klar, von welchen Elementen die Rede ist, nämlich von Modulen im Sinne des strukturierten Designs und ihren inneren Elementen. Dies gilt insbesondere auch für den Zusammenhang zwischen Kohäsion und Kopplung: Während die Kohäsion der Elemente innerhalb eines Moduls hoch sein soll, soll die Kopplung der Module untereinander gering sein. Was ich Kohäsion und was Kopplung nenne, ergibt sich aus dem Zusammenhang: Intramodular spreche ich von Kohäsion, extramodular von Kopplung.

2. Kohäsion aus der Sicht der System-Hierarchie

In Bezug auf moderne Software-Systeme wird Kohäsion jedoch nicht nur als Eigenschaft von Modulen (oder ihren objektorientierten Nachfolgern, den Klassen) gesehen, sondern auch auf andere Ebenen wie Services, Subsysteme, Pakete oder physische Einheiten angewandt. In meinem Blogartikel zum Prinzip der hohen Kohäsion habe ich daher allgemeiner von "Software-Elementen" an Stelle von Modulen gesprochen. 

Im Zuge der Besprechung des allgemeinen Modells für Software-Systeme hat sich gezeigt, dass die verschiedenen Element-Typen, auf die man das Konzept der Kohäsion anwenden kann, hierarchisch strukturiert sind. Jede Betrachungs-Ebene setzt bestimmte Elemente in Relation. Auf der nächst tieferen Ebene enthält jedes dieser Elemente Subelemente, die ebenfalls in Relation zueinander stehen usw. Damit ergibt sich jedoch für die Konzepte der Kohäsion und der Kopplung ein grundlegendes Problem: Aus der Sicht einer bestimmten Ebene (z. B. der Pakete) wird der Zusammenhang der Subelemente dieser Ebene (in Bezug auf Pakete sind dies die Typen) als "Kohäsion" bezeichnet. Aus der Sicht der nächst tieferen Ebene wird jedoch der Zusammenhang derselben Elemente zur "Kopplung". 

Betrachte ich also beispielsweise ein Paket, so resultiert aus der Forderung nach hoher Kohäsion, dass die darin enthaltenen Typen eng zusammengehören sollen. Auf der Ebene der Typen wird jedoch das, was auf Paket-Ebene "hohe Kohäsion" war, zu einer "starken Kopplung". Was aus der Sicht der Paket-Ebene gut war (hohe Kohäsion), wäre demnach aus der Sicht der Typ-Ebene schlecht (starke Kopplung). Wie lässt sich dieser Widerspruch erklären?

3. Die Auflösung des Widerspruchs

Im letzten Artikel hatten wir festgestellt, dass alle Relationen letztlich auf die Ebene der Funktionen und Daten-Objekte zurückzuführen sind. Wir hatten diese Relationen, die entweder zwischen Funktionen und Funktionen oder zwischen Funktionen und Daten-Objekten bestehen, als funktionale Relationen bezeichnet. Relationen auf höheren Ebenen sind lediglich Projektionen der funktionalen Relationen auf die Elemente der höheren Ebene. Für die weitere Erläuterung treffe ich folgende begriffliche Unterscheidung:
  • Eine auf eine Struktur-Ebene E projizierte Relation zwischen zwei Struktur-Elementen dieser Ebene bezeichne ich als externe Relation.
  • Sei die Struktur-Ebene E die aktuelle Betrachtungs-Ebene und die Ebene F die nächst tiefere Ebene. Dann bezeichne ich die Relationen der Ebene F als interne Relationen.
Was eine interne und eine externe Relation ist, hängt somit von der Betrachtungs-Ebene ab. Es ist nun zunächst festzustellen, dass die Anzahl der funktionalen Relationen völlig unabhängig von der Gruppierung der Funktionen und Daten-Objekte in Elementen höherer Ebene ist.  Aus der Sicht des Gesamtsystems ändert sich also die aktuale Strukturkomplexität nicht abhängig davon, wie Funktionen und Daten-Objekte auf höheren Ebenen zusammengefasst werden. 

Hohe Kohäsion bedeutet in diesem Sinne keine Änderung der Kopplung des Gesamtsystems, sondern lediglich eine Bündelung der Kopplungen an bestimmten Positionen in höheren Struktur-Ebenen. Jede solche Struktur-Ebene ist dazu geschaffen, die Elemente der nächst tieferen Ebene zu partitionieren und dabei diejenigen Elemente, die besonders viele Relationen eingehen, aus der Sicht dieser Ebene möglichst nahe aneinander zu positionieren. Betrachten wir zur Veranschaulichung die folgende Abbildung:
Quelle: NASA, via Wikipedia Commons
Bereiche hoher Kohäsion lassen sich mit Ballungsräumen vergleichen. Im Bereich der Software müssen diese Ballungsräume, die tatsächlich lediglich auf der Ebene funktionaler Relationen bestehen, vom Entwickler oder Architekten erkannt und korrekt auf die jeweilige höhere Struktur-Ebene übertragen werden. Erst beim Ziehen der Grenzen dieser höheren Struktur-Elemente tritt das Phänomen der Kohäsion auf: Werden die Grenzen so gezogen, dass sie den Ballungen funktionaler Relationen entsprechen, so wird die Kohäsion der Elemente dieser Ebene hoch und die Kopplung dieser Elemente untereinander gering sein. Im nächsten Abschnitt werde ich diese Übertragungs-Aufgabe an einem Beispiel näher erläutern.

4. Beispiel einer Strukturbildung auf höherer Ebene

Die Abbildung zeigt eine beliebige Struktur, die wir keiner konkreten Ebene zuordnen müssen. Es wäre aber denkbar, dass es sich bei den Elementen um Funktionen und Daten-Objekte handelt und bei den Relationen um Funktionsaufrufe und Zugriffe auf die Daten-Objekte. Ich werde diese Ebene im Folgenden e1 bezeichnen. Auf Grund der Anzahl der Elemente und Relationen erscheint dem Betrachter diese Struktur alles andere als einfach.
Hier wird dieselbe Struktur wie zuvor dargestellt. Die Elemente sind jedoch etwas gruppiert worden. Es fällt auf, dass die Struktur sofort übersichtlicher erscheint.
Die an Hand ihrer Relationen nahe zusammenliegenden Elemente wurden jetzt in ein übergeordnetes Struktur-Element "eingeschlossen". Zwischen den übergeordneten Struktur-Elementen ergeben sich neue (projizierte) Relationen, die gepunktet in das Diagramm eingezeichnet wurden. Aus der Sicht der übergeordneten Struktur-Ebene hat sich die Struktur damit deutlich vereinfacht. Ich nenne diese Ebene im Folgenden die Ebene e2:

Die hier gewählte Aufteilung ist vergleichsweise grob. Es wäre auch eine etwas feinere Aufteilung möglich gewesen:
Wohlgemerkt hat sich auch hier nichts an den Relationen der Ebene e1 geändert, lediglich die Aufteilung der Elemente aus e1 in der Ebene e2 wurde anders vorgenommen. Aus der Sicht von e2 erscheint diese Lösung weniger einfach. Andererseits könnte man der gröberen Aufteilung vorwerfen, dass die einzelnen Struktur-Elemente der Ebene e2 etwas zu groß geraten sind. Vergleichen wir die einzelnen Struktur-Elemente der Ebene e2 in der ersten und zweiten Lösung:
Die Struktur-Elemente der grobgranularen Lösung weisen für sich genommen noch eine beachtliche Komplexität auf, während die Elemente der feingranularen Lösung bereits sehr einfach wirken. Die Frage lautet, ob das Konzept der Kohäsion bei weiterhin rein struktureller Betrachtung (wir blenden also semantische Aspekte bewusst aus) eine Entscheidungshilfe für dieses Problem anbietet. Zu diesem Zweck werde ich Kohäsion im folgenden Abschnitt etwas formaler betrachten.

5. Kohäsion nach Wang

[Wang2007] stellt ein Modell der Kohäsion vor, das sich sehr allgemein auf Systeme und Subsysteme anwenden lässt und damit für unsere Zwecke ein guter Ausgangspunkt ist. Ich werde im Folgenden, um die hier eingeführte Terminologie beizubehalten, allgemein von Elementen und Subelementen sprechen. Als "Element" bezeichne ich dabei die aktuell betrachtete Einheit einer bestimmten Ebene. Als "Subelement" bezeichne ich die Einheiten der nächst tieferen Ebene, die durch dieses Element gruppiert werden.

Jedes Element weist die folgenden Relationen auf:
  • Ri: eingehende Relationen (Input)
  • Ro: ausgehende Relationen (Output)
  • Rc: interne Relationen zwischen den Subelementen des Elements
Wang definiert nun die Kohäsion eines Elements E wie folgt:
Kohäsion und Kopplung sind in diesem Modell komplementär, d. h. es gilt: Kohäsion + Kopplung = 1. Das Modell ist insbesondere deshalb interessant, weil Kohäsion kein bloßes Attribut der betrachteten Einheit ist, sondern die externen Relationen dieser Einheit mitbetrachtet. Hohe Kohäsion führt hier automatisch zu schwacher Kopplung und umgekehrt.

Wenn wir diese Betrachtungsweise auf die beiden Lösungsansätze (grobgranular / feingranular) des vorherigen Absatzes anwenden, so zeigt sich, dass die grobgranulare Lösung über erheblich mehr interne Relationen verfügt und somit den besseren CH-Wert aufweist. Die Kohäsion wächst also mit der Anzahl der internen Relationen, so lange dabei nicht auch die externen Relationen wachsen. 

Das Problem dieser Betrachtungsweise ist, dass die Anzahl und Anordnung der Elemente nicht berücksichtigt wird. Es widerspricht der Grundidee der Kohäsion als "degree to which the elements belong together" dass Elemente, in die immer mehr Subelemente und ihre Relationen aufgenommen werden, zu immer höherer Kohäsion führen. 

Tatsächlich zielt die Kohäsion letztlich auf eine Größenbeschränkung ab: Es sollen eben gerade nicht Subelemente zusammengefasst werden, die nicht zusammengehören. Je mehr Subelemente ein Element enthält, desto größer wird jedoch die Wahrscheinlichkeit, dass diese Subelemente nicht alle zusammengehören.

6. Anpassung von Wangs Kohäsions-Modell

Um diesen Mangel an Wangs Kohäsionsmodell besser zu verstehen, betrachten wir die folgenden beiden Lösungen, wobei die linke Lösung der oben gezeigten grobgranularen Lösung entspricht:
Die Lösungen (a) und (b) weisen dieselbe Anzahl von Elementen und Relationen und somit auch einen identischen CH-Wert auf (gleiche externe Relationen vorausgesetzt). In Lösung (b) gruppieren sich jedoch die Subelemente um ein Zentrum, was den Eindruck großer Zusammengehörigkeit vermittelt. Es ist kaum vorstellbar, dass es sinnvoll sein könnte, eines der Subelemente in ein anderes Element zu verlagern. Ganz anders bei Lösung (a). Die Zusammengehörigkeit erscheint hier viel weniger stark, und es ist durchaus nicht klar, ob eine weitere Partitionierung (siehe feingranulare Lösung oben) nicht doch sinnvoller sein könnte.

Eine Möglichkeit, diesen Unterschied auszudrücken, besteht in der Berücksichtigung der Distanzen zwischen den Subelementen. Ignoriert man die Gerichtetheit der Relationen, so kann man zwischen je zwei Subelementen einen kürzesten Pfad finden, der diese beiden Subelemente verbindet. In Lösung (a) liegt die durchschnittliche kürzeste Distanz etwas über 4, in Lösung (b) liegt sie bei 2. Die maximale durchschnittliche kürzeste Distanz entsteht bei Ketten oder Kreisen und liegt bei maxavg_dist = (n - 1) * n / 2. Die minimale durchschnittliche kürzeste Distanz entsteht bei vollständigen Graphen und beträgt minavg_dist = n - 1. Je näher sich die durchschnittliche kürzeste Distanz dem Wert minavg_dist nähert, desto weniger scheinen die Subelemente zusammengehörig. 

Wir können uns vorstellen, dieses Konzept auf einen Faktor zwischen 0 und 1 zu normalisieren. Der Faktor nimmt den Wert 0 an, wenn der Graph der Subelemente aus unverbundenen Teilgraphen besteht. Er nimmt den Wert 1 an, wenn jedes Subelement in direkter Relation zu jedem anderen Subelement steht, also für vollständige Graphen. Bezeichnen wir diesen Faktor als Nähe, so lässt er sich wie folgt in die Kohäsionsformel von Wang integrieren:
Auch diese Lösung differenziert verschiedene Formen der Kohäsion noch nicht perfekt. Ein Problem des Konzepts der Nähe ist, dass es im Einzelfall durchaus sinnvoll sein kann, Verkettungen der folgenden Art zu konstruieren:
Derartige Konstrukte können Pipelines oder auch geschachtelte Funktionsaufrufe sein, die im Einzelfall gerechtfertigt sind und faktisch auch eine große Zusammengehörigkeit aufweisen. Andererseits sind sehr lange Verkettungen dieser Art doch eher eine Seltenheit.

7. Andere Kohäsionsmodelle

Das Kohäsionsmodell von Wang setzt interne Relationen zu externen Relationen in ein Verhältnis. Insbesondere im Kontext der Software-Messung wurden jedoch zahlreiche andere Vorschläge zur Modellierung von Kohäsion gemacht. Da es die Möglichkeiten eines einzelnen Artikels übersteigen würde, all diese Ansätze zusammenzufassen, sei an dieser Stelle auf die einschlägige Literatur verwiesen. Übersichten vorgeschlagener Kohäsionsmaße geben bspw. [Fenton2014], [Sneed2010] oder [Diederichs2005].

Für die spätere Betrachtung von Kohäsion auf System-Ebene sowie ein besseres Gesamtverständnis dafür, wie Kohäsion und Kopplung im Zusammenspiel die Komplexität von Software-Systemen beeinflussen, möchte ich an dieser Stelle jedoch einige Annahmen explizit machen, die wir beim Nachdenken über Kohäsion oftmals unausgesprochen voraussetzen:
  1. Wir haben Kohäsion bislang als eine Eigenschaft einzelner Software-Elemente aufgefasst. Wir setzen voraus, dass sich aus den Ausprägungen der Kohäsionen der einzelnen Software-Elemente eine Gesamtkohäsion auf System-Ebene ermitteln lässt. Ich nenne diese den Kohäsionsgrad des Systems. Wäre dies nicht möglich, so könnten wir uns bei der Zusammenfassung der Elemente eines Systems nicht sicher sein, ob wir nur lokale Optimierungen vornehmen, die ggf. zu Lasten des Gesamtsystems gehen. Kohäsion wäre dann als Eigenschaft unbrauchbar, um Entscheidungen auf System-Ebene zu treffen.
  2. Der Kohäsionsgrad zweier verschiedener Systeme S1 und S2 lässt sich vergleichen, d. h. für zwei beliebige Systeme S1 und S2 lässt sich feststellen, ob der Kohäsionsgrad von S1 höher, gleich oder niedriger ist. Wäre dies nicht möglich, so würde der festgestellte oder vorhergesagte Kohäsionsgrad zweier Lösungen keinen Beitrag zur Entscheidungsfindung zwischen verschiedenen Lösungen leisten können.
  3. Der Kohäsionsgrad eines gegebenen Systems bewegt sich zwischen einem Minimum und einem Maximum. Die Annahme einer unendlich großen Zusammengehörigkeit ist ebenso sinnlos wie die Annahme einer unendlich großen Zusammengehörigkeit.
Ich möchte an dieser Stelle nicht näher untersuchen, warum diese Annahmen getroffen werden können. Ohne diese Voraussetzungen wäre Kohäsion als Eigenschaft von Software-Systemen jedoch nur sehr eingeschränkt nützlich.
 

8. Kohäsion und Einfachheit

Warum steigert hohe Kohäsion die Einfachheit einer Struktur? 
  • Hohe Kohäsion auf einer Struktur-Ebene geht mit einer geringeren Anzahl von Relationen auf der nächst höheren Struktur-Ebene einher. Diese nächst höhere Ebene wird daher als einfacher wahrgenommen.
  • Die Forderung nach enger Zusammengehörigkeit (engl. togetherness) verhindert ein übermäßiges Wachstum der einzelnen Einheiten. Jede Einheit weist für sich genommen eine kompakte und dichte Struktur auf, die im Vergleich zu einer weitläufigen und verstreuten Struktur als einfacher wahrgenommen wird.
  • Allgemein führt die enge Zusammengehörigkeit der Elemente in einer kohäsiven Einheit dazu, dass die Einheit als ein sinnvolles Ganzes wahrgenommen wird. Der Umgang mit sinnvollen Einheiten ist einfacher als der Umgang mit Einheiten, deren Bedeutung nicht klar umrissen ist.

9. Empirische Bestätigung

Das hier vorgestellte Kohäsionsmodell und der Zusammenhang zwischen Kohäsion und Einfachheit wird durch die Untersuchung "The Structural Complexity of Software" von C. F. Kemerer und Kollegen [Kemerer2005] empirisch unterstützt. Die Untersuchung trifft folgende Annahmen:
  • Komplexität wird in Form von Aufwand (engl. effort) bei der Durchführung von Wartungsaufgaben operationalisiert.
  • Kohäsion und Kopplung eines Beispielprogramms werden systematisch modifiziert, so dass sich die vier Varianten (1) geringe Kohäsion/geringe Kopplung, (2) geringe Kohäsion, starke Kopplung, (3) hohe Kohäsion/geringe Kopplung und (4) hohe Kohäsion/starke Kopplung ergeben. Dieses Programm wird erfahrenen Software-Entwicklern zwecks Durchführung einer Wartungsaufgabe übergeben. Die Zeit zur Durchführung der Aufgabe wird gemessen und als Maß für den erforderlichen Aufwand interpretiert.
Ein wesentliches Ergebnis der Studie ist, dass geringe Kohäsion insbesondere im Zusammenhang mit starker Kopplung (Variante (2) zu einer deutlichen Komplexitätssteigerung führt. Es wird die folgende Schlussfolgerung gezogen:
"The implication of this result is that when designing, implementing, and maintaining software to control complexity, both coupling and cohesion should be considered jointly, instead of independently." [Kemerer2005]
Das oben vorgeschlagene Kohäsions-Modell wird dieser Forderung gerecht, indem Kohäsion als Funktion sowohl der internen wie auch der externen Relationen betrachtet wird.

10. Zusammenfassung

In diesem Artikel haben wir den Zusammenhang zwischen Einfachheit und Kohäsion aus einer strukturellen Perspektive untersucht. 

Dabei war zunächst das Konzept der Kohäsion, das ursprünglich nur auf eine klar definierte Struktur-Ebene angewandt wurde, auf eine Hierarchie von Struktur-Ebenen zu übertragen, wie man sie in modernen Software-Systemen antrifft. Es wurde festgestellt, dass die Eigenschaft der Kohäsion erst bei der Bildung von Elementen höherer Struktur-Ebenen auftritt. Erfolgt die Grenzziehung bei der Bildung solcher Elemente richtig, so wird die Kohäsion maximiert und gleichzeitig die Kopplung unter den Elementen der neuen Ebene minimiert. 

Das Kohäsionsmodell von Wang spiegelt diesen Zusammenhang in einem einfachen Verhältnis der internen Relationen zur Summe der internen und externen Relationen. Um dem Größenwachstum der einzelnen Elemente entgegenzuwirken wurde zusätzlich das Konzept der Nähe eingeführt. Sind sich die Subelemente eines Elements im Durchschnitt weniger nahe, so führt dies zu einer Schwächung der Kohäsion. 

Die Grenzen dieses Modells sind im Bereich der Semantik anzutreffen und gehen somit über die hier angestellte rein strukturelle Betrachtung hinaus. Semantische Kohäsionskonzepte wie z. B. das Single-Responsibility Prinzip sind im Einzelfall immer erforderlich, um die strukturelle Sicht zu ergänzen.

10. Quellen

[Diederichs2005] - Komplexitätsreduktion in der Softwareentwicklung, Henner Diederichs (2005)

[Fenton2014] - Software Metrics: A Rigorous and Practical Approach, Third Edition, Norman Fenton (2014)

[Kemerer2005] - The Structural Complexity of Software: An Experimental Test - David P. Darcy, Chris F. Kemerer, Sandra A. Slaughter, James E. Tomayko (2005) 

[Sneed2010] - Software in Zahlen - Die Vermessung von Applikationen, Harry M. Sneed, Richard Seidl, Manfred Baumgartner (2010)

[Wang 2007] - Software Engineering Foundations - A Software Science Perspective, Wang, Yingxu (2007) 

[Yourdon1979] -  Structured design. Fundamentals of a discipline of computer program and systems design, Yourdon, E., Constantine, L. (1979)