4

I'm currently trying to get my head around a few patterns (especially the ones mentioned in the title above) that are made to address different problems and are being used in different parts of the application, however they seem to heavily overlap in functionality once they are implemented.

Let's take for example the following method:

public void MyAction(string param) {
    // do something with param
} 

As long as we want to make sure the parameter is at least initialized, we apply the Guarding pattern in order to make sure that no un-initialized arguments get passed.

public void MyAction(string param) {
    Guard.Require(param).NotNull();
}

However if we also require e.g. the string to be at least 3 characters in length, we have a business rule that needs to be handled by the Validation pattern.

public void MyAction(User user) {
    Guard.Require(user).NotNull();
    MyBusinessValidatorForUsers(user).UserNameAtLeast3Chars();
}

What about if we don't know if the username has been initialized? Monads to the rescue!

public void MyAction(User user) {
    Guard.Require(user).NotNull();
    user.ToMaybe()
        .With(user.Name).Do(MyBusinessValidatorFor...
}

Now imagine for all the patterns, we got a huge framework in use. That's like.. 6 frameworks just to make sure a certain business entity fits the requirements for further use within the business domain.

I know all those patterns go a lot further and usually aren't getting applied within the same scope in a real world application, however especially in simple cases with CRUD persistence layers and simple property bags, I get the feeling that a lot of those patterns can be used to address the exact same thing.

So, where are the main differences between those patterns that legitimate them to be separated in a business application? What would speak against a GuardAndValidateBySpecificationWithMonads framework?

1 Answer 1

1

I am having a bit of an issue with some of these things being called "pattern", but clearly, monads, guards and validators are different beasts one may consider patterns.

Particularly interesting about monads is of course, that their available operations mean you can apply other functions transparently within the monad (read: map). Therefore, monads are quite readily reusable.

Similarly, validators are typically reusable outside of your core business logic. I believe you are not taking full advantage of this yet. When I see UserNameAtLeast3Chars, I wonder what this method does that is so specific to a user name and which cannot be handled by a more easily reusable validator StringSizeAtLeast(username, 3). In terms of functional programming, a string size validator really just needs a function to provide the string and the minimum/maximum allowed length, which makes it applicable to a lot of possible strings.

Therefore, to answer your last question first: What speaks against a GuardAndValidateBySpecificationWithMonads-framework, is that you can barely reuse it elsewhere, because it is a very specific beast. In contrast, the other frameworks provide abstractions that are highly reusable on their own.

As for a more practical approach to the issue, it may be worth considering to add a custom abstraction layer, which unites these frameworks if you find yourself continuously writing the same sort of code. Of course, this union is similar to a custom framework, and the above answer about lack of reusability applies again as well.

I'd be more interested in discussing though, which of these frameworks are really necessary, because each of those has different pros/cons and you may reduce the overlap by eliminating those frameworks, where you do not really need the pros all that much.

Quick discussion of the individual patterns and their pros/cons:

  • Specification: I'm not aware of this as a pattern. Of course, you can have a specification and check against it and call the corresponding framework "specification" again, but that doesn't really make it a pattern of its own.

  • Condition: This is also not clear to me in the given context. A condition is a well-defined term in programming and occurs for example as part of an if-statement. As a pattern for checking your method input, it makes little sense.

  • Guard: This is the first one I recognize as a pattern, but it comes with a distinct behavior: a Guard (condition) checks for a certain property to be present on the input and fails hard if that property is not holding, i.e. throws an exception or something similar. This is a pro as well as a con though. On the pro side, every user of your API is immediately penalized for bad inputs, on the con side, every untested usage fails hard during runtime with potentially dangerous consequences due to the changed control flow.

  • Monads: These are not really a pattern for checking inputs w.r.t. some property. They have a huge number of advantages and really cool stuff you can do with them, but they are quite orthogonal to the rest of the matter discussed here. To say it frankly, you probably do not want to discuss whether a List-framework should be removed, yet lists are the best-known monads. That most people don't think of Lists as monads just shows how transparent they can be.

  • Validation: This is another interesting pattern for checking inputs, but has a clear distinction to Guarding - it does not fail hard. Validation is typically used when you want to also generate appropriate feedback for users to let them know what is wrong (f.ex. display a message like "Usernames must contain at least 3 characters").

From the point of view of checking method inputs, I'd argue that Guarding and Validation are the main frameworks to look at, and they have quite different applications, because one is geared towards developers, the other towards users.

The remaining "patterns" are no input-checking patterns to me and if you have correspondingly-named frameworks in your application, they may well have a huge overlap with the two main patterns, in which case I suggest you investigate how they differ in terms of treating a violation of the checked property.

Final example how not to consider these concepts as overlapping: consider the property that the given user may be null. You can handle this case with monads, guards, and validations, hence these three things overlap. No! They just share the (implicit) condition user == null, but treat it in completely different ways:

  • monads: I don't want to care about null, so if it it's not there, just don't do anything with the user. In particular, do not fail or report a problem to the user.
  • guards: if the user is not present, a developer made a mistake and I'm going to tell her by blowing up. Can't ignore a big bomb exploding in your face after all..
  • validation: looks like the application-user forgot to select a user, so I better inform the application-user that he should do so.

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.