POIT #232: Software Craftsmanship: Object-oriented programming

Witam w dwieście trzydziestym drugim odcinku podcastu „Porozmawiajmy o IT”. Tematem dzisiejszej rozmowy w serii podcastów o software craftsmanship jest object-oriented programming czyli programowanie obiektowe.

Dziś moim gościem jest Łukasz Drynkowski, z którym mam przyjemność współtworzyć portal z ofertami pracy dla branży IT o nazwie SOLID.Jobs.

Główne myśli o programowaniu obiektowym z tego odcinka to:

  • piszcie kod OOP a nie imperatywny wykorzystujący obiekty,
  • używajcie nie tylko enkapsulacji i dziedziczenia ale też poliformizmu,
  • przemyślcie jakie zalety daje wam w projekcie programowanie obiektowe i starajcie się je wykorzystać w celu poprawienia utrzymowalności kodu,
  • pamiętajcie że object-oriented programming nie jest jedynym paradygmatem programowania, może dla danego zadania znajdziesz lepsza alternatywę.

Subskrypcja podcastu:

Linki:

Wsparcie na Patronite:

Wierzę, że dobro wraca i że zawsze znajdą się osoby w bliższym lub dalszym gronie, którym przydaje się to co robię i które zechcą mnie wesprzeć w misji poszerzania horyzontów ludzi z branży IT.

Patronite to tak platforma, na której możesz wspierać twórców internetowych w ich działalności. Mnie możesz wesprzeć kwotą już od 5 zł miesięcznie. Chciałbym oddelegować kilka rzeczy, które wykonuję przy każdym podcaście a zaoszczędzony czas wykorzystać na przygotowanie jeszcze lepszych treści dla Ciebie. Sam jestem patronem kilku twórców internetowych i widzę, że taka pomoc daje dużą satysfakcję obu stronom.

👉Mój profil znajdziesz pod adresem: patronite.pl/porozmawiajmyoit

Pozostańmy w kontakcie:

 

Muzyka użyta w podcaście: „Endless Inspiration” Alex Stoner (posłuchaj)

Transkrypcja podcastu

To jest 232. odcinek podcastu Porozmawiajmy o IT, w którym w cyklu rozmów z Łukaszem Drynkowskim z portalu z ogłoszeniami pracy IT SolidJobs, której to zresztą mam przyjemność współtworzyć, dyskutujemy o Software Craftsmanship, czyli o rzemiośle programisty. 

Zapraszamy do słuchania i komentowania. A teraz życzymy Ci już miłego słuchania. 

Odpalamy! 

 

Cześć, Łukasz! 

 

Cześć, Krzysztof! 

 

Spotykamy się już po raz trzeci w ramach tej serii podcastów o Software Craftsmanship. Dzisiaj będziemy rozmawiać o czymś bardzo istotnym, z czym pewnie większość i aktywnych i początkujących programistów ma do czynienia, czyli z podejściem obiektowym do programowania. 

Jest to bardzo popularny paradygmat, pewnie większość osób, które zaczynają się uczyć, nie zdają sobie nawet sprawy, że są inne. Myślę, że o tym dzisiaj też powiemy. Wiele osób na co dzień właśnie korzysta z tego podejścia. Pytanie tylko, czy robią to dobrze, to już jest inny temat. Jakby nie było, jest to istotna część naszego programistycznego rzemiosła, więc dzisiaj o obiektowym programowaniu będzie mowa. 

 

Tak, chcielibyśmy tutaj postawić hipotezę, że raczej mało kto robi to dobrze. Raczej to programowanie obiektowe polega na programowaniu z użyciem klas i obiektów, a nie na takim Object Oriented Programming. Spróbujemy dzisiaj tak zdefiniować trochę i opowiedzieć o tym, czym tak naprawdę to programowanie obiektowe być powinno, a czym zazwyczaj jest, bo z mojego doświadczenia to często jest tak, że po prostu ktoś programuje z użyciem właśnie klasy i obiektów, ale tak naprawdę ten kod dalej jest imperatywny, tylko po prostu znajduje się wewnątrz jakiegoś obiektu ze słowem kluczowym klasy. 

 

Właśnie, jest to jakaś taka wydmuszka, czy taki kontener, coś takiego, co osłania nam kod imperatywny. Tutaj kompletnie nie o to chodzi. To nie jest forma organizacji kodu, tylko forma myślenia o tym, jak poszczególne elementy kodu powinny być ułożone, jak też powinny ze sobą rozmawiać. 

Ja mam wrażenie, że to właśnie tutaj o interakcje chodzi pomiędzy obiektami, czy o to, jak ten kod ma być ułożony, żeby ta współpraca przebiegała sensownie, że tutaj tkwi właśnie problem, że najbardziej, najczęściej powtarzający się issue jest związany z tym, że źle ten kod układamy, albo też, że nie wykorzystujemy takich zalet podstawowych cech, jakie OOP nam wprowadza. O jakich moglibyśmy właśnie takich feature’ach czy cechach tutaj powiedzieć? 

 

Tak, właśnie wydaje mi się, że taka podstawowa funkcja języków czysto imperatywnych to jest właśnie rozwiązanie danego problemu biznesowego. I tutaj piszemy kod, który rozwiązuje jakiś problem. Natomiast to, co nam daje programowanie obiektowe, to jest taka dodatkowa warstwa, która pozwala nam rozwiązywać takie metaproblemy, już czysto związane z pisaniem kodu, czyli np. ułatwia nam utrzymanie tego kodu, ułatwia nam dodanie nowych funkcji, ułatwia nam zmianę tego, co już jest. 

I to jest właśnie ta zaleta i ta wyższość programowania obiektowego nad tym programowaniem imperatywnym, czyli dodanie takiej dodatkowej warstwy, gdzie np. jedną z kluczowych cech jest np. możliwość użycia wzorców projektowych, które ja bym tutaj może tak dość odważnie zdefiniował jako takie meta-algorytmy, które właśnie pozwalają nam rozwiązywać problemy, które sobie tutaj dzielnie właśnie jako programiści tworzymy, czyli te problemy utrzymania kodu i jakichś po prostu przepływów i tego, żeby było łatwo dodać nowe funkcje, łatwo zmienić funkcje istniejące. 

 

Właśnie, takie szersze spojrzenie na programowanie obiektowe to jest też próba jego przedstawienia jako rodzaj odwzorowania rzeczywistości. Odwzorowujemy ten nasz problem biznesowy, tę naszą domenę właśnie jako obiekty, które ze sobą rozmawiają, można powiedzieć, które wymieniają jakąś informację, które żądają coś od siebie. Ale to nie jest jedyna rzecz, nie? 

 

Tak, programowanie obiektowe to właśnie nie jest tylko właśnie rozwiązywanie tego problemu, ale to jest też umiejętność definiowania abstrakcji, definiowania zachowań i interakcji między klasami, struktur hierarchii między klasami, nie tylko tutaj mówię o dziedziczeniu, ale też o odpowiednich powiązaniach między klasami, czy gdzieś powinno być właśnie to dziedziczenie, czy zamiast tego jakaś zależność między klasami powinna być. 

I to jest właśnie to, co odróżnia tutaj takie programowanie z użyciem obiektów od tego właściwego programowania orientowanego obiektowo. Czyli też definiowanie zachowań, definiowanie też tego własności danych, tego, gdzie te dane powinny być, definiowanie odpowiedzialności pomiędzy klasami i za tym też idzie definiowanie warstw abstrakcji, czyli też wydzielenie, które klasy tutaj mają odpowiadać np. za jakąś logikę biznesową, mają pilnować jakichś reguł związanych z tym problemem domenowym, a które klasy, które części systemu mają odpowiadać za jakieś problemy, nazwijmy to, związane z infrastrukturą, z dostępem do danych, z wymianą danych, czyli jakiś właśnie dostęp do API, wysyłanie maili, dostęp do bazy danych. 

 

Tak, wspomniałeś, że tworzenie całego software’u, tworzenie systemu z wykorzystaniem tego podejścia jest trudniejsze niż programowanie imperatywne. Myślę sobie, że można to zrozumieć w ten sposób, że pisanie kodu imperatywnego to jest takie wydawanie instrukcji, takie krok po kroku mówienie dokładnie, co komputer, co maszyna ma zrobić. Natomiast jeśli przechodzimy już na programowanie obiektowe, to musimy myśleć pewnymi abstrakcjami. Musimy myśleć też o tym, jak kod ułożyć, jak go zaplanować, rozłożyć na różne warstwy, o czym wspomniałeś. 

Ta doza myślenia, doza zastanawiania się i projektowania finalnego rozwiązania jest zdecydowanie większa, a programowanie imperatywne, to po prostu ciurkiem sobie te instrukcje wydajemy, nie zastanawiając się nad tym, czy ten kod może być wykorzystany później, czy on jakoś zależy od innego fragmentu itd., co myślę sobie, że w pewnych zastosowaniach jest jak najbardziej sensownym podejściem. Natomiast jeśli mówimy już o tworzeniu większej aplikacji z tą myślą właśnie utrzymania, rozszerzania, to bardzo trudno jest taki kod imperatywny właśnie gdzieś tam w ten maintenance wcisnąć po prostu. 

 

Tak, i podstawowymi elementami programowania obiektowego, o które np. na rozmowach kwalifikacyjnych się nie pyta, bo to są takie rzeczy oczywiste, to jest właśnie ta enkapsulacja, czyli umiejętność odpowiedniego, ja bym to nawet powiedział, podziału odpowiedzialności między klasami, czyli właśnie określenie tej własności danych, kto, za co odpowiada. 

To jest właśnie coś takiego, co wydaje się oczywiste, ale cały czas w mojej pracy, w mojej praktyce spotykam się z tym, że jednak nie jest to dobrze robione, nie jest to dobrze zaplanowane i to działa w dwie strony, bo najczęściej tutaj się mówi, że jest nie zenkapsulowane coś i wystawiamy tutaj gdzieś na światło dzienne, że tak powiem, coś, co powinno być prywatne, natomiast równie często spotykam się z taką sytuacją, że coś zostało właśnie by default oznaczone jako private i nie dajemy tutaj możliwości na jakieś dziedziczenie, na jakiś polimorfizm, bo po prostu coś, co powinno być protected, powinno być dostępne dla tych klas dziedziczących, nie jest dostępne. 

Wydaje mi się, że tutaj dobrym probierzem jest pisanie testów jednostkowych, bo to też wymusza dobry design w trakcie tworzenia tego kodu i określania widoczności poszczególnych elementów w klasie. 

Drugim zapomnianym pojęciem jest polimorfizm, czyli coś, co sprawia, że programowanie obiektowe ma sens, czyli możliwość użycia interfejsów i klas nadrzędnych, a tak naprawdę pod spodem mamy coś bardziej wyspecjalizowanego i coś, co robi już to zadanie konkretne, jakieś patterny typu double dispatch i znalezienie odpowiedniego robotnika do danego zadania. 

Drugim zapomnianym pojęciem jest polimorfizm, czyli coś, co sprawia, że programowanie obiektowe ma sens, czyli możliwość użycia interfejsów i klas nadrzędnych, a tak naprawdę pod spodem mamy coś bardziej wyspecjalizowanego i coś, co robi już to zadanie konkretne, jakieś patterny typu double dispatch i znalezienie odpowiedniego robotnika do danego zadania.

 

Tak, to może ułatwiać całą konstrukcję zadania. systemu. Może zdecydowanie służyć temu, że ten kod będzie łatwiej utrzymywalny, ale też, że po prostu zwyczajnie mniej go napiszemy, a to zawsze jest lepiej. Im mniej kodu, tym łatwiej jest po prostu zarządzać. 

 

Tak, raz, że mniej napiszemy, a dwa, że jeszcze zmieniając, się mniej napracujemy, bo będziemy mieli łatwą możliwość dodania czegoś ekstra. 

 

Dokładnie tak. Mówimy tutaj o programowaniu obiektowym, ale to nie jest jedyne oczywiście podejście, bo w ostatnich latach gdzieś tam coraz częściej się przebija ta świadomość, że mamy jeszcze programowanie funkcyjne. W przypadku frontendu, nie tylko frontendu, ale tam jak gdyby mam wrażenie, że najczęściej programowanie reaktywne, które też bardzo dobrze się sprawdza, więc będąc świadomym rzemieślnikiem programowania, trzeba sobie zdawać sprawę, że to nie jest jedyne narzędzie, które możemy wykorzystać. 

Ja natomiast bardzo często gdzieś tam się zastanawiam, jak to właściwie się stało, jak to właściwie jest, że programowanie obiektowe jest zdecydowanie bardziej popularne od innych paradygmatów, chociażby od programowania funkcyjnego, które często jest wstawiane w kontrze albo jako, można powiedzieć, jako taki paradygmat z drugiego bieguna. 

Jak robiłem sobie gdzieś tam research, czytałem w internecie, to muszę Ci powiedzieć, że to nie jest takie oczywiste, dlaczego właśnie programowanie obiektowe jest zdecydowanie popularniejsze. Niektórzy twierdzą, że jest ono bardziej naturalne, że odwzorowuje naszą rzeczywistość, która de facto jest oparta na jakichś obiektach, które są jakichś tam klas, można powiedzieć, które to z kolei zawierają ten swój stan, czyli zbiór cech, które charakteryzują te obiekty i w jaki sposób się zachowują, co ma być odpowiednikiem takich metod. Tutaj można by pewną analogię postawić. 

Ale też z takiego historycznego punktu widzenia Też nie jest to bardzo oczywiste, bo pierwszy taki nowożytny, że tak go nazwę, język programowania, który dosyć mocno korzystał z programowania obiektowego, to jest oczywiście C++, lata 80. Można powiedzieć, że powstał oczywiście on jako nadzbiór języka C, wprowadzając m.in. programowanie obiektowe i tutaj to m.in. starałem się podkreślić, bo nawet sam twórca nie do końca jest przekonany, czy to właśnie wprowadzenie programowania obiektowego do C++ przyczyniło się do jego sukcesu, czy też może to było tak, że te inne elementy, które niejako weszły do C++, jak lepsze zarządzanie pamięcią, obsługa wyjątków itd. nie spowodowały, że po prostu więcej ludzi zaczęło korzystać z C++, co automatycznie pociągnęło za sobą gdzieś tam upowszechnienie się programowania obiektowego. 

Nie jest to do końca takie jasne, myślę, że to jest bardziej skomplikowany problem, ale prawda jest też taka, że większość tych nowoczesnych języków programowania, zaczynając od C++, później Java i C Sharp, które gdzieś tam mocno brały garściami z C++, poprzez, idąc dalej, Pythony, Ruby itd. Wszystkie one jednak ten paradygmat obiektowy mają dominujący, więc to jest taka kula trochę śniegowa, która w tym momencie już się bardzo napędza. 

 

Tak, myślę, że jednak to jest ten kluczowy czynnik, czyli to że jest to programowanie obiektowe dla nas najbardziej naturalne i pozwala nam po prostu myśleć tutaj w taki sposób, jak naturalnie myślimy, a nie przestawiać się na jakieś tutaj trochę inne tryby. 

Pamiętam, jak na studiach mieliśmy taki przedmiot, gdzie programowaliśmy w Prologu. I to był szok, żeby w ogóle tutaj w to wejść i zacząć myśleć w ten sposób, zupełnie trzeba było zmienić sposób myślenia. I to jest trochę tak, jak np. gra w tenisa, jak grasz rakietą, tak, a teraz będziesz miał zagrać, nie wiem, w squasha albo w ping-ponga, tak, to masz zupełnie inne odbicie i sobie możesz zepsuć sobie to uderzenie, po prostu zmieniając tutaj jedno a drugie podejście, tak, i jest taki element szoku. 

 

Tak, tak. To jest inne podejście, inny sposób myślenia, inny sposób odwzorowywania problemu w produkcie, w projekcie, w software. Ale też trzeba być świadomym tego, że to nie jest tak, że to jest zero-jedynkowe, że mamy albo języki obiektowe, albo funkcyjne. 

 

Tak, teraz coraz więcej już jest elementów właśnie programowania m.in. funkcyjnego w tych nowoczesnych językach, takich jak np. C Sharp, i myślę, że są takie elementy podstawowe, np. LINQ, bo chyba nikt sobie już nie potrafi wyobrazić, jak coś zrobić bez LINQ.

 

Dokładnie, C Sharp, ale też Kotlin przecież, to jest też Python, Java, JavaScript, Ruby, mnóstwo języków, które takie możliwości dają i myślę, że trzeba z tego korzystać, bo to wcale nie jest tak, że korzystanie z jednego paradygmatu wyklucza drugi, wręcz przeciwnie, powinniśmy jako rzemieślnicy mieć takie podejście, gdzie dobieramy rozwiązanie do problemu i to podejście bardziej funkcyjne albo takie punktowo funkcyjne w pewnych elementach, w pewnych zastosowaniach może być po prostu lepsze, więc nie powinniśmy się bać mieszać, mam wrażenie, tych dwóch paradygmatów. 

 

Krzysztofie, jako orędownik języków funkcyjnych, powiedz mi, jakie tutaj bolączki widzisz w programowaniu obiektowym, dlaczego właśnie możemy zastanawiać się nad tym, żeby porzucić właśnie ten paradygmat i spróbować wybrać coś innego? 

 

Tak, ostatnich kilka ładnych lat programuję w języku funkcyjnym, ale wcześniej przynajmniej 10 w obiektowym, więc gdzieś tam mam wrażenie, że czuję, na czym te dwa światy polegają. 

Jak się trochę spojrzy w internetach, to na pewno można łatwo trafić na różnego typu hejt, czy różnego typu narzekanie, na różnego typu elementy związane z programowaniem obiektowym. Prawda jest taka, że nie zawsze mamy dobrą alternatywę, ale trzeba sobie zdawać z pewnych bolączek, bo tak bym je tutaj nazwał, programowania obiektowego. 

Jedną z takich najczęściej poruszanych jest to (to jest taki cytat twórcy Erlanga), że jeśli się chce dostać banana, to w przypadku programowania obiektowego dostaje się małpę dołączoną do tego banana i jeszcze z całą dżunglą, prawda? I często tak faktycznie jest, że wszystkie cechy, o których tu wspomnieliśmy, a tylko dotknęliśmy gdzieś tam powierzchni, programowanie obiektowe jest tutaj bardziej skomplikowane, ma dużo więcej możliwości, ale też automatycznie ustawia nas, w jaki sposób powinniśmy ten kod pisać, że to jest właśnie to, co automatycznie out of the box dostajemy, kiedy chcemy zgodnie z tym podejściem tworzyć oprogramowanie. I nie zawsze to jest potrzebne, nie? 

 

To tutaj się też łączy z tym druga bolączka, czyli właśnie taki boilerplating i konieczność napisania dużo takiego kodu, który właśnie nie wykonuje tej funkcji biznesowej, tego konkretnego czegoś, co byśmy chcieli osiągnąć, tylko musimy albo zaimportować, albo napisać dookoła trochę takiego środowiska, tak nazwijmy to. 

 

No tak, tutaj przykładowo Java pewnie do mistrzostwa panowała różnego typu boilerplating, ale nie tylko oczywiście, to jest generalnie taka bolączka, że nieraz ta struktura musi być odpowiednio duża, nadbudowana, zanim dopiero zaczniemy realizować pewne funkcje biznesowe. 

Jeśli mówimy o klasach i w ogóle całej tej strukturze, to oczywiście dziedziczenie jest jedną z takich podstawowych zalet programowania obiektowego. Dzięki temu możemy kod uprościć zdecydowanie, co oczywiście przytrzyma się do tego, że mamy mniej kodu do utrzymania, ale też niestety czasem jest pewną bolączką. Wykorzystujemy w nowoczesnych aplikacjach mnóstwo bibliotek. Teraz już pewnie nawet duże firmy big techowe nie wyobrażają sobie niekorzystania z open source’u. No i z tym się wiąże pewien problem. 

 

Ostatnio słyszałem, że nie mogę użyć biblioteki, bo właśnie tutaj jest problem, czy za jakiś czas ona będzie dalej wspierana. 

 

A, no tak, ryzyka z tym związane to oczywiście można by tutaj mnożyć, ale chodziło mi o to, że nawet takie duże rozwiązania tworzone przez duże firmy big techowe mają w sobie zaszyte biblioteki i niestety takie dołączenie biblioteki zewnętrznej, open-source czy nie, nieważne, trzeba brać z tym dobrodziejstwem inwentarza wszystko to, co z tym przychodzi. I wiesz, bardzo takie kusząca rzecz to jest wzięcie sobie jakiejś klasy bazowej z tej biblioteki i coś zgodnie z OOP, coś tutaj zrobienie z tą klasą, tak? Może podziedziczymy, może coś innego. 

 

Trafiasz na te private pola, które są Ci potrzebne i nie możesz ich puszczać po requesty, żeby zamienić. 

 

Robisz forka. 

 

Albo forka musisz zrobić swojego. 

 

Właśnie, to już jest problematyczne.

 

Jak już w to wchodzisz, to już jesteś na przegranej pozycji, więc myślę, że najpierw trzeba spróbować zrobić pull request, ale wiadomo jak to jest. Zazwyczaj pewnie Cię odrzucą. 

 

Różnie bywa. I teraz masz kilka właśnie wyborów. Jeśli sobie zamrozisz tę bibliotekę, dołączysz ją do swojego kodu źródłowego i ona taka zawsze będzie, no to okej. Oczywiście to też nie jest idealne rozwiązanie, bo nie dostajesz tych wszystkich update’ów, łatek itd., które mogą przychodzić w momencie, kiedy ta biblioteka się zamrozi, ale przynajmniej wiesz, co masz. 

Natomiast jeśli korzystałeś sobie z klasy bazowej takiej biblioteki i coś z nią zrobiłeś, stworzyłeś jakąś klasę dziedziczącą czy cokolwiek, no to niestety musisz liczyć się z tym, że któregoś pięknego dnia update tych bibliotek spowoduje, że nagle Twój kod po prostu przestanie działać, ponieważ klasa bazowa się zmieniła. To jest na pewno problem. 

 

Ale to jest trochę właśnie ten temat enkapsulacji i tego, że polegamy na danych, a nie na zachowaniach. I to jest też ten problem, że powinniśmy polegać na zachowaniach, a nie na danych, które gdzieś tam są i często po prostu tego typu problemy wynikają ze złego designu albo tej biblioteki, albo klienta, który korzysta z tej biblioteki. 

 

Zgadza się, na pewno. Trzymając się tutaj jeszcze enkapsulacji, która, tak jak tutaj mówiliśmy, powoduje, że dany obiekt ma nie tylko jakieś metody, ale też jakiś stan swój wewnętrzny, to trzeba powiedzieć, że często w takim programowaniu współbieżnym, kiedy kilka wątków, procesów, zależy od implementacji, próbuje coś w tym samym czasie z tym obiektem zrobić, to możemy mieć bardzo nieprzewidywalną sytuację, bo w zależności od tego, który tak naprawdę się gdzieś tam dostanie pierwszy, to może wynik być znacząco inny. Więc ta mutowalność tego stanu wewnętrznego w obiekcie może być w niektórych zastosowaniach również problemem. 

 

Tak, to jest ciekawe ogólnie, jeśli chodzi o programowanie współbieżne, a obiekty to jest cały wszechświat problemów oczywiście. Ta dostępność, ta enkapsulacja tutaj ma kolejne warstwy skomplikowania. Pewnie tutaj dochodzimy jeszcze do słowa mutowalność klas. To, żeby te klasy były immutable, czyli właśnie niezmienialne, gdzie dość krótka droga pewnie do programowania już funkcyjnego. Tak mi się wydaje, że to programowanie funkcyjne chyba w przypadku programowania współbieżnego jest tak gdzieś poziom bliżej jakby do tego, gdzie…

 

Działa inaczej, tak. Działa inaczej, nie ma tego stanu współdzielonego. Myślę, że ten temat sobie gdzieś tam zaadresujemy na pewno w jednym z kolejnych odcinków. Ja natomiast chciałbym powiedzieć właśnie o kolejnej takiej bolączce, która nie jest może bezpośrednio bolączką programowania obiektowego, a raczej tego, w jaki sposób programiści podchodzą do pisania kodu z wykorzystaniem tego paradygmatu, mianowicie olbrzymie klasy, które zawierają tam setki, tysiące linii kodu, mnóstwo logiki biznesowej w jednej klasie, mnóstwo metod. Oczywiście utrzymywanie tego typu kolosa jest zawsze problematyczne.

 

A jeszcze z każdym dniem dochodzą kolejne metody do tej klasy. To dopiero jest smutne. Już jest tam te 3000 linii kodu i jeszcze ktoś tam dokłada.

 

Właśnie i kolejne pola się gdzieś tam pojawiają i nie wiadomo już tak naprawdę, do czego, komu to jest potrzebne i wtedy robi się straszny, straszny chaos. I idąc tutaj dalej, jest na pewno ten boilerplate jako bolączka, o którym to już wspomniałeś, czyli musimy tam trochę tych linii napisać po to tylko, żeby być w stanie tworzyć jakąś wartość dalej. Taka nadmiarowość tutaj nam pojawia. I okej, jeśli ona jest tylko taka gdzieś wystarczająca, ale sam pewnie widziałeś i wielu z naszych słuchaczy na pewno również tego typu abstrakcje, które są w większości bolilerplate’em, bo tak to ktoś kiedyś wymyślił albo ktoś robi tzw. optymalizacje na przyszłość, tak że wydaje się, że wyniesienie tego do abstrakcji jakiejś spowoduje, że będzie nam w przyszłości łatwiej. Oczywiście wiemy, że to też jest taki antypattern.

 

Zawsze musimy sobie zadać pytanie, dlaczego robimy to, co robimy, w jakim celu tutaj coś dodajemy i czasami to jest odpowiednie rozwiązanie dodanie tej dodatkowej warstwy abstrakcji, a czasami to jest sztuka dla sztuki i wtedy powinniśmy się opamiętać.

 

Otóż to. Można też iść w drugą stronę, tzn. tworzyć mnóstwo małych klas, które no właśnie, może nam się przydadzą w przyszłości, albo może tutaj będziemy mieli inny wariant z tej klasy i będzie nam się żyło łatwiej kiedyś tam itd. Praktyka pokazuje, że rzadko tak jest, natomiast nadmiar klas może nas też strasznie boleć, ponieważ w pewnym momencie tracimy już ten obraz. Właściwie nie wiemy, gdzie i do czego te klasy stworzyliśmy.

 

Tak, też tutaj taki przykład może z życia wzięty. Mamy 3 warstwy, przez które musimy jakieś dane przepchnąć. Gdzieś to DTO jest tłumaczone kilka razy pomiędzy tymi warstwami, też jest do zastanowienia czy na pewno każda z tych warstw np. potrzebuje ten model tego DTO swój, czy gdzieś w osobnym assembly nie może być jakaś klasa, która po prostu będzie reprezentować te dane, które tam są wypychane, bąbelkowane gdzieś do góry.

Ale wydaje mi się, że to jest właśnie taki też ogólny problem programowania obiektowego, że mamy bardzo dużą dowolność działania i tutaj możemy naprawdę zrobić wszystko i te ograniczenia musimy sobie sami tak naprawdę na siebie nakładać poprzez stosowanie różnych zasad, np. solid, dry itd. I po prostu to jest tak, że jeśli my sobie sami tych ograniczeń nie nałożymy, to wyjdzie jak bądź. I to jest ta trudność, że te inne paradygmaty są bardziej takie stricte, a programowanie obiektowe jest takie bardziej otwarte na to, co Ty zrobisz – co jest wadą i zaletą.

Ale wydaje mi się, że to jest właśnie taki też ogólny problem programowania obiektowego, że mamy bardzo dużą dowolność działania i tutaj możemy naprawdę zrobić wszystko i te ograniczenia musimy sobie sami tak naprawdę na siebie nakładać poprzez stosowanie różnych zasad, np. solid, dry itd. I po prostu to jest tak, że jeśli my sobie sami tych ograniczeń nie nałożymy, to wyjdzie jak bądź. I to jest ta trudność, że te inne paradygmaty są bardziej takie stricte, a programowanie obiektowe jest takie bardziej otwarte na to, co Ty zrobisz – co jest wadą i zaletą.

 

Właśnie, dokładnie to samo chciałem powiedzieć. Tutaj jak gdyby na bazie doświadczeń, na bazie może wiedzy innych itd. trzeba podjąć tę decyzję, jak bardzo będziemy otwarci w tym naszym kodzie, a na ile będziemy chcieli jednak trzymać się zasad. Nie ma jednej dobrej niestety odpowiedzi.

Okej, wiesz co, tutaj mam wrażenie, że dotykamy dwóch różnych obszarów. Tego bardziej technicznego i tego bardziej, nazwałbym go, domenowego, czyli z jakich mechanizmów możemy skorzystać, w jaki sposób najlepiej je wykorzystać, ale też w jaki sposób zmapować tę naszą domenę, problem itd. na konkretne rozwiązanie w kodzie, czyli jakie klasy, jakie metody, jaki stan wewnętrzny itd. I to też jest swego rodzaju sztuka, to też jest swego rodzaju rzemiosło.

Jestem ciekawy, może to jest kontrowersyjna tutaj kwestia, ale jestem ciekawy, co ty o tym myślisz. Czy według Ciebie programiści, którzy lepiej znają domenę, więcej wiedzą o tym obszarze, są w stanie napisać lepszy kod obiektowy, czy nie ma to żadnego znaczenia?

 

Ja tu jestem zdecydowanie zwolennikiem tego, że ten programista powinien bardzo dobrze wiedzieć, co ta domena robi, z czym to się je. Bardzo dużo błędów z mojego doświadczenia można byłoby uniknąć, gdyby ten programista wiedział trochę więcej o tym co robi, w sensie o tej domenie. Wierzę, że w tym, co robi, jest specjalistą, ale właśnie wydaje mi się, że po prostu wiele problemów, wiele błędów można byłoby uniknąć, gdyby ktoś zadbał o to, żeby ci programiści jednak lepiej znali tę domenę, a wręcz nawet spotkałem się z takim antypatternem, że ten programista nie wiedział tak naprawdę, co to będzie robić, kazali mu zrobić sztukę, zrobił sztukę, zrobił to odwrotnie, niż miał zrobić. 

Załóżmy, że miał to liczyć jakąś tam płeć, wyszedł mężczyzna, powinna być kobieta, bo np. jest badanie piersi i potem mówi, że wydawało mu się, że to jest bez sensu, ale tak było tam gdzieś w tickecie, to się nie zastanawiał, tylko tak zrobił, a popełnił zwykły czeski błąd, analityk, który gdzieś tam źle przepisał z jednego Excela do drugiego.

 

I tutaj chyba leży to rzemiosło prawdziwe, czyli nie tylko znajomość narzędzi, możliwości, samych opcji, jakie mamy, tych technicznych, ale też zaznajomienie się z domeną i takie logiczne myślenie. Ta kombinacja tych elementów spowoduje, że po prostu ten kod, który piszemy w wydaniu obiektowym, będzie nie tylko poprawny pod względem technicznym, ale również będzie przynosił odpowiednią wartość dla klientów, dla użytkowników. I myślę sobie, że tutaj też trzeba jeszcze dodać dla przyszłych developerów, którzy będą ten kod rozwijać.

 

Tak, ale to też jest ciekawe, co powiedziałeś, nawiązując do jednego z poprzednich naszych odcinków właśnie o etosie programisty. Wydaje mi się, że to jest też ważne, że jeśli chcę być dobrym tutaj rzemieślnikiem, dobrym programistą, to sam dla siebie powinienem tutaj starać się tę domenę zrozumieć i jakby naciskać tutaj na ten management, na to, żebyśmy my jako programiści rozumieli tę domenę. Może jakieś są potrzebne np. dodatkowe szkolenia np. z dziedziny rozliczeń z NFZ, jeśli realizujemy projekt, który musi gdzieś tam wyliczyć jakieś kwoty.

Nie może być tak, że ja w ogóle nie wiem, jak to działa, tylko dostałem tutaj jakieś wzory matematyczne i teraz na końcu się okazuje, że jednak to nie jest to, co miało być.

 

Właśnie, mam wrażenie, że przeszliśmy tutaj do dawania rad, więc to jest pewnie najlepszy moment, żeby zrobić podsumowanie tego, o czym dzisiaj mówiliśmy.

 

Okej, to podsumowując, piszcie kod orientowany obiektowo, a nie tylko kod proceduralny, który wykorzystuje tam gdzieś słowo class i object. Pamiętajcie o tym, żeby enkapsulować, używać dziedziczenia, używać polimorfizmu. Przemyślcie oczywiście, jakie zalety daje Wam w projekcie Object Oriented Programming i starajcie się go wykorzystać w celu poprawienia tych meta wymagań, czyli tego, żeby ten kod był właśnie utrzymywalny, łatwo rozwijalny, żeby był mało podatny na błędy, bo to są właśnie te zalety programowania obiektowego, myślę, które są takie dość unikalne, że właśnie możemy tutaj dużo włożyć swojej energii w to, żeby ten kod był po prostu dla programisty, dla kogoś, kto przyjdzie też po nas tutaj, łatwy do zrozumienia i łatwy właśnie do zmiany.

Pamiętajcie też, że to nie jest złoty młotek, nie jest to jedyny paradygmat programowania i zastanówcie się, czy dla Waszego use case’a, czy to jest ta najlepsza możliwa alternatywa, czy też jest możliwość, żeby zrobić to trochę inaczej, też te języki programowania nowoczesne, pamiętajcie, mają już wbudowane tutaj różne narzędzia, niekoniecznie właśnie obiektowe, ale właśnie elementy programowania np.funkcyjnego.

Czy tutaj jeszcze Krzysztofie chciałbyś coś dodać do tego podsumowania?

Pamiętajcie też, że to nie jest złoty młotek, nie jest to jedyny paradygmat programowania i zastanówcie się, czy dla Waszego use case’a, czy to jest ta najlepsza możliwa alternatywa, czy też jest możliwość, żeby zrobić to trochę inaczej, też te języki programowania nowoczesne, pamiętajcie, mają już wbudowane tutaj różne narzędzia, niekoniecznie właśnie obiektowe, ale właśnie elementy programowania np.funkcyjnego.

 

Tak, ja bym może tylko dodał to, że w tej sztuce tworzenia kodu z wykorzystaniem AOP  trzeba się doskonalić. To nie jest tak, że tylko te podstawowe zasady opanowane dają nam już mandat do tego, żeby cały czas na nich polegać i tworzyć kod z ich wykorzystaniem. Zawsze można coś zrobić lepiej. To, co bym zalecał, to jest też czytanie np. repozytoriów jakichś projektów open source’owych, które są dobrze pod tym względem napisane. To też nam daje taki obraz tego, co jest w ogóle możliwe i jak możemy ten kod poukładać, więc warto z tego źródła się uczyć.

 

Tak że myślę, że temat programowania obiektowego gdzieś tam na dzisiaj wyczerpaliśmy i żeby to tak fajnie tutaj teraz zestawić, w kolejnym tygodniu będziemy rozmawiać o…

 

Właśnie, żeby zbalansować trochę ten obraz paradygmatów języków programowania, to podczas naszego następnego spotkania zerkniemy sobie na programowanie funkcyjne. Postaram się odczarować ten paradygmat, to podejście i pokazać, że niekoniecznie musimy być ekspertami z matematyki abstrakcyjnej, żeby za pomocą programowania funkcyjnego tworzyć kod. Tak że już oczywiście z tego miejsca tutaj serdecznie zapraszamy.

 

Tak że jeśli jesteście ciekawi, co to jest monada, to zapraszamy na przyszły odcinek.

 

Aż tak strasznie nie będzie. Nie trzeba odrabiać zadania domowego. Myślę, że sobie sprawnie przez ten temat przejdziemy.

Dobrze, Łukasz, to co? Ja Tobie bardzo dziękuję. Dziękuję słuchaczom za wysłuchanie tego odcinka o oprogramowaniu obiektowym. Zapraszam oczywiście już na ten kolejne. I zapraszamy na SolidJobs, gdzie możecie znaleźć ogłoszenia o pracę zawsze z widełkami wynagrodzeń i zapraszamy też do dodawania tam ogłoszeń o pracę. Na ten moment bardzo Wam dziękujemy.

Dzięki, Łukasz.

Cześć!

 

Dzięki, Krzysztof. Na razie

+ Pokaż całą transkrypcję
– Schowaj transkrypcję
mm
Krzysztof Kempiński
krzysztof@porozmawiajmyoit.pl

Jestem ekspertem w branży IT, w której działam od 2005 roku. Zawodowo zajmuję się web-developmentem i zarządzaniem działami IT. Dodatkowo prowadzę podcast, kanał na YouTube i blog programistyczny. Moją misją jest inspirowanie ludzi do poszerzania swoich horyzontów poprzez publikowanie wywiadów o trendach, technologiach i zjawiskach występujących w IT.