Avoid namespaces dependency cycles
Lists all application namespace dependency cycles; each row shows a cycle indexed with one entangled namespace. Avoiding cycles is a simple yet efficient way to clean a code base architecture; see our white books: https://www.ndepend.com/docs/white-books
How to fix
First fix the rule Avoid namespaces mutually dependent: this eliminates most cycles. Remaining cycles involve 3+ namespaces, like A is using B is using C is using A.
Right-click a cycle cell to export the namespaces to the dependency graph or matrix, illustrated here: https://www.ndepend.com/docs/visual-studio-dependency-graph#Entangled Then decide which namespaces are low-level vs high-level and remove the offending dependencies (e.g. if A is low-level, C shouldn't use A), using the patterns in Avoid namespaces mutually dependent HowToFix.
The matrix shows cycles as red squares and black cells; use the option Display Direct and Indirect Dependencies. See: https://www.ndepend.com/docs/dependency-structure-matrix-dsm#Cycle https://www.ndepend.com/docs/dependency-structure-matrix-dsm#Mutual
Estimated Debt doesn't depend on cycle length: even a long cycle can be broken by removing a few dependencies.
Right-click a cycle cell to export the namespaces to the dependency graph or matrix, illustrated here: https://www.ndepend.com/docs/visual-studio-dependency-graph#Entangled Then decide which namespaces are low-level vs high-level and remove the offending dependencies (e.g. if A is low-level, C shouldn't use A), using the patterns in Avoid namespaces mutually dependent HowToFix.
The matrix shows cycles as red squares and black cells; use the option Display Direct and Indirect Dependencies. See: https://www.ndepend.com/docs/dependency-structure-matrix-dsm#Cycle https://www.ndepend.com/docs/dependency-structure-matrix-dsm#Mutual
Estimated Debt doesn't depend on cycle length: even a long cycle can be broken by removing a few dependencies.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Avoid namespaces dependency cycles</Name>
// <Id>ND1401:AvoidNamespacesDependencyCycles</Id>
warnif count > 0
// Optimization: restraint application assemblies set
// If some namespaces are mutually dependent
// - They must be declared in the same assembly
// - The parent assembly must ContainsNamespaceDependencyCycle
from assembly in Application.Assemblies
.Where(a => a.ContainsNamespaceDependencyCycle != null &&
a.ContainsNamespaceDependencyCycle.Value)
// Optimization: restraint namespaces set
let namespacesSuspect = assembly.ChildNamespaces.Where(n =>
// A namespace involved in a cycle necessarily have a null Level.
n.Level == null &&
// Also require the namespace to be JustMyCode to avoid generated namespaces like My / My.Resources in VB.NET
JustMyCode.Contains(n))
// hashset is used to avoid iterating again on namespaces already caught in a cycle.
let hashset = new HashSet<INamespace>()
from suspect in namespacesSuspect
// By commenting in this line, the query matches all namespaces involved in a cycle.
where !hashset.Contains(suspect)
// Define 2 code metrics
// - Namespaces depth of is using indirectly the suspect namespace.
// - Namespaces depth of is used by the suspect namespace indirectly.
// Note: for direct usage the depth is equal to 1.
let namespacesUserDepth = namespacesSuspect.DepthOfIsUsing(suspect)
let namespacesUsedDepth = namespacesSuspect.DepthOfIsUsedBy(suspect)
// Select namespaces that are both using and used by namespaceSuspect
let usersAndUsed = from n in namespacesSuspect where
namespacesUserDepth[n] > 0 &&
namespacesUsedDepth[n] > 0
select n
where usersAndUsed.Count() > 0
// Here we've found namespace(s) both using and used by the suspect namespace.
// A cycle involving the suspect namespace is found!
// v2017.3.2: don't call Append() as an extension method else ambiguous syntax error
// with the new extension method in .NET Fx v4.7.1 / .NET Standard 2.0: System.Linq.Enumerable.Append()
let cycle = ExtensionMethodsEnumerable.Append(usersAndUsed,suspect)
// Fill hashset with namespaces in the cycle.
// .ToArray() is needed to force the iterating process.
let unused1 = (from n in cycle let unused2 = hashset.Add(n) select n).ToArray()
select new {
suspect,
cycle,
Debt = 120.ToMinutes().ToDebt(),
Severity = Severity.High
}
//<Expl>
// The *{1}* form a **dependency cycle**: they all depend on each other.
// This cycle prevents **clean layered architecture** and reduces maintainability.
// To fix it, first address all issues stemming from the rule
// *Avoid mutually dependent namespaces*.
// Then read this rule documentation that explains how to use
// the *Dependency Inversion Principle* to fix cycles involving
// 3 or more namespaces.
//</Expl>
//<Desc>
// Lists all *application namespace dependency cycles*; each row shows a
// cycle indexed with one entangled namespace. Avoiding cycles is a *simple
// yet efficient* way to clean a code base architecture; see our white books:
// https://www.ndepend.com/docs/white-books
//</Desc>
//<HowToFix>
// First fix the rule **Avoid namespaces mutually dependent**: this
// eliminates most cycles. Remaining cycles involve 3+ namespaces, like
// **A is using B is using C is using A**.
//
// Right-click a cycle cell to export the namespaces to the dependency graph
// or matrix, illustrated here:
// https://www.ndepend.com/docs/visual-studio-dependency-graph#Entangled
// Then decide which namespaces are low-level vs high-level and remove the
// offending dependencies (e.g. if A is low-level, C shouldn't use A), using
// the patterns in *Avoid namespaces mutually dependent* HowToFix.
//
// The matrix shows cycles as red squares and black cells; use the option
// **Display Direct and Indirect Dependencies**. See:
// https://www.ndepend.com/docs/dependency-structure-matrix-dsm#Cycle
// https://www.ndepend.com/docs/dependency-structure-matrix-dsm#Mutual
//
// Estimated Debt doesn't depend on cycle length: even a long cycle can be
// broken by removing a few dependencies.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Architecture: all 13 items
- Avoid namespaces mutually dependent ND1400
- Avoid namespaces dependency cycles ND1401
- Avoid partitioning the code base through many small library Assemblies ND1402
- Enforcing Clean Architecture ND1412
- UI layer shouldn't use directly DB types ND1403
- UI layer shouldn't use directly DAL layer ND1404
- Assemblies with poor cohesion (RelationalCohesion) ND1405
- Namespaces with poor cohesion (RelationalCohesion) ND1406
- Assemblies that don't satisfy the Abstractness/Instability principle ND1407
- Avoid excessive class coupling ND1410
- Higher cohesion - lower coupling ND1408
- Avoid mutually-dependent types ND1409
- Example of custom rule to check for dependency ND9900