Zapobiegaj kompilacji przestarzałego kodu po upływie terminu [zamknięte]

68

W moim zespole myjemy wiele starych rzeczy w dużym monolitycznym projekcie (całe klasy, metody itp.).

Podczas tych prac porządkowych zastanawiałem się, czy jest coś w rodzaju adnotacji lub bardziej wyszukanego w bibliotece niż zwykle @Deprecated. To @FancyDeprecatedpowinno zapobiec gromadzeniu projektu od powodzenia, jeśli nie czyścić stare niewykorzystany kod po określonej dacie minęło.

Szukałem w Internecie i nie znalazłem niczego, co ma możliwości opisane poniżej:

  • powinna być adnotacją lub czymś podobnym, aby umieścić w kodzie, który chcesz usunąć przed określoną datą
  • przed tą datą kod się skompiluje i wszystko będzie działać normalnie
  • po tej dacie kod nie będzie się kompilował i wyświetli komunikat ostrzegający o problemie

Myślę, że szukam jednorożca ... Czy istnieje podobna technologia dla dowolnego języka programu?

Jako plan BI myślę o możliwości wykonania magii za pomocą niektórych testów jednostkowych kodu, który ma zostać usunięty, które zaczynają kończyć się niepowodzeniem w „terminie”. Co o tym myślisz? Masz lepszy pomysł?

Arcones
źródło
168
Wycofywanie dotyczy wersji , a nie daty . Jeśli chcesz, aby ludzie przestali używać przestarzałych funkcji, wypuść wersję bez nich. To przyciągnie ich uwagę i zawsze mogą się wycofać, jeśli nie mogą tego jeszcze zrobić. Wiele osób utknęło na starych wersjach. Złamanie ich programu nie jest dobrym rozwiązaniem.
isanae
4
Plan B brzmi solidnie. Z dodatkowymi zaletami, które można umieścić komentarz w teście jednostkowym, dlaczego jest przestarzały. Dodanie komentarza do kodu źródłowego nie pomogłoby w odczytaniu dużego monolitu
dwana
53
To brzmi jak naprawdę zły jednorożec. Masz trochę oprogramowania, które dobrze się kompiluje, przechodzi wszystkie testy i wysłałeś je do klienta. Pewnego dnia ponownie sprawdzisz oprogramowanie i nie będzie ono budować, nawet na dokładnie tej samej platformie programistycznej. Jesteś teraz zmuszony zmodyfikować kod, który poprzednio przeszedł formalne testy, lub zrobić złe hacki, takie jak cofnięcie zegara komputera.
Simon B,
6
Zrób to @ Deprecated_RemoveMe_2018_06_01, a następnie w dniu 2018-06-01 usuń samą adnotację. Voila, cały kod używający adnotacji nie będzie się już kompilował! (ponieważ adnotacja nie została znaleziona)
immibis
65
Lata w przyszłości nowo zatrudniony programista zapyta: dlaczego czas na serwerze kompilacji jest ustawiony na styczeń 2016 r.? A facet, który jest tam przez 10 lat, powie mu, że jest to konieczne, lub kompilacja psuje się w przypadkowych miejscach. Westchnienie.
Wilbert,

Odpowiedzi:

62

Nie sądzę, aby była to przydatna funkcja, gdy naprawdę zabrania kompilacji. Kiedy na 01.06.2018 duże części kodu nie zostaną skompilowane, co skompilowano dzień wcześniej, Twój zespół szybko usunie tę adnotację, wyczyści kod lub nie.

Możesz jednak dodać niestandardową adnotację do kodu, np

@Deprecated_after_2018_07_31

i zbuduj małe narzędzie do skanowania w poszukiwaniu tych adnotacji. (Wystarczy prosta linijka w grep, jeśli nie chcesz używać odbicia). W innych językach niż Java można użyć standardowego komentarza odpowiedniego do „grepping” lub definicji preprocesora.

Następnie uruchom to narzędzie na krótko przed określoną datą lub po niej, a jeśli nadal znajdzie tę adnotację, przypomnij zespołowi, aby pilnie wyczyściła te części kodu.

Doktor Brown
źródło
9
@Bergi: hej, to tylko przykład, OP może używać wersji lub znaczników daty, cokolwiek woli w swoich kontrolach.
Doc Brown
4
Nie widzę żadnej przewagi nad robieniem tego nad zwykłym użyciem funkcji przestarzałych i analizowaniem danych wyjściowych kompilatora w określonym dniu. Wydaje się, że słabe wykorzystanie czasu programisty na ponowne wdrożenie czegoś, co prawie już istnieje. Nawet jeśli masz już mnóstwo ostrzeżeń (które warto poświęcić na ich wyczyszczenie), na pewno kompilator wyśle ​​wszystkie ostrzeżenia do pliku tekstowego, a następnie grep lub przeszuka go.
jpmc26
4
@jpaugh Zalecam, aby nie tracić godzin (uwaga, czas = pieniądze) na tworzenie nowych narzędzi do wykonywania zadań, które można już efektywnie wykonywać za pomocą istniejących narzędzi, niezależnie od tego, jakie mogą być.
jpmc26
3
@ jpmc26: Widzę dwie (małe) zalety: brak dostatecznej liczby ostrzeżeń o wycofaniu (co spowodowałoby ryzyko przeoczenia ważniejszych) oraz możliwość wprowadzenia różnych kryteriów wycofania (daty, wersje, cokolwiek) dla różnych sekcji kodu. Ponadto PO wyraźnie poprosił o powiązanie deprecjacji z datą.
Doc Brown
7
Dałbym +1, jeśli po prostu użyjesz kolejności RRRR-MM-DD dla daty w twoim przykładzie, ponieważ widziałem tylko dwuznaczne ?? - ?? - RRRR powoduje ból i nieporozumienia.
mtraceur
284

Stanowiłoby to cechę znaną jako bomba zegarowa . NIE TWORZENIE BOMB CZASU.

Kod, bez względu na to, jak dobrze zorganizować i dokumentować je, będzie przekształcić się źle zrozumiał niemal mitycznej czarnej skrzynki, jeśli mieszka poza pewnym wieku. Ostatnią rzeczą, jakiej potrzebuje ktoś w przyszłości, jest kolejny dziwny tryb awarii, który zaskakuje go całkowicie w najgorszym możliwym czasie i bez oczywistego lekarstwa. Nie ma absolutnie usprawiedliwienia dla celowego wywołania takiego problemu.

Spójrz na to w ten sposób: jeśli jesteś wystarczająco zorganizowany i zdajesz sobie sprawę ze swojej bazy kodu, że zależy ci na przestarzałości i postępujesz zgodnie z nią, to nie potrzebujesz mechanizmu w kodzie, aby ci to przypominać. Jeśli tak nie jest, istnieje prawdopodobieństwo, że nie będziesz na bieżąco z innymi aspektami bazy kodu i prawdopodobnie nie będziesz w stanie odpowiedzieć na alarm w odpowiednim czasie i poprawnie. Innymi słowy, bomby zegarowe nikomu nie służą. Po prostu powiedz nie!

Kilian Foth
źródło
74
+1 To będzie cię ugryźć. Miesiące później. W piątek, gdy próbujesz wykonać awaryjne wdrożenie. I to długi weekend, więc wszyscy ludzie, którzy coś o tym wiedzą, są poza biurem. Nie rób tego
Roger Lipscombe
3
Zgodzić się. Starzenie się jest kwestią organizacyjną, a nie kwestią kodowania. Nadal mogłem podłączyć Apple] [i napisać BASIC, nic mnie nie powstrzyma. Ale czy chciałbym ?
19
Prawidłowe rozwiązanie, idąc w kierunku „zorganizowanego i świadomego”, to zgłosić błąd w systemie śledzenia błędów, mówiąc „Usuń <takie i takie>”, z sugerowanym przedziałem czasowym w komentarzach. A potem w ciągu 6 miesięcy, kiedy pojawi się przegląd błędów, aby dowiedzieć się, jakie błędy powinny zostać naprawione w następnej wersji, jeśli ten przedział czasowy jest bliski, mówisz „czas to zrobić”. To podstawowe zarządzanie projektem.
Wyścigi lekkości na orbicie
1
W rzeczywistości, jeśli harmonogram wydawania jest wystarczająco przewidywalny, po prostu kamień milowy teraz.
Wyścigi lekkości na orbicie
13
Odwołaj się do komentarza isanae, aby znaleźć alternatywę: „ Jeśli chcesz, aby ludzie przestali używać przestarzałych funkcji, wypuść wersję bez nich. To przyciągnie ich uwagę i zawsze mogą się wycofać, jeśli nie mogą tego jeszcze zrobić.
Stevoisiak
70

W języku C # użyłbyś ObsoleteAttributew następujący sposób:

  • W wersji 1 dostarczasz tę funkcję. Metoda, klasa, cokolwiek.
  • W wersji 2 dostarczasz lepszą funkcję, która ma zastąpić oryginalną funkcję. Umieszczasz na funkcji atrybut Przestarzały, ustawiasz go na „ostrzeżenie” i wyświetlasz komunikat „Ta funkcja jest przestarzała. Zamiast tego użyj lepszej funkcji. W wersji 3 tej biblioteki, która zostanie wydana data, użycie tej funkcji będzie błędem ”. Teraz użytkownicy tej funkcji mogą nadal z niej korzystać, ale mają czas na aktualizację kodu w celu użycia nowej funkcji.
  • W wersji 3 aktualizujesz atrybut tak, aby był błędem, a nie ostrzeżeniem, i aktualizujesz komunikat, mówiąc: „Ta funkcja jest przestarzała. Zamiast tego użyj lepszej funkcji. W wersji 4 tej biblioteki, która zostanie wydana data, ta funkcja wyrzuci ”. Użytkownicy, którzy nie zastosowali się do twojego poprzedniego ostrzeżenia, nadal otrzymują pomocny komunikat, który mówi im, jak rozwiązać problem, i muszą go naprawić, ponieważ teraz ich kod się nie kompiluje.
  • W wersji 4 zmieniasz tę funkcję, tak aby generowała fatalny wyjątek, i zmieniasz komunikat, aby powiedzieć, że funkcja zostanie całkowicie usunięta w następnej wersji.
  • W wersji 5 całkowicie usuwasz tę funkcję, a jeśli użytkownicy narzekają, cóż, dałeś im trzy cykle wydania sprawiedliwego ostrzeżenia, i zawsze mogą nadal używać wersji 2, jeśli mocno o tym myślą.

Chodzi tutaj o to, aby dokonać przełomowej zmiany tak bezboleśnie, jak to możliwe, dla użytkowników, których to dotyczy, i zapewnić, że będą mogli nadal korzystać z tej funkcji w co najmniej jednej wersji biblioteki.

Eric Lippert
źródło
2
Sądzę, że jest to właściwe podejście, ale zmieniłbym jedną rzecz ... zamieniłbym „jeśli użytkownicy narzekają” na „kiedy użytkownicy narzekają”
Liath,
10
Usunięcie ciała w tym samym czasie, co przejście na błąd, wydaje się dziwne. Jedną z zalet przestarzałej wersji błędu jest to, że umożliwia ona działanie kodu zbudowanego w oparciu o poprzednie wersje, jednocześnie uniemożliwiając korzystanie z niego przez nowo skompilowany kod. W ten sposób pozostajesz kompatybilny z ABI, jednocześnie celowo psując zgodność API. Oczywiście idealny świat miałbyś wersję w stylu semver itp., Tak że nigdy nie uruchomiłbyś nowego kodu z wcześniej skompilowaną aplikacją, ale wiele projektów nigdy nie osiągnęło tego ideału.
Kevin Cathcart,
@KevinCathcart: To dobra uwaga; może kolejny etap jest uzasadniony! Zaktualizuję tekst.
Eric Lippert,
1
W rzeczywistości, jeśli robisz SemVer, możesz przejść od przestarzałej wersji XY0 (każda przestarzała wersja musi być niewielka) do całkowicie usuniętej w X + 1.0.0. Powiedziałbym, że fajnie jest wstrzymać się nieco dalej (do X + 2.0.0?), Ale ten pięciostopniowy proces prawdopodobnie pozłaca lilię. Następnym krokiem po „ostrzeżeniu” powinien być „błąd krytyczny” (ponieważ przestarzała funkcja została zastąpiona kodem generującym błędy). Ponieważ libfoo.so.2i libfoo.so.3mogą współistnieć ze sobą w porządku, twój downstream może nadal używać starej biblioteki, dopóki nie zostanie przełączony.
Monty Harder
@MontyHarder: Jasne. Dokładną sekwencję zdarzeń można określić na podstawie potrzeb programisty i społeczności użytkowników. Najważniejsze jest jednak to, że powinna istnieć przemyślana polityka radzenia sobie z tego rodzaju problemami związanymi z wersją, która jest wyraźnie przekazywana interesariuszom.
Eric Lippert,
24

Źle zrozumiałeś, co oznacza „przestarzałe”. Przestarzałe oznacza:

być użyteczne, ale uważane za przestarzałe i najlepiej unikać, zwykle dlatego, że zostało zastąpione.

Słowniki Oxford

Z definicji przestarzała funkcja będzie się nadal kompilować.

Chcesz usunąć tę funkcję w określonym dniu. W porządku. W ten sposób usuwasz go w tym dniu .

Do tego czasu oznaczaj jako przestarzałe, przestarzałe lub jak to nazywa Twój język programowania. W wiadomości podaj datę, o której zostanie usunięty, oraz informację, która go zastępuje. Spowoduje to wygenerowanie ostrzeżeń, wskazujących, że inni programiści powinni unikać nowego użycia i w miarę możliwości zastępować stare użycie. Ci programiści albo zastosują się do niego, albo go zignorują i ktoś będzie musiał poradzić sobie z konsekwencjami tego, gdy zostanie on usunięty. (W zależności od sytuacji może to być Ty lub programiści.)

jpmc26
źródło
Zainteresowany tym, z czym nie zgadza się downvoter.
jpmc26
2
+1. Jeśli używasz JIRA do sprawnego programowania, utwórz zadanie i umieść je w przyszłym sprincie; dostosuj się do wszelkich innych narzędzi i metod zarządzania projektami, które stosujesz. Najlepiej to rozwiązać metodami nietechnicznymi.
Matthew
1
Upewnij się także, że Class / Lib pozostaje w dokumentacji jako amortyzowana i / lub usunięta w wersji Xx
Phil M
12

Nie zapominaj, że musisz zachować możliwość budowania i debugowania starszych wersji kodu, aby obsługiwać wersje oprogramowania, które zostały już wydane. Sabotowanie kompilacji po określonej dacie oznacza, że ​​ryzykujesz również, że nie będziesz w stanie wykonywać legalnych prac konserwacyjnych i wsparcia w przyszłości.

Wydaje się to również trywialnym obejściem, aby ustawić zegar mojej maszyny o rok lub dwa wstecz przed kompilacją.

Pamiętaj, że „przestarzałe” to ostrzeżenie, że coś zniknie w przyszłości. Jeśli chcesz zdecydowanie uniemożliwić innym użytkownikom korzystanie z tego interfejsu API, po prostu usuń powiązany kod . Nie ma sensu pozostawiać kodu w bazie kodu, jeśli jakiś mechanizm sprawia, że ​​jest on bezużyteczny. Usunięcie kodu zapewnia sprawdzanie czasu kompilacji, którego szukasz, i nie ma trywialnego obejścia.

Edycja: Widzę, że w swoim pytaniu masz na myśli „stary nieużywany kod”. Jeśli kod jest naprawdę nieużywany , nie ma sensu go zastępować. Po prostu go usuń.

bta
źródło
Jak dotąd najlepsza odpowiedź, być może podkreślenie, że usunięcie kodu jest najlepszym sposobem na rozwiązanie problemu wcześniej w odpowiedzi. Przewijanie obok ściany odpowiedzi tekstowych może być łatwe
Clint
6

Nigdy wcześniej nie widziałem takiej funkcji - adnotacji, która zaczyna obowiązywać po określonej dacie.

@DeprecatedMoże być wystarczająca, jednak. Złap ostrzeżenia w CI i niech odmówi zaakceptowania kompilacji, jeśli takie istnieją. Przenosi to odpowiedzialność z kompilatora na potok kompilacji, ale ma tę zaletę, że można (częściowo) łatwo zmienić potok kompilacji, dodając dodatkowe kroki.

Zauważ, że ta odpowiedź nie rozwiązuje w pełni twojego problemu (np. Lokalne kompilacje na komputerach programistów nadal by się powiodły, choć z ostrzeżeniami) i zakłada, że ​​masz skonfigurowany i uruchomiony potok CI.

Mael
źródło
4

Szukasz kalendarzy lub list rzeczy do zrobienia .

Inną alternatywą jest użycie niestandardowych ostrzeżeń kompilatora lub komunikatów kompilatora, jeśli zdołasz mieć kilka ostrzeżeń w bazie kodu. Jeśli masz zbyt wiele ostrzeżeń, musisz poświęcić dodatkowy wysiłek (około 15 minut?) I musisz odebrać ostrzeżenie kompilatora w raporcie kompilacji, który twoja ciągła integracja zapewnia dla każdej kompilacji.

Przypomnienia o konieczności naprawienia kodu są dobre i konieczne. Czasami te przypomnienia mają ściśle określone rzeczywiste terminy, więc może być konieczne także ich odmierzenie.

Celem jest ciągłe przypominanie ludziom, że problem istnieje i należy go naprawić w określonym przedziale czasowym - funkcja, która po prostu psuje kompilację w określonym czasie, nie tylko tego nie robi, ale sama funkcja jest problemem, który musi zostać naprawione w określonym przedziale czasowym.

Piotr
źródło
1
Zgodzić się. Ale jeśli problem istnieje i należy go naprawić w określonym czasie, musi on stać się priorytetem kogoś we właściwym czasie. Pamiętam, kiedy na spotkaniu mój menedżer przyznał mi „najwyższy priorytet”, a potem powiedział: „ To jest twój priorytet numer jeden” (coś innego). Mój przełożony powiedział: „Nie może mieć dwóch priorytetów numer jeden!” Kierownik był zaskoczony. Myślę, że myślał, że ... mógłbym. Planowanie czegoś, co zostanie naprawione „we właściwym czasie”, kończy się czasem.
3

Jednym ze sposobów myślenia o tym jest to, co rozumiesz przez czas / datę ? Komputery nie wiedzą, jakie są te pojęcia: trzeba je jakoś zaprogramować. Dość często reprezentuje się czasy w formacie UNIX „sekund od epoki” i często podaje się określoną wartość do programu za pomocą wywołań systemu operacyjnego. Jednak bez względu na to, jak powszechne jest to użycie, należy pamiętać, że nie jest to „rzeczywisty” czas: jest to tylko logiczna reprezentacja.

Jak zauważyli inni, jeśli zrobiłeś „termin” za pomocą tego mechanizmu, trywialne jest karmienie w innym czasie i przełamanie tego „terminu”. To samo dotyczy bardziej skomplikowanych mechanizmów, takich jak żądanie serwera NTP (nawet przez „bezpieczne” połączenie, ponieważ możemy zastąpić własne certyfikaty, urzędy certyfikacji, a nawet załatać biblioteki kryptograficzne). Na początku może się wydawać, że takie osoby są winne obejścia twojego mechanizmu, ale może się zdarzyć, że zrobi to automatycznie i nie bez powodu . Na przykład dobrym pomysłem jest posiadanie odtwarzalnych kompilacji , a narzędzia, które mogą to pomóc, mogą automatycznie resetować / przechwytywać takie niedeterministyczne wywołania systemowe. libfaketime robi dokładnie to,ustawia znaczniki czasu wszystkich plików na 1970-01-01 00:00:01, funkcja nagrywania / odtwarzania Qemu udaremnia wszelkie interakcje sprzętowe itp.

Jest to podobne do prawa Goodharta : jeśli uzależnisz zachowanie programu od czasu logicznego, wówczas czas logiczny przestanie być dobrą miarą „rzeczywistego” czasu. Innymi słowy, ludzie na ogół nie będą bałagać się zegarem systemowym, ale zrobią to, jeśli dasz im powód.

Istnieją inne logiczne reprezentacje czasu: jednym z nich jest wersja oprogramowania (aplikacja lub zależność). Jest to bardziej pożądana reprezentacja dla „ostatecznego terminu” niż np. Czas UNIX, ponieważ jest bardziej specyficzna dla rzeczy, na których Ci zależy (zmiana zestawów funkcji / interfejsów API), a zatem mniej prawdopodobne jest deptanie ortogonalnych problemów (np. Majstrowanie przy czasie UNIX do obejście terminu może spowodować uszkodzenie plików dziennika, zadań cron, pamięci podręcznych itp.).

Jak powiedzieli inni, jeśli kontrolujesz bibliotekę i chcesz „wypchnąć” tę zmianę, możesz wypchnąć nową wersję, która przestaje działać (powodując ostrzeżenia, aby pomóc konsumentom znaleźć i zaktualizować ich użycie), a następnie inną nową wersję, która usuwa funkcje całkowicie. Możesz je opublikować bezpośrednio po sobie, jeśli chcesz, ponieważ (ponownie) wersje są tylko logiczną reprezentacją czasu, nie muszą być powiązane z „faktycznym” czasem. Pomocna może być tutaj wersja semantyczna.

Alternatywnym modelem jest „pociągnięcie” zmiany. To jest jak Twój „plan B”: dodaj test do aplikacji konsumującej, która sprawdza, czy wersja tej zależności jest co najmniej nową wartością. Jak zwykle czerwony / zielony / refaktor do propagowania tej zmiany przez bazę kodu. Może to być bardziej odpowiednie, jeśli funkcjonalność nie jest „zła” lub „zła”, ale tylko „źle pasuje do tego przypadku użycia”.

Ważnym pytaniem związanym z podejściem „pull” jest to, czy wersja zależności liczy się jako „jednostka” ( funkcjonalności ), a zatem zasługuje na przetestowanie; czy to tylko „prywatna” szczegółów wdrażania, które powinny być wykonywane jedynie w ramach rzeczywistego urządzenia ( funkcjonalności ) testów. Powiedziałbym: jeśli różnica między wersjami zależności naprawdę liczy się jako funkcja twojej aplikacji, to wykonaj test (na przykład sprawdzając, czy wersja Pythona to> = 3.x). Jeśli nie, to nie rób tegododaj test (ponieważ będzie on kruchy, pozbawiony informacji i nadmiernie ograniczający); jeśli kontrolujesz bibliotekę, idź ścieżką „push”. Jeśli nie kontrolujesz biblioteki, po prostu użyj dowolnej dostarczonej wersji: jeśli testy przejdą pomyślnie, nie warto się ograniczać; jeśli nie przejdą, to właśnie tam jest twój „ostateczny termin”!

Istnieje inne podejście, jeśli chcesz zniechęcić do niektórych zastosowań funkcji zależności (np. Wywoływania niektórych funkcji, które nie działają dobrze z resztą kodu), zwłaszcza jeśli nie kontrolujesz zależności: zabroń standardów kodowania / zniechęcaj do korzystania z tych funkcji i dodawaj je do linera.

Każdy z nich będzie miał zastosowanie w różnych okolicznościach.

Warbo
źródło
1

Zarządzasz tym na poziomie pakietu lub biblioteki. Kontrolujesz pakiet i kontrolujesz jego widoczność. Możesz cofnąć widoczność. Widziałem to wewnętrznie w dużych firmach i ma to sens tylko w kulturach, które szanują własność pakietów, nawet jeśli pakiety są otwarte lub bezpłatne.

Jest to zawsze bałagan, ponieważ zespoły klientów po prostu nie chcą niczego zmieniać, więc często potrzebujesz kilku rund tylko białej listy, pracując z konkretnymi klientami, aby uzgodnić termin migracji, oferując im wsparcie.

djechlin
źródło
Podoba mi się część wsparcia. Wszystkie zmiany następują płynniej, przyjemniej i prawdopodobnie z mniejszymi trudnościami, jeśli osoby je promujące oferują wsparcie. Jest to częściowo efekt psychologiczny: dobre wsparcie jest oparte na współpracy; traktuje to wszystko poważnie. Natomiast zmiany narzucone z góry bez angażowania zainteresowanych sprawiają, że czują się ignorowani i nie chcą współpracować. (Chociaż życzliwość musi być połączona z nieugiętym dążeniem do wprowadzenia zmian).
Peter A. Schneider
1

Jednym z wymagań jest wprowadzenie pojęcia czasu do kompilacji. W C, C ++ lub innych językach systemami wykorzystującymi C-jak preprocesor / build 1 , można wprowadzić znacznik czasu poprzez określa dla preprocesora w czasie kompilacji: CPPFLAGS=-DTIMESTAMP()=$(date '+%s'). Prawdopodobnie stanie się tak w makefile.

W kodzie można by porównać ten token i spowodować błąd, jeśli czas się skończy. Zauważ, że użycie makra funkcji łapie przypadek, którego ktoś nie zdefiniował TIMESTAMP.

#if TIMESTAMP() == 0 || TIMESTAMP() > 1520616626
#   error "The time for this feature has run out, sorry"
#endif

Alternatywnie można po prostu „zdefiniować” dany kod, kiedy nadejdzie czas. Pozwoliłoby to na kompilację programu, pod warunkiem, że nikt go nie używa. Załóżmy, że mamy nagłówek definiujący interfejs API „api.h” i old()po pewnym czasie nie zezwalamy na wywołanie :

//...
void new1();
void new2();
#if TIMESTAMP() < 1520616626
   void old();
#endif
//...

Podobna konstrukcja prawdopodobnie wyeliminowałaby old()ciało funkcji z jakiegoś pliku źródłowego.

Oczywiście nie jest to głupi dowód; można po prostu zdefiniować stary TIMESTAMPna wypadek awaryjnej kompilacji w piątek wieczorem, o której mowa w innym miejscu. Ale myślę, że jest to raczej korzystne.

Działa to oczywiście tylko wtedy, gdy biblioteka jest ponownie kompilowana - po tym czasie przestarzały kod po prostu już nie istnieje w bibliotece. Nie zapobiegnie to jednak łączeniu się kodu klienta z przestarzałymi plikami binarnymi.


1 C # obsługuje tylko prostą definicję symboli preprocesora, bez wartości liczbowych, co sprawia, że ​​ta strategia nie jest wykonalna.

Peter A. Schneider
źródło
Warto również zauważyć, że ta definicja preprocesora wymusi TIMESTAMPrekompilację całego używanego kodu na każdej kompilacji. Obezwładni także narzędzia takie jak ccache. Oznacza to, że typowy czas kompilacji przyrostowych kompilacji znacznie się wydłuży w zależności od tego, na ile podstawy kodu wpływają funkcje przestarzałe w ten sposób.
mindriot
@mindriot To interesujący aspekt. Przypuszczam, że tak jest w przypadku każdej metody wprowadzającej pojęcie czasu do kodu - OP powiedział wyraźnie „po upływie określonej daty”. Można jednak poradzić sobie z aspektem czasu w systemie kompilacji i pozostawić kod w spokoju, prawda. Ale OP wyraźnie poprosił o „coś włożonego do kodu”. Moje rozwiązanie ma tę zaletę, że jest niezależne od konkretnej metody kompilacji. Można go oszukiwać, ale musisz się w ten sposób zaspokoić.
Peter A. Schneider,
Masz całkowitą rację. Twoje rozwiązanie tutaj jest zasadniczo jedynym, które zapewnia praktyczne rozwiązanie rzeczywistego pytania PO . Niemniej jednak uważałem, że ważne jest zwrócenie uwagi na minus. To do OP będzie ważyć zalety i wady. Myślę, że zdrowy środek można by nawet osiągnąć, powiedzmy, dzieląc TIMESTAMPwartość przez, powiedzmy, 86400, aby uzyskać codzienną ziarnistość, a zatem mniejszą liczbę ponownych kompilacji.
mindriot
0

W programie Visual Studio można skonfigurować skrypt przed kompilacją, który generuje błąd po określonej dacie. Zapobiegnie to kompilacji. Oto skrypt, który zgłasza błąd 12 marca 2018 r. Lub później ( pobrany stąd ):

@ECHO OFF

SET CutOffDate=2018-03-12

REM These indexes assume %DATE% is in format:
REM   Abr MM/DD/YYYY - ex. Sun 01/25/2015
SET TodayYear=%DATE:~10,4%
SET TodayMonth=%DATE:~4,2%
SET TodayDay=%DATE:~7,2%

REM Construct today's date to be in the same format as the CutOffDate.
REM Since the format is a comparable string, it will evaluate date orders.
IF %TodayYear%-%TodayMonth%-%TodayDay% GTR %CutOffDate% (
    ECHO Today is after the cut-off date.
    REM throw an error to prevent compilation
    EXIT /B 2
) ELSE (
    ECHO Today is on or before the cut-off date.
)

Przed użyciem tego skryptu przeczytaj pozostałe odpowiedzi na tej stronie.

user2023861
źródło
-1

Rozumiem cel tego, co próbujesz zrobić. Ale jak wspomniano inni, system kompilacji / kompilator prawdopodobnie nie jest odpowiednim miejscem do wymuszenia tego. Sugerowałbym, że bardziej naturalną warstwą do egzekwowania tej zasady są albo SCM, albo zmienne środowiskowe.

Jeśli zrobisz to drugie, w zasadzie dodaj flagę funkcji, która oznacza przebieg przed deprecjacją. Za każdym razem, gdy budujesz przestarzałą klasę lub wywołujesz przestarzałą metodę, zaznacz flagę funkcji. Po prostu zdefiniuj pojedynczą funkcję statyczną assertPreDeprecated()i dodaj ją do każdej przestarzałej ścieżki kodu. Jeśli jest ustawiony, zignoruj ​​potwierdzenia połączeń. Jeśli nie jest to wyjątek. Gdy data upłynie, odznacz flagę funkcji w środowisku wykonawczym. Wszelkie długotrwałe przestarzałe wywołania kodu pojawią się w logach środowiska wykonawczego.

W przypadku rozwiązania opartego na SCM założę, że używasz git i git-flow. (Jeśli nie, logikę można łatwo dostosować do innych VCS). Utwórz nowy oddział postDeprecated. W tej gałęzi usuń cały przestarzały kod i zacznij pracę nad usunięciem wszelkich referencji, aż się skompiluje. Wszelkie normalne zmiany są nadal wprowadzane w masteroddziale. Przechowywać łączenie Obojętnie Nie nieaktualnych związanych zmiany kodu w masterplecy w postDeprecatedcelu zminimalizowania problemów integracyjnych.

Po zakończeniu daty wycofania utwórz nowy preDeprecatedoddział z master. Następnie połączyć postDeprecatedz powrotem master. Zakładając, że Twoje wydanie wychodzi poza mastergałąź, powinieneś teraz używać nieaktualnej gałęzi po dacie. Jeśli zdarzy się nagły wypadek lub nie będziesz w stanie dostarczyć wyników na czas, zawsze możesz wycofać się preDeprecatedi wprowadzić niezbędne zmiany w tej gałęzi.

użytkownik79126
źródło
7
Takie podejście brzmi jak logistyczny koszmar. Jeśli zaczniesz utrzymywać prawie zduplikowane równoległe gałęzie, skończysz na tym poświęcając cały swój czas. Odpady ogółem.
Wyścigi lekkości na orbicie
6
Nie mogę się zgodzić, że utrzymywanie równoległych gałęzi, używanie jednej po prostu do usuwania przestarzałych funkcji wielu wersji, zanim rzeczywiście chcesz je usunąć z produktu, jest w jakikolwiek sposób „standardem branżowym”. Jaki jest tego cel? Tak, VCS może automatycznie wykonywać niektóre scalenia, ale scalanie należy wykonać okiem programisty, aby rozwiązać logiczne konflikty (a co się stanie, gdy pojawi się konflikt, którego nie można nawet rozwiązać leksykalnie?). Posiadanie systemu kompilacji w sposób arbitralny każdego dnia jest po prostu ... bezcelowe. Usuń funkcję, gdy nadejdzie czas jej usunięcia.
Wyścigi lekkości na orbicie
3
Ponieważ istnieje dobry powód, aby utrzymywać gałęzie wydania (cofanie ważnych poprawek). Nie ma dobrego powodu, aby utrzymywać oddział „coś, co mogę zrobić w przyszłości”. To narzut, bez korzyści. Proste.
Wyścigi lekkości na orbicie
4
Gdzie to dostałem? Jest to dosłownie definicja deprecjacji. Przestarzasz coś, co możesz usunąć w przyszłości. Nie ma zatem nieuczciwości, żadnego przesunięcia słupków bramki, a na pewno nie wymyśla się po prostu „wygrać spór”. To nie jest „podręcznikowy przypadek rozgałęzienia SCM” w jakiejkolwiek organizacji, dla której chcę pracować! Myślę, że będziemy musieli zgodzić się nie zgodzić. Miłego wieczoru!
Wyścigi lekkości na orbicie
2
@lightness - Istnieje wiele wiele powodów oficjalnie deprecjację kod nie jest po prostu „rzeczą jaką może zrobić, gdy mamy do niego obejść”. Być może przestarzały kod korzysta z biblioteki, w której odrzucane jest oficjalne wsparcie. Być może przestarzały kod to adres IP, którego licencja wygasa po określonej dacie. Może po podanej dacie pojawią się nowe przepisy, a kod nie będzie zgodny. Twoje rozwiązanie jest dobre i dobre, jeśli mieszkasz w wieży z kości słoniowej. Ale prawdziwe organizacje cały czas radzą sobie z tego rodzaju sytuacjami. Oprogramowanie musi zaspokajać potrzeby firmy, a nie odwrotnie.
user79126,