2

In past projects I've noticed that many maintainability problems arise from the wide spread mixup of data access and business logic, and high dependancy of logic on entities. I'm not attempting to design a hypothetical system that avoids all of this, but I am interested in reducing the problems introduced in the long run by tighly coupled code.

Overview (simplified to represent only the problem at hand):

  • Cross Cutting: entities
  • Presentation Layer: UI, displays stuff using entities, usually initiates calls to the BLL
  • Business Logic Layer (BLL): logic that works with entities, usually implemented as static methods, often also calls the DAL
  • Data Access Layer (DAL): mappers that provide CRUD methods for entities (hand-coded SQL queries)

Changes

I intend to make all parts more testable and maintainable. Therefore I decided to introduce a number of changes, mostly in the DAL and BLL since they cause the most trouble. Logic is embedded in queries and the BLL becomes highly dependent of the DAL's methods and entities.

DAL

  • Introduced a mechanism that generates SQL from C# rather than hardcoding the queries. This enables compile-time errors rather than run-time. We should be able to catch inconsistencies with the queries and the entity model earlier on this way.

BLL

  • Removed the reference to the DAL (decoupling them entirely), all logic is called from the UI through a new "glue" layer, which links the UI to the DAL and the BLL.

In my opinion, so far so good, this should work out pretty well for us. Now comes the biggest change.

  • Another change I intend to introduce is a variation to the command pattern, in order to remove the dependency on the entity model. I also want to make sure that business logic is testable. Therefore it seems to me that the "glue" layer should translate entities into command objects that contain just the data a certain piece of logic needs. When the model changes, only the mappings needs to be adjusted and the business logic remains intact.

This seems like a good idea but I expect a huge amount of business logic, resulting in tons of command objects to maintain. Is this a justified fear or am I worrying too much? What are your experiences with these kinds of problems?

Korijn
  • 1,383
  • 9
  • 27

2 Answers2

1

I don't really see how the command pattern would help here. The approach I've successfully taken to decouple the BL from the DAL is to use the facade pattern. The DAL should implement interfaces and the BL should be initialized by injecting instances of those interfaces into it. When it comes to testing the BL, you can then supply an entire mocked DAL, making unit testing far easier.

David Arno
  • 42,717
  • 16
  • 86
  • 131
  • Thanks for the helpful comment. The facade pattern you mention would fulfill a similar task as the glue layer I've mentioned, correct? Also, wouldn't the DAL's interfaces still couple the BL to the entity model? – Korijn Nov 11 '13 at 21:07
  • 1
    @Korijn Indeed, I would view "glue layer" as another term for a facade :) How are you defining the entities, are they just POCOs, or do they contain logic? One approach (which is a lot of work if you have lots of entities) is to have the DAL convert entities to/from model objects defined - via interfaces - by the BL. – David Arno Nov 11 '13 at 21:12
  • They're just POCO's. The approach you mentioned with an additional set of domain objects to convert back and forth from is something we've already explored and it is indeed an accounting nightmare when you've got ~100 entities with up to 50 properties. – Korijn Nov 11 '13 at 21:19
  • @Korijn In that case, if possible, have your POCOs implement interfaces defined by the BL. – David Arno Nov 11 '13 at 21:21
  • Shouldn't the interfaces be defined in the facade instead? That way the DAL and BLL don't need to know about eachother. The POCOs can still implement the interfaces and the facade can pass the objects on to the BL. Correct? – Korijn Nov 11 '13 at 21:26
  • 1
    @Korijn My mistake, I meant facade. Sorry. – David Arno Nov 11 '13 at 21:28
1

There are several issues I can see with the design overall.

Removed the reference to the DAL (decoupling them entirely), all logic is called from the UI through a new "glue" layer, which links the UI to the DAL and the BLL.

This "glue" layer you are referring to should be an Interfaces layer. Generally speaking, the Interfaces layer loosely couples various otherwise unrelated layers in a test-able way.

Another change I intend to introduce is a variation to the command pattern, in order to remove the dependency on the entity model. I also want to make sure that business logic is testable. T

Look at a Repository Pattern. With Dependency Injection that's pretty much exactly what it solves.

Introduced a mechanism that generates SQL from C# rather than hardcoding the queries.

Be careful with this one. Be sure you are not reinventing the wheel with home brew LINQ to SQL.

To wrap it up, change is inevitable. There's no pattern that makes all change more manageable. The command pattern will not solve scope creep in the business layer. Your best bet is to stick to that n-tier solution you already have going and make intelligent design decisions to the best of your abilities with the best information you have available.

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
  • Thanks for the helpful suggestions. I didn't create my own version of LINQ to SQL, in fact its exactly what I'm using. I managed to embed it into the mappers so that the "outside world" has no idea that LINQ to SQL is in fact being used. Using interfaces sound like a good idea to investigate. Thanks. I think it coincides with David's suggestion too. I'll definitely explore it in a proof of concept soon. – Korijn Nov 11 '13 at 21:29