Formatowanie i kontrola wersji

23

Formatowanie kodu ma znaczenie. Nawet wcięcie ma znaczenie . A spójność jest ważniejsza niż drobne ulepszenia. Ale projekty zwykle nie mają jasnego, kompletnego, weryfikowalnego i egzekwowanego przewodnika stylu od pierwszego dnia, a poważne ulepszenia mogą nadejść każdego dnia. Może to znajdziesz

SELECT id, name, address
FROM persons JOIN addresses ON persons.id = addresses.person_id;

można lepiej napisać, ponieważ / jest lepiej napisany niż

SELECT persons.id,
       persons.name,
       addresses.address
  FROM persons
  JOIN addresses ON persons.id = addresses.person_id;

podczas pracy nad dodaniem kolejnych kolumn do zapytania. Być może jest to najbardziej złożone ze wszystkich czterech zapytań w kodzie lub trywialne zapytanie spośród tysięcy. Bez względu na to, jak trudne jest przejście, zdecydujesz, że warto. Ale jak śledzić zmiany kodu w przypadku głównych zmian formatowania? Możesz po prostu poddać się i powiedzieć „to jest punkt, od którego zaczynamy od nowa”, lub możesz sformatować wszystkie zapytania w całej historii repozytorium.

Jeśli używasz rozproszonego systemu kontroli wersji, takiego jak Git, możesz powrócić do pierwszego zatwierdzenia i sformatować swoją drogę stamtąd do bieżącego stanu. Ale to dużo pracy i wszyscy inni musieliby wstrzymać pracę (lub przygotować się na matkę wszystkich fuzji) podczas jej trwania. Czy istnieje lepszy sposób na zmianę historii, który daje najlepsze wyniki:

  • Ten sam styl we wszystkich zatwierdzeniach
  • Minimalna praca scalania

?

Aby to wyjaśnić, nie chodzi o najlepsze praktyki przy rozpoczynaniu projektu, ale raczej o to , co należy zrobić, gdy duże refaktoryzacje zostały uznane za Dobrą Rzecz, ale nadal chcesz mieć możliwą do prześledzenia historię? Nigdy nie przepisywanie historii jest świetne, jeśli jest to jedyny sposób, aby upewnić się, że Twoje wersje zawsze działają tak samo, ale co z korzyściami programisty z czystego przepisywania? Zwłaszcza jeśli masz sposoby (testy, definicje składni lub identyczny plik binarny po kompilacji), aby upewnić się, że przepisana wersja działa dokładnie tak samo jak oryginał?

l0b0
źródło
24
Dlaczego chcesz przepisać historię? To przeczy celowi kontroli wersji. Chcesz się upewnić, że aplikacja, którą wysłałeś 3 miesiące temu, jest bez wątpienia zgodna z wersją xxxxxx. Niedopuszczalne jest nawet banalne formatowanie.
Simon Bergot
5
Lubię komentować, że robię to z tagiem „Reformat. Brak zmian funkcjonalnych”
Rig
3
W niezwiązanym z tym temacie brzmi to tak, jakbyś sugerował przepisanie historii Git poprzez ponowne sformatowanie całego kodu. Nie daj ludziom pojęcia, przepisywanie historii Git jest złe w 99,9% przypadków. Ponowne formatowanie nie jest przypadkiem krawędzi .1%.
Andrew T Finnell,
4
W niektórych językach (patrzę na Ciebie, Pythona) przeformatowanie może zmienić logiczne działanie kodu. Musisz mieć możliwość analizowania wszystkich języków przechowywanych w VCS, aby bezpiecznie śledzić i ignorować formatowanie.
Joris Timmermans
3
Reformaty są zmianami w kodzie i powinny zostać zatwierdzone jako takie.
David Cowden

Odpowiedzi:

26

Przeprowadź formatowanie osobno. Spowoduje to minimalną ingerencję w historię i na pierwszy rzut oka powinieneś zobaczyć, które zmiany formatują, a które zmieniają kod. Może przechylać się git blamei podobnie, ale jeśli wskazuje na zatwierdzenie tylko do formatowania, dość prosto można poszukać poprzedniej zmiany wcześniej.

Harald
źródło
Od tygodni widziałem wykolejenie projektów, ponieważ jeden z programistów uznał, że to dobry pomysł. Jeśli masz zamiar to zrobić, najpierw zrozum ryzyko i zdecyduj, jak daleko zajdziesz z formatowaniem. Myślę, że mjfgates ma właściwą odpowiedź.
Johntron
1
Wygląda na to, że dany zespół ma większe problemy niż formatowanie kodu. Ale tak, nie polecam tego robić, chyba że musisz. Jeśli chcesz zrobić zmiany formatowania, nadal powiedziałbym, że lepiej zrobić je jako osobne zmiany, niż zmieszać ze zmianami funkcjonalnymi.
harald
Tak, wiele problemów: PI chce tylko ostrzec nowych programistów, że to nie takie proste, jak się wydaje. Narzędzia do przeformatowywania zbiorczego są ryzykowne (zwłaszcza jeśli tworzysz je sam z regexem - przynajmniej używasz AST), a jeśli zależy ci na przeglądaniu kodu i śledzeniu błędów, może to naprawdę popsuć proces. Osobiście piszę mój kod, aby był zgodny ze stylem każdego pliku, choć nie mam nic przeciwko przeglądaniu kodu, gdy kilka funkcji zostanie ponownie sformatowanych. Wielu programistów rozwiewa się stylem kodu i zaniedbuje większe problemy, takie jak architektura, proces, narzędzia itp.
Johntron
W programowaniu nic nie jest tak proste, jak się wydaje :)
harald
13

Nie przepisuj historii VCS: jest to sprzeczne z zasadami VCS.

Nie próbuj automatyzować naprawiania formatowania: leczy objawy, a nie prawdziwy problem (= programiści nie przestrzegają standardów kodowania).

Zdefiniuj standard kodowania i najlepsze praktyki formatowania we wspólnym dokumencie i poproś wszystkich programistów o zgodę.

Wspominasz o Git, co jest świetne, ponieważ jest rozpowszechniane. Dzięki DVCS bardzo łatwo jest egzekwować najlepsze praktyki poprzez przepływ pracy strażnika . Strażnicy odrzucają propozycje scalania (= ściągaj żądania w Git), które nie są zgodne ze wspólnymi wytycznymi. Mam na myśli odrzucenie pogrubionymi literami, w przeciwnym razie naruszający koder nie będzie zadawał sobie trudu przestrzegania zasad i nadal będzie powtarzał te same błędy.

Ta technika działa dla mnie dobrze. Koderzy chcą, aby ich praca została połączona, więc po kilku błędach na początku zaczynają przestrzegać zasad.

Jeśli chodzi o naprawianie istniejącej bazy kodu ... Zalecam robić to stopniowo, być może moduł po module lub jak to ma sens dla twojego projektu. Testuj dokładnie na każdym kroku. Może to zabrzmieć głupio, ale błędy zdarzają się nawet przy trywialnych zmianach, takich jak formatowanie, więc przygotuj się na drobne nierówności na drodze.

janos
źródło
1
Zagłosowano, ponieważ autor wyraźnie stwierdza, że ​​dzieje się tak w kontekście projektów, które nie zaczęły się od „… przejrzystego, pełnego, weryfikowalnego i egzekwowanego przewodnika stylu od pierwszego dnia”. Nie może wyleczyć prawdziwego problemu, ponieważ już się to wydarzyło. Zgadzam się jednak z tobą :)
Johntron
2
odrzucenie oznacza, że ​​będzie walka między ludźmi a robotem. Byłem tam Wcześniej czy później robot będzie wymagał bardzo złożonego kodu do sformatowania w nieczytelny sposób. Przykłady: łańcuch Java jest w rzeczywistości instrukcją SQL, ale robot o tym nie wie; białe znaki przed zamknięciem parens mogą przenosić informacje o strukturze kodu dla ludzi, ale nie dla robota; parametry funkcji dzielą się na wiele wierszy w najbardziej bezsensowny sposób ...
18446744073709551615
9

Odpowiedź na twoje rzeczywiste pytanie brzmi: „Ty nie”. Nie znam żadnego obecnego narzędzia SCM, które mogłoby śledzić zmiany w logice z kodu sformatowanego w jeden sposób, poprzez poważną zmianę formatowania i dalsze zmiany po sformatowaniu kodu w nowy sposób. I wiesz o tym, utrata historii na kodzie nie jest dobra.

W związku z tym zamierzam trochę zaprzeczyć twojemu pierwszemu zdaniu. Kod formatowania nie ma znaczenia , że dużo. Ładne jest miłe, ale nie po to tu jesteśmy. Rozumiem tak dobrze, jak każdy, kto zostaje wrzucony do czyjegoś piekielnie dziwnego kodu K&R z wcięciami dwóch spacji jest do bani (1), ale ... formatowanie nie jest przeszkodą w zrozumieniu, co się dzieje, chyba że jest to coś wyjątkowego patologiczny. W takim przypadku i tak będziesz mieć problemy ze zmianą kodu i nie powinieneś go niepokoić.

Dlatego nie warto wprowadzać zmian w ustalonym kodzie SZYBKO, aby go sformatować. Zmieniając nazwy zmiennych, rozkładając długie funkcje, wszystko to dobre refaktoryzacja, która zmienia treść, tak, ale nie TYLKO formatowanie.

1) - Kiedyś miałem przez pewien czas Przeglądarkę schowka Windows. Całość stanowiła jedna, 150k, moduł C. Znalazłem miejsce, w którym różni ludzie używali, jak sądzę, pięciu różnych stylów aparatu w odległości trzydziestu linii od siebie. Ale ta część rzeczy działała. Przez dziesięć lat nosiłem wydruk tego fragmentu kodu, ale nie naciągnąłem go, ponieważ ta historia się liczyła, a ten kod znajdował się w co najmniej trzech drzewach źródłowych (Windows 3.x, NT, przyszłość 95), które wszystkie żyły w różnych budynkach.

mjfgates
źródło
W przeszłości, używając hg, odkryłem, że scalanie według części jest nieocenionym narzędziem w radzeniu sobie z trudnymi, dużymi scaleniami typu re-factor . Zazwyczaj to, co bym zrobił, to scalenie zatwierdzeń przed dużym ponownym współczynnikiem, następnie scalenie samego dużego ponownego współczynnika, a następnie w końcu scalenie zatwierdzeń od ponownego współczynnika. Każdy z tych trzech scala na własną rękęznacznie łatwiejsze niż próbuje rozwikłać ten bałagan, który wynika z prowadzenia wszystkich scala w jednym zamachem.
Mark Booth
W pełni się zgadzam! Ponadto widziałem, jak wielu programistów przesadza (włączając w to młodszą wersję siebie) w zakresie formatowania i stylu kodu, i ostatecznie wprowadzają wady. Brak tutaj przecinka / średnika, zmienne deklaracje przeniesiono na szczyt funkcji, pętle for zmieniono na for-each - wszystkie mogą wprowadzać subtelne błędy. Aby wprowadzić te zmiany w bezpieczne miejsce, potrzeba zwodniczej umiejętności.
Johntron,
4

Ale jak śledzić zmiany kodu w przypadku głównych zmian formatowania?

Zmiany formatowania zmiany w kodzie; traktuj je jak każdą inną zmianę w kodzie. Każdy, kto pracował nad znaczącym projektem, prawdopodobnie zobaczy błędy i inne problemy, które powstały, gdy ktoś postanowił „po prostu” sformatować jakiś kod.

Ale to dużo pracy i wszyscy inni musieliby wstrzymać pracę (lub przygotować się na matkę wszystkich fuzji) podczas jej trwania.

Dlaczego musisz ponownie sformatować wszystko jednocześnie? Zwłaszcza jeśli ponowne formatowanie nie zmienia znaczenia kodu, powinieneś być w stanie ponownie formatować pliki indywidualnie i rejestrować je w miarę postępów. Lepiej, zachęć wszystkich członków zespołu do uzgodnienia stylu (w przeciwnym razie i tak nie ma sensu formatowania) i niech wszyscy zajmą się ponownym formatowaniem w trakcie swojej drugiej pracy. Po chwili ominiesz większość kodu, nie zakłócając reszty projektu.

Caleb
źródło
1

Istnieją realne dwa podejścia, które widziałem w tym celu.

1. Sformatuj kod po zakończeniu przechwytywania

Podczas gdy początkowo podnoszenie włosów ma na celu zmianę kodu po jego przesłaniu, jeśli twoja procedura formatowania (np. Astyle ) nie zaszkodzi kodowi, jest to bezpieczna operacja. Z czasem cały zespół zauważy, że cały kod ostatecznie wygląda tak samo. Oczywiście posiadanie kompleksowych testów jednostkowych / automatycznych zapewni, że nic się nie zepsuje.

2. Jednorazowe formatowanie całego kodu

Z mojego doświadczenia jest to bardziej niebezpieczne i utrudnia śledzenie problemów w Wielkim Wybuchu, ale jest to możliwe. Niezbędne jest przeprowadzenie wszystkich testów później. W przypadku stylu kodowania większość różnic dotyczy używania białych znaków - wcięć lub znaków nowej linii. Przyzwoite narzędzie do scalania powinno mieć możliwość ignorowania wszystkich różnic między białymi spacjami, więc pomoże to w scalaniu.

JBRWilkinson
źródło
1
Czy opcja 1 po włączeniu nie zaszumie szybko w większości baz kodu, co spowoduje taki sam wielki wybuch zmiany każdej pliku?
Podpisz
@Sign: Dokładnie o to mi chodzi - kiedy zmienia się hak zatwierdzania, twoja historia może zmienić się w coś prawie bezużytecznego. Formatowanie, które nie zmienia funkcjonalności, nie powinno być zatwierdzeniem, powinno zostać przeszczepione w całej historii kodu.
l0b0
1
Jeśli IDE to obsługuje, to są też 3) mieć autoformatowanie IDE przy zapisie. Następnie po prostu używaj wszędzie tych samych ustawień - jest to najłatwiejsze, jeśli używasz domyślnego IDE.
Zastosowałem oba te podejścia. Pierwsze podejście jest bardzo natrętne, ponieważ za każdym razem, gdy nowy plik zostanie zatwierdzony po raz pierwszy, będzie mnóstwo zmian. Drugie podejście jest lepsze dla zespołu, na przykład szybkie odrywanie bandaida.
Druska