logo

#adventdevstories v2020

Kwiecień i maj 2020 to dla mnie czas spędzony z Instagramem oraz inicjatywą #30devstories, gdzie poznałem mnóstwo świetnych ludzi (nie tylko programistów), którzy dzielili się wiedzą na Instagram stories i w prywatnych wiadomościach.

Było na tyle fajnie, że chłopaki z DevEnv postanowili powtórzyć akcję i zorganizowali #adventdevstories, do którego się podczepiłem.

Ostatnio mocno mnie wykończyło te 30-dniowe nagrywanie, więc tym razem wprowadzam sobie kilka zasad:

  • Będzie ultra szybko i konkretnie
  • Maksymalny czas trwania story to 2 minuty, czyli 8 takich piętnastosekundowych stories
  • Notatki z każdego DevStories znajdziecie w tym wpisie (albo inline, albo w postaci linka do osobnego wpisu)

Jest kilka plusów takiego rozwiązania:

  • Oszczędność czasu dla dwóch stron (i więcej czasu na stories u innych)
  • Struktura, dzięki której wiecie czego się spodziewać
  • Ja będę miał challenge i będzie ciekawiej
  • Notaki, z których możecie skorzystać w dowolnym czasie, a czytanie jest szybsze niż oglądanie stories

Have fun i zachęcam dołączyć do akcji 💪.

Notatki poniżej.

1. Jak debugujesz? Na co zwrócić uwagę?

Na początku używałem debuggerów, ale mają kilka problemów:

  • Potrafią przeskakiwać po breakpointach nie w taki sposób jak bym chciał
  • Czasem ciężko wrócić do poprzedniego kroku
  • Ciężko zachować stan zmiennych i tym samym prześledzić, co się działo podczas wykonywania kodu, trzeba odpalić go jeszcze raz
  • Lubię popatrzeć na output aplikacji z lotu ptaka i trochę nad nim pomedytować, to pomaga dostrzec wzory i stwierdzić, co jest nie tak z kodem, a debuggerach jest to utrudnione
  • Debugger to często ciężki, brzydki i skomplikowany kawałek softu (a ja lubie rzeczy lekkie i proste)

Zmieniłem więc podejście:

  • Zacząłem pisać więcej testów i częściej robić TDD
    • Testy to jest najlepszy debugger na świecie
  • Testy są cały czas odpalone i od razu widać output
  • Gdy trzeba coś przedebugować, to wstawiam console.loga
    • W kodzie i w testach
    • Zależy gdzie potrzeba
  • Dzięki temu output testów poprzeplatany jest stanem aplikacji, który wrzuciłem do console.loga
  • Tworzy się stream logów, na który mogę patrzeć z lotu ptaka i nad którym mogę rozmyślać tak długo, jak potrzebuję

Główne zalety:

  • Mam powtarzalne środowisko testowe, za każdym odpaleniem testów lub kodu, widzę ten sam zestaw zmiennych
  • Po dokonaniu zmian, mogę zrobić diffa względem poprzedniego outputu (oczami albo jakimś narzędziem)
  • Mogę przekierowac output do pliku (npm run test > test.log)
  • Łatwo się z takimi logami pracuje, można je pokolorować, dodać słowa kluczowe itp.
  • Ten sam sposób działa idealnie jako metoda debugowania w kontenerze dockerowym i na serwerach
    • Po prostu obserwuję logi
    • Bo podłączenie debuggera jest utrudnione i często niemożliwe
  • Najważniejsze: Przy okazji nauczyłem się jak pisać obserwowalne aplikacje
    • Instynktownie wiem, w których miejscach w produkcyjnej wersji aplikacji będę potrzebował wstawić logger

Mój ulubiony cytat:

“If you’re good at the debugger it means you spent a lot of time debugging. I don’t want you to be good at the debugger.” ~Uncle Bob

Linki:

https://www.geeksforgeeks.org/console-in-javascript/ - bo console to nie tylko log :)

2. CI/CD czy naprawdę tego potrzebujemy?

Glosariusz:

  • CI - Continuous Integration
  • CD - Continuous Delivery (nie Deployment)

Zacznę od CD, Continuous Delivery:

Natomiast CI - czy potrzebujemy?

  • Zadawanie tego pytania, to jest to samo, co pytanie czy potrzebujemy czystego kodu lub testów
  • Jasne, że nie potrzebujemy, ale jest ekstremalnie przydatne
  • I dlatego nie widzę sensu kwestionowania tego tematu
  • Na szczęście, tak jak z kodem i testami, wdrażanie dojrzałego CI to jest proces
  • Na początku nie musi być idealnie i dlatego możemy skupić się na dostarczaniu wartości biznesowej
  • Czasem biznes stwierdzi, że CI to jest ta wartość biznesowa, bo np. inny zespół będzie korzystał z Twojego kodu i potrzebują, żeby to działało
    • Wtedy spędzenie tygodnia na szlifowaniu ma sens
  • A czasem będzie potrzebował, żeby na następnym demo widzieć już UI, nawet zamockowany, bo np. chcą to zobaczyć ludzie, którzy sypią kasą na projekt
  • Bardzo pomaga tutaj myślenie produktowe - czego potrzebują ludzie po drugiej stronie
    • Czy CI jest częścią rozwiąznia? Jeśli tak, to jak dużą?
  • Można zacząć od Chodzącego Szkieletu, czyli minimalnej implementacji, która po prostu odpali testy, albo puści lintera
  • I w miarę jak projekt rośnie, dodawać kolejne ficzerki

Z jakich narzędzi korzystam? Głównie tych wbudowanych w repo:

3. Problemy w pracy z zastanym API

API to dla mnie zestaw funkcji, które dostarcza jakiś moduł:

  • To może być REST
  • To może być libka
  • To może być baza danych

Problemy:

  • API jest paskudne i używamy go, bo nie mamy lepszej opcji
  • API jest odziedziczonym legacy i wyciągnięcie jednej wartości wymaga robienia fikołków np. czterech zapytań do różnych metod zamiast jednego

Dwa rozwiązania:

  • Wrapowanie: zamykanie API w szczelnym pudełku, czyli module lub klasie i zbudowanie własnej abstrakcji, żeby nam się detale implementacyjne wrapowanego API (takie jak encje) nie wylewały po naszej (w założeniu czystej) aplikacji.
  • Zastosowanie Strangler Pattern: wzorzec dusiciela, który polega na odcinaniu tlenu tym modułom, które są paskudne i zastępowaniu ich implementacją, która nam bardziej pasuje. Krok po kroku.

Takie podejście powoduje, że gdy postanowimy pozbyć się zastanego API na rzecz nowego, albo innego (bo sobie klient przypomniał, że przecież ma nową wersję), to musimy przepisać tylko wnętrze pudełka, a cała reszta się nie zmienia.

4. Jak organizować kod by żyło się łatwiej?

Przykłady struktury folderów z tutoriali nie działają w większej skali.

Standardowo tutorialową strukturę, na której opierają się MVP refactoruje się do struktury opartej na ficzerach.

Przykład struktury folderu z tutoriala:

components/
services/
reducers/

Kolejny:

controllers/
models/
routes/

Przy takiej strukturze, gdy projekt rośnie, to musimy robić w głowie dużo mentalnych połączeń, żeby ogarnąć, co gdzie jest i jak się ze sobą łączy.

  • Ja czasem musiałem rysować sobie mapy na kartce, gdy większe projekty korzystały z takiej struktury 🙃
  • Ciężko się z takim czymś pracuje, zwłaszcza początkującym
  • Niektórzy się kłócą, że ta struktura jest ok. Zauważyłem, że to często dlatego, że się przyzwyczaili do crappiness.

W dużych projektach, albo się ktoś w takiej strukturze pogubi, albo zacznie refactorować do jakiejś formy Feature Folderów:

Przykład Feature Folderów:

userSettingsPage/
  actions.js
  api.js
  reducer.js
  selectors.js
profileForm.component.js
userSettingsPage.container.js

Niektórzy proponują taki sposób orgranizacji - http://react-file-structure.surge.sh/.

  • To jest dobra rada, ciągły refactor.
  • Jednak warto wiedzieć, że sposobów na organizację kodu w folderach jest wiele i niekoniecznie trzeba wymyślać koło na nowo przesuwając pliki na yolo.
  • Moje podejście: weź co działa i dostosuj, gdy przestanie.
  • Pliki same zaczynają wskakiwać na swoje miejsce, gdy poznamy i zrozumiemy takie patterny jak DDD czy Clean Architecture.
  • Jest to jednak długi proces. Feature foldery i kolokacja, to najlepsze, proste, niskopoziomowe narzędzia jakie stosuję.
  • I do tego są tech agnostic.

Warto też pamiętać o prawie Conwaya - struktura kodu odzwiercielda strukturę komunikacji:

  • Jest to jedna z najbardziej uniwersalnych prawd z jakimi się spotkałem w IT.
  • Często na podstawie kodu jestem w stanie powiedzieć jak zorganizowany jest zespół, kto się z kim dogaduje, a kto się nie lubi.
  • Najważniejsze jest jednak to, że prawo Conwaya ma praktyczne zastosowanie i jest to heurystyka - jeśli ciężko pracuje Ci się z kodem, to poszukaj problemów komunikacyjnych i je napraw. Sprawdza się 👍.
Podziel się:

Instagram, Twitter, YouTube, Facebook, LinkedIn