Czy istnieją najlepsze praktyki dotyczące organizacji pakietów (Java)? [Zamknięte]

201

Jakiś czas temu zobaczyłem odpowiedź na pytanie dotyczące drobiazgowej organizacji pakietów Java. Na przykład my.project.util, my.project.factory, my.project.service, itd.

Nie mogę go teraz znaleźć, więc równie dobrze mogę zadać pytanie.

Czy istnieją najlepsze praktyki dotyczące organizacji pakietów w Javie i co się w nich dzieje?

Jak organizujesz zajęcia w swoim projekcie Java?

Na przykład projekt, nad którym pracuję z kilkoma osobami, zawiera pakiet o nazwie fasola. Zaczęło się od projektu zawierającego prostą fasolę, ale ostatecznie (z powodu złego doświadczenia i braku czasu) zawierało wszystko (prawie). Wyczyściłem je trochę, umieszczając niektóre klasy fabryczne w pakiecie fabrycznym (klasy ze statycznymi metodami, które tworzą fasole), ale mamy inne klasy, które wykonują logikę biznesową i inne, które wykonują proste przetwarzanie (nie z logiką biznesową), takie jak pobieranie komunikat o kodzie z pliku właściwości.

Wasze przemyślenia i komentarze są mile widziane.

Cyntech
źródło
74
Nie zgadzam się z zamknięciem tego pytania. Nie zgadzam się, że pytania dotyczące najlepszych praktyk są prawie zawsze oparte na doświadczeniu i opiniach, jednak nie zgadzam się, że pytania te powinny zostać zamknięte w przypadku przepełnienia stosu. Na tym polega sedno dobrego programowania, korzystania z najlepszych praktyk i znajdowania najlepszego rozwiązania przy użyciu tych opinii i doświadczeń. Otwórz ponownie to pytanie.
Cyntech
Sugeruję przeczytanie tego: satysfakcja.com/blog/archives/5164 . TL; DR ... cała idea „najlepszych praktyk” jest zepsuta. W najlepszym razie jest to rażące mylące, w najgorszym jest wręcz szkodliwe.
Stephen C

Odpowiedzi:

174

Organizacja pakietu lub jego struktura to zwykle gorąca dyskusja. Poniżej znajduje się kilka prostych wskazówek dotyczących nazewnictwa i strukturyzacji pakietów:

  • Postępuj zgodnie z konwencjami nazewnictwa pakietów Java
  • Zbuduj swoje paczki według ich roli funkcjonalnej, a także ich roli biznesowej
    • Podziel swoje pakiety według ich funkcjonalności lub modułów. na przykład com.company.product.modulea
    • Dalszy podział może być oparty na warstwach w twoim oprogramowaniu. Ale nie przesadzaj, jeśli masz tylko kilka klas w pakiecie, wtedy sensowne jest mieć wszystko w pakiecie. np. com.company.product.module.weblub com.company.product.module.utilitp.
    • Unikaj przesadzania z strukturowaniem, IMO unikaj oddzielnego pakowania wyjątków, fabryk itp., Chyba że istnieje pilna potrzeba.
  • Jeśli twój projekt jest mały, uprość go kilkoma pakietami. np. com.company.product.modeli com.company.product.utilitp.
  • Rzuć okiem na niektóre popularne projekty open source dotyczące projektów Apache . Zobacz, jak używają strukturyzacji dla projektów o różnych rozmiarach.
  • Rozważ także kompilację i dystrybucję podczas nazywania (pozwalając na dystrybucję interfejsu API lub zestawu SDK w innym pakiecie, patrz aplet apletu)

Po kilku eksperymentach i próbach powinieneś być w stanie wymyślić strukturę, w której czujesz się komfortowo. Nie skupiaj się na jednej konwencji, bądź otwarty na zmiany.

naikus
źródło
Dzięki za twoją odpowiedź. Jest to w dużej mierze to, co próbowaliśmy uwzględnić, ale wiele niepowiązanych kodów dostało się do naszego pakietu bean, stąd moje pytanie.
Cyntech,
2
Zgadzam się, że pakiet według funkcji jest najbardziej sensowny. Słyszałem kiedyś świetną analogię do struktury biura firmy. W podejściu warstwowym każda osoba na poziom w firmie siedziałaby ze sobą, tj. Kadra kierownicza, kierownicy, administratorzy, pracownicy / pracownicy wszyscy siedzieli w osobnych sekcjach w budynku. Struktura ta prawdopodobnie nie jest tak skuteczna, jak zorganizowane podejście do „funkcji”. To znaczy, jeśli Dyrektor Sprzedaży zasiada u Kierownika Sprzedaży, który zasiada z pracownikami Sprzedaży, którzy wszyscy siedzą z Administratorem Sprzedaży. Zapewnia to lepszą spójność między działem, gdy jest zorganizowany w ten sposób.
alex
Zgadzam się ze swoimi punktami. Tylko jeden punkt, aby podkreślić nazwę firmy w pakiecie, gdy firma dostaje zakupiony produkt, zostaje sprzedana. Kierownictwo chce usunąć nazwę firmy. To może być narzut.
Tushar D
183

Organizuję pakiety według funkcji , a nie według wzorców lub ról implementacyjnych. Myślę, że pakiety takie jak:

  • beans
  • factories
  • collections

jest źle.

Wolę na przykład:

  • orders
  • store
  • reports

więc mogę ukryć szczegóły implementacji poprzez widoczności pakietu . Fabryka zamówień powinna znajdować się w orderspaczce, dlatego szczegóły dotyczące tworzenia zamówienia są ukryte.

onof
źródło
10
Ten post wskazuje na widoczność paczki. Nigdy nie widziałem używanego zakresu pakietów Java, ale odpowiednia struktura pakietu mogłaby pozwolić programistom na lepsze korzystanie z niego.
Jpnh
23
To dokładnie prawda, ale niewielu programistów to robi. Pakiety powinny być spójnymi zbiorami klas, z których niektóre są widoczne tylko w pakiecie. Pozwoliłoby to zminimalizować sprzężenie między klasami, których nie należy łączyć, ponieważ dotyczą one różnych cech. Podejście pakiet po warstwie nie wykorzystuje modyfikatorów widoczności pakietów, a pakiety w takim projekcie mają niską spójność i wysoki stopień sprzężenia między pakietami.
Nate Reed,
Czy masz tego przykład? Korzystam z Spring-MVC i trudno mi je uporządkować według funkcji / modułu, ponieważ Spring używa config xml.
Eric Huang,
2
@ofof Organizuję również kod według funkcji, ale jakie są najlepsze praktyki dla klas podstawowych wspólnych dla wszystkich funkcji?
Marc
Podążałem za pierwszym stylem. ale teraz muszę przeskakiwać z jednego pakietu do drugiego podczas pracy z klasami. to naprawdę sprawia złe wrażenia. Teraz przechodzę na drugi styl, ponieważ myślę, że łatwiej będzie razem śledzić powiązane klasy.
M.kazem Akhgary
40

Krótka odpowiedź: jeden pakiet na moduł / funkcję, ewentualnie z sub-pakietami. Połącz ze sobą ściśle powiązane rzeczy w jednym pakiecie. Unikaj okrągłych zależności między pakietami.

Długa odpowiedź: zgadzam się z większością tego artykułu

Peter Tseng
źródło
2
pakiety podrzędne przerywają enkapsulację. „Pod-pakiet” sam w sobie jest całkowicie niezależnym pakietem
Ricardo Gamba,
21

Wolę funkcję przed warstwami, ale myślę, że to zależy od twojego projektu. Rozważ swoje siły:

  • Zależności
    Spróbuj zminimalizować zależności pakietów, szczególnie między funkcjami. W razie potrzeby wyodrębnij interfejsy API.
  • Organizacja zespołu
    W niektórych organizacjach zespoły pracują nad funkcjami, aw innych na warstwach. Wpływa to na sposób organizacji kodu, służy do formalizowania interfejsów API lub zachęca do współpracy.
  • Wdrażanie i wersjonowanie
    Umieszczenie wszystkiego w module upraszcza wdrażanie i wersjonowanie, ale trudniej naprawia błędy. Dzielenie rzeczy zapewnia lepszą kontrolę, skalowalność i dostępność.
  • Odpowiedz na zmiany
    Dobrze zorganizowany kod jest dużo łatwiejszy do zmiany niż duża kula błota.
  • Rozmiar (ludzie i wiersze kodu)
    Im większy, tym bardziej musi być sformalizowany / znormalizowany.
  • Znaczenie / jakość
    Niektóre kody są ważniejsze niż inne. Interfejsy API powinny być bardziej stabilne niż implementacja. Dlatego należy go wyraźnie oddzielić.
  • Poziom abstrakcji i punkt wejścia
    Osoba z zewnątrz powinna mieć możliwość dowiedzenia się, o co chodzi w kodzie i od czego zacząć czytanie od spojrzenia na drzewo pakietu.

Przykład:

com/company/module
  + feature1/
    - MainClass          // The entry point for exploring
    + api/               // Public interface, used by other features
    + domain/
      - AggregateRoot
      + api/             // Internal API, complements the public, used by web
      + impl/ 
    + persistence/       
    + web/               // presentation layer 
    + services/          // Rest or other remote API 
    + support/            
  + feature2/
  + support/             // Any support or utils used by more than on feature
    + io
    + config
    + persistence
    + web

To tylko przykład. To jest dość formalne. Na przykład definiuje 2 interfejsy dla cechy1 . Zwykle nie jest to wymagane, ale może być dobrym pomysłem, jeśli używane są inaczej przez różne osoby. Możesz pozwolić wewnętrznemu API rozszerzyć publiczność.

Nie podoba mi się nazwa „impl” lub „support”, ale pomagają one oddzielić mniej ważne rzeczy od ważnych (domena i API). Jeśli chodzi o nazywanie, lubię być jak najbardziej konkretny. Jeśli masz pakiet o nazwie „utils” z 20 klasami, przejdź StringUtilsdo support / string, HttpUtilsupport / http i tak dalej.

ThomasGran
źródło
13

Czy istnieją najlepsze praktyki dotyczące organizacji pakietów w Javie i co się w nich dzieje?

Nie, naprawdę nie. Istnieje wiele pomysłów i opinii, ale prawdziwą „najlepszą praktyką” jest kierowanie się zdrowym rozsądkiem!

(Proszę przeczytać Brak najlepszych praktyk, aby uzyskać informacje na temat „najlepszych praktyk” i osób, które je promują).

Jest jednak jedna zasada, która prawdopodobnie ma szeroką akceptację. Struktura pakietu powinna odzwierciedlać strukturę modułu (nieformalną) aplikacji, a użytkownik powinien dążyć do minimalizacji (lub idealnie całkowitego uniknięcia) cyklicznych zależności między modułami.

(Cykliczne zależności między klasami w pakiecie / module są w porządku, ale cykle między pakietami zwykle utrudniają zrozumienie architektury aplikacji i mogą stanowić barierę dla ponownego użycia kodu. W szczególności, jeśli użyjesz Maven, zauważysz, że jest to cykliczne Zależności między pakietami / modułami oznaczają, że cały połączony bałagan musi być jednym artefaktem Maven.)

Należy również dodać, że nie jest jeden powszechnie akceptowane najlepsze praktyki dla nazw pakietów. Oznacza to, że nazwy pakietów powinny zaczynać się od nazwy domeny organizacji w odwrotnej kolejności. Przestrzegając tej zasady, zmniejszasz prawdopodobieństwo problemów powodowanych przez konflikt twoich (pełnych) nazw klas z innymi ludźmi.

Stephen C.
źródło
9

Widziałem, jak niektórzy ludzie promowali „pakiet po funkcji” zamiast „pakiet po warstwie”, ale przez wiele lat stosowałem kilka podejść i stwierdziłem, że „pakiet po warstwie” jest znacznie lepszy niż „pakiet po funkcji”.

Ponadto odkryłem, że strategia hybrydowa: „pakiet po module, warstwa, a następnie funkcja” działa wyjątkowo dobrze w praktyce, ponieważ ma wiele zalet „pakiet po funkcji”:

  • Promuje tworzenie frameworków wielokrotnego użytku (bibliotek z aspektami zarówno modelu, jak i interfejsu użytkownika)
  • Umożliwia implementacje warstw plug and play - praktycznie niemożliwe z „pakietem według funkcji”, ponieważ umieszcza implementacje warstw w tym samym pakiecie / katalogu co kod modelu.
  • Wiele więcej...

Dokładnie wyjaśniam tutaj: Struktura i organizacja nazw pakietów Java, ale moja standardowa struktura pakietów to:

revdomain.moduleType.moduleName.layer. [layerImpl] .feature.subfeatureN.subfeatureN + 1 ...

Gdzie:

revdomain Odwrócona domena np. com.mycompany

moduleType [app * | framework | util]

moduleName np. myAppName, jeśli typem modułu jest aplikacja lub „finanse”, jeśli jest to struktura rachunkowości

warstwa [model | interfejs | trwałość | bezpieczeństwo itp.]

layerImpl np., furtka, jsp, jpa, jdo, hibernacja (Uwaga: nieużywane, jeśli warstwa jest modelem)

funkcja np. finanse

podfunkcjaN np. księgowość

podfunkcja N + 1 np. amortyzacja

* Czasami „aplikacja” jest pomijana, jeśli moduleType jest aplikacją, ale umieszczenie jej tam sprawia, że ​​struktura pakietu jest spójna we wszystkich typach modułów.

Volksman
źródło
5

Nie znam standardowych praktyk dotyczących organizacji pakietów. Generalnie tworzę pakiety, które obejmują dość szerokie spektrum, ale mogę różnicować w ramach projektu. Na przykład osobisty projekt, nad którym obecnie pracuję, zawiera pakiet poświęcony moim niestandardowym kontrolkom interfejsu użytkownika (pełnym klasom klas podklasowych). Mam pakiet poświęcony zarządzaniu bazą danych, mam pakiet dla zestawu detektorów / zdarzeń, które utworzyłem i tak dalej.

Z drugiej strony kazałem współpracownikowi stworzyć nową paczkę dla prawie wszystkiego, co zrobił. Każde inne MVC, którego chciał, miało swoją własną paczkę i wydawało się, że zestaw MVC był jedyną grupą klas, która mogła znajdować się w tym samym pakiecie. Pamiętam, że w pewnym momencie miał 5 różnych pakietów, z których każdy zawierał jedną klasę. Myślę, że jego metoda jest trochę ekstremalna (a zespół zmusił go do zmniejszenia liczby pakietów, gdy po prostu nie mogliśmy sobie z tym poradzić), ale w przypadku aplikacji niepraktycznych, więc umieszczenie wszystkiego w tym samym pakiecie. Jest to punkt równowagi, który ty i twoi koledzy z drużyny musicie znaleźć dla siebie.

Jedną rzeczą, którą możesz zrobić, to cofnąć się i pomyśleć: jeśli byłeś nowym członkiem przedstawionym do projektu lub twój projekt został wydany jako open source lub API, jak łatwo / trudno byłoby znaleźć to, czego chcesz? Bo dla mnie to jest to, czego naprawdę chcę od pakietów: organizacja. Podobnie jak w przypadku przechowywania plików w folderze na komputerze, spodziewam się, że będę mógł je znaleźć ponownie bez konieczności przeszukiwania całego dysku. Oczekuję, że będę w stanie znaleźć klasę, którą chcę, bez konieczności przeszukiwania listy wszystkich klas w pakiecie.

Brian S.
źródło