0

I have this object

RelativeFoo{int relativeCode, Origin relativeTo}

And I want to map it to this other object

AbsoluteFoo{int absoluteCode}

In order to do this, I need to use a service whose implementation calls an external API

AbsoluteFoo absFoo = fooProvider.obtainAbsoluteVersionOf(new RelativeFoo(1, Origin.BAR))

In order to be sure that an AbsoluteFoo instance is indeed absolute (meaning, created by the external service), I think that I need to restrict the instantiation of AbsoluteFoo to the fooProvider.

One way of doing it is making obtainAbsoluteVersionOf a static method of AbsoluteFoo (AbsoluteFoo.from(relativeFoo) with AbsoluteFoo having a private constructor) or a instance method of RelativeFoo (relativeFoo.toAbsolute() with AbsoluteFoo having a private constructor and being a inner class of RelativeFoo).

However, since the method obtainAbsoluteVersionOf uses an external API, I can't really make it into an domain object method, can I? I mean, I don't like the idea of injecting dependencies in a domain object, so that's something that I'm not considering as a possibility.

Currently, obtainAbsoluteVersionOf is a domain service that is implemented in the infrastructure layer, and I don't know how to restrict the construction of AbsoluteFoo to this service in this setting.

Any ideas how I could model this better?

Also, I think my question is related to this other one, which wasn't really answered:

https://stackoverflow.com/questions/44776829/external-data-mapping-to-domain

18
  • 3
    This sounds like a horrible idea to me. If you want ever be able to write unit tests which require AbsoluteFoo objects as test data, your tests will depend on this external API. I would usually try to design a system in a way that code which is based on AbsoluteFoo is agnostic of who or what consttructed it. Maybe you can elaborate why you want to design the system this way?
    – Doc Brown
    Jan 11, 2023 at 14:27
  • 1
    Yeah, now I see that. Maybe a better question would be "Should a factory take a service as paramater"? Jan 11, 2023 at 15:42
  • 1
    "What I want is to make sure that the consumer of my domain (application layer) has no option to create an instance of AbsoluteFoo other than calling fooProvider.obtainAbsoluteVersionOf." Yes, but why? You already have an answer. You stated it in the OP! But, you don't like it. Why??? You were assured elsewhere that you don't even need to solve the problem. But, you're still trying to solve it. WHY!??
    – svidgen
    Jan 26, 2023 at 17:53
  • 1
    The details included in your SO post are much more concretely answerable. Though, I disagree with a large portion of the accepted answer there. In the abstract (the OP here), this is nearly impossible to answer. In the concrete (your SO post), the real answer is, "It depends on your risk assessment." If you want to be "sure" X comes from Y, Y should sign it, and your domain entity should explicitly promise it has an X signed by Y. That's not really an "object construction" problem, its a business requirement that should probably be in the domain itself. Maybe as simple as X.isSignedBy(Y)
    – svidgen
    Jan 26, 2023 at 19:41
  • 1
    ... Or perhaps when you create new X(), you need to pass in the signature, the constructor validates it at construction, and the result is an immutable object. On the other hand, if the business just wants to be reasonably sure that X's come from Y. Psh. You own the code. Just don't create X's in the prod codebase apart from calls to Y. Done.
    – svidgen
    Jan 26, 2023 at 19:42

1 Answer 1

0

Design patterns suitable to model AbsoluteFoo instantiation are builder design pattern and optionally, depending on where AbsoluteFoo has to be instantiated, factory design pattern:

        Factory design pattern, specifically abstract factory design pattern, for polymorphic object creation, encapsulates object creation code, thus following single responsibility principle (SRP) of Clean Architecture, and reduces code duplication, thus following don't repeat yourself (DRY) principle of The Pragmatic Programmer.

        Builder design pattern for sequential object creation, encapsulates object creation code, thus following SRP.

The layer handling external services invocation converts external responses to internally known representations returning to calling layers application specific entities, or domain objects, that can be created using instances of entities factories or entities builders from the layer handling the application's data model. Summed up for the actual scenario fooProvider should hold a reference of AbsoluteFoo factory or builder.

Update for comments:
Reduced accessibility to instantiation could be achieved, using access modifiers and inheritance, through package by feature.

1
  • Hi! Thank you for answering. About the answer, how could I restrict the construction to the fooProvider? I can see that it will need a reference of AbsoluteFoo factory or builder, but how can I make sure that only the fooProvider service can create instances of AbsoluteFoo? Should I do this at all? My intention is to avoid developers creating instances of AbsoluteFoo by means other than the fooProvider (this service could be mocked for the tests, so the test part is ok). Jan 25, 2023 at 13:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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