# Class Fan-Out Complexity



## realjoda (1. April 2009)

Hoi, ich muss in einem Projekt die Fan-Out Complexity reduzieren.

Erlaubt ist ein Wert bis zu 30 und es treten Werte bis 64 auf...
In erster linie werden die hohen Werte durch Interface Klassenvariablen erreicht (weiß nich tob ich mich so richtig ausdrücke  )
Code kann ich euch leider nicht hier posten aber falls nähere Beschreibungen notwendig sind werden die folgen.

Vll. hat jmd. shcon damit zu tun gehabt und weiß wie man Fan-Out Comlexity auflösen kann.

Ich habe auch erst nur eine Definition gefunden für dieses Problem:
"Fan-in/fan-out. For any module M, the fan-in of M is the count of the modules that call M plus the number of global data elements. The fan-out of M is the count of modules called by M plus the number of global data elements altered by M. "

Gruß
Joda


----------



## Oliver Gierke (1. April 2009)

Wenn man die ganze Pseudowissenschaft mal weglässt heißt das im Klartext nichts anderes als Dependencies reduzieren, Packages restrukturieren. Finds aber etwas strange, dass einem sowas zugetragen wird wenn nicht mal weiß, was Fan-Out genau ist bzw. wo das Problem dabei ist (keine Kritik an dir, eher eine grundsätzliche Frage).

Was ich dir dazu empfehlen kann ist das Agile Software Development - Principles, Patterns, Practices von Robert "Uncle Bob" Martin. In dem wird sehr detailliert auf Codemetriken eingegangen, warum Dinge wie Zyklenfreiheit wichtig sind und wie man Applikationen am besten (um)strukturiert. Eine Warnung vorweg: das ist nichts, was man sich mal eben anliest. Vor allem, weil es wie so oft kein wahr/falsch gibt, sonder es viel Fingerspitzengefühl bedarf.

Sehr entscheident ist hierbei auch der Scope. Bezieht sich der Fan-Out auf ein Projekt, ein Subsystem, ein Modul, ein Package, eine Klasse? Je nach Scope ändert sich die Semantik von "außen" ja stark, so dass es bei einer Klasse z.B. in gewissen Fällen kein Problem ist, einen großen Fan-Out zu haben, wenn die meisten Abhängikeiten im Package der Klasse selbst liegen. Zwischen Modulen und Subsystemen sollte eigentlich nur über dedizierte Interfaces und Typen gesprochen werden. IMHO ist dabei eine Zyklenfreiheit wesentlich wichtiger als ein geringer Fan-Out, wenn auch ein großer Fan-Out das Risiko birgt, dass sich Zyklen einschleichen. Wie du siehst - kein einfaches Brot. 

Als Grundlegende Arbeitstechniken würde ich hierbei allerdings das Einführen von Interfaces und Dependency Injection nennen. Damit wird man recht gut Dependencies los, wenn man vorher sehr viele Abhängigkeiten hatte die auf Implementierungsklassen gingen. Allerdings bedeutet das in vielen Fällen recht größerere Refactorings, womit wir wieder bei der Frage sind, wie das jemand ernsthaft bewerten, einschätzen und umsetzen soll, der sowas bisher nicht gemacht hat.

Aber - um noch was positives zu sagen - ich finde es gut, dass solcherlei Probleme in deiner Firma scheinbar erkannt und aktiv angegangen werden. Viele schieben sowas oft vor sich her bzw. achten gar nicht darauf und wundern sich dann, warum sie ihre Software alle 2 Jahre neu schreiben müssen.

Gruß
Ollie


----------



## realjoda (1. April 2009)

OK, ich danke dir schon mal. Mit Dependency Injection hatte ich schon zu tun, allerdings nicht bei solch komplexen Code, sondern nur bei Übungsklassen. Werde mich nochmal einlesen. Das Buch sieht auch sehr interessant aus!

Vll. ist es nützlich wenn ich kurz skizziere wie ich dazu gekommen bin.

Ich bin zur Zeit Auszubildender und seit ein paar Monaten in dieser Abteilung. 
Vor einer weile bat man mich metrics zu lösen (eclipse + checkstyle):
- Method Length
- Strict Duplicate Code
- Nested if-else depth
- Cyclometic Complexity
- Class Data Abstraction Coupling
- Class Fan-Out Complexity
In diesem zuge hab ich mich ein wenig übers Refactoring schlau gemacht und Martin Fowlers Buch "Refactoring - Improving the design of existing Code" zu Gemüte gezogen, bekam jedoch recht schnell Kopfschmerzen, was unter anderem am Englisch und an dem Großraumbüro (ca. 15 leute  ) lag...
Alles bis auf die letzten beiden Punkte habe ich auf Anhieb verstanden und nun sind diese halt noch übrig.

Es ist so, dass die Klassen die ich mir bis jetzt genauer angeschaut habe - in Projekt a - mit Interfaces aus verschiedenen  - Projekten x, y, z - arbeiten.

Könntest du mir bitte folgendes näher erklären?


> Zwischen Modulen und Subsystemen sollte eigentlich nur über dedizierte Interfaces und Typen gesprochen werden.


----------



## Oliver Gierke (1. April 2009)

Aber gern doch. Eines der SOLID Principles von Bob Martin ist "Separation of Concerns", was übersetzt heißt, dass Code anhand des "Reason to change" separiert werden sollte. Z.B. gibt es Teile einer Applikation die sich häufiger ändert als andere. Oder die Änderungen werden aus völlig verschiedenen Gründen stattfinden. D.h. man wird diesen Code in unterschiedliche Module aufteilen. Reden müssen die Module allerdings trotzdem irgendwie miteinander. Nun ist man daher natürlich gut beraten, die Schnittstelle (ein paar Java Interfaces und gemeinsam genutzte Typen) so schmal wie möglich zu halten, damit möglichst wenige Änderungen an dem Interface auftauchen und so möglichst selten die Notwendigkeit zu beidseitigen Anpassungen besteht. Ich sage bewusst "möglichst", denn es ist klar, dass das nicht immer geht.

Ich habe schon viele Projekte gesehen, in denen Code aus Modul B wie wild und völlig frei Typen aus Modul A benutzt hat und man sich dann nach einem Refactoring der Interna von A gewundert hat, warum B nicht mehr tut. Im Idealfall trennt man Interface und Implementierung eines Moduls auch physisch voneinander (mehrere Jars). Man kann sogar soweit gehen, mehrere Interface Jars zu haben, um verschiedene Clients des Moduls das Modul nur über eine bestimmte Schnittstelle ansprechen zu lassen. Oft hat man z.B. ein Client API und ein Plugin API für ein Modul, d.h. im Endeffekt 3 Jars.

Gruß
Ollie


----------



## realjoda (1. April 2009)

So wie du das beschreibst,  ist genau das bereits der Fall, um so verwirrter bin ich.

Eine Komponente besitzt Unterordner, die in  source, configuration und interface aufgeteilt sind und der source Ordner besitzt wiederum solch eine Struktur.
Sodass globale und interne Interfaces exestieren.
Nur ist das alles so komplex in meinen Augen, dass ich nicht weiß wo ich ansetzen soll. Zumindest noch nicht


----------

