Brownfield                  Greenfield

Legacy Code...

Where does it comes from?

I am Engineer!

My god... It's full of bugs!

SOLID

Open/Close Principle

Or "Protected Variations"

Or "Information Hiding"

Modules should be open for extension but closed to modification

Open/Close Principle

Why should we change any code?

New Feature?

Because of this guys...

  • if/else
  • switch
  • new
  • 3.14
  • Assumptions...
switch ($role) {
    case Role::CUSTOMER:
        return $this->customerBalance($user);
    case Role::MERCHANT:
        return $this->merchantBalance($user);
    case Role::SUPERVISER:
        return $this->userBalance($user);
    default:
        throw new UnknownRoleException($role);
}
foreach ($balanceProviders as $balanceProvider) {
    if ($balanceProvider->supports($role)) {
         return $balanceProvider->process($user);
    }
}

throw new UnknownRoleException($role);

Removing if/else

$notifier->sendWelcomeNotification($user);
$notifier->sendActivationEmail($user, $activationHash);

$users->findPremiumUsers($paging);
$users->findReferralUsers($introducer, $paging);
$notifier->send(new WelcomeNotification($user));
$notifier->send(new ActivationEmail($user, $activationHash));

$users->find(new PremiumUsers($paging));
$users->find(new ReferralUsers($introducer, $paging));

Delegation

Composition

$prices = [];
foreach ($this->orderLines as $orderLine) {
    $price = $orderLine->totalPrice();
    if ($orderLine->quantity() < 5) {
        $price = $price->multiply(0.7);
    }

    $prices[] = $price;
}
$applyDiscount = function ($next, $orderLine) {
    if ($orderLine->quantity() < 5) {
        return $next($orderLine);
    }
    return $next($orderLine)->multiply(0.7);
}

$price = function ($orderLine) {
    return $orderLine->totalPrice();
}

$prices = array_map(curry($applyDiscount)($price), $this->orderlines);
class Bar extends Foo
{
    public function __construct(Baz $baz)
    {
        parent::__construct($baz);
    }
}


class Bar implements FooInterface
{
    private $foo;
    public function __construct(Baz $baz) 
    {
        $this->foo = new Foo($baz);
    }
}

Composition over Inheritance

Inversion of Control

Don't call us, we call you

Inversion of Control

Inversion of Control

class Bar implements FooInterface
{
    private $foo;
    public function __construct(FooInterface $foo) 
    {
        $this->foo = $foo;
    }
}

Inversion of Control

Dependency Inversion

Dependency Inversion

Liskov Substitution Principle

If for each object O1 of type S there is an object O2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when O1 is substituted for O2 then S is a subtype of T. 

Liskov Substitution Principle

Objects of the derived class must behave in a manner consistent with the promises made in the base class' contract.

interface Stream
{
    public function write(string $data): void;
    public function seek(int $pos): void;
    public function read(int $length): string;
}

class InMemoryStream implements Stream
{
    public function seek(int $offset): void
    {
        throw new NotImplemented(
            "In memory stream doesn't support seek operation"
        );
    }

    // ...
}

Interface Segregation

interface ReadableStream
{
    public function read(int $length): void;
}

interface WritableStream
{
    public function write(string $data): void;
}

interface SeekableStream
{
    public function seek(int $pos): void;
}

Small Reusable Objects

Hail DRY!

Single Responsibility

SOLID is not the goal...

LSP

SOLID

GRASP

OCP

1970

2000

1990

1980

Information
Hiding

LoD

Coupling
Cohesion

As a User

deck

By Sergey Protko

deck

  • 102