0
Your code sucks,let’s !x it!Object Calisthenics and Code readabilityRafael Dohms@rdohms
photocredit:EliWhiteEvangelist, Speaker andContributor.Developer at WEBclusive.Enabler at AmsterdamPHP.Rafael Dohms@rdohms
photocredit:EliWhiteEvangelist, Speaker andContributor.Developer at WEBclusive.Enabler at AmsterdamPHP.Rafael Dohms@rdohms
Why does mycode suck?
Why does mycode suck?Is it Readable?
Why does mycode suck?Is it Readable?Is it Testable?
Why does mycode suck?Is it Readable?Is it Testable?Is it Maintainable?
Why does mycode suck?Is it Readable?Is it Testable?Is it Maintainable?Is it Reusable?
Does it look like this?<?php$list=mysql_connect("******","*******","*****");if(!$list)echo Cannot login.;else{mysql_select...
Does it look like this?<?php$list=mysql_connect("******","*******","*****");if(!$list)echo Cannot login.;else{mysql_select...
How do we fix it?
Object Calisthenics
Object Calisthenicscal·is·then·ics-noun-/ˌkaləsˈTHeniks/Calisthenics are a form of dynamicexercise consisting of a variety...
Object Calisthenicscal·is·then·ics-noun-/ˌkaləsˈTHeniks/Calisthenics are a form of dynamicexercise consisting of a variety...
Object Calisthenics“So here’s an exercise that can help you to internalizeprinciples of good object-oriented design and ac...
Object Calisthenics“So here’s an exercise that can help you to internalizeprinciples of good object-oriented design and ac...
Object Calisthenics+Readability Tips
Object Calisthenics+Readability Tips“You need to write code that minimizes the time it wouldtake someone else to understan...
Object Calisthenics+Readability Tips“You need to write code that minimizes the time it wouldtake someone else to understan...
Disclaimer:“These are guidelines exercises,not rules”
OC #1“Only one indentationlevel per method”
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(pric...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] ...
function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) ...
function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) ...
function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) ...
function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) ...
function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) ...
function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) ...
Key Benefits• Single Responsibility Principle (S in SOLID)• Increases re-use
OC #2“Do not use the ‘else’keyword”
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isV...
public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new My...
public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new My...
public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new My...
public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new My...
public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new My...
public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new My...
Key Benefits• Helps avoid code duplication• Easier to read (single true path)• Reduces cyclomatic complexity
OC #3“Wrap primitive typesand strings”Adapted* if there is behavior
//...$component->repaint(false);
//...$component->repaint(false);
unclear operation//...$component->repaint(false);
class UIComponent{//...public function repaint($animate = true){//...}}unclear operation//...$component->repaint(false);
class UIComponent{//...public function repaint( Animate $animate ){//...}}class Animate{public $animate;public function __...
class UIComponent{//...public function repaint( Animate $animate ){//...}}class Animate{public $animate;public function __...
Key Benefits• Helps identify what should be an Object• Type Hinting• Encapsulation of operations
OC #4“Only one -> per line”Adapted* getter chain or a fluent interface
$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this-...
$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this-...
$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this-...
- Underlying encapsulation problem- Hard to debug and test- Hard to read and understand$this->base_url = $this->CI->config...
- Underlying encapsulation problem- Hard to debug and test- Hard to read and understand$this->base_url = $this->CI->config...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());Source: Zend Framework AppSou...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());fluent interfaceSource: Zend F...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent inter...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent inter...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent inter...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent inter...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent inter...
$filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent inter...
Key Benefits• Readability• Easier Mocking (Testing)• Easier to Debug• Demeter’s Law
OC #5“Do not Abbreviate”
if($sx >= $sy) {if ($sx > $strSysMatImgW) {$ny = $strSysMatImgW * $sy / $sx;$nx = $strSysMatImgW;}if ($ny > $strSysMatImgH...
if($sx >= $sy) {if ($sx > $strSysMatImgW) {$ny = $strSysMatImgW * $sy / $sx;$nx = $strSysMatImgW;}if ($ny > $strSysMatImgH...
Why do you abbreviate?
Why do you abbreviate?Its repeated many times,and i’m lazy.
Why do you abbreviate?Its repeated many times,and i’m lazy.Underlying Problem!You need to transfer those operations into a...
function processResponseHeadersAndDefineOutput($response) { ... }Why do you abbreviate?
This method name is too long to type,and i’m lazy.function processResponseHeadersAndDefineOutput($response) { ... }Why do ...
This method name is too long to type,and i’m lazy.function processResponseHeadersAndDefineOutput($response) { ... }more th...
function getPage($data) { ... }function startProcess() { ... }$tr->process(“site.login”);
function getPage($data) { ... }get from where?function startProcess() { ... }$tr->process(“site.login”);
Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }$t...
Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }Us...
Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }Us...
Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }Us...
Key Benefits• Clearer communication and maintainability• Indicates underlying problems
OC #6“Keep your classessmall”Adapted
200 lines per class10 methods per class15 classes per package
200 lines per class10 methods per class15 classes per packageIncreased to includedocblocks
200 lines per class10 methods per class15 classes per package15-20 lines per methodIncreased to includedocblocks
200 lines per class10 methods per class15 classes per package15-20 lines per methodIncreased to includedocblocksread this ...
Key Benefits• Single Responsibility• Objective and clear methods• Slimmer namespaces• Avoids clunky folders
OC #7“Limit the number ofinstance variables in aclass (2 to 5)”Adapted
class MyRegistrationService{protected $userService;protected $passwordService;protected $logger;protected $translator;prot...
class MyRegistrationService{protected $userService;protected $passwordService;protected $logger;protected $translator;prot...
class MyRegistrationService{protected $userService;protected $passwordService;protected $logger;protected $translator;prot...
Key Benefits• Shorter dependency list• Easier Mocking for unit test
OC #8“Use first classcollections”
$collection->getIterator();$collection->filter(...);$collection->append(...);$collection->map(...);Doctrine:ArrayCollection
Key Benefits• Implements collection operations• Uses SPL interfaces• Easier to merge collections and not worryabout member...
OC #9“Do not use getters/setters”Dropped* Use them if you code PHP
/*** THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.*/class DoctrineTestsModelsCMSCmsUserProxyextends...
/*** THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.*/class DoctrineTestsModelsCMSCmsUserProxyextends...
Key Benefits• Injector operations• Encapsulation of transformations
OC #10 (bonus!)“Document your code!”Created!
//check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)// implode the revised...
//check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)really?// implode the ...
//check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)really?// implode the ...
$priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...
$priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...
$priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...
$priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...
/*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the coll...
/*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the coll...
/*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the coll...
/*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the coll...
/*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the coll...
Key Benefits• Automatic API documentation• Transmission of “line of thought”• Avoids confusion
Recap• #1 - Only one indentation level per method.• #2 - Do not use the ‘else’ keyword.• #3 - Wrap primitive types and str...
Questions?http://slides.doh.mshttp://doh.ms@rdohmshttp://fixthatcode.comhttp://joind.in/8183
Recommended Links:http://goo.gl/OcSNxhttp://goo.gl/unrijDISCLAIMER: This talk re-uses some of the examples used by Guilher...
Upcoming SlideShare
Loading in...5
×

Your code sucks, let's fix it! - php|tek13

16,966

Published on

Published in: Technology

Transcript of "Your code sucks, let's fix it! - php|tek13"

  1. 1. Your code sucks,let’s !x it!Object Calisthenics and Code readabilityRafael Dohms@rdohms
  2. 2. photocredit:EliWhiteEvangelist, Speaker andContributor.Developer at WEBclusive.Enabler at AmsterdamPHP.Rafael Dohms@rdohms
  3. 3. photocredit:EliWhiteEvangelist, Speaker andContributor.Developer at WEBclusive.Enabler at AmsterdamPHP.Rafael Dohms@rdohms
  4. 4. Why does mycode suck?
  5. 5. Why does mycode suck?Is it Readable?
  6. 6. Why does mycode suck?Is it Readable?Is it Testable?
  7. 7. Why does mycode suck?Is it Readable?Is it Testable?Is it Maintainable?
  8. 8. Why does mycode suck?Is it Readable?Is it Testable?Is it Maintainable?Is it Reusable?
  9. 9. Does it look like this?<?php$list=mysql_connect("******","*******","*****");if(!$list)echo Cannot login.;else{mysql_select_db("******", $list);$best=array("0","0","0","0","0","0");$id=mysql_num_rows(mysql_query("SELECT * FROM allnews"));$count=0;for($i=0;$i<6;$i++){while(mysql_query("SELECT language FROM allnews WHERE id=$id-$count")!="he")$count++;$best[$i]=mysql_query("SELECT id FROM allnews WHERE id=$id-$count");}$id=$id-$count;$maxdate=mktime(0,0,0,date(m),date(d)-7,date(Y));while(mysql_query("SELECT date FROM allnews WHERE id=$id-$count")>=$maxdate){if(mysql_query("SELECT language FROM allnews WHERE id=$id-$count")=="he"){$small=$best[0];while($i=0;$i<6;$i++){if(mysql_query("SELECT score FROM allnews WHERE id=$small)"<mysql_query("SELECT score FROM allnews WHERE id=$best[i+1]"))$small=$best[i+1];}if(mysql_query("SELECT score FROM allnews WHERE id=$small")<mysql_query("SELECT score FROM allnews WHERE id=$id-$count")){while($i=0;$i<6;$i++){if($small==$best[i])$best[i]=mysql_query("SELECT id FROMallnews WHERE id=$id-$count");}}}}while($i=0;$i<6;$i++)echo <a href="news-page.php?id=.$best[i]."><div class="box .mysql_query("SELECTtype FROM allnews WHERE id=$best[i]").">.mysql_query("SELECT title FROM allnews WHERE id=$best[i]").<div class="img" style="background-image:url(images/.mysql_query("SELECTimage1 FROM allnews WHERE id=$best[i]").);"></div></div></a>;mysql_close($list);}?>
  10. 10. Does it look like this?<?php$list=mysql_connect("******","*******","*****");if(!$list)echo Cannot login.;else{mysql_select_db("******", $list);$best=array("0","0","0","0","0","0");$id=mysql_num_rows(mysql_query("SELECT * FROM allnews"));$count=0;for($i=0;$i<6;$i++){while(mysql_query("SELECT language FROM allnews WHERE id=$id-$count")!="he")$count++;$best[$i]=mysql_query("SELECT id FROM allnews WHERE id=$id-$count");}$id=$id-$count;$maxdate=mktime(0,0,0,date(m),date(d)-7,date(Y));while(mysql_query("SELECT date FROM allnews WHERE id=$id-$count")>=$maxdate){if(mysql_query("SELECT language FROM allnews WHERE id=$id-$count")=="he"){$small=$best[0];while($i=0;$i<6;$i++){if(mysql_query("SELECT score FROM allnews WHERE id=$small)"<mysql_query("SELECT score FROM allnews WHERE id=$best[i+1]"))$small=$best[i+1];}if(mysql_query("SELECT score FROM allnews WHERE id=$small")<mysql_query("SELECT score FROM allnews WHERE id=$id-$count")){while($i=0;$i<6;$i++){if($small==$best[i])$best[i]=mysql_query("SELECT id FROMallnews WHERE id=$id-$count");}}}}while($i=0;$i<6;$i++)echo <a href="news-page.php?id=.$best[i]."><div class="box .mysql_query("SELECTtype FROM allnews WHERE id=$best[i]").">.mysql_query("SELECT title FROM allnews WHERE id=$best[i]").<div class="img" style="background-image:url(images/.mysql_query("SELECTimage1 FROM allnews WHERE id=$best[i]").);"></div></div></a>;mysql_close($list);}?>If Rebecca Black was a developer
  11. 11. How do we fix it?
  12. 12. Object Calisthenics
  13. 13. Object Calisthenicscal·is·then·ics-noun-/ˌkaləsˈTHeniks/Calisthenics are a form of dynamicexercise consisting of a variety ofsimple, often rhythmical, movements,generally using minimal equipment orapparatus.
  14. 14. Object Calisthenicscal·is·then·ics-noun-/ˌkaləsˈTHeniks/Calisthenics are a form of dynamicexercise consisting of a variety ofsimple, often rhythmical, movements,generally using minimal equipment orapparatus.A variety of simple, oftenrhythmical, exercises to achievebetter OO and code quality
  15. 15. Object Calisthenics“So here’s an exercise that can help you to internalizeprinciples of good object-oriented design and actuallyuse them in real life.”-- Jeff Bay
  16. 16. Object Calisthenics“So here’s an exercise that can help you to internalizeprinciples of good object-oriented design and actuallyuse them in real life.”-- Jeff BayImportant:PHP != JAVAAdaptations will be done
  17. 17. Object Calisthenics+Readability Tips
  18. 18. Object Calisthenics+Readability Tips“You need to write code that minimizes the time it wouldtake someone else to understand it—even if thatsomeone else is you.”-- Dustin Boswell and Trevor Foucher
  19. 19. Object Calisthenics+Readability Tips“You need to write code that minimizes the time it wouldtake someone else to understand it—even if thatsomeone else is you.”-- Dustin Boswell and Trevor FoucherI’m a tip
  20. 20. Disclaimer:“These are guidelines exercises,not rules”
  21. 21. OC #1“Only one indentationlevel per method”
  22. 22. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}}return $valid;}
  23. 23. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}}return $valid;}0123
  24. 24. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}}return $valid;}0123
  25. 25. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$validationResult = validateSingleProduct($rawProduct, $requiredFields);if ( ! $validationResult){$valid = false;}}return $valid;}function validateSingleProduct($product, $requiredFields){$valid = true;$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}return $valid;}
  26. 26. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$validationResult = validateSingleProduct($rawProduct, $requiredFields);if ( ! $validationResult){$valid = false;}}return $valid;}function validateSingleProduct($product, $requiredFields){$valid = true;$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}return $valid;}whitespace
  27. 27. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$validationResult = validateSingleProduct($rawProduct, $requiredFields);if ( ! $validationResult){$valid = false;}}return $valid;}function validateSingleProduct($product, $requiredFields){$valid = true;$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}return $valid;}whitespaceduplicated logic
  28. 28. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$validationResult = validateSingleProduct($rawProduct, $requiredFields);if ( ! $validationResult){$valid = false;}}return $valid;}function validateSingleProduct($product, $requiredFields){$valid = true;$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}return $valid;}whitespaceduplicated logic012012
  29. 29. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$validationResult = validateSingleProduct($rawProduct, $requiredFields);if ( ! $validationResult){$valid = false;}}return $valid;}function validateSingleProduct($product, $requiredFields){$valid = true;$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}return $valid;}012012
  30. 30. function validateProducts($products) {// Check to make sure that our valid fields are in there$requiredFields = array(price,name,description,type,);$valid = true;foreach ($products as $rawProduct) {$validationResult = validateSingleProduct($rawProduct, $requiredFields);if ( ! $validationResult){$valid = false;}}return $valid;}function validateSingleProduct($product, $requiredFields){$valid = true;$fields = array_keys($rawProduct);foreach ($requiredFields as $requiredField) {if (!in_array($requiredField, $fields)) {$valid = false;}}return $valid;}012012
  31. 31. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}
  32. 32. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}I see cheating!
  33. 33. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}I see cheating!Single line IF, simple operations
  34. 34. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}I see cheating!Single line IF, simple operations
  35. 35. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}return earlySingle line IF, simple operations
  36. 36. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}return earlySingle line IF, simple operationsC (native) functions arefaster then PHP
  37. 37. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}
  38. 38. function validateProducts($storeData) {$requiredFields = array(price,name,description,type);foreach ($storeData[products] as $rawProduct) {if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false;}return true;}function validateSingleProduct($product, $requiredFields){$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}
  39. 39. function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) == count($validProducts));}function isValidProduct($rawProduct){$requiredFields = array(price, name, description, type);$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}
  40. 40. function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) == count($validProducts));}function isValidProduct($rawProduct){$requiredFields = array(price, name, description, type);$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}faster iteration
  41. 41. function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) == count($validProducts));}function isValidProduct($rawProduct){$requiredFields = array(price, name, description, type);$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}faster iterationreusable method
  42. 42. function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) == count($validProducts));}function isValidProduct($rawProduct){$requiredFields = array(price, name, description, type);$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}faster iterationreusable methodmethod name matches “true” result
  43. 43. function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) == count($validProducts));}function isValidProduct($rawProduct){$requiredFields = array(price, name, description, type);$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}faster iterationreusable methodmethod name matches “true” resultassertable return: expected/returned
  44. 44. function validateProductList($products){$validProducts = array_filter($products, isValidProduct);return (count($products) == count($validProducts));}function isValidProduct($rawProduct){$requiredFields = array(price, name, description, type);$fields = array_keys($rawProduct);$missingFields = array_diff($requiredFields, $fields);return (count($missingFields) == 0);}faster iterationreusable methodmethod name matches “true” resultassertable return: expected/returnedList is more readable the plural
  45. 45. Key Benefits• Single Responsibility Principle (S in SOLID)• Increases re-use
  46. 46. OC #2“Do not use the ‘else’keyword”
  47. 47. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  48. 48. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  49. 49. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  50. 50. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  51. 51. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  52. 52. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  53. 53. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}
  54. 54. public function createPost($request){$entity = new Post();$form = new MyForm($entity);$form->bind($request);if ($form->isValid()){$repository = $this->getRepository(MyBundle:Post);if (!$repository->exists($entity) ) {$repository->save($entity);return $this->redirect(create_ok);} else {$error = "Post Title already exists";return array(form => $form, error => $error);}} else {$error = "Invalid fields";return array(form => $form, error => $error);}}intermediate variableintermediate variable
  55. 55. public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new MyForm($entity);$form->bind($request);if ( ! $form->isValid()){return array(form => $form, error => Invalid fields);}if ($repository->exists($entity)){return array(form => $form, error => Duplicate post title);}$repository->save($entity);return $this->redirect(create_ok);}
  56. 56. public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new MyForm($entity);$form->bind($request);if ( ! $form->isValid()){return array(form => $form, error => Invalid fields);}if ($repository->exists($entity)){return array(form => $form, error => Duplicate post title);}$repository->save($entity);return $this->redirect(create_ok);}
  57. 57. public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new MyForm($entity);$form->bind($request);if ( ! $form->isValid()){return array(form => $form, error => Invalid fields);}if ($repository->exists($entity)){return array(form => $form, error => Duplicate post title);}$repository->save($entity);return $this->redirect(create_ok);}removed intermediates
  58. 58. public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new MyForm($entity);$form->bind($request);if ( ! $form->isValid()){return array(form => $form, error => Invalid fields);}if ($repository->exists($entity)){return array(form => $form, error => Duplicate post title);}$repository->save($entity);return $this->redirect(create_ok);}removed intermediatesearly return
  59. 59. public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new MyForm($entity);$form->bind($request);if ( ! $form->isValid()){return array(form => $form, error => Invalid fields);}if ($repository->exists($entity)){return array(form => $form, error => Duplicate post title);}$repository->save($entity);return $this->redirect(create_ok);}removed intermediatesearly returnAlternate solution:Use Exceptions
  60. 60. public function createPost($request){$entity = new Post();$repository = $this->getRepository(MyBundle:Post);$form = new MyForm($entity);$form->bind($request);if ( ! $form->isValid()){return array(form => $form, error => Invalid fields);}if ($repository->exists($entity)){return array(form => $form, error => Duplicate post title);}$repository->save($entity);return $this->redirect(create_ok);}Separate codeinto blocks.Its like usingParagraphs.removed intermediatesearly returnAlternate solution:Use Exceptions
  61. 61. Key Benefits• Helps avoid code duplication• Easier to read (single true path)• Reduces cyclomatic complexity
  62. 62. OC #3“Wrap primitive typesand strings”Adapted* if there is behavior
  63. 63. //...$component->repaint(false);
  64. 64. //...$component->repaint(false);
  65. 65. unclear operation//...$component->repaint(false);
  66. 66. class UIComponent{//...public function repaint($animate = true){//...}}unclear operation//...$component->repaint(false);
  67. 67. class UIComponent{//...public function repaint( Animate $animate ){//...}}class Animate{public $animate;public function __construct( $animate = true ) {$this->animate = $animate;}}//...$component->repaint( new Animate(false) );
  68. 68. class UIComponent{//...public function repaint( Animate $animate ){//...}}class Animate{public $animate;public function __construct( $animate = true ) {$this->animate = $animate;}}//...$component->repaint( new Animate(false) );This can now encapsulate allanimation related operations
  69. 69. Key Benefits• Helps identify what should be an Object• Type Hinting• Encapsulation of operations
  70. 70. OC #4“Only one -> per line”Adapted* getter chain or a fluent interface
  71. 71. $this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading);Source: CodeIgniter
  72. 72. $this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading);properties are harder to mockSource: CodeIgniter
  73. 73. $this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading);properties are harder to mockno whitespaceSource: CodeIgniter
  74. 74. - Underlying encapsulation problem- Hard to debug and test- Hard to read and understand$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading);properties are harder to mockno whitespaceSource: CodeIgniter
  75. 75. - Underlying encapsulation problem- Hard to debug and test- Hard to read and understand$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both);$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading);properties are harder to mockno whitespacemove everything to uri object$this->getCI()->getUriBuilder()->getBaseUri(‘leading’);Source: CodeIgniter
  76. 76. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());Source: Zend Framework AppSource: Symfony 2 Docs.
  77. 77. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());fluent interfaceSource: Zend Framework AppSource: Symfony 2 Docs.
  78. 78. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent interfaceSource: Zend Framework AppSource: Symfony 2 Docs.
  79. 79. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent interface$user = $this->get(security.context)->getToken()->getUser();Source: Zend Framework AppSource: Symfony 2 Docs.
  80. 80. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent interface$user = $this->get(security.context)->getToken()->getUser();only getters (no operations)Source: Zend Framework AppSource: Symfony 2 Docs.
  81. 81. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent interface$user = $this->get(security.context)->getToken()->getUser();only getters (no operations)Source: Zend Framework AppSource: Symfony 2 Docs.
  82. 82. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent interface$user = $this->get(security.context)->getToken()->getUser();only getters (no operations)where did myautocomplete go?Source: Zend Framework AppSource: Symfony 2 Docs.
  83. 83. $filterChain->addFilter(new Zend_Filter_Alpha())->addFilter(new Zend_Filter_StringToLower());operator alignmentfluent interface$user = $this->get(security.context)->getToken()->getUser();only getters (no operations)return null?where did myautocomplete go?Source: Zend Framework AppSource: Symfony 2 Docs.
  84. 84. Key Benefits• Readability• Easier Mocking (Testing)• Easier to Debug• Demeter’s Law
  85. 85. OC #5“Do not Abbreviate”
  86. 86. if($sx >= $sy) {if ($sx > $strSysMatImgW) {$ny = $strSysMatImgW * $sy / $sx;$nx = $strSysMatImgW;}if ($ny > $strSysMatImgH) {$nx = $strSysMatImgH * $sx / $sy;$ny = $strSysMatImgH;}} else {if ($sy > $strSysMatImgH) {$nx = $strSysMatImgH * $sx / $sy;$ny = $strSysMatImgH;}if($nx > $strSysMatImgW) {$ny = $strSysMatImgW * $sy / $sx;$nx = $strSysMatImgW;}}
  87. 87. if($sx >= $sy) {if ($sx > $strSysMatImgW) {$ny = $strSysMatImgW * $sy / $sx;$nx = $strSysMatImgW;}if ($ny > $strSysMatImgH) {$nx = $strSysMatImgH * $sx / $sy;$ny = $strSysMatImgH;}} else {if ($sy > $strSysMatImgH) {$nx = $strSysMatImgH * $sx / $sy;$ny = $strSysMatImgH;}if($nx > $strSysMatImgW) {$ny = $strSysMatImgW * $sy / $sx;$nx = $strSysMatImgW;}}?????
  88. 88. Why do you abbreviate?
  89. 89. Why do you abbreviate?Its repeated many times,and i’m lazy.
  90. 90. Why do you abbreviate?Its repeated many times,and i’m lazy.Underlying Problem!You need to transfer those operations into a separate class.
  91. 91. function processResponseHeadersAndDefineOutput($response) { ... }Why do you abbreviate?
  92. 92. This method name is too long to type,and i’m lazy.function processResponseHeadersAndDefineOutput($response) { ... }Why do you abbreviate?
  93. 93. This method name is too long to type,and i’m lazy.function processResponseHeadersAndDefineOutput($response) { ... }more than oneresponsibility?Why do you abbreviate?
  94. 94. function getPage($data) { ... }function startProcess() { ... }$tr->process(“site.login”);
  95. 95. function getPage($data) { ... }get from where?function startProcess() { ... }$tr->process(“site.login”);
  96. 96. Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }$tr->process(“site.login”);
  97. 97. Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }Use a thesaurus:fork, create, begin, open$tr->process(“site.login”);
  98. 98. Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }Use a thesaurus:fork, create, begin, open$tr->process(“site.login”);Table row?
  99. 99. Use clearer names:fetchPage()downloadPage()function getPage($data) { ... }get from where?function startProcess() { ... }Use a thesaurus:fork, create, begin, open$tr->process(“site.login”);Easy understanding, complete scope:$translatorServiceTable row?
  100. 100. Key Benefits• Clearer communication and maintainability• Indicates underlying problems
  101. 101. OC #6“Keep your classessmall”Adapted
  102. 102. 200 lines per class10 methods per class15 classes per package
  103. 103. 200 lines per class10 methods per class15 classes per packageIncreased to includedocblocks
  104. 104. 200 lines per class10 methods per class15 classes per package15-20 lines per methodIncreased to includedocblocks
  105. 105. 200 lines per class10 methods per class15 classes per package15-20 lines per methodIncreased to includedocblocksread this asnamespace or folder
  106. 106. Key Benefits• Single Responsibility• Objective and clear methods• Slimmer namespaces• Avoids clunky folders
  107. 107. OC #7“Limit the number ofinstance variables in aclass (2 to 5)”Adapted
  108. 108. class MyRegistrationService{protected $userService;protected $passwordService;protected $logger;protected $translator;protected $entityManager;protected $imageCropper;// ...}
  109. 109. class MyRegistrationService{protected $userService;protected $passwordService;protected $logger;protected $translator;protected $entityManager;protected $imageCropper;// ...}Limit: 5
  110. 110. class MyRegistrationService{protected $userService;protected $passwordService;protected $logger;protected $translator;protected $entityManager;protected $imageCropper;// ...}Limit: 5Use an event basedsystem and move thisto listenerAll DB interactionshould be inuserService
  111. 111. Key Benefits• Shorter dependency list• Easier Mocking for unit test
  112. 112. OC #8“Use first classcollections”
  113. 113. $collection->getIterator();$collection->filter(...);$collection->append(...);$collection->map(...);Doctrine:ArrayCollection
  114. 114. Key Benefits• Implements collection operations• Uses SPL interfaces• Easier to merge collections and not worryabout member behavior in them
  115. 115. OC #9“Do not use getters/setters”Dropped* Use them if you code PHP
  116. 116. /*** THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.*/class DoctrineTestsModelsCMSCmsUserProxyextends DoctrineTestsModelsCMSCmsUserimplements DoctrineORMProxyProxy{public function getId(){$this->__load();return parent::getId();}public function getStatus(){$this->__load();return parent::getStatus();}
  117. 117. /*** THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.*/class DoctrineTestsModelsCMSCmsUserProxyextends DoctrineTestsModelsCMSCmsUserimplements DoctrineORMProxyProxy{public function getId(){$this->__load();return parent::getId();}public function getStatus(){$this->__load();return parent::getStatus();}Example: Doctrine uses getters toinject lazy loading operations
  118. 118. Key Benefits• Injector operations• Encapsulation of transformations
  119. 119. OC #10 (bonus!)“Document your code!”Created!
  120. 120. //check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)// implode the revised array of selections in group three into a string// variable so that it can be transferred to the database at the end of the// page$groupthree = implode($groupthree_array, "nr");
  121. 121. //check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)really?// implode the revised array of selections in group three into a string// variable so that it can be transferred to the database at the end of the// page$groupthree = implode($groupthree_array, "nr");
  122. 122. //check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)really?// implode the revised array of selections in group three into a string// variable so that it can be transferred to the database at the end of the// page$groupthree = implode($groupthree_array, "nr");Documenting because i’m doing it wrong in an unusual way
  123. 123. $priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...));}if (!isset($event[method])) {$event[method] = on.preg_replace(array(/(?<=b)[a-z]/ie,/[^a-z0-9]/i), array(strtoupper("0"), ), $event[event]);}$definition->addMethodCall(addListenerService,array($event[event],array($listenerId,$event[method]),$priority));Source: Symfony2
  124. 124. $priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...));}if (!isset($event[method])) {$event[method] = on.preg_replace(array(/(?<=b)[a-z]/ie,/[^a-z0-9]/i), array(strtoupper("0"), ), $event[event]);}$definition->addMethodCall(addListenerService,array($event[event],array($listenerId,$event[method]),$priority));What does this do?Source: Symfony2
  125. 125. $priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...));}if (!isset($event[method])) {$event[method] = on.preg_replace(array(/(?<=b)[a-z]/ie,/[^a-z0-9]/i), array(strtoupper("0"), ), $event[event]);}$definition->addMethodCall(addListenerService,array($event[event],array($listenerId,$event[method]),$priority));What does this do?Add a simple comment://Strips special chars and camel cases to onXxxSource: Symfony2
  126. 126. $priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {throw new InvalidArgumentException(...));}if (!isset($event[method])) {$event[method] = on.preg_replace(array(/(?<=b)[a-z]/ie,/[^a-z0-9]/i), array(strtoupper("0"), ), $event[event]);}$definition->addMethodCall(addListenerService,array($event[event],array($listenerId,$event[method]),$priority));What does this do?Add a simple comment://Strips special chars and camel cases to onXxxSource: Symfony2Don’t explain badcode, fix it!
  127. 127. /*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the collection.** @todo implement caching for better performance* @param mixed $element The element to search for.* @return boolean TRUE if the collection contains the element, or FALSE.*/function contains($element);
  128. 128. /*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the collection.** @todo implement caching for better performance* @param mixed $element The element to search for.* @return boolean TRUE if the collection contains the element, or FALSE.*/function contains($element);mark todo items so thechanges don’t get lost
  129. 129. /*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the collection.** @todo implement caching for better performance* @param mixed $element The element to search for.* @return boolean TRUE if the collection contains the element, or FALSE.*/function contains($element);mark todo items so thechanges don’t get lostA note on cost ofrunning function
  130. 130. /*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the collection.** @todo implement caching for better performance* @param mixed $element The element to search for.* @return boolean TRUE if the collection contains the element, or FALSE.*/function contains($element);mark todo items so thechanges don’t get lostA note on cost ofrunning functionDo a mind dump,then clean it up.
  131. 131. /*** Checks whether an element is contained in the collection.* This is an O(n) operation, where n is the size of the collection.** @todo implement caching for better performance* @param mixed $element The element to search for.* @return boolean TRUE if the collection contains the element, or FALSE.*/function contains($element);mark todo items so thechanges don’t get lostA note on cost ofrunning functionDo a mind dump,then clean it up.Generate API docswith phpDocumentor
  132. 132. Key Benefits• Automatic API documentation• Transmission of “line of thought”• Avoids confusion
  133. 133. Recap• #1 - Only one indentation level per method.• #2 - Do not use the ‘else’ keyword.• #3 - Wrap primitive types and string, if it has behavior.• #4 - Only one -> per line, if not getter or fluent.• #5 - Do not Abbreviate.• #6 - Keep your classes small• #7 - Limit the number of instance variables in a class (max: 5)• #8 - Use first class collections• #9 - Use getter/setter• #10 - Document your code!
  134. 134. Questions?http://slides.doh.mshttp://doh.ms@rdohmshttp://fixthatcode.comhttp://joind.in/8183
  135. 135. Recommended Links:http://goo.gl/OcSNxhttp://goo.gl/unrijDISCLAIMER: This talk re-uses some of the examples used by Guilherme Blanco in hisoriginal Object Calisthenic talk. These principles were studied and applied by us while weworked together in previous jobs. The result taught us all a lesson we really want to spreadto other developers.The ThoughtWorks AnthologyThe Art of Readable Code
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×