0
Your code sucks,   let’s !x it!   Object Calisthenics and Code readability            Rafael Dohms               @rdohms
Rafael Dohms                           photo credit: Eli White        @rdohms Evangelist, Speaker and      Contributor.Dev...
Why does mycode suck?
Is it Readable?Why does mycode suck?
Is it Readable?Why does mycode suck?        Is it Testable?
Is it Maintainable?   Is it Readable?           Why does my           code suck?                      Is it Testable?
Is it Maintainable?   Is it Readable?           Why does my           code suck?  Is it Reusable?     Is it Testable?
<?php                                                 Does it look like this?$list=mysql_connect("******","*******","*****...
<?php                                                 Does it look like this?$list=mysql_connect("******","*******","*****...
How do we fix it?
Object Calisthenics
cal·is·then·ics - noun - /ˌkaləsˈTHeniks/     Calisthenics are a form of dynamic      exercise consisting of a variety of ...
cal·is·then·ics - noun - /ˌkaləsˈTHeniks/     Calisthenics are a form of dynamic      exercise consisting of a variety of ...
“So here’s an exercise that can help you to internalize      principles of good object-oriented design and actually       ...
“So here’s an exercise that can help you to internalize      principles of good object-oriented design and actually       ...
Object Calisthenics         + Readability Tips
“You need to write code that minimizes the time it wouldObject Calisthenics          take someone else to understand it—ev...
“You need to write code that minimizes the time it wouldObject Calisthenics          take someone else to understand it—ev...
Disclaimer:“These are guidelines, not rules”
OC #1“Only one indentation  level per method”
function validateProducts($products) {    // Check to make sure that our valid fields are in there    $requiredFields = ar...
function validateProducts($products) {        // Check to make sure that our valid fields are in there        $requiredFie...
function validateProducts($products) {        // Check to make sure that our valid fields are in there        $requiredFie...
function validateProducts($products) {    // Check to make sure that our valid fields are in there    $requiredFields = ar...
function validateProducts($products) {    // Check to make sure that our valid fields are in there    $requiredFields = ar...
function validateProducts($products) {    // Check to make sure that our valid fields are in there    $requiredFields = ar...
function validateProducts($products) {      // Check to make sure that our valid fields are in there      $requiredFields ...
function validateProducts($products) {      // Check to make sure that our valid fields are in there      $requiredFields ...
function validateProducts($products) {      // Check to make sure that our valid fields are in there      $requiredFields ...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type);    foreach ($storeData[pr...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type); cheating!                ...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type); cheating!                ...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type); cheating!                ...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type);    foreach ($storeData[pr...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type);    foreach ($storeData[pr...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type);    foreach ($storeData[pr...
function validateProducts($storeData) {    $requiredFields = array(price,name,description,type);    foreach ($storeData[pr...
function validateProductList($products){    $validProducts = array_filter($products, isValidProduct);    return (count($pr...
function validateProductList($products)      faster iteration{    $validProducts = array_filter($products, isValidProduct)...
function validateProductList($products)      faster iteration{    $validProducts = array_filter($products, isValidProduct)...
function validateProductList($products)      faster iteration{    $validProducts = array_filter($products, isValidProduct)...
function validateProductList($products)      faster iteration{    $validProducts = array_filter($products, isValidProduct)...
List is more readable the pluralfunction validateProductList($products)      faster iteration{    $validProducts = array_f...
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);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity = new Post();    $form = new MyForm($entity);    $form->bind($request);  ...
public function createPost($request){    $entity     = new Post();    $repository = $this->getRepository(MyBundle:Post);  ...
public function createPost($request){    $entity     = new Post();    $repository = $this->getRepository(MyBundle:Post);  ...
public function createPost($request){    $entity     = new Post();    $repository = $this->getRepository(MyBundle:Post);  ...
public function createPost($request){    $entity     = new Post();    $repository = $this->getRepository(MyBundle:Post);  ...
public function createPost($request){    $entity     = new Post();    $repository = $this->getRepository(MyBundle:Post);  ...
Separate code                                                              into blocks.public function createPost($request...
Key Benefits• Helps avoid code duplication• Easier to read (single true path)• Reduces cyclomatic complexity
Ad                           ap                           te                            d       OC #3“Wrap primitive types...
//...$component->repaint(false);
//...$component->repaint(false);
//...$component->repaint(false);                  unclear operation
//...$component->repaint(false);                  unclear operationclass UIComponent{//...    public function repaint($ani...
class UIComponent{    //...    public function repaint( Animate $animate ){            //...    }}class Animate{    public...
class UIComponent{    //...    public function repaint( Animate $animate ){            //...    }}class Animate           ...
Key Benefits• Helps identify what should be an Object• Type Hinting• Encapsulation of operations
Ad                              ap                                te                                  d          OC #4   “...
Source: CodeIgniter$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segm...
Source: CodeIgniter                         properties are harder to mock$this->base_url = $this->CI->config->site_url()./...
Source: CodeIgniter                         properties are harder to mock$this->base_url = $this->CI->config->site_url()./...
Source: CodeIgniter                         properties are harder to mock$this->base_url = $this->CI->config->site_url()./...
Source: CodeIgniter                         properties are harder to mock$this->base_url = $this->CI->config->site_url()./...
Source: Zend Framework App$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Zend_Filter_StringTo...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
Source: Zend Framework App    fluent interface$filterChain->addFilter(new Zend_Filter_Alpha())            ->addFilter(new Z...
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($sx >= $sy) {                      ?    if ($sx > $strSysMatImgW) {        $ny = $strSysMatImgW * $sy / $sx;        $n...
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 t...
Why do you abbreviate?function processResponseHeadersAndDefineOutput($response) { ... }
Why do you abbreviate?function processResponseHeadersAndDefineOutput($response) { ... }      This method name is too long ...
Why do you abbreviate?                          more than one                          responsibility?function processResp...
function getPage($data) { ... }function startProcess() { ... }$tr->process(“site.login”);
get from where?function getPage($data) { ... }function startProcess() { ... }$tr->process(“site.login”);
get from where?                                  Use clearer names:function getPage($data) { ... }   fetchPage()          ...
get from where?                                  Use clearer names:function getPage($data) { ... }   fetchPage()          ...
get from where?                                  Use clearer names:function getPage($data) { ... }   fetchPage()          ...
get from where?                                  Use clearer names:function getPage($data) { ... }   fetchPage()          ...
Key Benefits• Clearer communication and maintainability• Indicates underlying problems
Ad                 ap                     te                     d     OC #6“Keep your classes     small”
200 lines per class 10 methods per class15 classes per package
Increased to include    docblocks  200 lines per class 10 methods per class15 classes per package
Increased to include    docblocks          15-20 lines per method  200 lines per class 10 methods per class15 classes per ...
Increased to include    docblocks             15-20 lines per method  200 lines per class 10 methods per class15 classes p...
Key Benefits• Single Responsibility• Objective and clear methods• Slimmer namespaces• Avoids clunky folders
Ad                     ap         OC #7                      te                          d “Limit the number ofinstance va...
class MyRegistrationService{    protected   $userService;    protected   $passwordService;    protected   $logger;    prot...
class MyRegistrationService{    protected   $userService;    protected   $passwordService;    protected   $logger;    prot...
class MyRegistrationService                     {                         protected   $userService;                       ...
Key Benefits• Shorter dependency list• Easier Mocking for unit test
OC #8“Use first class collections”
Doctrine:      ArrayCollection$collection->getIterator();$collection->filter(...);$collection->append(...);$collection->ma...
Key Benefits• Implements collection operations• Uses SPL interfaces• Easier to merge collections and not worry  about memb...
Dr                       op                         pe                             d       OC #9 “Do not use getters/     ...
/**  * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.  */class DoctrineTestsModelsCMSCmsUserProxy   ...
/**  * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.  */class DoctrineTestsModelsCMSCmsUserProxy   ...
Key Benefits• Injector operations• Encapsulation of transformations
Cr                   ea                    te                        d!   OC #10 (bonus!)“Document your code!”
//check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)// implode the revised...
really?//check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)// implode the ...
really?//check to see if the section above set the $overall_pref variable to voidif ($overall_pref == void)// implode the ...
$priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {    throw new InvalidArgumentExcept...
$priority = isset($event[priority]) ? $event[priority] : 0;if (!isset($event[event])) {    throw new InvalidArgumentExcept...
$priority = isset($event[priority]) ? $event[priority] : 0;                            Add a simple comment:if   (!isset($...
$priority = isset($event[priority]) ? $event[priority] : 0;                            Add a simple comment:if   (!isset($...
/*** 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...
A note on cost of       running function/*** Checks whether an element is contained in the collection.* This is an O(n) op...
Do a mind dump,                                                       then clean it up.      A note on cost of       runni...
Do a mind dump,                                                       then clean it up.      A note on cost of       runni...
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 a...
Questions?                          http://fixthatcode.com@rdohmshttp://doh.ms                       http://joind.in/7941ht...
Recommended Links:                    The ThoughtWorks Anthology                    http://goo.gl/OcSNx                   ...
Upcoming SlideShare
Loading in...5
×

Your code sucks, let's fix it - PHP Master Series 2012

15,296

Published on

Performance and testing are just one aspect of code, to really be successful your code needs to be readable, maintainable and generally easier to comprehend and work with. This talk draws from my own experience in applying the techniques of object calisthenics and code readability, within an existing team. It will help you identify trouble areas, learn how to refactor them and train you to write better code in future projects avoiding common pitfalls.

Published in: Technology

Transcript of "Your code sucks, let's fix it - PHP Master Series 2012"

  1. 1. Your code sucks, let’s !x it! Object Calisthenics and Code readability Rafael Dohms @rdohms
  2. 2. Rafael Dohms photo credit: Eli White @rdohms Evangelist, Speaker and Contributor.Developer at WEBclusive.Enabler at AmsterdamPHP.
  3. 3. Why does mycode suck?
  4. 4. Is it Readable?Why does mycode suck?
  5. 5. Is it Readable?Why does mycode suck? Is it Testable?
  6. 6. Is it Maintainable? Is it Readable? Why does my code suck? Is it Testable?
  7. 7. Is it Maintainable? Is it Readable? Why does my code suck? Is it Reusable? Is it Testable?
  8. 8. <?php Does it look like this?$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);}?>
  9. 9. <?php Does it look like this?$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 Rebecca WHERE id=$id-$count")){ If allnews Black was a developer 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. How do we fix it?
  11. 11. Object Calisthenics
  12. 12. cal·is·then·ics - noun - /ˌkaləsˈTHeniks/ Calisthenics are a form of dynamic exercise consisting of a variety of simple, often rhythmical, movements, generally using minimal equipment or apparatus.Object Calisthenics
  13. 13. cal·is·then·ics - noun - /ˌkaləsˈTHeniks/ Calisthenics are a form of dynamic exercise consisting of a variety of simple, often rhythmical, movements, generally using minimal equipment or apparatus.Object Calisthenics A variety of simple, often rhythmical, exercises to achieve better OO and code quality
  14. 14. “So here’s an exercise that can help you to internalize principles of good object-oriented design and actually use them in real life.” -- Jeff BayObject Calisthenics
  15. 15. “So here’s an exercise that can help you to internalize principles of good object-oriented design and actually use them in real life.” -- Jeff BayObject Calisthenics Important: PHP != JAVA Adaptations will be done
  16. 16. Object Calisthenics + Readability Tips
  17. 17. “You need to write code that minimizes the time it wouldObject Calisthenics take someone else to understand it—even if that someone else is you.” + -- Dustin Boswell and Trevor Foucher Readability Tips
  18. 18. “You need to write code that minimizes the time it wouldObject Calisthenics take someone else to understand it—even if that someone else is you.” + -- Dustin Boswell and Trevor Foucher Readability Tips I’m a tip
  19. 19. Disclaimer:“These are guidelines, not rules”
  20. 20. OC #1“Only one indentation level per method”
  21. 21. 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;}
  22. 22. function validateProducts($products) { // Check to make sure that our valid fields are in there $requiredFields = array( price, name, description, type, ); $valid = true; 0 foreach ($products as $rawProduct) { 1 $fields = array_keys($rawProduct); foreach ($requiredFields as $requiredField) { 2 if (!in_array($requiredField, $fields)) { 3 $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; 0 foreach ($products as $rawProduct) { 1 $fields = array_keys($rawProduct); foreach ($requiredFields as $requiredField) { 2 if (!in_array($requiredField, $fields)) { 3 $valid = false; } } } return $valid;}
  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) { $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;}
  25. 25. function validateProducts($products) { // Check to make sure that our valid fields are in there $requiredFields = array( price, name, description, type, ); $valid = true; whitespace 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; whitespace foreach ($products as $rawProduct) { $validationResult = validateSingleProduct($rawProduct, $requiredFields); if ( ! $validationResult){ $valid = false; } } return $valid;}function validateSingleProduct($product, $requiredFields){ $valid = true; duplicated logic $fields = array_keys($rawProduct); foreach ($requiredFields as $requiredField) { if (!in_array($requiredField, $fields)) { $valid = false; } } return $valid;}
  27. 27. function validateProducts($products) { // Check to make sure that our valid fields are in there $requiredFields = array( price, name, description, type, ); $valid = true; 0 foreach ($products as whitespace $validationResult $rawProduct) { = validateSingleProduct($rawProduct, $requiredFields); 1 if ( ! $validationResult){ } 2 $valid = false; } return $valid;}function validateSingleProduct($product, $requiredFields){ $valid = true; duplicated logic $fields = array_keys($rawProduct); 0 foreach(!in_array($requiredField, $fields)) ($requiredFields as $requiredField) { 1 if { } 2 $valid = false; } return $valid;}
  28. 28. function validateProducts($products) { // Check to make sure that our valid fields are in there $requiredFields = array( price, name, description, type, ); $valid = true; 0 foreach ($products as $validationResult $rawProduct) { = validateSingleProduct($rawProduct, $requiredFields); 1 if ( ! $validationResult){ } 2 $valid = false; } return $valid;}function validateSingleProduct($product, $requiredFields){ $valid = true; $fields = array_keys($rawProduct); 0 foreach(!in_array($requiredField, $fields)) ($requiredFields as $requiredField) { 1 if { } 2 $valid = false; } return $valid;}
  29. 29. function validateProducts($products) { // Check to make sure that our valid fields are in there $requiredFields = array( price, name, description, type, ); $valid = true; 0 foreach ($products as $validationResult $rawProduct) { = validateSingleProduct($rawProduct, $requiredFields); 1 if ( ! $validationResult){ } 2 $valid = false; } return $valid;}function validateSingleProduct($product, $requiredFields){ $valid = true; $fields = array_keys($rawProduct); 0 foreach(!in_array($requiredField, $fields)) ($requiredFields as $requiredField) { 1 if { } 2 $valid = false; } return $valid;}
  30. 30. 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);}
  31. 31. function validateProducts($storeData) { $requiredFields = array(price,name,description,type); cheating! I see 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); cheating! I see foreach ($storeData[products] as $rawProduct) { if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false; } return true; Single line IF, simple operations}function validateSingleProduct($product, $requiredFields){ $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);}
  33. 33. function validateProducts($storeData) { $requiredFields = array(price,name,description,type); cheating! I see foreach ($storeData[products] as $rawProduct) { if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false; } return true; Single line IF, simple operations}function validateSingleProduct($product, $requiredFields){ $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);}
  34. 34. function validateProducts($storeData) { $requiredFields = array(price,name,description,type); foreach ($storeData[products] as $rawProduct) { if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false; } return true; Single line IF, simple operations return early}function validateSingleProduct($product, $requiredFields){ $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);}
  35. 35. function validateProducts($storeData) { $requiredFields = array(price,name,description,type); foreach ($storeData[products] as $rawProduct) { if ( ! validateSingleProduct($rawProduct, $requiredFields)) return false; } return true; Single line IF, simple operations return early}function validateSingleProduct($product, $requiredFields){ $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);} C (native) functions are faster then PHP
  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);}
  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 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);}
  39. 39. function validateProductList($products) faster iteration{ $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) faster iteration{ $validProducts = array_filter($products, isValidProduct); return (count($products) == count($validProducts));} reusable methodfunction isValidProduct($rawProduct){ $requiredFields = array(price, name, description, type); $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);}
  41. 41. function validateProductList($products) faster iteration{ $validProducts = array_filter($products, isValidProduct); return (count($products) == count($validProducts));} reusable methodfunction isValidProduct($rawProduct){ $requiredFields = array(price, name, description, type); $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);} method name matches “true” result
  42. 42. function validateProductList($products) faster iteration{ $validProducts = array_filter($products, isValidProduct); return (count($products) == count($validProducts));} assertable return: expected/returned reusable methodfunction isValidProduct($rawProduct){ $requiredFields = array(price, name, description, type); $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);} method name matches “true” result
  43. 43. List is more readable the pluralfunction validateProductList($products) faster iteration{ $validProducts = array_filter($products, isValidProduct); return (count($products) == count($validProducts));} assertable return: expected/returned reusable methodfunction isValidProduct($rawProduct){ $requiredFields = array(price, name, description, type); $fields = array_keys($rawProduct); $missingFields = array_diff($requiredFields, $fields); return (count($missingFields) == 0);} method name matches “true” result
  44. 44. Key Benefits• Single Responsibility Principle (S in SOLID)• Increases re-use
  45. 45. OC #2“Do not use the ‘else’ keyword”
  46. 46. 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); }}
  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); intermediate variable return $this->redirect(create_ok); } else { $error = "Post Title already exists"; return array(form => $form, error => $error); } intermediate variable } else { $error = "Invalid fields"; return array(form => $form, error => $error); }}
  54. 54. 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);}
  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); removed intermediates 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); removed intermediates if ( ! $form->isValid()){ return array(form => $form, error => Invalid fields); } early return if ($repository->exists($entity)){ return array(form => $form, error => Duplicate post title); } $repository->save($entity); return $this->redirect(create_ok);}
  58. 58. public function createPost($request){ $entity = new Post(); $repository = $this->getRepository(MyBundle:Post); $form = new MyForm($entity); $form->bind($request); removed intermediates if ( ! $form->isValid()){ return array(form => $form, error => Invalid fields); } early return if ($repository->exists($entity)){ return array(form => $form, error => Duplicate post title); } $repository->save($entity); Alternate solution: return $this->redirect(create_ok); Use Exceptions}
  59. 59. Separate code into blocks.public function createPost($request){ Its like using $entity = new Post(); $repository = $this->getRepository(MyBundle:Post); Paragraphs. $form = new MyForm($entity); $form->bind($request); removed intermediates if ( ! $form->isValid()){ return array(form => $form, error => Invalid fields); } early return if ($repository->exists($entity)){ return array(form => $form, error => Duplicate post title); } $repository->save($entity); Alternate solution: return $this->redirect(create_ok); Use Exceptions}
  60. 60. Key Benefits• Helps avoid code duplication• Easier to read (single true path)• Reduces cyclomatic complexity
  61. 61. Ad ap te d OC #3“Wrap primitive types and strings” * if there is behavior
  62. 62. //...$component->repaint(false);
  63. 63. //...$component->repaint(false);
  64. 64. //...$component->repaint(false); unclear operation
  65. 65. //...$component->repaint(false); unclear operationclass UIComponent{//... public function repaint($animate = true){ //... }}
  66. 66. class UIComponent{ //... public function repaint( Animate $animate ){ //... }}class Animate{ public $animate; public function __construct( $animate = true ) { $this->animate = $animate;}}//...$component->repaint( new Animate(false) );
  67. 67. class UIComponent{ //... public function repaint( Animate $animate ){ //... }}class Animate This can now encapsulate all{ animation related operations public $animate; public function __construct( $animate = true ) { $this->animate = $animate;}}//...$component->repaint( new Animate(false) );
  68. 68. Key Benefits• Helps identify what should be an Object• Type Hinting• Encapsulation of operations
  69. 69. Ad ap te d OC #4 “Only one -> per line”* getter chain or a fluent interface
  70. 70. Source: CodeIgniter$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);
  71. 71. Source: CodeIgniter properties are harder to mock$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);
  72. 72. Source: CodeIgniter properties are harder to mock$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both); no whitespace$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading);
  73. 73. Source: CodeIgniter properties are harder to mock$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both); no whitespace$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading); - Underlying encapsulation problem - Hard to debug and test - Hard to read and understand
  74. 74. Source: CodeIgniter properties are harder to mock$this->base_url = $this->CI->config->site_url()./.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, both); no whitespace$this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, leading); move everything to uri object $this->getCI()->getUriBuilder()->getBaseUri(‘leading’); - Underlying encapsulation problem - Hard to debug and test - Hard to read and understand
  75. 75. Source: Zend Framework App$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); Source: Symfony 2 Docs.
  76. 76. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); Source: Symfony 2 Docs.
  77. 77. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); operator alignment Source: Symfony 2 Docs.
  78. 78. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); operator alignment $user = $this->get(security.context)->getToken()->getUser(); Source: Symfony 2 Docs.
  79. 79. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); operator alignment only getters (no operations) $user = $this->get(security.context)->getToken()->getUser(); Source: Symfony 2 Docs.
  80. 80. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); operator alignment only getters (no operations) $user = $this->get(security.context)->getToken()->getUser(); Source: Symfony 2 Docs.
  81. 81. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); operator alignment only getters (no operations) $user = $this->get(security.context)->getToken()->getUser(); where did my autocomplete go? Source: Symfony 2 Docs.
  82. 82. Source: Zend Framework App fluent interface$filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower()); operator alignment only getters (no operations) $user = $this->get(security.context)->getToken()->getUser(); where did my return null? autocomplete go? Source: Symfony 2 Docs.
  83. 83. Key Benefits• Readability• Easier Mocking (Testing)• Easier to Debug• Demeter’s Law
  84. 84. OC #5“Do not Abbreviate”
  85. 85. 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; }}
  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. Why do you abbreviate?
  88. 88. Why do you abbreviate? Its repeated many times, and i’m lazy.
  89. 89. Why do you abbreviate? Its repeated many times, and i’m lazy. Underlying Problem! You need to transfer those operations into a separate class.
  90. 90. Why do you abbreviate?function processResponseHeadersAndDefineOutput($response) { ... }
  91. 91. Why do you abbreviate?function processResponseHeadersAndDefineOutput($response) { ... } This method name is too long to type, and i’m lazy.
  92. 92. Why do you abbreviate? more than one responsibility?function processResponseHeadersAndDefineOutput($response) { ... } This method name is too long to type, and i’m lazy.
  93. 93. function getPage($data) { ... }function startProcess() { ... }$tr->process(“site.login”);
  94. 94. get from where?function getPage($data) { ... }function startProcess() { ... }$tr->process(“site.login”);
  95. 95. get from where? Use clearer names:function getPage($data) { ... } fetchPage() downloadPage()function startProcess() { ... }$tr->process(“site.login”);
  96. 96. get from where? Use clearer names:function getPage($data) { ... } fetchPage() downloadPage() Use a thesaurus:function startProcess() { ... } fork, create, begin, open$tr->process(“site.login”);
  97. 97. get from where? Use clearer names:function getPage($data) { ... } fetchPage() downloadPage() Use a thesaurus:function startProcess() { ... } fork, create, begin, open Table row?$tr->process(“site.login”);
  98. 98. get from where? Use clearer names:function getPage($data) { ... } fetchPage() downloadPage() Use a thesaurus:function startProcess() { ... } fork, create, begin, open Table row? Easy understanding, complete scope:$tr->process(“site.login”); $translatorService
  99. 99. Key Benefits• Clearer communication and maintainability• Indicates underlying problems
  100. 100. Ad ap te d OC #6“Keep your classes small”
  101. 101. 200 lines per class 10 methods per class15 classes per package
  102. 102. Increased to include docblocks 200 lines per class 10 methods per class15 classes per package
  103. 103. Increased to include docblocks 15-20 lines per method 200 lines per class 10 methods per class15 classes per package
  104. 104. Increased to include docblocks 15-20 lines per method 200 lines per class 10 methods per class15 classes per package read this as namespace or folder
  105. 105. Key Benefits• Single Responsibility• Objective and clear methods• Slimmer namespaces• Avoids clunky folders
  106. 106. Ad ap OC #7 te d “Limit the number ofinstance variables in a class (2 to 5)”
  107. 107. class MyRegistrationService{ protected $userService; protected $passwordService; protected $logger; protected $translator; protected $entityManager; protected $imageCropper; // ...}
  108. 108. class MyRegistrationService{ protected $userService; protected $passwordService; protected $logger; protected $translator; protected $entityManager; protected $imageCropper; // ...} Limit: 5
  109. 109. class MyRegistrationService { protected $userService; protected $passwordService; protected $logger;All DB interaction protected $translator; should be in protected $entityManager; userService protected $imageCropper; Use an event based system and move this // ... to listener } Limit: 5
  110. 110. Key Benefits• Shorter dependency list• Easier Mocking for unit test
  111. 111. OC #8“Use first class collections”
  112. 112. Doctrine: ArrayCollection$collection->getIterator();$collection->filter(...);$collection->append(...);$collection->map(...);
  113. 113. Key Benefits• Implements collection operations• Uses SPL interfaces• Easier to merge collections and not worry about member behavior in them
  114. 114. Dr op pe d OC #9 “Do not use getters/ setters”* Use them if you code PHP
  115. 115. /** * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE. */class DoctrineTestsModelsCMSCmsUserProxy extends DoctrineTestsModelsCMSCmsUser implements DoctrineORMProxyProxy{ public function getId() { $this->__load(); return parent::getId(); } public function getStatus() { $this->__load(); return parent::getStatus(); } Property accessor (get/set) syntax RFC may change the game.
  116. 116. /** * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE. */class DoctrineTestsModelsCMSCmsUserProxy extends DoctrineTestsModelsCMSCmsUser implements DoctrineORMProxyProxy{ public function getId() { $this->__load(); Example: Doctrine uses getters to return parent::getId(); inject lazy loading operations } public function getStatus() { $this->__load(); return parent::getStatus(); } Property accessor (get/set) syntax RFC may change the game.
  117. 117. Key Benefits• Injector operations• Encapsulation of transformations
  118. 118. Cr ea te d! OC #10 (bonus!)“Document your code!”
  119. 119. //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");
  120. 120. really?//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. really?//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"); Documenting because i’m doing it wrong in an unusual way
  122. 122. $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
  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, What does this do? $event[method]), $priority)); Source: Symfony2
  124. 124. $priority = isset($event[priority]) ? $event[priority] : 0; Add a simple comment:if (!isset($event[event])) { throw new //Strips special chars and camel cases to onXxx 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, What does this do? $event[method]), $priority)); Source: Symfony2
  125. 125. $priority = isset($event[priority]) ? $event[priority] : 0; Add a simple comment:if (!isset($event[event])) { throw new //Strips special chars and camel cases to onXxx InvalidArgumentException(...));}if (!isset($event[method])) { $event[method] = on.preg_replace(array( Don’t explain bad /(?<=b)[a-z]/ie, code, fix it! /[^a-z0-9]/i ), array(strtoupper("0"), ), $event[event]);}$definition->addMethodCall( addListenerService, array($event[event], array($listenerId, What does this do? $event[method]), $priority)); Source: Symfony2
  126. 126. /*** 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);
  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); mark todo items so the changes don’t get lost
  128. 128. A note on cost of running function/*** 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 the changes don’t get lost
  129. 129. Do a mind dump, then clean it up. A note on cost of running function/*** 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 the changes don’t get lost
  130. 130. Do a mind dump, then clean it up. A note on cost of running function/*** 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); Generate API docs with phpDocumentor mark todo items so the changes don’t get lost
  131. 131. Key Benefits• Automatic API documentation• Transmission of “line of thought”• Avoids confusion
  132. 132. 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!
  133. 133. Questions? http://fixthatcode.com@rdohmshttp://doh.ms http://joind.in/7941http://slides.doh.ms
  134. 134. Recommended Links: The ThoughtWorks Anthology http://goo.gl/OcSNx The Art of Readable Code http://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.
  1. A particular slide catching your eye?

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

×