Jak przekonac git-flow hejterów w projektach z zewnętrzną baza danych

0

W nowej pracy trafił mi się ciekawy projekt, który został niedawno zmigrowany na githuba.
problem polega na tym, że common practice to jest checkoutowanie lokalnie mastera i pushowanie doń zmian. <cringe>
Przy samym projekcie pracuje z kilkudziesięciu devów rozproszonych po całym świecie.
Cześć dinozaurów oprogromowanie żyją ciągle w SVN-owym mindsecie.

Chciałbym podrajvować ten temat w firmie, bo czemu nie.
myślę, ze to bedzie miało korzyść dla każdego.

ale im bardziej analizuję temat znajdujący się w naszej domenie, tym więcej pytań, a mniej odpowiedzi.

Sprawa polega na tym, że do kazdego releasu jest folder ze skryptami SQLowymi, które roszerzają bazę danych o jakieś columny albo dodają wartości lub procedury. Spotkałem to już w kilku firmach. Codziennie rano baza danych na podstawie sqli z mastera się rekonstruuje.

no i teraz rozkmina, jak mozna to zaimplementować do git-flow, żeby nie było to tak upierdliwe, że zmiany deweloperskie na jednym branchu, a zmiany w bazie danych na drugim i radosne pushowanie do mastera?

bardzo łatwo się rozsynchronizować, a z drugiej strony skypty restorujące sa odpalane poprzez jakiegoś bata, który jest wywołuje po nazwie.

Moim marzeniem byłoby, żeby kazdy miał lokalnie schemat bazy danych, ale niestety przy rozwoju oporogramowania często potrzebne są jakieś dane do pracy, choćby sprzed kilku miesiący z produkcji czy jakieś spreparowane dla DEVów.

2

W sensie chesz pokonać jeden syf innym? Może się nawet uda, ale wtedy nadal będziesz miał syf.

Dlacazego konkretnie skrypty aktualizujące bazę muszą być w masterze, a nie w feature branchu?

4

Git flow to zło w czystej postaci, ale "feature brancze" to nie jest git-flow. Git flow wprowadza zdecydowanie więcej zbędnego syfu, który IMHO tylko zaciemnia widok.

To czego szukasz to się nazywa manager migracji i jest tego całkiem sporo dostępnego.

1

Codziennie rano baza danych na podstawie sqli z mastera się rekonstruuje.

Gdzie jest ta baza? I to znaczy, że developerzy nie stawiają sobie lokalnej bazy danych, tylko łączą się z jakąś jedną główną bazą?

Moim marzeniem byłoby, żeby kazdy miał lokalnie schemat bazy danych, ale niestety przy rozwoju oporogramowania często potrzebne są jakieś dane do pracy, choćby sprzed kilku miesiący z produkcji czy jakieś spreparowane dla DEVów.

Ale to właśnie mógłby być argument za tym, żeby wszystko puszować na mastera - wtedy na masterze są wszystkie schematy danych(albo wszystkie zmiany) od początku projektu do końca, i po prostu wybierasz sobie, który schemat ci w danym momencie potrzebny.

Jak przekonac git-flow hejterów

s/hejterów/krytyków

Ja mam wrażenie, że nie ma czegoś takiego jak hejterzy git-flow, a jedynie osoby, które nadmiernie promują ten system pracy jako coś wspaniałego.

Cześć dinozaurów oprogromowanie żyją ciągle w SVN-owym mindsecie.

brak sympatii do git-flow nie oznacza ani hejtu ani bycia staroświeckim. Być może w twoim zespole są tacy ludzie, ale generalnie nie musi to być prawda. To trochę jak ze Scrum. To, że ktoś nie lubi Scruma nie oznacza, że żyje w waterfallowym mindsecie, bo może po prostu taka osoba pracowała kiedyś w Scrum i się zraziła do niego.

0

Lepszy jakikolwiek flow niż wolna amerykanka wg mnie.
jestem sfrustrowany, kiedy bez pull requesta moje zmiany lądują (lub mogą lądować) na produkcji.

skoro git ma słuzyć do kontroli wersji oraz jego idea polega na tworzeniu gałęzi, ale robią to głównie osoby nowe, które przyszły z innych firm i mają nawyk jakiegoś trzymania struktury branchy ... hmmm.... w tym ja xD
dlatego trochę się buntuję.

2

A ja popieram dinozaury, trunk based development z feature branchami ale tylko w ostateczności jeśli nie jesteśmy w stanie akceptowalnym kosztem wprowadzić feature toggle. Im kod żyje krócej poza głównym branchem i im wcześniej zostanie zintegrowany z całością tym lepiej.

2

@leggo: Czas zmienić firmę. Nie warto marnować energii na beton.

2
neves napisał(a):

A ja popieram dinozaury, trunk based development z feature branchami ale tylko w ostateczności jeśli nie jesteśmy w stanie akceptowalnym kosztem wprowadzić feature toggle.

Feature toggle to po pierwsze rak, a po drugie służą do czego innego niż feature branche, i nie rozwiązują tych samych problemów, więc pomysł zastępowania jednego drugim brzmi jak pomysł zastąpienia pralki lodówką.

Im kod żyje krócej poza głównym branchem i im wcześniej zostanie zintegrowany z całością tym lepiej.

Do tego właśnie służy normalne podejście - z masterem i feature branchami. Żaden git flow nie jest do tego potrzebny. A tym bardziej feature toggle.

0

A co jest takiego złego w Git Flow.? Czy to taka różnica, czy merg'ujesz do mastera czy branch'a develop?

0
Gworys napisał(a):

A co jest takiego złego w Git Flow.? Czy to taka różnica, czy merg'ujesz do mastera czy branch'a develop?

Czytałem o git-flow, nie stosowałem, i z mojego punktu widzenia największa wada to byłoby chyba to, że można się w tym pogubić.

5
Silv napisał(a):
Gworys napisał(a):

A co jest takiego złego w Git Flow.? Czy to taka różnica, czy merg'ujesz do mastera czy branch'a develop?

Czytałem o git-flow, nie stosowałem, i z mojego punktu widzenia największa wada to byłoby chyba to, że można się w tym pogubić.

Ja słyszałem to samo o całym programowaniu.

3
Gworys napisał(a):

A co jest takiego złego w Git Flow.? Czy to taka różnica, czy merg'ujesz do mastera czy branch'a develop?

No, jeśli czyjaś praca kończy się na mergowaniu do jednego brancha, to nie. Ale na poziomie projektu wciąż trzeba synchronizować developa z masterem i odwrotnie, a to dodatkowa, zbędna robota, która nie daje żadnej wartości dodanej. Więc po co to robić?

0

w ogóle śmiesznie, bo z jednej strony jest modne git-flow, a z drugiej strony mamy inną modę - continuous integration, które często jest nie do osiągnięcia w git-flow (nie to, żeby git-flow tego zabraniał, ale helou, jeśli ficzer brancze, się powoli integrują z developem, a develop jeszcze wolniej z masterem (kiedyś pracowałem w zespole gdzie merdż to developa trwał kilka tygodni, a do mastera to już w ogóle jeszcze dłużej, od święta tylko), to nie ma mowy o żadnej continous integration.

Ale z drugiej strony czytałem kiedyś artykuł, który w sposób błyskotliwy wyśmiewał w ogóle ideę mastera i merdzowania do jednego centralnego mastera. Wg tego artykułu to Gita powinno się używać w sposób bardziej P2P, że Alice merdzuje do Boba, a potem Bob merdzuje do Charliego, i w końcu wczesniej czy później się pomerdżuje wszystko (eventual consistency), ale no nie wiem. Może taki sposób jak opisywali to byłby dobry w jakichś dużych rozproszonych teamach open source, ale jak jest kilka osób w zespole to wydaje mi się, że raczej powinno się dążyć właśnie do tego, żeby każdy kawałek kodu był jak najszybciej zintegrowany, bo tak łatwiej jak wszyscy mają aktualny obraz całości i mogą działać dalej.

Czyli więc rozgałęzianie się (i czerpanie wolności z tego, że wszystko jest bardziej distributed, podzielone na gałęzie itp.) czy bardziej ciągłą integracja? To pierwsze brzmi bardziej cool (much distributed, wow), ale tak z doświadczenia to wolę to drugie.

0
somekind napisał(a):
Gworys napisał(a):

A co jest takiego złego w Git Flow.? Czy to taka różnica, czy merg'ujesz do mastera czy branch'a develop?

No, jeśli czyjaś praca kończy się na mergowaniu do jednego brancha, to nie. Ale na poziomie projektu wciąż trzeba synchronizować developa z masterem i odwrotnie, a to dodatkowa, zbędna robota, która nie daje żadnej wartości dodanej. Więc po co to robić?

Przecież i tak najwięcej będzie synchronizacji z feature i develop. Zaletą jest to, że masz bundle tematyczne. Master to tylko taki historical branch.

Jaką formę workflow możesz w zamian polecić?

1
Gworys napisał(a):

Przecież i tak najwięcej będzie synchronizacji z feature i develop.

Najwięcej synchronizacji jest między dev a master.

Zaletą jest to, że masz bundle tematyczne. Master to tylko taki historical branch.

No ten sam efekt osiągam mając jedynie mastera, więc jakoś nie widzę tej zalety.

Jaką formę workflow możesz w zamian polecić?

Feature branche mergowane do mastera + tagi na oznaczenie releasów.

Umie ktoś powiedzieć, jaki konkretnie problem rozwiązuje git-flow?

2

Dobry pomysł, wróćmy do podstaw jakie problemy rozwiązują feature branche ?

Najważniejszy problem to izolacja kodu w trakcie developmentu od kodu już gotowego przed użytkownikiem:

  • feature branche, robią to statycznie na etapie budowy
  • feature toggle, robią to dynamicznie na etapie wykonania
2
neves napisał(a):

Najważniejszy problem to izolacja kodu w trakcie developmentu od kodu już gotowego przed użytkownikiem

Feature branche służą do organizacji pracy developera. Feature toggle służą do udostępniania ficzerów użytkownikom. To są dwa zupełnie różne aspekty. Jeśli ktoś próbuje ich używać zamiennie, to znaczy, że wrzuca brudną bieliznę do lodówki.

Problemy rozwiązywane przez oddzielne branche to chociażby:

  • syf w historii (wymieszania commitów dotyczących różnych ficzerów);
  • brak potrzeby wielokrotnego rozwiązywania konfliktów (których będzie tym więcej, im więcej będzie commitów do głównej gałęzi);
  • większa wolność, elastyczność i wygoda dla programisty.

Czyli generalnie wszystkie problemy, które są tworzone przez scentralizowane systemy kontroli wersji.

No i tak ogólnie, to ideą przewodnią Gita jest praca z gałęziami. Jeśli ktoś nie używa gałęzi w Gicie, to działa w sposób bezsensowny, zupełnie tak jakby pchał samochód zamiast nim jechać.

0

Problemy rozwiązywane przez oddzielne branche to chociażby:
brak potrzeby wielokrotnego rozwiązywania konfliktów (których będzie tym więcej, im więcej będzie commitów do głównej gałęzi);

Ja to bym powiedział, że jest właśnie odwrotnie. Dla przykładu: jest sporo out-of-tree patches do Linuksa. Trzeba je co jakiś czas rebase'ować na najnowszą wersję Linuksa, bo pojawiają się konflikty. Natomiast, gdy patch zostanie zmerge'owany do głównej gałęzi to konflikty dotyczące tego patcha znikają, bo kolejne zmiany w Linuksie biorą już pod uwagę najnowszy kod, gdzie patch jest zintegrowany.

No i tak ogólnie, to ideą przewodnią Gita jest praca z gałęziami. Jeśli ktoś nie używa gałęzi w Gicie, to działa w sposób bezsensowny, zupełnie tak jakby pchał samochód zamiast nim jechać.

Prace nad Gitem rozpoczęły się po tym, jak BitKeeper, używany wtedy do rozwoju Linuksa, przestał być darmowy dla projektów o otwartym kodzie źródłowym. Torvalds szukał rozproszonego systemu kontroli wersji, który mógłby być użyty zamiast BitKeepera, głównymi kryteriami wyboru były:

  • Przykład CVS, czego nie robić.
  • System powinien być rozproszony.
  • System powinien być chroniony przed błędami w repozytorium (przypadkowymi, jak awaria twardego dysku, jak i złośliwymi, wprowadzonymi przez kogoś).
  • System powinien być szybki.

Nie widzę tutaj brandzlowania się branchami. To trochę tak jakby powiedzieć - ideą przewodnią OOPa jest dziedziczenie, więc dziedziczmy przy każdej okazji.

0

Ale patche to co innego, niż jako takie workflow.

Czy Git Flow wymusza robienie wszystkiego na oddzielnym barnchu.?
Jak mam 3 bugi to nie lepiej jest zrobić trzy commity na innym branchu.?

1

Ludzie nie kumają Gita i dlatego są takie dyskusje. Git daje możliwość robienia burdelu w lokalnym repo a porządku w centralnym. A że ktoś robi odwrotnie...

1

Ale patche to co innego, niż jako takie workflow.

Wydaje mi się, że w środowisku Linuksowym patch i branch to w zasadzie pojęcia bliskoznaczne. Brancha nie wrzucisz bezpośrednio na listę mejlingową do review, ale serię patchy wygenerowanych z commitów już tak. Jakkolwiek by tego nie nazwać, to jednak sprawa z konfliktami pozostaje ta sama - im szybciej wrzucisz zmiany do głównej gałęzi, tym mniej będzie konfliktów. Oczywiście przy założeniu, że te twoje zmiany nie są tymczasowe i nie zechcesz ich całych w niedługim czasie odkręcić.

Co do feature switchy - jest to przecież standardowa praktyka w IT. Jak się pogrzebie w ustawieniach programów to się znajdzie miljon feature switchy. W typowym biznesowym projekcie feature switchy jest zwykle bardzo mało, bo nie opłaca się utrzymywać dwóch sposobów na robienie tego samego, bądź np przedstawiania tych samych danych na dwa różne sposoby. W typowym biznesowym projekcie jest jedna jedyna słuszna wersja każdego feature'a.

Bardzo bliskim feature switchom zagadnieniem jest wersjonowanie API np RESTowego. Żeby udostępniać dwie wersje RESTowego API - starą i nową - trzeba mieć trochę zduplikowanego kodu w głównej gałęzi, identycznie jak przy feature switchach. Owa duplikacja kodu jest powodem dla którego programiści nie chcą robić ani feature switchy, ani wersjonowania API.

2
Wibowit napisał(a):

Ja to bym powiedział, że jest właśnie odwrotnie. Dla przykładu: jest sporo out-of-tree patches do Linuksa. Trzeba je co jakiś czas rebase'ować na najnowszą wersję Linuksa, bo pojawiają się konflikty. Natomiast, gdy patch zostanie zmerge'owany do głównej gałęzi to konflikty dotyczące tego patcha znikają, bo kolejne zmiany w Linuksie biorą już pod uwagę najnowszy kod, gdzie patch jest zintegrowany.

Nie wiem jaki flow mają w Linuksie, bazuję na swoich doświadczeniach.
Jeśli każdy commit ma zawsze trafiać do mastera, to konfliktów będzie ogólnie więcej niż w oddzielnym branchu, bo de facto mamy wtedy scentralizowany system z jego wszystkimi wadami. No i ponieważ zmiany wprowadzone w niektórych miejscach mogą się okazać niepotrzebne w ostatecznym rozwiązaniu i zostaną usunięte w późniejszych commitach, to część pracy nad rozwiązaniem konfliktów pójdzie na darmo. (No chyba, że ktoś od razu pisze idealnie, to pewnie nigdy nie ma żadnych konfliktów niezależnie od systemu.)
Alternatywą jest jeden commit na dzień/tydzień/task, no ale to jest jeszcze bardziej upośledzone.
Trzecia alternatywa to robienie po gitowemu, czyli używanie gałęzi. Dla mnie jest to najbardziej logiczne, bo pozwala logicznie zarządzać pracą, trzymać commity związane z zadaniem razem, no ogólnie jest to normalne podejście.

Nie widzę tutaj brandzlowania się branchami. To trochę tak jakby powiedzieć - ideą przewodnią OOPa jest dziedziczenie, więc dziedziczmy przy każdej okazji.

Jasne. Jak wolicie, to używajcie sobie jednej gałęzi, ja nie mam nic przeciwko temu.

Gworys napisał(a):

Czy Git Flow wymusza robienie wszystkiego na oddzielnym barnchu.?

No raczej. Ale nie to jest problemem, problemem jest nadmiar długo żyjących gałęzi.

Jak mam 3 bugi to nie lepiej jest zrobić trzy commity na innym branchu.?

A czemu nie zrobić brancha dla każdego buga, w nim tyle commitów ile trzeba, a na koniec mergować po kolei do mastera za każdym razem podbijając wersję?

Wibowit napisał(a):

Bardzo bliskim feature switchom zagadnieniem jest wersjonowanie API np RESTowego. Żeby udostępniać dwie wersje RESTowego API - starą i nową - trzeba mieć trochę zduplikowanego kodu w głównej gałęzi, identycznie jak przy feature switchach. Owa duplikacja kodu jest powodem dla którego programiści nie chcą robić ani feature switchy, ani wersjonowania API.

Dobra uwaga. No i czy ktokolwiek sugeruje, aby zastępować feature branche przez wersjonowanie REST API? Brzmi kuriozalnie, więc pewnie ktoś taki jest.

0

Jeśli każdy commit ma zawsze trafiać do mastera, to konfliktów będzie ogólnie więcej niż w oddzielnym branchu, bo de facto mamy wtedy scentralizowany system z jego wszystkimi wadami.

Załóżmy taki scenariusz: programista X robi zmiany w klasach A, B, a potem C. Programista Y orze klasy B, C, a potem D. Jeśli w poniedziałek programista X zrobi zmiany w klasie A, a programista Y w klasie B to nie będzie konfliktu. Podobnie w kolejnych dniach jeśli przejdą do kolejnych klas. Natomiast gdyby zrobić branche to konflikt na klasach B i C wystąpiłby podczas merge'owania drugiej gałęzi pobocznej do gałęzi głównej.

No i ponieważ zmiany wprowadzone w niektórych miejscach mogą się okazać niepotrzebne w ostatecznym rozwiązaniu i zostaną usunięte w późniejszych commitach, to część pracy nad rozwiązaniem konfliktów pójdzie na darmo.

To się zgadzam i wprost o tym wcześniej napisałem:

Jakkolwiek by tego nie nazwać, to jednak sprawa z konfliktami pozostaje ta sama - im szybciej wrzucisz zmiany do głównej gałęzi, tym mniej będzie konfliktów. Oczywiście przy założeniu, że te twoje zmiany nie są tymczasowe i nie zechcesz ich całych w niedługim czasie odkręcić.

Natomiast:

Dobra uwaga. No i czy ktokolwiek sugeruje, aby zastępować feature branche przez wersjonowanie REST API? Brzmi kuriozalnie, więc pewnie ktoś taki jest.

Ja taki jestem (w sensie moim zdaniem jest to sensowna opcja do wyboru w pewnych przypadkach). Feature switche czy też bliskie im wersjonowanie API są w zasadzie wymagane jeśli z naszego systemu korzystają też inni i nie chcemy zrobić im kuku.

Mamy np firmę A, która wystawia APIv1 i firmę B, która integruje się z APIv1. Firma A chce wydać nową wersję API. Co może zrobić? Jeśli podejdziemy do tematu na zasadzie feature brancha, który zastępuje stary kod nowym kodem to tak samo zastąpimy APIv1 za pomocą APIv2. Nie zostawi to żadnego pola do manewru firmie B, która będzie musiała się dokładnie zsynchronizować z firmą A - jest to w zasadzie nieakceptowalne. APIv1 i APIv2 muszą być wystawiane jednocześnie przez pewien czas (np kilka miesięcy) by dać firmie B czas na migrację. Wersjonowanie wymaga duplikacji kodu - APIv1 i APIv2 nie różnią się drastycznie, pokrywają się w dużym stopniu, ale trzeba je oba zaimplementować rzeczywistym kodem i to musi wiązać się z jakąś duplikacją.

Podobno w Amazonie takie wersjonowanie jest powszechną praktyką i każdy projekt (bądź duża część) wystawia publiczne (w sensie widoczne w całej firmie) API, z którego korzystają inne projekty i dzięki temu unika się pozyskiwania i mielenia tych samych danych w wielu projektach w tej samej firmie. Przy braku wersjonowania taka współpraca byłaby praktycznie niemożliwa.

0

Jeśli w poniedziałek programista X zrobi zmiany w klasie A, a programista Y w klasie B to nie będzie konfliktu.

Jeśli zmiany były w liniach, które nie dotyczą siebie, to konfliktów nie będzie, jeśli dotyczą, to konflikty i tak będą, tylko będą rozwiązywane na bieŻąco (Boże, widzisz takie błędy i nie grzmisz) zamiast post-factum. Poza tym są narzędzia, które wspomagają rozwiązywanie takich konfliktów, git-imerge czy rerere. Alternatywnie można używać Darcs czy innego patch-based VCS zamiast Gita, który też stara się zmniejszyć skalę problemu.

0

Jeśli zmiany były w liniach, które nie dotyczą siebie, to konfliktów nie będzie

No to oczywiste - brak nachodzących zmian to brak konfliktów niezależnie od kolejności wprowadzania zmian.

jeśli dotyczą, to konflikty i tak będą, tylko będą rozwiązywane na bieŻąco (Boże, widzisz takie błędy i nie grzmisz) zamiast post-factum

Dlaczego mają być? Programista X zaczyna robić zmiany w klasie B po tym jak programista Y zakończył robić zmiany w tejże klasie. Analogicznie z klasą C. Gdzie tu mają być konflikty?

0

brak nachodzących zmian to brak konfliktów

Otóż nie. W sensie VCS nie zgłosi konfliktów, ale to wcale nie oznacza, że ich nie ma (ale to zależy jak zdefiniujemy konflikt). Przykładowo ja uważam, że coś takiego:

Oryginalny plik:

fn foo() { println!("Foo"); }

fn bar() {
  foo();
}

Zmiana A:

5a6,9
> 
> fn baz() {
>   foo();
> }

Zmiana B:

1c1
< fn foo() { println!("Foo"); }
---
> fn f() { println!("Foo"); }
4c4
<   foo();
---
>   f();

To jak najbardziej konflikt, ale żadne narzędzie, które nie jest świadome języka z jakim pracuje, tego nie wykryje.

0
Wibowit napisał(a):

To się zgadzam i wprost o tym wcześniej napisałem:

Jakkolwiek by tego nie nazwać, to jednak sprawa z konfliktami pozostaje ta sama - im szybciej wrzucisz zmiany do głównej gałęzi, tym mniej będzie konfliktów. Oczywiście przy założeniu, że te twoje zmiany nie są tymczasowe i nie zechcesz ich całych w niedługim czasie odkręcić.

Wydaje mi się, że usuwanie uprzednio wprowadzonych zmian w plikach podczas pracy nad swoim taskiem i w efekcie pozostawianie ich w identycznym stanie jak przed rozpoczęciem pracy zdarza się dość często, więc stosowanie feature branchy pozwala nieraz uniknąć rozwiązywania konfliktów na darmo. Przynajmniej mi, więc dla mnie feature branch jest bardzo przydatną rzeczą.
Druga zaleta, to czysta historia w masterze, można z niej sobie nawet release notes generować.

Ja taki jestem (w sensie moim zdaniem jest to sensowna opcja do wyboru w pewnych przypadkach). Feature switche czy też bliskie im wersjonowanie API są w zasadzie wymagane jeśli z naszego systemu korzystają też inni i nie chcemy zrobić im kuku.

Jak dla mnie, to wersjonowanie API służy do zupełnie innych celów niż feature toggle, i obie te rzeczy istnieją na innym poziomie niż feature branche, i stosowanie ich się w żadnym stopniu wzajemnie nie wyklucza. Wersjonowanie i toggle mówią o tym jak działa aplikacja, a branche to sposób działania programisty.

Feature branch to po prostu sposób organizacji pracy programisty, pozwalająca na trzymanie zmian związanych z jednym zadaniem razem, niezależne ich testowanie, analizę metryk kodu, wdrożenie, pokazanie klientowi, itd.
Feature toggle pozwala na warunkowe włączanie jakichś funkcji albo zmianę ich działania już po wdrożeniu. Może to mieć cel testowy albo marketingowy (np. wdrażanie nowej funkcji tylko dla tych klientów, którzy za nią płacą). Co istotne, to właściciel serwisu ma nad tym kontrolę.
Wersjonowanie to podstawowa zasada higieny jeśli chcemy zachować kontrolę nad zmianami i trzymać kompatybilność dla użytkowników. Tylko w tym przypadku to konsument usługi (a nie jej właściciel) wybiera, z których funkcji chce korzystać poprzez wywołanie wersji API. Nie da się zastąpić wersjonowania feature togglem, bo nie da to konsumentowi wyboru ani nawet pewnej informacji odnośnie dostępnych funkcji.

Mamy np firmę A, która wystawia APIv1 i firmę B, która integruje się z APIv1. Firma A chce wydać nową wersję API. Co może zrobić? Jeśli podejdziemy do tematu na zasadzie feature brancha, który zastępuje stary kod nowym kodem to tak samo zastąpimy APIv1 za pomocą APIv2. Nie zostawi to żadnego pola do manewru firmie B, która będzie musiała się dokładnie zsynchronizować z firmą A - jest to w zasadzie nieakceptowalne.

To jakiś bardzo dziwny flow. Feature branchem nie zastępuje się mastera, tylko się go z nim scala. To, czy zmiany z feature brancha powodują niekompatybilność API albo wymagają feature toggle wiadomo od momentu rozpoczęcia taska, więc należy ten problem rozwiązać podczas pracy nad taskiem.

APIv1 i APIv2 muszą być wystawiane jednocześnie przez pewien czas (np kilka miesięcy) by dać firmie B czas na migrację. Wersjonowanie wymaga duplikacji kodu - APIv1 i APIv2 nie różnią się drastycznie, pokrywają się w dużym stopniu, ale trzeba je oba zaimplementować rzeczywistym kodem i to musi wiązać się z jakąś duplikacją.

Jeśli v1 i v2 mają być oddzielnymi fizycznie instancjami, to duplikacja będzie wręcz pełna, a jeśli wystarczy wersjonowanie w ramach jednego serwisu (np. po URLu, czy nagłówkach HTTP), to duplikacji może prawie nie być. Tylko nie bardzo jakoś widzę związek z gałęziami w Gicie.

1

@somekind:

Nie da się zastąpić wersjonowania feature togglem, bo nie da to konsumentowi wyboru ani nawet pewnej informacji odnośnie dostępnych funkcji.
Jeśli v1 i v2 mają być oddzielnymi fizycznie instancjami, to duplikacja będzie wręcz pełna, a jeśli wystarczy wersjonowanie w ramach jednego serwisu (np. po URLu, czy nagłówkach HTTP), to duplikacji może prawie nie być.

Moim zdaniem wersjonowanie i feature switch wymagają bardzo podobnej ilości duplikacji kodu (i nie ma znaczenia, czy mamy osobne instancje robione metodą Kopiego-Pejsta, czy wersjonujemy za pomocą nagłówków HTTP). Dla przykładu, feature switch w mikroserwisie X może określać z której wersji API mikroserwisu Y ma on korzystać. Z drugiej strony dużo zależy co ktoś rozumie przez wersję API. Gdzieś wyczytałem, że np zamiana pól na jakieś inne to już stworzenie nowego API, a nie zmiana starego. Niespecjalnie mnie taka terminologia przekonuje. Nie widzę przeszkód, by APIv2 wymagało nieco innych zapytań do bazy danych niż APIv1.

To jakiś bardzo dziwny flow. Feature branchem nie zastępuje się mastera, tylko się go z nim scala. To, czy zmiany z feature brancha powodują niekompatybilność API albo wymagają feature toggle wiadomo od momentu rozpoczęcia taska, więc należy ten problem rozwiązać podczas pracy nad taskiem.

Jeśli na masterze jest APIv1, a na branchu wywaliłem APIv1 i wstawiłem APIv2 to po zmerge'owaniu brancha na masterze APIv1 będzie zastąpione przez APIv2. Nie usuwasz starego kodu w swoich branchach?

@hauleth:
Opiszę przykład bardziej łopatologicznie. Programista X chce zmienić klasy A, B i C. Programista Y chce zmienić klasy B, C i D. Scenariusz działania wygląda tak:

  • poniedziałek 9 programista X rozgrzebuje klasę A, programista Y rozgrzebuje klasę B,
  • poniedziałek 17 programista X commituje zmiany w A, programista Y commituje zmiany w B,
  • wtorek 9 programista X rozgrzebuje klasę B, programista Y rozgrzebuje klasę C,
  • wtorek 17 programista X commituje zmiany w B, programista Y commituje zmiany w C,
  • środa 9 programista X rozgrzebuje klasę C, programista Y rozgrzebuje klasę D,
  • środa 17 programista X commituje zmiany w C, programista Y commituje zmiany w D,

Konfliktów nie ma, bo niby w którym momencie?

Teraz rozważmy schemat przy użyciu branchy. Programista X ma zmiany w A, B i C na swoim branchu, programista Y ma zmiany w B, C i D na swoim branchu. Oboje merge'ują się z masterem, ale ktoś musi być pierwszy. Ten drugi musi rozwiązać konflikty w klasach B i C.

Oczywiście powyższy scenariusz bardzo mocno faworyzuje brak branchy i rzeczywistość (bardzo często) jest zupełnie inna. Jednak próby podobnego szeregowania zmian w plikach się zdarzają. Konkretnie chodzi mi np o przypadek, w którym zarówno ja na swoim branchu jak i kolega chcemy zmodyfikować klasę S. Do tego jest też szereg innych zmian, ale przewidujemy, że w klasie S będzie najwięcej konfliktów. Kolega już rozgrzebał klasę S, więc mówi mi, żebym rozgrzebał inne klasy, on w międzyczasie zmerge'uje się do mastera, wtedy ja się zrebase'uję i będę mógł rozgrzebywać klasę S już z jego zmianami, unikając w ten sposób niepotrzebnych konfliktów. To miało szansę zadziałać, bo jego branch był już na ukończeniu, a mój dopiero rozgrzebywałem. Im mniejsze są zmiany na branchach tym częściej się takie manewry udają. Z drugiej strony - im mniejsze są zmiany na branchach, tym bliżej im do braku branchy.

Osobną sprawą niż wersjonowanie API, feature switche i rozmiary pull requestów jest ilość branchy. Branche pozwalają łatwo uniknąć wersjonowania API czy feature switchy - zamiast je implementować można deployować wersje z brancha na środowisko testowe i jak w końcu zadziałają poprawnie to można zastąpić nimi stare wersje. git-flow natomiast oznacza jakieś szalone żonglowanie branchami. master, develop, hotfix, release, feature, WTF? U nas efektywnie jest gałąź główna oraz feature branche i tyle. Więcej się nie przydaje, bo np nie prowadzimy wielu oficjalnych linii oprogramowania - na produkcji jest tylko jeden zestaw wersji. Faktycznie mamy dwie główne gałęzie - master i develop, bo kolega przekonywał, że takie coś się przyda. Jednak w praktyce się nie przydaje i master leży nieruszany odłogiem, a developa traktujemy jako główną gałąź. Hotfixów też nie mamy - zamiast tego jest rollback do poprzedniego release'a (co zdarza się nam bardzo rzadko). Reasumując schemat jest bardzo prosty - jedna główna gałąź i wiele feature branchy.

@leggo:
Wracając do problemu postawionego prze OPa, czyli użycie branchy do tworzenia ewolucji na bazie (czyli do skryptów SQLowych) to są one raczej problemem niż rozwiązaniem problemu. Narzędzia do ewolucji na bazkach czyli np https://flywaydb.org/ działają przyrostowo. Oczekują, że każdy kolejny skrypt będzie operował na stanie pozostawionym przez skrypt poprzedni. Jest to więc analogiczne do wrzucania commitów z SQLami bezpośrednio do mastera. Testowanie lokalnego brancha na pustej bazie to słaby test. Testowanie brancha na wspólnej bazie to prosta droga do rozsynchronizowania ewolucji na bazie. U nas ten problem jest pewnie w dużo mniejszej skali niż u was, bo rzadko kiedy dorzucamy kolejne ewolucje - możemy się więc dogadywać kiedy kto je wrzuca. Stąd zapewne nikt go u nas jakoś usilnie nie próbował rozwiązywać.

Jedyne co mi przychodzi do głowy jeśli chodzi o testowanie lokalnego brancha z ewolucjami na bazie to:

  • klonowanie zawartości wspólnej bazy do świeżej lokalnej bazy (żeby klonowanie było szybkie to danych musi być względnie mało, przynajmniej jeśli chodzi o bazkę służącą do klonowania)
  • odpalenie na niej zmian z lokalnego brancha i potestowanie
  • jeśli testy przejdą to zmerge'owanie zmian do mastera

Powyższe oczywiście skomplikuje się jeśli będziesz chciał zaimplementować git-flow, bo git-flow wymaga wielu branchy (master, develop, release, hotfix, itd), a każdy branch wymaga osobnej instancji bazki, która musi być synchronizowana jednocześnie ze zmianami w gicie. Moim zdaniem takie żonglowanie nie będzie się opłacać, bo synchronizowanie zmian na bazie razem ze zmianami w gicie znacznie zwiększa już dużą złożoność git-flowa.

0

@Wibowit:

Wibowit napisał(a):

Moim zdaniem wersjonowanie i feature switch wymagają bardzo podobnej ilości duplikacji kodu (i nie ma znaczenia, czy mamy osobne instancje robione metodą Kopiego-Pejsta, czy wersjonujemy za pomocą nagłówków HTTP).

Owszem, ale zwróć uwagę, że ja porównywałem dwa rodzaje wersjonowania (klon repozytorium kodu aplikacji vs endpointy nowej wersji dopisane w ramach tego samego repozytorium).

Dla przykładu, feature switch w mikroserwisie X może określać z której wersji API mikroserwisu Y ma on korzystać.

A co to daje z punktu widzenia mikroserwisu X? Jeśli Y ma nową wersję, i jesteśmy w stanie się z nią zintegrować, to czemu trzymać możliwość łączenia się ze starą?
No chyba, że jest takie wymaganie biznesowe, że np. ruch od niektórych konsumentów X kierujemy do starego Y, a część do nowego Y. Stary i nowy Y różni się jakoś w działaniu, np. zwraca inne dane. Jeśli to taki przypadek, to tak naprawdę tworzymy po prostu nowy ficzer, a więc i nową wersję naszego API.

Z drugiej strony dużo zależy co ktoś rozumie przez wersję API. Gdzieś wyczytałem, że np zamiana pól na jakieś inne to już stworzenie nowego API, a nie zmiana starego.

Hmm...
Jeśli wyłącznie dodajemy nowe pola, to zwiększamy minor, jeśli jakieś usuwamy (albo robimy jakiś inny breaking change), to zwiększamy major. I w tym wypadku trzeba wystawić nową wersję API (czy to URL, czy przez nagłówki), żeby nie zepsuć konsumentów starego.

Jeśli na masterze jest APIv1, a na branchu wywaliłem APIv1 i wstawiłem APIv2 to po zmerge'owaniu brancha na masterze APIv1 będzie zastąpione przez APIv2. Nie usuwasz starego kodu w swoich branchach?

Usuwam, ale nie wywalam starych wersji swojego API, póki ktoś z nich korzysta. U mnie po mergu nic nie będzie zastąpione - będą dwa endpointy, w zależności od headerów będzie wywoływany jeden albo drugi.

Z drugiej strony - im mniejsze są zmiany na branchach, tym bliżej im do braku branchy.

W sensie, że branch ma sens tylko dla dużych zmian?

Osobną sprawą niż wersjonowanie API, feature switche i rozmiary pull requestów jest ilość branchy. Branche pozwalają łatwo uniknąć wersjonowania API czy feature switchy - zamiast je implementować można deployować wersje z brancha na środowisko testowe i jak w końcu zadziałają poprawnie to można zastąpić nimi stare wersje.

Tylko czemu ktoś miałby unikać wersjonowania API? Jak dla mnie, brak wersjonowania to jest pewne źródło problemów natury organizacyjnej i komunikacyjnej. Wystawianie serwisu przez całe jego życie jako jedna wersja API, powoduje, że nikt w efekcie nie wie, co powinno, a co nie powinno działać ani kiedy.

Reasumując schemat jest bardzo prosty - jedna główna gałąź i wiele feature branchy.

Mam takie samo podejście, tylko najwyraźniej z zupełnie innych przyczyn. :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1