1

In our code we have some classes that represents business logic. Prior to usage, they are created and populated with two types of inputs:

  • business data required for execution (e.g. name, maxValue...)
  • infrastructure references to e.g. database, message bus, http client... etc, anything that is not related to business, but needed for communication with underlaying infrastructure.

We have the following options to separate inputs:

/A have everything in constructor:

public Foo(String name, DbRef db)

I would like to be able to separate somehow these two types of inputs. As number of arguments can be big, I do not want to overload constructor or to make it with huge number of arguments.

/B infra in constructor, data via setters

public Foo(DbRef db)...
public Foo setName(String name)...

This way you can't create an object without passing the infra, but you need to add extra validation if some required argument is not missing (there is no compile-time check for that).

/C required data in constructor, infra and optional data via setters

public Foo(String name)...
public Foo bind(DbRef dbref)...
public Foo setMaxValue(int maxValue)...

This way you must not forget to call bind, but at least it is always the same method - and this binding can be done automatically by e.g. proxy, probably, to reduce possible human errors.

I have started with B but now I am leaning towards the C.

How would you architecture this?

1

First of, I wouldn't couple the business concepts to infrastructure concerns - have a look at "port's and adapters", infrastructure should adapt to the primary/secondary ports of the domain. Databases, in this context, is a secondary port (something that is called by the domain object, rather than something that calls the domain object).

Regarding constructor/property/method injection, consider this: Is concept 'x' an actual whole 'x' without dependency 'y'? A customer without a name & id is probably not valid, so dont make it possible to make that (prefer constructor injection). Changing data via setters is generally a bad idea IMO, sonce it introduces temporal coupling and the need for all colaborative objects to query state, introducing a lot of other problems. Method injection is the best way to introduce trancient dependencies, something that can be used and trown away later - i.e. not something that defines the object, but something it needs in order to do something specific. This could be registration of an observer, persisting to a repository or notification via messaging.

In general, I think it smells mostly like the 'business logic' is polluted by infrastructure concerns, and untill you decouple that, neither A, B or C will have significant advantage. Hope that helps

  • But I cant, that is the whole point. Business logic uses infrastructure to get/write information during execution - and that is not a uncommon case. For example, one business method may read additional data from database and process it. Show me the business service method that is not 'polluted' by infrastructure - that is what I would like to see :) I will check "port and adapters", however, maybe I am missing something. – igor Mar 18 '17 at 13:00
  • Yea check out ports and adapters. Of course business logic depends on persisted data, and needs to persist data - which of course needs infrastructure... The point is that we don't need to be coupled to something just because we need to use it (inversion of control) – Julian Mar 18 '17 at 13:17
  • yes, I am aware of IOC - hence solution C. But in my case, the class is allowed to be strongly coupled to infrastructure. This is not the coupling between business components, cause this objects I am talking about are commands that needs to execute. Ok, will check port and adapters :) – igor Mar 18 '17 at 14:28
  • "ports and adapters" (from heax-pattern),,, adapters are wrappers over ports. This is nothing new, and of course I might have that. Think of DbRef as an db adapter. The question still remains. – igor Mar 18 '17 at 16:21
  • 1
    ... And leaves less refactoring work in the future... But you end up with more, yet smaller, classes - also easier to unittest – Julian Mar 19 '17 at 1:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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