Jak zrozumiec warstwy w aplikacji?

Jak zrozumiec warstwy w aplikacji?
kalimata
  • Rejestracja:prawie 5 lat
  • Ostatnio:5 miesięcy
  • Postów:131
0

Jak zrozumieć wartstwy w aplikacji i to, co się ma dziać w której? W
Załóżmy ze mam w aplikacji projekty (odpowiadajace warstwom)

  • Core
  • Application
  • Infrastructure
  • UI

Już na samym początku pojawiły mi sie wątpliwości, bo np w projekcie Core definiuije sobie klase
public class Employee

Kopiuj
{
 public string Name{get;set;}
 public int Age {get;set;}
}

Chciałbym to zapisać do bazy. Do tego bedzie uzyty projekt Infrastructure, który w referencji ma projekt Core. Jako ORM używam EF Core. No ale pytanie, gdzie się ma odbyć ten zapis? W Core czy w Infrastructure, no i jak to ma wyglądać?
Według tego co czytałem, nie moge przekazać do projketu Core referencji do Infrastructure (bo to Infrastructure ma mieć referencje do projketu Core). Myślałem nad zrobieniem i korzystaniem w projekcie Core interfejsu:

Kopiuj
public interface IWorkDbContext
{
 DbSet<Employee> Employees{get;set;}
 Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}

i wtedy ten interfejs implementowałby też mój DbContext w projekcie Infrastructure

Kopiuj
public class WorkDbContext : DbContext, IWorkDbContext
{
 //...
}

no, ale chciałem zrobić projekt database first i w bazie kolumny mają inne nazwy niż w encji Employee (i chce zeby tak zostało).
Jak to wsyzstko dobrze poustawić? Może nakierujecie mnie na jakiś przykładowy projekt.
Chciałem pisać aplikacje WPF ale wszsytkie przykłady jakie znajduje sa dla web i nie mogę tego przełożyć na swój problem.

Zobacz pozostałe 4 komentarze
AK
+1 za myśli: jeśli niezrozumiałe -> nie brnąć. Dobra architektura JEST zrozumiała dla profesjonalisty (który np przyszedł do firmy)
AdamWox
Ale co decyduje o dobrej architekturze? Sposobów na porządek w projekcie jest masa. Dlaczego akurat ten jest dobry? Jakie korzyści mam? Czepiam się bardziej, że jak coś na wstępie jest niezrozumiałe to znaczy, że nie jest proste. Skoro ktoś musi napisać wątek z zapytaniem gdzie, co powinno być tzn, że nie jest to takie oczywiste i autor idzie w kierunku tej architektury, bo jest popularna, a nie bo jest pomocna 🤔
somekind
@AdamWox: Ty czasem nie założyłeś ostatnio tematu o tym, że masz problemy z rozbudową aplikacji?
somekind
@AnyKtokolwiek: Core to nie jest żadne typowo dotnetowe słowo. Po prostu autor tego kodu tak sobie nazwał, ale to nie jest żaden powszechny wzorzec.
AdamWox
@somekind: tak, ale to nie była kwestia architektury, tylko moje, głupie podejście do filtrów i paginacji danych. OData w tym momencie rozwiązała mój problem.
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
5

Według tego co czytałem, nie moge przekazać do projketu Core referencji do Infrastructure (bo to Infrastructure ma mieć referencje do projketu Core). Myślałem nad zrobieniem i korzystaniem w projekcie Core interfejsu:

Dlatego masz jakiś interface. W Core masz interface w stylu EmployeeRepository a w infrastrukturze robisz EmployeePostgresRepository i tą implementacje wstrzykujesz do jakiegoś UseCase'a z warstwy domeny.


SZ
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 9 godzin
  • Postów:1475
1

Jak tworzę solucje to robię jak w tym pdfie https://github.com/jasontaylordev/NorthwindTraders/blob/master/Docs/Slides.pdf

Jest tam krótko wyszczególnione co w której warstwie. Jeśli wchodzę w projekt istniejący to robię analogicznie to istniejącej implementacji.
Btw:
dla mnie ten interface dla dbContextu to trochę nieporozumienie bo jest on uzależniony od EF (db sety).

WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:dzień
  • Postów:5109
3

@AdamWox:

Ja nigdy tego nie rozumiałem. Uważam to za kompletną stratę czasu. Durne doktoryzowanie się nad - "jak to powinno być", bo jakiś pacan wymyślił argumentując, że "tak jest dobrze" i 3/4 firm programistycznych w to idzie. Czy twoim zdaniem jest sens to drążyć? Czy skoro nie jest to takie oczywiste dla ciebie "gdzie, co i jak" to nie szkoda ci czasu? Czy ten "sposób" jest narzucany przez firmę, w której pracujesz? Masz możliwość stworzyć swój "sposób"?

Wiesz, no chyba na tym polega cały trik

Wyjdźmy w ogóle od definicji:

Inżynieria – działalność polegająca na projektowaniu, konstrukcji, modyfikacji i **utrzymaniu efektywnych kosztowo rozwiązań dla praktycznych problemów**, z wykorzystaniem wiedzy naukowej oraz technicznej.

Co ja rozumiem jako - mierzyć siły na zamiary

Jasne, jeżeli masz prostą appkę 5 podstronek, 10 tabelek w bazce z czego 5 jakichś słowników, to może faktycznie nie ma sensu robić tego state of art

Zrobisz sobie jeden projekt, viewmodele tylko do jakichś critical rzeczy typu uniknąć wysłania user password, czy jak najdzie cię fanciness to podepniesz mediatra zrobisz 5 query, 5 command i wszystko będzie chodzić i nadal będzie proste w ogarnięciu

Ale te wszystkie rzeczy od podziału na projekty, dtosy/viewmodele czy nawet accessibility modifiers chronią od fuckupów, może nie twoich, ale kolejnych devów, którzy nie będą znali projektu, a będą musieli coś w nim zmienić.

Nawet jeżeli ta "architektura" nie jest perfekcyjna, to i tak chyba lepsze są standardy i konwencje niż company's_framework, albo właściwie pytanie jaki jest kompromis?

edytowany 3x, ostatnio: WeiXiao
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
2
kalimata napisał(a):

Według tego co czytałem, nie moge przekazać do projketu Core referencji do Infrastructure (bo to Infrastructure ma mieć referencje do projketu Core). Myślałem nad zrobieniem i korzystaniem w projekcie Core interfejsu:

Kopiuj
public interface IWorkDbContext
...

i wtedy ten interfejs implementowałby też mój DbContext w projekcie Infrastructure

Kopiuj
public class WorkDbContext : DbContext, IWorkDbContext
...

Idziesz w dobrym kierunku. Z odpowiedzią przychodzi onion architecture i to że zgodnie z myślą takiej architektury warstwy znajdujące się najbardziej w środku (w Twoim przypadku Core) operują na abstrakcjach, a implementacje tych abstrakcji dostarczają warstwy zewnętrzne (w Twoim przypadku Infrastructure). Jedyne co bym radził to usunąć z warstwy Core wszelkie detale implementacje, a więc w Twoim przypadku IWorkDbContext wystawiające DbContext powinno być wymienione na jakieś repozytorium lub coś podobnego. Wtedy implementacja tego repozytorium (w Infrastructure) może korzystać bezpośrednio z EF czy czegokolwiek innego, ale dla warstwy Core będzie to transparentne.

no, ale chciałem zrobić projekt database first i w bazie kolumny mają inne nazwy niż w encji Employee (i chce zeby tak zostało).

To już jest oddzielny problem dotyczący ORMa. Dla czego chcesz aby modele w warstwie Core odpowiadały temu co wypluwa EF skoro powoduje to problemy? Warstwa Core nie powinna być "skażona" narzutem powodowanym przez jakiekolwiek frameworki. Zawsze możesz mapować z modelu bazy danych na model domenowy (Core).

Jak to wsyzstko dobrze poustawić? Może nakierujecie mnie na jakiś przykładowy projekt.

Tak jak napisałem, odpowiedzią jest onion architecature. Z przykładowym projektem najlepiej skorzystać z tego co oferuje Microsoft, a mianowicie ich (darmowa) książka i wspierający ją kod.

Chciałem pisać aplikacje WPF ale wszsytkie przykłady jakie znajduje sa dla web i nie mogę tego przełożyć na swój problem.

Problemy architektoniczne zazwyczaj są uniwersalne. WPF to przede wszystkim technologi frontendu. Backend możesz mieć oddzielny. Front napisany WPF traktuj tak jak front w przypadku aplikacji webowych. Różnica jest tylko w tym że front zamiast korzystać z protokołu HTTP do komunikacji, będzie korzystał z jakiejś abstrakcji przekazującej polecenia do właściwej warstwy biznesowej. Polecam do tego wzorzec mediator.

WeiXiao napisał(a):

@AdamWox:

Wiesz, no chyba na tym polega cały trik
...
Co ja rozumiem jako - mierzyć siły na zamiary

Dokładnie. Wszystko ładnie i pięknie dopóki nie przychodzi utrzymywać większego systemu. Nagle braki w odpowiedniej architekturze doprowadzają wydawało by się drobne przeszkody do absurdalnych rozmiarów.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus
WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:dzień
  • Postów:5109
2

Taki trochę sanity check możesz sobie zrobić odpowiadając na pytanie:

Masz napisaną aplikacje webową (np. liczenie czegoś lub cokolwiek innego dającego się zrobić po stronie klienta) i nagle klient chciałby również desktopa i mobilkę.
Ile musisz pozmieniać w kodzie od czysto logiki biznesowej?

albo po prostu

Jak łatwo idzie ci pisanie testów?

Jeżeli dużo/ciężko, to prawdopodobnie za dużo rzeczy tam się dzieje, co również pewnie utrudnia testowanie.

Ja wierzę, że pewnie do takiej sytuacji nie dojdzie, ale jak duży jest ten narzut? to już musisz sam sobie odpowiedzieć

edytowany 6x, ostatnio: WeiXiao
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0
kalimata napisał(a):

Jak zrozumieć wartstwy w aplikacji i to, co się ma dziać w której? W

Załóżmy ze mam w aplikacji projekty (odpowiadajace warstwom)

  • Core
  • Application
  • Infrastructure
  • UI

Powinieneś do tego dodać jeszcze trochę...

  • Models - to projekt z Twoimi modelami biznesowymi (np. Employee)
  • DAL (DataAccessLayer) - projekt, w którym masz obsługę bazodanową. Czy to w postaci repozytoriów, czy ORMa, czy ADO.NET. Nie łącz mi ORMa z repozytorium (chyba, że używasz Dappera)

I ja to widzę tak:

  • UI - no to wiadomo. Twój klient, całe UI (ale nie tylko widoki, również ViewModele itd)
  • Infrastructure - tutaj ładowałbym wszystkie interfejsy
  • Application/Core - no to w zależności od potrzeb. Generalnie tu powinny być konkretne klasy implementujące interfejsy z Infrastructure.

I teraz ważne - Models - nie powinno mieć referencji do żadnej innej warstwy przy takim układzie.

  • Infrastructure może korzystać raczej tylko z Models
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Wrocław
4

Infrastructure to raczej miejsce na implementacje, np. repozytoriów czy klientów zewnętrznych serwisów jeśli działamy zgodnie z clean architecture, albo różnych pomocniczych rzeczy, jeśli piszemy po swojemu. Interfejsy do tych implementacji to raczej w jakiejś domenie ewentualnie aplikacji siedzą.

JU
A jakbyś nazwał projekt z samymi interfejsami?
Aventus
@Juhas Ja bym nie nazwał bo bym takiego nie miał. Często widzę interfejsy w jednym projekcie lub przestrzeni nazwy, najczęściej Contracts. Ale ja jestem zwolennikiem trzymania interfejsów "bliżej" gdzie należą, oraz odpowiednio pogrupowanych. Czyli dla przykładu w projekcie domenowym Repositories, Queries (jeśli używa się oddzielnych), Services itp. Chociaż z tym ostatnim to też rośnie bo czasem lepiej dać interfejs serwisowy do konkretnej przestrzeni nazw.
somekind
@Juhas: Patologią. :P Interfejsy deklaruję w warstwie/projekcie, która ich używa, a implementuję tam, gdzie to prawidłowe z punktu widzenia architektury. Istnieje wszakże możliwość, że robiłbym jakąś bibliotekę, i dostarczał jej domyślną implementację, to wtedy pewnie zrobiłbym coś w rodzaju JakaśBibiloteka.Abstractions.
JU
Abstractions... Podoba mi się. Natomiast trzymanie interfejsów w projekcie, który ich używa nie podoba mi się. Tzn. jeśli interfejs jest używany tylko w jednym projekcie, to ok. Natomiast i tak chyba to może utrudniać testowanie.
somekind
Absolutnie nie utrudnia testowania. Mam np. projekt Shop.Domain, który zawiera IZiemniakRepository. Mogę w pełni przetestować jednostkowo Domain. A implementacja tego interfejsu znajduje się w projekcie Shop.Infrastructure.Cosmos
JU
OK, ale jeśli masz jakiś interfejs np. w projekcie WPF albo WebApp, to wtedy będzie problematyczne, bo trzeba będzie dołączać bez sensu cały framework do projektu testowego. Czy to jest wtedy dobre rozwiązanie? No zależy jeszcze jak i gdzie jest używany ten interfejs.
somekind
Nie bardzo rozumiem pytanie, który framework masz na myśli?
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)