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

Maven: moduły i cykliczne zależności między nimi.
TK
  • Rejestracja:ponad 13 lat
  • Ostatnio:21 dni
  • Postów:342
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?
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:4 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
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.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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ść.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
TK
  • Rejestracja:ponad 13 lat
  • Ostatnio:21 dni
  • Postów:342
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 :)

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:4 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
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.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
TK
  • Rejestracja:ponad 13 lat
  • Ostatnio:21 dni
  • Postów:342
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):

Kopiuj

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

Encja Document wygladalaby np. tak:

Kopiuj

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:

Kopiuj

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 :)

edytowany 4x, ostatnio: tk
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
TK
  • Rejestracja:ponad 13 lat
  • Ostatnio:21 dni
  • Postów:342
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?
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

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


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
TK
  • Rejestracja:ponad 13 lat
  • Ostatnio:21 dni
  • Postów:342
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.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)