I was discussing a project structure of mine with a friend and he pointed out an interesting point about how my architecture seems to introduce complexity and over abstraction into my layers by having "clones" of existing models.
My project structure, overall, is such:
[UIL] ---- Consumption / U.I. Layer (Just for the sake of completeness with respect to the architecture’s explanation) - Models (ViewModels & Mapping) - Controllers - Views [API] ---- Service/API Layer (We call it the API layer because we use actual services from others that would be confusing if we called our stuff services & clash...so we call these classes with the suffix of Api (i.e. UserApi, ProductApi)) (coordinates the lower level calls & interactions into consumable higher level facades) - Api Models (Initial properties are the same to that of DTO models) (Rich Domain Models that utilize dependency injection to BLL api's, these are passed to Consumption / UI Layer if needed) - Interfaces(self-explanatory) - Adapters - Api's / Services - Mixins [BLL] ---- Business Logic Layer (Domain) - Models (holds specific business logic rules & properties & engine references for corresponding api models that should not be publicly exposed) - Interfaces - Engines [DAL] ---- Data Access Logic Layer - Models (Database matching anemic DTO's) - Interfaces (...) - Connections - Factories - Repositories - UnitOfWork's - Contexts
He notes that I have multiple "clones" of the original models from my DB / DAL by the fact that each of the DAL, BLL, and API models hold the same properties that are in each other (usually not all, but they all link together via some). I think however that they progress nicely from anemic (just for Database interactions) to rich complex "domain" models with fully flushed out methods, fully expanded properties, linked models, linked model api's (behind methods / DI), validation, business logic api's (behind methods / DI), etc. These can be safely passed to any consumption layer for further usage or for mapping to view models.
I do not see a reason to clog my anemic DAL models with the logic in these models because nothing should ever know about my DAL other than the API/Service layer. Correct? This also breaks separation of concerns since now my DAL DTO model now maps to the database, business logic, view, etc. and can be sent back to the database...or somehow, I am missing something?
If I do use my DAL models for everything, my consumption / UI layer would then reference DAL.Models.Product for example and now my DAL is exposed. This is the antithesis of separating & decoupling the layers, right? If my understanding is correct, nothing above the API/Service layer should know about anything below it (i.e. DAL, BLL, and/or other layers below), correct?
The Api's Models are more fully customized to what a consumption layer would want to see versus a database (i.e. no foreign id's, "entity" classes, had clearly modeled behavior via methods, DI API's, etc.), this makes the front-end decoupled from the back-end if it changes, correct? Also, they interface nicely with ViewModels by just needing to use them as the ViewModel or via quick mapping to a view model.
I am not saying that I am right or that my friend is right, but he did bring up an interesting point that I wanted to explore. So far research is somewhat sporadic with people in many different camps.