Jak oflagować klasę jako rozwijaną w Javie

12

Pracuję nad projektem stażu, ale muszę odejść, zanim skończę wszystko.

Mam 1 klasę, która nie jest wystarczająco stabilna do użytku produkcyjnego. Chcę oznaczyć / oflagować tę klasę, aby inne osoby nie wykorzystały jej przypadkowo podczas produkcji. Umieściłem już ogłoszenie w Javadoc, ale to nie wydaje się wystarczające. Niektóre błędy lub ostrzeżenia kompilatora byłyby lepsze.

Kod jest zorganizowany w następujący sposób:

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

Gdyby istniała jedna klasa fabryczna, która wywołuje te klasy w metodach publicznych, mogłabym ustawić metodę na class3as private. Jednak interfejs API NIE jest narażony w ten sposób. Użytkownicy będą bezpośrednio korzystać z tych klas, np. new Class1();Ale nie mogę ustawić prywatnej klasy najwyższego poziomu. Jaka jest najlepsza praktyka radzenia sobie z tą sytuacją?

Wei Shi
źródło
1
Co rozumiesz przez „API nie jest ujawniany metodami”? Czy ta klasa ma być używana przez interfejs API Reflection?
Tom G
5
Błąd kompilatora? Dlaczego nie rzucić wyjątku w konstruktorze?
Mchl,
Przepraszam za zamieszanie. Zredagowałem swój post.
Wei Shi,
1
Nie możesz ustawić klasy jako prywatnej, ale możesz ustawić jej konstruktora jako prywatny.
Peter Taylor,

Odpowiedzi:

15

Dlaczego nie po prostu sprawdzić wszystkie niestabilne klasy w innej gałęzi w systemie kontroli wersji?

Andrew Moss
źródło
2
Wydaje mi się, że to „ukryłoby” kod. Co jeśli kod prawie robi to, co inni potrzebują, aby zrobić kilka drobnych poprawek. Jeśli umieścisz go w oddziale, mogą go nigdy nie zobaczyć i po prostu ponownie wprowadzą w życie całość.
c_maker,
3
@c_maker: Informowanie innych, że gałąź istnieje i co jest w niej, powinno być częścią tego, co zostaje przekazane, kiedy on odchodzi.
Blrfl,
2
@Birlf Jeśli martwi się, że inni nie zobaczą wyjaśnienia w JavaDoc kodu, którego używają, wątpię, aby poszli szukać innej dokumentacji, którą tworzy.
KeithB,
Obawiam się, że funkcja ta wciąż ewoluuje, ale mistrz Scrum postanowił ją odłożyć z dowolnego powodu (moratorium, które blokuje testowanie E2E, w naszym przypadku). Jeśli nie przyłączymy się do tego, aby opanować, może być wiele prac scalania na drodze. Właśnie uczyniliśmy c'tor prywatnym i opatrzyliśmy komentarz klasą @Experimental, jak w Spark
Joey Baruch
11

Jeśli poprawnie skomentowałeś klasę, możesz oznaczyć fragmenty niekompletnej funkcjonalności jako „przestarzałe” i lub skomentować wnętrzności metody i umieścić throw new UnsupportedOperationException();.

Zobacz Czy jest coś takiego jak NotImplementedException platformy .NET w Javie? dla szczegółów.

Heath Lilley
źródło
2
Jest to defaktyczny sposób radzenia sobie z trafieniem, gdy rozumiem
Martijn Verburg,
4

Nie znam takiego ostrzeżenia kompilatora.

W twojej sytuacji prawdopodobnie @Deprecatedużyłbym adnotacji. Skreśli wywołania metod, więc dla innych będzie oczywiste, że coś jest nie tak. Kiedy zobaczą, co słychać, zobaczą twoje komentarze na temat „nieprodukcji gotowej” i przejdą na AHA.

c_maker
źródło
2
wywołania metod są wykreślane tylko wtedy, gdy IDE je obsługuje.
FrustratedWithFormsDesigner
5
To prawda, ale większość ludzi prawdopodobnie użyje jednego z tych IDE, które go obsługują.
c_maker,
3

Nie sądzę, że jest to standardowy sposób oznaczania jako kod WIP, Incompleteczy coś takiego.

Możesz utworzyć nowy wyjątek o nazwie, ClassUnstableExceptiona następnie podnieść go w Class3konstruktorze za pomocą komunikatu wyjaśniającego, w jaki sposób nie powinni go używać. Jest to złe, ponieważ ostrzega je tylko w czasie wykonywania.

Możesz także spróbować w jakiś sposób uczynić klasę niekompilowalną, a następnie dodać notatkę do sekcji kodu, która wyzwala kompilator, aby jeśli ktoś pójdzie naprawić kod, mam nadzieję , że zobaczy wyjaśnienie, dlaczego nie powinien używać tej klasy . Może to nie działać, jeśli używają jakiegoś półautomatycznego narzędzia „napraw ten problem”, które mają niektóre IDE. Jest to również złe, ponieważ może uszkodzić kompilacje.

Możesz utworzyć adnotację o nazwie WIP(ponieważ najbliższe, o której myślę, to Deprecatedale to tak naprawdę nie znaczy tego samego) i użyć jej do opisu klasy. Prawdopodobnie byłoby to trochę więcej pracy, a co wspierałoby adnotację?

Na koniec możesz po prostu umieścić to w komentarzach, ale zadziała to tylko wtedy, gdy ludzie je przeczytają .

EDYTOWAĆ:

Może to mieć znaczenie: Jak celowo spowodować komunikat ostrzegawczy niestandardowego kompilatora Java?

FrustratedWithFormsDesigner
źródło
wyjątek rzucania powoduje, że zaćmienie narzeka na nieosiągalny kod. Jakieś obejście?
Wei Shi,
@Usavich: Nie jestem pewien, ponieważ nie widziałem kodu, ale może to może pomóc w zapobieganiu korzystania z niego przez przyszłych programistów ?
FrustratedWithFormsDesigner
@ Usavich: Spójrz na link dodany w EDIT w moim poście, to podobne pytanie, w którym OP chciał dodać niestandardowe ostrzeżenie kompilatora. Może pomóc dodać niestandardową adnotację „UnstableCode”.
FrustratedWithFormsDesigner
3

Dlaczego to w ogóle jest?

Sprawdziłeś niestabilny kod w głównej linii? Dlaczego?

Niestabilny kod nie powinien być sprawdzany w trunk / main / master lub jakikolwiek inny główny tytuł trunk. Jest to uważane za rozwój wysokiego ryzyka i zamiast tego powinno zostać zsekwencjonowane we własnym oddziale, nad którym pracowałeś, a nie w głównej.

Gorąco zachęcam was (i waszego zespołu) do przeczytania Strategii rozgałęziania Advanced SCM . W szczególności zwróć uwagę na rolę programistyczną i co mówi o tym, co uważa się za rozwój wysokiego ryzyka:

Zasadniczo rozważ użycie oddzielnych oddziałów dla każdego projektu wysokiego ryzyka. Projekty wysokiego ryzyka charakteryzują się dużą wielkością, dużą liczbą ludzi, nieznanym tematem, wysoce techniczną tematyką, bardzo napiętymi ramami czasowymi, niepewnymi datami dostawy, niekompletnymi lub zmiennymi wymaganiami oraz rozproszonymi geograficznie zespołami projektowymi. Podobnie, rozważ wyznaczenie jednego oddziału dla rozwoju niskiego ryzyka w każdym wydaniu. Kilka źródeł, w tym [WING98], zaleca użycie do tego celu głównej linii. Rozważ czynniki omówione powyżej dla głównej linii, zanim zdecydujesz się na taki sposób działania. Rozwój niskiego ryzyka może mieć inne zasady niż linia główna, nawet jeśli masz wielu członków rodziny produktów koordynujących przez linię główną.

Pozwalanie ludziom sprawdzać niestabilny (lub nieużywany) kod w głównej linii oznacza, że ​​pomylisz przyszłe wysiłki programistyczne związane z próbą utrzymania tego kodu. Każda gałąź i klon przedstawiciela od teraz aż do końca będzie go zawierał, dopóki ktoś nie powie „jego martwy kod” i go usunie.

Są tacy, którzy mówią „cóż, jeśli jest w gałęzi, zostaje zapomniany” i chociaż może to być prawda, zapomnienie martwego (i niestabilnego) kodu w linii głównej jest wielokrotnie gorsze, ponieważ dezorientuje cały przyszły rozwój, dopóki nie zostanie usunięty - i to jest jeszcze bardziej zapomniane. Dobrze nazwana gałąź „/ fooProject / branches / WeisBigIdea” (lub jej odpowiednik) jest widoczna i łatwiejsza do pracy w przyszłości - szczególnie jeśli działa.

@Deprecated

Pierwszą rzeczą jest @Deprecatedadnotacja. To wykracza poza javadoc i wyrzuca ostrzeżenia kompilatora. javaczapewnia -deprecationflagę opisaną jako:

Pokaż opis każdego użycia lub zastąpienia wycofanego członka lub klasy. Bez -deprecation, javacpokazuje podsumowanie z plików źródłowych, które użycie lub zastąpić przestarzałe członków lub klas. -deprecation jest skrótem od -Xlint:deprecation.

Jak wspomniano, wykracza to poza standardowe ostrzeżenia kompilatora.

W wielu IDE przestarzałe metody i wartości są pokazane z przekreśleniem:

foo.bar();

I produkuje dane wyjściowe takie jak:

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

W zależności od struktury kompilacji mogą pojawiać się ostrzeżenia uniemożliwiające kompilację. To tylko przełamać build jeśli jeden z klas użyto (jeśli nie jest on po prostu skompilowane w).

@CustomAnnotation

Istnieje wiele podejść do tego. Na przykład adnotacja Lightweight javac @Warning, która zapewnia procesor adnotacji, który uruchamia ostrzeżenie w czasie kompilacji, gdy używane jest coś z tą adnotacją ( samouczek Netbeans dotyczący niestandardowych procesorów adnotacji , abyś mógł zorientować się, co dzieje się za sceny).

Oracle opisuje nawet przykład użycia niestandardowych adnotacji jako @Unfinishedadnotacji w Jak najlepiej wykorzystać metadane Javy, część 2: Adnotacje niestandardowe .

Za pomocą AnnotationProcessor można uruchamiać dowolny kod w czasie kompilacji. To Ty decydujesz, co chcesz zrobić. Ostrzegaj, przerwij kompilację, gdy coś zostanie użyte. W sieci istnieje wiele samouczków na temat pisania tego rodzaju kodu. Niezależnie od tego, czy chcesz wygenerować błąd podczas kompilacji (będzie to denerwujące i spowoduje usunięcie go), czy też zostanie użyty (nieco bardziej skomplikowany do napisania).

Zauważ, że wszystko to implikuje zmianę kompilacji w celu faktycznego użycia procesora adnotacji.


źródło
2

Państwo mogłoby wprowadzać przetwarzania adnotacji czasie kompilacji , ale to będzie egzekwować od wszystkich członków zespołu, aby dostosować ich kompilacji proces.

Cały proces wydaje mi się jednak trochę zagmatwany. Niestabilny interfejs API należy wyraźnie oddzielić, tworząc gałąź w systemie kontroli wersji. Jeśli naprawdę musi znajdować się w pozostałej części bazy kodu, został udokumentowany jako niestabilny, a mimo to wykorzystany, problem nie jest tak naprawdę techniczny, ale leży w organizacji i komunikacji. Tak, możesz wprowadzić weryfikacje techniczne (takie jak przetwarzanie adnotacji), ale to nie rozwiązałoby problemu - wystarczy przenieść go na inny poziom.

Tak więc zalecam: jeśli nie możesz oddzielić bazy kodu, umieszczając ją w różnych gałęziach, porozmawiaj z ludźmi i wyjaśnij im, dlaczego nie mogą używać interfejsu API.

perdian
źródło
0

Czy możesz przenieść wszystkie niekompletne klasy do podpakietu o nazwie coś oczywistego, na przykład „NOTCOMPLETE”? To trochę hack, ale może być wystarczająco widoczne.

(Jeśli nie wszystkie znajdują się w tym samym pakiecie, możesz odtworzyć strukturę pakietu poniżej).

Alex Feinman
źródło
0

Nie wiem, czy jest to naprawdę dobry sposób na zrobienie tego w kodzie. Zrób krok wstecz:

Utwórz dwie kopie całego projektu, jeden z klasą, a drugi bez. Oznacz wersję bez klasy jako stabilną bazę kodu, gotową do wydania produkcyjnego, a wersję z klasą jako program do przyszłego wydania. Dokumentuj, co musi się stać, zanim ta klasa będzie mogła być uznana za jakość produkcji.

Najlepiej jest to zrobić, używając gałęzi w wybranym rozwiązaniu kontroli źródła. Być może będziesz musiał oszukać, ponieważ brzmi to tak, jakbyś nie używał takiej strategii rozgałęziania. Ostrożnie usuń nową klasę, sprawdź wersję bez niej i przeprowadź testy regresji. Gdy będziesz zadowolony, że jest stabilny, możesz oznaczyć tę wersję tagiem, utworzyć gałąź programistyczną z tagu, a następnie dodać klasę z powrotem do gałęzi programistycznej.

Adam Jaskiewicz
źródło
0

Zdecydowałbym się na streszczenie klasy i odpowiednie komentowanie - w ten sposób kod jest nadal dostępny w celach informacyjnych, ale powodzenia dla każdego, kto spróbuje go utworzyć :)

Phil Lello
źródło
-1

A co z uzależnieniem, którego kompilator nie może rozwiązać? Poprostu dodaj:

import this.is.not.done.yet.do.not.use.it;

na szczyt. Użytkownicy nie będą mogli się z nim skompilować.

Jeśli chcesz przetestować klasę, po prostu stwórz pakiet / klasę o tej nazwie (lub użyj prostszej, takiej jak „experimental.danger”) i możesz przetestować nowy kod.

Neal Tibrewala
źródło
1
Kompilacja