Jak radzisz sobie z kodowaniem integrującym z wielu gałęzi / programistów podczas każdego sprintu?

42

Właśnie dostałem telefon retro, w którym programiści wyrazili zaniepokojenie integracją swoich historii w głównej gałęzi każdego sprintu. Wszyscy programiści kodują we własnej gałęzi i pod koniec sprintu łączą się w jedną gałąź główną.

Następnie jeden programista (zwykle ten sam) ma za zadanie upewnić się, że wszystko dobrze zintegrowało się z kodem innego dewelopera (większość zmian znajduje się na tej samej stronie. Na przykład historia wyświetlania danych, historia filtrowania danych i wskaźnik SLA).

Jak możemy zmniejszyć to obciążenie i ułatwić scalanie naszego kodu? Z mojego punktu widzenia posiadanie przez PO lub SM priorytetów w opowieściach w bardziej efektywny sposób, abyśmy nie mieli tego rodzaju zależności w tym samym sprincie, może rozwiązać niektóre problemy. Jak wszyscy inni sobie z tym radzą? Czy to tylko część procesu?

krajacz ciastek
źródło
18
Nie masz działu rozwoju, w którym odbywa się ciągła integracja?
Kayaman
13
Jestem tutaj z Kayamanem, najlepszą praktyką jest wdrażanie ciągłej integracji.
RandomUs1r
27
Happy Merge Day! Za każdym razem, gdy Twój problem jest zbyt podobny do czegoś w The Daily WTF, wiesz, że masz kłopoty.
user3067860,
Scalaj wcześnie, scalaj często: {napisz najmniejszy kod testowy, który zawiedzie (czerwony), napisz najmniejszy kod produkcyjny, który przejdzie (zielony), refaktoryzuj, ponownie przetestuj, scal}} gdy nie jest skończony.
ctrl-alt-delor
1
Pierwsze zameldowanie Wygrywa! Nigdy nie bądź ostatni! :-)
ChuckCottrill

Odpowiedzi:

88

Jeśli korzystasz z Git, każdy programista ciągnie z developgałęzi do własnej gałęzi funkcji , aby upewnić się, że nie odejdą zbyt daleko od bieżącej linii bazowej. Mogą to robić codziennie, dzięki czemu zadania, które trwają dłużej niż kilka dni, pozostają zsynchronizowane i łączą problemy, gdy są jeszcze małe.

Gdy programista zakończy pracę, tworzy żądanie ściągnięcia . Po zatwierdzeniu zostanie on scalony z developoddziałem.

developOddział powinien zawsze mieć kod działa, i być gotowy do wydania w dowolnym momencie. Kiedy faktycznie tworzysz wydanie, łączysz developsię masteri otaczasz je.

Jeśli masz dobry serwer Continuous Integration Server, zbuduje on każdą gałąź po wpisaniu zmian - szczególnie w przypadku żądań ściągania. Niektóre serwery kompilacji integrują się z serwerem Git, aby automatycznie zatwierdzać lub odrzucać żądanie ściągnięcia, jeśli kompilacja się nie powiedzie lub testy automatyczne nie powiodą się. To kolejny sposób na znalezienie potencjalnych błędów integracyjnych.

Berin Loritsch
źródło
73
Ważną częścią (co sugeruje tylko twoja odpowiedź) jest to, że gałęzie powinny zostać połączone, gdy tylko będą gotowe, zwykle z tylko 1–5 zatwierdzeniami, a nie tylko na końcu sprintu. Jedna gałąź na funkcję / historię, a nie jedna gałąź na programistę. Wymaga to, aby historie były naprawdę małe, tzn. Trwały najwyżej dwa dni.
amon
@amon, zgodził się. Dodano słowa „gałąź funkcji”, ale staram się, aby odpowiedź była dość mała. Istnieje wiele dobrych artykułów, które pogłębiają ten proces.
Berin Loritsch
5
Nie bądź odizolowany od swojego oddziału. Tak zaczyna się piekło scalania. Korzystaj z programowania głównego, izoluj trwające prace za przełącznikami funkcji lub inną konfiguracją w czasie wykonywania.
Rob Crawford
3
@Zibbobz Mój zespół używa wyraźnych „gałęzi funkcji” dla tych, które są zasadniczo traktowane tak, jak gałąź rozwoju, ale tylko dla żądań ściągania i zatwierdzeń związanych z tą zmianą. Zasadniczo, w zależności od tego, jak długo musi pozostać osobno, co kilka dni ktoś scali zmiany z rozwijania do funkcji i rozwiązuje wszelkie problemy. W ten sposób gałęzie są jak najbardziej podobne, gdy nadchodzi czas połączenia. Uwaga: to tylko dla naprawdę dużych przełomowych zmian
reffu
9
„izoluj pracę w toku za przełączaniem funkcji lub inną konfiguracją w czasie wykonywania” Właśnie uniknąłeś scalenia piekła, przechodząc do konfiguracji piekła. „Scal piekło” jest tylko problemem dla jednego programisty naraz i można go łatwo ominąć przez regularną synchronizację, a ton efemerycznej konfiguracji jest piekłem dla wszystkich przyszłych programistów na zawsze.
Cubic
23

Pracowałem w zespole, w którym zmagaliśmy się z tym samym problemem. Odkryliśmy, że im mniej czasu mieliśmy na integrację, tym trudniej było. Wiem, że większość osób uczących ciągłej integracji mówi o angażowaniu się co kilka minut - prawdopodobnie faktycznie poświęcaliśmy się co godzinę.

Odkryliśmy również, że sam budynek to za mało. Potrzebowaliśmy dobrego poziomu pokrycia testowego, aby upewnić się, że nie złamaliśmy sobie nawzajem kodu.

Daniel
źródło
2
To też jest moje doświadczenie. Naprawdę nie ma znaczenia, jak często się popełniasz, ale po popełnieniu szybka integracja / scalenie zatwierdzenia oszczędza wiele wysiłku. Kiedyś byłem przy projekcie, w którym mieliśmy trzy różne gałęzie rozwoju, z których każda miała miesiące pracy. Łączenie ich nie było zabawne. Wiele się nauczyłem od tego błędu :)
amon
4
Tak - to właśnie oznacza „ciągła integracja”! Ciągle integrujesz swoje zmiany ze zmianami innych programistów!
Rob Crawford
@Rob, zgodził się. Moje oświadczenie nie miało sugerować, że ciągła integracja nie jest, no cóż, ciągła. Tyle, że nie do końca stworzyliśmy ideał i wciąż widzieliśmy wiele korzyści z jego zbliżenia.
Daniel
12
  • Niech twoje oddziały będą krótkotrwałe (wygląda na to, że już to robisz).
  • Niech twoje wyniki testu mówią same za siebie.
  • Nie czekaj na koniec sprintu.

Nie musisz nawet subskrybować TDD dla tego. Wystarczy kilka testów, które dowodzą, że funkcje programistów działają poprawnie. Mogą to być testy jednostkowe i testy integracyjne, ale idealnie będzie to kilka zautomatyzowanych kompleksowych testów kluczowych funkcji. Standardowy pakiet regresji.

Następnie, po zakończeniu scalania, możesz sprawdzić razem raport z testu automatyzacji i sprawdzić, czy wszystko zostało pomyślnie zintegrowane.

Zgadzam się z jedną z pozostałych odpowiedzi, w których autor stwierdził, że Git PRs rozwiąże ten problem, zmuszając każdego programistę do scalenia własnej pracy.

Jeszcze jedna kwestia, która moim zdaniem jest wystarczająco ważna, aby odejść do ostatniego akapitu. Sugeruję, abyś przeprowadzał testy ręczne w swoich nocnych kompilacjach, zamiast czekać do końca sprintu. Programiści powinni połączyć się, gdy tylko funkcja zostanie ukończona, aby można ją było jak najszybciej zintegrować, wdrożyć i przetestować.

Liath
źródło
6

Nie rób

W zależności od języka i edytowanych plików edytowanie ich we własnym oddziale może nie mieć sensu. Na przykład w C # stwierdziłem, że najlepiej jest, aby tylko jedna osoba mogła edytować dowolne pliki projektanta interfejsu użytkownika na raz. Są to pliki generowane automatycznie, więc kod jest czasami przenoszony bez wyraźnego powodu - i powoduje to spustoszenie w większości narzędzi do łączenia.

Oznacza to, że niektóre historie mogą blokować inne historie, dopóki interfejs użytkownika nie zostanie zakończony. I / lub tworzona jest nowa historia, aby po prostu ułożyć interfejs użytkownika, a inne historie implementują funkcjonalność. Lub może jeden programista wykonuje cały interfejs użytkownika, podczas gdy inni implementują jego funkcjonalność.

W powiązanej notatce, jeśli wiesz, że wiele historii będzie dotykać tego samego pliku (plików), możesz po prostu uniknąć pracy nad nimi wszystkimi w tym samym czasie. Nie wciągaj ich wszystkich w ten sam sprint, ani nie zaczynaj z nimi wszystkimi, dopóki nie skończysz jednego lub więcej.

mmathis
źródło
Szczerze mówiąc, używane narzędzie kontroli wersji ma większe znaczenie dla udanego rozgałęzienia i scalenia. Nawet z kodem C # i przypuszczalnie kodem WinForms lub WebForms, z którym musisz pracować, zazwyczaj nie zmieniasz zbyt wiele . Jeśli tak, być może musisz zrobić kilka makiet, zanim zaczniesz grać z kodem. Interfejsy użytkownika oparte na XAML są tak samo stabilne, jak zwykły kod, a kod pośredni nie jest rejestrowany.
Berin Loritsch
2
@BerinLoritsch Kod projektanta WinForms może naprawdę wiele zmienić, nawet przy niewielkich zmianach wizualnych. Przekonałem się, że same wiersze kodu są takie same, ale kolejność jest zupełnie inna - szczególnie, gdy wielu programistów dokonuje edycji w tym samym czasie. Być może jest to problem z narzędziem VCS (użyliśmy kilku, może po prostu używamy niewłaściwych), ale dla nas znacznie łatwiej jest nieco zmienić nasz proces.
mmathis
2
@BerinLoritsch Muszę tu powtórzyć mmathi przynajmniej w przypadku wygranych (nigdy nie używanych formularzy internetowych). Projektant interfejsu użytkownika winforms uwielbia losowe porządkowanie całego kodu w pliku projektanta w odpowiedzi na trywialną zmianę gdzieś w formularzu. O ile nie cofniesz ręcznie zmiany kolejności przed każdym zatwierdzeniem (coś, co może mieć 10 lub 15 minut w złożonym formularzu), historia pliku projektanta jest absolutnie bezużyteczna, a jeśli 2 osoby jednocześnie pracują nad interfejsem formularza konflikt scalania z piekła rodem. Blokowanie jest na ogół okropną opcją, ale z formami win naprawdę jest najmniejsze zło.
Dan Neely
@ DanNeely, to tylko jeden z powodów, dla których nasz zespół przeprowadził migrację z kodu WinForms. Innym powodem jest to, że projektant jest wyjątkowo delikatny, a niektóre z naszych złożonych form i tak nie mogły być edytowane wizualnie. Skończyło się na tym, że musieliśmy wprowadzać zmiany bezpośrednio w świecie kodowym - prawdopodobnie dlatego nie pamiętam tam zbyt wielkiego wstrząsu. To i nasi użytkownicy pracujący z wyświetlaczami o dużej gęstości naprawdę popchnęli nas do WPF. Bolesny proces z wysoką krzywą uczenia się, ale na końcu fajną nagrodą. Zresztą większość historii zaległości dotyczyła różnych części aplikacji.
Berin Loritsch
@BerinLoritsch to samo tutaj. Zwycięskie formularze opłacały dużą część moich rachunków przez większą dekadę podczas mojej poprzedniej pracy, ale będę szczęśliwy, że nigdy więcej ich nie dotknę w przyszłości.
Dan Neely
2

Innym możliwym sposobem uniknięcia późnych i dużych scaleń są flagi funkcji : chronisz swoje zmiany za pomocą (idealnie dynamicznie) konfigurowalnej flagi, która zapobiega ich aktywacji przed zamierzonym.

Dzięki temu możesz wcześnie połączyć swoje zmiany z jednym masterz oddziałów wspólnego rozwoju, nie przerywając niczego. Inni programiści mogą następnie scalić te zmiany z powrotem w swoich gałęziach funkcji (lub odpowiednio zmienić ich podstawy).

Jak już wskazały inne odpowiedzi, należy to połączyć z rozwiązaniem ciągłej integracji.

Flagi cech mają dodatkowe zalety (na przykład ułatwiają przeprowadzanie testów A / B). Więcej informacji można znaleźć w tym artykule Martina Fowlera .

Florian Brucker
źródło
0

Podążamy za podejściem oddzielnej gałęzi programistycznej dla każdej funkcji, a następnie łączymy gałęzie z gałęzią kontroli jakości w celu przetestowania w środowisku testowym integracji.

Po zakończeniu testów regresji i integracji łatwo przenosimy funkcje, które są gotowe do pracy, do działu wydania.

Jeśli wszystko pójdzie dobrze, łączymy gałąź wydania z gałęzią główną.

emarshah
źródło
0

Mówiąc prościej, zatwierdzanie i łączenie często zmniejsza okno możliwości łączenia konfliktów i znacznie zmniejsza konflikty. Druga część jest rzeczywiście planowana przez lidera, co może dodatkowo zapewnić płynność prac.

Inne odpowiedzi dają świetny wgląd w najlepsze praktyki dotyczące zatwierdzeń, a po prostu przestrzegając tych, prawdopodobnie zmniejszysz znaczną większość problemów z scalaniem. Więcej połączeń jest prawie na pewno koniecznością, ale w mniejszym zespole podejście oparte na oddziałach na osobę prawdopodobnie działa wystarczająco dobrze. Oczywiście nie zaszkodzi (wiele) wejść w bardziej rozszerzalne praktyki!

Wydaje się jednak, że nikt nie odpowiedział na jedno z najważniejszych pytań - co zrobić, gdy wszyscy dotykają tych samych obszarów kodu. W tym miejscu warto mieć lead, który zna podstawy kodu i rozpoznaje zależności różnych zadań. Jeśli nie ustalą harmonogramu pracy i zatwierdzeń, najprawdopodobniej skończysz z konfliktami scalania i rozdzielczością linia po linii. Zorganizowanie harmonogramu zadań jest znacznie trudniejsze w większym zespole, ale w małym zespole możliwe jest zidentyfikowanie tych sprzecznych zadań. Kierownik może wówczas nawet przenieść wszystkie powiązane zadania do tego samego inżyniera, aby całkowicie uniknąć konfliktu.

Mars
źródło