PHPRefactor

Table of Contents

1 Refactorings

  • The examples are trying to be as much short & simple as they can.
  • In most cases, there are still problems with the code at the end, but fixing these problems requires other refactorings.
  • Don't take any of these examples as suggestions for how to design objects. These examples are there only to illustrate the refactorings, nothing more.
  • I use int to represent monetary values. I've done this only to make the examples simpler, as the representation is not important to the refactoring. In commercial software use the Quantity pattern.

1.1 Based On Fowler 2002

1.1.1 Extract Function

public function printInvoice(Invoice $invoice): void
{
    echo 'Invoice';
    echo '<br>';
    echo $invoice->getNumber();
   
    echo 'phpRefactor: ';
    echo '<br>';
    echo $invoice->getDate();
}
  1. Write a test that pass
  2. Refactor the code

    Turn the fragment into a method whose name explains the purpose of the method

    public function printInvoice(Invoice $invoice): void
    {
        printInvoiceHeader($invoice);
        printInvoiceFooter($invoice);
    }
    
    function printInvoiceHeader(Invoice $invoice): void
    {
        echo 'Invoice';
        echo '<br>';
        echo $invoice->getNumber();
    }
    
    function printInvoiceFooter(Invoice $invoice): void
    {
        echo 'phpRefactor: ';
        echo '<br>';
        echo $invoice->getDate();
    }
    
  3. Run a test
  4. Notes
    function printInvoice() {
        $footer=function() {
            echo "phpRefactor.com \n";
            echo "2019";
        };
        
        echo "Header \n";
        $footer();
    }
    printInvoice();
    

1.1.2 Inline Function

Alias: Inline Method Smell: A function's body is just as clear as it's name

class Circle
{
    public const RADIUS = 2;

    public function getArea(): float
    {
        return $this->getValueOfPI() * self::RADIUS * self::RADIUS;
    }

    private function getValueOfPI(): float
    {
        return pi();
    }
}
  1. Write a test that pass
    use PHPUnit\Framework\TestCase;
    
    class CircleTest extends TestCase
    {   
        public function testGetArea()
        {
            $circle = new Circle();
            $this->assertEquals( 12.566370614359172, $circle->getArea());
        }
    }
    
    PHPUnit 7.4.3 by Sebastian Bergmann and contributors.
    
    .                                                                   1 / 1 (100%)
    
    Time: 53 ms, Memory: 10.00MB
    
    OK (1 test, 1 assertion)
    
  2. Refactor the code

    Put the method's body into the body of its callers and remove the method.

    public function getArea(): float
    {
        return pi() * $radius * $radius;
    }
    
  3. Pass a test

1.1.3 Inline Variable

Smell: Variable name doesn't really communicate more than the expression itself or gets in the way of refactoring neighboring code.

$basePrice = $anOrder->basePrice;
return ($basePrice > 1000);
  1. Refactor the code
    return $anOrder->basePrice > 1000;
    

    140

1.1.4 Replace Temp with Query

Smell: Using a temporary variable to hold the result of an expression. Damage: Temporary variable increase the temptation to write longer methods. Temporaries aren’t necessarily bad, but sometimes they attract new code.

public function getTotalPrice(): int
{
    $basePrice = $this->quantity * $this->itemPrice;

    if ($basePrice > self::DISCOUNT_POINT) {
        return $basePrice * self::DISCOUNT;
    }
    return $basePrice;
}
  1. Write a test that pass
  2. Refactor the code

    Extract the expression into a method. Replace all references to the temp with the expression. The new method can then be used in other methods.

    public function getTotalPrice(): int
    {
        if ($this->getBasePrice() > self::DISCOUNT_POINT) {
            return $this->getBasePrice() * self::DISCOUNT;
        }
        return $this->getBasePrice();
    }
    
    public function getBasePrice(): int
    {
        $this->quantity * $this->itemPrice;
    }
    
  3. Pass a test
  4. Info

    Now, but wait, you might say. Isn't this more inefficient? Because if we created the temp the old way, we'd only have to execute the expression once, but if we turn it into a method, we might be calling it many different times. And yes, you're absolutely right, but remember, the pure efficiency of the code is not our first goal in refactoring. Clarity is. The likelihood is that a typical expression you would deal with in this sort of refactoring is going to be so undemanding, it wouldn't be noticeable at all, even having to call it several more times. But if it is an intensive operation, an intensive expression, well you should really be working on that later, after you've refactored using profilers. And other tools to make sure you're not doing pointless, premature optimization. And the real benefit is that by creating this as its own method, we will also have use of it anywhere else in the class, which wasn't the case before. As the original temp was scoped to the original method. So, we won't be tempted to add more code to the original method just to have access to that temp.

1.1.5 Extract Variable

Alias: Introduce Explaining Variable Smell: Complicated expression

if(($stock->checkStatus($order->getItem) > $order->getQuantity()) 
    && ($order->getTotal() > 99) 
    && ($order->getCustomer()->getBillingAddress() === $order->getShippingAddress()));
  1. Write a test that pass
  2. Refactor the code

    Put the result of the expression, or part of it in a temporary variable with a name that explains the purpose

    $freeShipping = $order->getTotal() > 99;
    $stockAvailable = $stock->checkStatus($order->getItem) > $order->getQuantity();
    $addressMatches = $order->getCustomer()->getBillingAddress() === $order->getShippingAddress();
    if($stockAvailable && $freeShipping && $addressMatches);
    
  3. Pass a test

1.2 Add Type-Hint

1.2.1 If you CAN type-hint, then you MUST type-hint

Smell: A method with no type defined parameters or return type declaration

public function setNumber($number)
{
    $this->number = $number;
}
  1. Refactor the code
    public function setNumber(int $number): void
    {
        $this->number = $number;
    }
    
  2. Helper

    phpdoc-to-typehint adds automatically scalar type hints and return types to all functions and methods using existing PHPDoc annotations

  3. Further Reading

1.2.2 If you are type-hinting an array, you MUST document the array type in a docblock

Smell: An array with elements of generic type or method which can throw Exception

public function printUsersNames(array $users): void
{
    foreach ($users as $user) {
        echo $user->getName();
    }
}
  1. Refactor the code

    Add PHPDoc - the Object[] notation in addition to an array type-hint to explain what kind of object is expected

    /**
     * @param User[] $users
     */
    public function printUsersNames(array $users): void
    {
        foreach ($users as $user) {
            echo $user->getName();
        }
    }
    

1.3 Consolidate Conditional Expression

Smell: Sequence of conditionals with the same result

class Sale
{
    public function calculateShipping(Customer $customer)
    {
        if ($customer->isEmployee) return 0;
        if ($customer->isGoldCustomer) return 0;
        if ($customer->isHasACoupon) return 0;
        
        if($isUsa) return 10;
        if($isEurope) return 20;
    }
}

1.3.1 Write a test that pass

1.3.2 Refactor the code

Combine them into a single conditional expression and extract it.

class Sale
{
    public function calculateShipping(Customer $customer): int
    {
       if ($this->isFreeShipping()){
           return 0;
       }

        if($isUsa) {
            return 10;
        }

        if($isEurope) {
            return 20;
        }
    }

    private function isFreeShipping(): bool
    {
        return ($customer->isEmployee || $customer->isGoldCustomer || $customer->isHasACoupon);
    }
}

1.3.3 Pass a test

1.4 Consolidate Duplicate Conditional Fragments

Smell: The same fragment of code is in all branches of a conditional expression.

final class Sale
{
    public function calculateTotal(int $price)
    {
        if ($this->isSpecialDeal()) {
            $total = $price * 0.95;
            $this->setTotal($total);
        }
        else {
            $total = $price * 0.98;
            $this->setTotal($total);
        }
    }
}

1.4.1 Write a test that pass

1.4.2 Refactor the code

Move it outside of the expression.

final class Sale
{
    public function calculateTotal(int $price)
    {
        if ($this->isSpecialDeal()) {
            $total = $price * 0.95;
        }
        else {
            $total = $price * 0.98;
        }

        $this->setTotal($total);
    }
}

1.4.3 Pass a test

1.5 Decompose Conditional

Smell: Complicated conditional (if-else) statement.

class Sale
{
    public $expired_at;
    public $amount;

    public function getAmount()
    {
        if(null !== $this->expired_at && $this->expired_at < time())
        {
            $interest = 10;
            $this->amount = $this->amount + ($this->amount / 100 * $interest);
        }
        else
        {
            $discount = 10;
            $this->amount = $this->amount - ($this->amount / 100 * $discount);
        }
        return $this->amount;
    }
}

1.5.1 Write a test that pass

class SaleTest extends TestCase
{
    public function testAmount()
    {
        $sale = new Sale();
        $sale->amount = 10;
        $sale->expired_at = strtotime('-10 days');
        $this->assertEquals(10 + (10 / 100 * 10), $sale->getAmount());
        $sale = new Sale();

        $sale->amount = 10;
        $sale->expired_at = strtotime('+10 days');
        $this->assertEquals(10 - (10 / 100 * 10), $sale->getAmount());
    }
}

1.5.2 Refactor the code

Extract conditional code in a private method. We name the method isExpired() because our conditional chunk of code checks if the sale is expired. We create the private method isExpired() and, with the technique of extract method, we move chunks of code into the new method. The next step is to move each branch of the condition in a private method. We do the same as we did before for each branch. So we create the private method getAmountWithInterest() for the first branch and the method getAmountWithDiscount() for the second branch.

class Sale
{
    public $expired_at;
    public $amount;

    public function getAmount()
    {
        if ($this->isExpired()) {
            return $this->getAmountWithInterest();
        } else {
            return $this->getAmountWithDiscount();
        }
    }

    private function isExpired()
    {
        return !is_null($this->expired_at) && $this->expired_at < time();
    }

    private function getAmountWithInterest()
    {
        $interest = 10;
        return $this->amount + ($this->amount / 100 * $interest);
    }

    private function getAmountWithDiscount()
    {
        $discount = 10;
        return $this->amount - ($this->amount / 100 * $discount);
    }
}

1.5.3 Pass a test

1.6 Encapsulate Field

Smell: A public field

final class User
{
    /**
     * @var string
     */
    public $name;
}

1.6.1 Write a test that pass

1.6.2 Refactor the code

Make it private and provide accessors.

final class User
{
    /**
     * @var string
     */
    private $name;

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }
}

1.6.3 Run a test

1.7 Extract Class

SmellL Large Class

final class User
{
    private $name;
    private $surname;

    private $city;
    private $zipCode;
    private $street;
    private $state;
}

1.7.1 Write a test that pass

1.7.2 Refactor the code

Create a new class and move the relevant fields and methods from the old class into the new class.

final class User
{
    private $name;
    private $surname;

    private $address;
}

final class Address
{
    private $city;
    private $zipCode;
    private $street;
    private $state;
}

1.7.3 Pass a test

1.8 Inline Class

Smell: A class isn't doing very much

final class User
{
    private $name;
    private $surname;

    private $telephoneNumber;
}

final class TelephoneNumber
{
    private $number;
}

1.9 Introduce Parameter Object

Smell: Long Parameter List and parameters that naturally go together

final class Account
{
    public function findAllTransactions(DateTime $start, DateTime $end)
    {
        ...
    }
}

1.9.1 Write a test that pass

1.9.2 Refactor the code

Replace them with an object. #+BEGINSRC php#+ENDSRC

1.9.3 Pass a test

1.10 Optimize Imports

Smell: Imports unused or not in alphabetically order. Multiple use statement

use SomeClass\Worker;
use SomeClass\Foo;
use SomeClass\UnusedClass;

1.10.1 Write a test that pass

1.10.2 Refactor the code

Remove unused imports. Sort imports alphabetically (ascending order). Splits multiple use statement imports into single use statement imports

use SomeClass\{Foo, Worker};

1.10.3 Pass a test

1.11 Move Method

Smell: Method accessing fields and methods in different class

final class Customer
{
    function printInvoice(Order $order)
    {
        echo "Invoice {$order->getId()}";
        echo "Date: {$order->getDate()}";
        echo "Customer: {$this->getName()}";

        $address = $order->getAddress();
        echo "City: {$address->getCity()}";
        echo "Address: {$address->getStreet()}";

        foreach ($order->getItems() as $item){

            echo "Name: {$item->getName()}";
            echo "Price: {$item->getPrice()}";
        }
    }
}   

1.11.1 Write a test that pass

1.11.2 Refactor the code

Move all its features into another class and delete it.

final class Order
{
    function printInvoice()
    {
        echo "Invoice {$this->getId()}";
        echo "Date: {$this->getDate()}";
        echo "Customer: {$this->getCustomer()->getName()}";

        $address = $this->getAddress();
        echo "City: {$address->getCity()}";
        echo "Address: {$address->getStreet()}";

        foreach ($this->getItems() as $item){

            echo "Name: {$item->getName()}";
            echo "Price: {$item->getPrice()}";
        }
    }
}

1.11.3 Pass a test

1.12 Parameterize Method

Smell: Several methods do similar things but with different values contained in the method body.

final class Employee
{
    /**
     * @var float
     */
    private $salary;

    public function setSalary(float $salary)
    {
        $this->salary = $salary;
    }

    public function getSalary(): float
    {
        return $this->salary;
    }

    public function fivePercentRaise()
    {
        $this->salary += $this->salary* (5 / 100);
    }

    public function tenPercentRaise()
    {
        $this->salary += $this->salary* (10 / 100) ;
    }
}

1.12.1 TODO Write a test that pass

1.12.2 Refactor the code

Create one method that uses a parameter for the different values.

final class Employee
{
    /**
     * @var float
     */
    private $salary;

    public function setSalary(float $salary)
    {
        $this->salary = $salary;
    }

    public function getSalary(): float
    {
        return $this->salary;
    }

    public function raise(float $percent)
    {
        $this->salary += $this->salary * ($percent / 100);
    }
}

1.12.3 Pass a test

1.13 Preserve Whole Object

Smell: More than one value from an object are passing as parameters in a method call

class September
{
    /**
     * @var float
     */
    private $highestTemp;

    /**
     * @var float
     */
    private $lowestTemp;

    public function __construct(float $highestTemp, float $lowestTemp)
    {
        $this->highestTemp = $highestTemp;
        $this->lowestTemp = $lowestTemp;
    }

    public function getHighestTemp(): float
    {
        return $this->highestTemp;
    }

    public function getLowestTemp(): float
    {
        return $this->lowestTemp;
    }
}

class Calculator
{
    public function calculateAverageTemperature(float $highestTemp, float $lowestTemp)
    {
        return ($highestTemp + $lowestTemp) / 2;
    }
}

$september = new September(15,5);
$calculator = new Calculator();

$averageTemperature = $calculator->calculateAverageTemperature(
            $september->getHighestTemp(),
            $september->getLowestTemp()
        );

1.13.1 Write a test that pass

public function testCalculateAverageTemperature()
{
        $september = new September(15,5);
        $calculator = new Calculator();

        $averageTemperature = $calculator->calculateAverageTemperature(
            $september->getHighestTemp(),
            $september->getLowestTemp());

        $this->assertEquals(10, $averageTemperature);
}

1.13.2 Refactor the code

Add object as a new parameter. Set it default value to null, that will help to manage the transitions towards the final version of the method.

class Calculator
{
    public function calculateAverageTemperature(float $highestTemp, float $lowestTemp, September $september = null)
    {
        return ($highestTemp + $lowestTemp) / 2;
    }
}

1.13.3 Pass a test

1.13.4 Refactor the code

Replace values with values coming from the whole object

class Calculator
{
    public function calculateAverageTemperature(float $highestTemp, float $lowestTemp, September $september = null)
    {
        return ($september->getHighestTemp() + $september->getLowestTemp()) / 2;
    }
}

1.13.5 Pass a test

1.13.6 Refactor the code

Remove useless parameters and default null value of $september object

class Calculator
{
    public function calculateAverageTemperature(September $september)
    {
        return ($september->getHighestTemp() + $september->getLowestTemp()) / 2;
    }
}

1.13.7 Pass a test

1.14 Pull Up Method

Smell: Subclasses have the same method.

class Employee
{
    /**
     * @var string
     */
    protected $name;
    
    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

final class Salesman extends Employee
{
    public function getName()
    {
        return $this->name;
    }
}

final class Engineer extends Employee
{
    public function getName()
    {
        return $this->name;
    }
}

1.14.1 Write a test that pass

1.14.2 Refactor the code

Move the methods to the super class.

class Employee
{
    /**
     * @var string
     */
    protected $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }
}

final class Salesman extends Employee {}

final class Engineer extends Employee {}

1.14.3 Pass a test

1.15 Remove Assignments to Parameters

Smell: Reassign to a parameter

public function discount(int $priceTotal): int
{
    if ($priceTotal > 100) {
        $priceTotal = $priceTotal - 10;
    }
    
    return $priceTotal;
}  

1.15.1 Write a test that pass

1.15.2 Refactor the code

Use a temporary variable instead

public function discount(int $priceTotal): int
{
    $result = $priceTotal;

    if ($priceTotal > 100) {
        $result = $result - 10;
    }

    return $result;
}

1.15.3 Pass a test

1.15.4 Info

The best practice is that if you pass parameters into a method then they should always represent what were passed in and never be reassigned to mean something else. Btw. in Java you can prevent variable’s reassignment by keyword 'final' before a parameter https://stackoverflow.com/questions/500508/why-should-i-use-the-keyword-final-on-a-method-parameter-in-java

1.16 Remove PHPDoc

Smell: PHPDoc is duplicating type-hint information Damage: Adds information which not provides additional value

/**
 * @param int $number
 * @return void
 */
public function setNumber(int $number): void
{
    $this->number = $number;
}  

1.16.1 Write a test that pass

1.16.2 Refactor the code

Remove PHPDoc if it's not provides additional value


1.16.3 Pass a test

1.17 Rename Function

Alias: Rename Method, Change Function Declaration Smell: The name of a method does not reveal it's purpose1

public function getInvcdtlmt()

1.17.1 Write a test that pass

1.17.2 Refactor the code

Change the name of the method

public function getInvoiceableCreditLimit()

1.17.3 Pass a test

1.18 Replace Global with Dependency Injection

Smell: Variable with 'global' keyword

final class Item
{
    public function fetch()
    {
        global $db;
        return $db->query(...);
    }
}

1.18.1 Write a test that pass

1.18.2 Refactor the code

Move global variable in class to the constructor

final class Item
{
    /**
     * @var Database
     */
    private $db;

    public function __construct(Database $db)
    {
        $this->db = $db;
    }

    public function fetch()
    {
        return $db->query(...);
    }
}

1.18.3 Pass a test

1.19 Replace Magic Number With Symbolic Constant

Smell: Number with a particular meaning

final class Circle
{
    /**
     * @var float
     */
    private $radius;
    
    public function __construct(float $radius)
    {
        $this->radius = $radius;
    }
    
    public function getCircumference(): float
    {
        return $this->radius * 2 * 3.1416;
    }
}

1.19.1 Write a test that pass

use PHPUnit\Framework\TestCase;

class CircleTest extends TestCase
{   
    public function testGetCircumference()
    {
        $circle = new Circle(2);
        $this->assertEquals(12.5664, $circle->getCircumference());
    }
}
PHPUnit 7.5.2 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 151 ms, Memory: 10.00MB

OK (1 test, 1 assertion)

1.19.2 Refactor the code

Create a constant, name it after the meaning, and replace the number with it

final class Circle
{
    /**
     * @var float
     */
    private const PI = 3.1416;

    /**
     * @var float
     */
    private $radius;

    public function __construct(float $radius)
    {
        $this->radius = $radius;
    }

    public function getCircumference(): float
    {
        return $this->radius * 2 * self::PI;
    }
}

1.19.3 Run a test

1.19.4 Helper:

PHP Magic Number Detector is a tool to detect magic numbers in your PHP code

1.20 Replace Parameter with Method

Smell: A method runs different code depending on the values of parameters

final class EmailNotification
{
    public function send(string $to, string $body, string $from = null)
    {
        if($from){
            $this->mailer->send($to, $body, $from);
        }else{
            $this->mailer->send($to, $body, $this->defaultSender);
        }
    }
}

1.20.1 Write a test that pass

1.20.2 Refactor the code

Create a separate method for each value of the parameter

final class EmailNotification
{
    public function send(string $to, string $body, string $from)
    {
        $this->mailer->send($to, $body, $from);
    }
    
    public function sendFromDefaultSender(string $to, string $body)
    {
        $this->mailer->send($to, $body, $this->defaultSender);
    }
}

1.20.3 Pass a test

1.21 Replacing Type Code with Subclasses

Smell: Immutable type code affecting the class behavior.

final class Account
{
    /**
     * @var int
     */
    private $accountType;

    /**
     * @var float
     */
    private $balance;

    /**
     * @var int
     */
    public const CHECKING = 0;

    /**
     * @var int
     */
    public const SAVINGS = 1;

    /**
     * @var int
     */
    public const INVESTMENT = 2;

    public function __construct(int $accountType)
    {
        $this->accountType = $accountType;
    }

    public function getAccountType(): int
    {
        return $this->accountType;
    }

    public function getBalance(): float
    {
        return $this->balance;
    }

    public function withdraw(float $amount): void
    {
        switch ($this->accountType){
            case self::CHECKING:
                $this->balance -= $amount;
                break;
            case self::SAVINGS:
                $this->balance -= $amount + 100;
                break;
            case self::INVESTMENT:
                $this->balance -= $amount + 300;
                break;
            default:
                throw new RuntimeException('Unknown Account Type');
        }
    }
}

1.21.1 Write a test that pass

1.21.2 Refactor the code

Replace the type code with subclasses.

abstract class Account
{
    /**
     * @var float
     */
    private $balance;

    public function getBalance(): float
    {
        return $this->balance;
    }
    
    abstract public function withdraw(float $amount): void
}

final class AccountChecking extends Account
{
    public function withdraw(float $amount): void
    {
        $this->balance -= $amount;
    }
}

final class AccountSavings extends Account
{
    public function withdraw(float $amount): void
    {
        $this->balance -= $amount + 100;
    }
}

final class AccountInvestment extends Account
{
    public function withdraw(float $amount): void
    {
        $this->balance -= $amount + 300;
    }
}

1.21.3 Pass a test

1.22 Separate Query from Modifier

Smell: A method that returns a value but also changes the state of an object.

final class Account
{
    /**
     * @var float
     */
    private $balance;
    
    public function withdrawAndGetBalance(float $amount): float
    {
        $this->balance -= $amount;
        return $this->balance;
    }
}

1.22.1 Write a test that pass

1.22.2 Refactor the code

Create two methods, one for the query and one for the modification.

final class Account
{
    /**
     * @var float
     */
    private $balance;

    public function getBalance(): float
    {
        return $this->balance;
    }

    public function withdraw(float $amount): void
    {
        $this->balance -= $amount;
    }
}

1.22.3 Pass a test

1.23 Split Temporary Variable

Smell: Temporary variable is assigned to more than once (overwrite), but is not a loop variable nor a collecting temporary variable.

$temp = $itemPrice * $itemQuantity;
echo "Total: $temp";
$temp = $orderTotal - $orderDiscount;
echo "Price after discount: $temp;"

1.23.1 Write a test that pass

1.23.2 Refactor the code

Make a separate temporary variable for each assignment.

$totalPrice = $itemPrice * $itemQuantity;
echo "Total: $totalPrice";
$totalDiscountPrice = $orderTotal - $orderDiscount;
echo "Price after discount: $totalDiscountPrice";

1.23.3 Pass a test

2 Tutorials

2.1 Anti OOP

2.1.1 Stop Writing Classes

  • namespaces are for preventing name collisions, not for creating taxonomies

2.2 Functional

  1. Marco Pivetta – From helpers to middleware
  2. https://gist.github.com/adaburrows/941874
  3. Functional Programming with PHP
    1. avg of an array of numbers
      imperative - how to get result? declarative - what is it?
      - set x equal to zero x is the sum of all numbers in the array, divided bt the length of array
      - add the first number in the array to x  
      - repeat step 2 for the rest of the numbers in the array  
      - divide x by the length of the array  
    2. core concepts
      1. immutability

        state change - when program contains variables that are all constantly changing at different times, it can be very hard to know what state a program is in at any given point in time. FP. on the other hand starts off with immutable set of data as a single source of truth, and the uses functions to combine this data piece by piece and transform it into useful information.

      2. separating functions and data
      3. first-class functions
    3. advanced functional concepts
      1. recursion
      2. partial application
      3. composition
    4. notes

      #+beginsrc php $divide = function($x, $y) { return $x / $y; };

      $secondargisntzero = function($func) { return function(…$args) use ($func) { if ($args[1] == 0) { echo "Cannot divide by zero!\n"; return null; }

      return $func(…$args); }; };

      $dividesafe = $secondargisntzero($divide);

      echo $dividesafe(10, 0) . "\n"; #+endsrc>

2.4 Refactoring

2.4.1 Catalog of Refactorings Martin Fowler

2.4.2 Detecting Code Smells Patkós Csaba

2.4.3 How to Refactor Like a Boss 1 Michael Cheng

2.4.4 How to Refactor Like a Boss 2 Michael Cheng

2.4.5 Techniques for Refactoring Code Patkós Csaba

2.4.7 Refactoring 101 Adam Culp

2.4.8 Refactoring Legacy Code Patkós Csaba

2.4.9 Refactoring Legacy Code Adam Culp

2.4.11 Refactoring Done Right - Brandon Savage

  • what are we looking for ?
    • messy & overly complex code, code style, solid violations, dead code
    • code is meant to be read by humans

2.4.12 Refactoring to Collections Adam Wathan collections

2.4.13 Java: Refactoring to Design Patterns By Andrejs Doronins

2.4.14 IN-PROGRESS Java Refactoring: Best Practices By Andrejs Doronins

  • main programming activity
    • reading
    • writing
    • changing
  • without refactoring
    • productivity decreases
      • duplicated code accumulates
      • logic become more complex
      • code is difficult to understand
  • reasons for technical debt
    • not enough exp to code well
    • lazy coding
    • tight deadlines
  • boy scout rule : leave the (campground) code cleaner than you found it.
  • don't remove technical debt if:
    • current code dosent work
    • deadliness must be met
    • it results in gold-plating

2.4.15 Java: Writing Readable and Maintainable Code

2.4.16 Legacy Coderetreat (Java) Adrian Bolboaca

2.4.17 Philippe Bourgau - Live Legacy Code Refactoring with the Golden Master

2.4.18 Anna Filina - Rewriting Legacy Code

  • null pointer exception
  • rewrite fail
    • starts with a lot of fancy stuff
    • too often tool selection for re-writes are based on what will look good on the CV rather than what is really needed. If you start that way you are almost certain to fail. Especialy if you switch from using none of fancy tech to use it all at once

2.4.19 Christophe Thibaut - Stop managing technical debt and start solving problems again

  • technical debt - state of solution that is being build on or maintained with conflicting heuristics
  • bk. Koen, Billy Vaughn, Discussion of the Method: Conducting the Engineer’s Approach to Problem Solving
  • there is no such a thing like best practise there is alwayas a practice in a context

2.5 Delete

2.5.1 Greg Young - The art of destroying software

creating code refactoring code deleting code

delete ability small programs unix philospohy rewrite ability alan kay object orientation diff great & sucky code is size of the program good code - small isolated programs that can be deleted on the fly

2.6 Testing

2.6.1 Automated Tests with PHPUnit Anna Filina

2.6.2 HTTP Smoke Testing Peter Heinz

2.6.4 PHP: Testing Legacy Applications Chris Hartjes

2.7 Patterns

2.7.1 Catalog of Refactoring to Patterns Joshua Kerievsky

2.7.2 Encapsulation and SOLID Mark Seemann

2.8 Database

2.8.1 Doctrine Best Practices Marco Pivetta (Ocramius)

  • entities mostly represent your domain
  • define entities, after that define database
  • disallow collection access from outside the entity
  • soft-deletes
  • query functions are better than repositories
  • separate Repository#get() & Repository#find()
    • find() can return null
    • get() cannot return null - throw an exception

2.8.2 Solving the N+1 Problem Paul M. Jones

2.9 Clean Code PHP Piotr Plenik

2.11 Extremely Defensive PHP Programming Marco Pivetta (Ocramius)

  • poka yoka
  • code is not reusable - do not trust the code.
  • abstractions are reusable - you trust interfaces, how the code should behave
  • ex. with req

2.12 PHPUnit: Testing with a Bite

2.12.1 3 Types of Tests

  1. Unit Test - Test one specific function on a class. Fake any needed database connecnions.
  2. Integration Test - Just like unit test, except it use the real database connection.
  3. Functional Test - Write a test to programmatically command a browser

2.12.2 How much should I be testing my code?

If the feature scares you then test it! Too many tests = wasted time, add little value, slow you down

2.12.3 TDD

  1. Create the test
  2. Write just enough code for the test to pass
  3. Refactor your code

2.13 Test Automation Foundations

  • Automated testing follows the same steps as manual testing, but it's much quicker. While there is an initial time investment to write the scripts, once the scripts are complete they can be run repeatedly without much additional cost.
  • There will be maintenance that is required, but it saves time in the long run. This makes automation have a great return on investment. In addition, the exact same steps are executed every time, which reduces any possibility of human error.
  • Agile Testing Quadrants
  • Test Pyramid

2.14 Clean Application Development Adam Culp

bad code:

  • is easy
  • fast

    result:

  • wasted time
  • bugs
  • excessive debugging
  • procrastination
  • missed deadlines
  • technical debt
  • financial losses
  • company killer
  • I didn't write it!

Names should be clear - functions and variables should tell a story $elapsed -> $elapsedTimeInDays

Class - nouns - Describe ex - Customer, Account, Product, Company Method - verbs - getCustomer, closeAccount, updateProduct, addCompany Function - 20 lines - 10 lines

Recognizing bad dosen't mean we know how to make good - we know a good/bad, but are not song writers

smells - are indications of problems in your code

CodeSniffer

2.16 Agile is Dead • Pragmatic Dave Thomas

  1. agile is adjective not noun
  2. No Rules Are Universal. All Rules Need Context. All rules are contextual.
  3. Agile is not what you do. Agility is how you do it.
  4. If you about to jump put of airplane for the first time you don't care about the theory of aerodynamics you what to know what you pull and when

2.17 Beautiful Models in PHP

  • model - method of representing data in a logical way
    • sometimes map directly to a database table - a lot of times they don't
    • may not have databases at all

2.18 Symfony

2.18.2 Upgrade to Symfony4 and Flex!

  1. Upgrade to Symfony 3.4
  2. See depractions in toolbar
    1. remove $kernel->loadClassCache(); from app.php & appdev.php
    2. "Symfony\Component\Security\Guard\AuthenticatorInterface::supports()"
    3. logoutonuserchange

2.18.3 Symfony 5

2.20 BDD

2.20.1 BDD, Behat, Mink and other Wonderful Things

  • Write the behavior for a feature first
  • Code until the behavioral tests pass
  1. Two types of BDD
    1. Story: is done with Behat & functional tests
    2. Spec: is done with PHPSpec & Unit tests
  2. 4 Steps to BDD
    1. Define Business Value of all big features
    2. Prioritize your features
    3. Break feature down into user stories
    4. Write the code for the feature

2.20.4 Behavior-Driven Development

  1. The 5 Ws
    1. As (who, what or where)
    2. I (want)
    3. because (why)

      Example: Who - as a user of Acme.com What - I want to access content on my mobile phone Why - because I might not always have a computer available

      https://cucumber.io/training -> 3 youtube

  2. Throw Over the Wall
    1. Developers would coe and then throw it over the wall for someone else to test
  3. After BDD Transformation
    1. testing cycle went down
    2. defect count went down
    3. time to market went down
    4. team's confidence in code increased and anxiety decreased
    5. manual testing cost went down

      "The hardest part of building a software system is deciding precisely what to build." - Fred Brooks

      If you're having trouble, example mapping helps us keep these conversations short and on track by creating a visual representation of a user story to guide and document the discussion. The process of example mapping is fairly straightforward. Using a four-color pack of index cards, we build a visual representation of our user's story with each color providing a specific piece of information. We build this as we have our conversation to document what is discovered through the discussion about the user's story.

      We begin with a yellow card, which contains the name of our story itself and place this at the very top. Our blue cards represent specific rules that constrain the scope of our story. This is our acceptance criteria. With green cards, we provide concrete examples of the user's story in the context of a specific rule. So we place these under the relevant blue card. And finally, we have our red cards. These cards contain questions that cannot be immediately answered during the discussion, but are captured so that we can move on with the conversation.

    6. Acceptance criteria
      1. addresses what defines a working system
      2. written as pass/fail
    7. Scenario
      1. defines the initial conditions for acceptance criteria
      2. states the trigger of scenario and expected outcome
  4. Gherkin Syntax
    1. Feature: feature story - name of the feature and possibly brief description
      1. Scenario: a user story - single concrete example of how a system should behave - each feature generally have 5-20 scenarios - Scenarios describe the behaviour of the system under specific initial conditions.
      2. Given: some set of initial conditions - describe the context or precondition for the scenario
      3. When: an event occurs - identifies an event or actor enacted by some actor on the system
      4. Then: an outcome is expected - provides the expected outcome to the scenario
  5. Example
    1. Feature : Customer pays with a credit card
      1. As a sales associate
      2. I should be able to process payments
      3. when given a credit card

        Now we're ready to translate our conversation into scenarios that describe the concrete behavior of the application. Ideally, this is done using declared dephrasing, meaning without referencing the particulars of a user interface or sequence of steps. Remember that Gherkin is a way to phrase our acceptance criteria as an executable scenario that describes the behavior of a system. So, our conversations would describe the behavior of the system under specific initial conditions.

      4. Scenario 1
        1. Total charge is over the $2 credit card minimum.
        2. Given: Maria orders $3 of coffee from Li.
        3. When: Maria pays with a credit card.
        4. Then: Lit should process the payment.
      5. Scenario 2
        1. Total charge is under the $2 credit card minimum.
        2. Given: Maria orders $1 of coffee from Li.
        3. When: Maria pays with a credit card.
        4. Then: Li should not process the payment.
  6. Test Automation

    Allows for the execution of software tests that compare the expectations for software with the actual outcomes. Testing can be repetitive process and automation can be a boon to productivity.

  7. Living Documentation

    Is a system for dynamically generating documentation that contains information which is up to date and accurate. Cucumber provides a system that dynamically generates documentation because of the manner that tests are written. Because Cucumber tests are written in a way that can be easily interpreted by non-technical stakeholders and, at the same time, be executed by a computer, your tests themselves become a living source of documentation that reflect the accuracy of your application. Cucumber was designed to enhance the practice of test-driven development. It provides a single source of truth for an application's lifecycle by merging test automation and test documentation.

  8. Further
    1. https://cucumber.io/school
    2. https://cucumber.io/training
    3. BDD in Action by John Ferguson Smart
    4. The Cucomber Book by Aslak Hellesoy…
  9. Notes
    1. BDD is a process, not a tool
    2. Specialized frameworks can assist in this process by providing a common language for acceptance criteria.

      To types of BDD:

      1. Story - is done with Behat & functional tests
      2. Spec - is done with PHPSpec & Unit tests

      4 Steps to BDD 1.Define Business Value of all big features 2.Prioritize you features 3.Break feature down into user stories 4.Write the code for the feature

      https://github.com/Behatch/contexts

3 Books

3.2 Refactoring

3.2.1 Michael Feathers

  1. nil
    • To me, legacy code is simply code without tests. I’ve gotten some grief for this definition. What do tests have to do with whether code is bad? To me, the answer is straightforward, and it is a point that I elaborate throughout the book: 'Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.'
    • being able to confidently make changes in any code base.
    • Preserving existing behavior
    • Changes in a system can be made in two primary ways. I like to call them Edit and Pray and Cover and Modify. Unfortunately, Edit and Pray is pretty much the industry standard. When you use Edit and Pray, you carefully plan the changes you are going to make, you make sure that you understand the code you are going to modify, and then you start to make the changes. When you’re done, you run the system to see if the change was enabled, and then you poke around further to make sure that you didn’t break anything. The poking around is essential. When you make your changes, you are hoping and praying that you’ll get them right, and you take extra time when you are done to make sure that you did.
    • …testing is a tough problem, and people are often seduced by the idea that they can test through a GUI or web interface without having to do anything special to their application. It can be done, but it is usually more work than anyone on a team is prepared to admit. In addition, a user interface often isn’t the best place to write tests. UIs are often volatile and too far from the functionality being tested. When UI-based tests fail, it can be hard to figure out why. Regardless, people often spend considerable money trying to do all of their testing with those sorts of tools.
    • Pay now or pay more later

    [copied from somesite] Exploratory Refactoring: the recipe When you feel stuck because you don't understand what the code is doing, here's what you can do: Take a breath, there is a way out and you're about to find it Reset your git status to start fresh (git reset –hard or git stash will do) Set up a timer for 30 minutes Refactor the code freely, don't worry if the code still compiles, just go ahead and change it Throw away your changes when the timer rings! Just do it: git reset –hard Take a break, go drink some water and think about what you just learned

  2. LOOKING-FOR Brutal Refactoring: More Working Effectively with Legacy Code

3.2.2 Refactoring in Large Software Projects 2006

3.2.3

William J. Brown, Raphael C. Malveau, Hays W. "Skip" McCormick, Thomas J. Mowbray

3.2.4 Phillip A. Laplante, Colin J. Neill Antipatterns: Identification, Refactoring, and Management 2005

3.2.5

Catalog of smells. Focus on smell point of view. Also they introduce smell classification scheme, naming scheme for design smells which helps to increase awerness of smells. So definetly must read. (Java)

http://www.designsmells.com/

bk. Unbuilding Cities: Obduracy in Urban Sociotechnical Change 2008

Object-Oriented Reengineering Patterns

https://en.wikipedia.org/wiki/Lehman%27slawsofsoftwareevolution

As a program is evolved its complexity increases unless work is done to maintain or reduce it. Lehman’s law of Increasing Complexity [1]

Borrowing a phrase from the health care domain “a good doctor is one who knows the medicines but a great doctor is one who knows the disease”

Grady Booch

We believe that the impact of a smell can only be judged based on the design context in which it occurs.

However, today, software engineers are expected to build really complex software within a short time frame in an environment where requirements are continuously changing. Needless to say, it is a huge challenge to maintain the quality of the design and overall software in such a context.

In the midst of this struggle, it became clear to us that if we wanted to organize this collection so that we could share it in a beneficial manner with fellow architects, designers, and developers, our classification scheme should be linked to something fundamental, i.e., design principles.

  1. design smells?

    Design smells are certain structures in the design that indicate violation of fundamental design principles and negatively impact design quality. In other words, a design smell indicates a potential problem in the design structure. The medical domain provides a good analogy for our work on smells. The symptoms of a patient can be likened to a “smell,” and the underlying disease can be likened to the concrete “design problem.”

  2. technical debt

    Technical debt is the debt that accrues when you knowingly or unknowingly make wrong or non-optimal design decisions. Technical debt is a metaphor coined by Ward Cunningham in a 1992 report [44]. Technical debt is analogous to financial debt. When a person takes a loan (or uses his credit card), he incurs debt. If he regularly pays the installments (or the credit card bill) then the created debt is repaid and does not create further problems. However, if the person does not pay his installment (or bill), a penalty in the form of interest is applicable and it mounts every time he misses the payment. In case the person is not able to pay the installments (or bill) for a long time, the accrued interest can make the total debt so ominously large that the person may have to declare bankruptcy.

    • Code debt: Static analysis tool violations and inconsistent coding style. • Design debt: Design smells and violations of design rules. • Test debt: Lack of tests, inadequate test coverage, and improper test design. • Documentation debt: No documentation for important concerns, poor docu- mentation, and outdated documentation.

    Jim Highsmith [45] describes how Cost of Change (CoC) varies wth technical debt.

    congitive load

  3. smells
      structural behavioral
    architecture    
    design X  
    implementation    
  4. PHAME

    We treat the four major elements of Booch’s object model as “design principles” and refer to them collectively as PHAME (Principles of Hierarchy, Abstraction, Modularization, and Encapsulation).

  5. Booch’s fundamental design principles
    1. abstraction

      The principle of abstraction advocates the simplification of entities through reduction and generalization: reduction is by elimination of unnecessary details and generalization is by identification and specification of common and important characteristics.

      1. Missing Abstraction

        Clumps of data or encoded strings are used instead of creating a class or an interface

        1. Rationale
          • It can expose implementation details to different abstractions, violating the principle of encapsulation.
          • When data and associated behavior are spread across abstractions, it can lead to tight coupling between entities, resulting in brittle and non-reusable code. Hence, not creating necessary abstractions also violates the principle of modularization.
        2. Potential Causes
          1. Inadequate design analysis

            When careful thought is not applied during design, it is easy to overlook creating abstractions and use primitive type values or strings to “get the work done.” In our experience, this often occurs when software is developed under tight deadlines or resource constraints.

          2. Lack of refactoring

            As requirements change, software evolves and entities that were earlier represented using strings or primitive types may need to be refactored into classes or interfaces. When the existing clumps of data or encoded strings are retained as they are without refactoring them, it can lead to a Missing Abstraction smell.

          3. Misguided focus on minor performance gains

            This smell often results when designers compromise design quality for minor performance gains. For instance, we have observed developers using arrays directly in the code instead of creating appropriate abstractions since they feel that indexing arrays is faster than accessing members in objects. In most contexts, the performance gains due to such “optimizations” are minimal, and do not justify the resultant trade-off in design quality. https://steemit.com/php/@crell/php-use-associative-arrays-basi

        3. Examples
          1. from, to

            data clumps always used together

        4. Refactor

          create abstraction(s) that can internally make use of primitive type values or strings.

        5. Alias
          1. Primitive Obsession

            This smell occurs when primitive types are used for encoding dates, currency, etc. instead of creating classes.

          2. Data clumps

            This smell occurs when there are clumps of data items that occur together in lots of places instead of creating a class.

      2. Imperative Abstraction

        This smell arises when an operation is turned into a class. This smell manifests as a class that has only one method defined within the class. At times, the class name itself may be identical to the one method defined within it. For instance, if you see class with name Read that contains only one method named read() with no data members, then the Read class has Imperative Abstraction smell. Often, it is also seen in the case of this smell that the data on which the method operates is located within a different class. It should be noted that it is sometimes desirable to turn an operation into a class.

        1. Rationale

          Defining functions or procedures explicitly as classes (when the data is located somewhere else) is a glorified form of structured programing rather than object-oriented programming. One-operation classes cannot be representative of an “abstraction,” especially when the associated data is placed somewhere else. Clearly, this is a violation of the principle of abstraction. Since these classes are ‘doing’ things instead of ‘being’ things, this smell is named Imperative Abstraction. If operations are turned into classes, the design will suffer from an explosion of one-method classes and increase the complexity of the design. Furthermore, many of these methods that act on the same data would be separated into different classes and thus reduce the cohesiveness of the design. For these reasons, this smell also violates the principles of encapsulation and modularization. The smell not only increases the number of classes (in this case there are at least four classes when ideally one could have been used), but also increases the complex- ity involved in development and maintenance because of the unnecessary separation of cohesive methods.

        2. Potential Causes
          1. procedural thinking
        3. Refactor

          To refactor the Imperative Abstraction design smell, you have to either find or create an appropriate abstraction to house the method existing within the Imperative Abstraction. You also have to encapsulate the data needed by the method within the same abstraction to improve cohesion and reduce coupling.

        4. Reification

          is the promotion or elevation of something that is not an object into an object. When we reify behavior, it is possible to store it, pass it, or transform it. Reification improves flexibility of the system at the cost of introducing some complexity [52]. Many design patterns [54] employ reification. Examples:

          • State pattern: Encoding a state-machine.

          • Command pattern: Encoding requests as command objects. A permitted exception for this smell is when a Command pattern has been used to objectify method requests.

          • Strategy pattern: Parameterizing a procedure in terms of an operation it uses.

          In other words, when we consciously design in such a way to elevate non-objects to objects for better reusability, flexibility, and extensibility (i.e., for improving design quality), it is not a smell.

        5. Aliases

          “Operation class” ??? [51,52] — This smell occurs when an operation that should have been a method within a class has been turned into a class itself.

      3. Incomplete Abstraction

        An abstraction (entity or interface) does not support complementary or interrelated methods completely For example, if we need to be able to add or remove elements in a data structure, the type abstracting that data structure should support both add() and remove() methods. Supporting only one of them makes the abstraction incomplete

        Min/max Open/close Create/destroy Get/set
        Read/write Print/scan First/last Begin/end
        Start/stop Lock/unlock Show/hide Up/down
        First/last Push/pull    
        Enable/disable Left/right On/off  

        Sometimes, a designer may make a conscious design decision to not provide symmetric or matching methods. For example, in a read-only collection, only add() method may be provided without the corresponding remove() method. In such a case, the abstraction may appear incomplete, but is not a smell.

        1. Aliases

          This smell is also known in literature as:

          • “Class supports incomplete behavior” [18]—This smell occurs when the public interface of a class is incomplete and does not support all the behavior needed by objects of that class.

          • “Half-hearted operations” [63]—This smell occurs when interrelated methods provided in an incomplete or in an inconsistent way; this smell could lead to runtime problems.

      4. Multifaceted Abstraction

        This smell arises when an abstraction has more than one responsibility assigned to it.

        In particular, the Single Responsibility Principle says that an abstraction should have a single well-defined responsibility and that responsibility should be entirely encapsulated within that abstraction.

        Since the abstraction has multiple “faces” or “responsibilities”, it is named Multifaceted Abstraction.

        Single “Responsibility” Principle) does not mean logical grouping of all functionality related to a concept. Rather “responsibility” refers to a concrete, specific, and precise responsibility that has one reason to change

        1. Potential Causes
          1. General-purpose abstractions

            An abstraction with a generic name (Node , Component, Element, and Item ), it often becomes a “placeholder” for providing all the functionality related (but not necessarily belonging) to that abstraction. Hence, general purpose abstractions often exhibit this smell.

          2. Evolution without periodic refactoring

            When a class undergoes extensive changes over a long period of time without refac- toring, other responsibilities start getting introduced in these classes and design decay starts. In this way, negligence toward refactoring leads to the creation of monolithic blobs that exhibit multiple responsibilities.

          3. The burden of processes

            Sometimes the viscosity of the software and environment serves to discourage the adoption of good practices.

          4. Mixing up concerns
        2. Example

          Classes exhibiting Multifaceted Abstraction are usually large and complex. For example, java.util.Calendar class (in JDK 7) spans 2825 lines of code and has 67 methods and 71 fields! However, large or complex implementation is not an essential characteristic of classes having Multifaceted Abstraction smell; see the discussion on Insufficient Modularization smell (Section 5.2).

        3. Aliases

          • “Divergent change” [7]—This smell occurs when a class is changed for different reasons.

          • “Conceptualization abuse” [30]—This smell occurs when two or more noncohesive concepts have been packed into a single class of the system.

          • “Large class” [7,24,57,58]—This smell occurs when a class has “too many” responsibilities.

          • “Lack of cohesion” [59]—This smell occurs when there is a large type in a design with low cohesion, i.e., a “kitchen sink” type that represents many abstractions.

      5. Unnecessary Abstraction

        An abstraction that is not needed

        ALIASES: Irrelevant class - class does not have any meaningful behavior in the design Lazy class / Freeloader — class does “too little” Small class - class has no (or too few) variables or no (or too few) methods in it Mini-class - a public, non-nested class defines less than three methods and less than three attributes (including constants) in it No responsibility - class has no responsibility associated with it Agent classes - class serve as an “agent” (i.e., they only pass messages from one class to another), indicating that the class may be unnecessary

      6. Unutilized Abstraction

        An abstraction is left unused (either not directly used or not reachable). This smell manifests in two forms:

        • Unreferenced abstractions—Concrete classes that are not being used by anyone • Orphan abstractions—Stand-alone interfaces/abstract classes that do not have any derived abstractions

        This smell violates the principle YAGNI (You Aren’t Gonna Need It), which recommends not adding functionality until deemed necessary [53]

        When an abstraction is left unused in design, it does not serve a meaningful purpose in design, and hence violates the principle of abstraction.

        POTENTIAL CAUSES: Leftover garbage during maintenance or refactoring. Speculative generality - abstractions are introduced speculating that they may be required sometime in future.

        REFACTORING: remove the Unutilized Abstraction from the design.

        IMPACT: pollutes the design space and increases cognitive load. This impacts understandability. UNUTILIZED ABSTRACTION Two or more abstractions have identical names or identical implementation or both

        POTENTIAL CAUSES:

        Copy-paste programming The “get-the-work-done” mindset of a programmer leads him to copy and paste code instead of applying proper abstraction. Ad hoc maintenance When the software undergoes haphazard fixes or enhancements over many years, it leaves “crufts”6 with lots of redundant code in it. Lack of communication Often, in industrial software, code duplication occurs because different people work on the same code at different times in the life cycle of the software. They are not aware of existing classes or methods and end up re-inventing the wheel.

        REFACTORING: For identical name form, the suggested refactoring is to rename one of the abstrac- tions to a unique name. In the case of the identical implementation form of Duplicate Abstraction, if the implementations are exactly the same, one of the implementations can be removed. If the implementations are slightly different, then the common implementation in the duplicate abstractions can be factored out into a common class.

        IMPACT: it affects understandability of the design. Developers of client code will be confused and unclear about the choice of the abstraction that should be used by their code.

        identical implementation (i.e., they have duplicate code), it becomes difficult to maintain them. In summary, this smell indicates a violation of the DRY (Don’t Repeat Yourself) principle. If the DRY principle is not fol- lowed, a modification of an element within the system requires modifications to other logically unrelated elements making maintainability a nightmare. Since there is dupli- cation among abstractions in the design, this smell is named Duplicate Abstraction.

        3.7.6 ALIASES This smell is also known in literature as:

        • “Alternative classes with different interfaces” [7]—This smell occurs when classes do similar things, but have different names. • “Duplicate design artifacts” [74]—This smell occurs when equivalent design artifacts are replicated throughout the architecture.

      7. Duplicate Abstraction

        UNUTILIZED ABSTRACTION Two or more abstractions have identical names or identical implementation or both

        POTENTIAL CAUSES:

        Copy-paste programming The “get-the-work-done” mindset of a programmer leads him to copy and paste code instead of applying proper abstraction. Ad hoc maintenance When the software undergoes haphazard fixes or enhancements over many years, it leaves “crufts”6 with lots of redundant code in it. Lack of communication Often, in industrial software, code duplication occurs because different people work on the same code at different times in the life cycle of the software. They are not aware of existing classes or methods and end up re-inventing the wheel.

        REFACTORING: For identical name form, the suggested refactoring is to rename one of the abstrac- tions to a unique name. In the case of the identical implementation form of Duplicate Abstraction, if the implementations are exactly the same, one of the implementations can be removed. If the implementations are slightly different, then the common implementation in the duplicate abstractions can be factored out into a common class.

        IMPACT: it affects understandability of the design. Developers of client code will be confused and unclear about the choice of the abstraction that should be used by their code.

        identical implementation (i.e., they have duplicate code), it becomes difficult to maintain them. In summary, this smell indicates a violation of the DRY (Don’t Repeat Yourself) principle. If the DRY principle is not fol- lowed, a modification of an element within the system requires modifications to other logically unrelated elements making maintainability a nightmare. Since there is dupli- cation among abstractions in the design, this smell is named Duplicate Abstraction.

        3.7.6 ALIASES This smell is also known in literature as:

        • “Alternative classes with different interfaces” [7]—This smell occurs when classes do similar things, but have different names. • “Duplicate design artifacts” [74]—This smell occurs when equivalent design artifacts are replicated throughout the architecture.

    2. encapsulation
    3. modularization
    4. hierarchy

3.2.6

  1. Primitive Obsession
    1. Replace Type Code with Class

      if a primitive value controls logic in a class

    2. Replace State-Altering Conditionals with State

      if an object's state transitions are controller by complex conditional logic

    3. Replace Conditional Logic with Strategy

      if complicated conditional logic controls which algorithm to run and that logic relies on primitive values

3.2.7 Fowler, Martin


    • Two of the leading proponents of refactoring are Ward Cunningham and Kent Beck.
    • Ralph Johnson leads a group at the University of Illinois at Urbana-Champaign that is notable for its practical contributions to object technology. Ralph has long been a champion of refactoring, and several of his students have worked on the topic. Bill Opdyke developed the first detailed written work on refactoring in his doctoral thesis. John Brant and Don Roberts have gone beyond writing words into writing a tool, the Refactoring Browser, for refactoring Smalltalk programs
    • There's nothing wrong with a quick and dirty simple program. But if this is a representative fragment of a more complex system, then I have some real problems with this program.
    • Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
    • I like to get rid of temporary variables such as this as much as possible. Temps are often a problem in that they cause a lot of parameters to be passed around when they don't have to be. You can easily lose track of what they are there for. They are particularly insidious in long methods. Of course there is a performance price to pay; here the charge is now calculated twice. But it is easy to optimize that in the rental class, and you can optimize much more effectively when the code is properly factored.
    • Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.
    • Refactor (verb): to restructure software by applying a series of refactorings without changing its observable behavior.
    • …purpose of refactoring is to make the software easier to understand and modify
    • …refactoring does not change the observable behavior of the software. The software still carries out the same function that it did before. Any user, whether an end user or another programmer, cannot tell that things have changed.
    • I use refactoring to help me understand unfamiliar code. When I look at unfamiliar code, I have to try to understand what it does. I look at a couple of lines and say to myself, oh yes, that's what this bit of code is doing. With refactoring I don't stop at the mental note. I actually change the code to better reflect my understanding, and then I test that understanding by rerunning the code to see if it still works.
    • Early on I do refactoring like this on little details. As the code gets clearer, I find I can see things about the design that I could not see before. Had I not changed the code, I probably never would have seen these things, because I'm just not clever enough to visualize all this in my head. Ralph Johnson describes these early refactorings as wiping the dirt off a window so you can see beyond. When I'm studying code I find refactoring leads me to higher levels of understanding that otherwise I would miss.
    • refactoring helps you find bugs
      • …claryfing the structure of the program
    • refactoring helps you program faster
      • This sounds counterintuitive. When I talk about refactoring, people can easily see that it improves quality. Improving design, improving readability, reducing bugs, all these improve quality. But doesn't all this reduce the speed of development? I strongly believe that a good design is essential for rapid software development. Indeed, the whole point of having a good design is to allow rapid development. Without a good design, you can progress quickly for a while, but soon the poor design starts to slow you down. You spend time finding and fixing bugs instead of adding new function. Changes take longer as you try to understand the system and find the duplicate code. New features need more coding as you patchover a patch that patches a patch on the original code base. A good design is essential to maintaining speed in software development. Refactoring helps you develop software more rapidly, because it stops the design of the system from decaying. It can even improve a design.
    • When Should You Refactor
      • In almost all cases, I'm opposed to setting aside time for refactoring. In my view refactoring is not an activity you set aside time to do. Refactoring is something you do all the time in little bursts. You don't decide to refactor, you refactor because you want to do something else, and refactoring helps you do that other thing.
      • The Rule of Three
        • Here's a guideline Don Roberts gave me: The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor.
        • Tip: Three strikes and you refactor.
    • Refactor When You Add Function
      • first reason to refactor here is to help me understand some code I need to modify
      • The other driver of refactoring here is a design that does not help me add a feature easily. I look at the design and say to myself, "If only I'd designed the code this way, adding this feature would be easy."
    • Refactor When You Need to Fix a Bug
      • In fixing bugs much of the use of refactoring comes from making code more understandable. As I look at the code trying to understand it, I refactor to help improve my understanding. Often I find that this active process of working with the code helps in finding the bug. One way to look at it is that if you do get a bug report, it's a sign you need refactoring, because the code was not clear enough for you to see there was a bug.
    • Refactor As You Do a Code Review
    • I've found that refactoring helps me review someone else's code. Before I started using refactoring, I could read the code, understand some degree of it, and make suggestions. Now when I come up with ideas, I consider whether they can be easily implemented then and there with refactoring. If so, I refactor. When I do it a few times, I can see more clearly what the code looks like with the suggestions in place. I don't have to imagine what it would be like, I can see what it is like. As a result, I can come up with a second level of ideas that I would never have realized had I not refactored.
    • You just code the first approach that comes into your head, get it working, and then refactor it into shape.
    • The problem with building a flexible solution is that flexibility costs. Flexible solutions are more complex than simple ones. The resulting software is more difficult to maintain in general…
    1. Chapter 3. Bad Smells in Code
      • he [Kent Beck] had come up with the notion describing the "when" of refactoring in terms of smells.
      • One thing we won't try to do here is give you precise criteria for when a refactoring is overdue. In our experience no set of metrics rivals informed human intuition. What we will do is give you indications that there is trouble that can be solved by a refactoring. You will have to develop your own sense of how many instance variables are too many instance variables and how many lines of code in a method are too many lines.
      1. Duplicated Code
        • number one in the stink parade.
        • same code structure in more than one place
        1. Same expression in methods of the same class

          Extract Function and invoke the code from both places.

        2. Same expression in two sibling subclasses

          You can eliminate this duplication by using Extract Method in both classes then Pull Up Field. If the code is similar but not the same, you need to use Extract Method to separate the similar bits from the different bits. You may then find you can use Form Template Method. If the methods do the same thing with a different algorithm, you can choose the clearer of the two algorithms and use Substitute Algorithm.

        3. Duplicated code in two unrelated classes

          Consider using Extract Class in one class and then use the new component in the other. Another possibility is that the method really belongs only in one of the classes and should be invoked by the other class or that the method belongs in a third class that should be referred to by both of the original classes.

      2. Long Method

        whenever we feel the need to comment something, we write a method instead.

        Ninety-nine percent of the time, all you have to do to shorten a method is Extract Method. Find parts of the method that seem to go nicely together and make a new method.

        If you have a method with lots of parameters and temporary variables, these elements get in the way of extracting methods. If you try to use Extract Method, you end up passing so many of the parameters and temporary variables as parameters to the extracted method that the result is scarcely more readable than the original. You can often use Replace Temp with Query to eliminate the temps. Long lists of parameters can be slimmed down with Introduce Parameter Object and Preserve Whole Object.

        If you've tried that, and you still have too many temps and parameters, it's time to get out the heavy artillery: Replace Method with Method Object.

        Conditionals and loops also give signs for extractions. Use Decompose Conditional to deal with conditional expressions. With loops, extract the loop and the code within the loop into its own method.

      3. Large Class

        When a class is trying to do too much, it often shows up as too many instance variables. When a class has too many instance variables, duplicated code cannot be far behind.

        You can Extract Class to bundle a number of the variables. Choose variables to go together in the component that makes sense for each. For example, "depositAmount" and "depositCurrency"are likely to belong together in a component. More generally, common prefixes or suffixes for some subset of the variables in a class suggest the opportunity for a component. If the component makes sense as a subclass, you'll find Extract Subclass often is easier.

        Sometimes a class does not use all of its instance variables all of the time. If so, you may be able to Extract Class or Extract Subclass many times.

        As with a class with too many instance variables, a class with too much code is prime breeding ground for duplicated code, chaos, and death. The simplest solution…is to eliminate redundancy in the class itself. If you have five hundred-line methods with lots of code in common, you may be able to turn them into five ten-line methods with another ten two-line methods extracted from the original. As with a class with a huge wad of variables, the usual solution for a class with too much code is either to Extract Class or Extract Subclass. A useful trick is to determine how clients use the class and to use Extract Interface

      4. Long Parameter List

        Use Replace Parameter with Method when you can get the data in one parameter by making a request of an object you already know about. This object might be a field or it might be another parameter. Use Preserve Whole Object to take a bunch of data gleaned from an object and replace it with the object itself. If you have several data items with no logical object, use Introduce Parameter Object.

        There is one important exception to making these changes. This is when you explicitly do not want to create a dependency from the called object to the larger object. In those cases unpacking data and sending it along as parameters is reasonable, but pay attention to the pain involved. If the parameter list is too long or changes too often, you need to rethink your dependency structure.

      5. Divergent Change

        Divergent change occurs when one class is commonly changed in different ways for different reasons. If you look at a class and say, "Well, I will have to change these three methods every time I get a new database; I have to change these four methods every time there is a new financial instrument," you likely have a situation in which two objects are better than one. That way each object is changed only as a result of one kind of change. Of course, you often discover this only after you've added a few databases or financial instruments. Any change to handle a variation should change a single class, and all the typing in the new class should express the variation. To clean this up you identify everything that changes for a particular cause and use Extract Class to put them all together.

      6. Shotgun Surgery

        Shotgun surgery is similar to divergent change but is the opposite. You whiff this when every time you make a kind of change, you have to make a lot of little changes to a lot of different classes. When the changes are all over the place, they are hard to find, and it's easy to miss an important change. In this case you want to use Move Method and Move Field to put all the changes into a single class. If no current class looks like a good candidate, create one. Often you can use Inline Class to bring a whole bunch of behavior together. You get a small dose of divergent change, but you can easily deal with that. Divergent change is one class that suffers many kinds of changes, and shotgun surgery is one change that alters many classes. Either way you want to arrange things so that, ideally, there is a one-to-one link between common changes and classes.

      7. Feature Envy

        The whole point of objects is that they are a technique to package data with the processes used on that data. A classic smell is a method that seems more interested in a class other than the one it actually is in. The most common focus of the envy is the data…a method that invokes half-a-dozen getting methods on another object to calculate some value. Fortunately the cure is obvious, the method clearly wants to be elsewhere, so you use Move Method to get it there. Sometimes only part of the method suffers from envy; in that case use Extract Method on the jealous bit and Move Method…

        Of course not all cases are cut-and-dried. Often a method uses features of several classes, so which one should it live with? The heuristic we use is to determine which class has most of the data and put the method with that data. This step is often made easier if Extract Method is used to break the method into pieces that go into different places. Of course there are several sophisticated patterns that break this rule. From the Gang of Four [Gang of Four] Strategy and Visitor immediately leap to mind. Kent Beck's Self Delegation [Beck] is another. You use these to combat the divergent change smell. The fundamental rule of thumb is to put things together that change together. Data and the behavior that references that data usually change together, but there are exceptions. When the exceptions occur, we move the behavior to keep changes in one place. Strategy and Visitor allow you to change behavior easily, because they isolate the small amount of behavior that needs to be overridden, at the cost of further indirection.

      8. Data Clumps

        Data items tend to be like children; they enjoy hanging around in groups together. Often you'll see the same three or four data items together in lots of places: fields in a couple of classes, parameters in many method signatures. Bunches of data that hang around together really ought to be made into their own object. The first step is to look for where the clumps appear as fields. Use Extract Class on the fields to turn the clumps into an object. Then turn your attention to method signatures using Introduce Parameter Object or Preserve Whole Object to slim them down. The immediate benefit is that you can shrink a lot of parameter lists and simplify method calling. Don't worry about data clumps that use only some of the fields of the new object. As long as you are replacing two or more fields with the new object, you'll come out ahead.

      9. Primitive Obession

        …using Replace Data Value with Object on individual data values. If the data value is a type code, use Replace Type Code with Class if the value does not affect behavior. If you have conditionals that depend on the type code, use Replace Type Code with Subclasses or Replace Type Code with State/Strategy. If you have a group of fields that should go together, use Extract Class. If you see these primitives in parameter lists, try a civilizing dose of Introduce Parameter Object. If you find yourself picking apart an array, use Replace Array with Object.

      10. Switch Statements

        One of the most obvious symptoms of object-oriented code is its comparative lack of switch (or case) statements. The problem with switch statements is essentially that of duplication. Often you find the same switch statement scattered about a program in different places. If you add a new clause to the switch, you have to find all these switch, statements and change them. The object- oriented notion of polymorphism gives you an elegant way to deal with this problem.

        Most times you see a switch statement you should consider polymorphism. The issue is where the polymorphism should occur. Often the switch statement switches on a type code. You want the method or class that hosts the type code value. So use Extract Method to extract the switch statement and then Move Method to get it onto the class where the polymorphism is needed. At that point you have to decide whether to Replace Type Code with Subclasses or Replace Type Code with State/Strategy. When you have set up the inheritance structure, you can use Replace Conditional with Polymorphism.

        If you only have a few cases that affect a single method, and you don't expect them to change, then polymorphism is overkill. In this case Replace Parameter with Explicit Methods is a good option. If one of your conditional cases is a null, try Introduce Null Object.

      11. Parallel Inheritance Hierarchies

        Parallel inheritance hierarchies is really a special case of shotgun surgery. In this case, every time you make a subclass of one class, you also have to make a subclass of another. You can recognize this smell because the prefixes of the class names in one hierarchy are the same as the prefixes in another hierarchy.

        The general strategy for eliminating the duplication is to make sure that instances of one hierarchy refer to instances of the other. If you use Move Method and Move Field, the hierarchy on the referring class disappears.

      12. Lazy Class

        Each class you create costs money to maintain and understand. A class that isn't doing enough to pay for itself should be eliminated. Often this might be a class that used to pay its way but has been downsized with refactoring. Or it might be a class that was added because of changes that were planned but not made. Either way, you let the class die with dignity. If you have subclasses that aren't doing enough, try to use Collapse Hierarchy. Nearly useless components should be subjected to Inline Class.

      13. Speculative Generality

        You get it when people say, "Oh, I think we need the ability to this kind of thing someday" and thus want all sorts of hooks and special cases to handle things that aren't required. The result often is harder to understand and maintain. If all this machinery were being used, it would be worth it. But if it isn't, it isn't. The machinery just gets in the way, so get rid of it.

        If you have abstract classes that aren't doing much, use Collapse Hierarchy. Unnecessary delegation can be removed with Inline Class. Methods with unused parameters should be subject to Remove Parameter. Methods named with odd abstract names should be brought down to earth with Rename Method.

        Speculative generality can be spotted when the only users of a method or class are test cases. If you find such a method or class, delete it and the test case that exercises it. If you have a method or class that is a helper for a test case that exercises legitimate functionality, you have to leave it in, of course.

      14. Temporary Field

        Sometimes you see an object in which an instance variable is set only in certain circumstances. Such code is difficult to understand, because you expect an object to need all of its variables. Trying to understand why a variable is there when it doesn't seem to be used can drive you nuts.

        Use Extract Class to create a home for the poor orphan variables. Put all the code that concerns the variables into the component. You may also be able to eliminate conditional code by using Introduce Null Object to create an alternative component for when the variables aren't valid.

        A common case of temporary field occurs when a complicated algorithm needs several variables. Because the implementer didn't want to pass around a huge parameter list (who does?), he put them in fields. But the fields are valid only during the algorithm; in other contexts they are just plain confusing. In this case you can use Extract Class with these variables and the methods that require them. The new object is a method object [Beck].

      15. Message Chains

        You see message chains when a client asks one object for another object, which the client then asks for yet another object, which the client then asks for yet another another object, and so on. You may see these as a long line of getThis methods, or as a sequence of temps. Navigating this way means the client is coupled to the structure of the navigation. Any change to the intermediate relationships causes the client to have to change.

        The move to use here is Hide Delegate. You can do this at various points in the chain. In principle you can do this to every object in the chain, but doing this often turns every intermediate object into a middle man. Often a better alternative is to see what the resulting object is used for. See whether you can use Extract Method to take a piece of the code that uses it and then Move Method to push it down the chain. If several clients of one of the objects in the chain want to navigate the rest of the way, add a method to do that.

      16. Middle Man

        One of the prime features of objects is encapsulation—hiding internal details from the rest of the world. Encapsulation often comes with delegation. You ask a director whether she is free for a meeting; she delegates the message to her diary and gives you an answer. All well and good. There is no need to know whether the director uses a diary, an electronic gizmo, or a secretary to keep track of her appointments.

        However, this can go too far. You look at a class's interface and find half the methods are delegating to this other class. After a while it is time to use Remove Middle Man and talk to the object that really knows what's going on. If only a few methods aren't doing much, use Inline Method to inline them into the caller. If there is additional behavior, you can use Replace Delegation with Inheritance to turn the middle man into a subclass of the real object. That allows you to extend behavior without chasing all that delegation.

      17. Inappropriate Intimacy

        Sometimes classes become far too intimate and spend too much time delving in each others'private parts. We may not be prudes when it comes to people, but we think our classes should follow strict, puritan rules.

        Overintimate classes need to be broken up as lovers were in ancient days. Use Move Method and Move Field to separate the pieces to reduce the intimacy. See whether you can arrange a Change Bidirectional Association to Unidirectional. If the classes do have common interests, use Extract Class to put the commonality in a safe place and make honest classes of them. Or use Hide Delegate to let another class act as go-between.

        Inheritance often can lead to overintimacy. Subclasses are always going to know more about their parents than their parents w

      18. Alternative Classes with Different Interfaces

        Use Rename Method on any methods that do the same thing but have different signatures for what they do. Often this doesn't go far enough. In these cases the classes aren't yet doing enough. Keep using Move Method to move behavior to the classes until the protocols are the same. If you have to redundantly move code to accomplish this, you may be able to use Extract Superclass to atone.

      19. Incomplete Library Class

        Reuse is often touted as the purpose of objects. We think reuse is overrated (we just use). However, we can't deny that much of our programming skill is based on library classes so that nobody can tell whether we've forgotten our sort algorithms.

        Builders of library classes are rarely omniscient. We don't blame them for that; after all, we can rarely figure out a design until we've mostly built it, so library builders have a really tough job. The trouble is that it is often bad form, and usually impossible, to modify a library class to do something you'd like it to do. This means that tried-and-true tactics such as Move Method lie useless.

        We have a couple of special-purpose tools for this job. If there are just a couple of methods that you wish the library class had, use Introduce Foreign Method. If there is a whole load of extra behavior, you need Introduce Local Extension.

      20. Data Class

        These are classes that have fields, getting and setting methods for the fields, and nothing else. Such classes are dumb data holders and are almost certainly being manipulated in far too much detail by other classes. In early stages these classes may have public fields. If so, you should immediately apply Encapsulate Field before anyone notices. If you have collection fields, check to see whether they are properly encapsulated and apply Encapsulate Collection if they aren't. Use Remove Setting Method on any field that should not be changed.

        Look for where these getting and setting methods are used by other classes. Try to use Move Method to move behavior into the data class. If you can't move a whole method, use Extract Method to create a method that can be moved. After a while you can start using Hide Method on the getters and setters.

        Data classes are like children. They are okay as a starting point, but to participate as a grownup object, they need to take some responsibility.

      21. Refused Bequest

        Subclasses get to inherit the methods and data of their parents. But what if they don't want or need what they are given? They are given all these great gifts and pick just a few to play with.

        The traditional story is that this means the hierarchy is wrong. You need to create a new sibling class and use Push Down Method and Push Down Field to push all the unused methods to the sibling. That way the parent holds only what is common. Often you'll hear advice that all superclasses should be abstract.

        You'll guess from our snide use of traditional that we aren't going to advise this, at least not all the time. We do subclassing to reuse a bit of behavior all the time, and we find it a perfectly good way of doing business. There is a smell, we can't deny it, but usually it isn't a strong smell. So we say that if the refused bequest is causing confusion and problems, follow the traditional advice. However, don't feel you have to do it all the time. Nine times out of ten this smell is too faint to be worth cleaning.

        The smell of refused bequest is much stronger if the subclass is reusing behavior but does not want to support the interface of the superclass. We don't mind refusing implementations, but refusing interface gets us on our high horses. In this case, however, don't fiddle with t

      22. Comments

        If you need a comment to explain what a block of code does, try Extract Method. If the method is already extracted but you still need a comment to explain what it does, use Rename Method. If you need to state some rules about the required state of the system, use Introduce Assertion.

        Tip: When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.

        A good time to use a comment is when you don't know what to do. In addition to describing what is going on, comments can indicate areas in which you aren't sure. A comment is a good place to say why you did something. This kind of information helps future modifiers, especially forgetful ones

    2. Chapter 4. Building Tests
      • the essential precondition is having solid tests.
      • I'm a pretty lazy person and am prepared to work quite hard in order to avoid work.
      • In fact, one of the most useful times to write tests is before you start programming. When you need to add a feature, begin by writing the test. This isn't as backward as it sounds. By writing the test you are asking yourself what needs to be done to add the function. Writing the test also concentrates on the interface rather than the implementation (always a good thing). It also means you have a clear point at which you are done coding—when the test works.
      • Now we should continue adding more tests. The style I follow is to look at all the things the class should do and test each one of them for any conditions that might cause the class to fail. This is not the same as "test every public method," which some programmers advocate. Testing should be risk driven; remember, you are trying to find bugs now or in the future. So I don't test accessors that just read and write a field. Because they are so simple, I'm not likely to find a bug there.This is important because trying to write too many tests usually leads to not writing enough. I've often read books on testing, and my reaction has been to shy away from the mountain of stuff I have to do to test. This is counterproductive, because it makes you think that to test you have to do a lot of work. You get many benefits from testing even if you do only a little testing. The key is to test the areas that you are most worried about going wrong. That way you get the most benefit for your testing effort.
    3. Chapter 5. Toward a Catalog of Refactorings
      • The examples are of the laughably simple textbook kind. My aim with the example is to help explain the basic refactoring with minimal distractions, so I hope you'll forgive the simplicity. (They are certainly not examples of good business object design.) I'm sure you'll be able to apply them to your rather more complex situations. Some very simple refactorings don't have examples because I didn't think an example would add much.
      • In particular, remember that the examples are included only to illustrate the one refactoring under discussion. In most cases, there are still problems with the code at the end, but fixing these problems requires other refactorings. In a few cases in which refactorings often go together, I carry examples from one refactoring to another. In most cases I leave the code as it is after the single refactoring. I do this to make each refactoring self-contained, because the primary role of the catalog is as a reference.
      • Don't take any of these examples as suggestions for how to design employee or order objects. These examples are there only to illustrate the refactorings, nothing more.
    4. Chapter 6. Composing Methods
      • The key is the semantic distance between the method name and the method body.
  1. nil
    • With any introductory example, however, I run into a problem. If I pick a large program, describing it and how it is refactored is too complicated for a mortal reader to work through.(…) However, if I pick a program that is small enough to be comprehensible, refactoring does not look like it is worthwhile.
    • Thus, if I’m faced with modifying a program with hundreds of lines of code, I’d rather it be structured into a set of functions and other program elements that allow me to understand more easily what the program is doing. If the program lacks structure, it’s usually easier for me to add structure to the program first, and then make the change I need.
    • If the code works and doesn’t ever need to change, it’s perfectly fine to leave it alone. It would be nice to improve it, but unless someone needs to understand it, it isn’t causing any real harm. Yet as soon as someone does need to understand how that code works, and struggles to follow it, then you have to do something about it.
    • Refactoring changes the programs in small steps, so if you make a mistake, it is easy to find where the bug is.
    • Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
    • The true test of good code is how easy it is to change it.
    • Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.
    • Refactoring (verb): to restructure software by applying a series of refactorings without changing its observable behavior.
    • Refactoring is very similar to performance optimization, as both involve carrying out code manipulations that don’t change the overall functionality of the program. The difference is the purpose: Refactoring is always done to make the code “easier to understand and cheaper to modify.” This might speed things up or slow things down. With performance optimization, I only care about speeding up the program, and am prepared to end up with code that is harder to work with if I really need that improved performance.
    • Without refactoring, the internal design—the architecture—of software tends to decay.As people change code to achieve short­term goals, often without a full comprehensionof the architecture, the code loses its structure. It becomes harder for me to see thedesign by reading the code. Loss of the structure of code has a cumulative effect. Theharder it is to see the design in the code, the harder it is for me to preserve it, and themore rapidly it decays. Regular refactoring helps keep the code in shape.
    • It reminds me of a statement Kent Beck often makes about himself: “I’m not a great programmer; I’m just a good programmer with great habits.” Refactoring helps me be much more effective at writing robust code.
    • Branches. As I write this, a common approach in teams is for each team member to work on abranch of the code base using a version control system, and do considerable work onthat branch before integrating with a mainline (often called master or trunk) sharedacross the team. Often, this involves building a whole feature on a branch, notintegrating into the mainline until the feature is ready to be released into production.Fans of this approach claim that it keeps the mainline clear of any in­process code,provides a clear version history of feature additions, and allows features to be revertedeasily should they cause problems.There are downsides to feature branches like this. The longer I work on an isolatedbranch, the harder the job of integrating my work with mainline is going to be when I’mdone. Most people reduce this pain by frequently merging or re­basing from mainlineto my branch. But this doesn’t really solve the problem when several people areworking on individual feature branches. I distinguish between merging and integration.If I merge mainline into my code, this is a oneway movement—my branch changes butthe mainline doesn’t. I use “integrate” to mean a two­way process that pulls changesfrom mainline into my branch and then pushes the result back into mainline, changingboth. If Rachel is working on her branch I don’t see her changes until she integrateswith mainline; at that point, I have to merge her changes into my feature branch, whichmay mean considerable work. The hard part of this work is dealing with semanticchanges. Modern version control systems can do wonders with merging complexchanges to the program text, but they are blind to the semantics of the code. If I’vechanged the name of a function, my version control tool may easily integrate mychanges with Rachel’s. But if, in her branch, she added a call to a function that I’verenamed in mine, the code will fail.The problem of complicated merges gets exponentially worse as the length of featurebranches increases. Integrating branches that are four weeks old is more than twice ashard as those that are a couple of weeks old. Many people, therefore, argue for keepingfeature branches short—perhaps just a couple of days. Others, such as me, want themeven shorter than that. This is an approach called Continuous Integration (CI), alsoknown as Trunk­Based Development. With CI, each team member integrates withmainline at least once per day. This prevents any branches diverting too far from eachother and thus greatly reduces the complexity of merges. CI doesn’t come for free: Itmeans you use practices to ensure the mainline is healthy, learn to break large featuresinto smaller chunks, and use feature toggles (aka feature flags) to switch off any in­process features that can’t be broken down.Fans of CI like it partly because it reduces the complexity of merges, but the dominantreason to favor CI is that it’s far more compatible with refactoring. Refactorings ofteninvolve making lots of little changes all over the code base—which are particularlyprone to semantic merge conflicts (such as renaming a widely used function). Many ofus have seen feature­branching teams that find refactorings so exacerbate mergeproblems that they stop refactoring. CI and re­factoring work well together, which iswhy Kent Beck combined them in Extreme Programming.I’m not saying that you should never use feature branches. If they are sufficiently short,their problems are much reduced. (Indeed, users of CI usually also use branches, butintegrate them with mainline each day.) Feature branches may be the right techniquefor open source projects where you have infrequent commits from programmers whoyou don’t know well (and thus don’t trust). But in a full­time development team, thecost that feature branches impose on refactoring is excessive. Even if you don’t go to fullCI, I certainly urge you to integrate as frequently as possible. You should also considerthe objective evidence [Forsgren et al.] that teams that use CI are more effective insoftware deliver
  2. Summary of "Refactoring: Improving the Design of Existing Code" by Martin Fowler
  3. Patterns of Enterprise Application Architecture; 2012

3.2.8 Francesco Trucchia, Jacopo Romei Pro PHP Refactoring 2010

Old, without PHP 7 but still the best PHP book about refactoring. Great examples. Worth to have.

3.3 Database

3.3.1 Karwin, Bill SQL Antipatterns - Avoiding The Pitfalls of Database Programming 2010

3.3.2 Scott J Ambler and Pramod J. Sadalage Refactoring Databases - Evolutionary Database Design 2006

refactoring must read It's catalog of refactorings for database

3.3.3 Joe Celko’s Trees and Hierarchies in SQL for Smarties

3.3.4 SQL for Smarties: Advanced SQL Programming 2005

3.4 Andrew Hunt, David Thomas - The Pragmatic Programmer: From Journeyman to Master 1999

overall skip a lot of tips & tricks but too old

3.5 Fifty Quick Ideas To Improve Your Tests tests

3.6 Growing Object-Oriented Software, Guided by Tests

3.7 Working Effectively with Unit Tests

3.8 Scalable Internet Architectures

3.9 Anthology The Thoughtworks Anthology - Essays on Software Technology and Innovation 2008

3.10 Anthology The ThoughtWorks Anthology 2 - More Essays on Software Technology and Innovation 2012

3.11 Beck, Kent Extreme Programming Explained: Embrace Change 1999

overall can be read

3.12 Bhargava, Aditya Grokking Algorithms: An illustrated guide for programmers and other curious people

must read 2017 Fully illustrated, friendly, easy to read guide, worth to read. When you will stumble upon a problem, you will know how to recognize it and chose the right Algorithm

3.13

3.14 Buenosvinos, Carlos Domain-Driven Design in PHP 2016

3.15 Jones, Paul M. Modernizing Legacy Apps In PHP 2014

3.16 Junade, Ali Mastering PHP Design Patterns 2016

Little bit inmature, poorly written. Having a lot of tips and information about broad variaty of things which is a good place on website but not in the book. Code examples could be much better.

3.17 Rahman, Mizanur PHP 7 Data Structures and Algorithms 2017

3.18 Stephane Faroult, Pascal L'Hermite Refactoring SQL Application 2008

3.19 Tornhill, Adam Your Code as a Crime Scene - Use Forensic Techniques to Arrest Defects, Bottlenecks, and Bad Design in Your Programs 2015

3.20 West, David Object Thinking 2004

3.22 Build APIs You Won't Hate

3.23 McConnel, Steve "Code Complete 2"

3.24 Wake, William C.; Refactoring Workbook; 2003

3.25 Martin, Robert C.

3.25.1 nil

  • There are two parts to learning craftsmanship: knowledge and work. You must gain the knowledge of principles, patterns, practices, and heuristics that a craftsman knows, and you must also grind that knowledge into your fingers, eyes, and gut by working hard and practicing.
  • Do not refer to a grouping of accounts as an accountList unless it’s actually a List. The word list means something specific to programmers. If the container holding the accounts is not actually a List, it may lead to false conclusions (even if the container is a List, it’s probably better not to encode the container type into the name). So accountGroup or bunchOfAccounts or just plain accounts would be better.
  • A truly awful example of disinformative names would be the use of lower-case L or uppercase O as variable names, especially in combination. The problem, of course, is that they look almost entirely like the constants one and zero, respectively.
  • Certainly a loop counter may be named i or j or k (though never l!) if its scope is very small and no other names can conflict with it. This is because those single-letter names for loop counters are traditional.
int a = 1;
if ( O == 1 )
    a = O1;
else
    l = 01;

3.25.2 Agile Software Development: Principles, Patterns, and Practices; 2002

3.26 Design It!: From Programmer to Software Architect (The Pragmatic Programmers) 1st Edition by Michael Keelin

3.27 Mastering the SPL Library

3.28 Zandstra, Matt "PHP Objects, Patterns, and Practice" 2008

Pretty old. But written with precise language and with great examples |

3.29 TODO Halladay, Steve Principle-Based Refactoring: Learning Software Design Principles by Applying Refactoring Rules 2012

3.30 TODO Object Design Style Guide Matthias Noback

3.31 TODO xUnit Test Patterns - Refactoring Test Code

3.32 TODO The Psychology of Computer Programming

3.33 TODO Timeless Laws of Software Development

3.34 TODO Hacker's Delight

3.35 LOOKING-FOR Bernstein, David Scott Beyond Legacy Code 2015

3.36 LOOKING-FOR Bugayenko, Yegor Elegant Objects 2016

3.37 LOOKING-FOR Cusumano MA, Selby RW (1995) Microsoft secrets. Free Press, USA

describe how Microsoft uses 20% of its development effort to re-develop the code base of its products

3.38 LOOKING-FOR Cusumano MA, Yoffie DB (1998) Design strategy. In: Competing on internet time. Free Press, New York, USA, pp 180–198

report how Netscape’s inability to refactor the code base hindered their software development, and how Microsoft’s redesign efforts in the Internet Explorer 3.0 project later paid off.

4 Smells

4.1 Based On Fowler

4.1.1 Duplicated Code

same code structure in more than one place

  1. in methods of the same class

    Extract Function and invoke the code from both places.

  2. in two sibling subclasses

    You can eliminate this duplication by using Extract Method in both classes then Pull Up Field. If the code is similar but not the same, you need to use Extract Method to separate the similar bits from the different bits. You may then find you can use Form Template Method. If the methods do the same thing with a different algorithm, you can choose the clearer of the two algorithms and use Substitute Algorithm.

  3. in two unrelated classes

    Consider using Extract Class in one class and then use the new component in the other. Another possibility is that the method really belongs only in one of the classes and should be invoked by the other class or that the method belongs in a third class that should be referred to by both of the original classes.

4.1.2 Long Function

Find parts of the method that seem to go nicely together and Extract Method.

If you have a method with lots of parameters and temporary variables, these elements get in the way of extracting methods. If you try to use Extract Method, you end up passing so many of the parameters and temporary variables as parameters to the extracted method that the result is scarcely more readable than the original. You can often use Replace Temp with Query to eliminate the temps. Long lists of parameters can be slimmed down with Introduce Parameter Object and Preserve Whole Object.

If you've tried that, and you still have too many temps and parameters, it's time to get out the heavy artillery: Replace Method with Method Object.

Conditionals and loops also give signs for extractions. Use Decompose Conditional to deal with conditional expressions. With loops, extract the loop and the code within the loop into its own method.

Alias: Long Method

4.1.3 Large Class

When a class is trying to do too much, it often shows up as too many instance variables.

You can Extract Class to bundle a number of the variables. Choose variables to go together in the component that makes sense for each. For example, "depositAmount" and "depositCurrency"are likely to belong together in a component. More generally, common prefixes or suffixes for some subset of the variables in a class suggest the opportunity for a component. If the component makes sense as a subclass, you'll find Extract Subclass often is easier.

Sometimes a class does not use all of its instance variables all of the time. If so, you may be able to Extract Class or Extract Subclass many times.

As with a class with too many instance variables, a class with too much code is prime breeding ground for duplicated code, chaos, and death. The simplest solution…is to eliminate redundancy in the class itself. If you have five hundred-line methods with lots of code in common, you may be able to turn them into five ten-line methods with another ten two-line methods extracted from the original. As with a class with a huge wad of variables, the usual solution for a class with too much code is either to Extract Class or Extract Subclass. A useful trick is to determine how clients use the class and to use Extract Interface

4.1.4 Long Parameter List

  1. one of the parameter is switch parameter

    fix: Use Replace Parameter with Method

  2. more than one value from an object are passing as parameters

    fix: Preserve Whole Object

  3. parameters that naturally go together

    fix: Introduce Parameter Object

  4. exceptions

    when you explicitly do not want to create a dependency from the called object to the larger object. In those cases unpacking data and sending it along as parameters is reasonable, but pay attention to the pain involved. If the parameter list is too long or changes too often, you need to rethink your dependency structure.

  5. others fixes

    Replace Parameter with Query, Remove Flag Argument, Combine Functions into Class

4.1.5 Divergent Change

Divergent change occurs when one class is commonly changed in different ways for different reasons. If you look at a class and say, "Well, I will have to change these three methods every time I get a new database; I have to change these four methods every time there is a new financial instrument," you likely have a situation in which two objects are better than one. That way each object is changed only as a result of one kind of change. Of course, you often discover this only after you've added a few databases or financial instruments. Any change to handle a variation should change a single class, and all the typing in the new class should express the variation. To clean this up you identify everything that changes for a particular cause and use Extract Class to put them all together.

4.1.6 Shotgun Surgery

Opposite of Divergent Change. You whiff this when every time you make a kind of change, you have to make a lot of little changes to a lot of different classes. When the changes are all over the place, they are hard to find, and it's easy to miss an important change. In this case you want to use Move Method and Move Field to put all the changes into a single class. If no current class looks like a good candidate, create one. Often you can use Inline Class to bring a whole bunch of behavior together. You get a small dose of divergent change, but you can easily deal with that. Divergent change is one class that suffers many kinds of changes, and shotgun surgery is one change that alters many classes. Either way you want to arrange things so that, ideally, there is a one-to-one link between common changes and classes.

4.1.7 Feature Envy

  1. a method accesses the data of another object more than its own data

    fix: Move Method

  2. a part of method accesses the data of another object more than its own data

    fix: Extract Method, Move Method

  3. exceptions

    Strategy, Visitor, Self Delegation. You use these to combat the divergent change smell. The fundamental rule of thumb is to put things together that change together. Data and the behavior that references that data usually change together, but there are exceptions. When the exceptions occur, we move the behavior to keep changes in one place. Strategy and Visitor allow you to change behavior easily, because they isolate the small amount of behavior that needs to be overridden, at the cost of further indirection.

4.1.8 Data Clumps

data items together in lots of places: fields in a couple of classes, parameters in many method signatures. Use Extract Class on the fields to turn the clumps into an object. Then turn your attention to method signatures using Introduce Parameter Object or Preserve Whole Object to slim them down. The immediate benefit is that you can shrink a lot of parameter lists and simplify method calling. Don't worry about data clumps that use only some of the fields of the new object. As long as you are replacing two or more fields with the new object, you'll come out ahead.

4.1.9 Primitive Obession

are generic, classes are more specific fix: Replace Primitive with Object

  1. links

  2. individual data values

    fix: Replace Data Value with Object

  3. if data value is a type code

    fix: Replace Type Code with Class if the value does not affect behavior.

    1. If you have conditionals that depend on the type code,

      fix: Replace Type Code with Subclasses or Replace Type Code with State/Strategy.

  4. group of fields that should go together

    fix: Extract Class

  5. primitives in parameter lists

    fix: Introduce Parameter Object

  6. array

    fix: Replace Array with Object.

4.1.10 Switch Statements (deprecated)

One of the most obvious symptoms of object-oriented code is its comparative lack of switch (or case) statements. The problem with switch statements is essentially that of duplication. Often you find the same switch statement scattered about a program in different places. If you add a new clause to the switch, you have to find all these switch, statements and change them. The object-oriented notion of polymorphism gives you an elegant way to deal with this problem.

Most times you see a switch statement you should consider polymorphism. The issue is where the polymorphism should occur. Often the switch statement switches on a type code. You want the method or class that hosts the type code value. So use Extract Method to extract the switch statement and then Move Method to get it onto the class where the polymorphism is needed. At that point you have to decide whether to Replace Type Code with Subclasses or Replace Type Code with State/Strategy. When you have set up the inheritance structure, you can use Replace Conditional with Polymorphism.

If you only have a few cases that affect a single method, and you don't expect them to change, then polymorphism is overkill. In this case Replace Parameter with Explicit Methods is a good option. If one of your conditional cases is a null, try Introduce Null Object.

4.1.11 Parallel Inheritance Hierarchies

Parallel inheritance hierarchies is really a special case of shotgun surgery. In this case, every time you make a subclass of one class, you also have to make a subclass of another. You can recognize this smell because the prefixes of the class names in one hierarchy are the same as the prefixes in another hierarchy.

The general strategy for eliminating the duplication is to make sure that instances of one hierarchy refer to instances of the other. If you use Move Method and Move Field, the hierarchy on the referring class disappears.

4.1.12 Lazy Class

Each class you create costs money to maintain and understand. A class that isn't doing enough to pay for itself should be eliminated. Often this might be a class that used to pay its way but has been downsized with refactoring. Or it might be a class that was added because of changes that were planned but not made. Either way, you let the class die with dignity. If you have subclasses that aren't doing enough, try to use Collapse Hierarchy. Nearly useless components should be subjected to Inline Class.

4.1.13 Speculative Generality

You get it when people say, "Oh, I think we need the ability to this kind of thing someday" and thus want all sorts of hooks and special cases to handle things that aren't required. The result often is harder to understand and maintain. If all this machinery were being used, it would be worth it. But if it isn't, it isn't. The machinery just gets in the way, so get rid of it.

If you have abstract classes that aren't doing much, use Collapse Hierarchy. Unnecessary delegation can be removed with Inline Class. Methods with unused parameters should be subject to Remove Parameter. Methods named with odd abstract names should be brought down to earth with Rename Method.

Speculative generality can be spotted when the only users of a method or class are test cases. If you find such a method or class, delete it and the test case that exercises it. If you have a method or class that is a helper for a test case that exercises legitimate functionality, you have to leave it in, of course.

4.1.14 Temporary Field

Sometimes you see an object in which an instance variable is set only in certain circumstances. Such code is difficult to understand, because you expect an object to need all of its variables. Trying to understand why a variable is there when it doesn't seem to be used can drive you nuts.

Use Extract Class to create a home for the poor orphan variables. Put all the code that concerns the variables into the component. You may also be able to eliminate conditional code by using Introduce Null Object to create an alternative component for when the variables aren't valid.

A common case of temporary field occurs when a complicated algorithm needs several variables. Because the implementer didn't want to pass around a huge parameter list (who does?), he put them in fields. But the fields are valid only during the algorithm; in other contexts they are just plain confusing. In this case you can use Extract Class with these variables and the methods that require them. The new object is a method object [Beck].

4.1.15 Message Chains

a client asks one object for another object, which the client then asks for yet another object, which the client then asks for yet another another object, and so on. You may see these as a long line of getThis methods, or as a sequence of temps. Navigating this way means the client is coupled to the structure of the navigation. Any change to the intermediate relationships causes the client to have to change.

The move to use here is Hide Delegate. You can do this at various points in the chain. In principle you can do this to every object in the chain, but doing this often turns every intermediate object into a middle man. Often a better alternative is to see what the resulting object is used for. See whether you can use Extract Method to take a piece of the code that uses it and then Move Method to push it down the chain. If several clients of one of the objects in the chain want to navigate the rest of the way, add a method to do that.

4.1.16 Middle Man

One of the prime features of objects is encapsulation—hiding internal details from the rest of the world. Encapsulation often comes with delegation. You ask a director whether she is free for a meeting; she delegates the message to her diary and gives you an answer. All well and good. There is no need to know whether the director uses a diary, an electronic gizmo, or a secretary to keep track of her appointments.

However, this can go too far. You look at a class's interface and find half the methods are delegating to this other class. After a while it is time to use Remove Middle Man and talk to the object that really knows what's going on. If only a few methods aren't doing much, use Inline Method to inline them into the caller. If there is additional behavior, you can use Replace Delegation with Inheritance to turn the middle man into a subclass of the real object. That allows you to extend behavior without chasing all that delegation.

4.1.17 Inappropriate Intimacy

Sometimes classes become far too intimate and spend too much time delving in each others'private parts.

Overintimate classes need to be broken up as lovers were in ancient days. Use Move Method and Move Field to separate the pieces to reduce the intimacy. See whether you can arrange a Change Bidirectional Association to Unidirectional. If the classes do have common interests, use Extract Class to put the commonality in a safe place and make honest classes of them. Or use Hide Delegate to let another class act as go-between.

Inheritance often can lead to overintimacy. Subclasses are always going to know more about their parents than their parents would like them to know. If it's time to leave home, apply Replace Delegation with Inheritance.

4.1.18 Alternative Classes with Different Interfaces

Use Rename Method on any methods that do the same thing but have different signatures for what they do. Often this doesn't go far enough. In these cases the classes aren't yet doing enough. Keep using Move Method to move behavior to the classes until the protocols are the same. If you have to redundantly move code to accomplish this, you may be able to use Extract Superclass to atone.

4.1.19 Incomplete Library Class

If there are just a couple of methods that you wish the library class had, use Introduce Foreign Method. If there is a whole load of extra behavior, you need Introduce Local Extension.

4.1.20 Data Class (depracted)

These are classes that have fields, getting and setting methods for the fields, and nothing else. Such classes are dumb data holders and are almost certainly being manipulated in far too much detail by other classes. In early stages these classes may have public fields. If so, you should immediately apply Encapsulate Field before anyone notices. If you have collection fields, check to see whether they are properly encapsulated and apply Encapsulate Collection if they aren't. Use Remove Setting Method on any field that should not be changed.

Look for where these getting and setting methods are used by other classes. Try to use Move Method to move behavior into the data class. If you can't move a whole method, use Extract Method to create a method that can be moved. After a while you can start using Hide Method on the getters and setters.

Data classes are like children. They are okay as a starting point, but to participate as a grownup object, they need to take some responsibility.

4.1.21 Refused Bequest

Subclasses get to inherit the methods and data of their parents. But what if they don't want or need what they are given? They are given all these great gifts and pick just a few to play with.

The traditional story is that this means the hierarchy is wrong. You need to create a new sibling class and use Push Down Method and Push Down Field to push all the unused methods to the sibling. That way the parent holds only what is common. Often you'll hear advice that all superclasses should be abstract.

You'll guess from our snide use of traditional that we aren't going to advise this, at least not all the time. We do subclassing to reuse a bit of behavior all the time, and we find it a perfectly good way of doing business. There is a smell, we can't deny it, but usually it isn't a strong smell. So we say that if the refused bequest is causing confusion and problems, follow the traditional advice. However, don't feel you have to do it all the time. Nine times out of ten this smell is too faint to be worth cleaning.

The smell of refused bequest is much stronger if the subclass is reusing behavior but does not want to support the interface of the superclass. We don't mind refusing implementations, but refusing interface gets us on our high horses. In this case, however, don't fiddle with t

4.1.22 Comments

  1. if you need a comment to explain what a block of code does

    Extract Method

  2. if the method is already extracted but you still need a comment to explain what it does

    Rename Method

  3. if you need to state some rules about the required state of the system

    Introduce Assertion.

  4. exception

    A good time to use a comment is when you don't know what to do. In addition to describing what is going on, comments can indicate areas in which you aren't sure. A comment is a good place to say why you did something. This kind of information helps future modifiers, especially forgetful ones

4.2 Others

4.2.1 Duplicated Class Short Name

use App\Model\Category\Query;
use App\Model\Product\Contract\Query;
use App\Contract\Query;

4.2.2 Global Data

"Global data is especially nasty when it’s mutable. Global data that you can guarantee never changes after the program starts is relatively safe—if you have a language that can enforce that guarantee." Fix: Encapsulate Variable

4.2.3 Insider Trading

4.2.4 Lazy Element

It may be a function that’s named the same as its body code reads, or a class that is essentially one simple function. Fix: Inline Function, Inline Class, Collapse Hierarchy

4.2.5 Loops

Fix: Replace Loop with Pipeline

4.2.6 Mysterious Name

Fix: Change Function Declaration, Rename Variable, Rename Field

4.2.7 Refused Bequest

4.2.8 Repeated Switches

4.3 Taxonomy

4.3.1 2000 Fowler, Martin - Refactoring: improving the design of existing code

4.3.2 2003 Wake, William C. - Refactoring Workbook

4.3.3 DONE

  • *Szeroko rozumiany termin oznacza zdolność grupy organizmów tworzących linię ewolucyjną do efektywnej odpowiedzi adaptacyjnej w zmieniających się warunkach środowiska. Ewoluowalność
  • In order to be able to improve software maintainability, its current state and possible improvement efforts must be made measurable. However, assessing maintainability is a difficult task. Widely studied object-oriented metrics (Briand et al., 1997, 1999; Chidamber and Kemerer, 1994; Harrison et al., 1998; Henderson-Sellers, 1996; Hitz and Montazeri, 1996; Lorenz and Kidd, 1994) offer a way to assess software maintainability. Although some studies report successes in measuring maintainability with metrics (Bansiya and David, 2002; Chidamber et al., 1998; Coleman et al., 1994; Li and Henry 1993; Subramanyam and Krishnan, 2003), there are people, especially in the agile community (Beck et al., 2001), who are critical to using metrics for maintainability assessment, since they feel that metrics fail to account for the breadth of issues that humans consider when evaluating code.
  • Yet, software quality, as quality in general, is largely dependent on one’s point of view (Garvin 1984; Kitchenham and Pfleeger, 1996). From a developer’s viewpoint the ease of modifying and further developing the software is clearly one of the most important quality dimensions. Traditionally one would call this viewpoint to quality software maintainability.
  • Cusumano and Selby (Cusumano MA, Selby RW (1995) Microsoft secrets. Free Press, USA) describe how Microsoft uses 20% of its development effort to re-develop the code base of its products. Cusumano and Yoffie (Cusumano MA, Yoffie DB (1998) Design strategy. In: Competing on internet time. Free Press, New

York, USA, pp 180–198) report how Netscape’s inability to refactor the code base hindered their software development, and how Microsoft’s redesign efforts in the Internet Explorer 3.0 project later paid off.

  • The agile community…has come up with a term called code smell (Fowler and Beck, 2000) to help software developers recognise problematic code. These code smells are general descriptions of bad code that are supposed to help software developers decide when the code needs refactoring. In most cases, the goal of code refactoring is to make the software easier to understand and/or extend. Fowler and Beck (Fowler and Beck, 2000) claim that exact criteria cannot be given to determine when a software needs refactoring. In their words, when it comes to making refactoring decisions: "no set of metrics rivals informed human intuition." This opinion is in conflict with the idea that the level of software maintainability can be determined with source code or design metrics. A counterexample to Fowler and Beck is provided by Grady (Grady, 1994), who reports that in some HP divisions there were tight threshold limits that a program was not allowed to exceed, e.g., a Fortran program’s cyclomatic complexity (McCabe, 1976) should not exceed 15. This threshold was determined based on data from previous software projects. Also, the idea of measuring software maintainability with metrics (Coleman et al., 1994, 1995) seems to be conflicting with the idea of assessing maintainability using vaguely defined qualitative criteria, such as the code smells of Fowler and Beck.
  • Traditionally, the term software maintainability has been used to represent this quality attribute, and IEEE (IEEE, 1990) has defined software maintainability as follows: the ease with which a software system or component can be modified to correct faults, improve performance or other attributes, or to adapt to a changed environment.
  • We think that the term software evolution better describes what happens after the initial software deployment/release…
  • Fowler and Beck (2000) propose a list of 22 bad code smells. Fowler and Beck introduce code smells as a more concrete indication of the need for refactoring than "some vague idea of programming aesthetics." They also claim that no set of precise metrics can be given to identify the need for refactoring. Thus, the code smells can be seen as a compromise between precise source code metrics and totally unguided subjective evaluation. In their experience, Fowler and Beck say that when it comes to making refactoring decisions, no set of metrics rivals informed human intuition. The code smells have been developed based on Fowler’s and Beck’s industrial experience in several software projects that according to them varied from successful to nearly catastrophic. Some code smells represent two extremes of the same attribute. For example, the size of a class could be an attribute. Too much of it leads to a smell called 'Large Class’’ and too little to the 'Lazy Class’’ smell. The code smells are somewhat vaguely defined.
  • Structures similar to code smells are described by Brown et al. (1998), who discuss software anti-patterns. These anti-patterns describe code problems on class to architectural levels. Some of them are similar to code smells, e.g., God Class is equal to a Large Class smell and Lava Flow is a synonym for Dead Code. However, the scope of their work is quite wide as they also discuss problems in software processes, badly behaving developers, and many other areas.
  • The Air Force Operation Test and Evaluation Center (AFOTEC) pamphlet (AFOTEC, 1996) provides a rich set of instructions for evaluating software maintainability.
  • In this section we introduce the 23 code smells that we surveyed. Twenty-two of the code smells were introduced by Fowler and Beck (2000). Additionally, we included a code smell for dead code, i.e., code that is never executed, as we felt it was important but not included in the list by Fowler and Beck. In the rest of the paper we will use a bold font when referring to the smells, e.g., Dead Code. We chose four smells for automatic code analysis, namely Large Class, Long Method, Long Parameter List, and Duplicate Code. We selected these because we thought their operationalization would be quite straightforward, and because we had suitable tools to measure them.
  • One key assumption of code smells is that there are no exact conditions, which indicate when developers should improve the software design.
  1. A Taxonomy for "Bad Code Smells"
    1. The Bloaters
      • Long Parameter List
      • Long Method
      • Large Class
      • Primitive Obsession
      • Data Clumps

      Bloater smells represents something that has grown so large that it cannot be effectively handled. It seems likely that these smells grow a little bit at a time. Hopefully nobody designs, e.g., Long Methods. Primitive Obsession is actually more of a symptom that causes bloats than a bloat itself. The same holds for Data Clumps. When a Primitive Obsession exists, there are no small classes for small entities (e.g. phone numbers). Thus, the functionality is added to some other class, which increases the class and method size in the software. With Data Clumps there exists a set of primitives that always appear together (e.g. 3 integers for RGB colors). Since these data items are not encapsulated in a class this increases the sizes of methods and classes.

    2. The Object-Orientation Abusers
      • Switch Statements
      • Temporary Field
      • Refused Bequest
      • Alternative Classes with Different Interfaces

      When a solution does not fully exploit the possibilities of object-oriented design. For example, a Switch Statement might be considered acceptable or even good design in procedural programming, but is something that should be avoided in object-oriented programming. The situation where switch statements or type codes are needed should be handled by creating subclasses. Refused Bequest smells lack proper inheritance design, which is one of the key elements in object-oriented programming. The Alternative Classes with Different Interfaces smell lacks a common interface for closely related classes, so it can also be considered a certain type of inheritance misuse. The Temporary Field smell means a case in which a variable is in the class scope, when it should be in method scope. This violates the information hiding principle.

    3. The Change Preventers
      • Divergent Change
      • Shotgun Surgery
      • Parallel Inheritance Hierarchies

      Change Preventers are smells is that hinder changing or further developing the software. These smells violate the rule suggested by Fowler and Beck which says that classes and possible changes should have a one-to-one relationship. For example, changes to the database only affect one class, while changes to calculation formulas only affect the other class.

      The Divergent Change smell means that we have a single class that needs to be modified by many different types of changes. With the Shotgun Surgery smell the situation is the opposite, we need to modify many classes when making a single change to a system (change several classes when changing database from one vendor to another)

      Parallel Inheritance Hierarchies, which means a duplicated class hierarchy, was originally placed in OO-abusers. One could also place it inside of The Dispensables since there is redundant logic that should be replaced.

    4. The Dispensables
      • Lazy class
      • Data class
      • Duplicate Code
      • Dead Code
      • Speculative Generality

      …they all represent something unnecessary that should be removed from the source code. This group contains two types of smells (dispensable classes and dispensable code), but since they violate the same principle, we will look at them together. If a class is not doing enough it needs to be removed or its responsibility needs to be increased. This is the case with the Lazy class and the Data class smells. Code that is not used or is redundant needs to be removed. This is the case with Duplicate Code, Speculative Generality and Dead Code smells.

    5. The Couplers
      • Feature Envy
      • Inappropriate Intimacy
      • Message Chains
      • Middle Man

      This group has four coupling-related smells. One design principle that has been around for decades is low coupling (Stevens et al. 1974) . This group has 3 smells that represent high coupling. Middle Man smell on the other hand represent a problem that might be created when trying to avoid high coupling with constant delegation. Middle Man is a class that is doing too much simple delegation instead of really contributing to the application.

      The Feature Envy smell means a case where one method is too interested in other classes, and the Inappropriate Intimacy smell means that two classes are coupled tightly to each other. Message Chains is a smell where class A needs data from class D. To access this data, class A needs to retrieve object C from object B (A and B have a direct reference). When class A gets object C it then asks C to get object D. When class A finally has a reference to class D, A asks D for the data it needs. The problem here is that A becomes unnecessarily coupled to classes B, C, and D, when it only needs some piece of data from class D. The following example illustrates the message chain smell: A.getB().getC().getD().getTheNeededData()

      Of course, I could make an argument that these smells should belong to the Object-Orientation abusers group, but since they all focus strictly on coupling, I think it makes the taxonomy more understandable if they are introduced in a group of their own.

    6. The Others
      • Comments and Incomplete
      • Library Class

      Other smells that were studied, but could not be included in any of the groups are Comments and Incomplete Library Class. The Comments smell indicates the misuse of comments, i.e., when a programmer uses comments to explain some piece of code instead of writing code that is simpler and more self-explaining. Incomplete Library Class means that the application is using a third party library code that is not completely adequate for the application. According to Fowler and Beck this smell can be removed, for example, by introducing a local extension.

4.3.4

4.4 Notes

Automatic code analysis: Large Class Long Method Long Parameter List Duplicate Code

name object oriented not object oriented both
large class X    
       

4.4.1 Duplicated Code

Don't Repeat Yourself (DRY)

4.4.2 Large Class

A class contains too many fields, methods, lines of code. Fix: Extract Class, Extract Superclass, Replace Type Code with Subclass Alias: God Class, Blob, Winnebago

5 Codebases

Name LOC Description Tutorials
Video Rental Shop 132 book "Refactoring" by Martin Fowler Refactoring 101
Theatrical Players 144 book "Refactoring" by Martin Fowler, 2nd Edition  
Legacy Code Retreat - Trivia Game 196 Designed for Legacy Code Retreat events Refactoring Legacy Code
      Techniques for Refactoring Code
      Legacy Coderetreat (Java)
Gilded Rose 84   Advanced Testing & Refactoring Techniques
Racing Car 471    
Tennis 443    
Yatzy 293    

6 Definitions

6.1 Anemic Domain Model

  • focus on data
  • structured
  • easy to implement and to maintain
  • contains little or no logic
  • no guarantee to be valid or consisten

6.1.1 use

  • prototyping
  • easy of use
  • easily generated

6.2 Rich Domain Model

  • combines data and logic
  • valid by design
  • easy to test
  • defined state transistions

6.2.1 use

  • clean code
  • testability
  • truly OOP

6.3 Data Clump

a set of primitives that always appear together (e.g., three integers for RGB colours)

6.4 Characterization Test

Test that characterizes the actual behavior of a piece of code. It acts as a change detector, protecting legacy code from unintended changes.

6.5 Polymorphism

describes a pattern in object oriented programming in which classes have different functionality while sharing a common interface

6.6 Parameter vs. Argument

A parameter is the variable which is part of the method’s signature (method declaration). An argument is an expression used when calling the method.

Consider the following code:

void Foo(int i, float f)
{
    // Do things
}

void Bar()
{
    int anInt = 1;
    Foo(anInt, 2.0);
}

Here i and f are the parameters, and anInt and 2.0 are the arguments.

https://stackoverflow.com/questions/1788923/parameter-vs-argument

6.7 Principle vs. Practices

  • The Boy scout motto – “Be prepared”–is a timeless principle. “Buy a plunger before you need a plunger” is a practice that applies this principle in a memorable way.
  • Principles are good ideas or good values stated in a context-independent manner. Practices are applications of theses principles stated in a context-dependent way.
  • Principle: a fundamental, primary or general law or truth
  • Practice: the action or process of performing or doing something

6.8 Logical operators

They are used for different purposes and in fact have different operator precedences. The && and || operators are intended for Boolean conditions, whereas and and or are intended for control flow.

For example, the following is a Boolean condition:

if ($foo = $bar && $baz ! $quxx) {

This differs from control flow:

doSomething() or die();

6.9 Value Object

  • measures, quantifies or describe a thing in the domain
  • identity is based on composition of values
  • immutable
  • compared using all values
  • no side effects
  • value object should never be mocked
  • Value objects are powerful yet simple things. The problem that we were trying to solve earlier was that we need to constantly revalidate all of our properties. We do this because at every step, we don't know whether we can trust the object's properties to be valid. What if we could? In order to trust the values, we need two characteristics: for them to be validated and a guarantee that they haven't been changed since the validation.

#+beginsrc php final class PaymentInstrument {

** @var string * private $token;

private function _construct(string $token) { Assert::that($token)->lengt(32); $this->token = $token; }

public static function fromToken(string $token) : self { return new self($token); }

public function getToken() : string { return $this-token; } } #+endsrc> https://www.youtube.com/watch?time_continue=221&v=z3BDOoB8csA

6.10 Service

an object that dose work

6.11 Technical Dept

  • Based on W.Cunningham's metaphor of complexity as debt:
    • skipping design is like borrowing money
    • refactoring is like repaying principal
    • slower development due to complexity is like paying interest

is the debt that accumulate when you knowingly or unknowingly make wrong or non-optimal design decisions.

http://blog.insight.sensiolabs.com/2014/11/04/technical-debt-relevant-projects.html

6.12 Dead Code

  • code that is never used
  • data never delivered to the user

6.12.1 Links

https://www.slideshare.net/dseguy/hunt-for-dead-code

Here are some reasons why unused code should be removed:

  • For anyone new working on a project, they not only have to understand the working code, they have to understand unused material also. This is wasted time and creates confusion.
  • There is a danger that at sometime someone will make a change which inadvertently involve the 'dormant' code and can introduce bugs. I know it's happened on projects I've worked on.
  • The maintenance of any code is an administrative burden. By preserving old redundant code that burden is increased. For example, merging changes in the main branch becomes harder because there is more code to work through and more possibility to make a mistake.
  • What happens over time is that more and more old unused code is added to the codebase. This increases the confusion, potential misunderstanding and administrative overhead.
  • The chances that the unused code will ever be used again is very unlikely. With time that possibility of re-use diminishes. If code is to be removed and is considered important enough then the code can be branched off and documented.
  • Any personal feelings that a coder may have about code they may have worked hard on are understandable. But part of being professional requires that those thoughts have to be put to one side for the better good. Time stands for no-one and there is no place for preserving historical code in a working codebase.

6.13 Bus Factor

7 Practices

are a set of informal rules that the software development community employ to help improve the quality of software.

7.1 Refactoring

7.1.1 The Rule of Three

The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor. Tip: Three strikes and you refactor. [M.Fowler, "Refactoring…"]

7.2 Always Use 'declare(strictypes=1)'

declare(stric_types=1);

$var  = '0';
if ( !$var ) {
   echo 'negation';
}

7.3 Always leave things better than you found them

boy scout rule : leave the (campground) code cleaner than you found it

7.4 Avoid Else, Return Early (Guard Clause)

Return as soon as you know your method cannot do any more meaningful work.

 public function foo(int $x): string
    {
        $result = null;

        if ($x === 1) {
            $result = 'a';
        } elseif ($x === 2) {
            $result = 'b';
        } else {
            $result = 'c';
        }

        return $result;
    }
 public function foo(int $x): string
    {
        if ($x === 1) {
            return 'a';
        }

        if ($x === 2) {
            return 'b';
        }

        return 'c';
    }

Refactoring: Replace Nested Conditional with Guard Clauses Guard clause provides an early exit from a subroutine. Removing one level of nesting and resulting in flatter code.

https://stackoverflow.com/questions/4838828/why-should-a-function-have-only-one-exit-point

7.5 Avoid Negative Conditionals

It is much easier, for the human mind, to comprehend positive reasoning. So if you can avoid negative conditionals, you should always take that path.

if (!count){
...
}
if (count == 0){
...
}

7.6 Avoid Temporary Variables

Temporary variable increase the temptation to write longer methods. Temporaries aren’t necessarily bad, but sometimes they attract new code.

7.7 Don't Use 'clone'

7.7.2 TODO show example with Doctrine

7.8 Don't Use 'else if'

Else if is not compatible with the colon syntax for if|elseif blocks. For this reason, use elseif for conditionals

<?php if ($user) { ?>
    <span>OK. Your registration is successful</span>
<?php } else { ?>
    <span>Something went wrong! Please try again later! </span>
<?php } ?>
 if ($user) : ?>
    <div>OK. Your registration is successful</div>
<?php else : ?>
    <div>Something went wr+ong! Please try again later!</div>
<?php endif ?>

Most of the time the alternative (endif) syntax is used in view scripts. It's often hard to see/notice the end of an if statement since a curly brace only takes up one character, when you're at the bottom of a file, it's hard to tell if it's the end of an if or a foreach. For example:

<?php if ($condition): ?>

    <div>a huge block of html</div>

<?php endif; ?>

https://www.mediawiki.org/wiki/Manual:Coding_conventions/PHP And the latter has poorer performance.

// This:
if ( $foo == 'bar' ) {
    echo 'Hello world';
} else if ( $foo == 'Bar' ) {
    echo 'Hello world';
} else if ( $baz == $foo ) {
    echo 'Hello baz';
} else {
    echo 'Eh?';
}

// Is actually equivalent to:
if ( $foo == 'bar' ) {
    echo 'Hello world';
} else {
    if ( $foo == 'Bar' ) {
        echo 'Hello world';
    } else {
        if ( $baz == $foo ) {
            echo 'Hello baz';
        } else {
            echo 'Eh?';
        }
    }
}

7.9 Don't Use Globals

EVIL in pure form ;)

7.10 Don't Use Magic Numbers

Raw numbers in code. Like 86400 - that's a number of seconds per day. But it is not so obvious for every one whats that number means Refactoring: Replace Magic Number with Symbolic Constant

7.11 Don't Use Method Chaining Syntax

Violating CQS

7.12 Don't Use Optional Dependencies

Use Constructor Injection not Setter Injection. Constructor Injection gives you a valid object with all its dependencies, upon construction.

7.13 Don't Use Switch Parameter

A method runs different code depending on the values of an parameter Refactoring: Replace Parameter with Method

7.14 Don't Use Traits

7.15 Eliminate or Reduce Number of Comments

7.16 Eliminate or Reduce Number of Parameters

Functions should have a small number of arguments. No argument is best, followed by one, two, and three. More than three is very questionable and should be avoided with prejudice.

7.18 Make Class Constants & Variables Always Private

7.19 Make Classes Always Final

7.20 Sprout Class

7.21 Sprout Method

When adding new functionality, write the code in a new method with TDD and then call this method from the old code. So even if you can’t test the code where your method is being called, at least the new code has tests.

  1. Identify where you need to make your code change.
  2. If the change can be formulated as a single sequence of statements in one place in a method, write down a call for a new method that will do the work involved and then comment it out. (I like to do this before I even write the method so that I can get a sense of what the method call will look like in context.)
  3. Determine what local variables you need from the source method, and make them arguments to the call.

4.Determine whether the sprouted method will need to return values to source method. If so, change the call so that its return value is assigned to a variable.

  1. Develop the sprout method using test-driven development.
  2. Remove the comment in the source method to enable the call.

7.22 Use parentheses

Parentheses help clarify the order of operators…etc. PHP won’t get confused if you don’t use parentheses because it knows the order of operators table very well. However, a person looking at your program has to figure out which is done first, and parentheses help group operations together.

if (age < 20 || sales < 1200 && hrsWorked > 15) {}
if ((age < 20) || ((sales < 1200) && (hrsWorked > 15))) {}

7.23 Wrap Class

Choosing to use Wrap Class is a whole other issue. There is a higher thresh- old for this pattern. Generally two cases tip me toward using Wrap Class: 1. The behavior that I want to add is completely independent, and I don’t want to pollute the existing class with behavior that is low level or unre- lated. 2. The class has grown so large that I really can’t stand to make it worse. In a case like this, I wrap just to put a stake in the ground and provide a roadmap for later changes.

7.24 Wrap Method

7.25 Naming

7.25.1 variable

7.25.2 method

  • isX() or hasX() for bool return type

7.25.3 snakecase

  1. Clients must use API with snakecase (keys in JSON object sent in request body are in snakecase).
  2. Database column names are also snakecase.

    Based on an eye tracking study on camelCase and snakecase (PDF) from 2010, snakecase is 20% easier to read than camelCase!

    name psr comunnity description
    method names camelCase() 21/22. lowerunder 1/22 camelCase()  
    Properties names $StudlyCaps or $camelCase or $underscore $camelCase  

    XMLHttpRequest is still a great tragedy

    Based on an (PDF) from 2010, snakecase is 20% easier to read than camelCase! eye tracking study on camelCase and snakecase https://stitcher.io/blog/have-you-thought-about-casing http://www.cs.loyola.edu/~binkley/papers/icpc09-clouds.pdf?fbclid=IwAR2lZJWpYcV-TK2HNpy-JmB3A9g0nSeCeSaDr2ZVh30hSlS41n5O48YoiWc

  3. Tests

    There is a fundamental difference between the two environments: in src methods name are composed solely of a verb and a noun because a method shall have a single responsability and a simple way of acting; in tests for most of the edge cases we wrote entire phrases explaining what the test code can't explain well or quickly.

7.26 instanceof

class MyClass
{
}

$a = new MyClass;
echo (!($a instanceof stdClass));
echo (!$a instanceof stdClass); // not

8 Principles

8.1 SOLID

There is a strong relationship beetween each of those principles. If you take each of those principles in isolation and try to apply them in your codebase you will get limited benefit out of that. it's only when you take enterly package apply it in it entarity. Applying it all at once. Strong sinergy efect.

8.1.1 Single Responsibilty (SRP)

A class should have only one reason to change - doing one thing, and do it well The object should be able to do the job completely The class has only one well-defined responsibility which is exclusively handling user data. No more, no less.

8.1.2 Open/Closed Principle (OCP)

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. Interface is open for extension but closed for modification.

8.1.3 Liskov Substitution (LSP)

Metody do klas bazowych, muszą być w stanie używać również obiektów klas dziedziczących po klasach bazowych. Program to an, interface, not an implementation.

8.1.4 Interface Segregation (ISP)

A client should never be forced to implement an interface that it doesn't use or clients shouldn't be forced to depend on methods they do not use.

8.1.5 Dependency Inversion (DIP)

Depend on abstractions, not concretions. Program to an, interface, not an implementation.

8.2 GRASP General Responsibility Assignment Software Patterns

  • Craig Larman 1997 - Applying UML and Patterns (BN)

8.3 Design

8.3.1 Separation of Concerns (SoC)

The no.1 - the most important

  1. opposite

    Big Ball of Mud

8.3.2 Big Ball of Mud

8.3.3 Command Query Separation (CQS)

8.3.4 Composition Over Inheritance

8.3.5 YAGNI

8.3.6 Don't Repeat Yourself (DRY)

8.3.7 The Law of Demeter (LoD)

Each unit should only talk to its friends; don't talk to strangers.

  • Object Calisthenics - One Arrow Per Line

8.4 Architectural

8.4.1 Model-View-Controller

• The Model: Captures and centralizes all the domain model behaviour. This layer manages all the data, logic and business rules independently of the data representation. It can be said that the Model layer is the heart and soul of every MVC application. • The Controller: Orchestrates interactions between the other layers. Triggers actions on the model in order to update its state and refreshes the representations associated to the model. Additionally, the Controller can also send messages to the View layer in order to change the specific Model representation. • The View: A layer whose main purpose is to expose the differing representations of the Model layer and to give a way to trigger changes on the Model’s state.

8.4.2 Api

  1. Tools
  2. underscore vs camelCase vs kebab
  3. Info

    Pluralization of resource names in REST URIs is the widely adopted standard followed by the overwhelming majority of public and private APIs.

    method endpoint controller info
    GET /resources list returns a list of resource items
    POST /resources   creates one or many resource items
    PUT /resources   updates one or many resource items
    PATCH /resources   partially updates one or many resource items
    DELETE /resources   deletes all resource items And for single resource items:
    GET resources:id show returns a specific resource item based on :id parameter
    POST resources:id create creates one resource item with specified id (requires validation)
    PUT resources:id   updates a specific resource item
    PATCH resources:id update partially updates a specific resource item
    DELETE resources:id delete deletes a specific resource item
    1. HTTP Semantics
      1. DELETE

        If a DELETE method is successfully applied, the origin server SHOULD send a 202 (Accepted) status code if the action will likely succeed but has not yet been enacted, a 204 (No Content) status code if the action has been enacted and no further information is to be supplied, or a 200 (OK) status code if the action has been enacted and the response message includes a representation describing the status.

      2. PATCH

        ???

    2. Sorting

      We can also add a sort parameter to sort by field. The sort field in turn contains a list of comma separated columns to sort on; the first in the list is the highest sort priority. In order to negatively sort you prefix a column with a negative sign - GET /tickets?sort=-amount: sort orders by descending order of amount (highest first). GET /tickets?sort=-amount,createdat: sort orders by descending order of amount (highest first). Within those amounts (with orders of equal amounts), older orders are listed first.

    3. Searching

      We can then search using a simple parameter that applies a search query that can then be routed through a search service (for example, ElasticSearch). Suppose we want to search orders for the phrase refund, we can define a field for search queries: GET /orders?q=refund

    4. Limiting fields

      Additionally, using a fields parameter we can query for specific fields: GET /orders?fields=amount,createdat,customername,shippingaddress

  4. How to pack data

    https://jsonapi.org/format/

    A JSON object MUST be at the root of every JSON:API request and response containing data. This object defines a document’s “top level”.

    A document MUST contain at least one of the following top-level members:

    data: the document’s “primary data” errors: an array of error objects meta: a meta object that contains non-standard meta-information.

    The members data and errors MUST NOT coexist in the same document.

  5. Links

9 Patterns

  • formalized best practices
  • named description of a problem and solution that can be applied to new contexts
  • an idea that has been useful in one practical context

and will probably be useful in others

9.1 Software design patterns

9.1.1 Creational

Creation of objects themselves - separate the construction of a complex object from its representation

  1. Factory

    Separating the creation of an object from the actual implementation. If creating the object is a complicated job you can do all of the work in the factory, instead of repeating it every time you want to create a new instance.

    1. Simple Factory
      class Bicycle
      {
      }
      
      class SimpleFactory
      {
          public function createBicycle(): Bicycle
          {
              return new Bicycle();
          }
      }      
      
      class SimpleFactoryTest extends TestCase
      {
          public function testCanCreateBicycle()
          {
              $bicycle = (new SimpleFactory())->createBicycle();
              $this->assertInstanceOf(Bicycle::class, $bicycle);
          }
      }
      
    2. Method Factory
      interface CarFactory 
      {
          public function makeCar();
      }
      
      interface Car 
      {
          public function getType();
      }
      
      class SedanFactory implements CarFactory 
      {
          public function makeCar() 
          {
              return new Sedan();
          }
      }
      
      class Sedan implements Car 
      {
          public function getType() 
          {
              return 'Sedan';
          }
      }
      
      /* Client */
      $factory = new SedanFactory();
      $car = $factory->makeCar();
      
    3. Abstract Factory
      1. https://stackoverflow.com/questions/2280170/why-do-we-need-abstract-factory-design-pattern
    4. Links
  2. Builder
    class Car
    {
        ...
    }
    
    class CarBuilder
    {
        public function __construct()
        {
            $car = new Car;
        }
        
        public function build(): Car
        {
            return $car;   
        }
    
        public function setSeats(int $seats)
        {
            $car->setSeats($seats);
        }
    }
    
    1. links
  3. Prototype
    abstract class Prototype{
        protected $name;
     
        public function __construct($name) {
            $this->name=$name;
        }
        abstract function __clone();
        public function getName() {
            return $this->name;
        }
    }
     
    class ConcretePrototype extends Prototype{
     
        public function __construct($name) {
            parent::__construct($name);
        }
        public function __clone() {}
    }
     
    // testy
    $prototype = new ConcretePrototype("nazwa");
    echo  $prototype->getName(); // wyswietli "nazwa"
    $prototype2 = clone $prototype;
    echo  $prototype2->getName(); // wyswietli "nazwa"
    
    
  4. Dependency Injection

    A class receives its dependencies from external sources rather than creating them itself. It's a method of decoupling code & following the Dependency Inversion principle.

    1. Types of injection:
      1. Construction injection:

        dependencies are injected when creating the object. It can be used for required and optional dependencies.

      2. Setter injection:

        dependencies are injected through setters, and they are always optional.

      3. Property injection:

        dependencies are injected directly through public properties. This type of injection is not recommended as there is no control at all of what is being injected.

    2. Links
    3. Books
      1. Dependency Injection Principles, Practices, and Patterns Mark Seemann, Steven van Deursen

9.1.2 Structural

They act as interconnectors between entities. It serves as a blueprint for how basic classes can be combined to form bigger entities. Structural patterns describe the static architecture of a design;

  1. Bridge

    The Bridge pattern can be quite straightforward; it effectively allows us to decouple an abstraction from an implementation so the two can vary independently.

    interface FormatterInterface
    {
        public function format(string $text);
    }
    
    class PlainTextFormatter implements FormatterInterface
    {
        public function format(string $text)
        {
            return $text;
        }
    }
    
    class HtmlFormatter implements FormatterInterface
    {
        public function format(string $text)
        {
            return sprintf('<p>%s</p>', $text);
        }
    }
    
    abstract class Service
    {
        /**
         * @var FormatterInterface
         */
        protected $implementation;
    
        /**
         * @param FormatterInterface $printer
         */
        public function __construct(FormatterInterface $printer)
        {
            $this->implementation = $printer;
        }
    
        /**
         * @param FormatterInterface $printer
         */
        public function setImplementation(FormatterInterface $printer)
        {
            $this->implementation = $printer;
        }
    
        abstract public function get();
    }
    
    class HelloWorldService extends Service
    {
        public function get()
        {
            return $this->implementation->format('Hello World');
        }
    }
    
    class BridgeTest extends TestCase
    {
        public function testCanPrintUsingThePlainTextPrinter()
        {
            $service = new HelloWorldService(new PlainTextFormatter());
            $this->assertEquals('Hello World', $service->get());
    
            // now change the implementation and use the HtmlFormatter instead
            $service->setImplementation(new HtmlFormatter());
            $this->assertEquals('<p>Hello World</p>', $service->get());
        }
    }
    
  2. Facade
    • A Facade is meant to decouple a client and a sub-system by embedding many (but sometimes just one) interface, and of course to reduce complexity.
    • That’s why a good facade has no new in it. If there are multiple creations for each method, it is not a Facade, it’s a Builder or a [Abstract|Static|Simple] Factory [Method].
    • The best facade has no new and a constructor with interface-type-hinted parameters. If you need creation of new instances, use a Factory as argument.
    • A Facade design pattern works providing a single class that in itself instantiates other classes and provides a simple interface to use those functions. A warning when using such pattern is that, as classes are instantiated within the Facade, you are essentially tightly coupling the classes that it utilizes. There are cases where you want this, but there are cases where you do not. Where do you do not want this behavior, you are better suited to using dependency injection. I have found this to be useful when wrapping a set of poor APIs into a single unified API. It reduces external dependencies, allowing complexity to be internalized; this process can make your code more readable. In other situations, where the various classes were loosely coupled together, we may find it better to use dependency injection. By injecting objects that perform various actions into the ToyFactory class we can benefit from making testing easier by being able to inject fake classes that the ToyFactory class can manipulate. Personally, I am a huge believer in making code as easily testable as possible; hence why I don't like this approach.
    class Facade
    {
        /**
         * @var OsInterface
         */
        private $os;
    
        /**
         * @var BiosInterface
         */
        private $bios;
    
        /**
         * @param BiosInterface $bios
         * @param OsInterface   $os
         */
        public function __construct(BiosInterface $bios, OsInterface $os)
        {
            $this->bios = $bios;
            $this->os = $os;
        }
    
        public function turnOn()
        {
            $this->bios->execute();
            $this->bios->waitForKeyPress();
            $this->bios->launch($this->os);
        }
    
        public function turnOff()
        {
            $this->os->halt();
            $this->bios->powerDown();
        }
    }
    
    interface OsInterface
    {
        public function halt();
    
        public function getName(): string;
    }
    
    interface BiosInterface
    {
        public function execute();
    
        public function waitForKeyPress();
    
        public function launch(OsInterface $os);
    
        public function powerDown();
    }
    
    class FacadeTest extends TestCase
    {
        public function testComputerOn()
        {
            /** @var OsInterface|\PHPUnit_Framework_MockObject_MockObject $os */
            $os = $this->createMock('DesignPatterns\Structural\Facade\OsInterface');
    
            $os->method('getName')
                ->will($this->returnValue('Linux'));
    
            $bios = $this->getMockBuilder('DesignPatterns\Structural\Facade\BiosInterface')
                ->setMethods(['launch', 'execute', 'waitForKeyPress'])
                ->disableAutoload()
                ->getMock();
    
            $bios->expects($this->once())
                ->method('launch')
                ->with($os);
    
            $facade = new Facade($bios, $os);
    
            // the facade interface is simple
            $facade->turnOn();
    
            // but you can also access the underlying components
            $this->assertEquals('Linux', $os->getName());
        }
    }
    
    
  3. Composite

    To treat a group of objects the same way as a single instance of the object.

    Composite Imagine an audio system consisting of individual songs and also playlists of songs. Yes, playlists consist of songs, but we want both to be treated individually. Both are types of music, both can be played. The Composite design pattern can help here; it allows us to ignore the differences between compositions of objects and individual objects. It allows us to treat both with identical or nearly-identical code. Let's put together a little example; a song is our example of a leaf, with playlists being composites. Music is our abstraction of playlists and songs; therefore, we can call this our component. The client of all this is our index.php file. By not discriminating between leaf-nodes and branches, our code becomes less complex and therefore less error prone.

    interface RenderableInterface
    {
        public function render(): string;
    }
    
    /**
     * The composite node MUST extend the component contract. This is mandatory for building
     * a tree of components.
     */
    class Form implements RenderableInterface
    {
        /**
         * @var RenderableInterface[]
         */
        private $elements;
    
        /**
         * runs through all elements and calls render() on them, then returns the complete representation
         * of the form.
         *
         * from the outside, one will not see this and the form will act like a single object instance
         *
         * @return string
         */
        public function render(): string
        {
            $formCode = '<form>';
    
            foreach ($this->elements as $element) {
                $formCode .= $element->render();
            }
    
            $formCode .= '</form>';
    
            return $formCode;
        }
    
        /**
         * @param RenderableInterface $element
         */
        public function addElement(RenderableInterface $element)
        {
            $this->elements[] = $element;
        }
    }
    
    class InputElement implements RenderableInterface
    {
        public function render(): string
        {
            return '<input type="text" />';
        }
    }
    
    class TextElement implements RenderableInterface
    {
        /**
         * @var string
         */
        private $text;
    
        public function __construct(string $text)
        {
            $this->text = $text;
        }
    
        public function render(): string
        {
            return $this->text;
        }
    }
    
    class CompositeTest extends TestCase
    {
        public function testRender()
        {
            $form = new Composite\Form();
            $form->addElement(new Composite\TextElement('Email:'));
            $form->addElement(new Composite\InputElement());
            $embed = new Composite\Form();
            $embed->addElement(new Composite\TextElement('Password:'));
            $embed->addElement(new Composite\InputElement());
            $form->addElement($embed);
    
            // This is just an example, in a real world scenario it is important to remember that web browsers do not
            // currently support nested forms
    
            $this->assertEquals(
                '<form>Email:<input type="text" /><form>Password:<input type="text" /></form></form>',
                $form->render()
            );
        }
    }
    
  4. Adapter (Wrapper)
    // Concrete Implementation of PayPal Class
    class PayPal {
         
        public function __construct() {
            // Your Code here //
        }
         
        public function sendPayment($amount) {
            // Paying via Paypal //
            echo "Paying via PayPal: ". $amount;
        }
    }
     
    // Simple Interface for each Adapter we create
    interface paymentAdapter {
        public function pay($amount);
    }
     
    class paypalAdapter implements paymentAdapter {
         
        private $paypal;
     
        public function __construct(PayPal $paypal) {
            $this->paypal = $paypal;
        }
         
        public function pay($amount) {
            $this->paypal->sendPayment($amount);
        }
    }
    
    // Client Code
    $paypal = new paypalAdapter(new PayPal());
    $paypal->pay('2629');
    

    getData and setData (not as “pretty”).

  5. Container
    1. Benchmark

9.1.3 Behavioral

They work to explain how objects interact with each other; how they can send messages between each of the objects and how you can divide the steps of various tasks up among classes. Describe a flowing process.

  1. Chain Of Responsibility

    Is an object oriented version of the if … else if … else if ……. else … endif idiom

    interface PurchaserInterface
    {
        public function setNextPurchaser(PurchaserInterface $nextPurchaser): void;
    
        public function buy($price): void;
    }
    
    final class AssociatePurchaser implements PurchaserInterface
    {
        /**
         * @var PurchaserInterface
         */
        private $nextPurchaser;
    
        public function setNextPurchaser(PurchaserInterface $nextPurchaser): void
        {
            $this->nextPurchaser = $nextPurchaser;
        }
    
        public function buy($price): void
        {
            if ($price < 100) {
                echo('Associate purchased');
                return;
            }
    
            if ($this->nextPurchaser) {
                $this->nextPurchaser->buy($price);
                return;
            }
    
            echo 'Associate could not buy';
        }
    }
    
    final class ManagerPurchaser implements PurchaserInterface
    {
        /**
         * @var PurchaserInterface
         */
        private $nextPurchaser;
    
        public function setNextPurchaser(PurchaserInterface $nextPurchaser): void
        {
            $this->nextPurchaser = $nextPurchaser;
        }
    
        public function buy($price): void
        {
            if ($price < 200) {
                echo('Manager purchased');
                return;
            }
    
            if($this->nextPurchaser) {
                $this->nextPurchaser->buy($price);
                return;
            }
    
            echo 'Manager could not buy';
        }
    }
    
    final class DirectorPurchaser implements PurchaserInterface
    {
        /**
         * @var PurchaserInterface
         */
        private $nextPurchaser;
    
        public function setNextPurchaser(PurchaserInterface $nextPurchaser): void
        {
            $this->nextPurchaser = $nextPurchaser;
        }
    
        public function buy($price): void
        {
            if ($price < 300) {
                echo('Director purchased');
                return;
            }
    
            if($this->nextPurchaser) {
                $this->nextPurchaser->buy($price);
                return;
            }
    
            echo 'Director could not buy';
        }
    }
    
    class ChainOfResponsibilityTest extends TestCase
    {
        public function testOne()
        {
            $this->expectOutputString('Director purchased');
    
            $associate = new AssociatePurchaser();
            $manager = new ManagerPurchaser();
            $director = new DirectorPurchaser();
            $associate->setNextPurchaser($manager);
            $manager->setNextPurchaser($director);
    
            $associate->buy(299);
        }
    }
    
    
  2. Observer

    The Observer design pattern essentially allows an object (the subject) to maintain a list of observers that are automatically notified when the state of the that object changes. This pattern applies a one-to-many dependency between objects; there is always one subject that updates many observers. This pattern applies a one-to-many dependency between objects; there is always one subject that updates many observers.

    class User implements \SplSubject
    {
        /**
         * @var string
         */
        private $email;
    
        /**
         * @var \SplObjectStorage
         */
        private $observers;
    
        public function __construct()
        {
            $this->observers = new \SplObjectStorage();
        }
    
        public function attach(\SplObserver $observer)
        {
            $this->observers->attach($observer);
        }
    
        public function detach(\SplObserver $observer)
        {
            $this->observers->detach($observer);
        }
    
        public function changeEmail(string $email)
        {
            $this->email = $email;
            $this->notify();
        }
    
        public function notify()
        {
            /** @var \SplObserver $observer */
            foreach ($this->observers as $observer) {
                $observer->update($this);
            }
        }
    }
    
    class UserObserver implements \SplObserver
    {
        /**
         * @var User[]
         */
        private $changedUsers = [];
    
        /**
         * It is called by the Subject, usually by SplSubject::notify()
         *
         * @param \SplSubject $subject
         */
        public function update(\SplSubject $subject)
        {
            $this->changedUsers[] = clone $subject;
        }
    
        /**
         * @return User[]
         */
        public function getChangedUsers(): array
        {
            return $this->changedUsers;
        }
    }
    
    class ObserverTest extends TestCase
    {
        public function testChangeInUserLeadsToUserObserverBeingNotified()
        {
            $observer = new UserObserver();
    
            $user = new User();
            $user->attach($observer);
    
            $user->changeEmail('foo@bar.com');
            $this->assertCount(1, $observer->getChangedUsers());
        }
    }
    
  3. Strategy

    Allow us to alter the behavior of an object at runtime. We defined a family of algorithms, bound by one common interface These algorithms are interchangeable; they can be swapped in and out without affecting the client implementation We encapsulated each algorithm within a class

    class Customer
    {
        /**
         * @var float
         */
        private $bill;
    
        /**
         * @var BillingStrategyInterface
         */
        private $strategy;
    
        public function __construct(BillingStrategyInterface $strategy)
        {
            $this->strategy = $strategy;
        }
    
        public function setStrategy(BillingStrategyInterface $strategy)
        {
            $this->strategy = $strategy;
        }
    
        public function addBeer(float $price): void
        {
            $this->bill += $this->strategy->getPrice($price);
        }
    
        public function printBill(): void
        {
            echo "Total: $this->bill";
        }
    }
    
    interface BillingStrategyInterface
    {
        public function getPrice(float $rawPrice): float;
    }
    
    class NormalStrategy implements BillingStrategyInterface
    {
        public function getPrice(float $rawPrice): float
        {
            return $rawPrice;
        }
    }
    
    class HappyHourStrategy implements BillingStrategyInterface
    {
        public function getPrice(float $rawPrice): float
        {
            return $rawPrice * 0.5;
        }
    }
    
    class StrategyTest extends TestCase
    {
        public function testOne()
        {
            $this->expectOutputString('Total: 15');
    
            //Normal billing
            $customer = new Customer(new NormalStrategy());
            $customer->addBeer(10);
    
            //Start Happy Hour
            $customer->setStrategy(new HappyHourStrategy());
            $customer->addBeer(10);
    
            $customer->printBill();
        }
    }
    
  4. Command

    Command objects encapsulate an action and its parameters. We have an Invoker and a Receiver

  5. Iterator

    Iterators are used to access the elements of an aggregate object sequentially without exposing its underlying representation

  6. Interpreter

    GOF

    1. Query Builder
  7. Null Object

    Designed to act as a default value of an object

  8. Template method:

    Describes the program skeleton of a program

  9. State

9.1.4 Concurrency

9.2 Architectural patterns

This is not strictly a design pattern (but the Gang of Four didn't cover Architectural patterns in their book); but it is incredibly relevant for PHP developers due to the web-oriented nature of PHP. Architectural patterns address various different constraints in computer systems through addressing performance limitations, high availability, and also minimization of business risk. Most developers will be familiar with the Model-View-Controller architecture when it comes to web frameworks, more recently other architectures have started to emerge; for example, a microservices architecture works by a set of RESTful APIs that are independent and interconnected. Some people believe microservices move problems from the software development layer to the systems architecture layer. The opposite of microservices often referred to as a monolithic architecture, is where all the code is together in one application.

9.2.1 Active Record

Problem: Accessing data in a database prevent duplication & centralize access don't have to add any properties to class, just add new column to table objects are tightly coupled to the database schema - hard to test without actually using database breaking SOLID's Single Responsibility Principle - object is responsible for knowing how to create, retrieve, update and delete database entry

<?php declare(strict_types=1);

class User
{

    /**
     * @var int
     */
    private $id;

    /**
     * @var string
     */
    private $name;

    public function getId(): int
    {
        return $this->id;
    }

    public function setId(int $id)
    {
        $this->id = $id;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name)
    {
        $this->name = $name;
    }

}

$id = 1;
$pdo = new PDO('sqlite:test.db');
$sth = $pdo->prepare("SELECT * FROM user WHERE id =:id");
$sth->bindParam(":id", $id, PDO::PARAM_INT);
$sth->execute();
$row = $sth->fetch(PDO::FETCH_ASSOC);
$user = new User();
$user->SetId((int) $row['id']);
$user->SetName($row['name']);

cons: hardcoded columns name, every time we add new column to database we have to manually add it in code in multiple places, hard to maintain,

<?php declare(strict_types=1);

class User
{
    private $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
    public function load(int $id)
    {
        $sth = $this->pdo->prepare("SELECT * FROM user WHERE id =:id");

        $sth->bindParam(":id", $id, PDO::PARAM_INT);
        $sth->execute();
        $row = $sth->fetch(PDO::FETCH_ASSOC);

        $i = 0;
        foreach($row as $column => $value) {

            $meta = $sth->getColumnMeta($i);

            if($meta['sqlite:decl_type'] === 'INTEGER')
            {
                $this->$column = (int) $value;
            }else{
                $this->$column = $value;
            }

            $i++;
        }
    }
}

$pdo = new PDO('sqlite:test.db');
$user = new User($pdo);
$user->load(1);

pros: you don’t have to specify the properties of the object and how they relate to the database. The model is able to determine the properties automatically by looking at the schema of the database.

9.2.3 Data Transfer Object DTO

"a class with public variables and no functions" clean code p. 100. But in PHP we still can't declare type of variable, just type-hint parameters of methods. Like setters, so we can do it indirectly. Another great benefit it the standard rule is to not have public properties so we can stay consisten with this one. But more of great adventage of if we can make our DTO object immutable. So create only getters, without setters. Add all in constructor.

class IssResponse
{
    /**
     * @var float
     */
    private $latitude;

    /**
     * @var float
     */
    private $longitude;

    public function __construct(array $array)
    {
        $this->latitude = $array['latitude'];
        $this->longitude = $array['longitude'];
    }

    public function getLatitude(): float
    {
        return $this->latitude;
    }


    public function getLongitude(): float
    {
        return $this->longitude;
    }

}

final class PositionDTO
{
    /**
       @var float
    */
    private $latitude;

    /**
       @var float
    */
    private $longitude;

    public function __construct(float $latitude, float $longitude)
    {
        $this->latitude = $latitude;
        $this->longitude = $longitude;
    }

    public function getLatitude(): float
    {
        return $this->latitude;
    }

    public function getLongitude(): float
    {
        return $this->longitude;
    }
}

9.2.5 MVC

  1. Controllers
    • are what the user interacts with
    • they receive a request from the user, decide what to do, and send request back
    • it's the only component that interacts with the models
  2. Models
    • classes that are designed to work with information in your database
    • are where an anpplication's data are stored
    • responsible for storing and retrieving data
    • know nothing about the user interface
  3. Views
    • are what the user sees on the screen
    • they present the data to the user
    • kno nothing about the models
  4. Why use MVC?
    • business logic separate from presentation: Separation Of Concerns
    • developer specialisation
      • designers can focus on the front end without worrying about the business logic
      • developers of the models can focus on the business logic or back end without worrying about the look and feel
  5. Front controller
    • provide a central entry point for all request. All request are sent through one page
  6. Action suffix
    1. _call is exectued for a non-existent or non-public method call
    2. Stack

      No it wasn't just a naming convention. It was used to execute some code before or after every controller 'action' method. Like checking is user has logged in. It is based on magic _call function which is executed for a non-existent or non-public method call.

        $controller = new Posts();
        $controller->index();
      
        class Posts
        {
          public function __call($name, $args)
        {
        //run code before
        call_user_func_array()[$this, "$nameAction"], $args);
        //run code after
        }
          public function indexAction()
        {
        }
        }
      

      tutorial ended on 31 video

  7. tutorials
    1. MVC: It's all a lie!
      1. controller problems
        • poor separation of concerns
        • does a lot of things
        • has a lot of dependencies
        • becomes really fat
        • and hard to maintain
      2. ADR
        1. action
          • a function or class implementing the Command pattern
          • collects data from request and passes it to Domain
          • invoke Domain and retains the result
          • invokes Responder with any data needed
        2. domain
          • en entry point into whatever does the domain work
        3. responder
          • deals with all output
            • sets cookies
            • sets headers
            • applies compression
            • chooses presentation format
            • renders templates
  8. problems
    • fat controller and fat model

9.2.6 MVVM

Magento was here.

9.3 Antipatterns

9.3.1 God objects

Essentially, a God object is an object with either too many methods or too many properties; essentially, it's a class that knows too much or does too much. The God object soon becomes tightly coupled to (referenced by) lots of other bits of code in the application. So what's actually wrong with this? Well, in short, when you have one bit of code tied into every single other bit of code, you quickly find a maintenance disaster. If you adjust the logic for a method in a God object for one use case, you might find it having unintended consequences for another element.

The flip side to God objects being an anti-pattern is when developing embedded systems. Embedded systems are used to process data on anything from a calculator to LED signage; they are small chips that are essentially self-contained computers and quite low cost. In this use case, with restricted computational power you can often find that programming elegance and maintainability become peripheral concerns. Slight performance increase and centralization of control can be more important, meaning using God objects can be somewhat sensible. Fortunately, PHP is incredibly seldom used to program embedded systems, so you are incredibly unlikely to find yourself in this particular situation.

Another anti-pattern, called Fear of Adding Classes,

9.3.2 Singleton

<?php class{ Singleton private static $instance; public static function getInstance() { if (null = static::$instance) { static::$instance = new static(); } } return static::$instance; protected function _construct() { } private function _clone() { } private function _wakeup() { } }

So here are the reasons why this should be avoided:

  • They are inherently tightly coupled meaning they are difficult to test, for example

using unit tests. They even maintain their state throughout the life cycle of the application.

  • They violate the Single Responsibility Principle by controlling their own creation

and life cycle.

  • Fundamentally, it results in you hiding the dependencies of your application in a

global instance. You can no longer effectively follow your dependencies around your code as you can't follow where they are injected as function arguments. They make it ineffective to find the dependency chain should you need to analyze it.

Objects should typically be self-contained; they should only know problems about themselves and also should only solve one set of problems, its own problems. Anything that isn't relevant to this aim doesn't belong in that class.

9.3.3 Database as IPC

https://blog.engineyard.com/5-subtle-ways-youre-using-mysql-as-a-queue-and-why-itll-bite-you Let me clear this up for you; your database isn't a message queuing system. You don't use it schedule jobs or queue up tasks to be completed. If you need something to do that, use a queuing system. Your database is for data…the clue is in the name; don't shove temporary messages in there. There are many reasons why this is a bad idea. One major issue is the fact that in databases there is no real way to not enforce a policy by which you can guarantee that a double-read will not occur, and that is by utilizing row locks. This in turn, results in processes (either incoming out outgoing) being blocked, which in turn results in processing only being able to be done in a serial fashion. Furthermore, in order to check if there is any work to do you end up essentially counting the rows of data in the database to see if there is work to do; you run this on a continuous basis. MySQL doesn't support push notifications; unlike PostgreSQL it doesn't have the NOTIFY command to pair with a LISTEN channel. Also note that when you merge a job queue with a database table that stores real data, you also invalidate the cache every time you complete a job and update a flag, in turn making MySQL far slower. In short, it results in your database performing worse and can force it to slow critical messages to a standstill. You must be careful not to turn your database into a job queue by having this functionality sneak up on you; instead, use the database exclusively for data, and bear this in mind when extending your database. RabbitMQ provides an open source queuing system with some great PHP SDKs.

Interface Bloat Interfaces shouldn't contain thousands of methods that reference internal operations of the class. They should be lightweight and considered a way of guaranteeing that when something is queried that it is definitely there.

Interfaces should be used sparingly; do you actually need an interface if the class is only ever going to be implemented once and once alone (and realistically, no one is never going to need to tamper with such code?). If so, you might want to consider avoiding an interface in such a situation.

So, let me draw you to one implementation of Interface Bloat. Let's take a look at the Pheanstalk interface class in the Pheanstalk open source library (note I have stripped the comments to make it more readable): <?php namespace Pheanstalk; interface PheanstalkInterface { const DEFAULTPORT = 11300; const DEFAULTDELAY = 0; const DEFAULTPRIORITY = 1024; const DEFAULTTTR = 60; const DEFAULTTUBE = 'default'; public function setConnection(Connection $connection); public function getConnection(); public function bury($job, $priority = self::DEFAULTPRIORITY); public function delete($job); [ 49 ] Anti-Patterns public function ignore($tube); public function kick($max); public function kickJob($job); public function listTubes(); public function listTubesWatched($askServer = false); public function listTubeUsed($askServer = false); public function pauseTube($tube, $delay); public function resumeTube($tube); public function peek($jobId); public function peekReady($tube = null); public function peekDelayed($tube = null); public function peekBuried($tube = null); public function put($data, $priority = self::DEFAULTPRIORITY, $delay = self::DEFAULTDELAY, $ttr = self::DEFAULTTTR); public function putInTube($tube, $data, $priority = self::DEFAULTPRIORITY, $delay = self::DEFAULTDELAY, $ttr = self::DEFAULTTTR); public function release($job, $priority = self::DEFAULTPRIORITY, $delay = self::DEFAULTDELAY); public function reserve($timeout = null); public function reserveFromTube($tube, $timeout = null); public function statsJob($job); public function statsTube($tube); public function stats(); public function touch($job); public function useTube($tube); public function watch($tube); public function watchOnly($tube); } Yuck! Notice how even constants have been put in the implement, the one thing you might actually want to change. Clearly, this is an interface for a class that can only be implemented one way, making the Interface useless.

Bloated optimization Often, developers may trip over themselves trying to optimize their code or their design artifacts to a ridiculous extent, often before their code even performs basic functions, or even before any code has been created at all. This can rapidly perform issues in production. In this section, I wish to discuss three anti-patterns specifically relating to this topic: Analysis paralysis Bikeshedding Premature optimization [ 62 ] Anti-Patterns Analysis paralysis In short, this is where a strategy is over-analyzed to the point where progress is slowed down, or even stopped entirely in extreme cases. Not only can such solutions become obsolete rapidly, they can be made in under-educated circumstances, for example, in a meeting where an over-analytic boss tries to dig too deep into detail in advance without allowing their developers to actually do some research. Over-analyzing a problem and seeking a perfect solution upfront just does not work; programmers should seek to refine their solution, not come up with the refined solution up front. Bikeshedding Essentially, this is where analysis paralysis can occur on the basis of some very trivial decisions, for example, the color of a log in page. The only fix that's required is to not waste time on trivial decisions. Avoid design by committee where possible as the majority of people, regardless of how good they think their design skills are, are largely incompetent at design. Premature optimization In this section, so far, I've largely beaten up project managers; no time to beat up developers. Often, developers will seek to optimize their code prematurely without having educated data-led conclusions to drive where and when optimizations should be made. Writing clean and readable code is your first priority; then you can use some great profiling tools to determine where your bottlenecks are. XDebug and New Relic are just some of the tools that are good at this. That said, there are some cases where optimization must be done, particularly on some long computational tasks where it can be mission-critical to reduce something from O(N2) time to O(N). This said, most simple PHP web apps will have no real need to use this consideration.

9.3.4 Is storing types in the database an anti pattern?

You're then binding the type name to outside data, limiting your refactoring capabilities and making people change stuff in two places when they make a new class. https://stackoverflow.com/questions/336958/how-bad-is-it-to-store-class-and-assembly-names-in-the-database My hesitation over doing this is that I think it introduces a higher degree of coupling between the layers.

9.5 To add

9.5.2 ParamConverter

Value Resolver Route Model Binding

9.6 Enum

https://stitcher.io/blog/php-enums composer require myclabs/php-enum

10 Tests

10.3 TDD

Tests Focus on Require Speed Complexity Setup Needed
Unit Tests a class/method the source code very fast low no
Integration Tests a component/service part of the running system slow medium yes
           
           

10.4 Behat

10.4.1 install

behat/mink-extension

10.4.2 config

baseurl: 'http://localhost' Remember that have to be with http://

10.5 Notes

There are numerous benefits to writing unit tests; they help with regression, provide documentation, and facilitate good design.

Two Approach Test First Test After

Test doubles are tools you can use when you need to create substitute dependencies]

Legacy codebases are not ready for isolated unit tests.

ARRANGE-ACT-ASSERT a pattern for arranging and formatting code in UnitTest methods: Each method should group these functional sections, separated by blank lines: Arrange all necessary preconditions and inputs. Act on the object or method under test. Assert that the expected results have occurred.

'bit by bit you rewrite your code to be testable'

A double is a substitue for a real dependency

Assertions base test - most framework

dummies, spies, stubs, mocks, fakes

dummies - a stand-in for a dependency when class signatures or functionality don't matter, like PHP stdObject - but fail on type hints :/ stubs - substitue for a dependency and it matches the class signature, use stubs if you use type hints mocks - a stub that uses the framework tools - most common

fakes - dependency built without the use of framework tools

feedback loop

'your decision to not build systems to catch mistakes will cost you more money

Chris???

https://github.com/opencfp/opencfp

Dependencies that you are unable to set at runtime can cause a problem ->

What to test ? Critical Functionality - First the most valuable parts - like register form if it ncessary. Bug Fixes - Every Bug that was found. New Features - New Functionality

https://github.com/kahlan/kahlan

  • use real dependencies when you can
  • when you can't use real dependencies, try test doubles
  • if you have significant amounts of code that would be burdensome to refactor, consider monkey patching
  • keep doubles in sync with real dependencies

Manual or Automate Testing

-avoid regressions

Permutations != Execution Paths - you only nee to write a test case for each execution path, not for each permutation. The number of possible paths grows with each new decision branch.

https://www.brandonsavage.net/dont-write-useless-unit-tests/

http://www.ifdattic.com/mock-test-double-using-prophecy/

http://stakeholderwhisperer.com/posts/2015/1/economy-of-tests

First, create the test. Second, write the minimum amount of code to get that test to pass. And third, now that your tests are passing, you can safely refactor your code to make it fancier.

Test. Code. Refactor.

You should write the tests first and then write your code.

unit - test one specific method on a class. Fake any needed database connections. One class in complete isolation.

integration - just like a unit test. Except it uses the real database connection.

functional - write a test to command a browser. Browser surfs your site, clicks links, fills out forms & asserts things is sees on the page. Testing the interface that users actually use!

Mock services. But don't mock simple model objects.

Let me say it a different way: if you're organizing your code well, then all classes will fall into one of two types. The first type - a model class - is a class whose job is basically to hold data… but not do much work. Our entities are model classes. The second type - a service class - is a class whose main job is to do work, but it doesn't hold much data, other than maybe some configuration. DinosaurFactory is a service class.

As a rule, you will want to mock service classes, but you do not need to mock model classes. Why not? Well, you can… but usually it's overkill. Since model classes tend to be simple and just hold data, it's easy enough to create those objects and set their data to whatever you want.

https://github.com/humbug/humbug

https://github.com/beberlei/assert

You need tests; yes, automated tests can be slow to write, but they are crucial for ensuring things don't break when you rewrite or refactor them.

Isoloate One Method

Pinpointing the problem

10.8 Why?

10.8.1 Less coupled code

When code is tightly coupled, it can be difficult to unit test. Without creating unit tests for the code that you're writing, coupling may be less apparent. Writing tests for your code will naturally decouple your code, because it would be more difficult to test otherwise.

10.9 PHPUnit

$this->getMockBuilder(Object:class) ->setMethodExcept(['someMethod']) ->getMock(); https://devstyle.pl/2013/04/22/testy-jednostkowe-materialy-do-nauki/

10.9.1 xdebug

private function getDebugQuery()
{
    $debuggingQuerystring = '';
    if (isset($_GET['XDEBUG_SESSION_START'])) { // xdebug
        $debuggingQuerystring = 'XDEBUG_SESSION_START=' . $_GET['XDEBUG_SESSION_START'];
    }
    if (isset($_COOKIE['XDEBUG_SESSION'])) { // xdebug (cookie)
        $debuggingQuerystring = 'XDEBUG_SESSION_START=PHPSTORM';
    }
    if (isset($_GET['start_debug'])) { // zend debugger
        $debuggingQuerystring = 'start_debug=' . $_GET['start_debug'];
    }
    if (empty($debuggingQuerystring)) {
        $debuggingQuerystring = 'XDEBUG_SESSION_START=PHPSTORM';
    }

    return $debuggingQuerystring;
}

php -dxdebug.remoteenable=1 -dxdebug.remoteautostart=1 –stop-on-failure vendor/bin/phpunit –colors=always

#!/bin/bash
if [ $# -eq 0 ]; then
    php -dxdebug.remote_enable=1 -dxdebug.remote_autostart=1 vendor/bin/phpunit --colors=always
else
    php -dxdebug.remote_enable=1 -dxdebug.remote_autostart=1 vendor/bin/phpunit --colors=always --filter=$1
fi

10.9.2 install

10.9.3 naming

  1. MethodNameStateUnderTestExpectedBehavior
    1. MethodName - method name that being tested
    2. StateUnderTest - input value
    3. ExpectedBehaviour - what methods returns for specified input
  2. Feature to be tested: Many suggests that it is better to simply write the feature to be tested because one is anyway using annotations to identify method as test methods. It is also recommended for the reason that it makes unit tests as alternate form of documentation and avoid code smells. Following is how tests in first example would read like if named using this technique:
    1. IsNotAnAdultIfAgeLessThan18
    2. FailToWithdrawMoneyIfAccountIsInvalid
    3. StudentIsNotAdmittedIfMandatoryFieldsAreMissing

10.9.4 Types of Test Doubles:

  1. Dummy

    Used only as a placeholder when an argument needs to be filled in.

  2. Stub

    Provides fake data to the System Under Test

  3. Spy

    Records information about how it is used, and can provide that information back to the test.

  4. Mock

    Defines an expectation on how it will be used, and with what parameters. Will cause a test to fail automatically if the expectation isn’t met.

  5. Fake

    An actual implementation of the contract, but is unsuitable for production.

10.10 Codeception

10.11 Mockery

Mockery mocks out only the method which we specifically told it to. This means that the original constructor of the class we are mocking will be called.

10.12 structure/organize tests

tests/ \ unit/

- module1
- module2
  • integration/
  • functional/

11 Tools

11.1 Frameworks

11.1.1 Symfony

  1. Serializer
  2. Form
  3. Problems

    After update to Symfony 4 - blank page - remove var/bootstrap.php.cache

  4. Links
  5. KernelBrowser

    $client->request('GET', 'api/clubs', [], [], [ 'HTTPX-Requested-With' => 'XMLHttpRequest', ]);

    $client->request('POST', 'foo', array(), array(), array( 'HTTPX-Requested-With' => 'XMLHttpRequest', 'CONTENTTYPE' => 'application/json', ), '{"param": "value"}');

  6. Request

    // $GET parameters $request->query->get('name');

    albo wszystko ->all() // $POST parameters $request->request->get('name');

  7. Config

11.1.2 CodeIgniter

11.1.5 Links

11.2 Code Analize

11.2.3 phploc

wget https://phar.phpunit.de/phploc.phar
chmod +x phploc.phar
sudo mv phploc.phar /usr/local/bin/phploc

11.2.5 phpinsights

11.2.7 Psalm

  • immutable

11.3 Composer

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php composer-setup.php –install-dir=/usr/bin –filename=composer composer global require [packagename]

11.3.1 when composer update ?

Projekt nie jest jeszcze na produkcji, ciągle w fazie development to można raz na jakiś czas odpalić composer update, czyli podnieść wszystkie paczki.

11.4 Git

  • git reset HEAD~1 - move back to recent commit

11.5 Twig

11.5.1 comma

{% for role in user.roles %} {{ role.name }} {% if not loop.last %},{% endif %} {% endfor %}

11.6 Linux

sudo lsof -i -P -n | grep LISTEN sudo lsof -i:22 ## see a specific port such as 22 ##

12 Notepad

  1. Accurate predictions are an oxymoron in the real world. You can't predict accurately for things that aren't certain, and in almost all cases, developers won't know the systems they are dealing with fully enough. Moreover, they don't know their own personal efficiency from day to day; it just can't be foreseen accurately.
  2. Rules are for the guidance of the wise and the obedience of fools.
  3. A good property of software is the ability to change
  4. Anyone can take a chance at improving code, but refactoring brings a discipline of safely making changes (with tests) and leveraging the knowledge accumulated by the software development community (through refactorings).
  5. After all, like beauty, complexity is in the eye of the beholder.
  6. Using new programming languages will bring you new insights and ideas to already known languages. You get a better understanding.
  7. It's not about clever, crAFTY, PREETY CODE. iT'S ABOUT FAST AND EFFECTIVE COMMUNICATION. It's about communication beetween people.
  8. Any time someone sees some code that isn't as clear as it should be, they should take the opportunity to fix it right there and then — or at least within a few minutes. This opportunistic refactoring is referred to by Uncle Bob as following the boy-scout rule — always leave the code behind in a better state than you found it.
  9. software bugs are domiated by state
  10. where software complexity comes from?
  11. HN is fast because it is feature-barren.
  12. The advantages of less lines of code are evident: a smaller program contains less bugs, is easier to reason about, and – because of its simplicity – is more robust.
  13. Extracting statistical information from hundreds of processes without adversely affecting their performance is not a simple task.
  14. Quality is many small things done right

13 PHP

13.1 language

13.1.1 primitive elements - types

low-level language elements

  1. Integer
  2. Float
  3. String
  4. Booleans
  5. Array
  6. Object
  7. Resource
  8. NULL

13.2 Data Structures

13.2.1 Array

  1. Avoid complex arrays
  2. PHP's arraymap including keys
  3. How does PHP 'foreach' actually work?
  4. Why you should use array functions instead of basic loops
  5. array is empty
    1. empty
      // Declare an array and initialize it 
      $non_empty_array = array('URL' => 'https://www.geeksforgeeks.org/'); 
                               
                               // Declare an empty array 
                               $empty_array = array(); 
                               
                               // Condition to check array is empty or not 
                               if(!empty($non_empty_array))echo "Given Array is not empty <br>"; 
        
                               if(empty($empty_array)) echo "Given Array is empty"; 
      
                               if($array) {
                                   echo 'siema';
                               }
      
    2. count

      // Declare an empty array $emptyarray = array();

      / Function to count array / element and use condition if(count($emptyarray) == 0) echo "Array is empty"; else echo "Array is non- empty";

    3. sizeof

      // Declare an empty array $emptyarray = array();

      / Use array index to check / array is empty or not if( sizeof($emptyarray) == 0 ) echo "Empty Array"; else echo "Non-Empty Array";

    4. if

      $playerList = array(); if (!$playerList) { echo "No players"; } else { echo "Explode stuff…"; }

    5. compare to empty array

      if ($variableToTest = array()) { echo 'this is explicitly an empty array!'; }

  6. PHP Sort Array By SubArray Value

    usort($array, function ($a, $b) { return $a['optionNumber'] <=> $b['optionNumber']; });

    arraymultisort(arraymap(function($element) { return $element['optionNumber']; }, $array), SORTASC, $array);

  7. if you are iterating an array to build another array from it, you should use map.

    Anti-pattern: const numbers = [1,2,3,4,5], doubled = [];

    numbers.forEach((n, i) => { doubled[i] = n * 2 }); Proper use case of map:

    const numbers = [1,2,3,4,5]; const doubled = numbers.map(n => n * 2);

    console.log(doubled);

  8. if you are trying to reduce the array to a value, for example, you want to sum an array of numbers, you should use the reduce method

    Anti-pattern:

    const numbers = [1,2,3,4,5]; const sum = 0; numbers.forEach(num > { sum + num }); Proper use of reduce:

    const numbers = [1,2,3,4,5]; const sum = numbers.reduce((total, n) => total + n, 0);

    console.log(sum);

13.3 Functions Core

13.3.1 SPL Library

Great job on the implementation!

For larger training jobs, wondering if it's worthwhile to investigate implementing SplFixedArray in to the class? While I'm not sure of the PHP7 impacts, for PHP < 7 this resulted in a memory reduction of 144 bytes per array element to 56 bytes per array element.

If you were working with 50M data points total, this would reduce the memory requirements from 7.2GB to 2.8GB.

13.3.2 As opposed with isset(), propertyexists() returns TRUE even if the property has the value NULL.

13.3.3 isset() vs arraykeyexist

In simple terms, isset() checks whether a variable exists or its been declared or not. This can be anything, an array, a particular key in an array or a variable. It also checks if a declared variable, array or array key has null value, if it does, isset() returns false, it returns true otherwise.

On the other hand, arraykeyexists() checks whether a particular key or index exists in an array. It does not evaluate the value of the key for any null values. It returns false if it does not find the key in the array and true otherwise.

from the PHP manual: isset() does not return TRUE for array keys that correspond to a NULL value, while arraykeyexists() does

13.3.4 foreach vs arraymap

https://stackoverflow.com/questions/18144782/performance-of-foreach-array-map-with-lambda-and-array-map-with-static-function https://www.reddit.com/r/PHP/comments/65ihba/re_array_map_vs_foreach/

<?php

// test a simple array_map in the real world.
function test_array_map($data){
    return array_map(function($row){
        return array(
            'productId' => $row['id'] + 1,
            'productName' => $row['name'],
            'desc' => $row['remark']
        );
    }, $data);
}

// Another with local variable $i
function test_array_map_use_local($data){
    $i = 0;
    return array_map(function($row) use ($i) {
        $i++;
        return array(
            'productId' => $row['id'] + $i,
            'productName' => $row['name'],
            'desc' => $row['remark']
        );
    }, $data);
}

// test a simple foreach in the real world
function test_foreach($data){
    $result = array();
    foreach ($data as $row) {
        $tmp = array();
        $tmp['productId'] = $row['id'] + 1;
        $tmp['productName'] = $row['name'];
        $tmp['desc'] = $row['remark'];
        $result[] = $tmp;
    }
    return $result;
}

// Another with local variable $i
function test_foreach_use_local($data){
    $result = array();
    $i = 0;
    foreach ($data as $row) {
        $i++;
        $tmp = array();
        $tmp['productId'] = $row['id'] + $i;
        $tmp['productName'] = $row['name'];
        $tmp['desc'] = $row['remark'];
        $result[] = $tmp;
    }
    return $result;
}

$data = array_fill(0, 10000, array(
    'id' => 1,
    'name' => 'test',
    'remark' => 'ok'
));

$tests = array(
    'array_map' => array(),
    'foreach' => array(),
    'array_map_use_local' => array(),
    'foreach_use_local' => array(),
);

for ($i = 0; $i < 100; $i++){
    foreach ($tests as $testName => &$records) {
        $start = microtime(true);
        call_user_func("test_$testName", $data);
        $delta = microtime(true) - $start;
        $records[] = $delta;
    }
}

// output result:
foreach ($tests as $name => &$records) {
    printf('%.4f : %s '.PHP_EOL, 
           array_sum($records) / count($records), $name);
}

https://3v4l.org/lon7l#output

13.3.5 create an array

range(1,10);

13.3.6 foreach

foreach (range(1, 100) as $i) 

13.3.7 array

  1. flatten
    public function flatten(array $array) {
        $return = array();
        array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
        return $return;
    }
    
  2. sort by value of a given key
    //ascending
    usort($inventory, function ($item1, $item2) {
        return $item1['price'] <=> $item2['price'];
    });
    
    //descending
    usort($inventory, function ($item1, $item2) {
        return $item2['price'] <=> $item1['price'];
    });
    
  3. arraymap including keys
    $states = array('az' => 'Arizona', 'al' => 'Alabama');
    
    array_map(function ($short, $long) {
        return array(
            'short' => $short,
            'long'  => $long
        );
    }, array_keys($states), $states);
    
    // produces:
    array(
        array('short' => 'az', 'long' => 'Arizona'), 
        array('short' => 'al', 'long' => 'Alabama')
    )
    
    

13.4 Quirks

13.4.2 Adding float numbers

var_dump(0.1 + 0.2 - 0.3);

13.5 Config

php -i | grep "Loaded Configuration File"

13.6 Problems

13.6.1 PHP Add comma to every item but last one

$comma_separated = implode(", ", $vars);

14 Links

14.2 Dave Thomas

  • suggesting that as developers we need to spend more time just practicing: writing throwaway code just to get the experience of writing it.
  • There are no right or wrong answers in these kata: the benefit comes from the process, not from the result.

14.3 Carola Lilienthal

14.6 legacy code rocks!

14.6.1 Rewriting Code with Sabrina Leandro

14.6.3 Code Review with Pranay Suresh

  • legacy code - code after merge, because it's hard to change
  • PR Requestes
    • a small as possible, as less files as posible
    • functional corectness
    • don't break anything
    • fits to codebase standards
  • errors - switch parameters, lose of precsion

14.6.4 Working Effectively with Legacy Code with Michael Feathers

  • conway law
  • refactor and scrach just to understand
  • removing edges from the code
  • be very liberial of what you accept and conservative of what you produce- John
  • inside junky - kind of like looking at lot of informations and start to understand how things tight together, and then get a flash inside

14.6.5 Top Five Best Practices for Legacy Code with Leon Miller-Out

  • the CEO of a web app development and maintenance firm Singlebrook,

14.7 The Clean Code Blog by Robert C. Martin (Uncle Bob)

14.7.1 Code Hoarders

It’s also easy to believe that acquiring new stuff is more important than organizing old stuff. After all, organizing old stuff does not add value. It’s acquiring new stuff that counts. So if there’s any spare time, or spare effort, or spare energy, it should be directed towards acquiring new stuff. Organizing the old stuff is a waste.

15 Topics

15.6 Nginx

server { listen 80 defaultserver; listen [::]:80 defaultserver;

root /var/www/html; index index.html;

servername culturevein.com;

location / { tryfiles $uri $uri/ /index.html; }

location api { tryfiles $uri $uri/ /index.php; }

location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgipass unix:/run/php/php7.4-fpm.sock; } }

15.7 Routing

from most specific at the top to less specific at the bottom

15.7.1 yml vs. annotations

It's always have been a war about this. But I would simply divide them in to two options. Using annotations is quickier and kind of easier to use but it's increase noise in the code. I think it's great for prototyping small application, when you absolutly sure that app would not grow. Annotations become a tottaly mess when you have big application, it's hard to manage all routing compare to central routing like yaml. So I would go with word prototyping. Doctrine it's kind the same. It's great for prototyping but when you application finally reach maximum of what can you squize from ORM, you would have to leave it to pure SQL.

15.7.3 How to Pass an Array as URL Parameter in PHP?

15.8 Security

15.8.1 Cross-Site Request Forgery CSRF

also known as XSRF, Sea Surf or Session Riding is an attack that forces an end user to execute unwanted actions on a web application in which they're currently autheniticated.

  1. GET

    GET http://bank.com/transer.do?to=Attacker&amount=100 HTTP/1.1 <a href="http://bank.com/transer.do?to=Attacker&amount=100"> View my picture! </a> <img src="http://bank.com/transer.do?to=Attacker&amount=100" witdth="0", height="0", border="0">

    Next, he can distribute the hyperlink via email to a large number of bank customers. Those who click on the link while logged into their bank account will unintentionally initiate the $100 transfer.

    Note that if the bank’s website is only using POST requests, it’s impossible to frame malicious requests using a <a> href tag. However, the attack could be delivered in a <form> tag with automatic execution of the embedded JavaScript. This is how such a form may look like:

  2. POST

    POST http://bank.com/transer.do HTTP/1.1

    <body onload="document.forms[0].submit()">
      <form action="http://netbank.com/transfer.do" method="POST">
        <input type="hidden" name="acct" value="Attacker"/>
        <input type="hidden" name="amount" value="$100"/>
        <input type="submit" value="View my pictures!"/>
      </form>
    </body>
    

15.8.2 Cross-Site Scripting (XSS)

XSS enables attackers to inject client-side scripts into web pages viewed by other users.

15.10 Grep Test

  • http://jamie-wong.com/2013/07/12/grep-test/ I’ll occasionally see code that attempts to use clever mechanisms to reduce code duplication or be terser by using metaprogramming or string concatenation or any number of other mechanisms to DRY up code.

15.11 Jokes

15.12 Metrics

15.12.1 Cyclomatic Complexity Number (CCN)

Counts the available decision paths in a source code to determine it's complexity. Each decision path starts with one of the conditional statements from the following list:

  • ?
  • &&
  • ||
  • or
  • and
  • xor
  • case
  • catch
  • elseif
  • for
  • foreach
  • if
  • while

    Cyclomatic Complexity Number is never less than 1, because there’s always at least one code path.

    • 1-4 has low complexity.
    • 5-7 is moderate and still easy to understand.
    • 6-10 has a high complexity.
    • 10+ is very complex and hard to understand.
final class CyclomaticComplexityNumber
{
    // Class Cyclomatic Complexity = 1
}

final class CyclomaticComplexityNumber
{

    public function one()
    {
        // Function Cyclomatic Complexity = 1
    }

    public function two()
    {
        // Function Cyclomatic Complexity = 1
    }

    // Class Cyclomatic Complexity = 1
}

final class CyclomaticComplexityNumber
{

    public function one()
    {
        if(true){

        }
        // Function Cyclomatic Complexity = 2
    }

    public function two()
    {
        // Function Cyclomatic Complexity = 1
    }

    // Class Cyclomatic Complexity = 1 + 1 = 2
}

final class CyclomaticComplexityNumber
{

    public function one()
    {
        if(true){

        }
        // Function Cyclomatic Complexity = 2
    }

    public function two()
    {
        if(true){

        }
        // Function Cyclomatic Complexity = 2
    }

    // Class Cyclomatic Complexity = 1 + 1 + 1 = 3
}

15.12.2 NPath Complexity

function foo($a, $b)
{
    if ($a > 10) {
        echo 1;
    } else {
        echo 2;
    }
    if ($a > $b) {
        echo 3;
    } else {
        echo 4;
    }
}

So here we have function with 4 possible outcomes, since we have 2 statements that have 2 possible outcomes each (2 * 2 = 4). That means that the functions Npath complexity is 4. If we would add another statement with 2 possible outcomes we would get a complexity of 8 since 2 * 2 * 2 = 8.

15.13 Performance

15.13.1 Apache Bench

sudo apt-get install apache2-utils

15.13.2 Baseline Performance

  1. Stock install (Amazon EC2 Large, Ubuntu, Apache, PHP, MySQL)
  2. Static index.html (Hello World!)
  3. Dynamic index.php (<?php echo 'Hello World!';)
  4. Database connect (PDO)
    $pdo = new PDO('mysql:host=host;dbname=dbname', 'user, 'pass');
       echo 'PDO Connect!';
    
  5. Database connect, query, and fetch (PDO)
  6. Table

    5 runs of 10 users for 60 sec, avg

      relative req/s
    html 1,25 2 726
    php 1 2 178
    pdo connect 0,83 1 818
    pdo connect, query, fetch 0,73 1 611

15.13.3 CRUD vs. BREAD

15.13.4 N+1 Problem

  1. Single-Query Solution

    select all results, including relationships in a single query

  2. Query-and-Stitch Solution

15.13.6 Benchmark

  1. Fastest way to insert new records where one doesn’t already exist

15.13.10 Tools

16 About

It's a simple site about refactoring in PHP. I'm some kind of inside junky. I like looking at lot of informations and start to understand how things are tight together. Love this pleasure rush moment of understanding. Then I like to make things simplier.

16.2 Support

You can support this site: send some BitCoins 1D8xeRkxssTTLESfGZtPVoqVJDq7MJSqNx , send/buy one of the books I would like to read or just say Hello!

Author: slk

Created: 2020-08-17 Mon 22:41

Validate