This powerpoint was shown during a Blubird event that promised its attendees to make them a better developer (also experienced developers) and drastically improve the code.
This presentation will show you common but subtle mistakes and enlighten you with a better code
[PL] Jak nie zostać "programistą" PHP?Radek Benkel
Po sieci krąży wiele opinii, jak to programiści PHP nie są prawdziwymi programistami i że PHP to w ogóle nie jest język programowania, etc.
A winni takiego stanu rzeczy są sami programiści bądź właśnie „programiści”. Dlaczego? W każdym języku da się napisać kod zły jak i dobry. A w świecie PHP niestety dużo jest tego złego – choć trend ten zmienia się na lepsze.
Celem wykładu jest zapoznanie uczestników z rzeczami, na które należy zwrócić uwagę podczas tworzenia aplikacji w języku PHP. Druga (krótsza) część prezentacji będzie poświęcona ogólnym dobrym praktykom programistycznym, nie związanym z żadnym konkretnym językiem.
Here's a presentation I did for the Japanese Perl Association on April 21st, 2009.
It covers 10 aspects of Catalyst that may not be documented or discussed as much as they could be, that are very useful.
[PL] Jak nie zostać "programistą" PHP?Radek Benkel
Po sieci krąży wiele opinii, jak to programiści PHP nie są prawdziwymi programistami i że PHP to w ogóle nie jest język programowania, etc.
A winni takiego stanu rzeczy są sami programiści bądź właśnie „programiści”. Dlaczego? W każdym języku da się napisać kod zły jak i dobry. A w świecie PHP niestety dużo jest tego złego – choć trend ten zmienia się na lepsze.
Celem wykładu jest zapoznanie uczestników z rzeczami, na które należy zwrócić uwagę podczas tworzenia aplikacji w języku PHP. Druga (krótsza) część prezentacji będzie poświęcona ogólnym dobrym praktykom programistycznym, nie związanym z żadnym konkretnym językiem.
Here's a presentation I did for the Japanese Perl Association on April 21st, 2009.
It covers 10 aspects of Catalyst that may not be documented or discussed as much as they could be, that are very useful.
PHP has its own treasure chest of classic mistakes that surprises even the most seasoned expert: code that dies just by changing its namespace, strpos() that fails to find strings or arrays that changes without touching them. Do that get on your nerves too? Let's make a list of them, so we can always teach them to the new guys, spot them during code reviews and kick them out of our code once and for all. Come on, you're not frightening us!
Zen: Building Maintainable Catalyst ApplicationsJay Shirley
After several years of building Catalyst applications, I've established a list of techniques that greatly increase maintainability.
Subtle points that are easy to understand, and easy to implement, that will help please your users and make your life easier.
A long time ago in code base not so far away...
It's a time of prosperity and happiness. Development Teams have improved their coding skills and are now very familiar with writing code with proper DocBlock comments and unit tests, safeguarding their code bases against unwanted behaviour. But the evil Internet is building their new weapon against the Development Teams and sneaks through the gaps still uncovered by tests.
Will the Development Teams be in time to safeguard their code base again and bring peace and balance in the universe?
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Ralf Eggert
Das Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks" auf der Web-Developer-Conference kompakt 2013 zeigt die schrittweisen Aufbau eines Prototypen anhand des ZF2
Folien unter http://de.slideshare.net/eggertralf/rapidprototypingzf2 zu finden
Obfuscation, Golfing and Secret Operators in PerlJosé Castro
Everything you always wanted to know about Obfuscation and Golfing, some strange techniques and odd operators many are not aware of.
Also, everything you *never* wished to know about Obfuscation and Golfing, some even stranger techniques and even odder operators many wished they were *not* aware of.
Video available at http://conferences.yapcasia.org/ya2008/talk/1007.
Everyone talks about raising the bar on quality of code, but it's always hard to start implementing it when you have no clue where to start. With this talk I'm shooing that there are many levels developers can improve themselves by using the right tools. In this talk I'll go over each tool with examples how to use them against your codebase. A must attend talk for every developer that wants to scale up their quality. Most PHP developers deploy code that does what the customer requested but they don't have a clue about the quality of the product they deliver. Without this knowledge, maintenance can be a hell and very expensive. In this workshop I cover unit testing, code measuring, performance testing, debugging and profiling and give tips and tricks how to continue after this workshop.
Writing code you won’t hate tomorrow - PHPCE18Rafael Dohms
As developers we write code everyday, only to frown at it a week after that. Why do we have such a hard time with code written by others and ourselves, this raging desire to rewrite everything we see? Writing code that survives the test of time and self judgment is a matter of clarity and simplicity. Let's talk about growing, learning and improving our code with calisthenics, readability and good design.
PHP has its own treasure chest of classic mistakes that surprises even the most seasoned expert: code that dies just by changing its namespace, strpos() that fails to find strings or arrays that changes without touching them. Do that get on your nerves too? Let's make a list of them, so we can always teach them to the new guys, spot them during code reviews and kick them out of our code once and for all. Come on, you're not frightening us!
Zen: Building Maintainable Catalyst ApplicationsJay Shirley
After several years of building Catalyst applications, I've established a list of techniques that greatly increase maintainability.
Subtle points that are easy to understand, and easy to implement, that will help please your users and make your life easier.
A long time ago in code base not so far away...
It's a time of prosperity and happiness. Development Teams have improved their coding skills and are now very familiar with writing code with proper DocBlock comments and unit tests, safeguarding their code bases against unwanted behaviour. But the evil Internet is building their new weapon against the Development Teams and sneaks through the gaps still uncovered by tests.
Will the Development Teams be in time to safeguard their code base again and bring peace and balance in the universe?
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Ralf Eggert
Das Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks" auf der Web-Developer-Conference kompakt 2013 zeigt die schrittweisen Aufbau eines Prototypen anhand des ZF2
Folien unter http://de.slideshare.net/eggertralf/rapidprototypingzf2 zu finden
Obfuscation, Golfing and Secret Operators in PerlJosé Castro
Everything you always wanted to know about Obfuscation and Golfing, some strange techniques and odd operators many are not aware of.
Also, everything you *never* wished to know about Obfuscation and Golfing, some even stranger techniques and even odder operators many wished they were *not* aware of.
Video available at http://conferences.yapcasia.org/ya2008/talk/1007.
Everyone talks about raising the bar on quality of code, but it's always hard to start implementing it when you have no clue where to start. With this talk I'm shooing that there are many levels developers can improve themselves by using the right tools. In this talk I'll go over each tool with examples how to use them against your codebase. A must attend talk for every developer that wants to scale up their quality. Most PHP developers deploy code that does what the customer requested but they don't have a clue about the quality of the product they deliver. Without this knowledge, maintenance can be a hell and very expensive. In this workshop I cover unit testing, code measuring, performance testing, debugging and profiling and give tips and tricks how to continue after this workshop.
Writing code you won’t hate tomorrow - PHPCE18Rafael Dohms
As developers we write code everyday, only to frown at it a week after that. Why do we have such a hard time with code written by others and ourselves, this raging desire to rewrite everything we see? Writing code that survives the test of time and self judgment is a matter of clarity and simplicity. Let's talk about growing, learning and improving our code with calisthenics, readability and good design.
As presented at Dutch PHP Conference 2015, an introduction to command buses, how to implement your own in PHP and why they're both useful but unimportant.
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...Rafael Dohms
As developers we write code everyday, only to frown at it a week after that. Why do we have such a hard time with code written by others and ourselves, this raging desire to rewrite everything we see? Writing code that survives the test of time and self judgment is a matter of clarity and simplicity. Let's talk about growing, learning and improving our code with calisthenics, readability and good design.
Writing readable code is one of the most important aspects of web development. A developer should write code which another human is able to understand without the help of too many comments.
This talk will show you how to tidy up your code and write readable PHP.
PHP Data Objects (PDO) provides a clear, simple (but powerful), unified API for working with all our favorite databases. Features include prepared statements with bound parameters (for all databases, even those that don’t natively support them), transactions, cursors, LOBs, and flexible error handling.
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014Amazon Web Services
For both new and experienced users of the AWS SDK for PHP, we highlight features of the SDK as we work through building a simple, scalable PHP application. Attendees will learn about core features of the SDK including service clients, iterators, and waiters. We will also introduce new features in the upcoming Version 3 of the SDK, including asynchronous requests, paginators, and the new JMESPath result querying syntax.
You must’ve heard of Unit testing… If not, then this talk is definitely for you! If you do know Unit testing, you probably ran at some point into a hurdle: “Where do I start?” And despite your best efforts, you end up not having enough tests for your application – Then that change request comes in, requiring you to change that very same complex piece of code for which you are lacking tests! How do you going refactor while maintaining all those ‘undocumented’ business rules? This talk will show how Codeception can be leveraged to refactor the visuals aspects of an application, maintaining backwards compatibility on API changes and even assist in moving to a whole different server infrastructure.
The Hope of Salvation - Jude 1:24-25 - MessageCole Hartman
Jude gives us hope at the end of a dark letter. In a dark world like today, we need the light of Christ to shine brighter and brighter. Jude shows us where to fix our focus so we can be filled with God's goodness and glory. Join us to explore this incredible passage.
A375 Example Taste the taste of the Lord, the taste of the Lord The taste of...franktsao4
It seems that current missionary work requires spending a lot of money, preparing a lot of materials, and traveling to far away places, so that it feels like missionary work. But what was the result they brought back? It's just a lot of photos of activities, fun eating, drinking and some playing games. And then we have to do the same thing next year, never ending. The church once mentioned that a certain missionary would go to the field where she used to work before the end of his life. It seemed that if she had not gone, no one would be willing to go. The reason why these missionary work is so difficult is that no one obeys God’s words, and the Bible is not the main content during missionary work, because in the eyes of those who do not obey God’s words, the Bible is just words and cannot be connected with life, so Reading out God's words is boring because it doesn't have any life experience, so it cannot be connected with human life. I will give a few examples in the hope that this situation can be changed. A375
A Free eBook ~ Valuable LIFE Lessons to Learn ( 5 Sets of Presentations)...OH TEIK BIN
A free eBook comprising 5 sets of PowerPoint presentations of meaningful stories /Inspirational pieces that teach important Dhamma/Life lessons. For reflection and practice to develop the mind to grow in love, compassion and wisdom. The texts are in English and Chinese.
My other free eBooks can be obtained from the following Links:
https://www.slideshare.net/ohteikbin/presentations
https://www.slideshare.net/ohteikbin/documents
Exploring the Mindfulness Understanding Its Benefits.pptxMartaLoveguard
Slide 1: Title: Exploring the Mindfulness: Understanding Its Benefits
Slide 2: Introduction to Mindfulness
Mindfulness, defined as the conscious, non-judgmental observation of the present moment, has deep roots in Buddhist meditation practice but has gained significant popularity in the Western world in recent years. In today's society, filled with distractions and constant stimuli, mindfulness offers a valuable tool for regaining inner peace and reconnecting with our true selves. By cultivating mindfulness, we can develop a heightened awareness of our thoughts, feelings, and surroundings, leading to a greater sense of clarity and presence in our daily lives.
Slide 3: Benefits of Mindfulness for Mental Well-being
Practicing mindfulness can help reduce stress and anxiety levels, improving overall quality of life.
Mindfulness increases awareness of our emotions and teaches us to manage them better, leading to improved mood.
Regular mindfulness practice can improve our ability to concentrate and focus our attention on the present moment.
Slide 4: Benefits of Mindfulness for Physical Health
Research has shown that practicing mindfulness can contribute to lowering blood pressure, which is beneficial for heart health.
Regular meditation and mindfulness practice can strengthen the immune system, aiding the body in fighting infections.
Mindfulness may help reduce the risk of chronic diseases such as type 2 diabetes and obesity by reducing stress and improving overall lifestyle habits.
Slide 5: Impact of Mindfulness on Relationships
Mindfulness can help us better understand others and improve communication, leading to healthier relationships.
By focusing on the present moment and being fully attentive, mindfulness helps build stronger and more authentic connections with others.
Mindfulness teaches us how to be present for others in difficult times, leading to increased compassion and understanding.
Slide 6: Mindfulness Techniques and Practices
Focusing on the breath and mindful breathing can be a simple way to enter a state of mindfulness.
Body scan meditation involves focusing on different parts of the body, paying attention to any sensations and feelings.
Practicing mindful walking and eating involves consciously focusing on each step or bite, with full attention to sensory experiences.
Slide 7: Incorporating Mindfulness into Daily Life
You can practice mindfulness in everyday activities such as washing dishes or taking a walk in the park.
Adding mindfulness practice to daily routines can help increase awareness and presence.
Mindfulness helps us become more aware of our needs and better manage our time, leading to balance and harmony in life.
Slide 8: Summary: Embracing Mindfulness for Full Living
Mindfulness can bring numerous benefits for physical and mental health.
Regular mindfulness practice can help achieve a fuller and more satisfying life.
Mindfulness has the power to change our perspective and way of perceiving the world, leading to deeper se
2 Peter 3: Because some scriptures are hard to understand and some will force them to say things God never intended, Peter warns us to take care.
https://youtu.be/nV4kGHFsEHw
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptxOH TEIK BIN
A PowerPoint Presentation based on the Dhamma teaching of Kamma-Vipaka (Intentional Actions-Ripening Effects).
A Presentation for developing morality, concentration and wisdom and to spur us to practice the Dhamma diligently.
The texts are in English and Chinese.
Discover various methods for clearing negative entities from your space and spirit, including energy clearing techniques, spiritual rituals, and professional assistance. Gain practical knowledge on how to implement these techniques to restore peace and harmony. For more information visit here: https://www.reikihealingdistance.com/negative-entity-removal/
2. The Book of Psalms: Recognition of the kingship and sovereignty of God
Why your code suxx
1. Why Your Code Suxx
And why you should care about it ?
2. www.blubird.eu
Started mid 2013
Audit & consultancy
Project staffing
Project management
ABOUT BLUBIRD
Web & Mobile apps
Virtualization and cloud
Performance & optimization
Security
SMAC the picture
Security, Mobility, Apps & Cloud
3. Nicolas De Boose
➢ Freelancer
➢ PHP, Symfony2, (Node) Js, Css
➢ 10 yrs pro
➢ A wonderful fiancee <3
➢ @NicoDeBoose
➢ Blog: mechantblog.com
ABOUT ME
4. WHY THIS SUBJECT?
1. Laravel vs Symfony2 vs Zend Framework2 ? Google it!
2. “Clean code” is a subject I like
– Pull request
– Gave lots of reviews
– Read/watch Clean coders (book & website)
3. Every year, new coders must learn best practices, solid
principles, patterns, ... And it’s a good booster shot
6. //Let's go to the bar
interface Human{
public function getAge();
public function getFullName();
}
interface Drink{
public function getPrice();
}
interface Bar{
public function removeFromStock(Drink $drink);
public function hasInStock(Drink $drink);
}
7. class BarMan{
private $bar;
public function command(Human $human, Drink $drink){
if ($this->bar->hasInStock($drink) == true) {
if ($drink->doesNotContainAlcohol()) {
$this->prepare($human, $drink);
} else {
if ($human->getAge() >= 18){
$this->prepare($human, $drink);
} else {
$this->errorMessage = 'Too young :(';
return false;
}
}
} else {
$this->errorMessage = 'Not in stock :(';
}
return true;
}
}
8. class BarMan{
private $bar;
public function command(Human $human, Drink $drink){
if ($this->bar->hasInStock($drink) == true) {
if ($drink->doesNotContainAlcohol()) {
$this->prepare($human, $drink);
} else {
if ($human->getAge() >= 18){
$this->prepare($human, $drink);
} else {
$this->errorMessage = 'Too young :(';
return false;
}
}
} else {
$this->errorMessage = 'Not in stock :(';
}
return true;
}
}
Focus on this code
13. //In Barman::command(Human $human, Drink $drink)
if ($this->bar->hasInStock($drink)) {
if ($drink->doesNotContainAlcohol()) {
$this->prepare($human, $drink);
} else {
if ($human->getAge() >= 18){
$this->prepare($human, $drink);
} else {
$this->errorMessage = 'Too young :(';
return false;
}
}
} else {
$this->errorMessage = 'Not in stock :(';
return false;
}
return true;
14. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if ($drink->doesNotContainAlcohol()) {
$this->prepare($human, $drink);
} else {
if ($human->getAge() >= 18){
$this->prepare($human, $drink);
} else {
$this->errorMessage = 'Too young :(';
return false;
}
}
return true;
15. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if ($drink->doesNotContainAlcohol()) {
$this->prepare($human, $drink);
} else {
if ($human->getAge() >= 18){
$this->prepare($human, $drink);
} else {
$this->errorMessage = 'Too young :(';
return false;
}
}
return true;
call to “prepare()” here
And here + nested if
16. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if (!$drink->doesNotContainAlcohol()
&& $human->getAge() < 18
) {
$this->errorMessage = 'Too young :(';
return false;
}
$this->prepare($human, $drink);
return true;
17. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if (!$drink->doesNotContainAlcohol()
&& $human->getAge() < 18
) {
$this->errorMessage = 'Too young :(';
return false;
}
$this->prepare($human, $drink);
return true;
NOT doesNot… My head hurts!
18. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if ($drink->containsAlcohol()
&& $human->getAge() < 18
) {
$this->errorMessage = 'Too young :(';
return false;
}
$this->prepare($human, $drink);
return true;
19. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if ($drink->containsAlcohol()
&& $human->getAge() < 18
) {
$this->errorMessage = 'Too young :(';
return false;
}
$this->prepare($human, $drink);
return true;
can we be more explicit?
20. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan(18)
) {
$this->errorMessage = 'Too young :(';
return false;
}
$this->prepare($human, $drink);
return true;
21. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
$this->errorMessage = 'Not in stock :(';
return false;
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan(18)
) {
$this->errorMessage = 'Too young :(';
return false;
}
$this->prepare($human, $drink);
return true;
It’s not my job to keep the error message
It’s not my job to keep the error message
22. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
throw new DrinkNotInStockException($drink);
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan(18)
) {
return new CommandResult(false,'Too young :(');
}
$this->prepare($human, $drink);
return true;
Solution 1: Throw an exception
Solution 2: Return a “Result” object
Solution 1: Return nothing
Solution 2: Return a “Result” object
23. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
throw new DrinkNotInStockException($drink);
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan(18)
) {
throw new TooYoungToDrinkAlcoholException();
}
$this->prepare($human, $drink);
24. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
throw new DrinkNotInStockException($drink);
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan(18)
) {
throw new TooYoungToDrinkAlcoholException();
}
$this->prepare($human, $drink);
What is “18”?
It’s a magic number!
25. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
throw new DrinkNotInStockException($drink);
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan
(self::MINIMUM_AGE_FOR_ALCOHOL)
) {
throw new TooYoungToDrinkAlcoholException();
}
$this->prepare($human, $drink);
Better but not the best place
to store the constant
26. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink)) {
throw new DrinkNotInStockException($drink);
}
if ($drink->containsAlcohol()
&& $human->isYoungerThan
(BarLegislation::MINIMUM_AGE_FOR_ALCOHOL)
) {
throw new TooYoungToDrinkAlcoholException();
}
$this->prepare($human, $drink);
There, it’s good enough
for the moment
27. //In Barman::command(Human $human, Drink $drink)
if (!$this->bar->hasInStock($drink))
throw new DrinkNotInStockException($drink);
if ($drink->containsAlcohol()
&& $human->isYoungerThan
(BarLegislation::MINIMUM_AGE_FOR_ALCOHOL)
)
throw new TooYoungToDrinkAlcoholException();
$this->prepare($human, $drink);
28. interface Human{
// public function getAge(); => deleted
public function isYoungerThan($age); //New
public function getFullName();
}
interface Drink{
public function getPrice();
public function containsAlcohol(); //Rename
}
interface Bar{
public function removeFromStock(Drink $drink);
public function hasInStock(Drink $drink);
}
37. //In Barman::prepare(Human $human, Drink $drink)
$human->addToBill($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($human->getAcronym());
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',$human->getAcronym())
);
A bill for a “simple” human?
38. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($human->getAcronym());
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',$human->getAcronym())
);
Create a “Client” class:
He knows what he’s
drinking
39. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($human->getAcronym());
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',$human->getAcronym())
);
A drink should not be
more than a drink.
40. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$labeledDrink = new LabeledDrink(
$drink,
$human->getAcronym());
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',
$labeledDrink->getLabel())
);
Create a class that
symbolizes the drink
with an acronym
Take the label from the new object
41. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$labeledDrink = new LabeledDrink(
$drink,
$human->getAcronym());
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',
$labeledDrink->getLabel())
);
Is there a better
place to instantiate
the object?
42. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$labeledDrink = new LabeledDrink(
$drink,
$human->getAcronym());
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',
$labeledDrink->getLabel())
);
Is there a better
place to instantiate
the object?
Maybe here?
44. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
$human->getMobilePhoneNumber(),
sprintf('Drink %s ready',
$labeledDrink->getLabel())
);
Not all human have a phone number
45. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
$client->getMobilePhoneNumber(),
sprintf('Drink %s ready',
$labeledDrink->getLabel())
);
Our clients have a phone number!
46. //In Barman::prepare(Human $human, Drink $drink)
$client = new Client($human);
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
$client->getMobilePhoneNumber(),
sprintf('Drink %s ready',
$labeledDrink->getLabel())
);
Human becomes useless here
52. //In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
new DrinkIsReadyMessage($labeledDrink, $client);
);
Static is not testable!
53. //In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
new DrinkIsReadyMessage($labeledDrink, $client);
);
/*
Should the bar manage the sms messaging system?
*/
Static is not testable!
54. //In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
new DrinkIsReadyMessage($labeledDrink, $client);
);
/*
Should the bar manage the sms messaging system?
Why not, but it already manages the drinks stock.
*/
Static is not testable!
55. //In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
new DrinkIsReadyMessage($labeledDrink, $client);
);
/*
Should the bar manage the sms messaging system?
Why not, but it already manages the drinks stock.
Maybe the bar should be a facade?
*/
Static is not testable!
57. //In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$this->bar->sendMessage(
new DrinkIsReadyMessage($labeledDrink, $client);
);
Simplest solution...
Voilà! Let's not over engineering for the moment :)
58. interface Bar{
public function removeFromStock(Drink $drink);
public function hasInStock(Drink $drink);
public function sendMessage(Message $message);//New
}
interface Client{
public function addDrink(Drink $drink);
public function getMobilePhoneNumber();
}
interface labeledDrink extends Drink{ //New class
public function getLabel();
}
interface Message{ //New interface
public function getPhoneNumber();
public function getMessage();
}
interface DrinkIsReadyMessage extends Message{} //New
59. class BillPrinter{ //Let's print the bill!
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
$this->renderAsXml($client);
} elseif ($this->type === 'html') {
$this->renderAsHtml($client);
} else {
throw new Exception('Invalid input');
}
}
public function renderAsHtml(Client $client){}
public function renderAsXml(Client $client){}
}
60. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
$this->renderAsXml($client);
} elseif ($this->type === 'html') {
$this->renderAsHtml($client);
} else {
throw new Exception('Invalid input');
}
}
public function renderAsHtml(Client $client){}
public function renderAsXml(Client $client){}
}
Generic exception
61. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
$this->renderAsXml($client);
} elseif ($this->type === 'html') {
$this->renderAsHtml($client);
} else {
throw new InvalidTypeException();
}
}
public function renderAsHtml(Client $client){}
public function renderAsXml(Client $client){}
}
62. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
$this->renderAsXml($client);
} elseif ($this->type === 'html') {
$this->renderAsHtml($client);
} else {
throw new InvalidTypeException();
}
}
public function renderAsHtml(Client $client){}
public function renderAsXml(Client $client){}
}
Render an xml
Render an html
2 responsabilities
63. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
(new XmlBillPrinter())->render($client);
} elseif ($this->type === 'html') {
$this->renderAsHtml($client);
} else {
throw new InvalidTypeException();
}
}
public function renderAsHtml(Client $client){}
}
Render an html
Delegate xml
64. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
(new XmlBillPrinter())->render($client);
} elseif ($this->type === 'html') {
(new HtmlBillPrinter())->render($client);
} else {
throw new InvalidTypeException();
}
}
}
Delegate html
Delegate xml
65. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
(new XmlBillPrinter())->render($client);
} elseif ($this->type === 'html') {
(new HtmlBillPrinter())->render($client);
} else {
throw new InvalidTypeException();
}
}
}
66. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
(new XmlBillPrinter())->render($client);
} elseif ($this->type === 'html') {
(new HtmlBillPrinter())->render($client);
} else {
throw new InvalidTypeException();
}
}
}
interface BillPrinterInterface{
public function render(Client $client);
}
NB: The same interface is used
67. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
(new XmlBillPrinter())->render($client);
} elseif ($this->type === 'html') {
(new HtmlBillPrinter())->render($client);
} else {
throw new InvalidTypeException();
}
}
} It’s not my job to find what instantiate!
I just want to render a bill!
68. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
if ($this->type === 'xml') {
(new XmlBillPrinter())->render($client);
} elseif ($this->type === 'html') {
(new HtmlBillPrinter())->render($client);
} else {
throw new InvalidTypeException();
}
}
} It’s not my job to find what instantiate!
I just want to render a bill!
Delegate to a private method first...
69. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
$this->getPrinterInstance()->render($client);
}
public function getPrinterInstance(){
if ($this->type === 'xml') {
return new XmlBillPrinter();
} elseif ($this->type === 'html') {
return new HtmlBillPrinter();
} else {
throw new InvalidTypeException();
}
}
}
70. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
$this->getPrinterInstance()->render($client);
}
public function getPrinterInstance(){
if ($this->type === 'xml') {
return new XmlBillPrinter();
} elseif ($this->type === 'html') {
return new HtmlBillPrinter();
} else {
throw new InvalidTypeException();
}
}
}
It’s really not my job to
find what instantiate!
71. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
$this->getPrinterInstance()->render($client);
}
public function getPrinterInstance(){
if ($this->type === 'xml') {
return new XmlBillPrinter();
} elseif ($this->type === 'html') {
return new HtmlBillPrinter();
} else {
throw new InvalidTypeException();
}
}
}
It’s really not my job to
find what instantiate!
It’s a factory job!
72. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
BillPrinterFactory::create($this->type)
->render($client);
}
}
class BillPrinterFactory{
public static function create(string $type){
if ($type === 'xml') {
return new XmlBillPrinter();
} else //...
}
}
73. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
BillPrinterFactory::create($this->type)
->render($client);
}
}
class BillPrinterFactory{
public static function create(string $type){
if ($type === 'xml') {
return new XmlBillPrinter();
} else //...
}
}
What is the purpose of this class again?
74. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
BillPrinterFactory::create($this->type)
->render($client);
}
}
class BillPrinterFactory{
public static function create(string $type){
if ($type === 'xml') {
return new XmlBillPrinter();
} else //...
}
}
What is the purpose of this class again?
75. class BillPrinter{
public function __construct(string $type) {
$this->type = $type;
}
public function renderClientBill(Client $client){
BillPrinterFactory::create($this->type)
->render($client);
}
}
class BillPrinterFactory{
public static function create(string $type){
if ($type === 'xml') {
return new XmlBillPrinter();
} else //...
}
}
Remove the unnecessary class :)
76. //What about the render of the bill in HTML?
class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$render .= '<div class="drink-line"';
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
77. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$render .= '<div class="drink-line"';
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
It renders lines
78. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$render .= '<div class="drink-line"';
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
It manages HTML and its attributes
It renders lines
79. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$render .= '<div class="drink-line"';
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
It manages HTML and its attributes
And who’s gonna escape string if necessary?
It renders lines
80. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$render .= '<div class="drink-line"';
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
It manages HTML and its attributes
And who’s gonna escape string if necessary?
It renders lines
It’s bibi!
81. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
return '<div class="drink-line"';
$div = new HtmlTag('div');
$div->addAttribute('class', 'drink-line');
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
82. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$div = new HtmlTag('div');
$div->addAttribute('class', 'drink-line');
if ($drink->containsAlcohol()) {
$render .= ' data-alcohol="1"';
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
83. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$div = new HtmlTag('div');
$div->addAttribute('class', 'drink-line');
if ($drink->containsAlcohol()) {
return ' data-alcohol="1"';
$div->addAttribute('data-alcohol', '1');
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
84. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$div = new HtmlTag('div');
$div->addAttribute('class', 'drink-line');
if ($drink->containsAlcohol()) {
$div->addAttribute('data-alcohol', '1');
}
$render.= '>'. $drink->getPrice() .'</div>';
}
return $render;
}
}
85. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$div = new HtmlTag('div');
$div->addAttribute('class', 'drink-line');
if ($drink->containsAlcohol()) {
$div->addAttribute('data-alcohol', '1');
}
$render.= '>'. $drink->getPrice() .'</div>';
$div->setHtml($drink->getPrice());
return $div;
}
}
}
86. class HtmlBillPrinter
implements BillPrinterInterface{
public function render(Client $client){
foreach($client->getDrinks() as $drink){
$div = new HtmlTag('div');
$div->addAttribute('class', 'drink-line');
if ($drink->containsAlcohol()) {
$div->addAttribute('data-alcohol', '1');
}
$div->setHtml($drink->getPrice());
return $div;
}
}
}
87. It’s all about making
Your code comprehensible
WRAPPING UP