Last active
January 15, 2021 19:49
-
-
Save brentarias/5816e41450dc8aa02f2fbfe066236308 to your computer and use it in GitHub Desktop.
Cumulative Component Dependency (CCD)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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