26

According to this question on Stack Overflow, in DDD architecture "helper" classes can be in different layers depending on their purpose. For example a helper that formats something in a user friendly way would go in the UI. A database helper would go in infrastructure.

But what about helpers that can be used by more than one layer? For example age calculation. Age might be required in the model layer for business logic. It is used by more than one entity, so it should not be in a specific entity. Also there are places where age is required merely for display purposes in the UI. Similarly, I have string functions that can be used by more than one layer. For example my custom Right and Left methods could be used for formatting in the UI, but they might also be used in the model, for example conditional logic based on a prefix.

So where should these common methods go? My setup is like this:

  • UI
  • Application
  • Model
  • Infrastructure

Model is core and has no dependencies on infrastructure, so the common helpers cannot go in infrastructure. I am considering two options:

1) Have another layer called Common or similar that can be used by any layer. This would create a dependency between Model and Common.

2) Duplicate the helper logic in whatever layer is needed. Eg Have an Age helper in UI AND have an Age helper in the Model. This would violate DRY, but would not require the domain to have a dependency on a "Common" layer.

Which option is better? Is it OK for the Model layer to have a dependency on a "common" layer?

UPDATE:

In the 2.5 years since this question was asked I have concluded:

  1. Things like Right, Left, etc that compensate for limitations in the framework, belong in a "Common" utilities / helper component that even the Model/Domain layer has a dependency on.
  2. The "Common" utilities / helper component should not be very big. With more experience I found that many things I thought of as helpers actually belong in the domain model.
  3. Age belongs in its own class in the domain layer. Much like things like address, phone number and money I consider these things as value objects. Understanding value objects really was key to my understanding of creating reusable domain classes that can be incorportated into other classes.
Community
  • 1
  • 1
Louise Eggleton
  • 969
  • 2
  • 15
  • 27
  • Do you have a better example than age calculation? Or can you elaborate on the complexity of that example? – MattDavey May 27 '14 at 10:40
  • @MattDavey I also mentioned the string example where I use my custom Right and Left methods both in the UI eg for formatting, but also in the domain, for example conditional logic based on a prefix. There aren't really that many "helpers" that would fall into this scenario where they need to be in more than one layer. Most of my helpers to slot neatly into a particular layer, but as I mentioned there are a few that are required across layers. – Louise Eggleton May 27 '14 at 10:47

2 Answers2

12

The string helpers are slightly different I think - in that case your custom Right and Left methods are actually compensating for a limitation in the built-in string type of your language/platform - it doesn't have anything to do with your application as such so in this case it's fine to have it globally accessible.

The age calculation example is a little more interesting as it encapsulates behaviour/logic which is very much an intrinsic part of your application/domain. In that case it may be worth evaluating on a case-by-case basis whether it's worth duplicating the behaviour in each layer (violating DRY in favour of SRP). That's a tough decision to make. Although they may be identical now, by duplicating the behaviour you are giving the two methods the chance to diverge from each other in the future. This would typically happen if they had different reasons to change.

MattDavey
  • 8,897
  • 3
  • 31
  • 54
  • Yeah, it's C#, no native right and left functions. The age calculation is dead simple. Just feed it a DOB and convert to age. I don't envision this changing in the future. If I need something more complicated, I think I would create a different method. – Louise Eggleton May 27 '14 at 11:16
  • 1
    see update 2.5 years later. Thanks for sending me in the right direction – Louise Eggleton Dec 17 '16 at 15:28
8

From my experience, having a CommonInfrastructure (or some such) component/layer which contains all the helper classes/methods is the right way to go. both String helpers and Age helpers as you described can go in there (along with DateTime helpers, dictionary, dynamics, Linq, whatever).

it should be a library that could easily be carried on to the next project, as it would be so generic and without any dependency on current domain logic, and contain useful code for all-purposes.

the only reason to violate DRY would be if you needed Javascript code on the UI and C# code on your backend, in which case you'd need to duplicate that common infrastructure code (unless you come up with a more elaborate solution to keep it DRY).

Ami
  • 1,110
  • 1
  • 13
  • 26
  • Do you put all your helper classes/methods here even ones that don't need to be shared, for example cookie helpers and html extensions, that are only applicable to the UI? – Louise Eggleton May 27 '14 at 13:57
  • yes I would. I'd separate them into different folders and put all the classes related to UI, Web, DateTime, String, Encryption, etc. in a single folder. Usually you don't have hunderds of helpers, just a handful... – Ami May 27 '14 at 14:09
  • Although I originally leaned towards the idea of each layer having its own utilities, I found in practice there were too many times that I needed something in more than one layer and/or I would forget which layer a specific utility was in. So for the sake of maintenenace simplicity I will be following your suggestion to put the whole shooting match in one common layer and be done with it. – Louise Eggleton Nov 14 '14 at 18:15
  • Where do we keep a helper eg a Configuration helper , it is domain specific but used by repository and service layer – Thunder Jan 04 '15 at 04:44
  • 1
    @Thunder, a Configuration could be split for repository configuration and services configuration, and then each can be kept along with all other files of that layer. if they share common code that can be a common configuration helper that is kept in a layer that is accessible by all other layers ('infrastructure', 'common', 'general' or some such). it really depends on what the configuration does and how general or domain specific it is. – Ami Jan 04 '15 at 08:19