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

Odpowiedz Nowy wątek
2019-05-10 15:00
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.

Pozostało 580 znaków

2019-05-13 02:06
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.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2019-05-14 21:00
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.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit, 2019-05-14 21:01

Pozostało 580 znaków

2019-05-15 13:07
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.

Pozostało 580 znaków

2019-05-15 14:10
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?


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.

Pozostało 580 znaków

2019-05-15 14:31
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.

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). - w tym przypadku chodziło mi o konflikt w VCSie - Wibowit 2019-05-15 14:35

Pozostało 580 znaków

2019-05-18 02:52
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.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2019-05-18 14:17
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:00: programista X rozgrzebuje klasę A, programista Y rozgrzebuje klasę B,
  • poniedziałek 17:00: programista X commituje zmiany w A, programista Y commituje zmiany w B,
  • wtorek 9:00: programista X rozgrzebuje klasę B, programista Y rozgrzebuje klasę C,
  • wtorek 17:00: programista X commituje zmiany w B, programista Y commituje zmiany w C,
  • środa 9:00: programista X rozgrzebuje klasę C, programista Y rozgrzebuje klasę D,
  • środa 17:00: 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.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit, 2019-05-18 14:56
@leggo wołam w komentarzu, bo po edycji wołanie w poście nie działa :) - Wibowit 2019-05-18 14:59
Miałem trochę zwariowany weekend, więc pozwól że przeczytam w pracy :D :D :D - leggo 2019-05-19 13:45

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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

Robot: CCBot