Podział na pakiety ze względu na warstwy czy funkcjonalność.

0

Witam. Chciałbym zapytań jakie podejście stosujecie w waszych projektach jeśli chodzi o podział na pakiety. Chyba dwa najpopularniejsze podejścia to podział ze względu na warstwy lub funkcjonalność? Nie wiem czy dobrze przetłumaczyłem chodzi mi

Package by feature or layer

Osobiście lepszym podejściem wydaje mi się podział ze względu na funkcjonalność. Mam jednak co do takiego podziału jedną wątpliwość. Gdzie umieszczać wspólne interfejsy dla różnych pakietów? Przykładowo mamy projekt z takimi pakietami:

com.app.clinic

-doctor
--controller
--dao
--domain
--services
--view

-reports
--controller
--dao
--domain
--services
--view

itd.

Gdzie w takim wypadku umieścić te wspólne klasy i interfejsy? Np zarówno pakiet doctor jak i reports ma klasy dao, które mogą implementować jakieś dao generyczne, podobnie mogą być w obu pakietach klasy do walidacji, które implementują wspólny interfejs validator. Gdzie w takim przypadku umieszczać te wspólne klasy?

0

Ze względu na warstwy

0

Dlaczego preferujesz podział ze względu na warstwy? Mógłbyś uzasadnić? Jak dla mnie podział ze względu na funkcjonalność wydaje się bardziej uporządkowany i łatwiej się w nim odnaleźć.

Mam też jeszcze jedno pytanie dotycząc samego nazywania pakietów bo nie znalazłem jednoznacznej odpowiedzi. Jak nazywać podpakiety, które mają nazwy dłuższe niż pojedyncza nazwa. Przykładowo: network service. Nazywać wtedy pakiet:

com.app.test.networkService
com.app.test.network_service
com.app.test.networkservice

Z tego co wyczytałem w nazwach pakietów nie powinno się stosować camel case, więc pierwsze podejście raczej odpada. Co z kolejnymi stosować znak "_" czy może łączyć kilka wyrazów w jeden? Ale czy nie robi się to wtedy trudne w czytaniu? Może po prostu unikać nazw kilkuczłonowych i zamiast tego nazwać pakiet np. tak:

com.app.test.service (to chyba akurat nie najlepszy pomysł gdyż podpakiety z klasami serwisowymi często się tak nazywają)
com.app.test.network

0

W sumie takiego sztywnego podziału raczej nie ma. Ale troszkę ciut bardziej w stronę podziału na funkcjonalność

0

A co do nazywania pakietów to ze spokojem, kolejne wyrazy oddzielaj kropką czyli jak masz frazę "something big" to masz pakiet something.big

0

@Pinek No tak myślałem, że można by także oddzielać kropką, ale zastanawiałem się bo wtedy robi się taki pusty pakiet something w którym nie będzie żadnej klasy, a tylko kolejny podpakiet big.

Domyślam się, że takiego sztywnego podziału nie ma, ale co zrobić np. w sytuacji opisanej przeze mnie w pierwszym poście ze wspólnymi klasami? Jak mam pod pakiety doctor i report i oba mają klasy dao i jakieś walidatory. Gdzie wtedy umieścić klasy nadrzędne wspólne dla kilku pakietów? Takie jak generyczne dao czy interfejs validator?

2
  1. Na wspólne elementy zrób osobny moduł, jakieś Commons czy Infrastructure
  2. Z podziałem nie ma prostej jednoznacznej odpowiedzi, czasem lepiej dzielić względem warstwy, a czasem względem funkcjonalności. Podział warstwami pasuje do monolitycznych aplikacji i utrudnia trochę rozbudowę do dodanie czegoś wymaga zmian we wszystkich warstwach. Jest też sensowne jeśli aplikacja ma dość wąski zakres funkcji (nie znaczy to że aplikacja jest prosta!). Dla aplikacji z mocno rozbudowaną warstwą logiki biznesowej i tak konieczne będzie podzielenie tej logiki na osobne moduły. Do tego dochodzi też kwestia ponownego użycia - możesz importować sobie jeden moduł jako bibliotekę, zamiast importować całej aplikacji.
1

Aplikacja dzieli się na moduły, a te dzielą się na warstwy. Współczesne IDE nie będą strzelać fochów jak zaciągniesz 20 modułów. Zatem dzielisz projekt na moduły pod kątem funkcjonalności, co efektywnie wytworzy ci moduły w rodzaju:

  • Commons – tu lądują wszelkie ogólne interfejsy, tu podłączasz zależności do np. JPA API.
  • Utils – gdzie wylądują klasy typu StringUtil, DateFormatter itp. Jest to też miejsce gdzie podłączasz zależności typu Guava
  • API – gdzie umieszczasz interfejs kliencki aplikacji

Do tego każda funkcjonalność ma własny moduł, który gada z innymi modułami za pomocą jakiegoś API lub za pomocą komunikatów po ESB (jak mała apka użyj Guava ESB).

0

@Koziołek nie wiem czy dobrze zrozumiałem, mógłbyś to bardziej rozwinąć na moim przykładzie z pierwszego postu? Czy w takim podziale jak Ty zaprezentowałeś moje pakiety doctor i reports znajdowałyby się w module API a tam podzielone ze względu na funkcjonalności? Czy może same stanowiłyby osobne moduły?

Wyglądałoby to mniej więcej tak:

  • Moduł Commons: wrzucam tutaj te wspólne interfejsy i klasy typu generyczne dao, walidator itp.

  • Moduł Utils: to tak jak napisałeś klasy narzędziowe typu StringUtil czy DateFormatter, zależności do Guavy, Apache Commons.

  • Moduł API: tutaj wrzucam te wszystkie swoje klasy dzieląc na funkcjonalności, jak w pierwszym poście

-doctor
--controller
--dao
--domain
--services
--view

-reports
--controller
--dao
--domain
--services
--view

1

Wydaje mi się, że to zależy od tego czy programiści pracują warstwami czy funkcjonalnościami.

Jeśli biznes wymaga od programistów dostarczania kolejnych funkcjonalności, jeśli taski są zdefiniowane w formie funkcjonalności, jeśli commity do repo są w postaci całych funkcjonalności, to... no, to moim zdaniem nie ma sensu się bawić w podział plików warstwami, bo będzie to podział zakłamany.

np. Ruby on Rails. Tam się dzieli projekt na katalogi, gdzie każdy katalog to inny rodzaj pliku (osobny katalog dla szabonów HTML, osobny dla kodu Ruby, który renderuje te szablony, osobny katalog na CSS, osobny katalog na JS) to efekt jest taki, że pracując nad jedną rzeczą, nad jednym komponentem, musiałem przeskakiwać po 4 czy więcej katalogach, i wszystko mi się mieszało.

Tak samo niektóre projekty w AngularJS, gdzie się dzieli na katalogi directives, templates, services, styles, co jest o tyle niefunkcjonalne, że i tak się pracuje potem na tym komponentami, a nie warstwami. Edytuje się jednocześnie templatkę HTML, CSS, dyrektywę, kontroler, więc tutaj raczej jest dużo lepiej jak masz jeden katalog z komponentem X, gdzie masz wszystko związane z komponentem X, wtedy nie musisz latać po całym projekcie, tak jak tutaj: https://scotch.io/tutorials/angularjs-best-practices-directory-structure

Jednak tu mi się wydaje, że potrzeba pewnej refleksji i nie kopiowania bezwiednie schematów (bo niestety ludzie zobaczą to w jakimś tutorialu albo ściągną w jakimś boilerplate i potem już tak zostaje, bo nie pomyślą, że można inaczej.

Z drugiej strony jeśli aplikacja ma wyraźną architekturę warstwową, to wtedy oczywiście podział katalogów na warstwy ma sens. Podział na warstwy jest fajny, jeśli faktycznie istnieje coś takiego w projekcie (w przypadku AngularJS to ciężko powiedzieć - z jednej strony serwisy są oddzielną warstwą, ale już np. zestaw dyrektywa+templatka HTML+styl CSS to dla mnie po prostu części jednego "komponentu", więc po co to dzielić sztucznie?).

Czyli w skrócie - uważam, że struktura katalogów powinna odzwierciedlać rzeczywistość/potrzeby danego projektu, a nie być kopiowaniem bezmyślnie cudzych praktyk.

1

W twoim przypadku nie ma API, ale kilka osobnych modułów typu reports, doctor itp. Przy czym moduł reprezentuje funkcjonalność, a nie fragment modelu domenowego. Ten można wywalić do commons, albo domain. Zatem reports „brzmi” ok, ale doctor pachnie mi próbą modularyzacji kawałka domeny (jakiegoś bytu domenowego), a nie funkcjonalności. Chyba, że w doctors masz coś w rodzaju wizyty, specjalizacje, grafik pracy (o ile to pet clinic).

1 użytkowników online, w tym zalogowanych: 0, gości: 1