Podział aplikacji na podprojekty

0

Cześć, ostatnio robię aplikacje internetową asp.net (organizer pracy) w technologii mvc4 i mam pytanie odnośnie podziału aplikacji na pod projekty. Doradzono mi bym stworzył 3 pod projekty. Jeden z operujący bazą danych, drugi zawierający całą logikę i trzeci główny zawierający web interfejs.
Czy taki podział aplikacji ma duży wpływ na jej jakość tzn. jest potrzebny?
Czy jeśli pobieram enity frameworka, to tylko załączam go do tego projektu operującego bazą danych?
Może lepiej użyć nhibernate, bo baza danych nie będzie jakaś obszerna?

Z góry dzięki i pozdrawiam :)

0

Poczytaj o wzorcu MVC. Tu nie chodzi o "podprojekty", tylko podział jednego projektu na trzy warstwy Model-View-Controller. Odpowiednio model danych, widok (prezentację), i logikę biznesową.

0
Mikios napisał(a):

Cześć, ostatnio robię aplikacje internetową asp.net (organizer pracy) w technologii mvc4 i mam pytanie odnośnie podziału aplikacji na pod projekty. Doradzono mi bym stworzył 3 pod projekty. Jeden z operujący bazą danych, drugi zawierający całą logikę i trzeci główny zawierający web interfejs.
Czy taki podział aplikacji ma duży wpływ na jej jakość tzn. jest potrzebny?

Podział na warstwy ma wpływ na jakość, bo dzięki niemu kod jest usystematyzowany, a nie staje się spaghetti. Poszczególne warstwy mogą być w oddzielnych projektach, dzięki temu też łatwiej zapanować nad strukturą, bo fizycznie oddzielamy pliki z poszczególnych warstw, więc trudniej wprowadzić bałagan.
Należy tylko pamiętać, ze sam podział na warstwy i moduły nie gwarantuje jakości.

Czy jeśli pobieram enity frameworka, to tylko załączam go do tego projektu operującego bazą danych?
Może lepiej użyć nhibernate, bo baza danych nie będzie jakaś obszerna?

LOL
Entity Framework to zabawka dla przedszkolaków, słabe rozwiązanie dla małych baz i aplikacji. Niektórzy co prawda używają EF do dużych systemów, ale cierpi na tym wydajność i produktywność.
NHibernate to znacznie dojrzalsze, wydajniejsze i elastyczniejsze rozwiązanie, znacznie lepsze właśnie do dużych projektów.

1
Nie Mam Konta napisał(a):

Poczytaj o wzorcu MVC. Tu nie chodzi o "podprojekty", tylko podział jednego projektu na trzy warstwy Model-View-Controller. Odpowiednio model danych, widok (prezentację), i logikę biznesową.

Chyba mylisz MVC z n-tier. Całe MVC jest wzorcem warstwy prezentacji (a nie sam widok), pakowanie tam logiki biznesowej nie jest najlepszym pomysłem. Projekt MVC powinien tylko operować na gotowych serwisach innej warstwy.

0

Samo MVC wskazuje Nam na 3 wydzielone warstwy naszej aplikacji. Ewentualnie 4 ze względu na to, że można wziąć pod uwagę ViewModele aby odciążyć system bazodanowy.

Oprócz tego mam taką praktykę ( nie wiem czy tak się fachowo robi ), że w osobnym projekcie wydzielam sobie warstwe dostępu do danych np. DataAccessLayer(DAL), tam również zawieram Repository i UoW.

Natomiast dodatkowo, jeśli korzystasz z serwisów to warto do osobnego projektu sobie je również wydzielić.

Ogólnie chodzi o lepszą organizacje kodu co ułatwia później rozwój aplikacjii.

3
Odyn napisał(a):

Samo MVC wskazuje Nam na 3 wydzielone warstwy naszej aplikacji. Ewentualnie 4 ze względu na to, że można wziąć pod uwagę ViewModele aby odciążyć system bazodanowy.

ViewModele to nie jest ani warstwa ani odciążenie bazy danych, to tylko klasy.
MVC to jest wzorzec dla jednej warstwy - warstwa prezentacji. Za to Model może już się składać z n warstw.

Oprócz tego mam taką praktykę ( nie wiem czy tak się fachowo robi ), że w osobnym projekcie wydzielam sobie warstwe dostępu do danych np. DataAccessLayer(DAL), tam również zawieram Repository i UoW.

To akurat dobra praktyka, z dokładnością do tego, że w DAL umieszcza się implementacje repozytoriów, bo repozytoria to logika biznesowa.

0

Repozytoria w żadnym wypadku nie są logiką biznesową aplikacji. Powinny się ograniczać wyłącznie do operacji CRUD. MVC to jak ktoś już wspomniał wzorzec prezentacji. Nie potrafie sobie wyobrazić jak View Modele miałyby odciążyć bazę danych:D, wręcz odwrotnie, obciążają serwer. View modele są wykorzystywane do zapewnienia większej separacji w warstwie prezentacji. W tym wypadku wszystkie POCO/DTO z warstw niższych mapowane są na ViewModels w np. warstwie usług aplikacji, dzięki temu warstwa prezentacji nie zawiera do nich referencji. Porównywanie NHibernate z ET to jakaś głupota, oba frameworki służą do tego samego i różnią się detalami. Zamiast męczenia się relacyjnymi bazami danych polecam NOSQL (np. RavenDb czy MonboDb) - w 95% aplikacje które budujemy nie potrzebują atomowości danych czy narzędzi do raportowania z MSSQL. Do tego praca z takim RavenDb to czysta przyjemność. Można nawet pokusić się o zrezygnowanie z repo bo RavenDb jest implementowany w postaci właśnie UOW. Wszystko zależy od tego jakiej wielkości budujesz aplikacje i co będzie się z nią działo póżniej. Jednak minimum architektury zawsze należy zapewnić. Jeśli nie masz wielu reguł biznesowych - skorzystaj z Transaction Script - odsyłam do Fowlera. Ew Domain Model z kontraktami repo + implementacja repo w wartwie infrastruktury. Wszelka logika biznesowa która wymaga zestawów danych powinna być implementowana w warstwie usług DM w której można związać logikę biznesową z danymi. Zamiast warstwy usług można także skorzystać z imo ciekawszego rozwiązania jakim jest ServiceBus i zbudować aplikację w oparciu o CQRS (przykład tutaj: https://github.com/gregoryyoung/m-r/tree/master/SimpleCQRS). Podsumowując, dla bardzo prostej aplikacji która nie będzie w przyszłości rozwijana: Transaction Script, bardziej złożona (choć nie koniecznie jeśli czujesz się bardziej pewnie w paradygmacie obiektowym) Domain Model i/lub CQRS.

1

Nie potrafie sobie wyobrazić jak View Modele miałyby odciążyć bazę danych:D, wręcz odwrotnie, obciążają serwer

Dlaczego? Najczęstszą przyczyną problemów typu N+1 SELECT jest korzystanie z modeli bazodanowych bezpośrednio w widokach.

Porównywanie NHibernate z ET to jakaś głupota, oba frameworki służą do tego samego i różnią się detalami

No tak, oba są ORMami więc służą do tego samego więc pewno różnią się tylko detalami :P. A feature listy obu się bardzo różnią.

Repozytoria w żadnym wypadku nie są logiką biznesową aplikacji. Powinny się ograniczać wyłącznie do operacji CRUD.

Jesli korzystamy z ORMa to CRUDowe repozytoria są krokiem wstecz.

Można nawet pokusić się o zrezygnowanie z repo bo RavenDb jest implementowany w postaci właśnie UOW

To tak jak przy NHibernate czy ET, ORM sam robi za repozytorium.

Zamiast warstwy usług można także skorzystać z imo ciekawszego rozwiązania jakim jest ServiceBus i zbudować aplikację w oparciu o CQRS

Może jest ciekawsze, ale IMO w 90% aplikacji niepotrzebne.

1
Zimny Młot napisał(a):

Repozytoria w żadnym wypadku nie są logiką biznesową aplikacji. Powinny się ograniczać wyłącznie do operacji CRUD.

Repozytoria to kontrakty źródeł danych dla logiki biznesowej, z jej punktu widzenia mają się zachowywać po prostu jak kolekcja encji. To, że konkretne implementacje repozytoriów wykonują operacje CRUD na bazie nie zmienia faktu, że ich kontrakty muszą być częścią logiki biznesowej, żeby mogła ona na nich operować. W tym sensie repozytoria są częścią logiki biznesowej - co nie znaczy, że ją wykonują.

Nie potrafie sobie wyobrazić jak View Modele miałyby odciążyć bazę danych:D, wręcz odwrotnie, obciążają serwer.

To uwaga do wszystkich - same ViewModele nie odciążają ani nie obciążają bazy danych... No chyba, że trzymamy w niej kod C#. ;)

Odciążyć może generowanie ViewModeli na poziomie warstwy dostępu do danych, która zbuduje optymalne zapytania. Tylko to wymaga odejścia od podejścia z repozytoriami zwracającymi encje na rzecz prostoty i wydajności.

Porównywanie NHibernate z ET to jakaś głupota, oba frameworki służą do tego samego i różnią się detalami.

NHibernate oferuje wbudowane cache drugiego poziomu, kilka generatorów PK, obsługuje różne rodzaje kolekcji, możliwość batchowego wykonywania zapytań, pełną konfigurowalność (w dowolnym miejscu można się wpiąć i zmienic domyślne zachowanie lub wykonać dodatkową operację), możliwość wykonywania operacij bez wczytywania obiektów (w EF, żeby usunąć obiekt z bazy, musisz go najpierw odczytać!) i daje pełną kontrolę nad generowanym kodem SQL.

EF ma za to tylko LINQ providera generującego kod SQL metodą Monte Carlo. No i od grudnia zeszłego roku obsługuje takie skomplikowane elementy składni SQL 2012 jak OFFSET FETCH. Do tego implementuje własną matematykę, bo domyślnie przy zapisie liczby zmiennoprzecinkowej nie wykonuje zaokrąglenia tylko ucięcie miejsc po przecinku.

To są detale?

Do tego praca z takim RavenDb to czysta przyjemność. Można nawet pokusić się o zrezygnowanie z repo bo RavenDb jest implementowany w postaci właśnie UOW.

No, a w ORM to nie można? Dziwne, bo ja (o ile mam wpływ na projekt) repozytoriów nigdy nie używam. Repozytoria w 99% aplikacji nie są potrzebne, bo 99% aplikacji nie potrzebuje DDD. A ISession czy nawet głupi DbContext są same w sobie implementacjami UoW.

0

A ma ktoś może jakiś project example z podpiętym i skonfigurowanym NHibernatem?

0

@Mikios, podpięcie to zainstalowanie paczki Fluent NHibernate z NuGeta i napisanie banalnej klasy budującej konfigurację. Masz jakiś konkretny problem?

0

@somekind @Mikios Entity Framework z racji popularności, doczekał się m.in. takiego projektu https://genericunitofworkandrepositories.codeplex.com/ .
Po stwierdzeniu

Entity Framework to zabawka dla przedszkolaków, słabe rozwiązanie dla małych baz i aplikacji.
aż z ciekawości sobie sprawdzę jakiś przykładowy projekt napisany z NHibernate, bo przyznam że choć EF 6.1 jest zdecydowanie lepszy względem poprzednich wersji, to jednak ciągle jednak nie zachwyca.
Znalazłem coś takiego: https://github.com/sharparchitecture/Sharp-Architecture

3

@QwertzOne, repozytoria z definicji powinny definiować ścisłe kontrakty dla logiki biznesowej i izolować ją od źródła danych. Udostępnianie generycznych repozytoriów logice biznesowej to po prostu łamanie tego wzorca, bo po pierwsze w ten sposób wcale nie definiujesz żadnego kontraktu (bo nie masz specyficznych dla danej encji metod), dla większości przypadków takie repozytorium zawiera zbyt wiele metod (nie zawsze potrzebujesz GetAll, Save albo Delete. A udostępnianie metod zwracających IQueryable to po pierwsze wyciek abstrakcji, bowypuszczasz szczegół implementacji technologi dostępu do danych do logiki biznesowej, a po drugie przyczyna problemów wydajnościowych, bo logika biznesowa czy nawet warstwa prezentacji powodują wtedy materializację, a co za tym idzie dzięki lazy loading mogą spowodować problem n+1.

Repozytoria to są przede wszystkim INTERFEJSY z deklaracjami metod definiujących kontrakt dostępu do danych dla logiki biznesowej, a nie implementacja używająca takiego czy innego ORMa, żeby udawać jakąś separację między aplikacją a bazą.

Czy Microsoft promuje antywzorce? W dużej mierze tak - wszystkie ich oficjalne tutoriale do ASP.NET MVC łamią zasady tego wzorca, mają trywialne błędy projwktowe w bazowych bibliotekach (np. DateTime.Now nie powinno być właściwością), do tego np. MembershipProvider łamie podstawowe zasady SOLID, a taki System.Web to kupa legacy code.

I jeszcze coś - to, że coś się kompiluje i działa, nie znaczy jeszcze, że jest dobrze zrobione. A to, że wszyscy coś robią, nie znaczy od razu, że tak jest dobrze. Często jest wręcz przeciwnie.

0

@somekind Czy oceniając czy coś jest dobrze zrobione, nie powinno brać się pod uwagę skali projektu? Dla większego systemu takie rozwiązania nie będą się nadawać i o tworzeniu takich systemów nie mam pojęcia, ale w przypadku małych, średnich projektów (czyli takich którymi zajmuje się wielu programistów) kosztem łamania części "dobrych" wzorców, które sprawdzają się w większych projektach czy wycieków abstrakcji (myślę, że te ew. zawsze się pojawią i można iść na kompromis, przyjmując kiedy są akceptowalne), zyskuje się prostotę i czas, mniej doświadczonym osobom też łatwiej wejść do takiego projektu.
PHP + MySQL zyskały popularność, bo były proste, dzisiaj mamy m.in. C#, node.js, tony framework'ów/bibliotek javascriptowych(które odgrywają coraz większą rolę z popularyzacją SPA), z których użyciem można pisać prosto i przyjemnie, bez konieczności posiadania dużej wiedzy o tworzeniu architektury.
Przeciętni programiści stanowią większość, jest więc i na to popyt.

1

Ja jestem jak najbardziej za uproszczeniami i stosowaniem jak najprostszej architektury w stosunku do rozmiaru zadania. Ale jak ma nam w tym pomóc:

  1. nazywanie repozytorium czegoś, co z repozytorium nie ma nic wspólnego?
  2. tworzenie własnej abstrakcji w postaci generycznego repozytorium opakowującego kontekst EF, który sam w sobie jest przecież generycznym repozytorium?
  3. popełnianie elementarnych błędów, takich jak dopuszczenie do powstania n+1?

Zrobienie czegoś dobrze nie oznacza, że trzeba na to poświęcić więcej czasu. Często właśnie wręcz przeciwnie. Tylko trzeba przestać na siłę wciskać wszędzie antywzorce, do których jest się przyzwyczajonym.

0

Możesz napisać coś więcej o punkcie 2 i 3?

Jak powinna wyglądać dobrze zaprojektowana aplikacja?
Mam coś takiego: kontroler operuje na interfejsie, który reprezentuje operacje na konkretnej tabeli(klasie POCO) w bazie danych. Ten interfejs implementuje klasa, która operuje na interfejsie kontekstu. Z wykorzystaniem IoC.

Co jest złego w zwracaniu do kontrolera IQueryable<T>? Każda książka do ASP.NET MVC ma taki przykład z Lazy Loading.

Co do punktu 3. Problem N + 1 występuje gdy nie korzysta się z Lazy Loading i chce się pobrać listę obiektów połączonych relacją z inną tabelą. Wtedy dla każdego obiektu są pobierane w oddzielnym poleceniu obiekty połączone relacja.
W takim razie czy IQueryable<T> nie rozwiązuje tego problemu?

3
Gorzec napisał(a):

Jak powinna wyglądać dobrze zaprojektowana aplikacja?

Powinna trzymać się zasad SOLID, a chociaż SRP. Czyli:

  1. Klasa, która opisuje format danych w bazie, nie powinna służyć do wyświetlania ich użytkownikowi. Chociażby dlatego, że często użytkownik potrzebuje widzieć mniej albo więcej danych, niż te zawarte w jednej tabeli. Dlatego w widokach wyświetla się viewmodele, a nie encje.
  2. Jeśli mamy warstwę dostępu do danych, to ona powinna zwracać dane pobrane z bazy, a nie wirtualne zapytanie. Dlatego kontrolery nie powinny pracować na IQueryable.
  3. Klasa służąca do obsługi żądań użytkowników, wołania modelu i przekierowania widoku, nie realizacji logiki biznesowej ani pobierania danych z bazy. Chodzi mi w tym momencie o kontrolery - i o tej ich odpowiedzialności wyraźnie mówi wzorzec MVC.

Mam coś takiego: kontroler operuje na interfejsie, który reprezentuje operacje na konkretnej tabeli(klasie POCO) w bazie danych. Ten interfejs implementuje klasa, która operuje na interfejsie kontekstu. Z wykorzystaniem IoC.

Jak chcesz, ale to nie jest na pewno MVC, i na pewno nie masz tam repozytoriów.

Co jest złego w zwracaniu do kontrolera IQueryable<T>? Każda książka do ASP.NET MVC ma taki przykład z Lazy Loading.

Kontroler powinien dostać gotowe dane do przekazania do widoku, a nie wyciągać je z bazy. I nie powinien nic wiedzieć o konkretnej technologii dostępu do danych. Ani nawet o tym, że gdzieś tam jest baza danych.
Przykłady w książkach do ASP.NET MVC to uproszczone przykłady jak działa ten framework, a nie jak należy pisać sensowne aplikacje.

Problem N + 1 występuje gdy nie korzysta się z Lazy Loading

Jesteś pewien?
Ten problem występuje, gdy nawigujemy po właściwościach obiektów z jakiejś listy. Jeśli są one leniwe, to dla każdego obiektu z listy zostanie wykonane zapytanie do bazy. Jeśli obiekty listy wczytamy zachłannie z ich właściwościami, to problem ten przecież nie wystąpi.

W takim razie czy IQueryable<T> nie rozwiązuje tego problemu?

Ani go nie powoduje, ani go nie rozwiązuje. To zupełnie inna rzecz.

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