Vermeidung von zyklischen Abhängigkeiten – die Besten Strategien

Vermeidung von zyklischen Abhängigkeiten

Zyklische Abhängigkeiten treten auf, wenn zwei Elemente oder Objekte voneinander abhängen.

Im Software-Engineering betrachten wir üblicherweise den Fall von Modulen oder Klassen, die von einem anderen Modul oder einer anderen Klasse abhängen, welche wiederum eine Abhängigkeit zum ursprünglichen Modul oder zur ursprünglichen Klasse haben. 

Die zyklischen Abhängigkeiten – auch bekannt als zirkuläre Abhängigkeiten – sind in der Regel in Software unerwünscht.

Sie führen zu einer engen Kopplung zwischen zwei Elementen, was bedeutet, dass die Elemente nicht unabhängig voneinander verwendet oder geändert werden können.

Daher versuchen Software-Ingenieure im Allgemeinen, die Einführung zyklischer Abhängigkeiten zu vermeiden.

Manchmal werden sie jedoch unbeabsichtigt eingeführt. 

Wo treten die zyklischen Abhängigkeiten auf?

Zyklen können zwischen verschiedenen Softwareelementen auftreten.

Innerhalb dieser wird unterschieden zwischen: 

  • Typen: Diese bilden die kleinsten Bausteine einer Entität (z. B. Klassen, Schnittstellen, Traits, Aufzählungen).
  • Pakete: Sie bilden die nächsthöhere Ebene. Diese enthalten Gruppierungen von Typen in Abhängigkeit von der verwendeten Programmiersprache.
  • Physische Entitäten: Werden in der Regel zum Zeitpunkt der Erstellung angelegt. Sie sind einsatzfähig, zusammensetzbar, zustandslos und von Natur aus wiederverwendbar.

Abhängigkeiten zwischen Typen

  • Verwendungsbeziehung: Bestimmte Eigenschaften oder Funktionen einer Klasse können von einer anderen Klasse verwendet werden.
  • Vererbungsbeziehung: Unterklassifizierung – die Eigenschaften und Methoden einer Klasse werden an eine abgeleitete Klasse weitergegeben.

Bei der Analyse von Abhängigkeiten ist es wichtig, die Unterscheidung zwischen Verwendungs- und Vererbungsbeziehungen zu beachten.

Vererbungsbeziehungen können schwieriger zu beseitigen sein, da sie in der Regel tiefer in eine Codebasis eingebettet sind und bei Änderungen größere Auswirkungen auf das System haben können.

Abhängigkeiten zwischen Paketen

Abhängigkeiten zwischen Paketen in der Softwareentwicklung definieren die Beziehungen zwischen verschiedenen Softwarekomponenten, die in separaten Paketen oder Modulen organisiert sind.

Zum Beispiel Verweise auf bestimmte Objekte oder Funktionsaufrufe.

Abhängigkeiten zwischen physischen Einheiten

Analog zu den Abhängigkeiten zwischen Paketen entstehen die Abhängigkeiten zwischen physischen Einheiten, implizit durch Typabhängigkeiten.

Beispielsweise leiten generierte Bibliotheken Abhängigkeiten von Objektverwendung und Aufrufen aus dem ursprünglichen Code ab, die von anderen generierten Einheiten abhängen können.

Warum zyklische Abhängigkeiten ein Problem sind

In der Softwareentwicklung beziehen sich zyklische Abhängigkeiten auf eine Situation, in der zwei oder mehr Typen oder Pakete so voneinander abhängen, dass jedes von der Existenz des anderen abhängt. 

Bei größeren Zyklen nimmt die Erreichbarkeit innerhalb des Zyklus im Vergleich zu einer ähnlichen zyklusfreien Struktur stark zu.

Dies führt zu zwei Problembereichen:

  • Infizierbarkeit: Negative Eigenschaften (z.B. Fehleranfälligkeit, hohe Änderungsraten, Inflexibilität, schlechte Laufzeit, etc.) oder notwendige Änderungen an einzelnen Elementen (z.B. geänderte Methodensignaturen oder geänderte Semantik einzelner Methoden) können eine größere Anzahl anderer Elemente betreffen.
  • Gewichtigkeit: Es wird schwieriger, Entwicklungsaktivitäten auf kleinere, ausgewählte Gruppen von Elementen (Verständnis, Tests, Änderungen und Builds) anzuwenden. 

Während die Infizierbarkeit die negativen Auswirkungen von Zyklen auf problematische Einzelelemente hervorhebt, bezieht sich die Gewichtung auf die Auswirkungen von Zyklen im Entwicklungsprozesse selbst. 

Je schwieriger es wird, ein System zu warten und zu verbessern, desto höher sind sowohl die Infizierbarkeit als auch die Gewichtigkeit.

Dies führt zu höheren Kosten während der gesamten Lebensdauer.

Zyklische Abhängigkeiten können auch dazu führen, dass Entwickler den Kontext verlieren und unbeabsichtigt ineffiziente oder sogar instabile Software erstellen.

Daher ist es bei sehr großen Softwareentwürfen noch wichtiger darauf zu achten, zirkuläre Abhängigkeiten zu vermeiden und die Kopplung zwischen Modulen nach Möglichkeit zu reduzieren.

Abhängigkeiten mit Understand erkennen

Wenn Understand ein Projekt analysiert, erstellt es eine Datenbank mit Entitäten und Abhängigkeiten zwischen Entitäten im Quellcode.

Die Abhängigkeiten werden als Referenz zwischen den beiden Entitäten und als Abhängigkeit basierend auf dem Abhängigkeitstyp (d.h. call, called-by, include, use-of, etc.) aufgezeichnet.

Die generierten Abhängigkeitsdaten bieten die folgenden Möglichkeiten:

  • Schnelles Durchsuchen von Abhängigkeiten nach Dateien und Verstehen von Architekturen. 
  • Auflisten von „abhängigen“ und „abhängig von“ Entitäten für Dateien und Architekturen.
  • Exportieren der Listen von Abhängigkeitsbeziehungen zur Verwendung in Tabellenkalkulationen.
  • Ein „dependency browsing“-Fenster zeigt kontextabhängige Abhängigkeitsinformationen an.
  • Grafische Abhängigkeitsdiagramme mit Filtern zur Verwaltung der angezeigten Arten von Abhängigkeiten.

Bei der Betrachtung einer Abhängigkeit ist es wichtig die Regeln zu kennen, die ihre Beziehung regeln:

  • Eine Entität ist eine beliebige Information aus Ihrem Quellcode, z. B. eine Datei, Klasse, Funktion oder Variable.
  • Eine Referenz ist eine Stelle im Code, die zwei Entitäten miteinander verbindet. Sie können die Referenzen einer Entität im Information Browser einsehen und die Regeln überprüfen.
  • Eine Abhängigkeit ist eine Verbindung auf der Grundlage der Referenz(en) zwischen zwei Dateien, Klassen, Architekturknoten und bestimmten anderen sprachspezifischen Konstrukten. 
  • Entitätsgruppen basieren auf der Eigenschaft „Elternteil“ einer Entität. Der übergeordnete Teil einer Entität wird vom Parser während der Analyse bestimmt und ist sprachspezifisch. Im Allgemeinen basiert der übergeordnete Teil auf dem Referenztyp „definieren in“. Im Information Browser können Sie sehen, dass app in main definiert ist, so dass app und main eine Eltern-Kind-Beziehung haben.

Beispielsweise sollte API-Code im Allgemeinen nicht vom Code der Benutzeroberfläche (UI) abhängig sein. 

Mithilfe der grafischen Abhängigkeitsdiagramme und des Abhängigkeitsbrowsers lassen sich Verstöße leicht erkennen.

Um sicherzustellen, dass keine neuen Verstöße hinzugefügt werden, können der Konfiguration der Understand CodeCheck-Abhängigkeitsprüfungen Regeln hinzugefügt werden.

Wenn eine Änderung an der API-Komponente eine Abhängigkeit von der Benutzeroberfläche einführt, wird im Editor eine Warnung angezeigt.

Abhängigkeiten erforschen

Sie können die Abhängigkeiten für jede Datei, jedes Verzeichnis oder jede Architektur erfahren, indem Sie mit der rechten Maustaste auf die Entität klicken und „Abhängigkeiten anzeigen“ aus dem Kontextmenü auswählen.

Daraufhin wird der Abhängigkeits-Browser angezeigt, der standardmäßig am unteren Rand der Benutzeroberfläche angedockt ist.

Der Browser verfügt über zahlreiche Optionen, mit denen Sie das Fenster an Ihre Bedürfnisse anpassen können.

Automatisierte Abhängigkeitsregeln mit Understand

Mit Understand können Sie Ihre eigenen Abhängigkeitsregeln konfigurieren, die benutzerdefinierte Anforderungen zur Begrenzung von Abhängigkeiten zwischen Code-Komponenten hervorheben können.

Zum Beispiel Regeln zur Beschränkung des Zugriffs auf sichere Komponenten, zur Vermeidung von Verweisen zwischen bestimmten Komponenten oder zur Verwaltung der Verwendung von Drittanbieter-Code, der während der Code-Entwicklung kontinuierlich validiert werden kann.

So hilft SciTools Understand Ihnen, zyklische Abhängigkeiten zu vermeiden

Der Einsatz von Understand kann dazu beitragen, die Wartbarkeit und Skalierbarkeit Ihrer Software zu optimieren.

Mit Understand erhalten Sie einen besseren Überblick über die gesamte Codebasis.

Sie können schnell zu bestimmten Codeschnipseln navigieren und Probleme lösen.

Darüber hinaus enthält Understand auch Funktionen wie Code-Metriken und Diagramme, die Entwicklern helfen, die Qualität und den Zustand ihrer Codebasis zu überwachen.

So können sie strategische Entscheidungen treffen, um ihre Codebasis zu verbessern und die Produktivität zu steigern.

Die Verwendung von Understand von SciTools ist ein wichtiger Schritt, um Software von Anfang an richtig zu entwerfen und zu pflegen.

Es hilft Entwicklern, zyklische Abhängigkeiten zu erkennen, Redundanzen zu reduzieren und die Wartbarkeit und Skalierbarkeit des Projekts zu erhöhen.

Sie und/oder Ihr Team sind herzlich eingeladen, Understand kostenlos zu testen.

Textquellen

https://scitools.freshdesk.com/support/solutions/articles/70000641326-automated-dependency-checking

https://scitools.freshdesk.com/support/solutions/articles/70000583144-how-dependencies-in-understand-are-determined

https://scitools.freshdesk.com/support/solutions/articles/70000582792-understanding-understand-dependencies

https://scitools.freshdesk.com/support/solutions/articles/70000582788-dependency-browser

https://prinzipien-der-softwaretechnik.blogspot.com/2014/07/zyklische-abhangigkeiten-terminologie.html 

https://prinzipien-der-softwaretechnik.blogspot.com/2014/07/zyklische-abhangigkeiten-wo-liegt-das.html