Re: Measuring Complexity (was Re: Perl::Metrics::Simple 0.30)

2006-12-19 Thread Chris Dolan

On Dec 19, 2006, at 2:43 PM, Matisse Enzer wrote:

I agree that  ( $a == $b ) is not an extra branch, but, it is  
harder for a human to understand than

  ( $a )


When did this thread change from code complexity to human  
understandability?  Those are rather different topics.


( $a ) of course translates to ( defined $a && $a ne '' && $a ne  
'0' ) which is likely harder to understand than ( $a == $b ).   
Undoubtably, the former leads to more subtle bugs than the latter.


I think that for true Cyclomatic Complexity ($a==$b) is the same as  
($a) but there is some other thing going on with ($a == $b) that  
perhaps, should be considered some other kind of complexity.


You're likely biting off more than you can chew.  I recommend that  
you take a lesson from Kwalitee and focus on implementing easily- 
defined metrics first.


Chris

--
Chris Dolan, Software Developer, http://www.chrisdolan.net/
Public key: http://www.chrisdolan.net/public.key
vCard: http://www.chrisdolan.net/ChrisDolan.vcf





Re: Measuring Complexity (was Re: Perl::Metrics::Simple 0.30)

2006-12-19 Thread Matisse Enzer


On Dec 17, 2006, at 9:02 PM, Randy W. Sims wrote:


Matisse Enzer wrote:

On Dec 15, 2006, at 10:13 PM, Chris Dolan wrote:


OK, I see.  Perhaps I was distracted from your main point by  
mention of cyclomatic complexity, which has a rather specific  
definition.

Mea culpa.
In the next release I will change the documentation for  
Perl::Metrics::Simple to make clear how exactly the complexity  
score is calculated, and that it is only an approximation of true  
cyclomatic complexity.
Meanwhile, I am open to making the measurement more useful. For  
example, should

if ($a eq $b)
or
if ( $a == $b )
be counted as more complex than:
if ( $a )
?


I don't think so. The latter is simply an implicit version of the  
former. It means something like:


  if ( $a == $true_value || $a eq $true_value )

Another way of looking at it is that comparison operators are no  
different than any other expressions.


 if ( func() )
 if ( --$a   )

The expressions themselves do not represent branches. They just  
produce values that may be used as the basis for a branch.


I agree that  ( $a == $b ) is not an extra branch, but, it is harder  
for a human to understand than

  ( $a )

I think that for true Cyclomatic Complexity ($a==$b) is the same as  
($a) but there is some other thing going on with ($a == $b) that  
perhaps, should be considered some other kind of complexity.


---
Matisse Enzer <[EMAIL PROTECTED]>
http://www.matisse.net/  - http://www.eigenstate.net/





Re: Perl::Metrics::Simple 0.30

2006-12-18 Thread Leon Brocard

On 12/10/06, Matisse Enzer <[EMAIL PROTECTED]> wrote:

Now in a CPAN near you:  Perl::Metrics::Simple 0.30


Ah, the old Simple versus Basic argument:

 http://search.cpan.org/dist/Perl-Metric-Basic/

Leon, who has already renamed it once to please Adam.


Re: Measuring Complexity (was Re: Perl::Metrics::Simple 0.30)

2006-12-17 Thread Randy W. Sims

Matisse Enzer wrote:


On Dec 15, 2006, at 10:13 PM, Chris Dolan wrote:



OK, I see.  Perhaps I was distracted from your main point by mention 
of cyclomatic complexity, which has a rather specific definition.


Mea culpa.
In the next release I will change the documentation for 
Perl::Metrics::Simple to make clear how exactly the complexity score is 
calculated, and that it is only an approximation of true cyclomatic 
complexity.


Meanwhile, I am open to making the measurement more useful. For example, 
should

if ($a eq $b)
or
if ( $a == $b )

be counted as more complex than:
if ( $a )

?


I don't think so. The latter is simply an implicit version of the 
former. It means something like:


  if ( $a == $true_value || $a eq $true_value )

Another way of looking at it is that comparison operators are no 
different than any other expressions.


 if ( func() )
 if ( --$a   )

The expressions themselves do not represent branches. They just produce 
values that may be used as the basis for a branch.


Randy.


Re: Measuring Complexity (was Re: Perl::Metrics::Simple 0.30)

2006-12-16 Thread Chris Dolan

On Dec 16, 2006, at 12:07 PM, Matisse Enzer wrote:


On Dec 15, 2006, at 10:13 PM, Chris Dolan wrote:

OK, I see.  Perhaps I was distracted from your main point by  
mention of cyclomatic complexity, which has a rather specific  
definition.


Mea culpa.
In the next release I will change the documentation for  
Perl::Metrics::Simple to make clear how exactly the complexity  
score is calculated, and that it is only an approximation of true  
cyclomatic complexity.


Meanwhile, I am open to making the measurement more useful. For  
example, should

if ($a eq $b)
or
if ( $a == $b )

be counted as more complex than:
if ( $a )


*shrug* It's really up to you and your user base, as long as you are  
consistent.  Certainly the former examples require more tests to get  
full coverage.


Personally, I use Devel::Cover's concept of complexity implicitly.

Chris

--
Chris Dolan, Software Developer, http://www.chrisdolan.net/
Public key: http://www.chrisdolan.net/public.key
vCard: http://www.chrisdolan.net/ChrisDolan.vcf





Measuring Complexity (was Re: Perl::Metrics::Simple 0.30)

2006-12-16 Thread Matisse Enzer


On Dec 15, 2006, at 10:13 PM, Chris Dolan wrote:



OK, I see.  Perhaps I was distracted from your main point by  
mention of cyclomatic complexity, which has a rather specific  
definition.


Mea culpa.
In the next release I will change the documentation for  
Perl::Metrics::Simple to make clear how exactly the complexity score  
is calculated, and that it is only an approximation of true  
cyclomatic complexity.


Meanwhile, I am open to making the measurement more useful. For  
example, should

if ($a eq $b)
or
if ( $a == $b )

be counted as more complex than:
if ( $a )

?

-M

---
Matisse Enzer <[EMAIL PROTECTED]>
http://www.matisse.net/  - http://www.eigenstate.net/





Re: Perl::Metrics::Simple 0.30

2006-12-15 Thread Chris Dolan

On Dec 15, 2006, at 10:22 PM, Matisse Enzer wrote:


On Dec 15, 2006, at 7:52 AM, Chris Dolan wrote:



That can't be right.  Negation does not contribute to complexity.


I think it is fair to say, that to a human, negation *can* increase  
complexity:


   if ( $foo ) {
  # do something
   }

is a little bit easier to understand than:

   if ( ! $foo ) {
  # do something
   }


  Instead, I believe it is the for loop and the exit points that  
are increasing your count.


It certainly is possible to create a better, more sophisticated  
measure of cyclomatic complexity - and I think you are probably  
right, or at least "more right" in the way you are suggesting  
complexity be counted. Perl::Metrics::Simple simply gives one  
"point" for each of the following:


  qw( ! && || ||= &&= or and xor not ? <<= >>= );
  qw( for foreach goto if else elsif last next unless until while );

See themeasure_complexity()  method in
  Perl::Metrics::Simple::Analysis::File


OK, I see.  Perhaps I was distracted from your main point by mention  
of cyclomatic complexity, which has a rather specific definition.


Chris

--
Chris Dolan, Software Developer, http://www.chrisdolan.net/
Public key: http://www.chrisdolan.net/public.key
vCard: http://www.chrisdolan.net/ChrisDolan.vcf





Re: Perl::Metrics::Simple 0.30

2006-12-15 Thread Matisse Enzer


On Dec 15, 2006, at 7:52 AM, Chris Dolan wrote:



That can't be right.  Negation does not contribute to complexity.   
Instead, I believe it is the for loop and the exit points that are  
increasing your count.  Consider rewriting the for as ifs and gotos:


   sub complexity_of_six {
   my $bar = shift;
   my $total = 0;
   my $type = ref $bar;
   if ( ! $type ) {
   $total = $bar;
   }
   elsif ( $type eq 'ARRAY' ) {
   my $_i = 0;
 LOOP:
   goto DONE if ($_i >= @{$bar});
   my $baz = $bar->[$_i];
   $total += $baz;
   $_i++;
   goto LOOP;
 DONE:
   }
   else {
   confess("Don't know how to handle refs to $type");
   }
   return $total;
   }


Just for the record,  Perl::Metrics::Simple  gives that code a  
complexity count of 8.
I realize that I'm not actually counting  'ne', 'eq', 'ge', or 'le',  
which is probably a bug :-)


I'm totally interested in better way(s) to measure this by the way.

---
Matisse Enzer <[EMAIL PROTECTED]>
http://www.matisse.net/  - http://www.eigenstate.net/





Re: Perl::Metrics::Simple 0.30

2006-12-15 Thread Matisse Enzer


On Dec 15, 2006, at 7:52 AM, Chris Dolan wrote:



That can't be right.  Negation does not contribute to complexity.


I think it is fair to say, that to a human, negation *can* increase  
complexity:


   if ( $foo ) {
  # do something
   }

is a little bit easier to understand than:

   if ( ! $foo ) {
  # do something
   }


  Instead, I believe it is the for loop and the exit points that  
are increasing your count.


It certainly is possible to create a better, more sophisticated  
measure of cyclomatic complexity - and I think you are probably  
right, or at least "more right" in the way you are suggesting  
complexity be counted. Perl::Metrics::Simple simply gives one "point"  
for each of the following:


  qw( ! && || ||= &&= or and xor not ? <<= >>= );
  qw( for foreach goto if else elsif last next unless until while );

See themeasure_complexity()  method in
  Perl::Metrics::Simple::Analysis::File

---
Matisse Enzer <[EMAIL PROTECTED]>
http://www.matisse.net/  - http://www.eigenstate.net/





Re: Perl::Metrics::Simple 0.30

2006-12-15 Thread Michael G Schwern
Chris Dolan wrote:
> That can't be right.  Negation does not contribute to complexity. 
> Instead, I believe it is the for loop and the exit points that are
> increasing your count.  Consider rewriting the for as ifs and gotos:
> 
>sub complexity_of_six {
>my $bar = shift;
>my $total = 0;
>my $type = ref $bar;
>if ( ! $type ) {
>$total = $bar;
>}
>elsif ( $type eq 'ARRAY' ) {
>my $_i = 0;
>  LOOP:
>goto DONE if ($_i >= @{$bar});
>my $baz = $bar->[$_i];
>$total += $baz;
>$_i++;
>goto LOOP;
>  DONE:
>}
>else {
>confess("Don't know how to handle refs to $type");
>}
>return $total;
>}
> 
> Then the decision points are:
>   1) if ( ! $type )
>   2) if ( $type eq 'ARRAY')
>   3) if ($_i >= @{$bar})
>   4) else
> and the end points are
>   1) confess("Don't know how to handle refs to $type");
>   2) return $total
> 
> So I actually count a complexity of 7 (num decision points + num
> endpoints + 1) if I've understood the wiki definition correctly.
>   http://en.wikipedia.org/wiki/Cyclomatic_complexity

Are the else and confess different decision points?  There's no way out of the 
else but the confess.  Similar issue with the return.


Re: Perl::Metrics::Simple 0.30

2006-12-15 Thread Chris Dolan

On Dec 14, 2006, at 11:20 PM, Matisse Enzer wrote:



On Dec 14, 2006, at 3:05 PM, Michael G Schwern wrote:


Matisse Enzer wrote:

   sub complexity_of_six {
   my $bar = shift;
   my $total = 0;
   my $type = ref $bar;
   if ( ! $type ) {
   $total = $bar;
   }
   elsif ( $type eq 'ARRAY' ) {
   foreach my $baz ( @{$bar} ) {
   $total += $baz;
   }
   }
   else {
   confess("Don't know how to handle refs to $type");
   }
   return $total;
   }


I'm missing something, I only count 3 paths.  if, elsif and else.   
The confess() might count (die/throw exception) but its the only  
path through the else.  Same with the loop, its the only path  
through the elsif.




I over-simplified my explanation. It's not exactly paths-through- 
the-code.


The complexity "points" in that example are:

   1 for the subroutine itself.
   1 for the "if"
   1 for the ! logic operator in the if condition
   1 for the elsif
   1 for the "ne" logic operator in the elsif condition
   1 for the else
  
   6 total


That can't be right.  Negation does not contribute to complexity.   
Instead, I believe it is the for loop and the exit points that are  
increasing your count.  Consider rewriting the for as ifs and gotos:


   sub complexity_of_six {
   my $bar = shift;
   my $total = 0;
   my $type = ref $bar;
   if ( ! $type ) {
   $total = $bar;
   }
   elsif ( $type eq 'ARRAY' ) {
   my $_i = 0;
 LOOP:
   goto DONE if ($_i >= @{$bar});
   my $baz = $bar->[$_i];
   $total += $baz;
   $_i++;
   goto LOOP;
 DONE:
   }
   else {
   confess("Don't know how to handle refs to $type");
   }
   return $total;
   }

Then the decision points are:
  1) if ( ! $type )
  2) if ( $type eq 'ARRAY')
  3) if ($_i >= @{$bar})
  4) else
and the end points are
  1) confess("Don't know how to handle refs to $type");
  2) return $total

So I actually count a complexity of 7 (num decision points + num  
endpoints + 1) if I've understood the wiki definition correctly.

  http://en.wikipedia.org/wiki/Cyclomatic_complexity

Chris

--
Chris Dolan, Software Developer, Clotho Advanced Media Inc.
608-294-7900, fax 294-7025, 1435 E Main St, Madison WI 53703
vCard: http://www.chrisdolan.net/ChrisDolan.vcf

Clotho Advanced Media, Inc. - Creators of MediaLandscape Software  
(http://www.media-landscape.com/) and partners in the revolutionary  
Croquet project (http://www.opencroquet.org/)





Re: Perl::Metrics::Simple 0.30

2006-12-14 Thread Matisse Enzer


On Dec 14, 2006, at 3:05 PM, Michael G Schwern wrote:


Matisse Enzer wrote:

   sub complexity_of_six {
   my $bar = shift;
   my $total = 0;
   my $type = ref $bar;
   if ( ! $type ) {
   $total = $bar;
   }
   elsif ( $type eq 'ARRAY' ) {
   foreach my $baz ( @{$bar} ) {
   $total += $baz;
   }
   }
   else {
   confess("Don't know how to handle refs to $type");
   }
   return $total;
   }


I'm missing something, I only count 3 paths.  if, elsif and else.   
The confess() might count (die/throw exception) but its the only  
path through the else.  Same with the loop, its the only path  
through the elsif.




I over-simplified my explanation. It's not exactly paths-through-the- 
code.


The complexity "points" in that example are:

   1 for the subroutine itself.
   1 for the "if"
   1 for the ! logic operator in the if condition
   1 for the elsif
   1 for the "ne" logic operator in the elsif condition
   1 for the else
  
   6 total


---
Matisse Enzer <[EMAIL PROTECTED]>
http://www.matisse.net/  - http://www.eigenstate.net/





Re: Perl::Metrics::Simple 0.30

2006-12-14 Thread Michael G Schwern
Matisse Enzer wrote:
>sub complexity_of_six {
>my $bar = shift;
>my $total = 0;
>my $type = ref $bar;
>if ( ! $type ) {
>$total = $bar;
>}
>elsif ( $type eq 'ARRAY' ) {
>foreach my $baz ( @{$bar} ) {
>$total += $baz;
>}
>}
>else {
>confess("Don't know how to handle refs to $type");
>}
>return $total;
>}

I'm missing something, I only count 3 paths.  if, elsif and else.  The 
confess() might count (die/throw exception) but its the only path through the 
else.  Same with the loop, its the only path through the elsif.

Also...

sub foo {
if( ... ) {
...
}
else {
...
}

return ...
}

Complexity of two or three?  I count only two possible paths.


Re: Perl::Metrics::Simple 0.30

2006-12-14 Thread Matisse Enzer


On Dec 10, 2006, at 1:16 AM, Ovid wrote:


--- Matisse Enzer <[EMAIL PROTECTED]> wrote:

McCabe Complexity
-
Code not in any subroutine::
min:  1
max   10
mean: 1.00
std. deviation:   2.54
median:   1.00

Subroutines/Methods:
min:  1
max:  15
avg:  1.00
std. deviation:   2.60
median:   1.00


Hi Matisse,

Thanks or creating this code.  It looks interesting, though I confess
I'm feeling a little slow.

In reading through the Wikipedia description and
http://www.sei.cmu.edu/str/descriptions/cyclomatic_body.html, I still
don't understand how to interpret the above result.


I think the easy way to understand Cyclomatic Complexity is this: It  
is a measurement of how many possible paths there are through a chunk  
of code. So, if there are 3 possible paths through a subroutine then  
it has a complexity of 3. If you add one "if" statement then the  
complexity goes up by 1.  There are more sophisticated explanations,  
and, more sophisticated ways of measuring complexity than what my  
module does, but I think you get the idea:


   sub complexity_of_one {
   my $bar = shift;
   return $bar * 23;
   }

   sub complexity_of_two {
   my $bar = shift;
   if ( $bar->isa('Foo::Bar') ) {
   return $bar->multiply(23);
   }
   return $bar * 23;
   }

   sub complexity_of_two {
   my $bar = shift;
   if ( $bar->isa('Foo::Bar') ) {
   return $bar->multiply(23);
   }
   return $bar * 23;
   }

   sub complexity_of_six {
   my $bar = shift;
   my $total = 0;
   my $type = ref $bar;
   if ( ! $type ) {
   $total = $bar;
   }
   elsif ( $type eq 'ARRAY' ) {
   foreach my $baz ( @{$bar} ) {
   $total += $baz;
   }
   }
   else {
   confess("Don't know how to handle refs to $type");
   }
   return $total;
   }



Also, if your average (mean) is 1.00, how is the standard deviation
greater than that value?


You fund a bug :-)
The countperl script v0.30 is reporting the median, not the mean for  
the complexity numbers. I'll fix this and release a new version today  
or tomorrow.

Thanks !

Here's a portion of the corrected report:

./countperl lib/TAPx

Perl files found:12

Counts
--
total code lines:1959
lines of non-sub code:   1261
packages found:  14
subs/methods:98

Subroutine/Method Size
--
min:  1 lines
max:  48 lines
mean: 7.12 lines
std. deviation:   8.24
median:   4.00

McCabe Complexity
-
Code not in any subroutine::
min:  1
max   10
mean: 2.17<--- FIXED
std. deviation:   2.54
median:   1.00

Subroutines/Methods:
min:  1
max:  15
mean: 2.42<--- FIXED
std. deviation:   2.60
median:   1.00

Tab-delimited list of subroutines, with most complex at top
---
complexity  sub pathsize
15  _initialize lib/TAPx/Parser.pm  48
11  _finish lib/TAPx/Parser.pm  30
11  _switches   lib/TAPx/Parser/Source/Perl.pm  22
10  _aggregate_results  lib/TAPx/Parser.pm  11
10  {code not in named subroutines} lib/TAPx/Parser.pm  626
9   nextlib/TAPx/Parser/Iterator.pm 27
8   _filtered_inc   lib/TAPx/Parser/Source/Perl.pm  15
Etc.

-M

---
Matisse Enzer <[EMAIL PROTECTED]>
http://www.matisse.net/  - http://www.eigenstate.net/





Perl::Metrics::Simple 0.30

2006-12-09 Thread Matisse Enzer

Now in a CPAN near you:  Perl::Metrics::Simple 0.30

Installs thecountperlscript which you point at one or more  
Perl files (and/or directories) and get a report of all the  
subroutines, sorted by complexity.


Line counts exclude both comments and pod.


For example:


% countperl lib/TAPx/

Perl files found:12

Counts
--
total code lines:1959
lines of non-sub code:   1261
packages found:  14
subs/methods:98

Subroutine/Method Size
--
min:  1 lines
max:  48 lines
mean: 7.12 lines
std. deviation:   8.24
median:   4.00

McCabe Complexity
-
Code not in any subroutine::
min:  1
max   10
mean: 1.00
std. deviation:   2.54
median:   1.00

Subroutines/Methods:
min:  1
max:  15
avg:  1.00
std. deviation:   2.60
median:   1.00

Tab-delimited list of subroutines, with most complex at top
---
complexity  sub pathsize
15  _initialize lib/TAPx/Parser.pm  48
11  _finish lib/TAPx/Parser.pm  30
11  _switches   lib/TAPx/Parser/Source/Perl.pm  22
10  _aggregate_results  lib/TAPx/Parser.pm  11
10  {code not in named subroutines} lib/TAPx/Parser.pm  626
9   nextlib/TAPx/Parser/Iterator.pm 27
8   _filtered_inc   lib/TAPx/Parser/Source/Perl.pm  15
7   BEGIN   lib/TAPx/Parser.pm  39
6   nextlib/TAPx/Parser.pm  22
6   run lib/TAPx/Parser.pm  15
6   _lexlib/TAPx/Parser.pm  18
6   switcheslib/TAPx/Parser/Source/Perl.pm  16
5   BEGIN   lib/TAPx/Parser/Aggregator.pm   22
5   _make_plan_tokenlib/TAPx/Parser/Grammar.pm  17
4   _tokens lib/TAPx/Parser.pm  15
4   _check_ending_plan  lib/TAPx/Parser.pm  11
4   _initialize lib/TAPx/Parser/Aggregator.pm   11
4   add lib/TAPx/Parser/Aggregator.pm   15
4   _get_parserslib/TAPx/Parser/Aggregator.pm   10
4   new lib/TAPx/Parser/Iterator.pm 14
4   as_string   lib/TAPx/Parser/Results/Test.pm 15
4   {code not in named subroutines} lib/TAPx/Parser/ 
Grammar.pm  132

3   _validate   lib/TAPx/Parser.pm  10
3   Test::Builder::failure_output   lib/TAPx/Parser/ 
Builder.pm  8

3   filenamelib/TAPx/Parser/Source/Perl.pm  10
3   get_stream  lib/TAPx/Parser/Source/Perl.pm  13
3   _get_commandlib/TAPx/Parser/Source/Perl.pm  9
3   _get_perl   lib/TAPx/Parser/Source/Perl.pm  6
3   {code not in named subroutines} lib/TAPx/Parser/ 
Iterator.pm 45

2   good_plan   lib/TAPx/Parser.pm  4
2   parsers lib/TAPx/Parser/Aggregator.pm   7
2   _trim   lib/TAPx/Parser/Grammar.pm  6
2   exitlib/TAPx/Parser/Iterator.pm 1


#---output truncated for space---