Niedawno minęło 5 lat, odkąd zacząłem zawodowo pracować jako programista. Pomimo że programowanie jako hobby towarzyszyło mi już dużo wcześniej, to dopiero praca dała mi przysłowiowego “kopa”, dzięki któremu zacząłem się rozwijać.

Kiedy ostatnio przypomniałem sobie moje początki, byłem zaskoczony, jak wiele się we mnie zmieniło. Zauważyłem to dopiero po kilku latach. Postanowiłem więc to spisać.

Zabiorę Cię zatem na krótką wyprawę i opowiem Ci o etapach, które przeszedłem – jak wtedy myślałem, co robiłem i co się zmieniło. Idziesz?

Początkujący programista tworzy kod, który działa

Każdy, kto kiedykolwiek zaczynał programować, wie, że jeden z pierwszych powodów do radości to ten, kiedy program kompiluje się bez błędu i zaczyna działać. Nieważne, że wyświetla statyczny tekst na ekranie, komunikat po kliknięciu przycisku czy też wykonuje jakieś mniej ambitne zadania. Działa.

Na tym etapie nie myśli się jeszcze o architekturze. Przynajmniej ja nie myślałem. Bardziej byłem zafascynowany tym, co mogę jeszcze ciekawego zaprogramować. Boty do gier, proste strony internetowe, własny CMS… Im więcej przeprowadzonych eksperymentów, tym lepiej.

Z czasem pojawiają się bardziej zaawansowane projekty, a wraz z nimi pierwsze większe problemy. Problemy ze strukturą kodu, duplikacje, brak czytelności i ogólny nieład, który skutkuje coraz to większą frustracją. Wprowadzanie zmian staje się czasochłonne, a efekty działań zazwyczaj nie są zadowalające.

Źródło: giphy.com

Brak wiedzy na temat podstawowych wzorców projektowych potrafi szybko położyć nawet najbardziej ambitny projekt. Kod staje się nierozwijalny, w efekcie czego łatwiej jest napisać wszystko od początku. Z wiadomym skutkiem.

Kilka mądrych ludzi i książek podpowiadało, co z tym można zrobić. Zastosowanie reguł takich jak SOLID, DRY czy KISS było pierwszą poradą, o której przeczytałem – nawet już nie pamiętam gdzie. W teorii oczywiście wszystko brzmi świetnie, jednak stosowanie się do tych zasad stwarza problemy nawet doświadczonym programistom, a co dopiero początkującym.

Rozwiązaniem wydaje się użycie wzorców projektowych. To one wkrótce staną się moim podstawowym narzędziem pracy.

Etap używania wzorców projektowych

W miarę odkrywania programistycznego świata dowiedziałem się, że większość problemów, z którymi się mierzyłem, została już rozwiązana. Część z nich została uogólniona na tyle, że można je wpasować w któryś ze znanych już wzorców projektowych, np. tych zaproponowanych w książce gangu czworga.

Idea stojąca za używaniem wzorców projektowych była bardzo zachęcająca. Zapewniają one sprawdzone rozwiązania na konkretne problemy projektowe. Dla mnie, jako początkującego programisty był to sposób na umieszczenie kodu we właściwym miejscu we właściwy sposób.

Nadużywanie wzorców projektowych

Wzorce były tak świetnym narzędziem, że wręcz błędem wydawało mi się pisanie kodu bez ich użycia. Skutek był taki, że po jakimś czasie wszędzie widziałem możliwości wykorzystania jakiegoś wzorca. Nawet tam, gdzie nie było to potrzebne.

Początkowo posiadanie uogólnionego rozwiązania na każdy problem wydawało się dobrym pomysłem. Najczęściej jednak program stawał się zlepkiem abstrakcji, natomiast to, co faktycznie robił, było głęboko ukryte w kodzie.

Teraz już wiem, że wzorzec projektowy stanowi ramę do rozwiązania problemu, ale nie jest rozwiązaniem samym w sobie.

Tamtego czasu większość rzeczy pisałem samodzielnie, nie chcąc korzystać z gotowych rozwiązań. Z jednej strony było to dobre, ponieważ dużo rzeczy zrozumiałem, kiedy musiałem je zaimplementować. Z drugiej strony wymagało to jednak znacznie większej ilości czasu, a efekty tego były różne.

Wzorzec projektowy nie jest rozwiązaniem problemu. Jest uogólnieniem rozwiązania i stanowi dla niego szkielet.

Kiedy jednak znudziło mi się pisanie w kółko tych samych rzeczy, moja uwaga powędrowała w stronę gotowych rozwiązań.

Na każdy problem jest biblioteka

Bardzo szybko wszedłem w świat frameworków. Były dobre, ponieważ nałożyły ramy i strukturyzowały pracę, szczególnie jeżeli chodzi o pisanie kodu. Miały również masę gotowych do użycia komponentów, które przyspieszały development.

Szybko przyzwyczaiłem się do podejścia, że jeżeli jest jakiś problem, to jest bardzo prawdopodobne, że ktoś już znalazł na niego rozwiązanie. Możliwe, że nawet zaimplementował je w formie jakiejś biblioteki.

The chart which presents number of packages and their versions in time
Wykres przedstawiajacy wzrost liczby bibliotek i ich wersji w repozytorium packagist.org. Liczba bibliotek na maj 2019 wynosi ponad 225 tysięcy.

Szukanie gotowców zamiast rozwiązań

Ta sytuacja sprawiła, że zamiast skupiać się na rozwiązaniu problemów, zacząłem skupiać się na odnajdowaniu narzędzi, które ów problem mogłyby rozwiązać. Czy rozwiązywały? Oczywiście. Czy bezproblemowo? Niestety nie. Często użycie jakiegoś zewnętrznego kodu nakłada ograniczenia, które stają się problemem w bardziej specyficznych przypadkach biznesowych.

Po jakimś czasie zacząłem dużo uważniej przyglądać się wszystkim bibliotekom, jakie zamierzałem włączyć w projekt. Skoro i tak trzeba będzie poświęcić czas na dostosowanie danej funkcjonalności do wymagań, może jednak napisać to samodzielnie? Czy jeżeli użyje innej biblioteki, to czy nie wygeneruje ona nowych problemów? Czy faktycznie rozwiąże problem?

Adjusting ready-made solutions according to client’s requirements. Source: giphy.com

Rozwiązywanie problemów

W pewnym momencie stało się dla mnie jasne, że rozwiązywanie problemów nie polega jedynie na pisaniu oprogramowania. Niektóre klasy problemów można rozwiązać, wykorzystując do tego celu już istniejące programy. Trzeba tylko wiedzieć jakie.

Wsłuchanie się w potrzeby klienta

Załóżmy, że klient przychodzi z prośbą o stworzenie aplikacji do generowania zestawień i raportów z firmy, ale ma dosyć mocno ograniczony budżet. Z jakiegoś powodu przyszedł właśnie do nas. To z kolei powinno prowadzić do kilku pytań:

  • Czy to, że trafił właśnie do nas, wynika z tego, że źle adresujemy komunikat do potencjalnych klientów?
  • Skoro już się u nas pojawił, jak możemy mu pomóc?
    • Czy klient faktycznie potrzebuje dedykowanego oprogramowania?
    • Jeśli nie, to czy istnieje gotowe narzędzie, które możemy zaproponować klientowi w zamian, np. Microsoft Excel, Calc z pakietu Libre Office lub inny arkusz kalkulacyjny?
    • Czy możemy przekierować klienta do innej firmy, która być może się w tym specjalizuje lub dla której ten klient byłby odpowiedni?
    • Czy faktycznie w zadanym budżecie możemy coś wykonać?

Jak widać, nie wszystko musi się sprowadzać do pisania kodu. Jeżeli jednak się sprowadza, to należy zadbać, aby faktycznie było to ukierunkowane na rozwiązanie jakiegoś problemu. Najlepiej gdyby to rozwiązanie w pełni zaspokajało potrzeby.

Architektura, paradygmat, język, framework to tylko narzędzia, które mają za zadanie pomóc w rozwiązaniu problemu domenowego.

Zauważyłeś pewnie, że kiedy piszę o problemach, nie mam tu na myśli wyzwań, które sami jako programiści stawiamy sobie, wybierając architekturę, paradygmat czy framework. Są to nasze narzędzia, które mają za zadanie służyć do rozwiązania problemu wyższego poziomu, najczęściej jakiegoś problemu biznesowego lub bardziej ogólnie – problemu domenowego.

Rozwiązywanie problemów domenowych

Te problemy są najciekawsze, nie wystarczy tutaj sama wiedza z zakresu programowania. Potrzebna jest także specjalistyczna wiedza dziedzinowa. To prawdziwe wyzwania, które wymagają od programisty ciągłego doskonalenia się i chęci poznawania nowych rzeczy, niekoniecznie związanych ze światem IT.

To tutaj pojawia się słynny akronim DDD – Domain–Driven Design, który to jest świętym gralem każdego programisty aspirującego do roli projektanta systemów. Miejscem, w którym developerzy wiedzą, czego oczekuje biznes, a biznes czuje się zrozumiany przez developerów.

Aby to było możliwe, należy zrezygnować z rzeczy, które wprowadzają niepotrzebny szum. Używać ich tylko tam, gdzie jest to niezbędne, aby usprawnić rozwiązanie problemu. Rzeczy, które są skomplikowane, należy upraszać, a proste czynić jeszcze prostszymi.

Faworyzacja prostoty prowadzi w efekcie do tego, że programista zaczyna tworzyć kod, który po prostu działa. I jest prosty.

Doświadczony programista tworzy kod, który działa

Nie szukam projektów, które mogę zrobić w moim ulubionym frameworku lub wykorzystując aktualnie popularną architekturę. Nie tworzę na siłę z każdej pętli iteratora i staram się nie komplikować rzeczy, które mogą być proste.

Nie wymyślam też koła na nowo i używam narzędzi, które są dostosowane do rozwiązywania określonych problemów. Każda napisana linijka kodu to rzecz, o którą trzeba będzie dbać i którą trzeba konserwować w przyszłości.

Zamiast tego pomagam innym rozwiązywać ich problemy. Probuje dotrzeć do tego, czego tak naprawdę potrzebują, zrozumieć to i zaproponować najlepsze rozwiązanie do konkretnej sytuacji.

Korzystam też z hojności innych programistów, którzy dzielą się zarówno swoją wiedzą, jak i pracą. Sam staram odwdzięczać się tym samym – pokazując jak pisać dobry kod i samemu dzieląc się wiedzą z innymi.

Kiedy piszę kod, wiem, że nie tylko ja będę go oglądał. Wiele par oczu będzie czytało i starało się zrozumieć, jak dana funkcjonalność została zaimplementowana i co właściwie robi. Moim zadaniem jest ułatwić innym zrozumienie tego.

Wszystko to w połączeniu z doświadczeniem składa na mój warsztat, dzięki któremu mogę sprawnie rozwiązywać kolejne problemy, stale się przy tym rozwijając i doskonaląc. Codziennie poznaje nowe rzeczy i sam decyduje, które z nich mogę włączyć do mojego warsztatu.

Podsumowanie

Dziele się swoimi przemyśleniami, bo chce pokazać Ci, jak na różnym etapie życia i kariery zawodowej zmieniałem perspektywę i swój sposób myślenia.

Raz dążyłem do tego, aby pisać jak najwięcej samemu, innym razem szukałem gotowych rozwiązań. Potem usilnie starałem się wykorzystywać to, czego się nauczyłem. Dopiero po latach nauczyłem się jak robić to dobrze.

Jak widać, wiele się zmieniło – moim zdaniem na lepsze. Zmiany są widocznym następstwem i dowodem dokonywania postępu. Nie są jednak wynikiem samego upływu czasu.

Zmiana pracy, wpływ innych ludzi, utrzymywane relacje, środowisko, studia (🇺🇸) i książki to tylko niektóre z ważniejszych elementów, które wpłynęły na mój sposób myślenia. Dlatego tak ważne jest otwarcie się na inne doświadczenia i konfrontacja z nowymi ideami i pomysłami.

To, co opisałem to moja droga, która nie koniecznie musi pokrywać się z Twoją i zapewne nie będzie. Jeśli jednak w jakiś sposób identyfikujesz się z tym, co przedstawiłem, powiedz mi o tym, zostawiając komentarz lub przez e-mail.

To jeszcze nie koniec podróży.

Zanim się jednak pożegnamy, zostawię Cię z taką myślą – jaką najważniejszą zmianę widzisz w sobie, porównując obecnego siebie do siebie z przed roku?


Featured photo by Émile Perron on Unsplash.