Skip to content

Instantly share code, notes, and snippets.

@brentarias
Last active January 15, 2021 19:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brentarias/5816e41450dc8aa02f2fbfe066236308 to your computer and use it in GitHub Desktop.
Save brentarias/5816e41450dc8aa02f2fbfe066236308 to your computer and use it in GitHub Desktop.
Cumulative Component Dependency (CCD)
//This code is an algorithm for computing a "health metric" representing software architectural maintainability and testability.
//It could also be called a "coupling metric", as excessive coupling degrades maintainability and testability.
//The metric is called Cumulative Component Dependency (CCD).
// CCD = sum over all components C in a subsystem of the number
// of components needed in order to test each C incrementally.
//More info:
//https://baruzzo.wordpress.com/2009/08/22/how-testable-is-a-software-architecture/
//CCD should also account for cyclical dependencies, but this current
//implementation does not handle cyclical dependencies.
public class CcdCalc : List<CcdCalc>
{
public static Dictionary<int, int> LevelCcd;
public string Name;
protected int Level;
protected int computed;
public CcdCalc(string name)
{
Name = name;
}
public static int ComputeCcd(List<CcdCalc> parents){
LevelCcd = new Dictionary<int, int>();
parents.ForEach((x) => x.CalculateCcd(LevelCcd));
return LevelCcd.Values.Sum();
}
protected int CalculateCcd(Dictionary<int,int> levels)
{
if (computed == 0)
{
//there won't by cyclic dependencies, but just in case...
computed = -1;
Level = Count == 0 ? 0 : this.Max((x) => x.CalculateCcd(levels));
if (!levels.ContainsKey(Level))
{
levels[Level] = 0;
}
computed = Count == 0 ? 1 : this.Sum((x) => x.computed) + 1;
levels[Level] += computed;
}
return Level + 1;
}
}
//This code shows how the CcdCalc class is used to form an acyclic graph of arbitrary dependencies,
//which can then be used to compute Cumulative Component Dependency (CCD).
//Each instance conceptually represents a software class, library, or package.
var Q = new CcdCalc("Q");
var P = new CcdCalc("P");
var O = new CcdCalc("O");
var N = new CcdCalc("N");
var M = new CcdCalc("M");
var L = new CcdCalc("L");
var K = new CcdCalc("K");
var J = new CcdCalc("J");
var I = new CcdCalc("I");
var H = new CcdCalc("H");
var G = new CcdCalc("G");
var F = new CcdCalc("F");
var E = new CcdCalc("E");
var D = new CcdCalc("D");
var C = new CcdCalc("C");
var B = new CcdCalc("B");
var A = new CcdCalc("A");
//Form arbitrary dependencies between components, for the sake
//of testing the CCD computation.
A.AddRange(new List<CcdCalc>{F, G, L, Q});
B.AddRange(new List<CcdCalc>{G,H,M,Q});
C.AddRange(new List<CcdCalc>{H, I, M, N, O, Q});
D.AddRange(new List<CcdCalc>{I, J, Q});
E.AddRange(new List<CcdCalc>{J, K, O, Q});
F.AddRange(new List<CcdCalc> { L, Q });
G.AddRange(new List<CcdCalc> { L, M, Q });
H.AddRange(new List<CcdCalc> { M, N, O, Q });
I.AddRange(new List<CcdCalc> { O, Q });
J.AddRange(new List<CcdCalc> { O, Q });
K.AddRange(new List<CcdCalc>{O, P, Q});
//L.Add(Q);
//M.Add(Q);
//N.Add(Q);
//O.Add(Q);
//P.Add(Q);
var parents = new List<CcdCalc> { A, B, C, D, E };
int ccd = CcdCalc.ComputeCcd(parents);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment