0

I couldn't find a question on SE but it has probably been asked elsewhere already (in case, please mark it).

A method containing code to run just with specific external conditions can:

  • decide whether to execute after checking those conditions, or
  • just blindly run, sticking to the Single Responsibility Principle; and let the calling code check the conditions, deciding to call the method or not.

I am trying to understand what is more proper and when.

What are the pros and cons of the two approaches?

E.g.

  • check if a DOM element has a CSS class and return if it doesn't have it
  • check if an array parameter is empty and in case return, sparing the loop on it
  • lazy loading a value and return if it is already initialised

In general I tend to make my methods know as much as possible and take care of everything that concerns them, but that is not necessarily correct.

I suppose in functional programming a highest atomicity would be preferred (so not check the conditions and just do your job, eventually wasting cycles or incurring in an error). If it makes a difference, in my case the style is more OOP.

Edit:

I am probably talking about Guard Clauses.

5
  • 1
    Following the SRP, you often end up with 3 methods: one for validating the input/checking the "conditions", one for doing the actions in case the conditions are fulfilled; and one for calling the former two. But the real question you need to ask here is: are you going to expose only the latter in public, or all three?
    – Doc Brown
    Commented Feb 25, 2019 at 17:31
  • In my specific case the design is minimal, all methods of the object are exposed and reusable, if not of strictly private concern (assuming the developer knows that validation must occur). – For example, if the "actions" method is called multiple times from a loop then I would check the "conditions" before entering the loop itself (in case the validation would return always the same result). Commented Feb 25, 2019 at 17:50
  • 1
    This comment sounds you already know the answer to your question.
    – Doc Brown
    Commented Feb 25, 2019 at 19:10
  • This is not a technical question:"What is more proper...?" If you can identify a measurable NFR then this question will become answerable (e.g. you could ask "What performs better?" "What is more maintainable?" etc., each of which may have a different answer). As of now it is a matter of opinion.
    – John Wu
    Commented Feb 25, 2019 at 23:18
  • Changed to ask for pros/cons; should be fine now. Commented Feb 25, 2019 at 23:49

3 Answers 3

6

Your question effectively asks: when should I favour delegating responsibility for input validation to my methods?

It really depends. Looking through the details, it appears you are actually trying to solve a philosophical problem: when is interface simplicity more valuable than implementation simplicity?

If calling code is expected to handle input validation, then you have implementation simplicity (your individual methods are easier to write) at the expense of interface simplicity (your calling code has to work harder to use your methods). If your individual methods handle input validation, the inverse tradeoff is made.

This (ultimately philosophical) tradeoff has naturally attracted a lot of polarisation and dogmatism. Putting all that charged invective aside: in practical terms, which tradeoff matters more to you?

  1. How much duplicate work do your individual methods do for input validation? If it's a lot, be DRY: either extract the logic to your calling code, or interject a layer between your calling code and your methods to unify it.

  2. Who writes the calling code? If it's you, then it doesn't matter what you pick. If it's an external customer who doesn't know the internals, then use abstraction to your benefit - let your individual methods/microservices handle validation, or let a layer between your customers and your microservices do it for you.

  3. What kinds of workflows are you expecting? If your methods invoke each other (for example, you are chaining functions together to arrive at one end result), then it makes sense to invest in logic handling in each method or to use monadic composition (you exit early with an error value or type if one of the chained operations returns an error). If your methods are all completely independent, then it doesn't matter where the input validation runs.

  4. How important is input validation anyway? If your users are fine with lossy precision, then you may not even have to invest in input validation (though you should always sanitise your inputs).

There is no one answer to this because every situation is different. This highlights just how theoretical software engineering and practical software engineering are different, and serves as an important lesson: you should not blindly follow "best practice", but make conscious decisions about when to follow the rules.

Let's go through the examples you've listed:

  1. Checking if an array is empty and sparing a loop - if you have n functions that all operate on the same array, it makes sense to move this logic to the calling code to reduce code duplication. If those n functions operate on transformations of that array through sequential operation, then you should move that logic to each function so you can guarantee an end value rather than an end error/exception.

  2. Check if a DOM element has a CSS class and return the class if it has it - Who is using this function? If your users don't want the responsibility of validating input (say they're library consumers), let the function do the check. If you think your users would favour having more control over their input (say they're developing internal tooling), then let them do it.

The lazy loading a value case is the same as the CSS case.

1

The answer is, it depends. And it mainly depends on the scope of your function/method.

If the method is public and especially if it forms part of an API that will be called by other code, possibly written by other organisations, then it makes sense for the method to validate and verify its conditions.

If the method is internal or private, ie is an implementation detail that is only called by other parts of your own code, then it really doesn't make sense for it to check its conditions. Imagine that Foo is nine methods down in a call stack and all eight previous methods have checked their conditions. What possible benefit would there be from a ninth check? So what possible use of a second check even?

1

A method containing code to run just with specific external conditions can: decide whether to execute after checking those conditions, or just blindly run, sticking to the Single Responsibility Principle; and let the calling code check the conditions, deciding to call the method or not.

Generally this depends on the data needed to make the decision. If no additional argument are needed to make the decision, then it's reasonable to make the decision in the same method. If the decision depends on data not otherwise needed, then make the decision externally.

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