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