-2

I have been reading a lot about Domain Driven Design lately, and starting to feel a little more confident, than when i first touched this topic. I'm using a Asp Core project, with class libraries for:

  • PersistanceLayer
  • DomainLayer(Service)
  • ApplicationLayer
  • UILayer

Let's say I have an entity called "Company", this will have a model in:

  • PersistanceLayer(Persistance model/PM)
  • DomainLayer(Domain model/DM)
  • Application/UI-Layer(Data transfer object/DTO)

I see many people talking about doing mapping from PM to DM in the repository, when some of my models has five-hundred properties it's not appropriate to have a constructor with this many fields.

I know some of you will say that this model can be refactored etc, but since I'm writing software for my organization and we use old systems that's been around for 30 years, so this is not an option at the moment. I would also like to have domain-events triggered inside the DM, so by assembling a "Company" in the serviceclass, will trigger events.

I basically need a factory function inside my DomainModel that accepts a PersistanceModel and do not trigger any events, is this smelly good? And what are the pros/cons for going with this approach?

closed as too broad by Robert Harvey Aug 7 at 14:44

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

0

I don't like it*

The phrase "it's not appropriate to have a constructor with this many fields" makes little sense to me. There is no possible way to prevent the creation of some piece of knowledge that works with 500 fields, because you need to work with 500 fields. Whether they are all passed into a constructor, put into a container and passed into the constructor, or handled in a factory method/class has no real effect on the underlying needs of the system.

I call designs like this "moving the problem" rather than "solving the problem", or more broadly, "design by aesthetics". Fundamentally, you don't really have a problem at all. You have on object which mandates N fields passed into the constructor where N is some number greater than the threshold for which you comfortable working with in a single routine.

Honestly, I get it. The mental burden placed upon a developer to understand a block of code with 500 variables is high and should be looked at with suspicion in regard to refactoring towards greater insight. But this refactoring must involve actual refactoring (i.e. solving the problem), not just moving/partitioning the problem around. Doing so often has a way of creating a higher mental burden or introducing more problems.

For example, your proposed solution creates a whole new problem where you need a new method of hydrating your domain object in a way that doesn't trigger any events -- as well as adding a user-defined external dependency to your domain (eek!).

All that said, will creating a factory method with the added dependency work? Yes. On the spectrum of design compromises, is it really so bad? No. Have I done the same thing? Absolutely!

*Don't let my purist vision get in the way of making progress. Everything is a trade-off :)

EDIT

My answer above is mostly a tongue-in-cheek way of informing you (and whoever else might read this) about the trade-offs of your proposition - which I believe to be a minor compromise in the grand scheme of things.

More important than your specific problem/solution though, and where I fear I may have failed to be explicit enough, is about the dangers of using the way something "looks" as a means to appraise the quality of the design!

You see, the way something "looks" is a matter of perspective. Do you mean the class file looks cleaner? The package directory? Or maybe you mean the dependency graph looks cleaner? Often what "looks cleaner" from one point of view has the opposite effect on others! This is the problem with "design by aesthetics"; It generally opposes the low coupling/high cohesion ideal for which we should be striving.

Let's be honest, after you write the constructor how often will you need to "look" at it? I can say this, we know for sure that adding an additional dependency means at least one more vector of change that might prompt you to revisit this code where it would have otherwise been unnecessary.

Don't miss the forest for the trees! A system is bigger than any one file!

  • Totally agree! But the solution with a factory function inside the domain model also looks alot cleaner. Thank you for you insight! – Mojo Aug 6 at 15:03
  • @Mojo In light of your comment, I felt the need to extend my discussion above. See my edit. Cheers! – king-side-slide Aug 6 at 19:39
  • Yes but the constructor would also be called from the repository, passing 400 arguments each time, or i could make a helper function passing the arguments that accepts the persistance model? – Mojo Aug 7 at 4:20
  • Thank you for your edit, would you rather have a constructor taking all the fields, or a factory function accepting persistance? Both in domain model, not triggering events. – Mojo Aug 7 at 4:28
  • @Mojo Look. This isn't the straw that's going to break the camel's back. It's okay to make design compromises (I do all the time!) as long as they are done in full knowledge of what trade-offs are present in doing so. My answer above is less "don't do this" and more "be aware of the impacts this thought process can yield when applied too liberally". If I must... Were this a member of my team, I would demand they refactor to use a constructor. Not only is it less coupling, it makes it easier to test. Presumably this object has a constructor anyway right? How does that work? – king-side-slide Aug 7 at 14:49
2

I basically need a factory function inside my DomainModel that accepts a PersistanceModel and do not trigger any events, is this smelly good?

In practice, that's probably going to work out fine. Here's the key point

I know some of you will say that this model can be refactored etc, but since I'm writing software for my organization and we use old systems that's been around for 30 years, so this is not an option at the moment.

This sounds like your persistence model is stable - if it's part of a legacy system and you can't change it, then probably nobody else can either.

So you can accept it as a stable dependency, in much the same way that you accept the libraries provided by your run time as stable dependencies.

In an ideal world, the persistence model would be available in a separate package from the rest of the persistence system, which is to say that your domain factory package and your persistence implementation package should both depend on the persistence model package.

In practice, I wouldn't have a lot of hope for that - legacy systems are practically defined by unnecessary coupling (otherwise, you would be able to change them).

In some cases, it can make sense to isolate this sort of thing - a small package for this factory that depends on the persistence component and on the domain model; it's a way of clearly separating the compromises in your design from the elements that you are happier with.

  • Yes, and i'm very new to this domain, so this also composes a problem. Thank you for your answer! – Mojo Aug 6 at 15:05
  • Out of curiosity, what would the constructor look like for our object in either of the above paradigms? – king-side-slide Aug 7 at 15:13

Not the answer you're looking for? Browse other questions tagged or ask your own question.