Wytyczne, których programista powinien przestrzegać na co dzień, są tak samo ważne jak w każdej dziedzinie. Stosowanie tych zasad może z początku wydawać się żmudne i czasochłonne, ale z czasem korzyści stają się widoczne. Skróty, które mogą oszczędzić czas, bywają też źródłem różnych problemów w późniejszych etapach projektu.
Doświadczenie pokazuje, że zaśmiecony kod powoduje problemy, gdy tylko zaczyna się go rozbudowywać. Właśnie dlatego Robert Martin (znany jako Uncle Bob) zebrał zestaw reguł pisania dobrego kodu, które pozwalają tworzyć proste, łatwe w modyfikacji oprogramowanie. Uzupełnieniem tego podejścia jest podstawowa zasada KISS, której autorem jest Kelly Johnson.
W skrócie: KISS („keep it simple, stupid”) oznacza wybór najprostszego projektu, który rozwiązuje problem. SOLID to zestaw pięciu zasad projektowania obiektowego: jedna odpowiedzialność (Single responsibility), otwarte-zamknięte (Open/closed), podstawienie Liskov (Liskov substitution), segregacja interfejsów (Interface segregation) i odwrócenie zależności (Dependency inversion). Razem utrzymują kod czytelny, łatwy do rozbudowy i testowania.
Czym jest KISS?
KISS to termin stworzony w latach 60. XX wieku, który miał odzwierciedlać podejście do tworzenia prostych, trwałych samolotów, które można łatwo naprawić w sytuacji awaryjnej. Pomysł został od tamtej pory przyjęty w wielu dziedzinach nauki i inżynierii.
KISS jest też używany przy rozwiązywaniu problemów programistycznych. W dosłownym tłumaczeniu oznacza „keep it simple, stupid” lub „keep it stupid simple”. Przyjmuje się jednak, że sformułowanie nie miało brzmieć negatywnie, lecz sugerować, że prosty projekt sprawia, że serwis i utrzymanie są dziecinnie łatwe.
Zastosowanie KISS w programowaniu można rozpatrywać w trzech aspektach:
- upraszczanie kodu dla bieżącego i przyszłego wspólnego rozwoju. Z mojej perspektywy to nic innego jak umiejętne stosowanie zasad SOLID
- pisanie tylko tyle kodu, ile potrzeba do przejścia testu jednostkowego, co wiąże się z TDD i pierwszą zasadą SOLID, czyli jedną odpowiedzialnością
- intuicyjne podejście do pisania oprogramowania, przystępne i łatwe do zrozumienia dla każdego
Samo KISS nie ustala sztywnych reguł implementacji kodu, podobnie jak większość zasad SOLID, które są ogólnymi wytycznymi tworzenia kodu zgodnego z SOLID.
Z czego składa się SOLID?
Pięć zasad SOLID zebrał i spopularyzował, jak już wspomniano, Robert Martin. Sam akronim pochodzi od Michaela Feathersa, a poszczególne zasady opierają się na wcześniejszych pracach, takich jak zasada otwarte-zamknięte Bertranda Meyera i zasada podstawienia Barbary Liskov.
- Single responsibility (jedna odpowiedzialność)
- Open / Closed (otwarte-zamknięte)
- Liskov substitution (podstawienie Liskov)
- Interface segregation (segregacja interfejsów)
- Dependency inversion (odwrócenie zależności)
| Zasada | W jednym zdaniu | Typowy sygnał naruszenia |
|---|---|---|
| Jedna odpowiedzialność | Klasa lub metoda ma jeden powód do zmiany | Klasa, która waliduje dane, zapisuje je i wysyła e-maile |
| Otwarte-zamknięte | Nowe zachowanie dodajesz przez rozszerzenie, a nie edycję przetestowanego kodu | Każdy nowy przypadek to kolejny if w istniejącej metodzie |
| Podstawienie Liskov | Klasa pochodna może zastąpić bazową bez psucia zachowania | Podklasa, która dla odziedziczonej metody zgłasza „nieobsługiwane” |
| Segregacja interfejsów | Wiele małych interfejsów dla klientów jest lepsze niż jeden duży | Klasy zmuszone do implementacji metod, których nie używają |
| Odwrócenie zależności | Zależ od abstrakcji, a nie od konkretnych implementacji | Klasy, które same tworzą swoje zależności przez new |
Jedna odpowiedzialność mówi sama za siebie. Każda klasa lub metoda powinna odpowiadać za jedną, osobną funkcjonalność. Przykład złamania tej zasady widać w poniższym kodzie:

W powyższym przykładzie zasada jest łamana, bo klasa Person „przekracza swoje kompetencje”. Jej jedyną odpowiedzialnością powinno być reprezentowanie obiektu osoby i jej właściwości, takich jak: imię, wiek, adres (najlepiej też jako osobny obiekt).
Zdecydowanie nie powinna walidować adresu e-mail, kodu pocztowego ani dodawać produktu do koszyka.
Poprawienie powyższych błędów i dostosowanie kodu do zasady jednej odpowiedzialności wygląda następująco:

Stosowanie zasady KISS jest ściśle związane z podejściem TDD. Aby test jednostkowy był poprawny, powinna mu odpowiadać jedna, pojedyncza odpowiedzialność.
Otwarte-zamknięte, czyli otwarte na rozszerzenia, zamknięte na modyfikacje. Zgodnie z tą zasadą klasa lub metoda powinna być napisana tak, aby nowe zachowanie dodawać przez rozszerzanie, bez zmiany kodu, który już działa i jest przetestowany.
Co to oznacza w praktyce: przykłady
Zacznijmy od złamanej zasady poniżej:

Dlaczego powyższy kod łamie zasadę otwarte-zamknięte? Bo dodanie kodu do obliczania pola, np. trójkąta, wymagałoby bezpośredniej modyfikacji metody area z klasy Calculator.
Jak więc poprawnie zaimplementować obliczanie pola figury? Przykład poniżej:

Jak widać, aby dodać figurę z możliwością obliczania jej pola, wystarczy utworzyć kolejną klasę dziedziczącą po klasie Shape i zdefiniować w niej metodę obliczania pola.
Te dwie pierwsze zasady łatwo zastosować w każdej funkcjonalności, nawet małej. Stosując je, możemy pisać kod, który będzie czytelny i zrozumiały dla innych programistów oraz łatwy do rozbudowy.
Na tym etapie zastosowaliśmy dwie pierwsze zasady SOLID: jedną odpowiedzialność i otwarte-zamknięte.
Kolejne trzy zasady stosuje się w bardziej złożonych rozwiązaniach, czyli w rozbudowanej logice.
Trzecia zasada to podstawienie Liskov, która mówi, że obiekty klasy pochodnej muszą dać się używać wszędzie tam, gdzie oczekiwana jest klasa bazowa lub interfejs, bez psucia zachowania programu. Innymi słowy, interfejs, klasa abstrakcyjna i wszystkie metody klasy pochodnej muszą pozostać zgodne.
Co to oznacza w praktyce? Podobnie jak przy poprzednich zasadach pokażemy to na dwóch przykładach: błędnym i poprawnym.
Zwykle najpierw pokazuję wariant niepoprawny:

Na pierwszy rzut oka wszystko jest w porządku: jest klasa Animal reprezentująca zwierzę oraz dziedziczące po niej Dog i Fish. Gdzie więc problem? W metodzie wymuszonej przez interfejs pies biega i ma to sens, ale nikt nigdy nie słyszał o biegającej rybie.
Zasada ta jest więc bardziej odniesieniem do czystej logiki. Kolejny przykład pokazuje jej poprawne zastosowanie. Implementuje logikę narzędzia najważniejszego dla programisty: ekspresu do kawy:

Kawa zawsze jest parzona w ekspresie, niezależnie od jego typu.
Kolejna zasada to segregacja interfejsów.
Bardzo dobrym jej opisem jest zdanie: „wiele interfejsów dla konkretnych klientów jest lepsze niż jeden interfejs ogólnego przeznaczenia”.
W praktyce oznacza to, że tworzone interfejsy powinny być dedykowane tylko jednej funkcjonalności.
Przykład złamania tej zasady wygląda następująco:

W powyższym przykładzie zaimplementowano logikę drukowania różnych raportów. Utworzono interfejs z dwiema deklarowanymi metodami: do drukowania PDF i arkuszy Excel. Do wyników szkolnego egzaminu arkusz Excel nie jest jednak potrzebny.
W tym przypadku ta metoda jest zbędna, ale skoro wymusza ją interfejs, musi zostać zaimplementowana. Zgodnie z zasadą segregacji interfejsów lepszym rozwiązaniem jest zadeklarowanie kilku wyspecjalizowanych interfejsów.
Aby rozwiązać problem, możemy utworzyć dwa osobne interfejsy: PrintablePdfInterface i PrintableExcelInterface.
Ostatnia zasada SOLID to odwrócenie zależności. Mówi, że moduły wysokiego poziomu nie powinny zależeć od modułów niskiego poziomu, a oba powinny zależeć od abstrakcji, a nie od konkretnych typów. Brzmi to skomplikowanie, ale to prosty sposób deklarowania funkcjonalności tak, aby działała z dowolną implementacją interfejsu. Dzięki temu kod łatwiej testować i zmieniać.
Poniższe przykłady dobrze to ilustrują. Złamanie zasady:

Zastosowanie zasady:

Powyższe zasady należy traktować jako zestaw narzędzi do pisania dobrego, solidnego kodu. Nie trzeba jednak stosować wszystkich elementów w każdym projekcie. Staraliśmy się zawrzeć dobre praktyki programowania.
Programiści powinni dostosować to narzędzie do indywidualnych potrzeb aplikacji. Intuicyjnie w małym projekcie ostatnich trzech zasad możemy nie potrzebować w formalny sposób, choć podstawienie Liskov dotyczy każdego użycia dziedziczenia, ale dwóch pierwszych zdecydowanie warto się trzymać, nawet przy budowie mniejszych funkcjonalności.
Z własnego doświadczenia wiem, że kod pisany od początku zgodnie z dobrymi praktykami znacznie łatwiej się rozwija.
Jak SOLID i KISS stosują się do rozwoju WordPressa i WooCommerce?
Te same idee działają w kodzie WordPressa. Akcje i filtry pozwalają rozszerzać zachowanie bez edycji rdzenia WordPressa ani plików wtyczki, co jest zasadą otwarte-zamknięte w praktyce, a motywy potomne działają według tej samej logiki. Utrzymywanie każdej klasy wtyczki skupionej na jednym zadaniu i zależność od interfejsów zamiast klas konkretnych ułatwia testowanie własnego kodu i przekazanie go innemu zespołowi. Przykłady znajdziesz w artykułach jak stworzyć własny motyw WordPress oraz czym są endpointy WooCommerce.
Odwrotny wzorzec widzimy w sklepach, które zmieniły właściciela: zaśmiecony kod, którego nikt nie śmie ruszyć. Audyt techniczny pokazuje, jak głęboki jest problem, a projekt ratunkowy stabilizuje kod przed jakąkolwiek przebudową. Przy nowych pracach zobacz nasze wdrożenia WordPress i sklepy WooCommerce.
Najważniejsze wnioski
- Zachowaj prostotę: wybieraj najprostszy projekt, który rozwiązuje problem (KISS)
- Daj każdej klasie lub metodzie jedną odpowiedzialność
- Rozszerzaj zachowanie przez dodawanie kodu, a nie zmianę przetestowanego kodu
- Dopilnuj, by klasy pochodne mogły zastąpić klasy bazowe bez niespodzianek
- Preferuj małe, wyspecjalizowane interfejsy i zależ od abstrakcji
Najczęstsze pytania o SOLID i KISS
Co oznacza skrót SOLID?
SOLID oznacza: Single responsibility (jedna odpowiedzialność), Open/closed (otwarte-zamknięte), Liskov substitution (podstawienie Liskov), Interface segregation (segregacja interfejsów) i Dependency inversion (odwrócenie zależności). To pięć zasad projektowania obiektowego, które ułatwiają czytanie, rozszerzanie i testowanie kodu.
Co oznacza KISS w programowaniu?
KISS oznacza „keep it simple, stupid”. Zachęca do wyboru najprostszego projektu, który rozwiązuje problem, aby kod był łatwiejszy do zrozumienia, utrzymania i naprawy.
Czym różni się KISS od SOLID?
KISS to ogólna zasada unikania zbędnej złożoności. SOLID to konkretny zestaw pięciu zasad projektowania kodu obiektowego. Dobre stosowanie SOLID zwykle wspiera KISS, bo utrzymuje klasy małe i wyspecjalizowane.
Kto stworzył zasady SOLID?
Robert C. Martin (Uncle Bob) zebrał i spopularyzował zasady na początku lat 2000. Akronim stworzył Michael Feathers, a poszczególne zasady wywodzą się z wcześniejszych prac, takich jak zasada otwarte-zamknięte Bertranda Meyera i zasada podstawienia Barbary Liskov.
Czy w małym projekcie potrzebuję wszystkich pięciu zasad SOLID?
Niekoniecznie w formalny sposób. Jedna odpowiedzialność i otwarte-zamknięte popłacają nawet w małych funkcjach. Podstawienie Liskov ma znaczenie zawsze, gdy używasz dziedziczenia, a segregacja interfejsów i odwrócenie zależności zyskują na znaczeniu wraz z rozwojem kodu.
Jak zasady SOLID stosują się do rozwoju WordPressa i WooCommerce?
Haki WordPressa pozwalają rozszerzać zachowanie bez edycji plików rdzenia lub wtyczek, co jest zasadą otwarte-zamknięte w praktyce. Utrzymywanie wyspecjalizowanych klas wtyczki i zależność od interfejsów zamiast klas konkretnych ułatwia testowanie i utrzymanie własnego kodu.



