Sytuacja kobiet w IT w 2024 roku
24.02.20206 min
Joshua Saunders

Joshua SaundersSoftware DeveloperHoppier

Metodologia Depth-First Development

Poznaj metodologię zakładającą podejście “głębiej, nie szerzej” i zobacz, jak może Ci się przydać w codziennej pracy.

Metodologia Depth-First Development

Istnieje szereg metodologii, których można użyć podczas rozwoju oprogramowania, a wiele z nich ma w nazwie “first” i “driven”. Tak więc mamy na przykład test-driven development, mobile-first development, API-first development oraz YOLO-driven development. 

Każda metodologia określa jakiś główny priorytet - coś co kształtuje wszystkie inne priorytety w pewnym momencie rozwoju. 

Test-driven development może być aplikowany na wszystkich poziomach procesu (jeśli chodzi o kodowanie), podczas gdy API-first development jest metodologią makro, opisującą kolejność, w której zespół rozwijający oprogramowanie powinien zająć się zadaniami. Każda z tych metodologii ma jednak swój własny, specyficzny cel.

Metodologie mikro = jak pisać oprogramowanie
Metodologie makro = jak wyznaczyć kolejność zadań przy pisaniu oprogramowania

Chciałbym omówić pewną metodologię makro. Nazwę ją depth-first development i przedstawię jako coś, co spowalnia proces na początku, ale potem znacznie go przyśpiesza. 

Brzmi jak bardzo konkretny przykład użycia, prawda? Być może, ale robienie czegoś po raz pierwszy to bardzo powszechny scenariusz, zwłaszcza w startupach rozwijających oprogramowanie podczas pierwszych lat działalności. 

Pomysł, który zaprezentuję nie jest nowy. Istnieje szansa, że Twój zespół już z niego korzysta! Nazwanie go może go ożywić i pozwoli teamom na korzystanie z niego w codziennej pracy. 

Przykład budowania domów

Przyjmijmy scenariusz, że wszyscy budowniczowie właśnie strajkują, a trzeba wybudować dużo domów. Zakładam, że nikt z Was nigdy domu własnoręcznie nie wybudował. Zadanie to przypada więc niestety Tobie, a pewnie się na tym za bardzo nie znasz (chyba, że tak, to wtedy kudos). 

Zamiast wylewać fundamenty, stawiać ściany i pokryć to wszystko dachem, skorzystaj z metody depth-first, która prezentuje się tutaj następująco:

  1. Wylej kawałek fundamentu
  2. Postaw jedną ścianę i zmodyfikuj fundament, jeśli to konieczne
  3. Postaw następną ścianę w taki sam sposób
  4. Oceń proces stawiania ścian i zanotuj, co udało Ci się w nim poprawić
  5. Postaw resztę ścian
  6. Pokryj to wszystko dachem
  7. Wylej fundament pod następny dom
  8. Oceń proces wylewania fundamentu i zanotuj, co udało Ci się poprawić
  9. Postaw ściany w drugim domu
  10. Pokryj drugi dom dachem
  11. Oceń proces pokrywania dachem i zanotuj, co udało Ci się poprawić
  12. Wybuduj następny dom w taki sam sposób
  13. Oceń cały proces budowy trzeciego domu i zanotuj, co udało się poprawić
  14. Wybuduj wszystkie następne domy w taki sposób


Jest w tym kilka kluczowych punktów:

  1. Nie spędzaj za dużo czasu na jednym etapie- o wiele więcej nauczysz się o jakimkolwiek pierwszym kroku, jeśli spojrzysz na niego z perspektywy drugiego kroku. To o wiele lepsze niż powtarzanie pierwszego kroku, aż dobrze się go nauczysz i przechodzenie do drugiego dopiero kiedy już coś pojmiesz. I potem okazuje się, że pierwszy krok został wykonany źle. 
  2. Bądź bardzo krytyczny, robiąc drugą iterację. Jak robisz coś po raz pierwszy, zawsze wkraczasz na nieznane terytorium. Kiedy już coś powtarzasz, to masz więcej danych, których możesz użyć, żeby nakreślić wymagania dla przyszłych powtórzeń. 
  3. Pierwsze i drugie powtórzenie zazwyczaj idzie wolno, ale wszystko powyżej trzeciego już mocno przyspiesza. Zwolnij trochę przy dwóch pierwszych powtórzeniach i zbierz tego plony przy następnych.


Oto podejście generalizujące: 

  1. Zbuduj pierwszą część komponentu
  2. Zbuduj jego zależności
  3. Oceń interakcje między nimi i wprowadź poprawki tam, gdzie trzeba
  4. Stwórz drugą część komponentu w taki sam sposób, w jaki stworzyłeś pierwszy
  5. Oceń doświadczenie tworzenia komponentu w pierwszym przypadku i wprowadź poprawki tam gdzie trzeba
  6. Stwórz wszystkie części danego komponentu w taki sposób.

Pierwsze, drugie i dalsze iteracje z punktu widzenia programisty

Jeśli zajmujecie się czymś szerokim używając schematu, który przyjęliście po raz pierwszy (na przykład, pisząc drugi punkt końcowy, albo drugi komponent), oceń swoje doświadczenie z programowania: 

  • Czy było ciężko?
  • Czy kod jest niechlujny albo zbyt rozwleczony?
  • Czy musiałem coś powtórzyć z pierwszej iteracji?
  • Jeśli ten schemat miałby być powtarzany w nieskończoność, czy byłbym z niego niezadowolony? 


Jeżeli odpowiedzieliście twierdząco na którekolwiek z powyższych pytań, będzie Wam łatwiej się teraz zatrzymać i dokonać małych zmian niż kiedy baza kodu jest już pokaźnych rozmiarów i restrukturyzacja może wiele kosztować

Jest to szczególnie ważne dla mniejszych zespołów! Im mniejszy zespół, tym większy koszt wprowadzania poprawek, kiedy można to było zrobić wcześniej.

Kiedy to zastosujecie, dalsza praca pójdzie bardzo szybko. 

Wady

Żadna metoda nie pozostaje bez wad. Główna krytyka takiego podejścia opiera się na spowolnieniu procesu na początku, a w tym momencie startupy muszą poruszać się niezwykle szybko, a nie robić coś kosztem czegoś innego. Nie ma również na początku zbyt dużo materiału do przeanalizowania, bo nowe treści pojawiają się kiedy powtórzenia etapów 1 i 2 są ukończone. Ok, rozumiem. 

Jednak polemizowałbym ze stwierdzeniem, że spowolnienie procesu polega na poruszaniu się wolno - wszystko zależy od kontekstu.

Ktoś, kto jest w stanie przebiec 100 metrów w 9 sekund jest niesamowicie szybki, ale jeśli wyścig ma 10000 metrów, ten wynik niewiele znaczy, jeśli biegacz straci szybko siły i będzie biegł resztę wyścigu w bardzo wolnym tempie

Takie podejście zdecydowanie dużo kosztuje na początku, ale procentuje w środku szybkich projektów i na dłuższą metę. 

Krótkie przykłady

  • Masz do napisania dużo komponentów w React? Zastanów się nad tym, jak chcesz zrobić animacje dla jednego z nich przed napisaniem następnego. 
  • Piszesz aplikację front-endową? Zastanów się nad internacjonalizacją i skrótami klawiszowymi na jednej stronie, zanim zaczniesz pisać następną. 
  • Piszesz GET-LIST RESTful API? Zastanów się, jak chcesz poradzić sobie z paginacją i sortowaniem na jednym punkcie końcowym zanim zaczniesz pisać następny endpoint. 

Podsumowanie

To bardzo efektywna strategia na usprawnianie złożonych projektów i jest ona szczególnie istotna dla mniejszych zespołów, które nie mogą sobie pozwolić na poważne błędy. 

Nie zawsze jest to jednak dobre podejście, szczególnie, gdy potrzeba na początku dużych postępów. Jeśli jesteś jednak w stanie pogodzić się z tą metodologią, Twój zespół będzie w stanie wykonać fundamentalną pracę od razu.

Poniżej znajduje się pełniejszy przykład, w którym przedstawione jest działanie metody na przykładzie startupu. Przykład ten dokładniej omawia powyższe zasady.

Metoda: przykład rozwoju oprogramowania 

Załóżmy, że pracujesz w małym startupie w pierwszym dniu pisania kodu. Twój startup rozwija platformę do dostarczania hummusu - coś na zasadzie Uber Eats, czy SkipTheDishes, ale bardziej sfokusowane. 

Żeby zachować zwięzłość, powiedzmy, że obiektem w systemie są użytkownicy, zamówienia i restauracje, a poniżej znajduje się lista zadań do wykonania: 

  • back-end: konfiguracja bazy danych, usług (uwierzytelnienie, trwałość i tak dalej), RESTful API (bez GraphQL)
  • front-end: aplikacja webowa React
  • deployment: CI/CD


Istnieje szereg rozwiązań na przejście z dnia zero do skończonego produktu:

  • Oddzielne zespoły zajmują się back-endem i front-endem równolegle, a wdrożenie odbywa się po skończeniu przydzielonych zadań
  • Wszystkie zespoły pracują na back-endzie, potem nad front-endem i deploymentem równolegle
  • Wszystkie zespoły pracują równolegle


Metoda depth-first development działałaby tutaj w następujący sposób:

  1. Spraw by back-end zaczął działać
  2. Zaimplementuj ciągłą integrację
  3. Zaimplementuj ciągłe wdrażanie
  4. Wprowadź do systemu jeden obiekt (na przykład, restauracje)
  5. Napisz endpoint GET-LIST, włączając walidację
  6. Odpowiednio wyeksponuje API w artefakcie, który zdeploy'ujesz
  7. Napisz testy API i uruchom je podczas ciągłej integracji
  8. Uruchom front-end
  9. Napisz komponent, który wyświetla dane restauracji przy pomocy endpointu GET-LIST 
  10. Napisz testy integracyjne dla tego komponentu i uruchom je podczas ciągłej integracji
  11. Powtórz kroki 5-10 dla POST, PUT i DELETE i nanieś poprawki, jeśli takowe są potrzebne
  12. Powtarzaj kroki 4-11 dla innych obiektów w systemie i wprowadź poprawki tam gdzie trzeba


Zapewne widzisz, że moglibyśmy po prostu przejść na przełaj (np. zaczynając pisać POST endpoint po punkcie końcowym GET w kroku 5), zamiast tego, szliśmy jednak głębiej.  

Użyteczność takiej metody polega na tym, że solidny schemat na radzenie sobie z taskami pojawi się, gdy podejdziemy do projektu “pionowo”, a nie “na szerokość”. 

Na przykład, pisanie komponentu, który używa API w kroku 9 mogło spowodować, że uświadomiliście sobie potrzebę mechanizmu podczas walidacji, którego nie potrzebowaliście około kroku 5. W sytuacji gdy napisalibyście wszystkie punkty końcowe API podczas kroku 5 to w momencie pisania komponentów w kroku 9, zamiast poprawiać tylko jeden z nich, musielibyście poprawić je wszystkie. 

<p>Loading...</p>