SlideShare une entreprise Scribd logo
1  sur  47
Code smells in PHP




Dagfinn Reiersøl, ABC Startsiden            1
Who am I?

•      Dagfinn Reiersøl
         –     dagfinn@reiersol.com
         –     Twitter: @dagfinnr
         –     Blog: agilephp.com
•      Mostly PHP since 1999
•      Wrote PHP in Action
•      Code quality / agile development enthusiast




Dagfinn Reiersøl, ABC Startsiden                     2
What is a code smell?




                                    Train your nose to tell you...
                                       – ...when to refactor
                                       – ...what to refactor
                                       – ...how to refactor



Dagfinn Reiersøl, ABC Startsiden                               3
It's more like a diagnosis

• A disease has a treatment, a code smell has a refactoring
• (or several)
• Code smell distinctons are important
• For each smell, there is one or more refactorings
• http://industriallogic.com/papers/smellstorefactorings.pdf




Dagfinn Reiersøl, ABC Startsiden                               4
What is refactoring?

• “Improving the design of existing code”
• Maintain behavior
• Change the structure
• Make it more readable, eliminate duplication
• Proceed by small steps
• Keep code working always




Dagfinn Reiersøl, ABC Startsiden                 5
The “bible” of refactoring

                                    • “Martin Fowler...is not Jesus
                                      Christ, and his books are not
                                      the Bible.”
                                    • Except this one really is the
                                      bible.
                                    • Java examples, but mostly
                                      PHP-relevant




Dagfinn Reiersøl, ABC Startsiden                              6
Refactoring is a specific,
                         learnable skill
•     Learn to apply specific, named refactorings.
•     Refactorings have specific instructions
•     Learn to go in baby steps
•     Test between each step
•     Undo if you get lost
•     Weird intermediate results are OK




Dagfinn Reiersøl, ABC Startsiden                      7
Refactoring in PHP

• Very little tool support
• This is both a bad thing and a good thing
• Extract Method is particularly crucial, but unsupported by tools




Dagfinn Reiersøl, ABC Startsiden                            8
Why refactor?

• Make code easier to read (saves time)
• Make it easier to find bugs
• Learn design principles
• Discover new abstractions
• Clean, maintainable code




Dagfinn Reiersøl, ABC Startsiden          9
How much is enough?

• Make it as clean as you possibly can, if circumstances allow
• Boy Scout Rule
• When you change code, you're likely to change it again soon
• Better code needs less refactoring
• Better code is easier to refactor




Dagfinn Reiersøl, ABC Startsiden                            10
Why duplication is so bad

• Harder to maintain
• Harder to debug
• Incomplete bug fixes
      Original code                Original code



       First copy        Debug      First copy



      Second copy                  Second copy



Dagfinn Reiersøl, ABC Startsiden                     11
Automated test coverage is
                         essential
• Unit tests primarily
• Tests make it easy to fix when you break something
• Acceptance tests helpful sometimes
• Manual testing only in special, desperate circumstances
• Legacy code paradox




Dagfinn Reiersøl, ABC Startsiden                            12
Another bible: Clean Code

                                   •   Lots of smells and
                                       heuristics




Dagfinn Reiersøl, ABC Startsiden                            13
Don't take examples personally

• I'm using somewhat real open-source examples
• No personal criticism implied
• Refactoring examples must be somewhere in the middle (not
  awful, not perfect)
• Awful is too hard to refactor (=advanced material)
• Perfect doesn't exist
• Just pretend I wrote all of it ;-)




Dagfinn Reiersøl, ABC Startsiden                       14
Duplicated Code
// even if we are interacting between a table defined in a
// class and a/ table via extension, ensure to persist the
// definition
if (($tableDefinition = $this->_table->getDefinition()) !== null
&& ($dependentTable->getDefinition() == null)) {
      $dependentTable->setOptions(
          array(Table::DEFINITION => $tableDefinition));
}
...
// even if we are interacting between a table defined in a
// class and a/ table via extension, ensure to persist the
// definition
Dagfinn Reiersøl, ABC Startsiden= $this->_table->getDefinition()) !== 15
if (($tableDefinition                                                  null
Long Method

• Long methods are evil
• Hard to read (time-consuming)
• Hard to test
• Tend to have duplicate logic
• Hard to override specific behaviors




Dagfinn Reiersøl, ABC Startsiden        16
How long?

• “The first rule of functions is that they should be small”
• “The second rule of functions is that they should be smaller than
  that”. - Robert C. Martin, Clean Code
• My experience: the cleanest code has mostly 2-5 line methods
• But don't do it if it doesn't make sense
• Do One Thing
• One level of abstraction only




Dagfinn Reiersøl, ABC Startsiden                               17
Refactoring a Long Method

• Split method into smaller methods
• Extract Method is the most important refactoring
// Execute cascading updates against dependent tables.
// Do this only if primary key value(s) were changed.
if (count($pkDiffData) > 0) {
    $depTables = $this->_getTable()->getDependentTables();
    if (!empty($depTables)) {
        $pkNew = $this->_getPrimaryKey(true);
        $pkOld = $this->_getPrimaryKey(false);
        foreach ($depTables as $tableClass) {
            $t = $this->_getTableFromString($tableClass);
            $t->_cascadeUpdate($this->getTableClass(),
                 $pkOld, $pkNew);
        }
    }



Dagfinn Reiersøl, ABC Startsiden                             18
Extract Method: mechanics

1.Copy the code into a new method
2.Find all temporary variables
3.Return all of them from the method
In PHP, unlike Java, we can return multiple variabless

4.Find the ones that are initialized in the method
5.Pass all of those into the method
6.The result is ugly, but a step forward




Dagfinn Reiersøl, ABC Startsiden                         19
Extract Method: result

private function executeCascadingUpdates($pkDiffData) {
    if (count($pkDiffData) > 0) {
        $depTables = $this->_getTable()->getDependentTables();
        if (!empty($depTables)) {
            $pkNew = $this->_getPrimaryKey(true);
            $pkOld = $this->_getPrimaryKey(false);
            foreach ($depTables as $tableClass) {
                $t = $this->_getTableFromString($tableClass);
                $t->_cascadeUpdate(
                     $this->getTableClass(), $pkOld, $pkNew);
            }
        }
    }
    return array($pkDiffData,$tableClass,
                  $depTables,$pkNew,$pkOld,$t);
}




Dagfinn Reiersøl, ABC Startsiden                           20
Validation Overcrowding
function setTable(Table $table){
    $tableClass = get_class($table);
    if (! $table instanceof $this->_tableClass) {
        require_once 'My_Exception.php';
        throw new My_exception("blah blah");
    }
    $this->_table = $table;
    $this->_tableClass = $tableClass;
    $info = $this->_table->info();
    if ($info['cols'] != array_keys($this->_data)) {
        require_once 'My_Exception.php';
        throw new My_exception("blah blah");
    }
    if (!array_intersect((array)$this->_primary, info['primary'])
        == (array) $this->_primary) {
        require_once 'My_Exception.php';
        throw new My_exception("blah blah");
    }
    $this->_connected = true;

Dagfinn Reiersøl, ABC Startsiden                           21
Extracting Validation

• Don't waste time reading validation code
• Extract validation (logging, error handling) into separate
  method(s)
function setTable(Table $table) {
    $this-validateTable($table);
    $this->_table = $table;
    $this->_tableClass = get_class($table);
    $this->_connected = true;
}




Dagfinn Reiersøl, ABC Startsiden                               22
Large Class

• As methods get smaller, there will be more of them
• Hard to keep track of all the methods
• Class has multiple responsibilities
• A class should have only one reason to change
• Duplication is likely




Dagfinn Reiersøl, ABC Startsiden                       23
Refactoring a Large Class

• Primarily Extract Class
• Look for patterns in method names
function     __construct($url = null, $useBrackets = true)...
function     initialize()...
function     getURL()...
function     addQueryString($name, $value, $preencoded = false)...
function     removeQueryString($name)...
function     addRawQueryString($querystring)...
function     getQueryString()...
function     _parseRawQuerystring($querystring)...
function     resolvePath($path)...
function     getStandardPort($scheme)...
function     setProtocol($protocol, $port = null)...
function     setOption($optionName, $value)...
function     getOption($optionName)...


Dagfinn Reiersøl, ABC Startsiden                               24
Refactoring a Large Class

• Look for
    – Patterns in method names (see previous)
    – Subset of data and methods that go together
    – Subset of data that change together
• Mechanics in short
    – Create a new class
    – Copy variables and methods into it
    – Change methods one by one to delegate to the new class
• You must have automated tests

Dagfinn Reiersøl, ABC Startsiden                               25
Primitive Obsession

“People new to objects usually are reluctant to use small objects
  for small tasks, such as money classes that combine number
  and currency, ranges with an upper and lower, and special
  strings such as telphone numbers and ZIP codes.”

- Martin Fowler, Refactoring




Dagfinn Reiersøl, ABC Startsiden                            26
Primitive obsession: non-OO
                         dates
• Will this work?
strftime($arrivaltime);

• Plain PHP date handling is ambiguous, obscure and error-prone
• Use objects instead
$datetime = new DateTime('2008-08-03 14:52:10');
echo $datetime->format('jS, F Y') . "n";




Dagfinn Reiersøl, ABC Startsiden                        27
Primitive obsession example

• The primary key is an array (when?) or a scalar (when?)
• Are these names or values?
if (is_array($primaryKey)) {
  $newPrimaryKey = $primaryKey;
} else {
  $tempPrimaryKey = (array) $this->_primary;
  $newPrimaryKey = array(
         current($tempPrimaryKey) => $primaryKey);
}
return $newPrimaryKey;




Dagfinn Reiersøl, ABC Startsiden                            28
Primitive obsession example

• Huh?
/**
  * Were any of the changed columns part of the primary key?
  */
$pkDiffData = array_intersect_key(
     $diffData, array_flip((array)$this->_primary));
}

• It's clever, obscure, therefore error-prone
• I think I prefer this:
foreach ((array)$this->_primary as $pkName) {
    if (array_key_exists($pkName,$diffData))
        $pkDiffData[$pkName] = $diffData[$pkName];
}



Dagfinn Reiersøl, ABC Startsiden                               29
Primary key class
class PrimaryKey {
     public function __construct($primitive) {
         $this->primitive = $primitive;
     }
     public function isCompoundKey() {
         return is_array($this->primitive);
     }
     public function getSequenceColumn() {
         return array_shift($this->asArray());
     }
     public function asArray() {
         return (array) $this->primitive;
     }
     public function filter($data) {
         return array_intersect_key(
             $data, array_flip($this->asArray()));
     }
}

Dagfinn Reiersøl, ABC Startsiden                     30
Benefits of the PrimaryKey class

•     More expressive client code
•     Details can be found in one place
•     Less duplication
•     Easier to add features
•     Much easier to test




Dagfinn Reiersøl, ABC Startsiden                      31
More expressive code and tests
• What this comment is telling us...
/**
 * [The class] assumes that if you have a compound primary key
 * and one of the columns in the key uses a sequence,
 * it's the _first_ column in the compound key.
 */
• ...can be expressed as a test.
/** @test */
function shouldAssumeFirstColumnIsSequenceColumn() {
     $primaryKey = new PrimaryKey('phone','name');
     $this->assertEquals(
           'phone',
           $primaryKey->getSequenceColumn()
     );
}
Dagfinn Reiersøl, ABC Startsiden                           32
Consider a small class when...

• ...two or more data values occur together repeatedly (ranges,
  etc)
• ...you keep testing the type of a data value
• ...you keep converting a data value
• ...you keep testing for null




Dagfinn Reiersøl, ABC Startsiden                           33
More Primitive Obsession

Error-prone:
$info = $table->info();
$this->_primary = (array) $info['primary'];

Verbose:
$info = $table->info();
$this->_primary = (array) $info[SomeClassName::PRIMARY];

Better:
$this->_primary = $table->getPrimaryKey();




Dagfinn Reiersøl, ABC Startsiden                           34
Don't return null

Alternatives:
• Throw an exception
• Return an empty array
• Return a Null Object (Special Case)




Dagfinn Reiersøl, ABC Startsiden             35
Nested ifs and loops

• Hard to read
• Even harder to test
if (isset($this->session)) {
 //...
 if (isset($this->session['registered'])
  && isset($this->session['username'])
   && $this->session['registered'] == true
   && $this->session['username'] != '') {
     //...
     if ($this->advancedsecurity) {
      $this->log(
              'Advanced Security Mode Enabled.',AUTH_LOG_DEBUG);
       //...




Dagfinn Reiersøl, ABC Startsiden                            36
How to deal with nesting

• Start with the deepest level, extract methods
• How much code to extract?
    – Whole expression (foreach (...) {...})
    – Code inside expression
    – Part of code inside expression
• Adding tests (if none exist)
    – Write tests first, then extract?
    – Or do careful extraction, then add tests?
• Replace Nested Conditional with Guard Clauses

Dagfinn Reiersøl, ABC Startsiden                    37
Conditionals in general

• Often smelly
• Learn how to avoid or simplify them
• http://www.antiifcampaign.com
• Replace Conditional with Polymorphism
• Decompose Conditional
// handle single space character
if(($nb==1) AND preg_match("/[s]/u", $s))




if($this->isSingleSpaceCharacter($s))

Dagfinn Reiersøl, ABC Startsiden                   38
Feature envy / Inappropriate
                   Intimacy
• Does the row object need to poke inside the table objects,
  checking for null?
• No, it's an implementation detail of the Table class
• It's accessed as if it were public, breaking encapsulation
abstract class Row...


if (($tableDefinition = $this->_table->getDefinition())
    !== null
    && ($dependentTable->getDefinition() == null))
{
    $dependentTable->setOptions(
Dagfinn Reiersøl, ABC Startsiden
           array(Table::DEFINITION                             39
Move everything into the
                         “envied” class?
This simple?
$dependentTable->copyDefinitionFrom($this->_table);

Misleading method name. How about this?
$dependentTable->copyDefinitionIfNeededFrom($this->_table);

Ugh. Let's Separate Query from Modifier
if (!$dependentTable->hasDefinition()) //query

   $dependentTable->copyDefinitionFrom($this->_table);




Dagfinn Reiersøl, ABC Startsiden                              40
Redundant Comment

/**
  * If the _cleanData array is empty,
  * this is an INSERT of a new row.
  * Otherwise it is an UPDATE.
  */
if (empty($this->_cleanData)) {
     return $this->_doInsert();
} else {
     return $this->_doUpdate();
}




Dagfinn Reiersøl, ABC Startsiden             41
(Partly) obsolete comment

The comment has (apparently) not been updated to include all
  options

 * Supported params for $config are:-
 * - table...
 * - data...
 * @param...


public function __construct(array $config = array())...
{
    if (isset($config['table'])...
     if (isset($config['data']))...
Dagfinn Reiersøl, ABC Startsiden                          42
     if (isset($config['stored'])...
Functions should descend only one
                         level of abstraction

• _cleanData is at a lower level of abstraction than _doInsert()
  and _doUpdate()
• This is hard, but important
if (empty($this->_cleanData)) {
  return $this->_doInsert();
} else {
  return $this->_doUpdate();
}



if ($this->isNewObject()) {
  return $this->_doInsert();
} else {
  return $this->_doUpdate();
}
Dagfinn Reiersøl, ABC Startsiden                             43
Long Parameter List

• Hard-to-read method calls, especially with nulls and booleans
• Uncle Bob: More than three arguments “require special
  justification”
• Easy to mix up arguments, causing bugs
• Hard to test all variations
$nextContent = $phpcsFile->findNext(
    array(T_WHITESPACE, T_COMMENT),
    ($closeBrace + 1), null, true
);




Dagfinn Reiersøl, ABC Startsiden                          44
One way to shrink the argument
                         list
• Remove unused arguments
public function quoteInto($text, $value,
                            $type = null, $count = null)




Dagfinn Reiersøl, ABC Startsiden                           45
Replace optional / boolean
                         arguments with methods
Boolean argument
protected function _getPrimaryKey($useDirty = true)

Split into separate methods instead
protected function _getPrimaryKeyDirty()
protected function _getPrimaryKeyClean()

Or even objects
$this->dirtyData->getPrimaryKey();
$this->cleanData->getPrimaryKey();




Dagfinn Reiersøl, ABC Startsiden                      46
Introduce Parameter Object

• Encapsulate two or more arguments in a class
• Try to make it more meaningful than “options”
public function log($id, $username, $command = 'unknown',
                   $action,$e)




public function log(LogEvent $event)...




Dagfinn Reiersøl, ABC Startsiden                            47

Contenu connexe

Tendances

Ruby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybaraRuby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybaraBindesh Vijayan
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinMichelangelo van Dam
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great JusticeDomenic Denicola
 
Entry-level PHP for WordPress
Entry-level PHP for WordPressEntry-level PHP for WordPress
Entry-level PHP for WordPresssprclldr
 
Behavior Driven Development - How To Start with Behat
Behavior Driven Development - How To Start with BehatBehavior Driven Development - How To Start with Behat
Behavior Driven Development - How To Start with Behatimoneytech
 
Upstate CSCI 450 PHP Chapters 5, 12, 13
Upstate CSCI 450 PHP Chapters 5, 12, 13Upstate CSCI 450 PHP Chapters 5, 12, 13
Upstate CSCI 450 PHP Chapters 5, 12, 13DanWooster1
 
RxJS + Redux + React = Amazing
RxJS + Redux + React = AmazingRxJS + Redux + React = Amazing
RxJS + Redux + React = AmazingJay Phelps
 
Automate Debugging with git bisect
Automate Debugging with git bisectAutomate Debugging with git bisect
Automate Debugging with git bisectCamille Bell
 
You do not need automation engineer - Sqa Days - 2015 - EN
You do not need automation engineer  - Sqa Days - 2015 - ENYou do not need automation engineer  - Sqa Days - 2015 - EN
You do not need automation engineer - Sqa Days - 2015 - ENIakiv Kramarenko
 
Unit Testing in SilverStripe
Unit Testing in SilverStripeUnit Testing in SilverStripe
Unit Testing in SilverStripeIngo Schommer
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaExoLeaders.com
 
Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...
Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...
Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...Gáspár Nagy
 
Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...
Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...
Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...seleniumconf
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010singingfish
 
Getting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingGetting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingMark Rickerby
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Iakiv Kramarenko
 
Behavior Driven Development (BDD) and Agile Testing
Behavior Driven Development (BDD) and Agile TestingBehavior Driven Development (BDD) and Agile Testing
Behavior Driven Development (BDD) and Agile Testingdversaci
 
The LAZY Developer's Guide to BDD (with Cucumber)
The LAZY Developer's Guide to BDD (with Cucumber)The LAZY Developer's Guide to BDD (with Cucumber)
The LAZY Developer's Guide to BDD (with Cucumber)Tze Yang Ng
 
CUCUMBER - Making BDD Fun
CUCUMBER - Making BDD FunCUCUMBER - Making BDD Fun
CUCUMBER - Making BDD FunSQABD
 

Tendances (20)

Ruby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybaraRuby onrails cucumber-rspec-capybara
Ruby onrails cucumber-rspec-capybara
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great Justice
 
Entry-level PHP for WordPress
Entry-level PHP for WordPressEntry-level PHP for WordPress
Entry-level PHP for WordPress
 
Behavior Driven Development - How To Start with Behat
Behavior Driven Development - How To Start with BehatBehavior Driven Development - How To Start with Behat
Behavior Driven Development - How To Start with Behat
 
BDD, Behat & Drupal
BDD, Behat & DrupalBDD, Behat & Drupal
BDD, Behat & Drupal
 
Upstate CSCI 450 PHP Chapters 5, 12, 13
Upstate CSCI 450 PHP Chapters 5, 12, 13Upstate CSCI 450 PHP Chapters 5, 12, 13
Upstate CSCI 450 PHP Chapters 5, 12, 13
 
RxJS + Redux + React = Amazing
RxJS + Redux + React = AmazingRxJS + Redux + React = Amazing
RxJS + Redux + React = Amazing
 
Automate Debugging with git bisect
Automate Debugging with git bisectAutomate Debugging with git bisect
Automate Debugging with git bisect
 
You do not need automation engineer - Sqa Days - 2015 - EN
You do not need automation engineer  - Sqa Days - 2015 - ENYou do not need automation engineer  - Sqa Days - 2015 - EN
You do not need automation engineer - Sqa Days - 2015 - EN
 
Unit Testing in SilverStripe
Unit Testing in SilverStripeUnit Testing in SilverStripe
Unit Testing in SilverStripe
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
 
Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...
Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...
Behavior Driven Web UI Automation with Selenium and Cucumber/SpecFlow (BDDx L...
 
Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...
Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...
Testing Rapidly Changing Applications With Self-Testing Object-Oriented Selen...
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
 
Getting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingGetting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe Testing
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
 
Behavior Driven Development (BDD) and Agile Testing
Behavior Driven Development (BDD) and Agile TestingBehavior Driven Development (BDD) and Agile Testing
Behavior Driven Development (BDD) and Agile Testing
 
The LAZY Developer's Guide to BDD (with Cucumber)
The LAZY Developer's Guide to BDD (with Cucumber)The LAZY Developer's Guide to BDD (with Cucumber)
The LAZY Developer's Guide to BDD (with Cucumber)
 
CUCUMBER - Making BDD Fun
CUCUMBER - Making BDD FunCUCUMBER - Making BDD Fun
CUCUMBER - Making BDD Fun
 

En vedette

Top 10 things_mazlyn
Top 10 things_mazlynTop 10 things_mazlyn
Top 10 things_mazlynndavis1
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservicestdc-globalcode
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Jstdc-globalcode
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservicestdc-globalcode
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservicestdc-globalcode
 
TDC2016POA | Trilha Arquitetura - Onion Architecture
TDC2016POA | Trilha Arquitetura - Onion ArchitectureTDC2016POA | Trilha Arquitetura - Onion Architecture
TDC2016POA | Trilha Arquitetura - Onion Architecturetdc-globalcode
 
TDC2016POA | Trilha Arquitetura - CQRS e Event Driven Architecture valem a p...
TDC2016POA | Trilha Arquitetura -  CQRS e Event Driven Architecture valem a p...TDC2016POA | Trilha Arquitetura -  CQRS e Event Driven Architecture valem a p...
TDC2016POA | Trilha Arquitetura - CQRS e Event Driven Architecture valem a p...tdc-globalcode
 
TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...
TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...
TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...tdc-globalcode
 
TDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadelo
TDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadeloTDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadelo
TDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadelotdc-globalcode
 
TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?
TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?
TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?tdc-globalcode
 
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...tdc-globalcode
 
TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...
TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...
TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...tdc-globalcode
 
TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...
TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...
TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...tdc-globalcode
 
Code Smells and Refactoring
Code Smells and RefactoringCode Smells and Refactoring
Code Smells and RefactoringStanly Lau
 

En vedette (15)

Top 10 things_mazlyn
Top 10 things_mazlynTop 10 things_mazlyn
Top 10 things_mazlyn
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservices
 
Doctrine for Dummies
Doctrine for DummiesDoctrine for Dummies
Doctrine for Dummies
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Js
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservices
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservices
 
TDC2016POA | Trilha Arquitetura - Onion Architecture
TDC2016POA | Trilha Arquitetura - Onion ArchitectureTDC2016POA | Trilha Arquitetura - Onion Architecture
TDC2016POA | Trilha Arquitetura - Onion Architecture
 
TDC2016POA | Trilha Arquitetura - CQRS e Event Driven Architecture valem a p...
TDC2016POA | Trilha Arquitetura -  CQRS e Event Driven Architecture valem a p...TDC2016POA | Trilha Arquitetura -  CQRS e Event Driven Architecture valem a p...
TDC2016POA | Trilha Arquitetura - CQRS e Event Driven Architecture valem a p...
 
TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...
TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...
TDC2016POA | Trilha Ruby - Melhorando seu código com Law of Demeter e Tell do...
 
TDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadelo
TDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadeloTDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadelo
TDC2016POA | Trilha Ruby - Como não fazer do Rails o seu pesadelo
 
TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?
TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?
TDC2016POA | Trilha Ruby - Hora da aventura! Vamos melhorar seu código?!?
 
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
 
TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...
TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...
TDC2016POA | Trilha PHP - Quero ser desenvolvedor PHP. Como me preparar para ...
 
TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...
TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...
TDC2016POA | Trilha Programacao Funcional - Por que sua próxima aplicação web...
 
Code Smells and Refactoring
Code Smells and RefactoringCode Smells and Refactoring
Code Smells and Refactoring
 

Similaire à Code smells in PHP

Zend Certification Preparation Tutorial
Zend Certification Preparation TutorialZend Certification Preparation Tutorial
Zend Certification Preparation TutorialLorna Mitchell
 
Recursion, debugging in c
Recursion, debugging in cRecursion, debugging in c
Recursion, debugging in cSaule Anay
 
Introduction to functional programming (In Arabic)
Introduction to functional programming (In Arabic)Introduction to functional programming (In Arabic)
Introduction to functional programming (In Arabic)Omar Abdelhafith
 
Modernizing Legacy Applications in PHP, por Paul Jones
Modernizing Legacy Applications in PHP, por Paul JonesModernizing Legacy Applications in PHP, por Paul Jones
Modernizing Legacy Applications in PHP, por Paul JonesiMasters
 
powerpoint 1-19.pdf
powerpoint 1-19.pdfpowerpoint 1-19.pdf
powerpoint 1-19.pdfJuanPicasso7
 
Functional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented ProgrammersFunctional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented ProgrammersDiego Freniche Brito
 
Building a Simple Theme Framework
Building a Simple Theme FrameworkBuilding a Simple Theme Framework
Building a Simple Theme FrameworkJoe Casabona
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redisjimbojsb
 
Code Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured ExceptionsCode Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured ExceptionsJohn Anderson
 
Test First Teaching
Test First TeachingTest First Teaching
Test First TeachingSarah Allen
 
The Essential Perl Hacker's Toolkit
The Essential Perl Hacker's ToolkitThe Essential Perl Hacker's Toolkit
The Essential Perl Hacker's ToolkitStephen Scaffidi
 
Introducing Scala to your Ruby/Java Shop : My experiences at IGN
Introducing Scala to your Ruby/Java Shop : My experiences at IGNIntroducing Scala to your Ruby/Java Shop : My experiences at IGN
Introducing Scala to your Ruby/Java Shop : My experiences at IGNManish Pandit
 
Perl 5.10
Perl 5.10Perl 5.10
Perl 5.10acme
 
Leveling Up at JavaScript
Leveling Up at JavaScriptLeveling Up at JavaScript
Leveling Up at JavaScriptRaymond Camden
 
Code Like Pythonista
Code Like PythonistaCode Like Pythonista
Code Like PythonistaChiyoung Song
 
Rubinius - A Tool of the Future
Rubinius - A Tool of the FutureRubinius - A Tool of the Future
Rubinius - A Tool of the Futureevanphx
 
Bioinformatics p1-perl-introduction v2013
Bioinformatics p1-perl-introduction v2013Bioinformatics p1-perl-introduction v2013
Bioinformatics p1-perl-introduction v2013Prof. Wim Van Criekinge
 

Similaire à Code smells in PHP (20)

Zend Certification Preparation Tutorial
Zend Certification Preparation TutorialZend Certification Preparation Tutorial
Zend Certification Preparation Tutorial
 
Recursion, debugging in c
Recursion, debugging in cRecursion, debugging in c
Recursion, debugging in c
 
Rails traps
Rails trapsRails traps
Rails traps
 
Introduction to functional programming (In Arabic)
Introduction to functional programming (In Arabic)Introduction to functional programming (In Arabic)
Introduction to functional programming (In Arabic)
 
Modernizing Legacy Applications in PHP, por Paul Jones
Modernizing Legacy Applications in PHP, por Paul JonesModernizing Legacy Applications in PHP, por Paul Jones
Modernizing Legacy Applications in PHP, por Paul Jones
 
powerpoint 1-19.pdf
powerpoint 1-19.pdfpowerpoint 1-19.pdf
powerpoint 1-19.pdf
 
Functional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented ProgrammersFunctional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented Programmers
 
Building a Simple Theme Framework
Building a Simple Theme FrameworkBuilding a Simple Theme Framework
Building a Simple Theme Framework
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redis
 
SPL Primer
SPL PrimerSPL Primer
SPL Primer
 
Code Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured ExceptionsCode Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured Exceptions
 
Test First Teaching
Test First TeachingTest First Teaching
Test First Teaching
 
The Essential Perl Hacker's Toolkit
The Essential Perl Hacker's ToolkitThe Essential Perl Hacker's Toolkit
The Essential Perl Hacker's Toolkit
 
Introducing Scala to your Ruby/Java Shop : My experiences at IGN
Introducing Scala to your Ruby/Java Shop : My experiences at IGNIntroducing Scala to your Ruby/Java Shop : My experiences at IGN
Introducing Scala to your Ruby/Java Shop : My experiences at IGN
 
Perl 5.10
Perl 5.10Perl 5.10
Perl 5.10
 
Leveling Up at JavaScript
Leveling Up at JavaScriptLeveling Up at JavaScript
Leveling Up at JavaScript
 
2012 03 08_dbi
2012 03 08_dbi2012 03 08_dbi
2012 03 08_dbi
 
Code Like Pythonista
Code Like PythonistaCode Like Pythonista
Code Like Pythonista
 
Rubinius - A Tool of the Future
Rubinius - A Tool of the FutureRubinius - A Tool of the Future
Rubinius - A Tool of the Future
 
Bioinformatics p1-perl-introduction v2013
Bioinformatics p1-perl-introduction v2013Bioinformatics p1-perl-introduction v2013
Bioinformatics p1-perl-introduction v2013
 

Dernier

Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZABSYZ Inc
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...Akihiro Suda
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 

Dernier (20)

Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZ
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 

Code smells in PHP

  • 1. Code smells in PHP Dagfinn Reiersøl, ABC Startsiden 1
  • 2. Who am I? • Dagfinn Reiersøl – dagfinn@reiersol.com – Twitter: @dagfinnr – Blog: agilephp.com • Mostly PHP since 1999 • Wrote PHP in Action • Code quality / agile development enthusiast Dagfinn Reiersøl, ABC Startsiden 2
  • 3. What is a code smell? Train your nose to tell you... – ...when to refactor – ...what to refactor – ...how to refactor Dagfinn Reiersøl, ABC Startsiden 3
  • 4. It's more like a diagnosis • A disease has a treatment, a code smell has a refactoring • (or several) • Code smell distinctons are important • For each smell, there is one or more refactorings • http://industriallogic.com/papers/smellstorefactorings.pdf Dagfinn Reiersøl, ABC Startsiden 4
  • 5. What is refactoring? • “Improving the design of existing code” • Maintain behavior • Change the structure • Make it more readable, eliminate duplication • Proceed by small steps • Keep code working always Dagfinn Reiersøl, ABC Startsiden 5
  • 6. The “bible” of refactoring • “Martin Fowler...is not Jesus Christ, and his books are not the Bible.” • Except this one really is the bible. • Java examples, but mostly PHP-relevant Dagfinn Reiersøl, ABC Startsiden 6
  • 7. Refactoring is a specific, learnable skill • Learn to apply specific, named refactorings. • Refactorings have specific instructions • Learn to go in baby steps • Test between each step • Undo if you get lost • Weird intermediate results are OK Dagfinn Reiersøl, ABC Startsiden 7
  • 8. Refactoring in PHP • Very little tool support • This is both a bad thing and a good thing • Extract Method is particularly crucial, but unsupported by tools Dagfinn Reiersøl, ABC Startsiden 8
  • 9. Why refactor? • Make code easier to read (saves time) • Make it easier to find bugs • Learn design principles • Discover new abstractions • Clean, maintainable code Dagfinn Reiersøl, ABC Startsiden 9
  • 10. How much is enough? • Make it as clean as you possibly can, if circumstances allow • Boy Scout Rule • When you change code, you're likely to change it again soon • Better code needs less refactoring • Better code is easier to refactor Dagfinn Reiersøl, ABC Startsiden 10
  • 11. Why duplication is so bad • Harder to maintain • Harder to debug • Incomplete bug fixes Original code Original code First copy Debug First copy Second copy Second copy Dagfinn Reiersøl, ABC Startsiden 11
  • 12. Automated test coverage is essential • Unit tests primarily • Tests make it easy to fix when you break something • Acceptance tests helpful sometimes • Manual testing only in special, desperate circumstances • Legacy code paradox Dagfinn Reiersøl, ABC Startsiden 12
  • 13. Another bible: Clean Code • Lots of smells and heuristics Dagfinn Reiersøl, ABC Startsiden 13
  • 14. Don't take examples personally • I'm using somewhat real open-source examples • No personal criticism implied • Refactoring examples must be somewhere in the middle (not awful, not perfect) • Awful is too hard to refactor (=advanced material) • Perfect doesn't exist • Just pretend I wrote all of it ;-) Dagfinn Reiersøl, ABC Startsiden 14
  • 15. Duplicated Code // even if we are interacting between a table defined in a // class and a/ table via extension, ensure to persist the // definition if (($tableDefinition = $this->_table->getDefinition()) !== null && ($dependentTable->getDefinition() == null)) { $dependentTable->setOptions( array(Table::DEFINITION => $tableDefinition)); } ... // even if we are interacting between a table defined in a // class and a/ table via extension, ensure to persist the // definition Dagfinn Reiersøl, ABC Startsiden= $this->_table->getDefinition()) !== 15 if (($tableDefinition null
  • 16. Long Method • Long methods are evil • Hard to read (time-consuming) • Hard to test • Tend to have duplicate logic • Hard to override specific behaviors Dagfinn Reiersøl, ABC Startsiden 16
  • 17. How long? • “The first rule of functions is that they should be small” • “The second rule of functions is that they should be smaller than that”. - Robert C. Martin, Clean Code • My experience: the cleanest code has mostly 2-5 line methods • But don't do it if it doesn't make sense • Do One Thing • One level of abstraction only Dagfinn Reiersøl, ABC Startsiden 17
  • 18. Refactoring a Long Method • Split method into smaller methods • Extract Method is the most important refactoring // Execute cascading updates against dependent tables. // Do this only if primary key value(s) were changed. if (count($pkDiffData) > 0) { $depTables = $this->_getTable()->getDependentTables(); if (!empty($depTables)) { $pkNew = $this->_getPrimaryKey(true); $pkOld = $this->_getPrimaryKey(false); foreach ($depTables as $tableClass) { $t = $this->_getTableFromString($tableClass); $t->_cascadeUpdate($this->getTableClass(), $pkOld, $pkNew); } } Dagfinn Reiersøl, ABC Startsiden 18
  • 19. Extract Method: mechanics 1.Copy the code into a new method 2.Find all temporary variables 3.Return all of them from the method In PHP, unlike Java, we can return multiple variabless 4.Find the ones that are initialized in the method 5.Pass all of those into the method 6.The result is ugly, but a step forward Dagfinn Reiersøl, ABC Startsiden 19
  • 20. Extract Method: result private function executeCascadingUpdates($pkDiffData) { if (count($pkDiffData) > 0) { $depTables = $this->_getTable()->getDependentTables(); if (!empty($depTables)) { $pkNew = $this->_getPrimaryKey(true); $pkOld = $this->_getPrimaryKey(false); foreach ($depTables as $tableClass) { $t = $this->_getTableFromString($tableClass); $t->_cascadeUpdate( $this->getTableClass(), $pkOld, $pkNew); } } } return array($pkDiffData,$tableClass, $depTables,$pkNew,$pkOld,$t); } Dagfinn Reiersøl, ABC Startsiden 20
  • 21. Validation Overcrowding function setTable(Table $table){ $tableClass = get_class($table); if (! $table instanceof $this->_tableClass) { require_once 'My_Exception.php'; throw new My_exception("blah blah"); } $this->_table = $table; $this->_tableClass = $tableClass; $info = $this->_table->info(); if ($info['cols'] != array_keys($this->_data)) { require_once 'My_Exception.php'; throw new My_exception("blah blah"); } if (!array_intersect((array)$this->_primary, info['primary']) == (array) $this->_primary) { require_once 'My_Exception.php'; throw new My_exception("blah blah"); } $this->_connected = true; Dagfinn Reiersøl, ABC Startsiden 21
  • 22. Extracting Validation • Don't waste time reading validation code • Extract validation (logging, error handling) into separate method(s) function setTable(Table $table) { $this-validateTable($table); $this->_table = $table; $this->_tableClass = get_class($table); $this->_connected = true; } Dagfinn Reiersøl, ABC Startsiden 22
  • 23. Large Class • As methods get smaller, there will be more of them • Hard to keep track of all the methods • Class has multiple responsibilities • A class should have only one reason to change • Duplication is likely Dagfinn Reiersøl, ABC Startsiden 23
  • 24. Refactoring a Large Class • Primarily Extract Class • Look for patterns in method names function __construct($url = null, $useBrackets = true)... function initialize()... function getURL()... function addQueryString($name, $value, $preencoded = false)... function removeQueryString($name)... function addRawQueryString($querystring)... function getQueryString()... function _parseRawQuerystring($querystring)... function resolvePath($path)... function getStandardPort($scheme)... function setProtocol($protocol, $port = null)... function setOption($optionName, $value)... function getOption($optionName)... Dagfinn Reiersøl, ABC Startsiden 24
  • 25. Refactoring a Large Class • Look for – Patterns in method names (see previous) – Subset of data and methods that go together – Subset of data that change together • Mechanics in short – Create a new class – Copy variables and methods into it – Change methods one by one to delegate to the new class • You must have automated tests Dagfinn Reiersøl, ABC Startsiden 25
  • 26. Primitive Obsession “People new to objects usually are reluctant to use small objects for small tasks, such as money classes that combine number and currency, ranges with an upper and lower, and special strings such as telphone numbers and ZIP codes.” - Martin Fowler, Refactoring Dagfinn Reiersøl, ABC Startsiden 26
  • 27. Primitive obsession: non-OO dates • Will this work? strftime($arrivaltime); • Plain PHP date handling is ambiguous, obscure and error-prone • Use objects instead $datetime = new DateTime('2008-08-03 14:52:10'); echo $datetime->format('jS, F Y') . "n"; Dagfinn Reiersøl, ABC Startsiden 27
  • 28. Primitive obsession example • The primary key is an array (when?) or a scalar (when?) • Are these names or values? if (is_array($primaryKey)) { $newPrimaryKey = $primaryKey; } else { $tempPrimaryKey = (array) $this->_primary; $newPrimaryKey = array( current($tempPrimaryKey) => $primaryKey); } return $newPrimaryKey; Dagfinn Reiersøl, ABC Startsiden 28
  • 29. Primitive obsession example • Huh? /** * Were any of the changed columns part of the primary key? */ $pkDiffData = array_intersect_key( $diffData, array_flip((array)$this->_primary)); } • It's clever, obscure, therefore error-prone • I think I prefer this: foreach ((array)$this->_primary as $pkName) { if (array_key_exists($pkName,$diffData)) $pkDiffData[$pkName] = $diffData[$pkName]; } Dagfinn Reiersøl, ABC Startsiden 29
  • 30. Primary key class class PrimaryKey { public function __construct($primitive) { $this->primitive = $primitive; } public function isCompoundKey() { return is_array($this->primitive); } public function getSequenceColumn() { return array_shift($this->asArray()); } public function asArray() { return (array) $this->primitive; } public function filter($data) { return array_intersect_key( $data, array_flip($this->asArray())); } } Dagfinn Reiersøl, ABC Startsiden 30
  • 31. Benefits of the PrimaryKey class • More expressive client code • Details can be found in one place • Less duplication • Easier to add features • Much easier to test Dagfinn Reiersøl, ABC Startsiden 31
  • 32. More expressive code and tests • What this comment is telling us... /** * [The class] assumes that if you have a compound primary key * and one of the columns in the key uses a sequence, * it's the _first_ column in the compound key. */ • ...can be expressed as a test. /** @test */ function shouldAssumeFirstColumnIsSequenceColumn() { $primaryKey = new PrimaryKey('phone','name'); $this->assertEquals( 'phone', $primaryKey->getSequenceColumn() ); } Dagfinn Reiersøl, ABC Startsiden 32
  • 33. Consider a small class when... • ...two or more data values occur together repeatedly (ranges, etc) • ...you keep testing the type of a data value • ...you keep converting a data value • ...you keep testing for null Dagfinn Reiersøl, ABC Startsiden 33
  • 34. More Primitive Obsession Error-prone: $info = $table->info(); $this->_primary = (array) $info['primary']; Verbose: $info = $table->info(); $this->_primary = (array) $info[SomeClassName::PRIMARY]; Better: $this->_primary = $table->getPrimaryKey(); Dagfinn Reiersøl, ABC Startsiden 34
  • 35. Don't return null Alternatives: • Throw an exception • Return an empty array • Return a Null Object (Special Case) Dagfinn Reiersøl, ABC Startsiden 35
  • 36. Nested ifs and loops • Hard to read • Even harder to test if (isset($this->session)) { //... if (isset($this->session['registered']) && isset($this->session['username']) && $this->session['registered'] == true && $this->session['username'] != '') { //... if ($this->advancedsecurity) { $this->log( 'Advanced Security Mode Enabled.',AUTH_LOG_DEBUG); //... Dagfinn Reiersøl, ABC Startsiden 36
  • 37. How to deal with nesting • Start with the deepest level, extract methods • How much code to extract? – Whole expression (foreach (...) {...}) – Code inside expression – Part of code inside expression • Adding tests (if none exist) – Write tests first, then extract? – Or do careful extraction, then add tests? • Replace Nested Conditional with Guard Clauses Dagfinn Reiersøl, ABC Startsiden 37
  • 38. Conditionals in general • Often smelly • Learn how to avoid or simplify them • http://www.antiifcampaign.com • Replace Conditional with Polymorphism • Decompose Conditional // handle single space character if(($nb==1) AND preg_match("/[s]/u", $s)) if($this->isSingleSpaceCharacter($s)) Dagfinn Reiersøl, ABC Startsiden 38
  • 39. Feature envy / Inappropriate Intimacy • Does the row object need to poke inside the table objects, checking for null? • No, it's an implementation detail of the Table class • It's accessed as if it were public, breaking encapsulation abstract class Row... if (($tableDefinition = $this->_table->getDefinition()) !== null && ($dependentTable->getDefinition() == null)) { $dependentTable->setOptions( Dagfinn Reiersøl, ABC Startsiden array(Table::DEFINITION 39
  • 40. Move everything into the “envied” class? This simple? $dependentTable->copyDefinitionFrom($this->_table); Misleading method name. How about this? $dependentTable->copyDefinitionIfNeededFrom($this->_table); Ugh. Let's Separate Query from Modifier if (!$dependentTable->hasDefinition()) //query $dependentTable->copyDefinitionFrom($this->_table); Dagfinn Reiersøl, ABC Startsiden 40
  • 41. Redundant Comment /** * If the _cleanData array is empty, * this is an INSERT of a new row. * Otherwise it is an UPDATE. */ if (empty($this->_cleanData)) { return $this->_doInsert(); } else { return $this->_doUpdate(); } Dagfinn Reiersøl, ABC Startsiden 41
  • 42. (Partly) obsolete comment The comment has (apparently) not been updated to include all options * Supported params for $config are:- * - table... * - data... * @param... public function __construct(array $config = array())... { if (isset($config['table'])... if (isset($config['data']))... Dagfinn Reiersøl, ABC Startsiden 42 if (isset($config['stored'])...
  • 43. Functions should descend only one level of abstraction • _cleanData is at a lower level of abstraction than _doInsert() and _doUpdate() • This is hard, but important if (empty($this->_cleanData)) { return $this->_doInsert(); } else { return $this->_doUpdate(); } if ($this->isNewObject()) { return $this->_doInsert(); } else { return $this->_doUpdate(); } Dagfinn Reiersøl, ABC Startsiden 43
  • 44. Long Parameter List • Hard-to-read method calls, especially with nulls and booleans • Uncle Bob: More than three arguments “require special justification” • Easy to mix up arguments, causing bugs • Hard to test all variations $nextContent = $phpcsFile->findNext( array(T_WHITESPACE, T_COMMENT), ($closeBrace + 1), null, true ); Dagfinn Reiersøl, ABC Startsiden 44
  • 45. One way to shrink the argument list • Remove unused arguments public function quoteInto($text, $value, $type = null, $count = null) Dagfinn Reiersøl, ABC Startsiden 45
  • 46. Replace optional / boolean arguments with methods Boolean argument protected function _getPrimaryKey($useDirty = true) Split into separate methods instead protected function _getPrimaryKeyDirty() protected function _getPrimaryKeyClean() Or even objects $this->dirtyData->getPrimaryKey(); $this->cleanData->getPrimaryKey(); Dagfinn Reiersøl, ABC Startsiden 46
  • 47. Introduce Parameter Object • Encapsulate two or more arguments in a class • Try to make it more meaningful than “options” public function log($id, $username, $command = 'unknown', $action,$e) public function log(LogEvent $event)... Dagfinn Reiersøl, ABC Startsiden 47