{"id":1893,"date":"2014-10-30T00:00:00","date_gmt":"2014-10-30T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/take-your-crud-to-the-next-level-with-ddd-concepts\/"},"modified":"2021-05-17T18:35:59","modified_gmt":"2021-05-17T18:35:59","slug":"take-your-crud-to-the-next-level-with-ddd-concepts","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/take-your-crud-to-the-next-level-with-ddd-concepts\/","title":{"rendered":"Take your CRUD to the next level with DDD concepts"},"content":{"rendered":"<div id=\"pretty\">\n<h2>Let the journey begin<\/h2>\n<p>There is a skill that I particularly  admire in a developer: It is being able to recognize correctly that something,  whether code or process, is no longer working well. &#160;It is useful because a project will so  often start with right architecture and design but, over time, travels in  unexpected direction. Without this skill, the project is liable to cross the  &#8216;fit-for-purpose&#8217; border and enter into &#8216;big-ball-of-mud&#8217; land. Why? The project  has changed, but the architecture hasn&#8217;t. No architecture is suitable for all  types of software development project, yet we, who are assumed to be  specialists, tend to be too eager to use the same solution for different  problems. As in so many of life&#8217;s problems, &#8216;one size does not fit all&#8217;.<\/p>\n<p>Many solutions start as mainly routine  CRUD requirements (Create, Read, Update and Delete) but usually with some  specific part that has considerable complexity. Software architecture should  address those two areas separately. DDD (Domain-driven design) might seem a  perfect tactic to address complex requirements, but it relies on access to  domain experts and a shared intent to focus primarily on the domain and refine  it iteratively.<\/p>\n<p>Even when these prerequisites aren&#8217;t  available, DDD might still be an inspiration for structuring code in these more  complex areas of a development project because, in large part, it is plain good  OOP. Such an approach, without defined context, ubiquitous language or even  communication benefits, is called DDD-lite. It concentrates on technical-side  patterns and concepts. Of course, it doesn&#8217;t mean that we forget about domain or  communication &#8211; those elements are still present, but they are not at such a  high level; nor are they explicit enough to warrant calling the approach &#8216;DDD&#8217;.<\/p>\n<h2>Aggregated root and action classes<\/h2>\n<p>Let&#8217;s look at how complexity may creep  in your model, and how DDD concepts may help. Imagine we are implementing a  classic ASP.NET MVC application with following layers:<\/p>\n<p> \t<img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2082-img25.gif\" alt=\"2082-img25.gif\" \/><\/p>\n<p>MVC controllers execute business logic  that is kept in the domain and this logic is exposed through a fa&#195;&#167;ade of  application services, which use repositories to access the database. Entity  Framework&#8217;s <code>DbContext<\/code> is internally  used to implement repositories.<\/p>\n<p>For the sake of example, let&#8217;s assume  that we start with the following model:<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2082-img21.jpg\" alt=\"2082-img21.jpg\" \/><\/p>\n<p> We have a customer with a name and  addresses. A customer can create orders &#8211; each one has delivery date, addresses  and set of ordered products.<\/p>\n<p>Initially our code may look similar to  this:<\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public  class  OrderRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  void Save(Order order)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  class  OrderLineRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  IList&lt;OrderLine&gt; Find(Order orderline)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  OrderLine Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  void Save(OrderLine orderline)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  class  OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  void Save(Order order)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<p>Two repositories, <code>Order<\/code> and <code>OrderLine<\/code>, give  access to the respective tables through a set of base operations. Order service  combines those and exposes logic to higher layers. A <code>Find <\/code>method on service, for example,  could be as simple as calling <code>Find<\/code> on <code>OrderRepository<\/code> and returning only  order headers. The <code>Save<\/code> method, on  the other hand, invokes <code>Save<\/code> on <code>OrderRepository<\/code> and iterates over  order lines to persist each of them with the <code>OrderLineRepository <\/code>class: All  reasonably good so far.<\/p>\n<p>Now, let&#8217;s imagine that the customer  changes his mind or we suddenly find out that the save operation is more  complex. Depending on the order status, we have to perform a basic or more  sophisticated validation. I often witnessed service evolving into something like  that:<\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public class OrderRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public void Save(Order order)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderLineRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;OrderLine&gt; Find(Order orderline)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public OrderLine Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public void Save(OrderLine orderline)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; public  ValidationResult Save(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  ValidationResult Submit(Order order)...\n\t\t\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  void SaveOrder(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  ValidationResult ValidateOnSave(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  ValidationResult ValidateOnSubmit(Order order)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<p>There is a new public method to submit  an order. <code>Save<\/code> and <code>Submit <\/code>internally call the appropriate private method to do the  validation (<code>ValidateOnSave<\/code> or <code>ValidateOnSubmit<\/code>). As the actual  logic of order saving is common it is extracted into separate private method (<code>SaveOrder<\/code>).<\/p>\n<p>If developer writing this piece of code  would know DDD better, a solution might look like this:<\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public class OrderRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public void Save(Order order)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderLineRepository...\n\t\t\n\t\t &#160;&#160;&#160; public  class  OrderValidator\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  ValidationResult ValidateSave(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  ValidationResult ValidateSubmit(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  void ValidateCustomerLimits()...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  void ValidateOtherLimits()...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public  ValidationResult Save(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  ValidationResult Submit(Order order)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<p>One of key technical concepts of DDD is  aggregated root. This is the parent entity, which controls access to its  children, defines their lifetime and takes care about concurrent access to the  same objects. This way, aggregate root can ensure the integrity of aggregates as  a whole. All repositories should operate at aggregated root level. No other  entities should be exposed directly through the methods of repository. That is  the reason why<code> OrderLineRepository<\/code>  has been removed. With the full logic of saving <code>Order <\/code>and <code>OrderLine<\/code> in  the repository, there is no need to have a separate <code>SaveOrder<\/code> method on <code> OrderService<\/code> &#8211; this kind of logic is better kept at repository, where it is  easily mockable and testable.<\/p>\n<p>One addition &#8211; there is a new class, <code>OrderValidator<\/code>, named after an action  and replacing logic that was kept previously in the private methods of <code>OrderService<\/code>. Contrary to what we  have learned during Computer Science studies, it is better to not only call your  classes after nouns, but also verbs. In our case, all the logic that is related  to order validation is now kept in a separate class with single responsibility.  Sub-validations, constituting on full validation, can be kept is private methods  of <code>OrderValidator<\/code> (e.g. <code>ValidateCustomerLimits<\/code>). If we would  need access to other areas of domain model inside <code>OrderValidator<\/code>, we can easily inject dependencies into that class  without increasing overall class coupling too much and still have testability at  the same level.<\/p>\n<h2>Domain events<\/h2>\n<p>Next, the customer might express a  requirement to send an email notification to its recipients, and for legal  reasons might need to generate an invoice at the time of order submission. A  sufficient implementation, which often comes to mind could looks like this:<\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public class OrderRepository...\n\t\t\n\t\t &#160;&#160;&#160;  public  class  EmailTemplateRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  EmailTemplate Get(EmailTemplateType type)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  class  InvoiceRepository\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  void Save(Invoice invoice)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderValidator...\n\t\t\n\t\t &#160;&#160;&#160; public class OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Save(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Submit(Order order)...\n\t\t\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  void SendEmailNotification(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  private  void CreateInvoice(Order order)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<p>We have new repositories:<\/p>\n<ul>\n<li> \t\tFirst to access email  templates (EmailTemplateRepository) \t\t<\/li>\n<li> \t\tSecond to create invoices (InvoiceRepository) \t\t<\/li>\n<\/ul>\n<p>Two new private methods on <code>OrderService<\/code> are called inside <code>Submit<\/code> to meet the customer&#8217;s  requirements. Again the problem is with embedding the logic mostly in the <code>OrderService <\/code>class and, again, the  DDD concept comes to the rescue.<\/p>\n<p>Event-based programming is popular, but  we habitually think about it only in terms of the user interface. Domain events  are events that signal a change in the domain that we care about. They are  especially important when multiple aggregate roots need to interact. What if we  try to use it here to reduce the coupling? Let&#8217;s see.<\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public class OrderRepository...\n\t\t &#160;&#160;&#160; public class EmailTemplateRepository...\n\t\t &#160;&#160;&#160; public class InvoiceRepository...\n\t\t &#160;&#160;&#160; public class OrderValidator...\n\t\t\n\t\t &#160;&#160;&#160;  public  interface  IDomainEvent {}\n\t\t\n\t\t &#160;&#160;&#160;  public  class  OrderPlaced :  IDomainEvent\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  Order Order {  get;  set; }\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  static  class  DomainEvents\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  static  void Raise&lt;T&gt;(T args)  where T :  IDomainEvent...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  interface  Handles&lt;T&gt;  where T :  IDomainEvent\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  void Handle(T args);\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  class  OrderPlacedNotificationSender :  Handles&lt;OrderPlaced&gt;\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  void Handle(OrderPlaced args)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160;  public  class  OrderPlacedInvoiceGenerator :  Handles&lt;OrderPlaced&gt;\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  void Handle(OrderPlaced args)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Save(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Submit(Order order)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<p>Domain events can be implemented in many  ways, but I am here following <a href=\"http:\/\/www.udidahan.com\/2009\/06\/14\/domain-events-salvation\/\">Udi  Dahan&#8217;s recommendations<\/a>. An empty <code> IDomainEvent<\/code> interface is used to mark the domain events &#8211; <code>OrderPlaced <\/code>in our example. The Event class has all the information  related to the event (<code>Order<\/code>  property). All events are pumped through central hub (<code>DomainEvents<\/code> static class), which finds subscribers by looking for  classes implementing <code>Handles&lt;T&gt;<\/code>  interfaces. We&#8217;ve got two of those for our <code>OrderPlaced <\/code>event: one is responsible  for email notifications and the other one for invoices. The names of handlers  have been chosen to best describe their intention. Unnecessary private methods  on <code>OrderService<\/code> have been deleted.<\/p>\n<p>It is worth mentioning that true domain  events should be named in the past tense. The table below shows a few different  conventions for naming events, of which domains are most legible.<\/p>\n<table>\n<tbody>\n<tr>\n<td valign=\"top\">\n<p><b>Event name<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p><b>Comments<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>CustomerAddressChanged<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Domain event<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>OrderPlaced<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Domain event<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>CustomerUpdated<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>CRUD-ish  \t\tevent<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>CustomerInserting<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Trigger-like event<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"caption\">Table1- Examples of events<\/p>\n<p>In my example, events are processed  synchronously, but there are other viable alternative approaches. They could be  assembled during actions and processed either right before transaction-commit or  send to the queue to be handled asynchronously by background workers.  <\/p>\n<p>From the technical perspective,  implementation may vary. My sample is based on the global event hub by Udi  Dahan, but instead we could:<\/p>\n<ul>\n<li>Use plain Old .NET events<\/li>\n<li>&#160;Use recent Reactive Extensions framework <\/li>\n<li>&#160; Simply return events from domain methods (which is easiest to  \t\ttest).<\/li>\n<\/ul>\n<h2>Factories<\/h2>\n<p>Finally, our customer may request an  operation to clone an order. Naturally we may want to place such a simple  operation inside <code>OrderService.<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public class OrderRepository...\n\t\t &#160;&#160;&#160; public class EmailTemplateRepository...\n\t\t &#160;&#160;&#160; public class InvoiceRepository...\n\t\t &#160;&#160;&#160; public class OrderValidator...\n\t\t &#160;&#160;&#160; public interface IDomainEvent...\n\t\t &#160;&#160;&#160; public class OrderPlaced...\n\t\t &#160;&#160;&#160; public static class DomainEvents...\n\t\t &#160;&#160;&#160; public interface Handles&lt;T&gt;...\n\t\t &#160;&#160;&#160; public class OrderPlacedNotificationSender...\n\t\t &#160;&#160;&#160; public class OrderPlacedInvoiceGenerator...\n\t\t\n\t\t &#160;&#160;&#160; public class OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Save(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Submit(Order order)...\n\t\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; public  Order CloneOrder(Order originalOrder)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<p>But, what if it&#8217;s not that easy? What if  some fields are omitted during cloning? What if we require access to additional  repositories to fulfil the process? Do we have to impose those needs on <code>OrderService<\/code> and make it more  difficult to test?<\/p>\n<p>IoC (Inversion of Control) containers  are very popular and this may have blinded us to the idea of writing custom  factories. If our order cloning could be implemented as a factory, then that  would relieve us from all the problems above. In this scenario, <code>OrderService<\/code> would be what it meant  to be i.e. a fa&#195;&#167;ade over our business logic with nothing complex inside.<\/p>\n<pre class=\"lang:c# theme:vs2012\">\t\t &#160;&#160;&#160; public class OrderRepository...\n\t\t &#160;&#160;&#160; public class EmailTemplateRepository...\n\t\t &#160;&#160;&#160; public class InvoiceRepository...\n\t\t &#160;&#160;&#160; public class OrderValidator...\n\t\t &#160;&#160;&#160; public interface IDomainEvent...\n\t\t &#160;&#160;&#160; public class OrderPlaced...\n\t\t &#160;&#160;&#160; public static class DomainEvents...\n\t\t &#160;&#160;&#160; public interface Handles&lt;T&gt;...\n\t\t &#160;&#160;&#160; public class OrderPlacedNotificationSender...\n\t\t &#160;&#160;&#160; public class OrderPlacedInvoiceGenerator...\n\t\t\n\t\t&#160;&#160;&#160; public  class  OrderCloneFactory\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160;  public  Order CloneOrder(Order originalOrder)...\n\t\t &#160;&#160;&#160; }\n\t\t\n\t\t &#160;&#160;&#160; public class OrderService\n\t\t &#160;&#160;&#160; {\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public IList&lt;Order&gt; Find(Customer customer)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public Order Get(int id)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Save(Order order)...\n\t\t &#160;&#160;&#160;&#160;&#160;&#160;&#160; public ValidationResult Submit(Order order)...\n\t\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; public  Order CloneOrder(Order originalOrder)...\n\t\t &#160;&#160;&#160; }\n<\/pre>\n<h2>Takeaways<\/h2>\n<p>I have shown you how DDD concepts of  aggregated root, action classes, domain events and custom factories can help you  in everyday work to avoid transaction scripts for complex logic. Definitely not  all elements of your system will be so complicated as to require those patterns,  but you should generally follow a &#8216;thin application service, fat domain&#8217;  paradigm.<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes, in a software development, the level of complexity in part of the project can get to a point where the experienced developers will rethink their strategy. Domain-Driven Design can often help, but if the necessary prerequisites aren&#8217;t there, it could be that DDD-Lite can help. Konrad Lukasik gives a simple example where some DDD patterns can help to clarify complex logic. &hellip;<\/p>\n","protected":false},"author":110510,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4229],"coauthors":[],"class_list":["post-1893","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-framework"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/110510"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1893"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1893\/revisions"}],"predecessor-version":[{"id":91087,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1893\/revisions\/91087"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1893"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}