Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I reduce duplication of domain/entity/DTO objects?

I am in the process of redesigning my current project to be more maintainable, and doing my best to follow good design practices. Currently I have a solution with a Silverlight component, ASP.Net host for said SL app that also contains a WCF RIA service, and a shared class library so both SL and the WCF service can share objects. Business logic is scattered all over the place, and all CRUD operations are hand coded inside my WCF services. So, I am creating a new structure for everything and will port this mess into the new format. In the process of doing this, I find that I am duplicating classes when I don't know if I should be.

My new structure is laid out as such:

Client:
Reporting.Silverlight = Silverlight Application. This will reference my DTO classes.
Reporting.Web = Holds my SL app and is the main entry point for people to get to it.

Business:
Reporting.Services = My WCF services live here. My SL app will make calls to this to do stuff, and these services will return DTO classes.
Reporting.Services.Contracts = Holds my interfaces for the WCF services, and contains my DTO classes with the DataContract decorators.
Reporting.Domain = Holds my domain objects and business logic

Data:
Reporting.Data.Contract = Holds my interfaces for repository & unit of work
Reporting.Data = Concrete implemention of repository/UoW. Entity Framework 5 context is defined here.
Reporting.Data.Models = Holds all my Entity objects so EF5 can do its thing with SQL.

I have 3 places where I have almost the exact same class, and to me it smells. Inside of Reporting.Services.Contracts I have a DTO that gets handed to the SL client. Here is one as an example:

[DataContract(Name = "ComputerDTO")]
public class ComputerDTO
{
    [DataMember(Name = "Hostname")]
    public string Hostname { get; set; }

    [DataMember(Name = "ServiceTag")]
    public string ServiceTag { get; set; }

  // ... lots more
}

I think the above DTO is fine, as it just a bunch of properties that get passed to the SL client. The vast majority of my DTO properties map to my Entity objects' properities 1:1 except for ID fields. Here is my Entity object that corresponds with the above DTO:

[Table("Inventory_Base")]
public class ComputerEntity
{
    // primary key
    [Key]
    public int AssetID { get; set; }

    // foreign keys
    public int? ClientID { get; set; }

    // these props are fine without custom mapping
    public string Hostname { get; set; }
    public string ServiceTag { get; set; }
    // ... plus a bunch more in addition to my navigation properties
}

I am using the code first approach with EF5. I'm still in the very beginning stages of my re-write, and so far I have the impression that business logic should NOT be inside my EF Entity. DTO's shouldn't have business logic either. That means it goes into my domain model, right? Well, that gives my 3rd almost identical class in Reporting.Domain

public class Computer
{
   public string Hostname { get; set; }
   public string ServiceTag { get; set; }
   // ... lots more, pretty much mirrors the DTO

   public string Method1(string param1)
   {
       // lots of methods and logic go in here
   }
}

Having 3 almost identical classes can't possibly be the right way to go about this, can it? Should I be putting all my business logic inside the EF entity, then projecting the result into a DTO that gets passed across the wire? If it is a good idea to cram all my domain/business logic inside the EF entity classes, structurally should I move that assembly to my business layer and outside my data layer, even though those objects are the ones that get saved to my database? Ideally I'm trying to keep any references to Entity Framework contained within my data projects and outside of my business projects. I have about 200 or so classes that I'm porting over and will comprise my domain, and I expect this thing to scale to a lot more functionality once I get this re-write done. Any insight on how to structure this thing and keep it DRY would be much appreciated.

In case it helps define what I'm trying to do any better, let me know if I should include my repository/unitofwork methodology that I am following.

like image 453
Bill Sambrone Avatar asked Sep 10 '13 19:09

Bill Sambrone


1 Answers

Having 3 almost identical classes can't possibly be the right way to go about this, can it?

IMO they aren't "3 almost identical classes", they don't serve the same purpose. They are rather multiple facets of the same domain notion, each one tailored for the needs of a specific layer.

It's the price to pay for modularity and clear separation of concerns. The more ports (as in Hexagonal Architecture's Ports & Adapters) you have, the more facets you'll need and the more mapping you'll have to do.

A good article on this : http://blog.ploeh.dk/2012/02/09/IsLayeringWorththeMapping/

like image 136
guillaume31 Avatar answered Nov 08 '22 11:11

guillaume31