Axa Assurance Maroc - Insurer Innovation Award 2024
Clean code & design patterns
1.
2. Pascal Larocque
● TrustCharge Team
● Behat guy
● Testing guy
● SOLID guy
● Pattern guy
● Father of 3
● Star Wars Geek
@pascallarocque
3. Bad Code
● Singletons
● Tight Coupling
● Untestable
● Premature Optimization
● Indescriptive name
● Duplication
4. Cost of Bad Code
● Very hard / Impossible to estimate
● Slows down team velocity
● High Learning curve
● Brings down team moral
● Increases cost of development
5. The Primal Conundrum
Programmers face a conundrum of basic
values. All developers with more than a few
years experience know that previous messes
slow them down. And yet all developers feel the
pressure to make messes in order to meet
deadlines. In short, they don’t take the time to
go fast!
6. True professionals know that the second part of
the conundrum is wrong. You will not make the
deadline by making the mess. Indeed, the
mess will slow you down instantly, and will
force you to miss the deadline. The only way to
make the deadline—the only way to go fast—is
to keep the code as clean as possible at all
times.
8. What is Clean Code?
“Clean code can be read, and enhanced by a
developer other than its original author. It has
unit and acceptance tests. It has meaningful
names. It provides one way rather than many
ways for doing one thing. It has minimal
dependencies, which are explicitly defined,
and provides a clear and minimal API. Code
should be literate since depending on the
language, not all necessary information can be
expressed clearly in code alone.”
- Dave Thomas
“Clean code is simple and direct. Clean code reads
like well-written prose. Clean code never obscures
the designer’s intent but rather is full of crisp
abstractions and straightforward lines of control.”
- Grady Booch
“I like my code to be elegant and efficient. The logic
should be straightforward to make it hard for bugs to
hide, the dependencies minimal to ease maintenance,
error handling complete according to an articulated
strategy, and performance close to optimal so as not to
tempt people to make the code messy with unprincipled
optimizations. Clean code does one thing well.”
- Bjarne Stroustrup
You know you are working on clean code
when each routine you read turns out to be
pretty much what you expected. You can call it
beautiful code when the code also makes it
look like the language was made for the
problem.
- Ward Cunningham
10. The Boy Scout Rule
“Leave the campground cleaner than you found it”
Code Rots and Degrades as time passes
The Code has to be kept clean over time. We
must take an active role in preventing the
degradation.
11. Naming
● Use intention revealing names
○ Why it exists
○ What it does
○ How it’s used
● Classes should have nouns or noun phrases
○ Don’t use Manager, Processor, Data or Info
● Methods should have verbs or verb phrases
● Accessor, Mutators or predicates should
have get, set or is
● Use solution domain name
○ Factory, Visitor, Queue
12. Functions
● Small
● Smaller than that!!!
● Does ONE THING
● Does ONLY ONE THING
● Blocks and Indentation
○ IF, While, For
● One level of abstraction per function
○ getHTML()
○ $parsed = Parser::render($url)
○ $xml->append($node)
13. Functions
● Reads like a Top Down Narrative
○ To render the page we get all the content
○ To get all the content we extract it from the DB
○ To extract it from the DB we need to connect
14. Function Arguments
The ideal number of arguments for a function is
zero (niladic).
Next comes one (monadic), followed closely by
two (dyadic).
Three arguments (triadic) should be avoided
where possible.
More than three (polyadic) requires very special
justification—and then shouldn’t be used
anyway.
15. Function Arguments - Flags
Flag Arguments should
be avoided.
It does 1 thing if true
and another thing when
it’s false.
render(true):
renderForScreen()
renderForTest()
16. Function Argument - Objects
It’s easier to pass Objects instead of a long
argument list or array
Rectangle makeRectangle(Double x1, Double y1, Double x2, Double y2)
Rectangle makeRectangle(Point point1, Point point2)
17. checkPassword(username, password) {
user = $this->dataAccessor->findByUsername
(username)
valid= md5($user->getPassword()) === password
if(valid) {
Session.init(user)
} else {
Session.clear()
}
return valid
}
Have no side effect
Sides effects are lies.
BAD
18. Enforce Temporal Coupling
class ACL {
function login(username, password) {
this->user = this->findUser(username, password)
this->getPermissions()
this->startACLSession()
}
}
BAD
class ACL {
function login(username, password) {
this->user = this->findUser(username, password)
this->permissions = this->getPermissions($this->user)
this->startACLSession(this->permissions)
}
}
BETTER
22. Encapsulate Change
Class UserRepository {
function findById(id) {
return Doctrine::getTable('Users')->createQuery(‘u’)
->where(‘u.id = ?’, id)
->fetchOne();
}
}
ORM
MY
GOD
Class UserRepository {
function findById(id) {
userData = this->dataAccessor->findById(id)
user = userFactory->create(userData)
return user
}
}
The only constant is Change.
24. The Law of Demeter
method f of a class C should only call the
methods of these:
● C
● An object created by f
● An object passed as an argument to f
● An object held in an instance variable of C
25. Class ACL {
protected user
function hasAccessToAdmin() {
return this->user ->isAdmin()
}
}
The Law of Demeter
Class ACL {
function hasAccessToAdmin() {
return getUserManager()
->getUser(123)
->getProfile()
->isAdmin()
}
}
BAD
Class ACL {
protected user
protected aclVisitor
function setVisitor(visitor) { … }
function hasAccessToAdmin() {
return this->aclVisitor
->isAdmin(this->user-getProfile())
}
}
Class AclVisitor {
function isAdmin(profile) {
return profile->isadmin()
}
}
MEH
PATTERNS!!!
31. Singleton Pattern
"Singletons are the path of the dark side.
Singletons lead to implicit dependencies.
Implicit dependencies lead to global state.
Global state leads to suffering."
32. As events arrive from the outside world at a port, a
technology-specific adapter converts it into a usable
procedure call or message and passes it to the application.
CreditCardService
Hexagonal Architecture
CreditCardService
HTTP
REST
PHPUnit
SOCKET ADAPTER
33. When the application has something to send out, it sends it out through a port
to an adapter, which creates the appropriate signals needed by the receiving
technology (human or automated).
CreditCardService
Hexagonal Architecture
CreditCardService
HTML
XML
PHPUnit
JSONP
ADAPTER
34. Class CreditCardService
__construct(InputInterface, OutputInterface) {
this->input = InputInterface
this->output = OutputInterface
}
function process() {
input = this->input->getInput()
output = this->doProcessing(input)
return this->ouput
->sendOutput(output)
}
}
CreditCardService
Hexagonal Architecture
CreditCardService
class CreditCardHTTPInputAdapter implements
InputInterface{
function getInput() {..}
}
class CreditCardJSONPOutputAdapter
implements OutputInterface{
function sendOutput(output) {..}
}
35. More stuff
Command Query Separation
Functions should either do something or answer something, but not both.
DRY
Don’t repeat yourself. Duplication may be the root of all evil in software.
SOLID
Single Responsibility, Open/Closed Principle, Liskov substitution principle,
Interface segregation, Dependency Inversion
Structured Programming
Every function and every block has one Entry and one Exit
Use Exceptions and Error Handling
Functions should do one thing. Error handling is one thing. Thus, a function that
handles errors should do nothing else.