Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Introduction to Clean Code

178 views

Published on

Talk given to university students during the "Seminari UPC 2017"

Published in: Technology
  • Be the first to comment

Introduction to Clean Code

  1. 1. Clean code Cleaner, cleaner, cleaner!
  2. 2. What is clean code? Clean code
  3. 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. 4. 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; } }
  5. 5. ● Code surface ○ Code style, DRY (duplication), comments ● Naming ● Easier functions ● Cleaner logic ○ Guards, configuration over hardcoding Clean code Index
  6. 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. 7. ● A repository with n developers should look homogeneous ● Code style (CS) tools ○ Verification ○ Automatic fixer Clean code Code style
  8. 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. 9. ● Imposed duplication (unavoidable case) ○ Multiple representations of information ● Use a copy-paste detector Clean code Don’t Repeat Yourself (DRY)
  10. 10. ● The less, the better! ● Usually comments are not needed ○ Redundant ○ Outdated ● Or even worse.. ○ Commented out code Clean code Comments
  11. 11. 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; } (...)
  12. 12. ● 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
  13. 13. 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); }
  14. 14. 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); }
  15. 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. 16. 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); }
  17. 17. 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); }
  18. 18. ● Small! Really small! ○ 2, 3, 4 lines ● Do ONLY one thing! Clean code Easier functions
  19. 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. 20. 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; }
  21. 21. ● 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
  22. 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. 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. 24. ● Guard clauses ● Configuration over hardcoding Clean code Cleaner logic
  25. 25. 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
  26. 26. 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"); } }
  27. 27. Clean code class FeedParser { public function doParse() { $xmlData = $this->readXML("/tmp/products.xml"); $products = $this->extractProductsFromXmlData($xmlData); return $products; } // Let’s remove the hardcoding
  28. 28. 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; }
  29. 29. ● Books: ○ Clean Code (Robert “Uncle Bob” Martin) ○ The Pragmatic Programmer (Hunt & Tomas) ○ Refactoring (Fowler) Clean code And you can continue cleaning… forever

×