All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tngtech.archunit.library.metrics.LakosMetrics Maven / Gradle / Ivy

Go to download

A Java architecture test library, to specify and assert architecture rules in plain Java - Module 'archunit'

The newest version!
/*
 * Copyright 2014-2024 TNG Technology Consulting GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.tngtech.archunit.library.metrics;

import java.util.Collection;
import java.util.function.Function;

import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
import com.tngtech.archunit.PublicAPI;

import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
import static java.util.Collections.singleton;

/**
 * Calculates architecture metrics as defined by John Lakos in his book "Large-Scale C++ Software Design".
* To calculate these metrics every component is assigned a "dependsOn" value that represents the number * of other components that this component can reach transitively, including itself. Take e.g. components *

 * A -> B -> C
 * A -> D
 * 
* Then {@code dependsOn(A) = 4}, {@code dependsOn(B) = 2}, {@code dependsOn(C) = 1}, {@code dependsOn(D) = 1}
* The Lakos metrics are then calculated as: *

*

    *
  • Cumulative Component Dependency (CCD): * The sum of all dependsOn values of all components
  • *
  • Average Component Dependency (ACD): * The CCD divided by the number of all components
  • *
  • Relative Average Component Dependency (RACD): * The ACD divided by the number of all components
  • *
  • Normalized Cumulative Component Dependency (NCCD): * The CCD of the system divided by the CCD of a balanced binary tree with the same number of components
  • *
*

* Given the example graph above we would obtain * {@code CCD = 4 + 2 + 1 + 1 = 8}, {@code ACD = 8 / 4 = 2}, {@code RACD = 2 / 4 = 0.5}, {@code NCCD = 8 / 8 = 1.0} */ @PublicAPI(usage = ACCESS) public final class LakosMetrics { private final int cumulativeComponentDependency; private final double averageComponentDependency; private final double relativeAverageComponentDependency; private final double normalizedCumulativeComponentDependency; LakosMetrics(Collection> components, Function> getDependencies) { MetricsComponentDependencyGraph graph = MetricsComponentDependencyGraph.of(components, getDependencies); int cumulativeComponentDependency = components.stream() .mapToInt(component -> 1 + getNumberOfTransitiveDependencies(graph, component)) .sum(); this.cumulativeComponentDependency = cumulativeComponentDependency; this.averageComponentDependency = ((double) cumulativeComponentDependency) / components.size(); this.relativeAverageComponentDependency = averageComponentDependency / components.size(); this.normalizedCumulativeComponentDependency = ((double) cumulativeComponentDependency) / calculateCumulativeComponentDependencyOfBinaryTree(components.size()); } private int getNumberOfTransitiveDependencies(MetricsComponentDependencyGraph graph, MetricsComponent component) { Sets.SetView> transitiveDependenciesWithoutSelf = Sets.difference(graph.getTransitiveDependenciesOf(component), singleton(component)); return transitiveDependenciesWithoutSelf.size(); } private int calculateCumulativeComponentDependencyOfBinaryTree(int treeSize) { int ccdOfBinaryTree = 0; int level = 1; int maxNodesUpToCurrentLevel = 1; for (int currentNode = 1; currentNode <= treeSize; currentNode++) { if (currentNode > maxNodesUpToCurrentLevel) { level++; maxNodesUpToCurrentLevel += Math.pow(2, level - 1); } ccdOfBinaryTree += level; } return ccdOfBinaryTree; } /** * The {@link LakosMetrics Cumulative Component Dependency (CCD)} of the components. * * @see LakosMetrics */ @PublicAPI(usage = ACCESS) public int getCumulativeComponentDependency() { return cumulativeComponentDependency; } /** * The {@link LakosMetrics Average Component Dependency (ACD)} of the components. * * @see LakosMetrics */ @PublicAPI(usage = ACCESS) public double getAverageComponentDependency() { return averageComponentDependency; } /** * The {@link LakosMetrics Relative Average Component Dependency (RACD)} of the components. * * @see LakosMetrics */ @PublicAPI(usage = ACCESS) public double getRelativeAverageComponentDependency() { return relativeAverageComponentDependency; } /** * The {@link LakosMetrics Normalized Cumulative Component Dependency (NCCD)} of the components. * * @see LakosMetrics */ @PublicAPI(usage = ACCESS) public double getNormalizedCumulativeComponentDependency() { return normalizedCumulativeComponentDependency; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("cumulativeComponentDependency", cumulativeComponentDependency) .add("averageComponentDependency", averageComponentDependency) .add("relativeAverageComponentDependency", relativeAverageComponentDependency) .add("normalizedCumulativeComponentDependency", normalizedCumulativeComponentDependency) .toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy