Wzorzec mediator - zależność handlerów

Wzorzec mediator - zależność handlerów
Kordoba
  • Rejestracja:około 5 lat
  • Ostatnio:8 dni
  • Postów:149
0

Cześć, czy we wzorcu mediator (korzystajac z biblioteki MediatR) handlery mogą zależeć od samych siebie?
Tzn chodzi mi o to, czy powinny odpytywać inne handlery o jakieś dane im potrzebne?

SA
  • Rejestracja:około 12 lat
  • Ostatnio:około 3 godziny
  • Postów:1427
3
edytowany 2x, ostatnio: Saalin
99xmarcin
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 miesiące
  • Postów:2420
4

Generalnie nie, w obiekcie command powinieneś dostać wszystkie dane konieczne do wykonania komendy.
Jeżeli chodzi o query to nie był bym aż tak pewien. Oczywiście w idealnym świecie każde query jest oddzielne, ale czasami aż się prosi żeby np. złożyć wyniki z 3 innych query i w mojej opinii, o ile się z tym nie przesadza, jest to OK.

Problemy mogą się pojawić jeżeli masz jakieś PipelineBehaviour (aka aspekty) zapięte na handlerach. Jeżeli uwspólniać to być może za pomocą wydzielenia osobnego obiektu Query który nie będzie implementował żadnych interfejsów z MediaR'a.

Z drugiej strony w Query można też pozwolić sobie od czasu do czasu na duplikacje. To też nic złego (o ile z tym nie przesadzamy).


Holy sh*t, with every month serenityos.org gets better & better...
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Wrocław
4

Bez sensu by to było, a już na pewno łamałoby SRP.
Jeśli potrzebujesz w handlerze dodatkowych danych, to niech je dostarczy jakaś klasa do dostarczania tych danych, a nie inny handler.

edytowany 1x, ostatnio: somekind
AreQrm
  • Rejestracja:prawie 11 lat
  • Ostatnio:21 dni
  • Lokalizacja:Londyn
  • Postów:873
2

Nie. Jeśli handler FooHandler ma zrobić(lub potrzebuje danych) ABC, a BarHandler ma zrobić(lub potrzebuje) BCD, to wydziel sobie do osobnej klasy np BC i zawołaj w każdym z nich oddzielnie.
Oczywiście może będzie lepiej wydzielić A, B i C do soobnych klas itp, ale to już zależy od tego co tam się dzieje dokładnie.
U ciebie pewnie potrzebujesz jakiegoś dostępu do danych, repozytorium itp wydzielonego poza handler.


Kordoba
  • Rejestracja:około 5 lat
  • Ostatnio:8 dni
  • Postów:149
0

Ogólnie jeśli chodzi o logikę znajdującą się w takich handlerach, to co tam najczęściej powinno się znajdować?
Np. Pobranie czegoś z bazy danych, puszczenie to do wykonania przez logikę biznesową i zwrócenie do kontrolera jakiegoś DTO, albo innego wyniku?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Wrocław
2

To zależy od architektury Twojej aplikacji. Taki Handler może być zarówno skryptem transakcji, który łączy się z jakimś źródłem danych, przetwarza i zapisuje wynik gdzieś, jak wywoływać jakąś grubszą logikę w agregacie DDD.

Aventus
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
2

Chyba nie do końca rozumiem o co konkretnie chodzi. Coś takiego?

Kopiuj
public MyHandlerOne(IMediator mediator)
{
  _mediator = mediator;
}

public async Task Handler(DoSomething request)
{
  // ...
  var somethingElseResult = await _mediator.Send(new DoSomethingElse(request.SomeParam));// Handled by MyHandlerTwo
  // Do further processing using the request as well as somethingElseResult
  // ...
}

Jeśli tak to wyjdę chyba przedmówcom na heretyka ale nie widzę w tym nic złego. Paradoksalnie to właśnie może pomóc w utrzymaniu SRP, bo każda klasa (handler) będzie miała swoją odpowiedzialność, chociaż kwestia SRP to chyba jedno z najbardziej niejednoznacznych zagadnień w inżynierii oprogramowania, i tam gdzie ktoś widzi SRP ktoś inny widzi jego łamanie, a jeszcze ktoś widzi przerost formy nad treścią.

Tak czy inaczej jeśli DoSomethingElse jest odpowiedzialny za "odpalanie" jakiejś logiki która jest wywoływana z niejednego miejsca (np. z różnych części aplikacji) to ja nie widzę nic złego w takim podejściu. Mowa tutaj o sytuacjach gdzie ten drugi handler wykonuje bardziej zaawansowaną logikę, a nie przypadku gdzie dla każdego wyciągnięcia encji z bazy danych wywołujemy oddzielny handler, bo wtedy lepiej po prostu wstrzyknąć wymagane queries/repositories i użyć je bezpośrednio.

EDIT: Proszę jeszcze zwrócić uwagę że w zasadzie nie ma tutaj mowy o bezpośredniej zależności do innych handlerów. Paradoksalnie jawnych zależności mamy mniej bo nie musimy wstrzykiwać dodatkowych serwisów- tym zajmuje się inny handler. Ale handler wywołany przez mediator. Z perspektywy pierwszego handlera, (zakładając że mamy dobrze nazwane requesty) kod jest bardziej ekspresywny i skupia się na tym co ma być zrobione, a nie jak. Jak dotyczy jakiejś konkretnej odpowiedzialności tego konkretego handlera, zostawiając resztę pracy innemu handlerowi.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Wrocław
1

Handlery tworzą warstwie abstrakcji zwaną logiką aplikacji, czyli zarządzają przetwarzaniem żądań wysłanych do aplikacji, zarządzają realizacją logiki biznesowej, a następnie zwracają jakieś wyniki.
Pytanie zatem - dlaczego obiekty z jednej warstwy abstrakcji miałyby się ze sobą komunikować? Takie podejście zazwyczaj prowadzi do rozmycia warstw, czyli powstania kodu spaghetti.

Aventus
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
0

Nigdzie nie jest powiedziane że handlery należą tylko do warstwy aplikacji, to już zależy od programisty. Jeśli stosuje się takie podejście to faktycznie, można użyć argumentu że nie powinno być dalszego przepływu danych między innymi handlerami. Specjalnie używam tutaj sformułowania "przepływ danych" bo mówienie o zależności od innych handlerów może być mylące, o czym pisałem wcześniej. Rzecz tylko w tym że jeśli masz handlery odpowiadające za warstwę aplikacji to należało by być sumiennym i takie handlery nie powinny zawierać logiki biznesowej/domenowej. Co za tym idzie każdy handler bez wyjątku powinien posiadać co najmniej jeden odpowiadający mu serwis domenowy, a moim zdaniem to już przerost formy nad treścią bo przy zastosowaniu wzorca mediator to właśnie handlery mogą spełniać rolę serwisów, poza pewnymi wyjątkami gdzie faktycznie jest sens mieć dedykowany serwis.

Podsumowując- handlery mogą, a wręcz moim zdaniem powinny należeć do warstwy logiki biznesowej/domenowej, a co za tym idzie każdy handler powinien mieć logike odpowiedzialną za konkretną operację biznesową. Idąc dalej tym tokiem myślenia wysyłanie requestów z handlerów do innych handlerów jest czymś normalnym, promującym właśnie SRP i nie za bardzo widzę gdzie tu spaghetti kod. Owszem, to również ma swoje wady bo sprawdzając jakiś workflow trzeba również sprawdzić gdzie dany request jest obsługiwany, ale to nie świadczy o kodzie spaghetti. W przeciwnym razie można powiedzieć że chociażby każdy system oparty o mikroserwisy i asynchroniczną komunikację sieciową to jedno wielkie spaghetti, bo tam również różne części systemu reagują na polecania i/lub zdrzenia wysyłane przez inne części. Mając dobrze wydzielone handlery unikamy wręcz kodu spaghetti bo każdy zajmuje się konkretnym elementem logiki biznesowej, w swoim własnym zakresie, delegując resztę pracy do innego handlera jeśli jest taka potrzeba. Tylko znów chcę zaznaczyć że wysyłanie/delegowanie do handlera jest sformułowaniem mylącym, bo handler wysyłający nowy request nic nie wie o innym handlerze, nie ma więc bezpośredniej komunikacji handler -> handler. Jedyne co takiego handlera interesuje to wysłać request i otrzymać wynik- a co, jak i gdzie jest obsługiwane to nie jego sprawa. Rozbijamy więc jeden większy workflow na kilka małych pod-systemów (handlerów), każdy odpowiedzialny za swój ograniczony element logiki biznesowej.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
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)