SlideShare una empresa de Scribd logo
1 de 58
Object Calisthenics
      Applied to PHP
Object Calisthenics
The speaker




    @guilhermeblanco

    http://github.com/guilhermeblanco
Object Calisthenics
Agenda




‣ Motivation
‣ Rules
‣ Application
Object Calisthenics
Erm... WTH is Object Calisthenics?




‣ Object Calisthenics
Object Calisthenics
Erm... WTH is Object Calisthenics?




‣ Object Calisthenics

     Term derived from greek,
     “exercise”, under the
     context of gymnastics.
Object Calisthenics
Erm... WTH is Object Calisthenics?




‣ Jeff Bay in The ThoughtWorks                                     Anthology [1]

  coined the term Object Calisthenics in computers,
  as a group of exercises to Object Oriented
  programming.



[1] The ThoughtWorks Anthology: Essays on Software Technology and Innovation
Object Calisthenics
Motivation




‣ Readable Code
‣ Comprehensible
‣ Testable
‣ Maintainable
                   Learning about good code practices
                      at Object CaIisthenics talk of
                     @guilhermeblanco on @gtaphp
Object Calisthenics
Rules




‣ Nine (9) rules “very” simple...
Object Calisthenics
Rule 1: Only one indentation level per method




‣ Only one indentation level per method
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters='', $validators='', $options='')
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ($input->hasInvalid() || $input->hasMissing()) {
        foreach ($input->getMessages() as $field => $messageList) {
            foreach ($messageList as $message) {
                if (strpos($message, "empty")) {
                    throw new Tss_FormException(
                        "The field {$field} cannot be empty!",
                        3, 'javascript:history.back();'
                    );
                } else {
                    throw new Tss_FormException(
                        "{$message}", 3, 'javascript:history.back();'
                    );
                }
            }
        }
    }

    return $input;
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters='', $validators='', $options='')
{
    $data = $_POST;

      $input = new Zend_Filter_Input($filters, $validators, $data, $options);
      $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    0 if ($input->hasInvalid() || $input->hasMissing()) {
       1 foreach ($input->getMessages() as $field => $messageList) {
           2 foreach(strpos($message, "empty")) {
                      ($messageList as $message) {
               3 if throw new Tss_FormException(
                   4      "The field {$field} cannot be empty!",
                          3, 'javascript:history.back();'
                      );
                  } else {
                      throw new Tss_FormException(
                          "{$message}", 3, 'javascript:history.back();'
                      );
                  }
              }
          }
      }

      return $input;
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters='', $validators='', $options='')
{
    $data = $_POST;

      $input = new Zend_Filter_Input($filters, $validators, $data, $options);
      $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    0 if ($input->hasInvalid() || $input->hasMissing()) {
       1 foreach ($input->getMessages() as $field => $messageList) {
           2 foreach(strpos($message, "empty")) {
                      ($messageList as $message) {
               3 if throw new Tss_FormException(
                   4      "The field {$field} cannot be empty!",
                          3, 'javascript:history.back();'
                      );
                  } else {
                      throw new Tss_FormException(
                          "{$message}", 3, 'javascript:history.back();'
                      );
                  }
              }
          }
      }

      return $input;
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ( ! ($input->hasInvalid() || $input->hasMissing())) {
        return $input;
    }

    foreach ($input->getMessages() as $field => $messageList) {
        foreach ($messageList as $message) {
            if (strpos($message, "empty")) {
                throw new Tss_FormException(
                     "The field {$field} cannot be empty!",
                     3, 'javascript:history.back();'
                );
            } else {
                throw new Tss_FormException(
                     "{$message}", 3, 'javascript:history.back();'
                );
            }
        }
    }
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ( ! ($input->hasInvalid() || $input->hasMissing())) {
        return $input;
    }

0 foreach ($input->getMessages() as $field => $messageList) {
   1 foreach(strpos($message, "empty")) {
              ($messageList as $message) {
       2 if throw new Tss_FormException(
           3 "The field {$field} cannot be empty!",
                    3, 'javascript:history.back();'
                );
            } else {
                throw new Tss_FormException(
                     "{$message}", 3, 'javascript:history.back();'
                );
            }
        }
    }
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ( ! ($input->hasInvalid() || $input->hasMissing())) {
        return $input;
    }

    foreach ($input->getMessages() as $field => $messageList) {
        foreach ($messageList as $message) {
            $errorMessage = (strpos($message, "empty") === false)
                ? "The field {$field} cannot be empty!"
                : "{$message}";

            throw new Tss_FormException(
                $errorMessage, 3, 'javascript:history.back();'
            );
        }
    }
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ( ! ($input->hasInvalid() || $input->hasMissing())) {
        return $input;
    }

0 foreach ($input->getMessages() as $field => $messageList) {
   1 foreach ($messageList as $message) { "empty") === false)
       2 $errorMessage = (strpos($message,be empty!"
              ? "The field {$field} cannot
                : "{$message}";

            throw new Tss_FormException(
                $errorMessage, 3, 'javascript:history.back();'
            );
        }
    }
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validatePost($filters = array(), $validators = array(), $options = null)
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ( ! ($input->hasInvalid() || $input->hasMissing())) {
        return $input;
    }

    foreach ($input->getMessages() as $field => $message) {
        $messageKey   = key($message);
        $message      = $message[$messageKey];
        $errorMessage = (strpos($message, "empty") === false)
            ? "The field {$field} cannot be empty!"
            : "{$message}";

        throw new Tss_FormException(
            $errorMessage, 3, 'javascript:history.back();'
        );
    }
}
Object Calisthenics
Rule 1: Only one indentation level per method
public function validatePost($filters = array(), $validators = array(), $options = null)
{
    $data = $_POST;

    $input = new Zend_Filter_Input($filters, $validators, $data, $options);
    $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

    if ( ! ($input->hasInvalid() || $input->hasMissing())) {
        return $input;
    }

    foreach ($input->getMessages() as $field => $message) {
        $messageKey   = key($message);
        $message      = $message[$messageKey];
        $errorMessage = (strpos($message, "empty") === false)
            ? "The field {$field} cannot be empty!"
            : "{$message}";

        throw new Tss_FormException(
            $errorMessage, 3, 'javascript:history.back();'
        );
    }
}
Object Calisthenics
Rule 2: Do not use the “else” keyword




‣ Never use the “else” keyword
Object Calisthenics
Rule 2: Do not use the “else” keyword
function login()   {
    $login     =   $this->input->post('email', true);
    $password =    $this->input->post('password', true);
    $reference =   $this->input->post('reference', true);

    if ($this->clients_model->login($login, $password)) {
        redirect($reference);
    } else {
        $this->session->set_flashdata('error', 'User or password invalid.');
        $this->session->set_flashdata('reference', $reference);
        redirect('clients');
    }
}
Object Calisthenics
Rule 2: Do not use the “else” keyword
function login()   {
    $login     =   $this->input->post('email', true);
    $password =    $this->input->post('password', true);
    $reference =   $this->input->post('reference', true);

    if ($this->clients_model->login($login, $password)) {
        redirect($reference);
    } else {
        $this->session->set_flashdata('error', 'User or password invalid.');
        $this->session->set_flashdata('reference', $reference);
        redirect('clients');
    }
}
Object Calisthenics
Rule 2: Do not use the “else” keyword
function login()   {
    $login     =   $this->input->post('email', true);
    $password =    $this->input->post('password', true);
    $reference =   $this->input->post('reference', true);

    if ($this->clients_model->login($login, $password)) {
        redirect($reference);
    } else {
        $this->session->set_flashdata('error', 'User or password invalid.');
        $this->session->set_flashdata('reference', $reference);
        redirect('clients');
    }
}
Object Calisthenics
Rule 2: Do not use the “else” keyword
function login()   {
    $login     =   $this->input->post('email', true);
    $password =    $this->input->post('password', true);
    $reference =   $this->input->post('reference', true);

    if ( ! ($this->clients_model->login($login, $password))) {
        $this->session->set_flashdata('error', 'User or password invalid.');
        $this->session->set_flashdata('reference', $reference);

        $reference = 'clients';
    }

    redirect($reference);
}
Object Calisthenics
Rule 3: Wrap primitive types and strings




‣ Wrap all primitive types and strings
Object Calisthenics
Rule 3: Wrap primitive types and strings




‣ This rule cannot be completely ported to PHP, because
  the language does not perform well with an entirely
  Object Oriented code with a huge amount of instances
Object Calisthenics
Rule 3: Wrap primitive types and strings




‣ But... if the variable of primitive type has a behavior, it
  must be encapsulated
Object Calisthenics
Rule 3: Wrap primitive types and strings
class UIComponent
{
! // ...
!
    public function repaint($animate = true)
    {
        // ...
    }
}

// ...
$component->repaint(false);
Object Calisthenics
Rule 3: Wrap primitive types and strings
class UIComponent
{
! // ...
!
    public function repaint($animate = true)
    {
        // ...
    }
}

// ...
$component->repaint(false);
Object Calisthenics
Rule 3: Wrap primitive types and strings
class UIComponent
{
! // ...
!
    public function repaint(Animate $animate)
    {
        // ...
    }
}

class Animate
{
    public $animate;

    public function __construct($animate = true)
    {
        $this->animate = $animate;
    }
}

// ...
$component->repaint(new Animate(false));
Object Calisthenics
Rule 4: Only one dot per line




‣ Only one dot (arrow for PHP) per line
Object Calisthenics
Rule 4: Only one dot per line




‣ Not applicable to PHP...
Object Calisthenics
Rule 4: Only one dot per line




‣ ...but multiple nested calls...
   ‣ tend to expose an encapsulation problem
   ‣ increase difficulty to debug and exception handling
   ‣ do not represent an atomic action
Object Calisthenics
Rule 4: Only one dot per line




‣ We could adapt to the language, contemplating...
Object Calisthenics
Rule 4: Only one dot per line

‣ A chain of different objects, but only if the execution
  only includes getters and setters


               $user->getLocationPoint()->getCountry()->getName();
Object Calisthenics
Rule 4: Only one dot per line

‣ A chain of a unique object, through the usage of a
  fluent interface


            $filterChain->addFilter(new Zend_Filter_Alpha())
                        ->addFilter(new Zend_Filter_StringToLower());
Object Calisthenics
Rule 5: Do not abbreviate




‣ Do not abbreviate
Object Calisthenics
Rule 5: Do not abbreviate
Object Calisthenics
Rule 5: Do not abbreviate



‣ Think about it... why do you want to abbreviate?
Object Calisthenics
Rule 5: Do not abbreviate



‣ Think about it... why do you want to abbreviate?
   ‣ Write the same name repeatedly?
Object Calisthenics
Rule 5: Do not abbreviate



‣ Think about it... why do you want to abbreviate?
   ‣ Write the same name repeatedly?
     ‣ Then your method is reused multiple times,
       signalling a code duplication.
Object Calisthenics
Rule 5: Do not abbreviate



‣ Think about it... why do you want to abbreviate?
   ‣ Write the same name repeatedly?
     ‣ Then your method is reused multiple times,
       signalling a code duplication.
   ‣ Method name too long?
Object Calisthenics
Rule 5: Do not abbreviate



‣ Think about it... why do you want to abbreviate?
   ‣ Write the same name repeatedly?
     ‣ Then your method is reused multiple times,
       signalling a code duplication.
   ‣ Method name too long?
     ‣ Maybe your class has multiple responsibilities or it
       is missing a helper class (bad architecture).
Object Calisthenics
Rule 5: Do not abbreviate



‣ Think about it... why do you want to abbreviate?
   ‣ Write the same name repeatedly?
     ‣ Then your method is reused multiple times,
       signalling a code duplication.
   ‣ Method name too long?
     ‣ Maybe your class has multiple responsibilities or it
       is missing a helper class (bad architecture).
Object Calisthenics
Rule 6: Keep your entities small




‣ Keep your entities small
Object Calisthenics
Rule 6: Keep your entities small




‣ Original rule: 50 lines per class
Object Calisthenics
Rule 6: Keep your entities small




‣ Adapted to PHP: 100 lines per class and no more than
  15 classes per package.
‣ The change is necessary because of the lack of rule for
  documentation, which can easily occupy up to 50% of
  the lines of a class.
Object Calisthenics
Rule 7: Do not create classes with more than 2 instance variables




‣ Do not create classes with more than 2 instance
  variables
Object Calisthenics
Rule 7: Do not create classes with more than 2 instance variables




‣ Objective:
   ‣ Low cohesion
   ‣ Better encapsulation
Object Calisthenics
Rule 7: Do not create classes with more than 2 instance variables




‣ The original rule points to 2 instance variables
‣ To PHP, the suggestion is no more than 5 variables
Object Calisthenics
Rule 8: Use first class collections




‣ Use first class collections
Object Calisthenics
Rule 8: Use first class collections




‣ The rule is simple: Any class that contains a collection
  (array to PHP), cannot contain any other properties
Object Calisthenics
Rule 8: Use first class collections




‣ Objectives:
   ‣ Specific behaviors have a good place to stay
   ‣ Filtering, combining, mapping, ...
Object Calisthenics
Rule 8: Use first class collections




‣ DoctrineCommonCollectionsArrayCollection
   ‣ Countable
   ‣ IteratorAggregate (inherits Traversable)
   ‣ ArrayAccess
Object Calisthenics
Rule 9: Do not create getter/setter methods to properties




‣ Do not create getter/setter methods to properties
Object Calisthenics
Rule 9: Do not create getter/setter methods to properties




‣ Non-applicable to PHP due to language’s nature
Object Calisthenics
Rule 9: Do not create getter/setter methods to properties
/**
  * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
  */
class ApplicationCoreDomainUserModelUserProxy
! extends ApplicationCoreDomainUserModelUser
! implements DoctrineORMProxyProxy
{
     // ...

    public function getId()
    {
        $this->__load();
        return parent::getId();
    }

    public function setId($id)
    {
        $this->__load();
        return parent::setId($id);
    }

    // ...
}
Object Calisthenics
“Rule 10”: Document your code!




‣ Document your code!!!!!!!!!!!!!!!!!
Object Calisthenics
That’s all folks!




‣ Questions?



    @guilhermeblanco

    http://github.com/guilhermeblanco

Más contenido relacionado

La actualidad más candente

La actualidad más candente (20)

JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0
 
Sql query patterns, optimized
Sql query patterns, optimizedSql query patterns, optimized
Sql query patterns, optimized
 
JUnit 4
JUnit 4JUnit 4
JUnit 4
 
You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)
 
Indexing
IndexingIndexing
Indexing
 
Applicative style programming
Applicative style programmingApplicative style programming
Applicative style programming
 
JDBC
JDBCJDBC
JDBC
 
Java Basics
Java BasicsJava Basics
Java Basics
 
computer project code ''payroll'' (based on datafile handling)
computer project code ''payroll'' (based on datafile handling)computer project code ''payroll'' (based on datafile handling)
computer project code ''payroll'' (based on datafile handling)
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Optional in Java 8
Optional in Java 8Optional in Java 8
Optional in Java 8
 
Collection v3
Collection v3Collection v3
Collection v3
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object Calisthenics
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in php
 
Threads V4
Threads  V4Threads  V4
Threads V4
 

Similar a Object Calisthenics Applied to PHP

Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
Taras Kalapun
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
mfrost503
 

Similar a Object Calisthenics Applied to PHP (20)

1st CI&T Lightning Talks: Writing better code with Object Calisthenics
1st CI&T Lightning Talks: Writing better code with Object Calisthenics1st CI&T Lightning Talks: Writing better code with Object Calisthenics
1st CI&T Lightning Talks: Writing better code with Object Calisthenics
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
 
TestFest - Respect\Validation 1.0
TestFest - Respect\Validation 1.0TestFest - Respect\Validation 1.0
TestFest - Respect\Validation 1.0
 
Workshop unittesting
Workshop unittestingWorkshop unittesting
Workshop unittesting
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
PHPUnit elevato alla Symfony2
PHPUnit elevato alla Symfony2PHPUnit elevato alla Symfony2
PHPUnit elevato alla Symfony2
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
 
Gta v savegame
Gta v savegameGta v savegame
Gta v savegame
 
Drupal 8 database api
Drupal 8 database apiDrupal 8 database api
Drupal 8 database api
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 

Más de Guilherme Blanco

Más de Guilherme Blanco (12)

Enterprise php
Enterprise phpEnterprise php
Enterprise php
 
PHP 7
PHP 7PHP 7
PHP 7
 
ORM dont kill your DB, developers do
ORM dont kill your DB, developers doORM dont kill your DB, developers do
ORM dont kill your DB, developers do
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHP
 
Javascript para adultos
Javascript para adultosJavascript para adultos
Javascript para adultos
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
 
Doctrine2 Seminário PHP
Doctrine2 Seminário PHPDoctrine2 Seminário PHP
Doctrine2 Seminário PHP
 
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHPIPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
 
Doctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHPDoctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHP
 
PHP, Daemons e Multimedia
PHP, Daemons e MultimediaPHP, Daemons e Multimedia
PHP, Daemons e Multimedia
 
Doctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPDoctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHP
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine Orm
 

Último

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Último (20)

Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

Object Calisthenics Applied to PHP

  • 1. Object Calisthenics Applied to PHP
  • 2. Object Calisthenics The speaker @guilhermeblanco http://github.com/guilhermeblanco
  • 4. Object Calisthenics Erm... WTH is Object Calisthenics? ‣ Object Calisthenics
  • 5. Object Calisthenics Erm... WTH is Object Calisthenics? ‣ Object Calisthenics Term derived from greek, “exercise”, under the context of gymnastics.
  • 6. Object Calisthenics Erm... WTH is Object Calisthenics? ‣ Jeff Bay in The ThoughtWorks Anthology [1] coined the term Object Calisthenics in computers, as a group of exercises to Object Oriented programming. [1] The ThoughtWorks Anthology: Essays on Software Technology and Innovation
  • 7. Object Calisthenics Motivation ‣ Readable Code ‣ Comprehensible ‣ Testable ‣ Maintainable Learning about good code practices at Object CaIisthenics talk of @guilhermeblanco on @gtaphp
  • 8. Object Calisthenics Rules ‣ Nine (9) rules “very” simple...
  • 9. Object Calisthenics Rule 1: Only one indentation level per method ‣ Only one indentation level per method
  • 10. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters='', $validators='', $options='') { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ($input->hasInvalid() || $input->hasMissing()) { foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } } } return $input; }
  • 11. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters='', $validators='', $options='') { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); 0 if ($input->hasInvalid() || $input->hasMissing()) { 1 foreach ($input->getMessages() as $field => $messageList) { 2 foreach(strpos($message, "empty")) { ($messageList as $message) { 3 if throw new Tss_FormException( 4 "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } } } return $input; }
  • 12. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters='', $validators='', $options='') { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); 0 if ($input->hasInvalid() || $input->hasMissing()) { 1 foreach ($input->getMessages() as $field => $messageList) { 2 foreach(strpos($message, "empty")) { ($messageList as $message) { 3 if throw new Tss_FormException( 4 "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } } } return $input; }
  • 13. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters = array(), $validators = array(), $options = null) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } } }
  • 14. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters = array(), $validators = array(), $options = null) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } 0 foreach ($input->getMessages() as $field => $messageList) { 1 foreach(strpos($message, "empty")) { ($messageList as $message) { 2 if throw new Tss_FormException( 3 "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } } }
  • 15. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters = array(), $validators = array(), $options = null) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : "{$message}"; throw new Tss_FormException( $errorMessage, 3, 'javascript:history.back();' ); } } }
  • 16. Object Calisthenics Rule 1: Only one indentation level per method public function validateForm($filters = array(), $validators = array(), $options = null) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } 0 foreach ($input->getMessages() as $field => $messageList) { 1 foreach ($messageList as $message) { "empty") === false) 2 $errorMessage = (strpos($message,be empty!" ? "The field {$field} cannot : "{$message}"; throw new Tss_FormException( $errorMessage, 3, 'javascript:history.back();' ); } } }
  • 17. Object Calisthenics Rule 1: Only one indentation level per method public function validatePost($filters = array(), $validators = array(), $options = null) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $message) { $messageKey = key($message); $message = $message[$messageKey]; $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : "{$message}"; throw new Tss_FormException( $errorMessage, 3, 'javascript:history.back();' ); } }
  • 18. Object Calisthenics Rule 1: Only one indentation level per method public function validatePost($filters = array(), $validators = array(), $options = null) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $message) { $messageKey = key($message); $message = $message[$messageKey]; $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : "{$message}"; throw new Tss_FormException( $errorMessage, 3, 'javascript:history.back();' ); } }
  • 19. Object Calisthenics Rule 2: Do not use the “else” keyword ‣ Never use the “else” keyword
  • 20. Object Calisthenics Rule 2: Do not use the “else” keyword function login() { $login = $this->input->post('email', true); $password = $this->input->post('password', true); $reference = $this->input->post('reference', true); if ($this->clients_model->login($login, $password)) { redirect($reference); } else { $this->session->set_flashdata('error', 'User or password invalid.'); $this->session->set_flashdata('reference', $reference); redirect('clients'); } }
  • 21. Object Calisthenics Rule 2: Do not use the “else” keyword function login() { $login = $this->input->post('email', true); $password = $this->input->post('password', true); $reference = $this->input->post('reference', true); if ($this->clients_model->login($login, $password)) { redirect($reference); } else { $this->session->set_flashdata('error', 'User or password invalid.'); $this->session->set_flashdata('reference', $reference); redirect('clients'); } }
  • 22. Object Calisthenics Rule 2: Do not use the “else” keyword function login() { $login = $this->input->post('email', true); $password = $this->input->post('password', true); $reference = $this->input->post('reference', true); if ($this->clients_model->login($login, $password)) { redirect($reference); } else { $this->session->set_flashdata('error', 'User or password invalid.'); $this->session->set_flashdata('reference', $reference); redirect('clients'); } }
  • 23. Object Calisthenics Rule 2: Do not use the “else” keyword function login() { $login = $this->input->post('email', true); $password = $this->input->post('password', true); $reference = $this->input->post('reference', true); if ( ! ($this->clients_model->login($login, $password))) { $this->session->set_flashdata('error', 'User or password invalid.'); $this->session->set_flashdata('reference', $reference); $reference = 'clients'; } redirect($reference); }
  • 24. Object Calisthenics Rule 3: Wrap primitive types and strings ‣ Wrap all primitive types and strings
  • 25. Object Calisthenics Rule 3: Wrap primitive types and strings ‣ This rule cannot be completely ported to PHP, because the language does not perform well with an entirely Object Oriented code with a huge amount of instances
  • 26. Object Calisthenics Rule 3: Wrap primitive types and strings ‣ But... if the variable of primitive type has a behavior, it must be encapsulated
  • 27. Object Calisthenics Rule 3: Wrap primitive types and strings class UIComponent { ! // ... ! public function repaint($animate = true) { // ... } } // ... $component->repaint(false);
  • 28. Object Calisthenics Rule 3: Wrap primitive types and strings class UIComponent { ! // ... ! public function repaint($animate = true) { // ... } } // ... $component->repaint(false);
  • 29. Object Calisthenics Rule 3: Wrap primitive types and strings class UIComponent { ! // ... ! public function repaint(Animate $animate) { // ... } } class Animate { public $animate; public function __construct($animate = true) { $this->animate = $animate; } } // ... $component->repaint(new Animate(false));
  • 30. Object Calisthenics Rule 4: Only one dot per line ‣ Only one dot (arrow for PHP) per line
  • 31. Object Calisthenics Rule 4: Only one dot per line ‣ Not applicable to PHP...
  • 32. Object Calisthenics Rule 4: Only one dot per line ‣ ...but multiple nested calls... ‣ tend to expose an encapsulation problem ‣ increase difficulty to debug and exception handling ‣ do not represent an atomic action
  • 33. Object Calisthenics Rule 4: Only one dot per line ‣ We could adapt to the language, contemplating...
  • 34. Object Calisthenics Rule 4: Only one dot per line ‣ A chain of different objects, but only if the execution only includes getters and setters $user->getLocationPoint()->getCountry()->getName();
  • 35. Object Calisthenics Rule 4: Only one dot per line ‣ A chain of a unique object, through the usage of a fluent interface $filterChain->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower());
  • 36. Object Calisthenics Rule 5: Do not abbreviate ‣ Do not abbreviate
  • 37. Object Calisthenics Rule 5: Do not abbreviate
  • 38. Object Calisthenics Rule 5: Do not abbreviate ‣ Think about it... why do you want to abbreviate?
  • 39. Object Calisthenics Rule 5: Do not abbreviate ‣ Think about it... why do you want to abbreviate? ‣ Write the same name repeatedly?
  • 40. Object Calisthenics Rule 5: Do not abbreviate ‣ Think about it... why do you want to abbreviate? ‣ Write the same name repeatedly? ‣ Then your method is reused multiple times, signalling a code duplication.
  • 41. Object Calisthenics Rule 5: Do not abbreviate ‣ Think about it... why do you want to abbreviate? ‣ Write the same name repeatedly? ‣ Then your method is reused multiple times, signalling a code duplication. ‣ Method name too long?
  • 42. Object Calisthenics Rule 5: Do not abbreviate ‣ Think about it... why do you want to abbreviate? ‣ Write the same name repeatedly? ‣ Then your method is reused multiple times, signalling a code duplication. ‣ Method name too long? ‣ Maybe your class has multiple responsibilities or it is missing a helper class (bad architecture).
  • 43. Object Calisthenics Rule 5: Do not abbreviate ‣ Think about it... why do you want to abbreviate? ‣ Write the same name repeatedly? ‣ Then your method is reused multiple times, signalling a code duplication. ‣ Method name too long? ‣ Maybe your class has multiple responsibilities or it is missing a helper class (bad architecture).
  • 44. Object Calisthenics Rule 6: Keep your entities small ‣ Keep your entities small
  • 45. Object Calisthenics Rule 6: Keep your entities small ‣ Original rule: 50 lines per class
  • 46. Object Calisthenics Rule 6: Keep your entities small ‣ Adapted to PHP: 100 lines per class and no more than 15 classes per package. ‣ The change is necessary because of the lack of rule for documentation, which can easily occupy up to 50% of the lines of a class.
  • 47. Object Calisthenics Rule 7: Do not create classes with more than 2 instance variables ‣ Do not create classes with more than 2 instance variables
  • 48. Object Calisthenics Rule 7: Do not create classes with more than 2 instance variables ‣ Objective: ‣ Low cohesion ‣ Better encapsulation
  • 49. Object Calisthenics Rule 7: Do not create classes with more than 2 instance variables ‣ The original rule points to 2 instance variables ‣ To PHP, the suggestion is no more than 5 variables
  • 50. Object Calisthenics Rule 8: Use first class collections ‣ Use first class collections
  • 51. Object Calisthenics Rule 8: Use first class collections ‣ The rule is simple: Any class that contains a collection (array to PHP), cannot contain any other properties
  • 52. Object Calisthenics Rule 8: Use first class collections ‣ Objectives: ‣ Specific behaviors have a good place to stay ‣ Filtering, combining, mapping, ...
  • 53. Object Calisthenics Rule 8: Use first class collections ‣ DoctrineCommonCollectionsArrayCollection ‣ Countable ‣ IteratorAggregate (inherits Traversable) ‣ ArrayAccess
  • 54. Object Calisthenics Rule 9: Do not create getter/setter methods to properties ‣ Do not create getter/setter methods to properties
  • 55. Object Calisthenics Rule 9: Do not create getter/setter methods to properties ‣ Non-applicable to PHP due to language’s nature
  • 56. Object Calisthenics Rule 9: Do not create getter/setter methods to properties /** * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE. */ class ApplicationCoreDomainUserModelUserProxy ! extends ApplicationCoreDomainUserModelUser ! implements DoctrineORMProxyProxy { // ... public function getId() { $this->__load(); return parent::getId(); } public function setId($id) { $this->__load(); return parent::setId($id); } // ... }
  • 57. Object Calisthenics “Rule 10”: Document your code! ‣ Document your code!!!!!!!!!!!!!!!!!
  • 58. Object Calisthenics That’s all folks! ‣ Questions? @guilhermeblanco http://github.com/guilhermeblanco

Notas del editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n