Czy istnieje potrzeba przełączenia się na moduły podczas migracji do Java 9 + / Java 11?

80

Obecnie przeprowadzamy migrację z Java 8 do Java 11. Jednak aktualizacja naszych usług była mniej bolesna, niż oczekiwaliśmy. W zasadzie musieliśmy tylko zmienić numer wersji w naszym build.gradlepliku, a usługi były szczęśliwie uruchomione. Zaktualizowaliśmy biblioteki oraz (mikro) usługi, które używają tych bibliotek. Do tej pory żadnych problemów.

Czy rzeczywiście trzeba przejść na moduły? Generowałoby to niepotrzebne koszty IMHO. Wszelkie sugestie lub dalsze materiały do ​​czytania są mile widziane.

Aby wyjaśnić, czy są jakieś konsekwencje używania kodu Java 9+ bez wprowadzania modułów? Czy może np. Stać się niekompatybilny z innym kodem?

Younes EO
źródło
10
Jest to to samo ryzyko, z którym już się spotkałeś w Javie 8: wylądowanie w "Piekle Klasy".
4
Podsumowanie sotms / # odpowiadałoby w pewnym stopniu. Możesz sprawdzić, czy cele projektu są zgodne z projektem Jigsaw . Poza tym, moim zdaniem, kwestia aktualności jest ważna także dla bibliotek / serwisów wspierających swoich konsumentów.
Naman
4
@Taschi Nie sądzę, by samo piekło klasowe usprawiedliwiało przejście na modułowość, ponieważ cały kod przed Java 9 miał ten problem i w większości przypadków nie mieliśmy z tym problemu (osobiście nigdy nie mieliśmy z tym problemu).
Younes EO
1
@Naman poruszenie celów układanki projektu jest rzeczywiście bardzo dobrym argumentem.
Younes EO
8
@Younes El Ouarti, usunięcie „Classpath Hell” jest jednym z dwóch określonych celów projektu Jigsaw. Jeśli uważasz, że to niewystarczający powód do zajmowania się Jigsaw, cóż ... Zgadzam się z Tobą i unikam Jigsaw, kiedy tylko mogę.

Odpowiedzi:

132

Nie.

Nie ma potrzeby przełączania się na moduły.

Nigdy nie było potrzeby przechodzenia na moduły.

Java 9 i nowsze wersje obsługują tradycyjne pliki JAR na tradycyjnej ścieżce klas, poprzez koncepcję nienazwanego modułu i prawdopodobnie będą to robić aż do śmierci wszechświata.

Decyzja o rozpoczęciu korzystania z modułów zależy wyłącznie od Ciebie.

Jeśli utrzymujesz duży projekt, który nie zmienia się zbytnio, prawdopodobnie nie jest to warte wysiłku.

Jeśli pracujesz nad dużym projektem, który przez lata stał się trudny do utrzymania, przejrzystość i dyscyplina, jaką zapewnia modularyzacja, mogą być korzystne, ale może to być również dużo pracy, więc dobrze się zastanów, zanim zaczniesz.

Jeśli zaczynasz nowy projekt, bardzo polecam zacząć od modułów, jeśli możesz. Wiele popularnych bibliotek zostało już zaktualizowanych do postaci modułów , więc istnieje duża szansa, że ​​wszystkie potrzebne zależności są już dostępne w formie modułowej.

Jeśli utrzymujesz bibliotekę, zdecydowanie zalecam aktualizację jej do modułu, jeśli jeszcze tego nie zrobiłeś i jeśli wszystkie zależności Twojej biblioteki zostały przekonwertowane.

Nie oznacza to, że nie napotkasz kilku przeszkód podczas przechodzenia poza Javę 8. Te, które napotkasz, prawdopodobnie nie będą miały nic wspólnego z modułami jako takimi . Najwięcej problemów powszechne migracji że słyszeliśmy o odkąd wydaliśmy Java 9 w 2017 roku mamy do czynienia z zmian w składni łańcucha wersji oraz do usuwania lub hermetyzacji API wewnętrznych ( np , sun.misc.Base64Decoder), dla którego publiczne, wspierane zamienniki mają były dostępne od lat.

Mark Reinhold
źródło
26

Mogę tylko powiedzieć wam moją opinię organizacji w tej sprawie. My w procesie przechodzenia do modułów dla każdego pojedynczego projektu, że pracujesz. To, co budujemy, to w zasadzie mikro-usługi + niektóre biblioteki klienckie. W przypadku mikroserwisów przejście na modulesma w jakiś sposób niższy priorytet: kod tam jest już w jakiś sposób odizolowany w kontenerze dockera, więc „dodawanie” tam modułów nie wydaje się (nam) bardzo ważne. Ta praca jest podejmowana powoli, ale ma niski priorytet.

Z drugiej strony biblioteki klienckie to zupełnie inna historia. Nie mogę ci powiedzieć, jaki bałagan mamy czasami. Wyjaśnię jedną kwestię, której wcześniej nienawidziłem jigsaw. Udostępniasz interfejs klientom, z których każdy może korzystać. To interfacejest automatycznie public- wystawiane na świat. Zwykle robię wtedy kilka package-privateklas, które nie są widoczne dla klientów, które używają tego interfejsu. Nie chcę, aby klienci tego używali, jest to wewnętrzne. Brzmi dobrze? Źle.

Pierwszym problemem jest to, że gdy te package-privateklasy rosną i chcesz mieć więcej klas, jedynym sposobem na ukrycie wszystkiego jest utworzenie klas w tym samym pakiecie:

  package abc:
        -- /* non-public */ Usage.java
        -- /* non-public */ HelperUsage.java
        -- /* non-public */ FactoryUsage.java
        ....

Kiedy rośnie (w naszych przypadkach tak), te pakiety są o wiele za duże. Przechodzisz do oddzielnego pakietu, o którym mówisz? Jasne, ale wtedy tak będzie HelperUsagei FactoryUsagetak będzie publici od początku staraliśmy się tego unikać.

Problem numer dwa: każdy użytkownik / dzwoniący naszych klientów może utworzyć tę samą nazwę pakietu i rozszerzyć te ukryte klasy. Zdarzyło nam się to już kilka razy, zabawne czasy.

modulesrozwiązuje ten problem w piękny sposób: publictak naprawdę public już nie jest ; Mogę uzyskać frienddostęp za pośrednictwem exports todyrektywy. To znacznie ułatwia cykl życia naszego kodu i zarządzanie nim. I uciekamy od piekła klas. Oczywiście maven/gradlezałatwimy to głównie dla nas, ale kiedy pojawi się problem, ból będzie bardzo realny. Może być też wiele innych przykładów.

To powiedziawszy, przejście nie jest (nadal) łatwe. Przede wszystkim wszyscy w zespole muszą być wyrównani; po drugie są przeszkody. Dwa największe, jakie wciąż widzę, to: jak oddzielić każdy moduł, na podstawie czego konkretnie? Nie mam jeszcze jednoznacznej odpowiedzi. Po drugie split-packages, och, ta piękna „ta sama klasa jest eksportowana przez różne moduły”. Jeśli tak się stanie z twoimi bibliotekami, istnieją sposoby na złagodzenie; ale jeśli są to biblioteki zewnętrzne ... nie jest to takie proste.

Jeśli polegasz na jarAi jarB(oddzielnych modułach), ale oba eksportują abc.def.Util, możesz się zaskoczyć. Istnieją jednak sposoby rozwiązania tego problemu. W jakiś sposób bolesne, ale możliwe do rozwiązania.

Ogólnie rzecz biorąc, od czasu migracji do modułów (i nadal to robimy), nasz kod stał się znacznie czystszy. A jeśli Twoja firma jest firmą, która stawia na kod, ma to znaczenie. Z drugiej strony byłem zaangażowany w firmy, które były postrzegane przez starszych architektów jako „zbyt drogie”, „brak realnej korzyści”.

Eugene
źródło
4
Dzięki za zachęty! Otrzymuję więc to, że modularyzacja wiąże się z wieloma ograniczeniami dostępu, których brakowało w poprzednich wersjach. Zdecydowanie widzę, jak jest to przydatne dla bibliotek. W przypadku komunikacji z usługą za pośrednictwem REST / AMQP / itp. to znowu nie jest taki problem, a raczej nie ma żadnych korzyści? Może nie możemy arbitralnie powiedzieć, że cały kod Java 9+ powinien być modułowy? Czy więc powinniśmy traktować to samo jako „narzędzie”? Niemniej jednak interesujące.
Younes EO
Przydatny może być wzorzec API „akcesora” (ale pamiętaj, że zamiast publicznego pola statycznego preferowane jest prywatne pole z metodami, aby uniknąć zakleszczenia podczas ładowania klas). Zobacz tutaj: wiki.netbeans.org/…
Tomáš Myšík
Dziękuję za podzielenie się swoimi doświadczeniami! Byłoby dobrze, gdybyś udostępnił więcej szczegółów lub linków do problemów, o których wspomniałeś, które są bolesne, ale nadal możliwe do rozwiązania.
botismarius
3
„Problem numer dwa: każdy użytkownik / dzwoniący naszych klientów może utworzyć tę samą nazwę pakietu i rozszerzyć te ukryte klasy”. Na długo przed Java 9 można było zapieczętować pakiety, aby temu zapobiec. (Zdarza mi się myśleć moduły są doskonałym pomysłem, a ja ich używać we wszystkich moich projektach Chciałem tylko zwrócić uwagę, że ten konkretny przypadek użycia nie wymaga od nich..)
VGR