So kennzeichnen Sie eine Klasse in Java als in Entwicklung

12

Ich arbeite an einem Praktikumsprojekt, aber ich muss gehen, bevor ich alles beenden kann.

Ich habe eine Klasse, die nicht stabil genug für die Produktion ist. Ich möchte diese Klasse markieren / kennzeichnen, damit andere sie nicht versehentlich in der Produktion verwenden. Ich habe den Hinweis bereits in Javadoc abgelegt, aber das scheint nicht genug zu sein. Ein Compilerfehler oder eine Warnung wäre besser.

Der Code ist folgendermaßen aufgebaut:

[Package] | company.foo.bar.myproject
          |-- Class1.java
          |-- Class2.java
          |-- Class3.java <--(not stable)

Wenn es eine einzelne Factory-Klasse gegeben hätte, die diese Klassen in öffentlichen Methoden aufruft, hätte ich die Methode auf class3as setzen können private. Die API wird jedoch NICHT auf diese Weise verfügbar gemacht. Benutzer werden diese Klasse direkt verwenden new Class1();, aber ich kann eine Klasse der obersten Ebene nicht als privat kennzeichnen. Was ist die beste Vorgehensweise, um mit dieser Situation umzugehen?

Wei Shi
quelle
1
Was meinen Sie mit "Die API wird nicht durch Methoden verfügbar gemacht?" Soll diese Klasse über die Reflection-API verwendet werden?
Tom G
5
Ein Compilerfehler? Warum nicht einfach eine Ausnahme im Konstruktor auslösen?
Mchl
Entschuldigung für die Verwirrung. Ich habe meinen Beitrag bearbeitet.
Wei Shi
1
Sie können die Klasse nicht privat machen, aber Sie können ihren Konstruktor privat machen.
Peter Taylor

Antworten:

15

Warum checken Sie nicht einfach alle instabilen Klassen in einem anderen Zweig Ihres Versionskontrollsystems ein?

Andrew Moss
quelle
2
Mir scheint, das würde den Code "verstecken". Was ist, wenn der Code fast das tut, was andere für kleinere Optimierungen benötigen? Wenn Sie es in einen Zweig stellen, sehen sie es möglicherweise nie und implementieren das Ganze einfach neu.
c_maker
3
@c_maker: Anderen mitteilen, dass der Zweig existiert und was darin enthalten ist, sollte ein Teil dessen sein, was weitergegeben wird, wenn er geht.
Blrfl
2
@Birlf Wenn er sich Sorgen macht, dass andere die Erklärung des verwendeten Codes im JavaDoc nicht sehen, bezweifle ich, dass sie nach der anderen Dokumentation suchen, die er produziert.
KeithB
Ich befürchte, dass sich die Funktion noch weiterentwickelt, aber der Scrum-Master hat sie aus irgendeinem Grund aufgehoben (in unserem Fall ein Moratorium, das E2E-Tests blockiert). Wenn wir es nicht schaffen, es zu meistern, wird es möglicherweise eine Menge Zusammenführungsarbeit geben. Wir haben nur die c`tor privat, und kommentierte die Klasse @Experimental, wie Spark
joey baruch
11

Wenn Sie die Klasse richtig kommentiert haben, können Sie die Teile unvollständiger Funktionalität als "veraltet" markieren und die Eingeweide der Methode auskommentieren und ein throw new UnsupportedOperationException();.

Siehe Gibt es etwas Ähnliches wie die NotImplementedException von .NET in Java? für Details.

Heath Lilley
quelle
2
Dies ist die defacto Art und Weise, mit Witzschlägen umzugehen, wie ich die Dinge verstehe
Martijn Verburg,
4

Ich kenne eine solche Compiler-Warnung nicht.

In Ihrer Situation würde ich wahrscheinlich die @DeprecatedAnmerkung verwenden. Es werden Methodenaufrufe durchgestrichen, sodass den anderen klar ist, dass etwas nicht stimmt. Wenn sie sich das ansehen, werden sie Ihre Kommentare zu "nicht produktionsbereit" sehen und sich für AHA entscheiden.

c_maker
quelle
2
Methodenaufrufe werden nur durchgestrichen, wenn die IDE dies unterstützt.
FrustratedWithFormsDesigner
4
Stimmt, aber die meisten Leute werden wahrscheinlich eine dieser IDEs verwenden, die dies unterstützen.
c_maker
3

Ich glaube nicht , dass es eine Standardmethode ist der Markierungscode wie WIP, Incompleteoder so ähnlich.

Sie können eine neue Ausnahme mit dem Namen erstellen ClassUnstableExceptionund diese dann im Class3Konstruktor mit einer Meldung auslösen, in der erläutert wird, wie sie nicht verwendet werden sollte. Dies ist jedoch schlecht, da es sie nur zur Laufzeit warnt.

Sie können auch versuchen, die Klasse in irgendeiner Weise inkompilierbar zu machen, und dann dem Codeabschnitt, der den Compiler auslöst, eine Notiz hinzufügen, damit jemand, der den Code repariert, hoffentlich eine Erklärung erhält, warum er diese Klasse nicht verwenden sollte . Dies funktioniert möglicherweise nicht, wenn sie ein halbautomatisches Tool zum Beheben dieses Problems verwenden, über das einige IDEs verfügen. Das ist auch schlimm, weil es Builds brechen könnte.

Sie können eine Annotation mit dem Namen erstellen WIP(da die Annotation, die ich mir vorstellen kann, Deprecatednicht wirklich das Gleiche bedeutet) und sie zum Annotieren der Klasse verwenden. Dies wäre wahrscheinlich ein bisschen mehr Arbeit, und was würde die Annotation unterstützen?

Schließlich könnten Sie es einfach in die Kommentare einfügen, aber das funktioniert nur, wenn die Leute sie tatsächlich lesen .

BEARBEITEN:

Dies kann relevant sein: Wie kann absichtlich eine Warnmeldung für einen benutzerdefinierten Java-Compiler ausgelöst werden?

FrustratedWithFormsDesigner
quelle
Throw Exception bewirkt, dass sich die Eclipse über nicht erreichbaren Code beschwert. Irgendeine Problemumgehung?
Wei Shi
@Usavich: Nicht sicher, da ich den Code nicht gesehen habe, aber könnte das möglicherweise auch dazu beitragen, zukünftige Entwickler von der Verwendung des Codes abzuhalten ?
FrustratedWithFormsDesigner
@Usavich: Sehen Sie sich den Link an, den ich in meinem Beitrag in EDIT hinzugefügt habe. Es ist eine ähnliche Frage, bei der das OP eine benutzerdefinierte Compiler-Warnung hinzufügen wollte. Könnte Ihnen helfen, eine benutzerdefinierte "UnstableCode" -Anmerkung hinzuzufügen.
FrustratedWithFormsDesigner
2

Sie könnten eine Anmerkungsverarbeitung zur Kompilierungszeit einführen , dies würde jedoch alle Mitglieder des Teams dazu zwingen, ihren Kompilierungsprozess anzupassen.

Allerdings finde ich den ganzen Vorgang etwas verwirrend. Eine instabile API sollte klar voneinander getrennt werden, indem Sie in Ihrem Versionskontrollsystem eine Verzweigung erstellen. Wenn es wirklich in der restlichen Codebasis sein muss, als instabil dokumentiert wurde und trotzdem verwendet wird, ist das Problem nicht wirklich technisch, sondern liegt in der Organisation und der Kommunikation. Ja, Sie könnten technische Überprüfungen (wie das Verarbeiten von Anmerkungen) einführen, aber das würde das Problem nicht lösen - verschieben Sie es einfach auf eine andere Ebene.

Meine Empfehlung lautet daher: Wenn Sie die Codebasis nicht trennen können, indem Sie sie in verschiedene Zweige einteilen, sprechen Sie mit Personen und erklären Sie ihnen, warum sie die API nicht verwenden dürfen.

perdian
quelle
2

Warum ist es überhaupt dort?

Sie haben instabilen Code in die Hauptzeile eingecheckt? Warum?

Instabiler Code sollte nicht in Trunk / Main / Master oder wie auch immer der Name des Haupttrunks lautet eingecheckt werden. Dies wird als Entwicklung mit hohem Risiko angesehen und sollte stattdessen in einer eigenen Filiale abgespeichert werden, an der Sie gearbeitet haben, anstatt in main einzuchecken.

Ich möchte Sie (und Ihren Teamleiter) nachdrücklich ermutigen, Advanced SCM Branching Strategies zu lesen . Achten Sie insbesondere auf die Rolle der Entwicklung und darauf, was als Entwicklung mit hohem Risiko angesehen wird:

Erwägen Sie im Allgemeinen, für jedes Projekt mit hohem Risiko separate Zweigstellen zu verwenden. Projekte mit hohem Risiko zeichnen sich durch große Größe, große Anzahl von Personen, unbekannte Themen, hochtechnische Themen, sehr enge Zeitpläne, ungewisse Liefertermine, unvollständige oder schwankende Anforderungen und geografisch verteilte Projektteams aus. In ähnlicher Weise sollten Sie in jeder Version einen einzelnen Zweig für eine risikoarme Entwicklung festlegen. Mehrere Quellen, einschließlich [WING98], empfehlen, für diesen Zweck die Hauptleitung zu verwenden. Berücksichtigen Sie die oben für die Hauptlinie erörterten Faktoren, bevor Sie sich zu dieser Vorgehensweise begeben. Bei der Entwicklung mit geringem Risiko kann es zu Abweichungen von der Hauptstrategie kommen, selbst wenn mehrere Mitglieder einer Produktfamilie über die Hauptstrategie koordiniert werden.

Wenn Sie es zulassen, dass Leute instabilen (oder nicht verwendeten) Code in die Hauptzeile einchecken, werden Sie die zukünftigen Entwicklungsbemühungen hinsichtlich des Versuchs, diesen Code zu verwalten, verwirren. Jeder Zweig und Klon des Repräsentanten von jetzt an bis zum Ende der Zeit wird dies enthalten, bis jemand "seinen toten Code" sagt und ihn löscht.

Es gibt einige, die sagen "Nun, wenn es in einem Zweig ist, wird es vergessen", und obwohl dies wahr sein mag, ist es um ein Vielfaches schlimmer, toten (und instabilen) Code in der Hauptzeile vergessen zu haben, da er die gesamte zukünftige Entwicklung verwirrt, bis er entfernt wird - und dann ist es noch mehr vergessen. Ein gut benannter Zweig von "/ fooProject / branches / WeisBigIdea" (oder einem gleichwertigen Zweig) ist sichtbar und in Zukunft einfacher zu bearbeiten - insbesondere, wenn er funktioniert.

@Deprecated

Das erste ist die @DeprecatedAnmerkung. Dies geht über den Javadoc hinaus und gibt Compiler-Warnungen aus. javacstellt ein -deprecationFlag bereit , das wie folgt beschrieben wird:

Zeigen Sie eine Beschreibung jeder Verwendung oder Außerkraftsetzung eines veralteten Members oder einer Klasse an. Ohne -deprecation, javaczeigt eine Zusammenfassung der Quelldateien , die Verwendung oder Überschreibung veraltet Mitglieder oder Klassen. -Deprecation ist eine Abkürzung für -Xlint:deprecation.

Wie bereits erwähnt, geht dies über die Standard-Compiler-Warnungen hinaus.

In vielen IDEs werden veraltete Methoden und Werte durchgestrichen dargestellt:

foo.bar();

Und würde eine Ausgabe erzeugen wie:

$ javac -Xlint:all Foo.java Bar.java
Bar.java:2: warning: [deprecation] Foo in unnamed package has been deprecated
interface Bar extends Foo { }
                      ^

Abhängig von Ihrer Build-Struktur wird der Build möglicherweise durch Warnungen unterbrochen. Dies würde den Build nur unterbrechen, wenn eine Ihrer Klassen verwendet wird (nicht, wenn sie einfach kompiliert wird).

@CustomAnnotation

Hierfür gibt es viele Ansätze. Zum Beispiel die Lightweight-Annotation javac @Warning, die einen Annotationsprozessor bereitstellt , der beim Kompilieren eine Warnung auslöst , wenn etwas mit dieser Annotation verwendet wird ( ein NetBeans-Tutorial zu benutzerdefinierten Annotationsprozessoren, damit Sie eine Vorstellung davon bekommen, was hinter der steht Szenen).

Oracle beschreibt sogar ein Beispiel für die Verwendung von benutzerdefinierten Annotationen für eine @UnfinishedAnnotation in Das Beste aus Javas Metadaten machen, Teil 2: Benutzerdefinierte Annotationen .

Mit dem AnnotationProcessor können Sie während der Kompilierung beliebigen Code ausführen. Es liegt ganz bei Ihnen zu entscheiden, was Sie tun möchten. Warnen Sie, brechen Sie den Build ab, wenn etwas verwendet wird. Es gibt zahlreiche Tutorials im Internet, in denen erklärt wird, wie man diese Art von Code schreibt. Ob Sie beim Kompilieren einen Fehler erzeugen möchten (dies ist ärgerlich und führt dazu, dass er gelöscht wird) oder wenn er verwendet wird (das Schreiben ist etwas komplexer).

Beachten Sie, dass dies alles bedeutet, dass die Builds geändert werden, um den Annotation-Prozessor tatsächlich zu verwenden.


quelle
0

Könnten Sie alle unvollständigen Klassen in ein Unterpaket mit dem Namen "NOTCOMPLETE" verschieben? Es ist ein bisschen hacken, aber vielleicht sichtbar genug.

(Wenn sich nicht alle im selben Paket befinden, können Sie die Paketstruktur dort neu erstellen.)

Alex Feinman
quelle
0

Ich weiß nicht, dass es wirklich eine gute Möglichkeit gibt, dies im Code zu tun. Geh einen Schritt zurück:

Erstellen Sie zwei Kopien des gesamten Projekts, eine mit der Klasse und eine ohne. Markieren Sie die Version ohne die Klasse als stabile Codebasis, die für die Produktionsfreigabe bereit ist, und die Version mit der Klasse als Entwicklung für eine zukünftige Version. Dokumentieren Sie, was geschehen muss, bevor diese Klasse als Produktionsqualität angesehen werden kann.

Im Idealfall sollten Sie dazu Verzweigungen in der Versionsverwaltungslösung Ihrer Wahl verwenden. Möglicherweise müssen Sie jedoch ein wenig schummeln, da es sich so anhört, als hätten Sie keine solche Verzweigungsstrategie angewendet. Entfernen Sie die neue Klasse vorsichtig, checken Sie eine Version ohne sie ein und führen Sie einige Regressionstests durch. Wenn Sie zufrieden sind, können Sie diese Revision mit einem Tag versehen, einen Entwicklungszweig aus dem Tag erstellen und die Klasse dann wieder in den Entwicklungszweig einfügen.

Adam Jaskiewicz
quelle
0

Ich würde mich dafür entscheiden, die Klasse abstrakt zu machen und angemessen zu kommentieren - auf diese Weise ist der Code immer noch als Referenz da, aber viel Glück für jeden, der versucht, ihn zu instanziieren :)

Phil Lello
quelle
-1

Was ist mit einer Abhängigkeit, die der Compiler nicht auflösen kann? Einfach hinzufügen:

importiere dies.ist.nicht.doch.doch.nicht.verwendet.it;

Zum Seitenanfang. Benutzer können damit nicht kompilieren.

Wenn Sie die Klasse testen möchten, erstellen Sie einfach ein Paket / eine Klasse mit diesem Namen (oder verwenden Sie ein einfacheres wie "experimental.danger"), und Sie können den neuen Code testen.

Neal Tibrewala
quelle
1
Die Kompilierung schlägt fehl, auch wenn ich sie nicht benutze ... schlechte Idee ...
Silviu Burcea