Verhindern, dass veralteter Code nach Ablauf einer Frist kompiliert wird [geschlossen]


68

In meinem Team haben wir viele alte Sachen in einem großen monolithischen Projekt aufgeräumt (ganze Klassen, Methoden usw.).

Während dieser Reinigungsarbeiten habe ich mich gefragt, ob es eine Art Annotation oder Bibliothek gibt, die schicker ist als üblich @Deprecated. Dies @FancyDeprecatedsollte verhindern, dass das Erstellen des Projekts erfolgreich ist, wenn Sie alten, nicht verwendeten Code nach Ablauf eines bestimmten Datums nicht bereinigt haben.

Ich habe im Internet gesucht und nichts gefunden, was die unten beschriebenen Funktionen aufweist:

  • sollte eine Anmerkung oder ähnliches in dem Code sein, den Sie vor einem bestimmten Datum löschen möchten
  • vor diesem Datum wird der Code kompiliert und alles wird normal funktionieren
  • Nach diesem Datum wird der Code nicht kompiliert und es wird eine Meldung angezeigt, die Sie über das Problem warnt

Ich glaube, ich bin auf der Suche nach einem Einhorn ... Gibt es eine ähnliche Technologie für eine Programmiersprache?

Als Plan überlege ich mir die Möglichkeit, die Magie mit einigen Unit-Tests des Codes, der entfernt werden soll, zu machen, die zum "Stichtag" anfangen zu scheitern. Was denkst du darüber? Irgendeine bessere Idee?


168
Die Abschreibung erfolgt für eine Version , nicht für ein Datum . Wenn Sie möchten, dass Benutzer veraltete Funktionen nicht mehr verwenden, geben Sie eine Version ohne sie frei. Das wird ihre Aufmerksamkeit erregen und sie können immer zurückrollen, wenn sie es noch nicht können. Viele Leute stecken in alten Versionen fest. Ihr Programm zu brechen ist nicht der richtige Weg.
Isanae

4
Plan B klingt solide. Mit den zusätzlichen Vorteilen, die Sie beim Komponententest angeben können, warum er veraltet ist. Das Hinzufügen des Kommentars zum Quellcode würde die Lesbarkeit in einem großen Monolithen nicht
verbessern

53
Das klingt nach einem wirklich bösen Einhorn. Sie haben eine Software, die sich gut kompilieren lässt, alle Tests besteht und die Sie an einen Kunden verschickt haben. Dann checken Sie eines Tages die Software erneut aus und sie wird auch auf genau derselben Entwicklungsplattform nicht erstellt. Sie sind jetzt gezwungen, Code zu ändern, der zuvor formale Tests bestanden hat, oder üble Hacks wie das Zurücksetzen der Computeruhr durchzuführen.
Simon B

6
Machen Sie es @ Deprecated_RemoveMe_2018_06_01 und löschen Sie dann am 2018-06-01 die Anmerkung selbst. Voila, all dein Code mit der Annotation wird nicht mehr kompiliert! (weil die Anmerkung nicht gefunden wird)
User253751

65
Jahre in der Zukunft wird ein neu eingestellter Entwickler fragen: Warum ist die Zeit auf dem Build-Server auf Januar 2016 eingestellt? Und der Typ, der seit 10 Jahren da ist, wird ihm sagen, dass es notwendig ist oder der Build an zufälligen Stellen abbricht. Seufzer.
Wilbert

Antworten:


62

Ich denke nicht, dass dies ein nützliches Feature wäre, wenn es das Kompilieren wirklich verbietet. Wenn am 01/06/2018 große Teile des Codes nicht kompiliert werden können, der am Vortag kompiliert wurde, wird Ihr Team diese Annotation schnell wieder entfernen, den Code bereinigen oder nicht.

Sie können jedoch dem Code eine benutzerdefinierte Anmerkung wie hinzufügen

@Deprecated_after_2018_07_31

Erstellen Sie ein kleines Tool, um nach diesen Anmerkungen zu suchen. (Ein einfacher Einzeiler in grep wird es tun, wenn Sie keine Reflektion verwenden möchten). In anderen Sprachen als Java kann ein für "grepping" geeigneter standardisierter Kommentar oder eine Präprozessordefinition verwendet werden.

Führen Sie das Tool dann kurz vor oder nach dem jeweiligen Datum aus. Wenn diese Anmerkung weiterhin angezeigt wird, erinnern Sie das Team daran, diese Codeteile dringend zu bereinigen.


9
@Bergi: Hey, dies ist nur ein Beispiel, OP kann Versionen oder Datums-Tags verwenden, was auch immer sie in ihrer Steuerung bevorzugen.
Doc Brown

4
Ich sehe keinen Vorteil darin, dies gegenüber der Verwendung der normalen Verfallsfeatures und der Anzeige der Compiler-Ausgabe zu dem bestimmten Datum zu tun. Es scheint, als würde die Entwicklerzeit schlecht genutzt, um etwas neu zu implementieren, das so ziemlich schon existiert. Selbst wenn Sie bereits eine Menge Warnungen haben (deren Bereinigung sich lohnen würde), können Sie den Compiler doch alle Warnungen in eine Textdatei ausspucken lassen und sie dann durchsuchen oder durchsuchen.
jpmc26

4
@jpaugh Ich empfehle, keine Stunden (Notiz, Zeit = Geld) in die Erstellung neuer Tools zu investieren, um Aufgaben zu erledigen, die Sie bereits mit vorhandenen Tools effizient ausführen können, unabhängig davon, um welche Tools es sich handelt.
jpmc26

3
@ jpmc26: Ich sehe zwei (kleine) Vorteile: Ich bekomme nicht jede Menge Verwerfungswarnungen (die die Gefahr bergen würden, wichtigere zu übersehen) und die Möglichkeit, verschiedene Verwerfungskriterien (Datumsangaben, Versionen, was auch immer) für verschiedene Codeabschnitte einzuführen. Darüber hinaus forderte das OP ausdrücklich die Kopplung des Verfalls mit einem Datum.
Doc Brown

7
Ich würde +1 geben, wenn Sie in Ihrem Beispiel nur die Reihenfolge JJJJ-MM-TT für das Datum verwenden würden, weil ich je gesehen habe, dass die mehrdeutige Reihenfolge ?? - ?? - JJJJ Schmerzen und Missverständnisse verursacht.
mtraceur

284

Dies würde ein Merkmal darstellen, das als Zeitbombe bekannt ist . KEINE ZEITBOMBEN ERSTELLEN.

Code, egal wie gut Sie ihn strukturieren und dokumentieren, wird zu einer missverstandenen, fast mythischen Black Box, wenn er über ein bestimmtes Alter hinaus lebt. Das Letzte, was irgendjemand in der Zukunft braucht, ist ein weiterer seltsamer Fehlermodus, der sie völlig überrascht, zum schlimmsten Zeitpunkt und ohne offensichtliche Abhilfe einfängt. Es gibt absolut keine Entschuldigung dafür, ein solches Problem absichtlich zu produzieren.

Betrachten Sie es so: Wenn Sie so gut organisiert sind und sich Ihrer Codebasis bewusst sind, dass Sie sich für die Veralterung interessieren und sich daran halten, brauchen Sie keinen Mechanismus im Code, der Sie daran erinnert. Andernfalls sind Sie möglicherweise auch in anderen Aspekten der Codebasis nicht auf dem neuesten Stand und können möglicherweise nicht rechtzeitig und korrekt auf den Alarm reagieren. Mit anderen Worten, Zeitbomben haben für niemanden einen guten Zweck. Sag einfach nein!


74
+1 Das wird dich beißen. Monate später. An einem Freitag, gerade als Sie versuchen, einen Noteinsatz durchzuführen. Und es ist ein langes Wochenende, also sind alle Leute, die etwas darüber wissen, aus dem Büro. Tu es nicht.
Roger Lipscombe

3
Zustimmen. Obsoleszenz ist ein organisatorisches Problem, kein Codierungsproblem. Ich könnte immer noch einen Apple einstecken und BASIC schreiben, nichts hindert mich daran. Aber würde ich wollen ?

19
Die richtige Lösung, die Ihrer "organisierten und bewussten" Richtung entspricht, besteht darin, einen Fehler in Ihrem Fehlerverfolgungssystem zu melden, indem Sie in den Kommentaren "<so und so> entfernen>" mit einem vorgeschlagenen Zeitrahmen angeben. Und dann, in 6 Monaten, wenn die Fehlerüberprüfung auftaucht, um herauszufinden, welche Fehler in der nächsten Version behoben werden sollen, sagen Sie, wenn dieser Zeitrahmen unmittelbar bevorsteht, "es ist Zeit, dies zu tun". Es ist grundlegendes Projektmanagement.
Leichtigkeit Rennen im Orbit

1
In der Tat, wenn Ihr Release-Zeitplan ausreichend vorhersehbar ist, setzen Sie jetzt einen Meilenstein.
Leichtigkeit Rennen im Orbit

13
In Isanaes Kommentar finden Sie eine Alternative: " Wenn Sie möchten , dass Benutzer veraltete Funktionen nicht mehr verwenden, geben Sie eine Version ohne sie frei. Dies wird ihre Aufmerksamkeit auf sich ziehen und sie können immer einen Rollback durchführen, wenn sie dies noch nicht können. "
Stevoisiak

70

In C # würden Sie ObsoleteAttributefolgendermaßen vorgehen:

  • In Version 1 wird die Funktion ausgeliefert. Eine Methode, eine Klasse, was auch immer.
  • In Version 2 wird eine bessere Funktion ausgeliefert, die die ursprüngliche Funktion ersetzen soll. Sie fügen der Funktion ein veraltetes Attribut hinzu, setzen es auf "Warnung" und geben eine Meldung aus, die besagt: "Diese Funktion ist veraltet. Verwenden Sie stattdessen die bessere Funktion. In Version 3 dieser Bibliothek, die auf solchen und solchen veröffentlicht wird." Wenn Sie ein Datum eingeben, ist die Verwendung dieser Funktion ein Fehler. " Jetzt können Benutzer der Funktion diese weiterhin verwenden, haben jedoch Zeit, ihren Code zu aktualisieren, um die neue Funktion zu verwenden.
  • In Version 3 aktualisieren Sie das Attribut so, dass es eher ein Fehler als eine Warnung ist, und aktualisieren die Meldung mit dem Hinweis "Diese Funktion ist veraltet. Verwenden Sie stattdessen die bessere Funktion. In Version 4 dieser Bibliothek, die auf solchen und solchen Systemen veröffentlicht wird ein Datum, das diese Funktion auslöst. " Benutzer, die Ihre vorherige Warnung nicht beachtet haben, erhalten weiterhin eine hilfreiche Meldung, in der sie erfahren, wie das Problem behoben werden kann. Sie müssen sie beheben, da ihr Code jetzt nicht kompiliert werden kann.
  • In Version 4 ändern Sie das Feature so, dass es eine schwerwiegende Ausnahme auslöst, und ändern die Meldung, dass das Feature in der nächsten Version vollständig entfernt wird.
  • In Version 5 entfernen Sie die Funktion vollständig, und wenn sich die Benutzer beschweren, haben Sie ihnen drei Release-Zyklen mit angemessenen Warnungen gegeben. Sie können Version 2 immer weiter verwenden, wenn sie dies sehr zu schätzen wissen.

Die Idee dabei ist, eine grundlegende Änderung für die betroffenen Benutzer so einfach wie möglich zu gestalten und sicherzustellen, dass sie die Funktion für mindestens eine Version der Bibliothek weiterhin verwenden können.


2
Ich glaube, das ist der richtige Ansatz, aber ich würde eine Sache ändern ... das wäre "wenn Benutzer sich beschweren" zu "wenn Benutzer sich beschweren" zu tauschen
Liath

10
Das Entfernen des Körpers zur gleichen Zeit wie das Umschalten auf einen Fehler erscheint seltsam. Einer der Vorteile der Fehlerversion von Veraltet ist, dass Code, der mit früheren Versionen erstellt wurde, weiterhin funktioniert, während neu kompilierter Code daran gehindert wird, ihn zu verwenden. So bleiben Sie ABI-kompatibel und brechen absichtlich die API-Kompatibilität. In der perfekten Welt hätten Sie natürlich eine Versionierung im Semesterstil usw., sodass Sie den neuen Code nie mit einer zuvor kompilierten Anwendung ausführen würden, aber viele Projekte erreichen dieses Ideal nie.
Kevin Cathcart

@ KevinCathcart: Das ist ein guter Punkt; Vielleicht ist eine weitere Etappe angesagt! Ich werde den Text aktualisieren.
Eric Lippert

1
Wenn Sie SemVer ausführen, können Sie direkt von der veralteten Version XY0 (bei der es sich um eine Nebenversion handeln muss) zu der vollständig entfernten Version X + 1.0.0 wechseln. Ich würde sagen, es ist schön, etwas länger zu warten (auf X + 2.0.0?), Aber dieser fünfstufige Prozess vergoldet wahrscheinlich die Lilie. Der nächste Schritt nach "Warnung" sollte "schwerwiegender Fehler" sein (da die veraltete Funktion durch den fehlererzeugenden Code ersetzt wird). Da libfoo.so.2und libfoo.so.3können gut miteinander koexistieren, können Ihre Downstreams weiterhin die alte Bibliothek verwenden, bis sie umgeschaltet werden.
Monty Harder

@MontyHarder: Sicher. Die genaue Reihenfolge der Ereignisse kann von den Bedürfnissen des Entwicklers und seiner Benutzergemeinschaft bestimmt werden. Der größere Punkt ist jedoch, dass es eine durchdachte Richtlinie für den Umgang mit dieser Art von Versionsproblemen geben sollte, die den Stakeholdern klar mitgeteilt wird.
Eric Lippert

24

Sie haben falsch verstanden, was "veraltet" bedeutet. Veraltet bedeutet:

verwendbar sein, aber als veraltet angesehen und am besten vermieden werden, normalerweise, weil es ersetzt wurde.

Oxford Wörterbücher

Per Definition wird ein veraltetes Feature immer noch kompiliert.

Sie möchten die Funktion an einem bestimmten Datum entfernen . Das ist gut. Auf diese Weise entfernen Sie es an diesem Datum .

Markieren Sie es bis dahin als veraltet, veraltet oder wie auch immer Ihre Programmiersprache es nennt. Geben Sie in der Nachricht das Datum an, an dem sie entfernt wird, und das Datum, an dem sie ersetzt wird. Dadurch werden Warnungen generiert, die darauf hinweisen, dass andere Entwickler eine neue Verwendung vermeiden und die alte nach Möglichkeit ersetzen sollten. Diese Entwickler werden es entweder einhalten oder ignorieren, und jemand wird sich mit den Konsequenzen davon auseinandersetzen müssen, wenn es entfernt wird. (Abhängig von der Situation sind es möglicherweise Sie oder die Entwickler, die es verwenden.)


Interessiert an dem, was der Downvoter nicht meint.
jpmc26

2
+1. Wenn Sie JIRA für die agile Entwicklung verwenden, erstellen Sie eine Aufgabe und nehmen Sie sie in einen zukünftigen Sprint auf. Passen Sie sich an alle anderen Projektmanagement-Tools und -Methoden an, denen Sie folgen. Dies lässt sich am besten mit nichttechnischen Methoden lösen.
Matthew Read

1
Stellen Sie außerdem sicher, dass die Klasse / Bibliothek in der Dokumentation als nicht mehr empfohlen und / oder entfernt in Version Xx
Phil M

12

Vergessen Sie nicht, dass Sie die Fähigkeit behalten müssen, ältere Versionen des Codes zu erstellen und zu debuggen, um bereits veröffentlichte Versionen der Software zu unterstützen. Wenn Sie einen Build nach einem bestimmten Datum sabotieren, riskieren Sie auch, dass Sie in Zukunft keine legitimen Wartungs- und Supportarbeiten mehr durchführen.

Außerdem scheint es eine triviale Lösung zu sein, die Uhr meines Computers ein oder zwei Jahre vor dem Kompilieren zurückzusetzen.

Denken Sie daran, "veraltet" ist eine Warnung, dass in Zukunft etwas weggehen wird. Wenn Sie verhindern möchten, dass Benutzer diese API verwenden, entfernen Sie einfach den zugehörigen Code . Es hat keinen Sinn, Code in der Codebasis zu belassen, wenn ein Mechanismus ihn unbrauchbar macht. Wenn Sie den Code entfernen, erhalten Sie die gesuchten Überprüfungen zur Kompilierungszeit und haben keine triviale Problemumgehung.

Bearbeiten: Ich sehe, dass Sie in Ihrer Frage auf "alten unbenutzten Code" verweisen. Wenn der Code wirklich nicht verwendet wird , macht es keinen Sinn, ihn zu missbrauchen. Löschen Sie es einfach.


Die mit Abstand beste Antwort. Vielleicht möchten Sie betonen, dass das Löschen des Codes der beste Weg ist, um das Problem in Ihrer Antwort schneller zu lösen. Es kann einfach sein, an einer Wand mit Textantworten vorbei zu scrollen
Clint

6

Ich habe noch nie zuvor eine solche Funktion gesehen - eine Anmerkung, die nach einem bestimmten Datum wirksam wird.

Das @Deprecatedkann aber ausreichen. Fangen Sie Warnungen in CI ab und lehnen Sie ab, den Build zu akzeptieren, falls vorhanden. Dies verlagert die Verantwortung vom Compiler auf Ihre Build-Pipeline, hat jedoch den Vorteil, dass Sie die Build-Pipeline (halb) einfach ändern können, indem Sie zusätzliche Schritte hinzufügen.

Beachten Sie, dass diese Antwort Ihr Problem nicht vollständig löst (z. B. würden lokale Builds auf Entwicklermaschinen trotz Warnungen weiterhin erfolgreich sein) und davon ausgehen, dass eine CI-Pipeline eingerichtet und ausgeführt wird.


4

Sie suchen nach Kalendern oder Aufgabenlisten .

Eine andere Alternative besteht darin, benutzerdefinierte Compiler-Warnungen oder Compiler-Meldungen zu verwenden, wenn Sie nur wenige oder gar keine Warnungen in Ihrer Codebasis haben. Wenn Sie zu viele Warnungen haben, müssen Sie zusätzliche Anstrengungen unternehmen (etwa 15 Minuten?) Und die Compiler-Warnung im Build-Bericht aufgreifen, die Ihre fortlaufende Integration für jeden Build liefert.

Erinnerungen, dass Code repariert werden muss, sind gut und notwendig. Manchmal haben diese Erinnerungen strenge reale Fristen, so dass es auch notwendig sein kann, sie auf einen Timer zu setzen.

Das Ziel ist es, die Leute kontinuierlich daran zu erinnern, dass das Problem besteht und innerhalb eines bestimmten Zeitrahmens behoben werden muss - eine Funktion, die den Build zu einem bestimmten Zeitpunkt einfach abbricht, erledigt dies nicht nur, sondern diese Funktion ist selbst ein Problem, das behoben werden muss innerhalb eines bestimmten Zeitrahmens festgelegt werden.


1
Zustimmen. Wenn jedoch ein Problem besteht und innerhalb eines bestimmten Zeitraums behoben werden muss, muss es zur richtigen Zeit zur obersten Priorität einer Person werden. Ich erinnere mich, dass mein Vorgesetzter mir in einer Besprechung eine "oberste Priorität" gab und später sagte: " Dies ist Ihre oberste Priorität" (etwas anderes). Mein Vorgesetzter sagte: "Er kann nicht zwei Prioritäten haben!" Der Manager erschrak. Ich denke, er dachte, dass ... ich könnte. Planen, dass etwas "zur richtigen Zeit" repariert wird, bedeutet, dass die Zeit knapp wird.

3

Eine Möglichkeit, darüber nachzudenken, ist, was Sie unter Zeit / Datum verstehen . Computer wissen nicht, was diese Konzepte sind: Sie müssen irgendwie programmiert werden. Es ist durchaus üblich, Zeiten im UNIX-Format "Sekunden seit der Epoche" darzustellen , und es ist üblich, einen bestimmten Wert über Betriebssystemaufrufe in ein Programm einzugeben. Unabhängig davon, wie häufig diese Verwendung verwendet wird, ist es wichtig zu berücksichtigen, dass es sich nicht um die "tatsächliche" Zeit handelt, sondern nur um eine logische Darstellung.

Wie andere darauf hingewiesen haben, ist es trivial, eine andere Zeit einzugeben und diese "Frist" zu überschreiten, wenn Sie mit diesem Mechanismus eine "Frist" festgelegt haben. Das gleiche gilt für aufwändigere Mechanismen wie das Fragen an einen NTP-Server (auch über eine "sichere" Verbindung, da wir unsere eigenen Zertifikate, Zertifizierungsstellen oder sogar die Kryptobibliotheken ersetzen können). Auf den ersten Blick mag es so aussehen, als ob solche Personen daran schuld sind, an Ihrem Mechanismus herumzuarbeiten, aber es kann sein, dass dies automatisch und aus guten Gründen geschieht . Zum Beispiel ist es eine gute Idee, reproduzierbare Builds zu haben , und Tools, die dies unterstützen, könnten solche nicht deterministischen Systemaufrufe automatisch zurücksetzen / abfangen. libfaketime macht genau das,1970-01-01 00:00:01Setzt alle Zeitstempel der Datei auf , die Aufnahme- / Wiedergabefunktion von Qemu fälscht alle Hardware-Interaktionen usw.

Dies ähnelt dem Goodhartschen Gesetz : Wenn Sie das Verhalten eines Programms von der logischen Zeit abhängig machen, ist die logische Zeit kein gutes Maß für die "tatsächliche" Zeit mehr. Mit anderen Worten, die Leute werden sich im Allgemeinen nicht mit der Systemuhr anlegen, aber sie werden es tun, wenn Sie ihnen einen Grund dafür geben.

Es gibt andere logische Darstellungen der Zeit: Eine davon ist die Version der Software (entweder Ihre App oder eine Abhängigkeit). Dies ist eine wünschenswertere Darstellung für eine "Frist" als z. B. die UNIX-Zeit, da sie spezifischer für das ist, was Sie interessieren (Ändern von Feature-Sets / APIs) und daher weniger wahrscheinlich auf orthogonalen Bedenken herumtrampeln (z. B. mit der UNIX-Zeit herumspielen) Die Umgehung Ihrer Frist kann dazu führen, dass Protokolldateien, Cronjobs, Caches usw. beschädigt werden.

Wie andere bereits gesagt haben, können Sie, wenn Sie die Bibliothek steuern und diese Änderung "pushen" möchten, eine neue Version pushen, die die Funktionen nicht mehr unterstützt (was zu Warnungen führt, um den Verbrauchern das Auffinden und Aktualisieren ihrer Verwendung zu erleichtern) Funktionen vollständig. Sie können diese sofort nacheinander veröffentlichen, wenn Sie möchten, da (wieder) Versionen lediglich eine logische Darstellung der Zeit sind, müssen sie nicht mit der "tatsächlichen" Zeit zusammenhängen. Die semantische Versionierung kann hier Abhilfe schaffen.

Das alternative Modell ist das "Ziehen" der Änderung. Dies ähnelt Ihrem "Plan B": Fügen Sie der konsumierenden Anwendung einen Test hinzu, der überprüft, ob die Version dieser Abhängigkeit mindestens dem neuen Wert entspricht. Wie üblich, Rot / Grün / Refaktor, um diese Änderung durch die Codebasis zu verbreiten. Dies ist möglicherweise angemessener, wenn die Funktionalität nicht "schlecht" oder "falsch" ist, sondern nur "schlecht für diesen Anwendungsfall geeignet".

Eine wichtige Frage beim "Pull" -Ansatz ist, ob die Abhängigkeitsversion als "Einheit" ( der Funktionalität ) gilt oder nicht und daher einen Test verdient. oder ob es sich nur um ein "privates" Implementierungsdetail handelt, das nur im Rahmen tatsächlicher Unit ( of Functional ) -Tests ausgeführt werden sollte. Ich würde sagen: Wenn die Unterscheidung zwischen den Versionen der Abhängigkeit wirklich als Merkmal Ihrer Anwendung gilt, führen Sie den Test durch (überprüfen Sie beispielsweise, ob die Python-Version> = 3.x ist). Wenn nicht, dann nichtFügen Sie den Test hinzu (da er spröde, nicht aussagekräftig und zu restriktiv ist). Wenn Sie die Bibliothek kontrollieren, gehen Sie die "Push" -Route hinunter. Wenn Sie die Bibliothek nicht kontrollieren, verwenden Sie einfach die mitgelieferte Version: Wenn Ihre Tests erfolgreich sind, lohnt es sich nicht, sich einzuschränken. Wenn sie nicht bestehen, ist das genau dort Ihre "Frist"!

Es gibt einen anderen Ansatz, wenn Sie bestimmte Verwendungszwecke der Funktionen einer Abhängigkeit verhindern möchten (z. B. das Aufrufen bestimmter Funktionen, die mit dem Rest Ihres Codes nicht gut funktionieren), insbesondere, wenn Sie die Abhängigkeit nicht kontrollieren: Lassen Sie Ihre Codierungsstandards verbieten Ich rate von der Verwendung dieser Funktionen ab und füge Ihrem Linter Überprüfungen hinzu.

Jedes von diesen ist unter verschiedenen Umständen anwendbar.


1

Sie verwalten dies auf Paket- oder Bibliotheksebene. Sie steuern ein Paket und dessen Sichtbarkeit. Sie können die Sichtbarkeit zurückziehen. Ich habe dies intern bei großen Unternehmen gesehen und es ist nur in Kulturen sinnvoll, die das Eigentum an Paketen respektieren, selbst wenn die Pakete Open Source sind oder frei verwendet werden können.

Dies ist immer problematisch, da die Kundenteams einfach nichts ändern möchten. Daher benötigen Sie häufig einige Runden der Whitelist, wenn Sie mit den jeweiligen Kunden zusammenarbeiten, um eine Frist für die Migration zu vereinbaren und ihnen möglicherweise Unterstützung anzubieten.


Ich mag den Support-Teil. Alle Veränderungen verlaufen reibungsloser, angenehmer und wahrscheinlich mit weniger Schwierigkeiten, wenn die sie fördernden Personen Unterstützung anbieten. Das ist zum Teil ein psychologischer Effekt: Gute Unterstützung ist kooperativ; es nimmt alle Beteiligten ernst. Im Gegensatz dazu fühlen sich von oben auferlegte Änderungen, ohne die Betroffenen einzubeziehen, ignoriert und unkooperativ. (Obwohl die Freundlichkeit mit einem unerbittlichen Antrieb gepaart werden muss, um die Änderungen durchzuhalten.)
Peter - Monica

1

Eine Anforderung besteht darin, einen Zeitbegriff in den Build einzuführen. In C, C ++ oder anderen Sprachen / baut Systeme , die eine C-ähnliche Präprozessor verwenden 1 , könnte man einen Zeitstempel durch definiert für den Preprozessor auf Kompilierzeit vorstellen: CPPFLAGS=-DTIMESTAMP()=$(date '+%s'). Dies würde wahrscheinlich in einem Makefile passieren.

Im Code würde man dieses Token vergleichen und einen Fehler verursachen, wenn die Zeit abgelaufen ist. Beachten Sie, dass die Verwendung eines Funktionsmakros den Fall abfängt, den jemand nicht definiert hat TIMESTAMP.

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

Alternativ könnte man den fraglichen Code einfach "definieren", wenn die Zeit gekommen ist. Das würde das Programm kompilieren lassen, vorausgesetzt, niemand benutzt es. Angenommen, wir haben einen Header, der eine API definiert, "api.h", und wir erlauben old()nach einer bestimmten Zeit keinen Aufruf mehr :

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

Ein ähnliches Konstrukt würde wahrscheinlich den old()Funktionskörper von einer Quelldatei entfernen.

Natürlich ist dies kein Narrensicher. man kann einfach ein altes TIMESTAMPfür den an anderer Stelle erwähnten Freitag-Nacht-Notfallbau definieren . Aber das finde ich ziemlich vorteilhaft.

Dies funktioniert natürlich nur, wenn die Bibliothek neu kompiliert wird - danach existiert der veraltete Code einfach nicht mehr in der Bibliothek. Es würde jedoch nicht verhindern, dass der Client-Code mit veralteten Binärdateien verknüpft wird.


1 C # unterstützt nur die einfache Definition von Präprozessorsymbolen, keine numerischen Werte, wodurch diese Strategie nicht praktikabel ist.


Es ist auch erwähnenswert, dass diese Präprozessordefinition erzwingt, dass der gesamte verwendete Code TIMESTAMPbei jedem Build neu kompiliert wird. Es wird auch Werkzeuge wie außer Gefecht setzen ccache. Dies bedeutet, dass die typische Kompilierungszeit für inkrementelle Builds erheblich zunimmt, je nachdem, wie stark die Codebasis von Funktionen betroffen ist, die auf diese Weise veraltet sind.
Mindriot

@mindriot Das ist ein interessanter Aspekt. Ich nehme an, dass dies bei jeder Methode zutrifft, die einen Zeitbegriff in den Code einführt - das OP sagte explizit "nachdem ein bestimmtes Datum verstrichen ist". Man könnte jedoch den Zeitaspekt im Build-System behandeln und den Code in Ruhe lassen, wahr. Das OP forderte jedoch ausdrücklich "etwas, das in den Code eingefügt wurde". Meine Lösung hat den Vorteil, unabhängig von einer bestimmten Erstellungsmethode zu sein. Es kann betrogen werden, aber man muss es auf die eine oder andere Weise befriedigen.
Peter - Reinstate Monica

Du hast absolut recht. Ihre Lösung hier ist im Wesentlichen die einzige, die eine praktische Lösung für die eigentliche Frage des OP bietet . Trotzdem fand ich es wichtig, auf den Nachteil hinzuweisen. Es liegt an der OP, die Vor- und Nachteile abzuwägen. Ich denke, ein gesunder Mittelweg könnte sogar erreicht werden, indem beispielsweise der TIMESTAMPWert durch 86400 dividiert wird, um eine tägliche Granularität und damit weniger Neukompilierungen zu erzielen .
Mindriot

0

In Visual Studio können Sie ein vorab erstelltes Skript einrichten, das nach einem bestimmten Datum einen Fehler auslöst. Dies verhindert das Kompilieren. Hier ist ein Skript, das am oder nach dem 12. März 2018 einen Fehler auslöst ( von hier übernommen ):

@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.
)

Lesen Sie die anderen Antworten auf dieser Seite, bevor Sie dieses Skript verwenden.


-1

Ich verstehe das Ziel dessen, was Sie versuchen zu tun. Aber wie andere bereits erwähnt haben, ist das Build-System / der Compiler wahrscheinlich nicht der richtige Ort, um dies durchzusetzen. Ich würde vorschlagen, dass die natürlichere Ebene zur Durchsetzung dieser Richtlinie entweder die SCM- oder die Umgebungsvariablen ist.

Wenn Sie Letzteres tun, fügen Sie im Grunde genommen ein Feature-Flag hinzu, das einen Vor-Verfalls-Lauf kennzeichnet. Überprüfen Sie jedes Mal, wenn Sie die veraltete Klasse erstellen oder eine veraltete Methode aufrufen, das Feature-Flag. Definieren Sie einfach eine einzelne statische Funktion assertPreDeprecated()und fügen Sie diese jedem veralteten Codepfad hinzu. Wenn dies festgelegt ist, ignorieren Sie Assert-Aufrufe. Wenn es keine Ausnahme gibt. Wenn das Datum abgelaufen ist, deaktivieren Sie das Feature-Flag in der Laufzeitumgebung. Veraltete Aufrufe des Codes werden in den Laufzeitprotokollen angezeigt.

Für eine SCM-basierte Lösung gehe ich davon aus, dass Sie Git und Git-Flow verwenden. (Wenn nicht, ist die Logik leicht an andere VCS anpassbar). Erstellen Sie eine neue Niederlassung postDeprecated. Löschen Sie in diesem Zweig den gesamten veralteten Code und beginnen Sie mit dem Entfernen aller Verweise, bis dieser kompiliert ist. Alle normalen Änderungen werden weiterhin an der masterZweigstelle vorgenommen. Führen Sie alle nicht veralteten Codeänderungen masterwieder in zusammen, postDeprecatedum die Integrationsprobleme zu minimieren.

Erstellen Sie nach Ablauf des Verfallsdatums einen neuen preDeprecatedZweig von master. Dann postDeprecatedwieder zusammenführen in master. Angenommen, Ihre Freigabe verlässt den masterZweig, sollten Sie jetzt den nach dem Datum veralteten Zweig verwenden. Wenn es einen Notfall gibt oder Sie die Ergebnisse nicht rechtzeitig bereitstellen können, können Sie jederzeit zu preDeprecateddiesem Zweig zurückkehren und die erforderlichen Änderungen vornehmen.


7
Dieser Ansatz klingt nach einem logistischen Albtraum. Wenn Sie anfangen, nahezu doppelte parallele Zweige zu pflegen, verbringen Sie am Ende Ihre ganze Zeit damit. Gesamtmüll.
Leichtigkeit Rennen im Orbit

6
Ich kann nicht zustimmen, dass die Beibehaltung paralleler Verzweigungen, bei denen nur eine verwendet wird, um veraltete Funktionen in vielen Versionen zu entfernen, bevor Sie sie tatsächlich aus dem Produkt entfernen möchten, in irgendeiner Weise "Industriestandard" ist. Was ist der Zweck davon? Ja, ein VCS kann einige Zusammenführungen automatisch durchführen, aber eine Zusammenführung sollte mit dem Auge eines Entwicklers durchgeführt werden, um logische Konflikte zu lösen (und was passiert, wenn ein Konflikt auftritt, der nicht einmal lexikalisch gelöst werden kann?). Es ist einfach ... sinnlos, wenn ein Build-System jeden Tag willkürlich zusammengeführt wird. Entfernen Sie das Feature, wenn es Zeit ist, es zu entfernen.
Leichtigkeit Rennen im Orbit

3
Weil es einen guten Grund gibt, Release-Zweige beizubehalten (die wichtige Patches zurückportieren). Es gibt keinen guten Grund, eine Branche zu unterhalten, die "etwas ist, was ich in Zukunft tun könnte". Es ist Overhead, ohne Nutzen. So einfach ist das.
Leichtigkeit Rennen im Orbit

4
Wo habe ich es bekommen? Es ist buchstäblich die Definition von Verfall. Sie missbilligen etwas, das Sie möglicherweise in Zukunft entfernen werden. Somit gibt es keine Unaufrichtigkeit, kein Verschieben der Torpfosten und sicher kein Ausdenken, nur "um das Argument zu gewinnen". Dies ist kein "Lehrbuch-Anwendungsfall für SCM-Verzweigungen" in einer Organisation, für die ich arbeiten möchte! Ich denke, wir müssen uns einigen, wenn wir nicht einverstanden sind. Hab einen schönen Abend!
Leichtigkeitsrennen im Orbit

2
@lightness - Es gibt viele Gründe, warum es nicht einfach ist, Code offiziell abzulehnen, "was wir tun könnten , wenn wir dazu kommen". Möglicherweise verwendet der veraltete Code eine Bibliothek, in der die offizielle Unterstützung eingestellt wird. Möglicherweise ist der veraltete Code IP, dessen Lizenz nach einem festgelegten Datum abläuft. Möglicherweise gibt es nach dem angegebenen Datum neue Vorschriften, und der Code ist nicht konform. Ihre Lösung ist gut und schön, wenn Sie in einem Elfenbeinturm leben. Aber echte Organisationen beschäftigen sich die ganze Zeit mit solchen Situationen. Software muss die Anforderungen des Unternehmens erfüllen, nicht umgekehrt.
User79126
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.