# Keeping it Simple

### An overview of static code analysis

Ryan Kois
@kid_ic4rus
http://ryankois.com

## The Problem With Complex Code

• Easier to write,  far more difficult to maintain.
• Requires more time to read and comprehend.
• Inhibits code re-use.
• More difficult to test.
• Positive correlation to defective code.

## What is Complexity?

Many factors, let's focus on
• Cyclomatic Complexity
• Npath Complexity

## Cyclomatic Complexity

For loop ->

Condition ->

Number of independent linear paths through code.

## Example

``````// 1 point for the function declaration
function foo(\$list) {
// 1 point for any for, foreach, or while
foreach (\$list as \$item) {
// 1 point for any if, elseif, case
if (\$item == 'foo') {
return 'bar';
}
else if (\$item == 'bar') {
return 'baz';
}
//no points given for else, this represents default execution path
else {
return 'default';
}
}
}
``````
Cyclomatic Complexity: 4

## What is the cyclomatic complexity of this function?

``````function complex_form_alter(&\$form, &\$form_state, \$form_id) {
switch (\$form_id) {
case 'search_form':
if (user_is_logged_in()) {
array_unshift(\$form['#submit'], 'complex_submit');
}
break;

case 'article_node_form':
drupal_set_title('This is an article form!');
break;

default:
watchdog('complex', 'someone accessed a form!');
break;
}
}
``````

## Npath complexity

The number of acyclic execution paths through a function...

## Example

``````function foo(\$foo, \$bar) {
// First conditional, two possible outcomes
if (\$foo > 100) {
echo 'path 1';
} else {
echo 'path 2';
}
// Second conditional, two possible outcomes
if (\$foo > \$bar) {
echo 'path 3';
} else {
echo 'path 4';
}
}
``````
(1 conditional * 2 outcomes) * (1 conditional * 2 outcomes) = 4

## Example 2

``````function foo(\$foo, \$bar) {
// First conditional, two possible outcomes
if (\$foo > 100) {
echo 'path 1';
}
else {
echo 'path 2';
}
// Second conditional, two possible outcomes
if (\$foo > 200) {
echo 'path 3';
}
else {
echo 'path 4';
}
// Third conditional, two possible outcomes
if (\$foo > \$bar) {
echo 'path 5';
} else {
echo 'path 6';
}
}
``````
3 conditionals with 2 outcomes each:
(2 * 2 * 2) = 8
NOT 6! NPath complexity grows exponentially :O

## all computers suck anyway.

I know they do, but we can ease the pain a bit through the power of refactoring.

But first, lets add a valuable tool to our toolbox.

## phpmd

• Written by By Manuel Pichler
• FOSS
• Requires PHP >= 5.2.3

Installation
`````` composer global require 'phpmd/phpmd'
``````

## Usage

`` phpmd [filename|directory] [report format] [ruleset file]``

Report formats
• xml, which formats the report as XML.
• text, simple textual format.
• html, single HTML file with possible problems.

Rulesets
`` php foo.php text codesize``

## Example output

Cyclomatic complexity too high

``foo.php:2 The function foo() has a Cyclomatic Complexity of 17. The configured cyclomatic complexity threshold is 10.           ``

NPath complexity too high

``foo.php:20  The function bar() has an NPath complexity of 226. The configured NPath complexity threshold is 200.``

## TL;DR

Don't create the pyramid of doom in your code.

## The Pyramid of doom

``````if (\$something) {
foreach (\$list as \$item) {
if (\$item == 'foo') {
foreach (\$other_list as \$other_item) {
while (\$yet_another = get_another_thing()) {
if (\$yet_another == 'bar') {
print 'AAAAAAAAHHHHH!!!!!!';
}
}
}
}
}
}
``````

## Functional Programming to the rescue!

Use the Extract Method refactoring pattern  in order to extract new functions where conditionals and loops once existed.

We can save the code and our minds!

## EXAMPLE

``````function foo(\$words) {
\$contains_long_word = false;
foreach (\$words as \$word) {
if (strlen(\$item) >= 20) {
\$contains_long_word = true;
}
}
if (\$contains_long_word) {
foreach (\$words as \$key => \$word) {
\$words[\$key] = strtolower(\$words[\$key);
}
}
}
``````

## refactored

``````function array_some(\$arr, \$fn) {
foreach (\$arr as \$item) {
if (!\$fn(\$item)) {
return false;
}
return true;
}
}``````
function is_long_word(\$word) {
return (strlen(\$word) >= 20);
}

function foo(\$words) {
\$has_long_word = array_some(\$words, 'is_long_word');
if (\$has_long_word) {
return array_map('strtolower', \$words);
}
return \$words;
}
``````

## Practical drupal examples

• If, else if, switch statements in hook_form_alter()
• Conditionals inside theme overrides or templates
• Use theme hook and template suggestions
• block__module
• block__module__delta
• example.com/page/something
• page--something.tpl.php

## go forth and create beautiful code!

Thank you for listening!

☜(:༎ຶ;益;༎ຶ;)☞