Architecture Metrics
Toggle main menu visibility
Loading...
Searching...
No Matches
MetricsCalculator.cs
Go to the documentation of this file.
1
using
ArchUnitNET.Domain;
2
3
namespace
Ucu.Andis.ArchitectureMetrics
;
4
17
public
static
class
MetricsCalculator
18
{
34
public
static
IReadOnlyCollection<Component>
BuildAssemblyComponents
(
35
Architecture architecture,
36
params
string
[] assemblyNames)
37
{
38
return
assemblyNames
39
.Select(assemblyName =>
40
new
Component
(
41
assemblyName,
42
architecture.Types
43
.Where(t => t.Assembly.Name == assemblyName)
44
.ToList()))
45
.ToList();
46
}
47
68
public
static
IReadOnlyCollection<ComponentDependencies>
69
BuildDependencyGraph
(IEnumerable<Component> components)
70
{
71
var componentMap = components
72
.SelectMany(
73
c => c.Types,
74
(component, type) => (type, component.Name))
75
.ToDictionary(x => x.type, x => x.Name);
76
77
var graph = components.ToDictionary(
78
c => c.Name,
79
_ =>
new
HashSet<string>());
80
81
foreach
(var component
in
components)
82
{
83
foreach
(var type
in
component.Types)
84
{
85
foreach
(var dependency
in
type.Dependencies)
86
{
87
var targetType = dependency.Target;
88
89
if
(!componentMap.TryGetValue(
90
targetType,
91
out var targetComponent))
92
{
93
continue
;
94
}
95
96
if
(targetComponent != component.Name)
97
{
98
graph[component.Name]
99
.Add(targetComponent);
100
}
101
}
102
}
103
}
104
105
return
graph
106
.Select(kv =>
new
ComponentDependencies
(kv.Key, kv.Value))
107
.ToList();
108
}
109
124
public
static
ComponentCouplings
CalculateCouplings
(
125
IReadOnlyCollection<ComponentDependencies> graph)
126
{
127
var fanOut = graph.ToDictionary(
128
cd => cd.ComponentName,
129
cd => cd.Dependencies.Count);
130
131
var fanIn = graph.ToDictionary(
132
cd => cd.ComponentName,
133
_ => 0);
134
135
foreach
(var componentDep
in
graph)
136
{
137
foreach
(var target
in
componentDep.Dependencies)
138
{
139
fanIn[target]++;
140
}
141
}
142
143
return
new
ComponentCouplings
(fanIn, fanOut);
144
}
145
181
public
static
double
CalculateAbstractness
(
Component
component)
182
{
183
var totalTypes = component.Types.Count;
184
185
if
(totalTypes == 0)
186
return
0;
187
188
var abstractTypes = component.Types.Count(t =>
189
IsAbstractOrExtensible(t));
190
191
return
(
double
)abstractTypes / totalTypes;
192
}
193
208
private
static
bool
IsAbstractOrExtensible(IType type)
209
{
210
// Interfaces son siempre abstractas
211
if
(type is Interface)
212
return
true
;
213
214
// Clases abstractas
215
if
(type is Class c && c.IsAbstract ==
true
)
216
return
true
;
217
218
// Tipos genéricos son extensibles por parametrización
219
if
(type.GenericParameters.Count > 0)
220
return
true
;
221
222
return
false
;
223
}
224
245
public
static
IReadOnlyCollection<ComponentMetrics>
CalculateMetrics
(
246
IReadOnlyCollection<Component> components)
247
{
248
var graph =
BuildDependencyGraph
(components);
249
250
var couplings =
CalculateCouplings
(graph);
251
252
return
components
253
.Select(component =>
254
{
255
var fanIn = couplings.FanIn[component.Name];
256
var fanOut = couplings.FanOut[component.Name];
257
258
var a =
CalculateAbstractness
(component);
259
260
var i = fanIn + fanOut == 0 ? 0 : (double)fanOut / (fanIn + fanOut);
261
262
var d = Math.Abs(a + i - 1);
263
264
return
new
ComponentMetrics
(component.Name, fanIn, fanOut, a, i, d);
265
})
266
.ToList();
267
}
268
}
Ucu.Andis.ArchitectureMetrics.MetricsCalculator
Calcula métricas de estabilidad arquitectónica para componentes basadas en sus dependencias.
Definition
MetricsCalculator.cs:18
Ucu.Andis.ArchitectureMetrics.MetricsCalculator.CalculateMetrics
static IReadOnlyCollection< ComponentMetrics > CalculateMetrics(IReadOnlyCollection< Component > components)
Calcula todas las métricas de estabilidad arquitectónica para los componentes.
Definition
MetricsCalculator.cs:245
Ucu.Andis.ArchitectureMetrics.MetricsCalculator.CalculateAbstractness
static double CalculateAbstractness(Component component)
Calcula la abstracción —A— de una instancia de Component.
Definition
MetricsCalculator.cs:181
Ucu.Andis.ArchitectureMetrics.MetricsCalculator.BuildDependencyGraph
static IReadOnlyCollection< ComponentDependencies > BuildDependencyGraph(IEnumerable< Component > components)
Construye un grafo de dependencias entre instancias de Component.
Definition
MetricsCalculator.cs:69
Ucu.Andis.ArchitectureMetrics.MetricsCalculator.CalculateCouplings
static ComponentCouplings CalculateCouplings(IReadOnlyCollection< ComponentDependencies > graph)
Calcula el acoplamiento aferente -fan-in- y eferente -fan-out- para todos los componentes.
Definition
MetricsCalculator.cs:124
Ucu.Andis.ArchitectureMetrics.MetricsCalculator.BuildAssemblyComponents
static IReadOnlyCollection< Component > BuildAssemblyComponents(Architecture architecture, params string[] assemblyNames)
Construye una colección de instancias de Component agrupando tipos por ensamblado.
Definition
MetricsCalculator.cs:34
Ucu.Andis.ArchitectureMetrics
Definition
Component.cs:3
Ucu.Andis.ArchitectureMetrics.Component
record Component(string Name, IReadOnlyCollection< IType > Types)
Representa un componente arquitectónico, agrupando tipos por ensamblado -assembly-.
Ucu.Andis.ArchitectureMetrics.ComponentCouplings
record ComponentCouplings(Dictionary< string, int > FanIn, Dictionary< string, int > FanOut)
Contiene el acoplamiento aferente -FanIn- y eferente -FanOut- para todos los componentes.
Ucu.Andis.ArchitectureMetrics.ComponentDependencies
record ComponentDependencies(string ComponentName, IReadOnlyCollection< string > Dependencies)
Representa las dependencias de un componente hacia otros componentes.
Ucu.Andis.ArchitectureMetrics.ComponentMetrics
record ComponentMetrics(string Name, int FanIn, int FanOut, double Abstractness, double Instability, double Distance)
Contiene todas las métricas de estabilidad arquitectónica para un componente.
src
MetricsCalculator.cs
Generated by
1.17.0