Bezdyskusyjnie każdy szanujący się programista powinien posiadać wiedzę na temat wzorców projektowych - jest to podstawa aby dobrze projektować aplikacje - jeżeli do dziś nie zaznajomiłeś się z wzorcami, ale popularne frameworki frontendowe lub backendowe nie są Ci obce to prawdopodobnie wykorzystywałeś je w swoich projektach nieświadomie.

Ten wpis jest dopiero początkiem, z biegiem czasu mam w planach omówienie najpopularniejszych wzorców projektowych i zaprezentować ich zastosowanie w praktyce, dlatego na bieżąco będę aktualizował ten wpis i uaktualniał odnośniki żeby finalnie stworzyć przejrzystą serię artykułów z serii wzorców programowania.

Z racji tego, że bardzo dobrze się czuję pisząc w PHP - ten właśnie język wykorzystam do przedstawienia swoich implementacji

Trochę teorii na początek

Wzorce projektowe to schematy, które powstały w celu rozwiązania dobrze znanego problemu. Jesteś osobą która trafiła na blog, który poświęcony jest programowaniu, dlatego wzorce w tym przypadku będą dotyczyły problemów projektowych w środowisku IT. Środowisko programistów to nie jedyna grupa ludzi wykorzystujących wzorce architektoniczne, konstruktorzy maszyn, elektronicy, budowlańcy czy drogowcy również je stosują żeby uniknąć komplikacji. Wzorce w IT są abstrakcjami, nie definiują one konkretnego rozwiązania, dlatego każda implementacja wzorca może wyglądać inaczej, elementy mogą mieć inną nazwę niż w opisie poszczególnego wzorca.

Każdy zdefiniowany wzorzec posiada:

  • Nazwę (czasami kilka nazw)
  • Przeznaczenie (realizuje jeden lub wiele problemów)
  • Strukturę (składającą się z elementów charakterystycznych)

Podział wzorców

Wzorce projektowe dzielimy według trzech głównych kategorii: konstrukcyjne, strukturalne i operacyjne. Rodzina wzorca wynika z jego charakterystyki. Kiedy wzorzec opisuje sposób łączenia klas lub obiektów wpisujemy go do wzorców strukturalnych, kiedy wzorzec opisuje proces tworzenia obiektów ląduje w grupie wzorców konstrukcyjnych natomiast wzorce operacyjne to takie, które w jednoznaczny sposób opisują komunikację(współpracę) pomiędzy obiektami.

  • Wzorce konstrukcyjne(kreacyjne)
    • Metoda wytwórcza
    • Fabryka abstrakcyjna
    • Metoda wytwórcza
    • Prototyp
    • Singleton
    • Budowniczy
  • Wzorce strukturalne
    • Adapter
    • Most
    • Kompozyt
    • Dekorator
    • Fasada
    • Pyłek
    • Pełnomocnik
  • Operacyjne
    • Interpreter
    • Metoda szablonowa
    • Łańcuch zobowiazań
    • Polecenie
    • Iterator
    • Mediator
    • Pamiątka
    • Obserwator
    • Stan
    • Strategia
    • Odwiedzający

Niektóre wzorce często stosuje się razem, główne dlatego że doskonale się uzupełniają.

Jak wzorce programowania mogą nam pomóc?

Żeby lepiej zobrazować jak ważne jest stosowanie wzorców wymyśliłem dwie historyjki, pierwsza przedstawia nieudolnego początkującego programistę bez wiedzy na temat wzorców projektowych, druga PHP-owego geeka który pracuje w zawodzie wiele lat i wie co to są wzorce projektowe.

Wyobraź sobie sytuację w której klient zlecił stworzenie aplikacji webowej ułatwiającej organizację w swojej firmie. System posiada moduł kalendarza, moduł powiadomień o spotkaniach, system notatek, dashboard użytkownika i kilka innych funkcjonalności.

  1. Początkujący programista PHP - bez większych umiejętności:
    Wszystkie dane zapisuje w relacyjnej bazie MySQL, bo sam tak zdecydował(typowa sytuacja w której brak konkretnych ustaleń z klientem). Nie wie co to są wzorce, jak się je stosuje, pracował nad projektem kilka miesięcy. Na koniec testuje wszystkie funkcjonalności. W dzień wdrożenia systemu u klienta dowiaduje się, że jedyne bazy które klient posiada to bazy Oracle, w szybki sposób musi zareagować i dostosować system do infrastruktury zleceniodawcy(nie ma innego wyjścia, klient nie chce nic dodatkowego instalować). Masa kodu i wykorzystany mysqli do połączenia z bazą. W wielu miejscach użył składni MySQL Improved Extension musi teraz poświęcić sporo czasu, żeby przepisać wszystko tak, żeby wykorzystać OCI8 lub PDO_OCI. Projekt z szybkiego zarobku stał się nieopłacalną kulą u nogi z tragicznym kodem do którego już mu się nie chce wracać, ale trzeba bo po przejściu na inny driver wiele modułów przestało prawidłowo działać(oczywiście nie pisał również testów :)), czasu na refaktoryzację brak a wszystko odwleka się w czasie, programista musi pracować na lokalnej instancji Oracle DB(nie będzie już powrotu do MySQL dopóki nie dowie się co to jest Adapter). Klient jest niezadowolony, długo czeka na produkt a w ostateczności otrzymuje dziurawy system na skutek czego zrywa współpracę z początkującym freelancerem (╯°□°)╯︵ ┻━┻
  2. Zaawansowany programista - programistyczny geek PHP:       Wszystkie dane zapisuje w relacyjnej bazie MySQL, ale liczy się z tym że może się to zmienić, dlatego piszę implementację adaptera MysqlDbAdapter, implementuje proste Dependency Injection i tworzy kilka metod wytwórczych, dodatkowo implementuje system ustawień całego projektu dla środowiska produkcyjnego, deweloperskiego i testowego. Swój kod pokrywa testami(wie że poświęcony dodatkowy czas na testy zaowocuje w późniejszym etapie projektu). W dzień wdrożenia systemu u klienta dowiaduje się, że jedyne bazy które klient posiada to bazy Oracle, w szybki sposób musi zareagować i dostosować system do infrastruktury zleceniodawcy(nie ma innego wyjścia, klient nie chce nic dodatkowego instalować). Szybko dopisuje brakujący adapter do bazy Oracle bazując na OCI8 lub PDO_OCI i dodaje go do DI, podmienia adapter w metodzie wytwórczej i uruchamia testy. Naprawia błędy wynikające z różnic w składni zapytań pomiędzy Oracle DB a MySQL, jeszcze raz testuje wszystkie funkcjonalności i wysyła nową wersję do klienta. Lokalnie pozostaje przy MySQL podmieniając adapter w konfiguracji deweloperskiej. Klient jest zadowolony z szybkiego dostarczenia działającego produktu, było kilka błędów które szybko zostały naprawione, system w firmie się sprawdził dlatego klient chce kolejnych funkcjonalności ヽ( ͝° ͜ʖ͡°)ノ

Historia pierwsza co prawda jest dramatyczna, ale doskonale przedstawia skutki braku teoretycznej i praktycznej znajomości wzorców. Jeżeli chcesz pisać dobry kod musisz przynajmniej wiedzieć jakie wzorce programistyczne stosuje się najczęściej, reszta przyjdzie z praktyką lub od starszych kolegów z zespołu.

Nieświadome wykorzystywanie wzorców

Niektóre wzorce mają skomplikowaną budowę o której można się rozpisywać godzinami, inne są tak proste że ciężko nad nimi długo dywagować. Przykładem może być Dependency Injection - nazwa wskazuje, że w opisie tego wzorca znajdziemy wiele teorii i rozbudowaną strukturę wzorca. Niespodzianka, tego wzorca używałeś prawdopodobnie już wcześniej nieświadomie w swoich prostych projektach lub pierwszych skryptach z wykorzystaniem OOP.

Wielu programistów zaczyna przygodę od poznania podstawowych konstrukcji, struktur i słów kluczowych po czym rozpoczyna naukę jednego z poopularniejszych frameworków. Zend Framework, Symfony, Laravel to jedne z pierwszych wyborów(ze względu na ich popularność), kilkudniowa podróż po dokumentacji, pierwsze kontrolery, modele i widoki... powstaje prosta aplikacja. Stworzenie pierwszego formularza w Symfony powoduje, że trzeba wykorzystać gotowe rozwiązania bazujące na przynajmniej kilku wzorcach projektowych(fabryka, MVC, DI).

Czyli da się je wykorzystywać nawet nie wiedząc o ich istnieniu? - Dokładnie

Czy jest więc sens poznawać je dokładniej? - Jak najbardziej

Podsumowanie

Na tym koniec. Ten wpis jest początkiem serii związanej z wzorcami projektowymi w PHP. Zapraszam i polecam rozwijać swoją wiedzę teoretyczną, bez wzorców projektowych żaden bardziej skomplikowany projekt nie ma racji bytu a każdy programista powinien je znać.