Waar past de “bedrijfslogicalaag” in een MVC-toepassing?

Ten eerste, voordat iemand dupe schreeuwt, vond ik het moeilijk om het in een eenvoudige titel samen te vatten. Een andere titel zou kunnen zijn: “Wat is het verschil tussen een domeinmodel en een MVC-model?” of “Wat is een model?”

Conceptueel versta ik onder een model de gegevens die worden gebruikt door de views en controller. Buiten dat, lijken er veel verschillende meningen te zijn over wat het model vormt. Wat is een domeinmodel, versus een app-model, versus een weergavemodel, versus een servicemodel, enz.

Bij een recente vraag die ik stelde over het patroon van de repository, kreeg ik bijvoorbeeld te horen dat de repository deel uitmaakt van het model. Ik heb echter andere meningen gelezen dat het model moet worden gescheiden van het persistentiemodel en de bedrijfslogica-laag. Is het niet de bedoeling dat het Repository-patroon de concrete persistentiemethode loskoppelt van het model? Andere mensen zeggen dat er een verschil is tussen het domeinmodel en het MVC-model.

Laten we een eenvoudig voorbeeld nemen. De AccountController die bij het MVC-standaardproject wordt geleverd. Ik heb verschillende meningen gelezen dat de meegeleverde accountcode een slecht ontwerp is, in strijd is met SRP, enz. enz. Als men een “juist” lidmaatschapsmodel voor een MVC-toepassing zou ontwerpen, wat zou dat dan zijn?

Hoe zou u de ASP.NET-services (lidmaatschapsprovider, rolprovider, enz.) scheiden van het model? Of zou je dat helemaal niet?

Zoals ik het zie, moet het model “puur” zijn, misschien met validatielogica… maar moet gescheiden zijn van bedrijfsregels (behalve validatie). Stel dat u bijvoorbeeld een bedrijfsregel heeft die zegt dat iemand een e-mail moet krijgen wanneer een nieuw account wordt gemaakt. Dat hoort in mijn ogen niet echt in het model. Dus waar hoort het thuis?

Iemand die enig licht op deze kwestie wil werpen?


Antwoord 1, autoriteit 100%

De manier waarop ik het heb gedaan – en ik zeg niet dat het goed of fout is, is om mijn visie te hebben en dan een model dat van toepassing is op mijn visie. Dit model heeft alleen wat relevant is voor mijn mening – inclusief gegevensannotaties en validatieregels. De controller bevat alleen logica voor het bouwen van het model. Ik heb een servicelaag die alle bedrijfslogica bevat. Mijn controllers noemen mijn servicelaag. Daarbuiten is mijn repository-laag.

Mijn domeinobjecten zijn apart gehuisvest (eigenlijk in hun eigen project). Ze hebben hun eigen gegevensannotaties en validatieregels. Mijn repository valideert de objecten in mijn domein voordat ze in de database worden opgeslagen. Omdat elk object in mijn domein erft van een basisklasse waarin validatie is ingebouwd, is mijn repository generiek en valideert alles (en vereist dat het erft van de basisklasse).

Je zou kunnen denken dat het hebben van twee sets modellen duplicatie van code is, en tot op zekere hoogte is dat ook zo. Maar er zijn volkomen redelijke gevallen waarin het domeinobject niet geschikt is voor de weergave.

Een voorbeeld hiervan is wanneer ik met creditcards werk – ik moet een cvv hebben bij het verwerken van een betaling, maar ik kan de cvv niet opslaan (hiervoor staat een boete van $ 50.000). Maar ik wil ook dat u uw creditcard kunt bewerken – adreswijziging, naam of vervaldatum. Maar je gaat me het nummer of de cvv niet geven bij het bewerken, en ik ga zeker niet je creditcardnummer in platte tekst op de pagina zetten. Mijn domein heeft deze waarden die nodig zijn voor het opslaan van een nieuwe creditcard omdat je ze aan mij geeft, maar mijn bewerkingsmodel bevat niet eens het kaartnummer of cvv.

Een ander voordeel van zoveel lagen is dat je, indien correct ontworpen, structuremap of een andere IoC-container kunt gebruiken en stukken kunt verwisselen zonder je applicatie nadelig te beïnvloeden.

Naar mijn mening moet de controllercode alleen code zijn die is gericht op de weergave. Toon dit, verberg dat, enz. De servicelaag moet de bedrijfslogica voor uw app bevatten. Ik vind het prettig om alles op één plek te hebben, zodat het gemakkelijk is om een ​​bedrijfsregel te wijzigen of aan te passen. De opslagplaatslaag zou relatief dom moeten zijn – verstoken van bedrijfslogica en alleen uw gegevens opvragen en uw domeinobjecten retourneren. Door de weergavemodellen te scheiden van het domeinmodel, heb je veel meer flexibiliteit als het gaat om aangepaste validatieregels. Het betekent ook dat u niet elk stukje gegevens in uw weergave in verborgen velden hoeft te dumpen en het heen en weer hoeft te duwen tussen de client en de server (of het opnieuw moet opbouwen op de backend). Uw weergavemodel bevat dan alleen de informatie die relevant is voor de weergave – en het kan worden aangepast om bools te hebben voor weergavelogica of tellingen of opsommingen, zodat de weergave zelf niet vol zit met ingewikkelde logische uitspraken zoals

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

Hoewel alles uitgespreid en overgelaagd lijkt, heeft het een doel om op deze manier te worden ontworpen. Is het volmaakt? niet echt. Maar ik geef er de voorkeur aan boven sommige eerdere ontwerpen om repositories aan te roepen vanaf de controller en om bedrijfslogica te mengen in de controller, repository en het model.


Antwoord 2, autoriteit 25%

Ik heb me te vaak afgevraagd hoe de MVC-elementen precies passen in een traditionele webapplicatie-structuur, waar je views (pagina’s), controllers, services en data-objecten (model) hebt. Zoals je al zei, daar zijn veel versies van.

Ik geloof dat de verwarring bestaat vanwege de hierboven genoemde, algemeen aanvaarde architectuur, die het “anemische domeinmodel” (vermeende) antipatroon gebruikt. Ik zal niet ingaan op veel details over het “anti-patroon” van het anemische datamodel (je kunt kijken naar een poging van mij om dingen uit te leggen hier(gebaseerd op Java, maar relevant voor elke taal)). Maar in het kort betekent dit dat ons model alleen gegevens bevat en dat bedrijfslogica in services/managers wordt geplaatst.

Maar laten we aannemen dat we domeingestuurde architectuurhebben, en dat onze domeinobjecten er wordt van hen verwacht dat ze zowel staats- als bedrijfslogica hebben. En in dit domeingestuurde perspectief vallen dingen op hun plaats:

  • de weergave is de gebruikersinterface
  • de controller verzamelt de invoer van de gebruikersinterface, roept methoden op het model aan en stuurt een reactie terug naar de gebruikersinterface
  • het model zijn onze bedrijfscomponenten – de gegevens bevatten, maar ook bedrijfslogica hebben.

Ik denk dat dit je belangrijkste vragen beantwoordt. Het wordt ingewikkeld als we wat meer lagen toevoegen, zoals de repository-laag. Er wordt vaak gesuggereerd dat het moet worden aangeroepen door de bedrijfslogica die in het model is geplaatst (en daarom heeft elk domeinobject een verwijzing naar een repository). In het artikel van mij dat ik heb gelinkt, betoog ik dat dit niet helemaal een best practice is. En dat het eigenlijk helemaal niet erg is om een ​​servicelaag te hebben. Overigens sluit domeingestuurd ontwerp de servicelaag niet uit, maar wordt verondersteld ‘dun’ te zijn en alleen domeinobjecten te coördineren (dus geen bedrijfslogica daar).

Voor het anemische datamodelparadigma, dat algemeen wordt aangenomen (ten goede of ten kwade), zou het model zowel de servicelaag als uw gegevensobjecten zijn.


Antwoord 3, autoriteit 4%

Naar mijn mening,

Model –

Mag geen bedrijfslogica bevatten, het moet pluggable zijn (WCF-achtig scenario). Het wordt gebruikt om te binden aan weergave, dus het zou eigenschappen moeten hebben.

Zakelijke logica –

Het zou op “Domain Services Layer” moeten worden geplaatst, het is een aparte laag.
Zal hier ook nog een laag “Applicatieservices” toevoegen.

App Services praat met de Domain Services-laag om bedrijfslogica toe te passen en als laatste het model terug te sturen.

Dus,
Controller zal Application Service om Model vragen en de stroom zal gaan als,

   Controller->Application Services(using domain services)->Model

Antwoord 4, Autoriteit 3%

Het MVC-patroon en het ASP.NET-framework maakt geen onderscheid op wat het model zou moeten zijn.

eigen voorbeelden van MS zijn Pershility-klassen in het model. Uw vraag over het lidmaatschap dat in het model is. Dit hangt ervan af. Zijn klassen in je model in eigendom van iets? Is er een link tussen wie zich aanmeldt en welke gegevens worden weergegeven? Is er het filteren van gegevensonderdeel van een machtigingssysteem dat bewerkbaar is? Want het laatst bijgewerkt of bewerkt een objectdeel van uw domein, zoals bij iemand anders moet het of iets voor backend-ondersteuning zien?

Het e-mailvoorbeeld is ook het hangt af. Bent u bekend met Domein Eventing of Eventing in het bijzonder? Heeft u een afzonderlijke service om e-mails te verzenden? Is de daad van het verzenden van een e-mailonderdeel van uw domein of is het een betreffende toepassingsniveau buiten de reikwijdte van uw systeem? Moet de UI weten of een e-mail succesvol is verzonden of niet? Verdien e-mails die niet moeten worden verzonden, pogingen nodig? Wordt de inhoud van het verzonden e-mailadres opgeslagen voor ondersteuning of klantenservicevereisten?

Dit soort vragen zijn overdreven breed en subjectief, maar ik beantwoord, zodat jij en iedereen die je hebt gestemd, dit kan begrijpen.

Uw vereisten / Tijdlijnen / middelen die allemaal zijn uitgeschakeld in de architectuur van uw systeem. Zelfs de Revenue Model kan een effect hebben. Je moet ook rekening houden met het patroon waar je voor fotografeert. DDD is veel anders dan Pershility-as-Model-applicaties en al het slord daartussen zijn ook geldig voor bepaalde apps. Schiet u op voor het testen van de app? Dit alles heeft een effect.

Other episodes