Ein bisschen Hintergrundwissen: Als Teamleiter benutze ich NDepend ungefähr einmal pro Woche, um die Qualität unseres Codes zu überprüfen. Insbesondere die Testabdeckung, Codezeilen und zyklomatische Komplexitätsmetriken sind für mich von unschätzbarem Wert. Aber wenn es um Levelisierungs- und Abhängigkeitszyklen geht, bin ich ein bisschen ... sehr besorgt. Patrick Smacchia hat einen schönen Blog-Beitrag, der das Ziel der Levelisierung beschreibt.
Um es klar zu sagen: Unter "Abhängigkeitszyklus" verstehe ich Zirkelverweise zwischen zwei Namespaces.
Derzeit arbeite ich an einem Windows CE-basierten GUI-Framework für eingebettete Instrumente - denken Sie nur an die Android-Grafikplattform, aber für sehr einfache Instrumente. Das Framework ist eine einzelne Baugruppe mit ca. 50.000 Codezeilen (ohne Tests). Das Framework ist in folgende Namespaces unterteilt:
- Kernnavigations- und Menüsubsystem
- Bildschirm-Subsystem (Moderatoren / Ansichten / ...)
- Steuerelemente / Widget-Ebene
Heute habe ich den halben Tag damit verbracht, den Code auf das richtige Niveau zu bringen [dank Resharper im Allgemeinen kein Problem], aber in allen Fällen existieren einige Abhängigkeitszyklen.
Meine Frage: Wie streng befolgen Sie die Regel "Kein Abhängigkeitszyklus"? Ist Levelisierung wirklich so wichtig?
quelle
Antworten:
Ich habe kürzlich zwei Whitebooks geschrieben, die auf Simple-Talk zum Thema Architektur von .NET-Code veröffentlicht wurden (das erste Buch befasst sich mit .NET-Assemblys, das zweite mit Namespaces und Levelisierung):
Partitionieren Ihrer Codebasis über .NET-Assemblys und Visual Studio-Projekte
Definieren von .NET-Komponenten mit Namespaces
Ja ist es!
Zitat aus dem 2. Weißbuch:
(...)
quelle
Ich erlaube niemals zirkuläre Abhängigkeiten zwischen Klassen oder Namespaces. In C #, Java und C ++ können Sie eine zirkuläre Klassenabhängigkeit jederzeit durch Einführung einer Schnittstelle aufheben.
Das Codieren von Test-First macht es schwierig, zirkuläre Abhängigkeiten einzuführen.
quelle
Es ist immer ein Kompromiss: Sie müssen die Kosten von Abhängigkeiten verstehen, um zu verstehen, warum Abhängigkeiten vermieden werden sollen. Wenn Sie die Kosten einer Abhängigkeit verstehen, können Sie auf die gleiche Weise besser entscheiden, ob sie sich in Ihrem speziellen Fall lohnt.
Beispielsweise verlassen wir uns in Konsolenvideospielen häufig auf Abhängigkeiten, bei denen enge Informationsbeziehungen erforderlich sind, hauptsächlich aus Leistungsgründen. Das ist in Ordnung, sofern wir nicht so flexibel sein müssen wie beispielsweise ein Edition-Tool.
Wenn Sie die Einschränkungen verstehen, unter denen Ihre Software ausgeführt werden muss (Hardware, Betriebssystem oder einfach nur Design (wie "die einfachere Benutzeroberfläche, die wir können")), sollte es einfach sein, zu verstehen, welche Abhängigkeiten nicht ausgeführt werden sollten und welche okay.
Wenn Sie jedoch keinen guten und klaren Grund haben, vermeiden Sie jede mögliche Abhängigkeit. Abhängiger Code ist die Hölle der Debug-Sitzung.
quelle
Wenn dieses Thema besprochen wird, verlieren die Teilnehmer normalerweise den Ort der Unterscheidung zwischen Erstellungs- und Laufzeitzyklen. Ersteres ist das, was John Lakos als "physisches Design" bezeichnete, während letzteres für die Diskussion im Grunde genommen irrelevant ist (lassen Sie sich nicht auf Laufzeitzyklen ein, wie sie durch Rückrufe entstehen).
John Lakos war jedoch sehr streng darin, alle (Bauzeit-) Zyklen zu eliminieren. Bob Martin vertrat jedoch die Auffassung, dass nur Zyklen zwischen Binärdateien (z. B. DLLs, ausführbare Dateien) von Bedeutung sind und vermieden werden sollten. Er glaubte, dass Zyklen zwischen Klassen innerhalb einer Binärdatei nicht besonders wichtig sind.
Ich persönlich halte Bob Martins Ansicht dazu. Ich widme den Zyklen zwischen den Klassen jedoch immer noch einige Aufmerksamkeit, da das Fehlen solcher Zyklen das Lesen und Lernen des Codes für andere erleichtert.
Es sollte jedoch darauf hingewiesen werden, dass Code, den Sie mit Visual Studio erstellen, keine zirkulären Abhängigkeiten zwischen Binärdateien aufweisen kann (ob nativer oder verwalteter Code). Damit ist das schwerwiegendste Problem mit Zyklen für Sie gelöst. :) :)
quelle
Fast vollständig, da Abhängigkeitszyklen vom Build-Typ in Haskell unpraktisch und in Agda und Coq unmöglich sind. Dies sind die Sprachen, die ich normalerweise verwende.
quelle