SlideShare a Scribd company logo
Why Your Code Suxx
And why you should care about it ?
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
Nicolas De Boose
➢ Freelancer
➢ PHP, Symfony2, (Node) Js, Css
➢ 10 yrs pro
➢ A wonderful fiancee <3
➢ @NicoDeBoose
➢ Blog: mechantblog.com
ABOUT ME
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
HOW ?
1. Presentation of code that smells
2. Your opinion
3. Refactoring
//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);
}
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;
}
}
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
//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;
//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) ...
//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;
//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
//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;
//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;
//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
//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;
//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!
//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;
//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?
//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;
//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
//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
//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);
//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!
//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
//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
//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);
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);
}
//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)
);
//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?
//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)
);
//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?
//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 ...
//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)
);
//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
//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())
);
//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?
//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
//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.
//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
//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?
//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?
//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())
);
//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
//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!
//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
//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())
);
//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!
//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...
//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(){/* … */}
}
//In Barman::prepare(Client $client, Drink $drink)
$labeledDrink = $client->addDrink($drink);
$this->bar->removeFromStock($drink);
/* ... Prepare the drink ... */
SmsSender::send(
new DrinkIsReadyMessage($labeledDrink, $client);
);
//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!
//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!
//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!
//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!
//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...
//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 :)
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
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){}
}
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
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){}
}
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
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
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
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();
}
}
}
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
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!
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...
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();
}
}
}
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!
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!
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 //...
}
}
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?
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?
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 :)
//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;
}
}
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
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
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
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!
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
}
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;
}
}
}
It’s all about making
Your code comprehensible
WRAPPING UP
Books
Thank you ☺
Questions?
INFO@BLUBIRD.EU
+32 2 880 05 41

More Related Content

What's hot

Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::ManagerJay Shirley
 
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
John Ford
 
R57shell
R57shellR57shell
R57shell
ady36
 
Top 10 php classic traps php serbia
Top 10 php classic traps php serbiaTop 10 php classic traps php serbia
Top 10 php classic traps php serbia
Damien Seguy
 
NSClient++ Workshop: 05 Monitoring
NSClient++ Workshop: 05 MonitoringNSClient++ Workshop: 05 Monitoring
NSClient++ Workshop: 05 Monitoring
Michael Medin
 
Zen: Building Maintainable Catalyst Applications
Zen: Building Maintainable Catalyst ApplicationsZen: Building Maintainable Catalyst Applications
Zen: Building Maintainable Catalyst Applications
Jay Shirley
 
Recettes de tests
Recettes de testsRecettes de tests
Recettes de tests
Charles Desneuf
 
Webinar PHParty7 - Errors handlings
Webinar PHParty7 - Errors handlingsWebinar PHParty7 - Errors handlings
Webinar PHParty7 - Errors handlings
Darkmira
 
PHPSpec BDD Framework
PHPSpec BDD FrameworkPHPSpec BDD Framework
PHPSpec BDD Framework
Marcello Duarte
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
Michelangelo van Dam
 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Ralf Eggert
 
cocos2d入門
cocos2d入門cocos2d入門
cocos2d入門
Kohki Miki
 
Obfuscation, Golfing and Secret Operators in Perl
Obfuscation, Golfing and Secret Operators in PerlObfuscation, Golfing and Secret Operators in Perl
Obfuscation, Golfing and Secret Operators in Perl
José Castro
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
markstory
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка TwistedMaxim Kulsha
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
Michelangelo van Dam
 

What's hot (20)

Nop2
Nop2Nop2
Nop2
 
Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::Manager
 
R57.Php
R57.PhpR57.Php
R57.Php
 
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
 
R57shell
R57shellR57shell
R57shell
 
Top 10 php classic traps php serbia
Top 10 php classic traps php serbiaTop 10 php classic traps php serbia
Top 10 php classic traps php serbia
 
NSClient++ Workshop: 05 Monitoring
NSClient++ Workshop: 05 MonitoringNSClient++ Workshop: 05 Monitoring
NSClient++ Workshop: 05 Monitoring
 
Zen: Building Maintainable Catalyst Applications
Zen: Building Maintainable Catalyst ApplicationsZen: Building Maintainable Catalyst Applications
Zen: Building Maintainable Catalyst Applications
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Recettes de tests
Recettes de testsRecettes de tests
Recettes de tests
 
Webinar PHParty7 - Errors handlings
Webinar PHParty7 - Errors handlingsWebinar PHParty7 - Errors handlings
Webinar PHParty7 - Errors handlings
 
PHPSpec BDD Framework
PHPSpec BDD FrameworkPHPSpec BDD Framework
PHPSpec BDD Framework
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
 
cocos2d入門
cocos2d入門cocos2d入門
cocos2d入門
 
Obfuscation, Golfing and Secret Operators in Perl
Obfuscation, Golfing and Secret Operators in PerlObfuscation, Golfing and Secret Operators in Perl
Obfuscation, Golfing and Secret Operators in Perl
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка Twisted
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
 

Similar to Why your code suxx

Writing code you won’t hate tomorrow - PHPCE18
Writing code you won’t hate tomorrow - PHPCE18Writing code you won’t hate tomorrow - PHPCE18
Writing code you won’t hate tomorrow - PHPCE18
Rafael Dohms
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
Ricardo Signes
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
Ross Tuck
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
XSolve
 
Functional php
Functional phpFunctional php
Functional php
Jean Carlo Machado
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
Presentation1
Presentation1Presentation1
Presentation1
Rahadyan Gusti
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
Rafael Dohms
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
Flavio Poletti
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
Abbas Ali
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHPTaras Kalapun
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
Wez Furlong
 
Taming Command Bus
Taming Command BusTaming Command Bus
Taming Command Bus
Krzysztof Menżyk
 
PHP 良好實踐 (Best Practice)
PHP 良好實踐 (Best Practice)PHP 良好實踐 (Best Practice)
PHP 良好實踐 (Best Practice)
Win Yu
 
PHP Tips & Tricks
PHP Tips & TricksPHP Tips & Tricks
PHP Tips & Tricks
Radek Benkel
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
Marcello Duarte
 
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
Amazon Web Services
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
Jeroen van Dijk
 
groovy & grails - lecture 12
groovy & grails - lecture 12groovy & grails - lecture 12
groovy & grails - lecture 12
Alexandre Masselot
 
Development by the numbers
Development by the numbersDevelopment by the numbers
Development by the numbers
Anthony Ferrara
 

Similar to Why your code suxx (20)

Writing code you won’t hate tomorrow - PHPCE18
Writing code you won’t hate tomorrow - PHPCE18Writing code you won’t hate tomorrow - PHPCE18
Writing code you won’t hate tomorrow - PHPCE18
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
Functional php
Functional phpFunctional php
Functional php
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
Presentation1
Presentation1Presentation1
Presentation1
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
Taming Command Bus
Taming Command BusTaming Command Bus
Taming Command Bus
 
PHP 良好實踐 (Best Practice)
PHP 良好實踐 (Best Practice)PHP 良好實踐 (Best Practice)
PHP 良好實踐 (Best Practice)
 
PHP Tips & Tricks
PHP Tips & TricksPHP Tips & Tricks
PHP Tips & Tricks
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
groovy & grails - lecture 12
groovy & grails - lecture 12groovy & grails - lecture 12
groovy & grails - lecture 12
 
Development by the numbers
Development by the numbersDevelopment by the numbers
Development by the numbers
 

Recently uploaded

St John's Parish Diary for June 2024.pdf
St John's Parish Diary for June 2024.pdfSt John's Parish Diary for June 2024.pdf
St John's Parish Diary for June 2024.pdf
Chris Lyne
 
St. John's Parish Magazine - June 2024 ..
St. John's Parish Magazine - June 2024 ..St. John's Parish Magazine - June 2024 ..
St. John's Parish Magazine - June 2024 ..
Chris Lyne
 
The Hope of Salvation - Jude 1:24-25 - Message
The Hope of Salvation - Jude 1:24-25 - MessageThe Hope of Salvation - Jude 1:24-25 - Message
The Hope of Salvation - Jude 1:24-25 - Message
Cole Hartman
 
快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样
快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样
快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样
cfk7atz3
 
Deerfoot Church of Christ Bulletin 6 9 24
Deerfoot Church of Christ Bulletin 6 9 24Deerfoot Church of Christ Bulletin 6 9 24
Deerfoot Church of Christ Bulletin 6 9 24
deerfootcoc
 
A375 Example Taste the taste of the Lord, the taste of the Lord The taste of...
A375 Example Taste the taste of the Lord,  the taste of the Lord The taste of...A375 Example Taste the taste of the Lord,  the taste of the Lord The taste of...
A375 Example Taste the taste of the Lord, the taste of the Lord The taste of...
franktsao4
 
A Free eBook ~ Valuable LIFE Lessons to Learn ( 5 Sets of Presentations)...
A Free eBook ~ Valuable LIFE Lessons    to Learn   ( 5 Sets of Presentations)...A Free eBook ~ Valuable LIFE Lessons    to Learn   ( 5 Sets of Presentations)...
A Free eBook ~ Valuable LIFE Lessons to Learn ( 5 Sets of Presentations)...
OH TEIK BIN
 
Hajj and umrah notes short procedure with important duas and translation
Hajj and umrah notes short procedure with important duas and translationHajj and umrah notes short procedure with important duas and translation
Hajj and umrah notes short procedure with important duas and translation
syedsaudnaqvi1
 
Vertical Church Kyiv Report 2022-2023: Church at war
Vertical Church Kyiv Report 2022-2023: Church at warVertical Church Kyiv Report 2022-2023: Church at war
Vertical Church Kyiv Report 2022-2023: Church at war
Olena Tyshchenko-Tyshkovets
 
Exploring the Mindfulness Understanding Its Benefits.pptx
Exploring the Mindfulness Understanding Its Benefits.pptxExploring the Mindfulness Understanding Its Benefits.pptx
Exploring the Mindfulness Understanding Its Benefits.pptx
MartaLoveguard
 
The_Chronological_Life_of_Christ_Part_103_Search_and_Rescue
The_Chronological_Life_of_Christ_Part_103_Search_and_RescueThe_Chronological_Life_of_Christ_Part_103_Search_and_Rescue
The_Chronological_Life_of_Christ_Part_103_Search_and_Rescue
Network Bible Fellowship
 
1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...
1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...
1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...
COACH International Ministries
 
Twisters
TwistersTwisters
Twisters
Dave Stewart
 
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptx
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptxWhy is this So? ~ Do Seek to KNOW (English & Chinese).pptx
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptx
OH TEIK BIN
 
Vain Traditions of Men that are Irrelevant to Bible
Vain Traditions of Men that are Irrelevant to BibleVain Traditions of Men that are Irrelevant to Bible
Vain Traditions of Men that are Irrelevant to Bible
charlesdefeo2
 
Effective Techniques for Removing Negative Entities
Effective Techniques for Removing Negative EntitiesEffective Techniques for Removing Negative Entities
Effective Techniques for Removing Negative Entities
Reiki Healing Distance
 
2. The Book of Psalms: Recognition of the kingship and sovereignty of God
2. The Book of Psalms: Recognition of the kingship and sovereignty of God2. The Book of Psalms: Recognition of the kingship and sovereignty of God
2. The Book of Psalms: Recognition of the kingship and sovereignty of God
COACH International Ministries
 

Recently uploaded (17)

St John's Parish Diary for June 2024.pdf
St John's Parish Diary for June 2024.pdfSt John's Parish Diary for June 2024.pdf
St John's Parish Diary for June 2024.pdf
 
St. John's Parish Magazine - June 2024 ..
St. John's Parish Magazine - June 2024 ..St. John's Parish Magazine - June 2024 ..
St. John's Parish Magazine - June 2024 ..
 
The Hope of Salvation - Jude 1:24-25 - Message
The Hope of Salvation - Jude 1:24-25 - MessageThe Hope of Salvation - Jude 1:24-25 - Message
The Hope of Salvation - Jude 1:24-25 - Message
 
快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样
快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样
快速办理(PU毕业证书)普渡大学毕业证文凭证书一模一样
 
Deerfoot Church of Christ Bulletin 6 9 24
Deerfoot Church of Christ Bulletin 6 9 24Deerfoot Church of Christ Bulletin 6 9 24
Deerfoot Church of Christ Bulletin 6 9 24
 
A375 Example Taste the taste of the Lord, the taste of the Lord The taste of...
A375 Example Taste the taste of the Lord,  the taste of the Lord The taste of...A375 Example Taste the taste of the Lord,  the taste of the Lord The taste of...
A375 Example Taste the taste of the Lord, the taste of the Lord The taste of...
 
A Free eBook ~ Valuable LIFE Lessons to Learn ( 5 Sets of Presentations)...
A Free eBook ~ Valuable LIFE Lessons    to Learn   ( 5 Sets of Presentations)...A Free eBook ~ Valuable LIFE Lessons    to Learn   ( 5 Sets of Presentations)...
A Free eBook ~ Valuable LIFE Lessons to Learn ( 5 Sets of Presentations)...
 
Hajj and umrah notes short procedure with important duas and translation
Hajj and umrah notes short procedure with important duas and translationHajj and umrah notes short procedure with important duas and translation
Hajj and umrah notes short procedure with important duas and translation
 
Vertical Church Kyiv Report 2022-2023: Church at war
Vertical Church Kyiv Report 2022-2023: Church at warVertical Church Kyiv Report 2022-2023: Church at war
Vertical Church Kyiv Report 2022-2023: Church at war
 
Exploring the Mindfulness Understanding Its Benefits.pptx
Exploring the Mindfulness Understanding Its Benefits.pptxExploring the Mindfulness Understanding Its Benefits.pptx
Exploring the Mindfulness Understanding Its Benefits.pptx
 
The_Chronological_Life_of_Christ_Part_103_Search_and_Rescue
The_Chronological_Life_of_Christ_Part_103_Search_and_RescueThe_Chronological_Life_of_Christ_Part_103_Search_and_Rescue
The_Chronological_Life_of_Christ_Part_103_Search_and_Rescue
 
1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...
1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...
1. The Book of Job: God's infinite wisdom is the key to acknowledging his jus...
 
Twisters
TwistersTwisters
Twisters
 
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptx
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptxWhy is this So? ~ Do Seek to KNOW (English & Chinese).pptx
Why is this So? ~ Do Seek to KNOW (English & Chinese).pptx
 
Vain Traditions of Men that are Irrelevant to Bible
Vain Traditions of Men that are Irrelevant to BibleVain Traditions of Men that are Irrelevant to Bible
Vain Traditions of Men that are Irrelevant to Bible
 
Effective Techniques for Removing Negative Entities
Effective Techniques for Removing Negative EntitiesEffective Techniques for Removing Negative Entities
Effective Techniques for Removing Negative Entities
 
2. The Book of Psalms: Recognition of the kingship and sovereignty of God
2. The Book of Psalms: Recognition of the kingship and sovereignty of God2. The Book of Psalms: Recognition of the kingship and sovereignty of God
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
  • 5. HOW ? 1. Presentation of code that smells 2. Your opinion 3. Refactoring
  • 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
  • 9. //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;
  • 10. //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) ...
  • 11. //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;
  • 12. //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
  • 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); }
  • 29. //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) );
  • 30. //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?
  • 31. //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) );
  • 32. //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?
  • 33. //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 ...
  • 34. //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) );
  • 35. //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
  • 36. //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()) );
  • 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?
  • 43. //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()) );
  • 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
  • 47. //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()) );
  • 48. //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!
  • 49. //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...
  • 50. //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(){/* … */} }
  • 51. //In Barman::prepare(Client $client, Drink $drink) $labeledDrink = $client->addDrink($drink); $this->bar->removeFromStock($drink); /* ... Prepare the drink ... */ SmsSender::send( new DrinkIsReadyMessage($labeledDrink, $client); );
  • 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!
  • 56. //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...
  • 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
  • 88. Books