Question

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.

Was it helpful?

Solution

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?

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
scroll top