8
votes

I had created an infrastructure our brandly new intranet project and tried to follow nearly all best practices. Also i want to mention, too, this is my first time for creating an architecture from zero.

Currently my infrastructure's first version is ready and well working. But i want to implement bounded context structure at next version.

I tried to explain current situation following.

DbCore: responsible for data operations. Entity Framework 5 Code First used. There is only one DbContext class and all DbSets defined in it. Also GenericRepository pattern and Unit of Work pattern implemented based on following interfaces.

IGenericRepository

public interface IGenericRepository<TEntity>
     where TEntity : class {
        void Delete(object id);
        void Delete(TEntity entityToDelete);
        System.Collections.Generic.IEnumerable<TEntity> Get(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, Func<System.Linq.IQueryable<TEntity>, System.Linq.IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
        System.Collections.Generic.IEnumerable<TEntity> GetAll();
        TEntity GetByID(object id);
        System.Collections.Generic.IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters);
        void Insert(TEntity entity);
        void Update(TEntity entityToUpdate);
    }

IUnitOfWork

 public interface IUnitOfWork {
        void Dispose();
        IGenericRepository<Test> TestRepository {
            get;
        }
        IGenericRepository<Log> LogRepository {
            get;
        }
        void Save();
    }

Models: Responsible storing entity models for DbCore and Entity Framework Domain: Represent business logic layer also stores DTOs for entity objects which stored at Models project. Currently business logic stored in Service class that implemented following interface IService

public interface IService<TEntity> {

        IEnumerable<TEntity> Get();
        TEntity GetByID(int id);
        void Insert(TEntity entity);
    }

This service class gets UnitOfWork via ctor parameter and use for operations. Also Automapper implemented to convert entity objects to DTOs or vice versa. From now on all upper layers no longer interested in entity models, only use DTOs. So nearly all projects (including, api and web ) references this project.

Common: Responsible for storing commonly used libraries like logging.

WebCore: Responsible for storing commonly used libraries for web based projects like API or MVC. Also contains, extension, handlers and filters for MVC based projects.

Api: ASP.Net MVC Web API project represents service layer. Consumes Domain layer and serves to clients. Controllers gets IService interface as ctor parameter and use it to access data layer through domain layer.

Web: ASP.Net MVC 4 based web project, responsible with interaction with user. Consumes Api methods to access data. All controllers gets an interface named IConsumeRepository which connects API via HttpClient.

 public interface IConsumeRepository<TEntity> {
        Task<TEntity> Create(TEntity TestInfo);
        Task Delete(int id);       
        Task<IEnumerable<TEntity>> Get();
        Task<TEntity> Get(int id);
        TEntity New();       
        Task<TEntity> Update(TEntity TestInfo, int entityId);
    }

Autofac is reponsible for IoC and DI for all projects.

For now this is my current infrastructure, i think i explained everything that needs to evaluate.

Now i am trying to figuring out following things,

Question 1: Is there anything MUST NOT be impelemented the way i used?

Question 2: What is best approach to implement Bounded Contexts? I recently watched Julie Lerman's videos and reviewed lots of sample projects. Common thing i saw deriving BC from DbContext. But i couldn't be sure. Because i had thought BC's should be in domain (business logic) layer not in DbCore (data access) layer.

Question 3: As i mentioned above, my Api and Web projects uses DTOs so both of them needs to have references Domain layer. But i didn't like it, because i am seperating business layer from UI with an API and coupled them again for entities. But i couldn't find any way better than this.

This became a long question but i will be very happy if you share your ideas with me to create better architecture.

1

1 Answers

30
votes

Question 1: Assuming you have a complex business domain and significant business logic, it can be worth making the effort as you have to isolate your domain layer from infrastructure concerns. However, this is often not the case. If you are mostly just moving data from the database to the UI and back again, then this is overengineering and you should seek something with fewer moving parts.

Question 2: How many distinct domain models (with different ubiquitous languages) do you have? One? Two? Three? For each model, isolate it from other models and infrastructure concerns as much as possible.

Eric Evans defines a bounded context as primarily a linguistic boundary (quote from his book):

A BOUNDED CONTEXT delimits the applicability of a particular model so that team members have a clear and shared understanding of what has to be consistent and how it relates to other CONTEXTS. Within that CONTEXT, work to keep the model logically unified, but do not worry about applicability outside those bounds. In other CONTEXTS, other models apply, with differences in terminology, in concepts and rules, and in dialects of the UBIQUITOUS LANGUAGE.

DBContext may point you in the right direction, but remember it is an infrastructure artifact, not a domain concept. It "represents a combination of the Unit-Of-Work and Repository patterns and enables you to query a database and group together changes that will then be written back to the store as a unit."_ (from MSDN Docs).

DDD is about domain modeling: using models to solve hard business problems in complex business domains. Deriving model boundaries from technical considerations can feel like the tail wagging the dog. Define the boundary of your model conceptually, then align your technical infrastructure accordingly.

Question 3: DTO's can be a good way to enforce a context boundary, such as for an API. The API can then function as an anti-corruption layer to other models. The reason people typically use them for UIs is to avoid having to bleed UI concepts into the domain model.

Don't seek a perfect architecture. And realize that "best practices" are really just guidelines based on particular situations. Follow the guidelines other more experienced people have laid out, with the understanding that your situation is likely subtly different. Use what you have with the expectation of refactoring your design decisions when you find friction. For example, if later you find that the DTOs to the UI are overkill, then remove them. Simplify wherever you can.