why your code suxx
TRANSCRIPT
![Page 1: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/1.jpg)
Why Your Code SuxxAnd why you should care about it ?
![Page 2: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/2.jpg)
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 pictureSecurity, Mobility, Apps & Cloud
![Page 3: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/3.jpg)
Nicolas De Boose
➢ Freelancer
➢ PHP, Symfony2, (Node) Js, Css
➢ 10 yrs pro
➢ A wonderful fiancee <3
➢@NicoDeBoose
➢ Blog: mechantblog.com
ABOUT ME
![Page 4: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/4.jpg)
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
![Page 5: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/5.jpg)
HOW ?
1. Presentation of code that smells
2. Your opinion
3. Refactoring
![Page 6: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/6.jpg)
//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);
}
![Page 7: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/7.jpg)
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;
}}
![Page 8: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/8.jpg)
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
![Page 9: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/9.jpg)
//In Barman::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 false;
}return true;
![Page 10: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/10.jpg)
//In Barman::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 false;
}return true;
== true) == true) ...
![Page 11: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/11.jpg)
//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;
![Page 12: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/12.jpg)
//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;
Nested if’s
![Page 13: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/13.jpg)
//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;
![Page 14: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/14.jpg)
//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;
![Page 15: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/15.jpg)
//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
![Page 16: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/16.jpg)
//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;
![Page 17: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/17.jpg)
//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!
![Page 18: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/18.jpg)
//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;
![Page 19: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/19.jpg)
//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?
![Page 20: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/20.jpg)
//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;
![Page 21: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/21.jpg)
//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
![Page 22: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/22.jpg)
//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 nothingSolution 2: Return a “Result” object
![Page 23: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/23.jpg)
//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);
![Page 24: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/24.jpg)
//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!
![Page 25: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/25.jpg)
//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
![Page 26: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/26.jpg)
//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
![Page 27: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/27.jpg)
//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);
![Page 28: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/28.jpg)
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);
}
![Page 29: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/29.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$tmp = explode(" ", $human->getFullName());$ac = "";foreach ($tmp as $w) {
$ac .= $w[0];}$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($ac);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $ac)
);
![Page 30: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/30.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$tmp = explode(" ", $human->getFullName());$ac = "";foreach ($tmp as $w) {
$ac .= $w[0];}$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($ac);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $ac)
);
What does “tmp” mean?
What does “ac” mean?
![Page 31: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/31.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$nameParts = explode(" ",$human->getFullName());$acronym = "";foreach ($nameParts as $w) {
$acronym .= $w[0];}$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($acronym);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $acronym)
);
![Page 32: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/32.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$nameParts = explode(" ",$human->getFullName());$acronym = "";foreach ($nameParts as $w) {
$acronym .= $w[0];}$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($acronym);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $acronym)
);
Can we compute the acronym elsewhere?
![Page 33: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/33.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$acronym = $this->getHumanAcronym($human);$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($acronym);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $acronym)
);
That’s better, but ...
![Page 34: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/34.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$acronym = $human->getAcronym();$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($acronym);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $acronym)
);
![Page 35: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/35.jpg)
//In Barman::prepare(Human $human, Drink $drink)
$acronym = $human->getAcronym();$human->addToBill($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
$drink->setAcronym($acronym);SmsSender::send(
$human->getMobilePhoneNumber(),sprintf('Drink %s ready', $acronym)
);
Now let’s remove $acronym var
![Page 36: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/36.jpg)
//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())
);
![Page 37: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/37.jpg)
//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?
![Page 38: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/38.jpg)
//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
![Page 39: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/39.jpg)
//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.
![Page 40: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/40.jpg)
//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
![Page 41: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/41.jpg)
//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?
![Page 42: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/42.jpg)
//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?
![Page 43: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/43.jpg)
//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()));
![Page 44: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/44.jpg)
//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
![Page 45: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/45.jpg)
//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!
![Page 46: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/46.jpg)
//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
![Page 47: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/47.jpg)
//In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send($client->getMobilePhoneNumber(),sprintf('Drink %s ready',
$labeledDrink->getLabel()));
![Page 48: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/48.jpg)
//In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send($client->getMobilePhoneNumber(),sprintf('Drink %s ready',
$labeledDrink->getLabel()));
Hello ugly hard coded content!
![Page 49: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/49.jpg)
//In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send($client->getMobilePhoneNumber(),sprintf('Drink %s ready',
$labeledDrink->getLabel()));
Hello ugly hard coded content!
We actually send a message here...
![Page 50: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/50.jpg)
//In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(new DrinkIsReadyMessage($labeledDrink, $client););
//FYI
class DrinkIsReadyMessage implements Message{public function getPhoneNumber(){
return $this->client->getMobilePhoneNumber();}public function getMessage(){/* … */}
}
![Page 51: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/51.jpg)
//In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(new DrinkIsReadyMessage($labeledDrink, $client););
![Page 52: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/52.jpg)
//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!
![Page 53: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/53.jpg)
//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!
![Page 54: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/54.jpg)
//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!
![Page 55: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/55.jpg)
//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!
![Page 56: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/56.jpg)
//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...
![Page 57: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/57.jpg)
//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 :)
![Page 58: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/58.jpg)
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 interfacepublic function getPhoneNumber();public function getMessage();
}interface DrinkIsReadyMessage extends Message{} //New
![Page 59: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/59.jpg)
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){}
}
![Page 60: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/60.jpg)
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
![Page 61: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/61.jpg)
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){}
}
![Page 62: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/62.jpg)
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
![Page 63: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/63.jpg)
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
![Page 64: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/64.jpg)
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
![Page 65: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/65.jpg)
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();
}}
}
![Page 66: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/66.jpg)
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
![Page 67: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/67.jpg)
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!
![Page 68: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/68.jpg)
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...
![Page 69: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/69.jpg)
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();
}}
}
![Page 70: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/70.jpg)
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!
![Page 71: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/71.jpg)
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!
![Page 72: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/72.jpg)
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 //...
}}
![Page 73: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/73.jpg)
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?
![Page 74: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/74.jpg)
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?
![Page 75: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/75.jpg)
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 :)
![Page 76: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/76.jpg)
//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;
}}
![Page 77: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/77.jpg)
class HtmlBillPrinterimplements 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
![Page 78: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/78.jpg)
class HtmlBillPrinterimplements 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
![Page 79: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/79.jpg)
class HtmlBillPrinterimplements 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
![Page 80: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/80.jpg)
class HtmlBillPrinterimplements 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!
![Page 81: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/81.jpg)
class HtmlBillPrinterimplements 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;
}}
![Page 82: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/82.jpg)
class HtmlBillPrinterimplements 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;
}}
![Page 83: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/83.jpg)
class HtmlBillPrinterimplements 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;
}}
![Page 84: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/84.jpg)
class HtmlBillPrinterimplements 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;
}}
![Page 85: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/85.jpg)
class HtmlBillPrinterimplements 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;
}}
}
![Page 86: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/86.jpg)
class HtmlBillPrinterimplements 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;
}}
}
![Page 87: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/87.jpg)
It’s all about making
Your code comprehensible
WRAPPING UP
![Page 88: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/88.jpg)
Books
![Page 89: Why your code suxx](https://reader034.vdocument.in/reader034/viewer/2022051400/55ab23501a28abe0488b4641/html5/thumbnails/89.jpg)
Thank you ☺Questions?