Maven: moduły i cykliczne zależności między nimi.

0

Chciałbym stworzyć pewien projekt w oparciu o narzędzie MAVEN. Dobrze by było gdyby projekt, o którym mowa był podzielony na kilka modułów i wszystko byłoby ok gdyby nie pewien problem związany z encjami i ewentualnie z repozytoriami.

Otóż w pewnych sytuacjach może się zdarzyć, że moduł A do poprawnej pracy potrzebuje danych zapisanych w tabeli utworzonej z myślą o module B - potrzebuje więc dostać się do encji z modułu B. Problem w tym, że równie dobrze moduł B może potrzebować dostępu do tabeli utworzonej z myślą o module A.

W takim przypadku encje z obu modułów mogą być od siebie wzajemnie zależne co doprowadzi do tzw. cyklicznej zależności między modułami i problemu podczas budowania projektu.

Pewnym rozwiązaniem jest stworzenie wspólnego modułu, w którym przechowywane byłyby wszystkie encje (repozytoria pewnie tez) dla wszystkich modułów. Rozwiąże to problem cyklicznych zależności jednak odbędzie się to kosztem architektury (w takiej sytuacji musialbym trzymać encje o nazwie Produkt we wspolnym module a wolalbym umieścić ja w module "sklep internetowy" - to tylko przykład bo akurat nie chodzi tutaj o sklep internetowy).

Moje pytania:

  1. Czy w taki sposob rozwiązuje sie tego typu problemy w praktyce?
  2. Czy istnieje jakiś lepszy sposób na rozwiązanie tego problemu?
2

w takim wypadku wyciągasz sobie moduł C, ktory jest tylko interfejsem do komunikacji pomiędzy A i B. Zawiera wszystkie wspólne elementy.

2

Nie jestem pewien czy twoje podejście do "architektury" jest tu poprawne. Bo jak chcesz zapakować do "sklepu internetowego" wszystko co z nim związane (zarówno encje, dao jak i UI) to ten twój "moduł" wygląda już jak osobna aplikacja która sama w sobie powinna być podzielona na moduły ;] Czy nie jest czasem tak, że zrobiłeś właśnie taki projekt w stylu "mother of all projects" gdzie masz 17 różnych, jakośtam luźno powiązanych aplikacji? Bo to nie jest dobre podejście żeby takie cos trzymać jako jedną całość.

0
Shalom napisał(a):

Nie jestem pewien czy twoje podejście do "architektury" jest tu poprawne. Bo jak chcesz zapakować do "sklepu internetowego" wszystko co z nim związane (zarówno encje, dao jak i UI) to ten twój "moduł" wygląda już jak osobna aplikacja która sama w sobie powinna być podzielona na moduły ;]

Masz racje, że sklep internetowy to projekt, który powinien być podzielony na moduły a nie moduł. Jednak był to przykład nad którym się specjalnie nie zastanawiałem - kończąc wiadomość napisałem to co akurat przyszło mi do głowy.

Równie dobrze może to być projekt (niech już będzie ten sklep internetowy żeby za bardzo nie mieszać) gdzie modułami będzie np:

  • moduł magazyn
  • moduł księgowość
  • moduł raporty
  • itd.

Faktem natomiast jest, że miałem zamiar umieścić w każdym z modułów encje i dao (to źle?), UI już niekoniecznie.

Istnieje wiec pewna zaleznosc miedzy modulami. Np. zeby wygenerowac raport zwiazany z obladowaniem magazynu moge potrzebowac encji z modulu magazyn. Problemu jak na razie nie ma bo to jeszcze nie jest zaleznosc cykliczna. Gorzej by bylo jakbym dodatkowo w module magazyn potrzebowal encji z modulu raporty (troche malo prawdopodobne ale to tylko przyklad).

Wpadlem wiec na pomysl aby stworzyć modul odpowiedzialny tylko za dostep do danych - w nim bylyby przechowywane encje i tym podobne rzeczy, jednak srednio mi sie ten pomsyl podoba, choc cykl w takiej sytuacji nie ma prawa wystapic - przynajmniej nie w przypadku encji.

Co do modulu "raporty" to zdaje sobie sprawe z tego, ze czesc osob moze byc zwolennikami generowania raportow dotyczacych magazynu w module magazyn itd. (zwolennikow modulu "raporty" tez moze nie brakowac). Jest to jednak tylko przyklad dla zobrazowania tego o co mi chodzi.

Dodam tez, ze w praktyce nie wiem jakie jest prawdopodobienstwo wystapienia takiego przypadku z cyklem. Jak sobie ukladam w glowie realizacje roznych swoich pomyslow to widze co prawda zaleznosci miedzy modulami ale nie sa to zaleznosci cykliczne. No ale takie zdarzenie moze jednak wystapic i warto byloby sie zabezpieczyc przed wiekszymi zmianami w aplikacji z powodu jednej czy dwoch drobnostek :)

Shalom napisał(a):

Czy nie jest czasem tak, że zrobiłeś właśnie taki projekt w stylu "mother of all projects" gdzie masz 17 różnych, jakośtam luźno powiązanych aplikacji? Bo to nie jest dobre podejście żeby takie cos trzymać jako jedną całość.

Nie miałem zamiaru robić takich rzeczy. Podałem może niezbyt dobry przykład i stąd mogłeś dojść do takich wniosków :)

0

Ja bym to jednak dzielił trochę inaczej. Mniej dziedzinowo a bardziej funcjonalnie -> np. modułami niech będą kolejne "warstwy" aplikacji. Bo moduły muszą mieć jakiś sens istnienia. Na przykład fakt że deployujesz je osobno. Albo że ktoś pracuje tylko nad jakimś modułem. W przypadku który opisujesz nie bardzo jest to możliwe, bo u ciebie każdy moduł zawiera kawałek z każdej warstwy najwyraźniej.

0

@tk, zle podejście. Dzielisz moduły funkcjonalnie na poziomie mavena, ale nie na poziomie projektu. Inne podejście. Jeżeli moduł np. raportow potrzebuje danych z magazynu to niech pyta się o te dane za pomocą jakiegoś interfejsu. Oczywiście najprościej by dostał "gołe" dane na przykład chcesz mieć raport stan magazynu na koniec miesiąca. To moduł raportowy uderza do magazymy o stan na datę. Dostaje (przykładowo) mapę na ktorej już sobie pracuje.

0
Shalom napisał(a):

Ja bym to jednak dzielił trochę inaczej. Mniej dziedzinowo a bardziej funcjonalnie -> np. modułami niech będą kolejne "warstwy" aplikacji.

Ok, czyli proponujesz cos na zasadzie:

  • warstwa dostepu do danych (encje, repozytoria itd).
  • warstwa logiki biznesowej (servisy itd)
  • warstwa gui

Dobrze rozumiem?

Koziołek napisał(a):

@tk, zle podejście. Dzielisz moduły funkcjonalnie na poziomie mavena, ale nie na poziomie projektu. Inne podejście. Jeżeli moduł np. raportow potrzebuje danych z magazynu to niech pyta się o te dane za pomocą jakiegoś interfejsu. Oczywiście najprościej by dostał "gołe" dane na przykład chcesz mieć raport stan magazynu na koniec miesiąca. To moduł raportowy uderza do magazymy o stan na datę. Dostaje (przykładowo) mapę na ktorej już sobie pracuje.

Wbrew pozorom nie chodzi mi o to, zeby modul "raporty" przejal czesc logiki biznesowej, ktora powinna byc zawarta w module "magazyn" - bo tak to chyba zrozumiales, o ile ja poprawnie zrozumialem Twoja wypowiedz.

Modul magazym moze dostarczac stan magazynowy modulowi raporty, ale ten stan magazynowy czasem moze byc po prostu lista encji. Przykladowo modul magazym moze zawierac schedulera ktory na podstawie swojej wewnetrznej logiki wyznacza stan magazynowy i dodaje raz dziennie wpis do bazy danych, ktory ten stan zawiera. Jak modul raportow poprosi o historie stanow magazynu to dostanie nic innego jak wlasnie liste encji zawierajaca stan na kazdy dzien. Tutaj klasa encji bylaby przydatna w module raporty.

Tak czy inaczej to temat sie troche zagmatwal i chyba przyczyna takiego zagmatwania jest brak dobrego przykladu z mojej strony co prowadzi to do pewnych nieporozumien. Z drugiej strony na chwile obecna ciezko mi wymyslec na tyle dobry przyklad aby tych nieporozumien nie bylo - moze sie troche pospieszylem zakladajac ten watek.

Generalnie mowiac zaczelo sie od tego, ze w mojej glowie pojawila sie mysl, ze baza danych zawiera pewne tabele. Chcialbym te tabele budowac automatycznie na podstawie encji. Pomyslalem, ze relacje miedzy encjami moga wymusic na mnie pewna cykliczna zaleznosc modulow, ale jak staram sie wymyslec jakis przyklad to dochodze do wniosku, ze musialbym wymyslec przyklad zlego podzialu po to zeby pokazac o co mi chodzi. W momencie kiedy wymysle jakis poprawny podzial to akurat rozwiazuje sie problem cyklicznych zaleznosci :) Nie byloby w ogole problemu gdyby nie to, ze czuje, ze istnieje scenariusz z dobrym podzialem i problemem z cyklami :)

Ale tak z ciekawosci to jak rozwiazac taki problem? Zalozmy ze mam dwa moduly:

  • modul uzytkownicy (zawiera encje User oraz roznego rodzaju uslugi na uzytkownikach, o ktorych nie ma sensu wspominac na razie).
  • modul dokumenty (zawiera m.in. encje Document).

Encja User wygladalaby np. tak (odpuscilem sobie gettery, settery, adnotacje itd):


class User 
{
    private String name;
    private String password;  
}

Encja Document wygladalaby np. tak:


class Document
{
    private User owner;
    private String title;
    private String content;
}

Teraz co by bylo gdybym z poziomu encji User chcial miec dostep do listy dokumentow użytkownika? Mozna byloby zrobic to tak:


class User 
{
    private String name;
    private String password;  
    private List<Document> documents;
}

Ale Maven mi na to nie pozwoli, poniewaz kazda z encji jest w oddzielnym module. Tutaj nie jest to jakis wielki problem poniewaz mozna sie bez pola documents obejsc i tabele w bazie danych zbuduja mi sie poprawnie. Problem bylby natomiast wtedy kiedy wstawilbym dowolna encje w module uzytkownicy, ktora:

  • bylaby powiazana z encja z modulu documents
  • przechowywalaby klucz obcy do encji z modulu documents

No i chcialem wlasnie zapytac jak tego typu problemy obchodzic. W pierwszej kolejnosci wpadlem na pomysl aby stworzyc modul z samymi encjami i ewentualnie repozytoriami, ale srednio mi sie to podobalo. Shalom zaproponowal podzial na moduly ze wzgledu na warstwy co tez rozwiazuje problem ale bede musial sie zastanowic czy taki podzial bylby rzeczywiscie najlepszym rozwiazaniem, bo wydaje mi sie ze ma pewne wady ale najpierw chcialbym sie upewnic czy dobrze go rozumiem :)

1

W przykładzie który podałeś zrobiłbym podział warstwowy, tzn warstę danych wydzielił osobno. Warstwę serwisów możesz sobie juz podzielic na wiele modułów i zrobić wspólny moduł z interfejsami. Wtedy w ogóle nie ma problemu -> serwisy między sobą nie maja zalezności, potrzebują tylko interfejsu, a same są zależne od warstwy danych.
Ale gdybyś chciał zrobić jak jak pisałeś, tzn wpychać kawałek każdej warstwy, to wtedy podzieliłbym to na osobne aplikacje.

0

Dobrze, to moze jeszcze jedno pytanie. Załóżmy, że decyduje się na podział techniczny (różne warstwy systemu takie jak serwisy czy repozytoria stanowią różne moduły) a nie na podział biznesowy (modułem jest np. moduł o nazwie magazyn, który zawiera różne warstwy aplikacji). Przykładowy podział na moduły wyglądałby wtedy mniej-więcej tak:

  • moduł encje
  • moduł repozytoria
  • moduł uslugi

Załóżmy, że jedną z funkcjonalności systemu jest obsługa magazynu a ja potrzebuje encji "StanMagazynu", w której przechowywałbym stan magazynu w konkretnym dniu (odpalany raz dziennie scheduler). Encja ta byłaby umieszczona w modułe "encje". W jakiej paczce umieściłbyś tę encję?

  • bezpośrednio w paczce encje (czyli pełna nazwa klasy to encje.StanMagazynu)
  • w paczce encje.magazyn (czyli pełna nazwa klasy to encje.magazyn.StanMagazynu)
  • w paczce magazyn.encje (czyli pełna nazwa klasy to magazyn.encje.StanMagazynu)
  • innaczej?
1

To jest generalnie twoja sprawa, ale ja bym zrobił encje.magazyn.StanMagazynu, oczywiście w języku angielskim...

0
Shalom napisał(a):

To jest generalnie twoja sprawa, ale ja bym zrobił encje.magazyn.StanMagazynu

OK, dzieki za wypowiedz.

Shalom napisał(a):

oczywiście w języku angielskim...

Język polski został użyty wyłącznie na potrzeby posta :) W kodzie oczywiście użyje angielszczyzny.

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