Tłumaczenie artykułu przygotowane dla studentów kursu w projekcie edukacyjnym OTUS.
Musisz wybrać monorepo, ponieważ zachowanie, które ono wspiera w twoich zespołach – to przejrzystość i wspólna odpowiedzialność, szczególnie przy wzroście zespołów. W każdym razie będziesz musiał zainwestować w narzędzia, ale zawsze lepiej, gdy zachowaniem domyślnym jest to, które chcesz widzieć w swoich zespołach.
Dlaczego o tym mówimy?
Matt Klein napisał artykuł (przyp. tłumacza: tłumaczenie na habrze ). Lubię Matta, myślę, że jest bardzo mądry i powinieneś przeczytać jego punkt widzenia. Początkowo opublikował ankietę na Twitterze:
Tłumaczenie:
W ten noworoczny dzień zamierzam założyć, jak absurdalne są monorepo. Rok 2019 rozpoczął się niezauważalnie. W tym duchu proponuję ci ankietę. Kto jest największym fanatykiem? Zwolennicy:
— Monorepo
— Rust
— Błędna ankieta / obaj
Moja odpowiedź brzmiała: „Jestem dosłownie obie te osoby”. Zamiast mówić o tym, jak Rust to narkotyk, przyjrzyjmy się, dlaczego myślę, że się myli w sprawie monorepo. Trochę o sobie. Jestem dyrektorem technicznym w Chef Software. Mamy około 100 inżynierów, bazę kodu liczącą około 11-12 lat i 4 główne produkty. Część tego kodu znajduje się w polirepo (moja początkowa pozycja), część w monorepo (moje obecne stanowisko).
Zanim zacznę: każdy argument, który tu przedstawiam, będzie dotyczył obydwu typów repozytoriów. Moim zdaniem nie ma żadnych technicznych powodów, dla których powinieneś wybrać jeden lub drugi typ repozytorium. Możesz sprawić, że jakiekolwiek podejście zadziała. Chętnie o tym porozmawiam, ale nie interesują mnie sztuczne techniczne powody, dla których jedno jest lepsze od drugiego.
Zgadzam się z pierwszą częścią punktu widzenia Matta:
Ponieważ w dużej skali monorepo będzie rozwiązywać te same problemy, które rozwiązuje polirepo, jednocześnie prowokując cię do silniejszej spójności twojego kodu i wymagając niewiarygodnych wysiłków w zakresie zwiększania skalowalności twojego systemu kontroli wersji.
Będziesz musiał zmierzyć się z takimi samymi problemami, niezależnie od tego, czy wybierzesz monorepo, czy polirepo. Jak wydajesz wersje? Jakie masz podejście do aktualizacji? Wsteczna kompatybilność? Wzajemne zależności projektów? Jakie style architektury są akceptowalne? Jak zarządzasz swoją infrastrukturą budowania i testowania? Lista jest nieskończona. I będziesz rozwiązywać je wszystkie w miarę rozwoju. Nic nie ma za darmo.
Uważam, że argumentacja Matta odzwierciedla poglądy wielu inżynierów (i menedżerów), których szanuję. Wynika to z perspektywy inżyniera pracującego nad komponentem lub zespołu pracującego nad komponentem. Słyszy się takie rzeczy jak:
- Baza kodu jest przytłaczająca - nie potrzebuję całego tego bałaganu.
- Trudniej to testować, ponieważ muszę sprawdzić cały ten bałagan, który nie jest mi potrzebny.
- Trudniej jest pracować z zewnętrznymi zależnościami.
- Potrzebuję swoich własnych systemów zarządzania wersjami.
Z pewnością wszystkie te punkty są uzasadnione. Dotyczy to obu przypadków — w polirepo mam swój bałagan, oprócz tego, który potrzebny jest do budowy... Mogę potrzebować jeszcze więcej bałaganu. Dlatego po prostu tworzę narzędzia, które wykonują checkout całego projektu. Albo tworzę fałszywe monorepo z submodułami. Moglibyśmy o tym rozmawiać cały dzień. Ale myślę, że argument Matta pomija główny powód, za którym silnie opowiadam się za monorepo:
Wzbudza to komunikację i ujawnia problemy.
Kiedy dzielimy repozytoria, de facto tworzymy problem z koordynacją i przejrzystością. Odpowiada to temu, jak myślimy o zespołach (szczególnie temu, jak myślą o nich poszczególni członkowie): ponosimy odpowiedzialność za określony komponent. Pracujemy w stosunkowej izolacji. Granice są ustalane na moim zespole i komponentach, nad którymi pracujemy.
W miarę komplikacji architektury jedna drużyna nie może już sama nią zarządzać. Bardzo niewielu inżynierów ma cały system w głowie. Załóżmy, że zarządzasz wspólnym komponentem A, który jest używany przez zespoły B, C i D. Zespół A przeprowadza refaktoryzację, ulepsza API, a także zmienia wewnętrzną implementację. W rezultacie zmiany nie są wstecznie kompatybilne. Jaką radę byś dał?
- Znajdź wszystkie miejsca, w których używane jest stare API.
- Czy są miejsca, w których nowe API nie może być używane?
- Czy możesz poprawić i przetestować inne komponenty, aby upewnić się, że nie ulegną awarii?
- Czy te zespoły mogą sprawdzić twoje zmiany teraz?
Zauważ, że te pytania nie zależą od typu repozytorium. Będziesz musiał znaleźć zespoły B, C i D. Musisz z nimi porozmawiać, ustalić czas, zrozumieć ich priorytety. Przynajmniej mamy nadzieję, że to zrobisz.
Tak naprawdę nikt nie chce się tym zająć. To znacznie mniej ekscytujące niż po prostu naprawienie cholernie API. To wszystko jest ludzkie i skomplikowane. W repozytorium polimorficznym możesz po prostu wprowadzać zmiany, poddać to przeglądowi tym, którzy pracują nad tym komponentem (prawdopodobnie nie B, C ani D), i iść dalej. Zespoły B, C i D mogą na razie pozostać przy swojej aktualnej wersji. Zaktualizują się, gdy zdobędą twoją genialność!
W monorepozytorium odpowiedzialność przesuwa się domyślnie. Zespół A zmienia swój komponent i, jeśli nie zachowa ostrożności, natychmiast łamie B, C i D. To prowadzi do sytuacji, w której B, C i D pojawiają się u drzwi A, zastanawiając się, dlaczego zespół A złamał budowę. To uczy A, że nie mogą pominąć mojej listy powyżej. Muszą rozmawiać o tym, co zamierzają zrobić. Czy B, C i D mogą działać? Co jeśli B i C mogą, ale D było ściśle związane z efektem ubocznym zachowania starego algorytmu?
Następnie musimy porozmawiać o tym, jak wyjść z tej sytuacji:
- Wsparcie wielu wewnętrznych API, przy czym stary algorytm będzie oznaczony jako przestarzały, dopóki D nie będzie mogło przestać go używać.
- Wsparcie wielu wersji wydań, jedna ze starym interfejsem, jedna z nowym.
- Opóźnienie wydania zmian A, dopóki jednocześnie B, C i D nie będą mogły ich zaakceptować.
Załóżmy, że wybraliśmy 1, kilka interfejsów API. W takim przypadku mamy dwa kawałki kodu. Stary i nowy. Dość wygodne w niektórych sytuacjach. Przywracamy stary kod, oznaczamy go jako przestarzały (deprecated) i uzgadniamy harmonogram jego usunięcia z zespołem D. Zasadniczo jest to identyczne zarówno dla poli, jak i dla monorepozytoriów.
Do wydania kilku wersji potrzebujemy gałęzi. Teraz mamy dwa komponenty — A1 i A2. Zespoły B i C korzystają z A2, a D z A1. Musimy upewnić się, że każdy komponent jest gotowy do wydania, ponieważ zanim D będzie mogło pójść dalej, mogą być wymagane aktualizacje zabezpieczeń i poprawki błędów. W poli-repozytorium możemy to ukryć w długożyjącej gałęzi, która czuje się dobrze. W monorepozytorium wymuszamy tworzenie kodu w nowym module. Zespół D wciąż będzie musiał wprowadzić zmiany w "starym" komponencie. Każdy może zobaczyć koszty, które tutaj ponosimy — mamy teraz dwa razy więcej kodu, a wszelkie poprawki błędów, które są stosowane do A1 i A2, muszą być stosowane do obu. Przy podejściu z użyciem gałęzi w poli-repozytorium jest to ukryte za cherry-pick. Uważamy koszt za mniejszy, ponieważ nie ma tam dublowania. Z praktycznego punktu widzenia, koszt jest taki sam: będziesz tworzyć, wydawać i utrzymywać dwa zasadniczo identyczne bazy kodu, dopóki nie będziesz mógł usunąć jednego z nich. Różnica polega na tym, że w monorepozytorium ten ból jest bezpośredni i widoczny. To jeszcze gorsze, a to dobrze.
W końcu dotarliśmy do trzeciego punktu. Opóźnienie w wydaniu. Możliwe, że zmiany wprowadzone przez zespół A poprawią życie zespołu A. Ważne, ale nie pilne. Czy możemy po prostu to opóźnić? W monorepozytorium popychamy to do ustalenia artefaktu. Oczywiście mówimy o tym z zespołem D. Po prostu pozostańcie przy starej wersji, aż nadrobicie! To sprawia, że gra się w strach. Zespół A ciągle pracuje nad swoim komponentem, ignorując fakt, że zespół D używa coraz bardziej przestarzałej wersji (to problem zespołu D, są głupi). W międzyczasie zespół D źle się wypowiada o lekkomyślnym podejściu zespołu A do stabilności kodu, jeśli w ogóle o tym mówią. Mijają miesiące. W końcu zespół D postanawia spojrzeć na możliwość aktualizacji, ale zmian w A tylko przybywa. Zespół A ledwo pamięta, kiedy i jak złamali D. Aktualizacja jest bardziej bolesna i zajmie więcej czasu. Co przesuwa to dalej w dół listy priorytetów. Do momentu, gdy pojawi się problem z bezpieczeństwem w A, co zmusza nas do utworzenia gałęzi. Zespół A musi cofnąć się w czasie, znaleźć moment, w którym D było stabilne, naprawić problem i przygotować je do wydania. To de facto wybór, który ludzie robią, i z pewnością jest to najgorsze. Wydaje się, że to dobrze zarówno dla zespołu A, jak i D, dopóki możemy ignorować się nawzajem.
W monorepozytorium trzeci — naprawdę nie jest opcją. Musicie radzić sobie z sytuacją na jeden z dwóch sposobów. Musicie widzieć koszty posiadania dwóch gałęzi wydania. Nauczyć się chronić przed aktualizacjami, które łamią zgodność wsteczną. Ale najważniejsze: nie unikniesz trudnej rozmowy.
Z mojego doświadczenia, gdy zespoły stają się duże, nie ma już możliwości śledzenia całego systemu, i to jest najważniejsza część. Musisz poprawić widoczność rozbieżności w systemie. Musisz aktywnie pracować, aby skłonić zespoły do oderwania wzroku od swoich komponentów i spojrzenia na pracę innych zespołów i użytkowników.
Tak, możesz stworzyć narzędzia, które spróbują rozwiązać problem polirepozytoriów. Jednak moje doświadczenie w zakresie ciągłej dostawy i automatyzacji w dużych przedsiębiorstwach mówi mi jedno: domyślne zachowanie, bez użycia dodatkowych narzędzi, to właśnie to, czego możesz się spodziewać. Domyślne zachowanie polirepozytoriów to izolacja, to jest cały sens. Domyślne zachowanie monorepozytoriów to wspólna odpowiedzialność i przezroczystość, to jest cały sens. W obu przypadkach zamierzam stworzyć narzędzie, które pozwoli wygładzić ostre krawędzie. Jako lider wybiorę monorepozytorium za każdym razem, ponieważ narzędzia powinny wzmacniać kulturę, którą pragnę, a kultura wynika z drobnych decyzji i codziennej pracy zespołu.
Tylko zarejestrowani użytkownicy mogą brać udział w ankiecie. , proszę.
Kto jest większym fanatykiem? Zwolennicy:
Monorepo
Rust
Błędna ankieta / obaj
33 użytkowników zagłosowało. 13 użytkowników wstrzymało się od głosu.
Źródło: habr.com
