Clean code
Cleaner, cleaner, cleaner!
What is clean code?
Clean code
Clean code
Code example: product XML-feed parser
class FeedParser
{
public function doParse()
{
$products = array(); //array of products to return
$xml = simplexml_load_file("/tmp/products.xml"); //read xml file
if ($xml === FALSE) {
throw new Exception("feed not found"); //file not found
} else {
if (count($xml) === 0) {
throw new Exception("empty feed");
} else {
foreach($xml as $elem) {
$prod = $this->parse_elem($elem);
array_push($products, $prod); //add Product object
}
}
}
return $products;
}
(...)
Clean code
http://bit.ly/seminariUPCexample
class FeedParser
{
(...)
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
//Product not active
return new Product($name, $url, $elem->id, false);
}
private function getElementErrorHandler($elem, $attr) {
$item = (string)$elem->$attr;
if ($item == "") {
throw new Exception("incorrect item");
}
return $item;
}
}
● Code surface
○ Code style, DRY (duplication), comments
● Naming
● Easier functions
● Cleaner logic
○ Guards, configuration over hardcoding
Clean code
Index
Clean code
Code style: let’s find fails
class FeedParser
{
(...)
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
//Product not active
return new Product($name, $url, $elem->id, false);
}
private function getElementErrorHandler($elem, $attr) {
$item = (string)$elem->$attr;
if ($item == "") {
throw new Exception("incorrect item");
}
return $item;
}
}
● A repository with n developers should look homogeneous
● Code style (CS) tools
○ Verification
○ Automatic fixer
Clean code
Code style
● Impatient duplication
○ copy it and make a couple of changes
● Inter-developer duplication
○ Make it easy to use/reuse
Clean code
Don’t Repeat Yourself (DRY)
● Imposed duplication (unavoidable case)
○ Multiple representations of information
● Use a copy-paste detector
Clean code
Don’t Repeat Yourself (DRY)
● The less, the better!
● Usually comments are not needed
○ Redundant
○ Outdated
● Or even worse..
○ Commented out code
Clean code
Comments
Clean code
Any useful comment here?
class FeedParser
{
public function doParse()
{
$products = array(); //array of products to return
$xml = simplexml_load_file("/tmp/products.xml"); //read xml file
if ($xml === FALSE) {
throw new Exception("feed not found"); //file not found
} else {
if (count($xml) === 0) {
throw new Exception("empty feed");
} else {
foreach($xml as $elem) {
$prod = $this->parse_elem($elem);
array_push($products, $prod); //add Product object
}
}
}
return $products;
}
(...)
● Use the code itself to explain the logic
○ Use a variable instead of a comment
○ Use intention revealing names in vars and functions
Clean code
Comments
Clean code
Use a variable instead of a comment
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
//Product not active
return new Product($name, $url, $elem->id, false);
}
Clean code
Use a variable instead of a comment
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
//Product not active
return new Product($name, $url, $elem->id, false);
}
--------
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
$isActive = false;
return new Product($name, $url, $elem->id, $isActive);
}
● Intention-revealing names
○ int days; //days since last purchase
○ int daysSinceLastPurchase;
● Shared vocabulary with the team
● Precise vocabulary
○ No “manageUser(...)” but “updateUserContactInfo(...)”
○ No “killUserInDb()” but “deleteUserFromDb()”
Clean code
Naming
Clean code
Looking for meaningful names
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
$isActive = false;
return new Product($name, $url, $elem->id, $isActive);
}
Clean code
Looking for meaningful names
private function parse_elem($elem)
{
$name = $this->getElementErrorHandler($elem, "title");
$url = $this->getElementErrorHandler($elem, "link");
$isActive = false;
return new Product($name, $url, $elem->id, $isActive);
}
--------
private function createProductFromXmlData($productXmlData)
{
$name = $this->getAttribute($productXmlData, "title");
$url = $this->getAttribute($productXmlData, "link");
$isActive = false;
return new Product($name, $url, $productXmlData->id, $isActive);
}
● Small! Really small!
○ 2, 3, 4 lines
● Do ONLY one thing!
Clean code
Easier functions
Clean code
Does doParse() do only one thing?
public function doParse()
{
$products = array();
$xml = simplexml_load_file("/tmp/products.xml");
if ($xml === FALSE) {
throw new Exception("feed not found");
} else {
if (count($xml) === 0) {
throw new Exception("empty feed");
} else {
foreach($xml as $elem) {
$prod = $this->createProductFromXmlData($elem);
array_push($products, $prod);
}
}
}
return $products;
}
Clean code
public function doParse()
{
$xmlData = $this->readXML("/tmp/products.xml");
$products = $this->extractProductsFromXmlData($xmlData);
return $products;
}
private function readXML($filename)
{
$xmlData = simplexml_load_file($filename);
if ($xmlData === FALSE) {
throw new Exception("feed not found");
} elseif (count($xml) === 0) {
throw new Exception("empty feed");
}
return $xmlData;
}
private function extractProductsFromXmlData($xmlData)
{
$products = array();
foreach($xmlData as $productXml) {
$prod = $this->createProductFromXmlData($productXml);
array_push($products, $prod);
}
return $products;
}
● Keep same level of abstraction
○ From top to bottom, outside in
● Arguments
○ Avoid many arguments: use objects or DTOs instead
○ Caution with flags (bool arguments)
Clean code
Easier functions
Clean code
Avoiding flags, and keeping same level
private function createProductFromXmlData($productXmlData)
{
$name = $this->getAttribute($productXmlData, "title");
$url = $this->getAttribute($productXmlData, "link");
$isActive = false;
return new Product($name, $url, $productXmlData->id, $isActive);
}
Clean code
Avoiding flags, and keeping same level
private function createProductFromXmlData($productXmlData)
{
$name = $this->getAttribute($productXmlData, "title");
$url = $this->getAttribute($productXmlData, "link");
$isActive = false;
return new Product($name, $url, $productXmlData->id, $isActive);
}
private function createProductFromXmlData($productXmlData)
{
$name = $this->getAttribute($productXmlData, "title");
$url = $this->getAttribute($productXmlData, "link");
$id = $this->getAttribute($productXmlData, "id");
return new Product::createInactive($name, $url, $id);
}
● Guard clauses
● Configuration over hardcoding
Clean code
Cleaner logic
Clean code
private function readXML($filename)
{
$xmlData = simplexml_load_file($filename);
if ($xmlData === FALSE) {
throw new Exception("feed not found");
} elseif (count($xml) === 0) {
throw new Exception("empty feed");
}
return $xmlData;
}
// Let’s add guard clauses
Clean code
private function readXML($filename)
{
$xmlData = simplexml_load_file($filename);
if ($xmlData === FALSE) {
throw new Exception("feed not found");
} elseif (count($xml) === 0) {
throw new Exception("empty feed");
}
return $xmlData;
}
// Let’s add guard clauses
private function readXML($filename)
{
$this->checkFileExists($filename);
$xmlData = simplexml_load_file($filename);
$this->checkXmlHasContent($xmlData);
return $xmlData;
}
private function checkFileExists($filename)
{
if (!file_exists($filename)) {
throw new Exception("File $filename not found");
}
}
Clean code
class FeedParser
{
public function doParse()
{
$xmlData = $this->readXML("/tmp/products.xml");
$products = $this->extractProductsFromXmlData($xmlData);
return $products;
}
// Let’s remove the hardcoding
Clean code
class FeedParser
{
public function doParse()
{
$xmlData = $this->readXML("/tmp/products.xml");
$products = $this->extractProductsFromXmlData($xmlData);
return $products;
}
// Let’s remove the hardcoding
class FeedParser
{
public function __construct($filename)
{
$this->XmlFilename = $filename;
}
public function doParse()
{
$xmlData = $this->readXML($this->XmlFilename);
$products = $this->extractProductsFromXmlData($xmlData);
return $products;
}
● Books:
○ Clean Code (Robert “Uncle Bob” Martin)
○ The Pragmatic Programmer (Hunt & Tomas)
○ Refactoring (Fowler)
Clean code
And you can continue cleaning… forever

Introduction to Clean Code

  • 1.
  • 2.
    What is cleancode? Clean code
  • 3.
    Clean code Code example:product XML-feed parser class FeedParser { public function doParse() { $products = array(); //array of products to return $xml = simplexml_load_file("/tmp/products.xml"); //read xml file if ($xml === FALSE) { throw new Exception("feed not found"); //file not found } else { if (count($xml) === 0) { throw new Exception("empty feed"); } else { foreach($xml as $elem) { $prod = $this->parse_elem($elem); array_push($products, $prod); //add Product object } } } return $products; } (...)
  • 4.
    Clean code http://bit.ly/seminariUPCexample class FeedParser { (...) privatefunction parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); //Product not active return new Product($name, $url, $elem->id, false); } private function getElementErrorHandler($elem, $attr) { $item = (string)$elem->$attr; if ($item == "") { throw new Exception("incorrect item"); } return $item; } }
  • 5.
    ● Code surface ○Code style, DRY (duplication), comments ● Naming ● Easier functions ● Cleaner logic ○ Guards, configuration over hardcoding Clean code Index
  • 6.
    Clean code Code style:let’s find fails class FeedParser { (...) private function parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); //Product not active return new Product($name, $url, $elem->id, false); } private function getElementErrorHandler($elem, $attr) { $item = (string)$elem->$attr; if ($item == "") { throw new Exception("incorrect item"); } return $item; } }
  • 7.
    ● A repositorywith n developers should look homogeneous ● Code style (CS) tools ○ Verification ○ Automatic fixer Clean code Code style
  • 8.
    ● Impatient duplication ○copy it and make a couple of changes ● Inter-developer duplication ○ Make it easy to use/reuse Clean code Don’t Repeat Yourself (DRY)
  • 9.
    ● Imposed duplication(unavoidable case) ○ Multiple representations of information ● Use a copy-paste detector Clean code Don’t Repeat Yourself (DRY)
  • 10.
    ● The less,the better! ● Usually comments are not needed ○ Redundant ○ Outdated ● Or even worse.. ○ Commented out code Clean code Comments
  • 11.
    Clean code Any usefulcomment here? class FeedParser { public function doParse() { $products = array(); //array of products to return $xml = simplexml_load_file("/tmp/products.xml"); //read xml file if ($xml === FALSE) { throw new Exception("feed not found"); //file not found } else { if (count($xml) === 0) { throw new Exception("empty feed"); } else { foreach($xml as $elem) { $prod = $this->parse_elem($elem); array_push($products, $prod); //add Product object } } } return $products; } (...)
  • 12.
    ● Use thecode itself to explain the logic ○ Use a variable instead of a comment ○ Use intention revealing names in vars and functions Clean code Comments
  • 13.
    Clean code Use avariable instead of a comment private function parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); //Product not active return new Product($name, $url, $elem->id, false); }
  • 14.
    Clean code Use avariable instead of a comment private function parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); //Product not active return new Product($name, $url, $elem->id, false); } -------- private function parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); $isActive = false; return new Product($name, $url, $elem->id, $isActive); }
  • 15.
    ● Intention-revealing names ○int days; //days since last purchase ○ int daysSinceLastPurchase; ● Shared vocabulary with the team ● Precise vocabulary ○ No “manageUser(...)” but “updateUserContactInfo(...)” ○ No “killUserInDb()” but “deleteUserFromDb()” Clean code Naming
  • 16.
    Clean code Looking formeaningful names private function parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); $isActive = false; return new Product($name, $url, $elem->id, $isActive); }
  • 17.
    Clean code Looking formeaningful names private function parse_elem($elem) { $name = $this->getElementErrorHandler($elem, "title"); $url = $this->getElementErrorHandler($elem, "link"); $isActive = false; return new Product($name, $url, $elem->id, $isActive); } -------- private function createProductFromXmlData($productXmlData) { $name = $this->getAttribute($productXmlData, "title"); $url = $this->getAttribute($productXmlData, "link"); $isActive = false; return new Product($name, $url, $productXmlData->id, $isActive); }
  • 18.
    ● Small! Reallysmall! ○ 2, 3, 4 lines ● Do ONLY one thing! Clean code Easier functions
  • 19.
    Clean code Does doParse()do only one thing? public function doParse() { $products = array(); $xml = simplexml_load_file("/tmp/products.xml"); if ($xml === FALSE) { throw new Exception("feed not found"); } else { if (count($xml) === 0) { throw new Exception("empty feed"); } else { foreach($xml as $elem) { $prod = $this->createProductFromXmlData($elem); array_push($products, $prod); } } } return $products; }
  • 20.
    Clean code public functiondoParse() { $xmlData = $this->readXML("/tmp/products.xml"); $products = $this->extractProductsFromXmlData($xmlData); return $products; } private function readXML($filename) { $xmlData = simplexml_load_file($filename); if ($xmlData === FALSE) { throw new Exception("feed not found"); } elseif (count($xml) === 0) { throw new Exception("empty feed"); } return $xmlData; } private function extractProductsFromXmlData($xmlData) { $products = array(); foreach($xmlData as $productXml) { $prod = $this->createProductFromXmlData($productXml); array_push($products, $prod); } return $products; }
  • 21.
    ● Keep samelevel of abstraction ○ From top to bottom, outside in ● Arguments ○ Avoid many arguments: use objects or DTOs instead ○ Caution with flags (bool arguments) Clean code Easier functions
  • 22.
    Clean code Avoiding flags,and keeping same level private function createProductFromXmlData($productXmlData) { $name = $this->getAttribute($productXmlData, "title"); $url = $this->getAttribute($productXmlData, "link"); $isActive = false; return new Product($name, $url, $productXmlData->id, $isActive); }
  • 23.
    Clean code Avoiding flags,and keeping same level private function createProductFromXmlData($productXmlData) { $name = $this->getAttribute($productXmlData, "title"); $url = $this->getAttribute($productXmlData, "link"); $isActive = false; return new Product($name, $url, $productXmlData->id, $isActive); } private function createProductFromXmlData($productXmlData) { $name = $this->getAttribute($productXmlData, "title"); $url = $this->getAttribute($productXmlData, "link"); $id = $this->getAttribute($productXmlData, "id"); return new Product::createInactive($name, $url, $id); }
  • 24.
    ● Guard clauses ●Configuration over hardcoding Clean code Cleaner logic
  • 25.
    Clean code private functionreadXML($filename) { $xmlData = simplexml_load_file($filename); if ($xmlData === FALSE) { throw new Exception("feed not found"); } elseif (count($xml) === 0) { throw new Exception("empty feed"); } return $xmlData; } // Let’s add guard clauses
  • 26.
    Clean code private functionreadXML($filename) { $xmlData = simplexml_load_file($filename); if ($xmlData === FALSE) { throw new Exception("feed not found"); } elseif (count($xml) === 0) { throw new Exception("empty feed"); } return $xmlData; } // Let’s add guard clauses private function readXML($filename) { $this->checkFileExists($filename); $xmlData = simplexml_load_file($filename); $this->checkXmlHasContent($xmlData); return $xmlData; } private function checkFileExists($filename) { if (!file_exists($filename)) { throw new Exception("File $filename not found"); } }
  • 27.
    Clean code class FeedParser { publicfunction doParse() { $xmlData = $this->readXML("/tmp/products.xml"); $products = $this->extractProductsFromXmlData($xmlData); return $products; } // Let’s remove the hardcoding
  • 28.
    Clean code class FeedParser { publicfunction doParse() { $xmlData = $this->readXML("/tmp/products.xml"); $products = $this->extractProductsFromXmlData($xmlData); return $products; } // Let’s remove the hardcoding class FeedParser { public function __construct($filename) { $this->XmlFilename = $filename; } public function doParse() { $xmlData = $this->readXML($this->XmlFilename); $products = $this->extractProductsFromXmlData($xmlData); return $products; }
  • 29.
    ● Books: ○ CleanCode (Robert “Uncle Bob” Martin) ○ The Pragmatic Programmer (Hunt & Tomas) ○ Refactoring (Fowler) Clean code And you can continue cleaning… forever