The MVB update 2

This blog has become yet-another-not-updated blog lately, so I thought I’ll bring you up to speed.

There are a great many things I was participating in lately and this had successfully foiled my plans for producing quality content here. Between the last entry and now I did:
Help organise 4 coding dojos
Worked on several projects
Delivered 7 talks
Finished a 10K run \o/
Started doing classes for children again
Worked on 2 workshops
And 1 festival
And 1 article
I can probably come up with much now excuses.

That was a pretty busy six months, but I plan to change around some things, so you can expect more content in December 馃檪

I would like this blog to be a go to source for best practices, explained as best as possible, since I do this a lot during my talks as well. This is because I believe that we can do better with teaching people the clean code principles and design patterns to say the least.

This is a crucial part of software engineering, which makes a big difference. Also that knowledge remains basically unchanged over the years, which cannot be said about the tools we are using, once learned, it will stay with you for a long time.

See you this December, when I’ll post an guide to a decorator pattern 馃槈

MVB update + small rebranding~!

Hello there~!
(Hello PHPers ;))

Just a friendly reminder that this is an MVB (Minimal Viable Blog) and will be expanded soon. In a few days, I will translate the rest of the site and it will be English-only (or with some Polish translations, haven’t decided yet).

Also, I’ve given this blog a name! Just my name is not the best brand, so I’ve decided on naming the blog Pattern Fever, which seems appropriate 馃槈

Wzorce projektowe #1: Value Object

Za艂o偶eniem tego bloga jest pisanie g艂贸wnie o dobrych praktykach. Pisz膮c o nich nie spos贸b jest nie wspomnie膰 o wzorcach projektowych. W kolejnych postach b臋d臋 stara艂 si臋 opowiada膰 o r贸偶nych wzorcach w jak najprzyst臋pniejszy spos贸b.

Pierwszy wzorzec, o kt贸rym opowiem jest do艣膰 prosty, ale bardzo wa偶ny. Ka偶dy wzorzec projektowy ma za zadanie rozwi膮za膰 jaki艣 powszechny programistyczny problem (je艣li odpowiednio go zastosujemy). Zaczn臋 wi臋c od sformu艂owania pewnego przyk艂adowego problemu.

Opis problemu

Poni偶ej napisa艂em przyk艂adowy kod raportu, w kt贸rym spisywane s膮 wszystkie wp艂ywy danego dnia. Raport bierze kwoty netto, dodaje do nich VAT i tworzy list臋 wszystkich wp艂yw贸w.

final class DailySalesReport {
  (...)

  public function formatInvoicePriceGross(
    float $netPrice
  ) : string {
    $netPrice = $netPrice * 1.23;
    return number_format(
      $netPrice, 2, ',', ' '
    ) . ' PLN';
  }
}

Funkcja jest do艣膰 prosta. Najpierw dodaje do podanej kwoty 23% podatku VAT, po czym drukuje j膮 w odpowiednim formacie z walut膮 na ko艅cu. Problem pojawia si臋 w momencie kiedy firma zaczyna przyjmowa膰 p艂atno艣ci w r贸偶nych walutach. Rozwi膮zanie tego problemu jest jednak do艣膰 proste.

Rozwi膮zanie proste

final class DailySalesReport {
  (...)

  public function formatInvoicePriceGross(
    float $netPrice, 
    string $currency
  ) : string {
    $netPrice = $netPrice * 1.23;
    return number_format(
      $netPrice, 2, ',', ' '
    ) . ' ' . $currency;
  }
}

Problem rozwi膮zany, ale czy na pewno? Nale偶y si臋 jeszcze upewni膰, 偶e format waluty jest poprawny.

final class DailySalesReport {
  (...)

  public function formatInvoicePriceGross(
    float $netPrice, 
    string $currency
  ) : string {
    if (!$currencyValidator->isValid($currency)) {
      throw new InvalidCurrencyException($currency);
    }

    $netPrice = $netPrice * 1.23;
    return number_format(
      $netPrice, 2, ',', ' '
    ) . ' ' . $currency;
  }
}

Jak widzimy ca艂o艣膰 zaczyna si臋 do艣膰 mocno komplikowa膰. Nie do艣膰, 偶e wsz臋dzie musimy przekazywa膰 conajmniej jeden dodatkowy parametr, to jeszcze jeste艣my zmuszeni w ka偶dym miejscu upewnia膰 si臋, czy warto艣ci s膮 poprawne. Co艣 takiego nie mie艣ci si臋 w zakresie odpowiedzialno艣ci tego prostego raportu, a ca艂o艣膰 systemu si臋 nam niepotrzebnie komplikuje. Co zatem mo偶emy zrobi膰?

Value Object

Wzorzec Value Object s艂u偶y nam do przechowania jakiej艣 warto艣ci, kt贸r膮 ci臋偶ko b臋dzie nam przedstawi膰 za pomoc膮 zwyk艂ego skalara. W tym przypadku chcemy przedstawi膰 pieni膮dze, ale wraz z walut膮 potrzebujemy conajmniej dw贸ch typ贸w prostych. Zdefiniujmy wi臋c klas臋, kt贸ra pos艂u偶y nam do przechowywania warto艣ci pieni臋偶nej.

final class Money {
  /** @type float */
  private $value;

  /** @type string */
  private $currency;

  public function __construct(
    float $value, 
    string $currency
  ) {
    if (!$this->isCurrencyValid($currency)) {
      throw new InvalidCurrencyException($currency);
    }

    $this->value = $value;
    $this->currency = $currency;
  }

  public function getFormattedValue() {
    return number_format(
      $this->value, 2, ',', ' '
    ) + ' ' + $this->currency;
  }

  public function multiply(float $multiplier) : void {
    $this->value = $this->value * $multiplier;
  }
}

Nasz obiekt enkapsuluje nasze dwa typy proste, oba przekazywane s膮 przez konstruktor. To bardzo wa偶ne! Przez konstruktor zawsze przekazujemy wszystkie sk艂adniki, kt贸r膮 s膮 nam potrzebne do utworzenia poprawnego obiektu. Dzi臋ki temu chronimy si臋 przed powstawaniem wadliwych obiekt贸w klasy Money, np. nie posiadaj膮cych ustawionej waluty. W konstruktorze te偶 upewniamy si臋 czy waluta jest poprawna, eliminuj膮c konieczno艣膰 sprawdzania tego w innych miejscach w kodzie.

Posiadaj膮c tak膮 klas臋 mo偶emy w niej umie艣ci膰 wszystkie funkcje zwi膮zane z warto艣ci膮 pieni臋偶n膮. To znacznie uporz膮dkuje nasz kod. Po zastosowaniu wzorca kod funkcji b臋dzie prezentowa艂 si臋 nast臋puj膮co:

final class DailySalesReport {
  (...)

  public function formatInvoicePriceGross(
    Money $netPrice
  ) : string {
    $netPrice->multiply(1.23);
    return $netPrice->getFormattedValue();
  }
}

Jest jednak jeden powa偶ny problem. Zaimplementowali艣my ten wzorzec w spos贸b nie w艂a艣ciwy. Musimy zadba膰 o jeszcze jedn膮 rzecz.

Niezmienno艣膰 / Immutability

Nale偶y zauwa偶y膰, 偶e kiedy u偶ywamy metody multiply, to zmieniamy warto艣膰 obiektu. Obiekt ten do funkcji trafi艂 najprawdopodobniej przez referencj臋, prowadz膮c膮 prosto do np. faktury. Zmieniaj膮c ten obiekt mo偶emy przypadkowo zmieni膰 kwot臋 ca艂ej faktury! Przyj臋t膮 zasad膮 jest, 偶e ka偶dy Value Object powinien by膰 niezmienny (immutable). Oznacza to, 偶e raz ustawionej warto艣ci nigdy nie zmieniamy w danej instancji obiektu, a w razie potrzeby zmiany tworzymy po prostu now膮 instancj臋. Jak to wp艂ynie na nasz kod?

final class Money {
  (...)

  public function multiply(float $multiplier) : Money {
    $newValue = $this->value * $multiplier;
    return new Money($newValue, $this->currency);
  }
}

Nale偶y te偶 wprowadzi膰 kilka zmian do naszej funkcji:

final class DailySalesReport {
  (...)

  public function formatInvoicePriceGross(
    Money $netPrice
  ) : string {
    $grossPrice = $netPrice->multiply(1.23);
    return $grossPrice->getFormattedValue();
  }
}

Value Object w PHP

Przy okazji warto wspomnie膰 o tym, 偶e bardzo popularny w PHP obiekt DateTime r贸wnie偶 ma sw贸j niezmienny odpowiednik DateTimeImmutable. Warto rozwa偶y膰 jego wykorzystanie podczas pisania kolejnych operacji na datach. Pozwala to unikn膮膰 wielu wyrwanych w艂os贸w z g艂owy 馃槈

Je艣li podoba艂 Ci si臋 ten wpis, daj mi o tym zna膰 i obserwuj tego bloga. B臋d臋 jeszcze duuu偶o pisa艂 o r贸偶nych wzorcach projektowych. Je艣li co艣 z tego co napisa艂em jest niejasne, albo co gorsza b艂臋dne, daj mi prosz臋 zna膰, s艂u偶臋 pomoc膮.

DRY mo偶e powa偶nie Ci zaszkodzi膰

Jedn膮 z pierwszych zasad jakie pozna艂em kiedy uczy艂em si臋 podstaw programowania obiektowego by艂a regu艂a DRY – Don’t Repeat Yourself. Polega ona na tym, 偶e powinni艣my unika膰 powtarzaj膮cego si臋 kodu i wyci膮ga膰 ten sam kod do osobnych modu艂贸w (klas, funkcji), aby by艂 w jednym miejscu.

Dobre strony

Regu艂臋 t膮 mo偶na zrozumie膰 dwojako. W艂a艣ciwa interpretacja b臋dzie dotyczy艂a unikania powt贸rzenia tej samej logiki. Przyk艂adowo – kiedy w kodzie u偶ywamy jakiego艣 algorytmu szyfrowania i solenia hase艂, zwykle chcemy aby wsz臋dzie ten algorytm by艂 ten sam. Co wi臋cej, chcemy unikn膮膰 sytuacji, kiedy zmieniamy ten algorytm w jakim艣 miejscu, a zapomnimy w innym, poniewa偶 mo偶emy wprowadzi膰 b艂edy regresji w naszym kodzie. W tym kontek艣cie skorzystanie z regu艂y DRY sprowadzi si臋 do napisania jednego modu艂u, kt贸rym jest algorytm szyfruj膮cy. Zastosujemy go zamiast powtarzania tego samego kodu. Rozs膮dnym rozwi膮zaniem b臋dzie u偶ycie wzorca strategii.

final class BcryptPasswordEncryptingStrategy 
implements PasswordEncryptingStrategy {
    public function encryptPassword(string $password)
     : string {
        // kod
    }
}

Problemy

DRY cz臋sto jest te偶 interpretowane jako regu艂a, kt贸ra m贸wi o unikaniu powtarzania si臋 podobnego kodu. Kod ten strukturalnie jest bardzo podobny i na jakim艣 poziomie abstrakcji robi to samo, ale jednak nie jest cz臋艣ci膮 tej samej logiki. W jednym z projekt贸w, przy kt贸rych pracowa艂em, do dos艂ownie kilku tabel powsta艂a skomplikowana og贸lna funkcja sortowania, filtrowania i paginacji. Kod ten by艂 ca艂y czas rozszerzany i poprawiany. W efekcie doprowadzi艂o do powstania strzasznie skomplikowanej pl膮taniny warunk贸w i operacji na ci膮gach znak贸w. Mimo, 偶e stworzony zosta艂 pozornie uniwersalny modu艂, to co chwile wymaga艂 on poprawek i rozszerze艅 oraz by艂 praktycznie niemo偶liwy do przetestowania. Ostatecznie stracili艣my pewnie wi臋cej czasu ni偶 zaoszcz臋dzili艣my.

Innym cz臋stym powodem stosowania tej zasady jest ch臋膰 stworzenia kodu reu偶ywalnego. Podczas nauki programowania cz臋sto m贸wi si臋 o tworzeniu kodu w taki spos贸b, aby mo偶na by艂o go u偶y膰 potem w innych projektach. Niestety jest to cz臋sto podej艣cie szkodliwe, poniewa偶 abstrakcje naprawde ci臋偶ko si臋 testuje i bardzo 艂atwo co艣 przeoczy膰. Poza tym w praktyce wychodzi, 偶e i tak kod rzadko si臋 po prostu reu偶ywa. Warto wi臋c zapami臋ta膰 inny ciekawy skr贸t: YAGNI. You ain’t gonna need it! Piszmy tylko kod, kt贸ry jest nam rzeczywi艣cie potrzebny i ani linijki wi臋cej, z ten spos贸b oszcz臋dzamy sobie i kodzenia i p贸藕niejszego debugowania.

Code for your use case, not for your re-use case
–Marco Pivetta @Ocramius

Minimal Viable Blog

Hi there!
After many years of thinking to myself that I should start writing a blog, I’ve decided to go full #yolo and just start writing and see what happens.

My name is Dawid Mazur. I am a software developer since 2012 (professionally), also I have some experience as a team leader and a project manager. I’m also a part of an amazing IT community, organizing events, doing talks and workshops. I work mainly in PHP and JavaScript, so you can expect the examples to be in that languages, the content on this blog should be pretty language-agnostic though.

And what will that content be? Many of my talks focus on best practices, so I’ll most likely write o lot about them. We’ll see what happens then. If you want to know more about clean code, design patterns, SOLID, Scrum and this kind of jazz. Drop by from time to time, I’ll do my best to deliver 馃檪