Stop wasting-time-by-applying-clean-code-principles

Preview:

DESCRIPTION

 

Citation preview

Stop wasting time through clean code#phpnw11

Volker Dusch / @__edorian

2

So stop wasting time!

Why are we here?

Introduction

3

Why are we here

to talk code and coding!

Introduction

4

});});});

Introduction

5

Me?

Introduction

6

Volker Dusch

@__edorian

Introduction

7

PHP for around 9 years

Introduction

8

I’m currently into TDD, CI, Clean Code and shipping

Introduction

…amongst other stuff

9

Just go and buy those

Introduction

*Book covers used under fair use

10

Get in touch

Twitter: @__edorianXing / G+: Volker DuschStackoverflow:(visit us at http://chat.stackoverflow.com/rooms/11/php

IRC: edorianMail: php@wallbash.com

Introduction

11

Ask questions at any time!

Introduction

First question gets an elePHPant

Another question gets one too!

12

Why try to save time?

Motivation

13

Because we are

professionals

Motivation

14

Even so our field is

quite young

Motivation

15

Do you know how expensive it is to have

you people around?

Motivation

16 Motivation

German numbers, ymmv

You get around 50k a year

Adding non-wage labor costs of around 60%

50.000 / Year

80.000 / Year

Office space, water, hardware, coffee, plants, cleaning, drugs, travels, training

100.000 / Year

250 Days without weekends and holidays and your 30 holidays => 220 days

455 / Day

€, £, Approx.. values

When working 8 hours a day 55 Bucks per Hour!

Your employer expects you to contribute

over 100.000 Bucks in business value per year!

17

Wait

why are we here again?

Motivation

18

To get things done, fast!

Delivering is fun!

Motivation

19

Coding!

Motivation

Not:• Requirement engineering, • Scrum, • Kanban, • Organizational structures• Sane hardware• Sane working environments• Tools

20

What do we spent time on?

Time! It matters!

21 Time! It matters!

Thinking

Asking

Changing

Reviewing Reading

Typing

Not programming

Growing/BuildingCreating

Planning

22

We spent time:

Time! It matters!

• Planning

• Reading

• Processing

• Writing

• Going to 10

• Actual typing? Not that much

23

Your codebase is just likethe database of a website

Time! It matters!

Read:Write Ratio - 10:1

and brains suck as caches

24

Goals:

Time! It matters!

• Cheap writes

The ability to change your software quickly

• Cheap reads

The ability to understand your software

quickly

• Writes require reads

25

Cheap reads

Time! It matters!

People will read your code!

again and again and again and again

Does it take 5 minutes or 2 hours to

understand a module?

26

Why is our code hard to understand?

Clean code?

• Management?

• Unclear requirements?

• Customers?

• Schedules?

• Requirement changes?

27

Because WE wrote it like that!

We had our reasons but it still is our responsibility!

Clean code?

28

Rushing out stuff to make people happy

“Well I’d go back and fix it but I can’t because $x”

Is that comfortable?

Clean Code?

29

What we need:

Clean Code?

A way to WRITE to our codebase so that we

are able to keep our READ costs low!

• Fearing we might break something leads

to us not making necessary changes

• If we don‘t fix stuff we won‘t have a

readable, maintainable codebase

30

We need a “Pragmatic” approach for cheap writes

Pragmatic!

31

Pragmatic?

Pragmatic?

• Fast

• Simple

• Just get it done as fast as possible

• Nobody cares how you do it

• Micromanagement?

32

‘Pragmatic’ === ‘TDD’

Pragmatic!

• My boss should NOT have to care about

the fact that I’m writing unit tests!

• If you can go faster when writing tests it

is your responsibility to do that!

• When not writing tests means “getting it

done slower” nobody is asking you to do

it!

33

I don’t have time to sharpen my axe!

There are so many trees that I need to cut down

Pragmatic!

34

This is not a TDD session

TDD! It saves kittens!

A small TDD checklist:

• Write unit tests! TDD is just the fastest

way.

• Just do it. It’s not magic, don’t fear doing

it!

• Practice before you do it at work!

• Tools? You don‘t need tools to get started!

• watch –n1 'phpunit' and ¼ of a screen

is ALL you need!

35

Get the basics right

TDD! It saves kittens!

A small TDD checklist (continued):

• Aim for 100% test coverage

• Your tests should run REALLY fast

• If you can‘t do that now use --filter

• „You“ means everyone in your team!

36

Writing unit tests is a SKILL

TDD! It saves kittens!

• You need to acquire it

• You need to practice

• It‘s just like any other tool and concept

• Actually – Unit testing is really easy…

• Writing testable code can be hard and

NEEDS practice!

37

Enough! Code! Now!

Enough! Code! Now!

38

What to focus on?

Is there anything we can base our decisions on?

Enough! Code! Now!

39 I <2 off by one errors

"There are only two hard problems in Computer Science: cache invalidation, naming things, and off-by-one errors.“

- Phil Karlton

40 Naming things!

41

We name everything

We might want to get that right

Naming matters

42

The purpose of a name

is to reveal intent

Naming matters

43

A good name tells you everything you need to know!

Examples!

class User {public function getId() {…}public function getName() {…}

/** Calculate Body-Mass-Index @link … */public function getBMI() {…}

/** @param float $kg Weight in Kilogramm */public function setWeight($kg) {…}

44

You shouldn’t need comments

Code! Finally!

class User {public function getUserId() {…}public function getFirst/Last/DisplayName() {…}

/** @link … */public function getBodyMassIndex() {…}

/** @param float $kilogramm */public function setWeight($kilogramm) {…}

45

Names already are

compliable documentation

Naming matters

46

Another example

Code!

class Calendar {public function getMonth($shortened = false) {…}

}

class Calendar {public function getMonthNames() {…}public function getShortendMonthNames() {…}

}

47

Proper naming is important and easily neglectable

Names matter! A lot!

• Descriptive names communicate intent

• They enable us to understand what‘s up

• Misleading names can make it nearly

impossible to navigate in a codebase

48

It is easy to write code that a machine understands

Names matter! A lot!

Writing code that ANOTHER human can understand is

A LOT harder

49

Before we start

naming things

Let’s go!

50

Hungarian Notation?

$pszError = &“E_FATAL\0“;

$aArray; $sString; $fFloat; $cCount;

interface IUser {} class CUser {}

• For classes and interfaces we have IDEs

• If you have long methods you might be

interested in types 100 lines later

• But that isn‘t the issue we want to adress

51

Let’s name things!

Name everything!

• Namespaces

• Classes

• Functions

• Variables

52

Namespaces

Name Namespaces!

• The things that come before the last

underscore of your class name

• Namespaces gave us the ability to get

pretty class names• “User” vs “Framework_Util_Stuff_Foo_Auth_User”

53

Namespaces

PSR-0

• The PHP world has mostly agreed that

Namespaces Directory structure

• Is that a good idea?

• Harder to change folder structure

• Duplicate information

• Just do it anyways. It’s the expected

layout

• It also pushes you to create modules!

54

Classes

Classy class names

• The class name is the single most

important definition of what fits into that

class

• Using generic names throws that away!

• ApplicationManager,

FrameworkDataInformationProvider,

UtilityDataProcessor

55

One class, one purpose

Putting the “S” in “SOLID”

• Name it after its purpose

• Single responsibility principle!

• There should be only one reason to

change a class

56

Proper class namesrelate to good methods

It’s good if it doesn’t fit!

• Think of the real world

$user->getStoreDiscount() ?

$userManager->getStoreDiscount(); ?

• Do we ask your customers how much

they owe us or do we keep track of that?

57

Proper class nameslead to smaller classes

Focus!

• Should we let our Email class figure out

attachment mime types?

• By always asking if stuff fits we can

‘discover’ new classes in our

applications

• EmailAttachment,

ImageEmailAttachment?

58

And we care because?• Big classes rob you of all OO benefits

• You depend on way to much other stuff

• Usually tightly coupled

• You can extend from those classes and

chances are you can’t swap out ether

• You don’t get nice interfaces as well

OOP is there to help us!

59

A logger interfaceinterface Logger {

public function log($message);

}

Loggers log!

Another logger interface

60

interface Logger { public function log($logMessage);

public function setOutputFormat($format);

public function activate();

public function deactivate();

public function flush();

public function setIncludeTimestamp($format);

public function addLogger(Logger $logger);

}

Composite?

61

All those rules! I want to get things done!

Rule 1: Segmentation fault

• These are just guidelines

• They exist to act as early warning signs

• Not running into trouble two hours later

can save an amazing amount of time

62 ‘Util’ is the new ‘Manager’

Util Because naming is harddjango/core/files/utils.py

django/core/mail/utils.py

django/db/backends/util.py

django/db/utils.py

django/forms/util.py

django/http/utils.py

django/test/utils.py

django/utils/... (django still rocks btw.)

63

Reserved class names

Name everything!

• Some names already have meaning

• If you name stuff like a design pattern

you’d better implement that pattern!

• Factory, DataMapper, Visitor,

Composite, Strategy, Builder

• A Logger without a log function?

64

Functions!

Best thing since LJMP

• First unit of organization

• Functions are where the action is

• For a long time functions where all we

had!

• Calling one got A LOT faster over the

years

65

Function naming

Starting off easy

• Does it return a boolean?

• Call it hasX or isX

66

Hidden booleans

Implementation details

$status = $user->getStatus();

if($status == $user::STATUS_BANNED) {

}

if($user->isBanned()) {

}

67

Getters and Setters

setTitle($this);

• Getter retrieve internal state

• Setters modify internal state

• Both should not modify anything else

• Don’t make your setters into liars

68

Setters return null!

setTitle($this);

• Or maybe $this but nothing else!

• Return codes for ugly IFs onto

consumers

if(!$config->set("key", "value")) {

}

if(!$config->has("key")) {

$config->set("key", "value");

}

69

No boolean parameters

$user->setInactive(false);

If you don’t have a very good reason!

$user->setAdminStatus(false);

$user->setAdminStatus(true);

vs

$user->revokeAdminRights();

$user->grantAdminRights();

70

Classes are nounsFunctions start with verbs!

$title->show();

->createStuff(); ->deleteStuff()

->dispatchCall(); ->subscribeUser();

But never

$user->admin(); or $user->bag();

$list->subscription();

71

Agree on verbs for actions

Don’t $dir->expunge();

Can you tell me the difference between

$directory->delete($entry);

And

$directory->remove($entry);

$router->dispatch/delegate($call);

$list->add/append($user);

72

Different actions need distinguishable names!

Name everything!

• Even if that makes function names

longer

• Usually those functions get created for

“doing the same thing with different

side effects but not wanting to call it

that”

• If you can agree upon terms with your

team that’s even better!

73

Always favor longfunction names? NO!

Bigger is not always better

• A short an precise public API is

important

• But you want long privates

$user->setUserNameOrThrowAn\

ExceptionIfNotPossible();

$logger->logMessageButDontDoAnything\

IfYouCantWriteToTheBackend($message);

Not even: $logger->logMessage($message);

74

Public functions will be called from many places

Bigger is not always better

• They should do one thing and maybe

throw an exception if they can’t do that

• Precise names help a lot to create

readable client code

• Interally used functions can be named

as verbosely as needed to communicate

their intent and behavior

75

Readable classes

implements humanReadable

• Some state

• Lots of small descripte methods

• Best arranged in order of interest

76

Readable classes?

sort($this) stuff out

class Log {

private function writeToLogfile() {}

private function flushCurrentLogfileBuffer(){}

public function log($message) {}

private isLogfileWriteable {}

public function __construct(

SplFileInfo $logfile) {}

private createLogfileIfNecaccary() {}

}

77

Method ordering

usort

• First you build it

• Then you call it

• Then it does work

• Most work happens in private methods

78

Readable classes?

sorted($this)

class Log {

public function __construct(

SplFileInfo $logfile) {}

public function log {}

private function isLogfileWriteable {}

private function createLogfileIfNecaccary() {}

private function writeToLogfile() {}

private function flushCurrentLogfileBuffer(){}

}

79

Maximum function length?

Name everything!

• LOC of the function body?

• Do you like reading functions that are:

• Over 100?

• Over 20?

• Over 7?

80

6 Lines ought to be enough for everybody?

Reading > Writing

• Doing only one thing shouldn’t take much

space

• Can you split it into 2 functions? Then do!

81

Why long function bodies?

main::doEverything();

• It’s very easy to create

• You just have to worry about

functionality

82

What is in a long function?

Implements unreadable

Local variables and code that operates on them

public function log($message) {

$log = ''; $errors = array();

$log .= PHP_EOL . date('Y-m-d H:i:s') . ': ';

if(!$message) { $errrors[] = 'No Message'; }

else { $log .= $message; }

if(!fwrite($this->log)) {

$errors[] = 'Write E'; }

return $errros;

} // I'm really 12 lines long

83

State and operations?

We shall name it Timmy

• It’s a class!

• Long functions are where classes hide!

• Even in the small example we could

separate Log and LogFileWriter

84

Function overflow?

Methods everywhere!

• Good thing they have nice names

• And we wrapped them in classes

• That’s good for read/write access!

• Calling overhead just doesn’t matter

85

Smaller is harder to write

Wrapping up functions

• Writing ONLY small functions is a SKILL

• It is _easy_ to write big functions!

• But the first change makes it all worth!

• If everything is small it can even impact

your coding standard ;)

86

Last thing to nameVariables

We shall name it Timmy

• Rules of thumb:

• Descriptive function parameters

• Big scope: long name

• Short scope: short name

87

Example

We shall name it Timmy

for($i = 7; $i; --$i) {

$this->doStuffToListItem($i);

}

vs

for($currentlistItemId = 7;

$this->listItemIdIsValid($currentlistItemId);

--$currentlistItemId

) {

$this->doStuffToListItem($currentlistItemId);

}

88

Descriptive members!

Class scope is big scope!

• Members are accessed from many

places. They should communicate

intent!

• Local variables in small classes are only

used twice or thrice

89

Wrapping up naming

Names matter

"A name, like an honorable human, should say what it means and mean what it says”

Names are the basis of our

communication!

They can speed up things immensely!

90

Arrays

Hash maps everywhere!

• PHP is hash-map-based programming

• Our constants are in hash maps

• Our variables are stored in hash maps

• Our arrays are hash maps

• We’d like to foreach over EVERYTHING!

• PHP Arrays let us create amazing data

structures without much hassle

91

Arrays

Hash maps everywhere!

PHP Arrays also let us create amazingly

complex and unmaintainable data structures$config['user'][$user['id']]['languages']['native'] ='en';

But arrays are too way cool to not use them.

Maybe we need OOP arrays?

92

Value objects!

New them everywhere!

• OOP Data structure

• You can create them everywhere, no DI!

• Identitiy is based on state! Think dates

• Lots of getters and setters. If you really

miss arrays you can implement

ArrayAccess too• http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/

• Implement IteratorAggregate and you get foreach back!

93

Value objects!

New them everywhere!

class List implements IteratorAggregate, Countable {

protected $list = array();

public function add($item) { $this->list[] = $item; }

public function count() { return count($this->list); }

public function remove($index) {

if(!isset($this->list[$index])) {/* throw ... */ }

unset($this->list[$index]);

$this->list = array_merge($this->list); }

public function getIterator {

return new ArrayIterator($this->list); }

}

94

Value objects!

New them everywhere!

class MonthlyValues implements IteratorAggregate {

protected $values = array();

public function __construct(array $values) {

if(count($values) != 12) {

thrown new InvalidArgumentException('...');

}

$this->values = $values;

}

public function get($monthNumber) {

return $this->values[$monthNumber];

} // ... public function getIterator() ...

95

Comments

New them everywhere!

• I’ve spend a lot of time ranting about

comments. Name things properly!

• Additional Resources:• http://edorian.posterous.com/they-told-you-to-

document-everything-they-lie

• http://www.slideshare.net/Edorian/php-unconference-

europa-clean-code-stop-wasting-my-time

96 Find the method body

abstract class xyzRequest { /** * Initializes this xyzRequest. * * Available options: * * * logging: Whether to enable logging or not (false by default) * * @param xyzEventDispatcher $dispatcher An xyzEventDispatcher instance * @param array $parameters An associative array of initialization parameters * @param array $attributes An associative array of initialization attributes * @param array $options An associative array of options * * @return bool true, if initialization completes successfully, otherwise false * * @throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest */ public function initialize(xyzEventDispatcher $dispatcher, $parameters = array(), $attributes = array(), $options = array()) {

97

Error handling

Name everything!

• Is a big topic that requires a whole

session

• Just use exceptions in favor of return

codes

• Don‘t force IF statements in client code

$stuff = $factory->create('unkownStuff');

$stuff->doWork(); // E_FATAL?

• Enable consumers to handle errors at a

point of their choosing!

Wrapping up

98 Professionals deliver!

• Testing makes you FASTER!

• Creating small functions saves time!

• Only tested code can stay clean

• You can only fix what you can reproduce!

• JUST – DO – IT! YOU – ARE – IN –

CHARGE!

99 Thanks a lot!

Thank you for your time!

Slides will be at: http://joind.in/3600the link will be at @__edorian too ;)

Please leave me feedback!

100

Recommended Reads

Rate my talk please!

*Book covers used under fair use

Clean Code Management Professionalism

^ Best book in 2011 ^In my humble opinion

https://www.google.com/bookmarks/l#!threadID=GU46RJYjEsMU%2FBDcqV3woQ8eH4sOcl

More:

Recommended