Upload
edorian
View
13.049
Download
0
Embed Size (px)
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: [email protected]
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: