-2

Suppose that I have a Value Object representing an Image URL of a Cake.

To check that it really is a cake, I make an asynchronous API call to a server that checks whether the image really represents a cake.

Would it be ok to put this kind of validation inside the constructor of the Value Object? After all, I can't identify my CakeImage object without checking first. The other solution would be to use an ImageURL object, and check if it represents a cake when using it, but it seems like a bad solution.

3
  • 1
    I recommend you to check this absolutely wonderful talk by Misko Hevery: youtu.be/RlfLCWKxHJ0
    – Andy
    Apr 26, 2020 at 6:58
  • Why is checking if an ImageURL represents a cake when using it a bad solution? It is in fact the only solution that ensures any sort of integrity within this system. The content of a url can change at any time. Apr 27, 2020 at 17:18
  • How about a Future<ImageURL> ?
    – rwong
    Apr 28, 2020 at 1:43

2 Answers 2

4

Sounds like you're running into the old argument about how much work to allow a constructor to do. I personally like constructors that validate and assign state and nothing more. Why? Here's a good explanation.

How much work should be done within a constructor? It seems reasonable to do some computations inside a constructor and then encapsulate results. That way, when the results are required by object methods, we’ll have them ready. Sounds like a good approach? No, it’s not. It’s a bad idea for one reason: It prevents composition of objects and makes them un-extensible.

yegor256.com - ctors must be code free

However, you seem to have found a hole in my policy because I'd be horrified to see a constructor sitting around waiting for a remote server call to respond.

I'd much prefer to see a factory give this remote API calling code somewhere else to live so the CakeImage object is testable when the internet is down and is validatable even after the company running the server goes out of business.

I'm leaning towards giving CakeImage a constructor that takes the result of this validation, whatever that is, and so can only be built after it's complete.

Of course this means you need a name for the unvalidated pile of data that you're hoping to make into a CakeImage. Hmm, ImageURL?

12
  • You misunderstood my question: I mean that I have a class representing a CakeImage, not an instance Apr 25, 2020 at 21:10
  • I have a CakeImage Value Object supposed to represent a valid cake image. How should I instanciate it ? The CakeImage itself should be immutable Apr 25, 2020 at 21:27
  • @HillelSAAL better? Apr 25, 2020 at 22:35
  • 1
    I read Yegor's post twice and I still have no idea WTF he is talking about. He turns something simple like parsing a name once, in the constructor, where everything is obvious and you can fail fast, and adds decorators, caching annotations, typical Java overdesign B.S.
    – user949300
    Apr 25, 2020 at 22:45
  • 2
    While I agree with the sentiment of the linked article, I also agree with @user949300 that the example is... well... confused. Maybe if the author considered renaming his interface to NameThatStartsWithS or included an example that required startDate and endDate as construction parameters he could have delineated the difference between domain rules and data rules and expounded upon where different kinds of validation are appropriate. As it stands the article reads as if the author worked backwards from his ridiculous abuse of the decorator pattern to make a point unrelated to the title. Apr 27, 2020 at 19:36
0

Fail Fast principle says you should fail as soon as possible for robust debugging. It is provides quicker feedback to a user if they have messed up. This goes against the "Constructors should do nothing" principle.

The good thing about Software Engineering principles is that there are so many to choose from. :-)

Imagine that your application asks for a Cake URL. Version A checks the URL as soon as possible. Version B waits and does no error checking. Both then ask for your name, the date you baked the cake, a review of the cake, and walk you through the special offer to receive 3 free issues of "Cake Monthly". So far, so good.

Finally, Version B does error checking and notices that the URL isn't a cake.

Maybe the user mis-typed, selected the wrong picture, or the code that dealt with that input has a bug and added a leading "http:" when it was already in the URL. Or maybe it is a cake and the network call is down.

1) Which would be easier to debug?
Version A should have a very clear stack trace pointing to myUrlHTTPAdder() as a recent call that perhaps did something wrong. Version B will have a flaky URL and something about a magazine.

2) Which will retain more users?
I'll let you decide.

That said, doing an async network call in a constructor is a bit much.

Added

One approach might be to have a Boolean isValidatedCakeImage field, or a method CakeImage getValidatedCakeImage(), which returns a Promise or a Future or whatever depending on your language. (Or maybe just a null and some method of polling or waiting).

At some point in the process your code calls that and takes the async hit. These methods could be mocked for testing.

A good question is whether the constructor launches the validation, or a later method. Good arguments for both sides here. Mainly, I don't think that "constructors shouldn't do nothing" should guide your decision here. Lean towards "Fail Fast" as your default, and back away if that doesn't fit the complexities.

2
  • 1
    I'm familiar with the concept of "Fail fast", which is a reason why I like validated value objects. Your last sentence answers half of the question, since you didn't provide an alternative way of doing it Apr 27, 2020 at 21:10
  • See edits for some ideas
    – user949300
    Apr 27, 2020 at 22:28

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.