## Slide 1

### Slide 1 text

What is software complexity and how can you manage it?

Carl Alexander

@twigpress

carlalexander.ca

No content

## Slide 6

### Slide 6 text

“How did this happen? How did this code get so messy?”

## Slide 7

### Slide 7 text

Culprit is software complexity

## Slide 8

### Slide 8 text

Not a topic that we’re familiar with when we start coding

## Slide 9

### Slide 9 text

Focused on creating code that works

## Slide 11

### Slide 11 text

Software complexity makes this hard

## Slide 12

### Slide 12 text

What is software complexity?

## Slide 13

### Slide 13 text

Complexity is a measurement

## Slide 14

### Slide 14 text

How much does your code interact with other code?

## Slide 15

### Slide 15 text

Multiple ways to measure this

## Slide 16

### Slide 16 text

Cyclomatic complexity

## Slide 17

### Slide 17 text

Better-known complexity measurement method

## Slide 18

### Slide 18 text

Measures the number of "linearly independent paths" through a piece of code

No content

## Slide 20

### Slide 20 text

function insert_default_value(\$mixed) { if (empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 21

### Slide 21 text

function insert_default_value(\$mixed) { if (empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 22

### Slide 22 text

function insert_default_value(\$mixed) { if (empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 23

### Slide 23 text

function insert_default_value(\$mixed) { if (empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 24

### Slide 24 text

Use control ﬂow graph to represents paths in our code

No content

1 2 3 4

1 2 3 4

## Slide 28

### Slide 28 text

Cyclomatic complexity equation: M = E − N + 2

## Slide 29

### Slide 29 text

Cyclomatic complexity equation: M = 4 − 4 + 2

1 2

## Slide 31

### Slide 31 text

This is a lot of work! (Ain’t nobody got time for that!)

## Slide 32

### Slide 32 text

Easy mode calculation

## Slide 33

### Slide 33 text

function insert_default_value(\$mixed) // 1 { if (empty(\$mixed)) { // 2 \$mixed = 'value'; } return \$mixed; }

## Slide 34

### Slide 34 text

function insert_default_value(\$mixed) // 1 { if (!is_string(\$mixed) || empty(\$mixed)) { // 2,3 \$mixed = 'value'; } return \$mixed; }

## Slide 35

### Slide 35 text

What's a good cyclomatic complexity value?

## Slide 36

### Slide 36 text

Low complexity (1 - 4)

## Slide 37

### Slide 37 text

Moderate complexity (5 - 7)

## Slide 38

### Slide 38 text

High complexity (8 - 10)

## Slide 39

### Slide 39 text

“Ludicrous!” complexity (10+)

## Slide 40

### Slide 40 text

Issues with cyclomatic complexity

## Slide 41

### Slide 41 text

Treats if, while, for and case statements as identical

## Slide 42

### Slide 42 text

A for loop is the same the 1st or 10,000th time

## Slide 43

### Slide 43 text

An if statement alters the path through your code

## Slide 44

### Slide 44 text

Different effect on complexity

## Slide 45

### Slide 45 text

Doesn't account for nesting

## Slide 46

### Slide 46 text

Is nested for loops the same as linear for loops?

## Slide 47

### Slide 47 text

Cognitive complexity not taken into consideration

NPATH

## Slide 49

### Slide 49 text

Solves the shortcomings of cyclomatic complexity

## Slide 50

### Slide 50 text

Counts the number of “acyclic execution paths” in your code

No content

## Slide 52

### Slide 52 text

Counts the number of “unique paths” in your code

## Slide 53

### Slide 53 text

function insert_default_value(\$mixed) { if (!is_string(\$mixed) || empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 54

### Slide 54 text

How many unique paths does our function have?

No content

No content

No content

## Slide 58

### Slide 58 text

Easy to visualize so far!

## Slide 59

### Slide 59 text

function insert_default_value(\$mixed) { if (\$mixed instanceof ToStringInterface) { \$mixed = \$mixed->to_string(); } if (!is_string(\$mixed) || empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 60

### Slide 60 text

function insert_default_value(\$mixed) { if (\$mixed instanceof ToStringInterface) { \$mixed = \$mixed->to_string(); } if (!is_string(\$mixed) || empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 61

### Slide 61 text

How many paths are there now?

## Slide 62

### Slide 62 text

(Answer: 6) How many paths are there now?

## Slide 63

### Slide 63 text

Statements are multiplicative

2 * 3 = 6

## Slide 65

### Slide 65 text

Conditionals are dangerous

## Slide 66

### Slide 66 text

Unique paths increase quickly

## Slide 67

### Slide 67 text

Rarely have two conditionals

## Slide 68

### Slide 68 text

What if we had a dozen?

## Slide 69

### Slide 69 text

What if we had a dozen? (2¹² = 4096 unique paths!)

## Slide 70

### Slide 70 text

How many unique paths should your code have?

## Slide 71

### Slide 71 text

Tools warn you at 200 paths

## Slide 72

### Slide 72 text

50 paths is more reasonable

## Slide 73

### Slide 73 text

How to reduce complexity

## Slide 74

### Slide 74 text

Break your large function or method into smaller ones

## Slide 75

### Slide 75 text

Example: Going from 12 to 6 statements

## Slide 76

### Slide 76 text

Example: Going from 12 to 6 statements (4096 => 2⁶ = 64 unique paths)

## Slide 77

### Slide 77 text

Not easy to split functions or methods in two

## Slide 78

### Slide 78 text

More common to extract small blocks of code

## Slide 79

### Slide 79 text

What code is good to extract?

## Slide 80

### Slide 80 text

Easiest is code that logically belongs together

## Slide 81

### Slide 81 text

function create_reminder(\$name, \$date = '') { // ... \$date_format = 'Y-m-d H:i:s'; \$formatted_date = DateTime::createFromFormat(\$date_format, \$date); if (!empty(\$date) && (!\$formatted_date || \$formatted_date->format(\$date_format) != \$date) ) { throw new InvalidArgumentException(); } // ... }

## Slide 82

### Slide 82 text

function create_reminder(\$name, \$date = '') { // ... \$date_format = 'Y-m-d H:i:s'; \$formatted_date = DateTime::createFromFormat(\$date_format, \$date); if (!empty(\$date) && (!\$formatted_date || \$formatted_date->format(\$date_format) != \$date) ) { throw new InvalidArgumentException(); } // ... }

## Slide 83

### Slide 83 text

function create_reminder(\$name, \$date = '') { // ... if (!empty(\$date) && !is_reminder_date_valid(\$date)) { throw new InvalidArgumentException(); } // ... } function is_reminder_date_valid(\$date) { \$date_format = 'Y-m-d H:i:s’; \$formatted_date = \DateTime::createFromFormat(\$date_format, \$date); return \$formatted_date && \$formatted_date->format(\$date_format) === \$date; }

## Slide 84

### Slide 84 text

function create_reminder(\$name, \$date = '') { // ... if (!empty(\$date) && !is_reminder_date_valid(\$date)) { throw new InvalidArgumentException(); } // ... } function is_reminder_date_valid(\$date) { \$date_format = 'Y-m-d H:i:s'; \$formatted_date = \DateTime::createFromFormat(\$date_format, \$date); return \$formatted_date && \$formatted_date->format(\$date_format) === \$date; }

## Slide 85

### Slide 85 text

Large conditional statements

## Slide 86

### Slide 86 text

function send_response(array \$response) { if (empty(\$response['headers']) || !is_array(\$response['headers']) || empty(\$response[‘headers']['status']) ) { throw new \InvalidArgumentException(); } // ... }

## Slide 87

### Slide 87 text

function send_response(array \$response) { if (empty(\$response['headers']) || !is_array(\$response['headers']) || empty(\$response[‘headers']['status']) ) { throw new \InvalidArgumentException(); } // ... }

## Slide 90

### Slide 90 text

Combining conditionals together

## Slide 91

### Slide 91 text

function insert_default_value(\$mixed) { if (\$mixed instanceof ToStringInterface) { \$mixed = \$mixed->to_string(); } if (!is_string(\$mixed) || empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 92

### Slide 92 text

function insert_default_value(\$mixed) { if (\$mixed instanceof ToStringInterface) { \$mixed = \$mixed->to_string(); } elseif (!is_string(\$mixed) || empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 93

### Slide 93 text

function insert_default_value(\$mixed) { if (\$mixed instanceof ToStringInterface) { \$mixed = \$mixed->to_string(); } elseif (!is_string(\$mixed) || empty(\$mixed)) { \$mixed = 'value'; } return \$mixed; }

## Slide 94

### Slide 94 text

Are we just hiding the problem?

## Slide 95

### Slide 95 text

Evaluating the complexity of a function or method

## Slide 96

### Slide 96 text

Not evaluating the complexity of the software as a whole

## Slide 97

### Slide 97 text

Correlation between the two

Tools

## Slide 99

### Slide 99 text

Calculating complexity values isn’t practical

## Slide 100

### Slide 100 text

Tools needed to scan your code

## Slide 101

### Slide 101 text

Command-line tools

## Slide 102

### Slide 102 text

Good starting point

PHP code sniffer

## Slide 104

### Slide 104 text

Enforces coding standards

## Slide 105

### Slide 105 text

Includes cyclomatic complexity (But not NPATH)

## Slide 106

### Slide 106 text

PHP mess detector

## Slide 108

### Slide 108 text

Supports both measurement methods

## Slide 109

### Slide 109 text

Consider using both

## Slide 110

### Slide 110 text

Code quality services

Good for teams

## Slide 114

### Slide 114 text

Enforces code quality

## Slide 115

### Slide 115 text

Codacity Code Climate Scrutinizer

## Slide 116

### Slide 116 text

Complexity isn't that complex

## Slide 117

### Slide 117 text

Intimidating topic

## Slide 118

### Slide 118 text

Theory and language make it seem complicated

## Slide 120

### Slide 120 text

Mathematics only there to quantify the effect

## Slide 121

### Slide 121 text

Not necessary to reduce complexity

## Slide 122

### Slide 122 text

Just focus on keeping your functions and methods small

Thank you!