Composition over inheritance - zasady
1. W zdecydowanej większości przypadków composition over inheritance
Wspólny kod ma należeć do wydzielonej funkcjonalności (concern), a nie do wydzielonego rodzica; obiekt jest kompozycją doczepianych zachowań.
2. Test pytaniem
Dziedziczenie twardo odpowiada na "czym jesteś" i celowo narzuca ograniczenia (nie ma ssaka bez produkcji mleka); concern odpowiada na "co robisz / jak działasz" i podłącza się bez pełnego commitmentu w resztę pakietu.
3. Dziedziczenie wymusza branie całego pakietu naraz
Gdy dziedzic zaczyna skipować i nadpisywać, to hack psujący samą ideę, że ten kod jest reusable. Dziedziczenie ogranicza też architekturę i nazewnictwo.
4. Nawet gdy tożsamość ma być wymuszona, parent powinien być klasą includującą concerny
Rodzic includuje wspólne wymuszone zachowania, a dzieci dokładają te, które nie wynikają z dziedziczenia.
5. Nazwa concernu musi się sama tłumaczyć
Biznesowość polega na tym, że czytając nazwę wiesz, co to robi - stąd formy typu ProtectedByPin, SetsLocales, SetsTimezone, DisablesBrowserCaching.
6. Nazwa kaskaduje do implementacji
Implementacja musi się zgadzać z nazwą; jeśli wycieka poza nią albo ma niespodziewane side effecty - zła nazwa albo powinny być dwa osobne concerny.
7. Więcej mniejszych, single responsibility, zamiast jednego zbiorczego ("concern-klasy")
Wtedy tam, gdzie potrzeba tylko jednego zachowania, includujesz tylko ten concern, który cię obchodzi.
8. Concern nie musi być reusable "from the get go"
Może służyć do porządkowania jednej klasy - reusable w sensie "da się dorzucić", nie "użyty w wielu miejscach". Jeśli ładnie spina funkcjonalność i dobrze czyta się na górze klasy, jest wartość; jeśli za mały - może nie być sensu.