``````package Analizo::GlobalMetric::ChangeCost;
use strict;
use parent qw(Class::Accessor::Fast);
use List::Util qw( sum );
use Graph::TransitiveClosure::Matrix;

Analizo::GlobalMetric::ChangeCost - Change Cost global metric

The metric calculation is based on the following article and calculates the
degree to which a change to any file causes a (potential) change to other files
in the system.

Article: Exploring the Structure of Complex Software Designs: An Empirical
Study of Open Source and Proprietary Code by Alan MacCormack, John Rusnak and
Carliss Baldwin.

See the paragraph about Change Cost in the article:

"... characterize the structure of a design is by measuring the degree of
'coupling' it exhibits, as captured by the degree to which a change to any
single element causes a (potential) change to other elements in the system,
either directly or indirectly (i.e., through a chain of dependencies that exist
across elements).

... measures the percentage of elements affected, on average, when a change is
made to one element in the system."

=cut

__PACKAGE__->mk_accessors(qw( model ));

sub new {
my (\$package, %args) = @_;
my @instance_variables = (
model => \$args{model},
);
return bless { @instance_variables }, \$package;
}

sub description {
return "Change Cost";
}

sub calculate {
my (\$self) = @_;
my \$reachability_matrix = \$self->model->files_graph->transitive_closure_matrix;
my @vertices = sort \$reachability_matrix->vertices;
my \$rows = scalar @vertices;
return unless \$rows;
my @fan_out = (0) x \$rows;
my \$n = 0;
foreach my \$i (@vertices) {
foreach my \$j (@vertices) {
\$fan_out[\$n] += \$reachability_matrix->[0]->get(\$i, \$j);
}
\$fan_out[\$n] = \$fan_out[\$n] / \$rows;
\$n++;
}
sprintf("%0.02f", sum(@fan_out) / \$rows);
}

1;
``````