Attacking Your Inputs

While I’ve rallied against painting all code with final in Java, and have accepted that it’s handy to have const in JavaScript as it generally forces some discipline into free-for-all code, there’s an underlying rule which could be used to make me want more constants everywhere.

The rule is that a function should return something. This can be enforced, to a degree by treating all variables as immutable constants, including inputs to a function. With this approach, which underpins thread-safe functional programming, you’re structurally less likely to have bugs.

However, there are a couple of caveats about solving this problem with things like const or final.

  • Sometimes it’s a reasonable thing to ask a function to accumulate its result into an existing container – like an array or map, because using a cloning approach to make a new one to return would be cumbersome
  • Making a reference constant does not guarantee immutability, so you can appear to be taking things seriously, with the constant keyword all over the place, while still violating the general principle

Why Functions Should Return Something

If a function operates on one its inputs alone and returns a value, then:

  • It probably has one responsibility
  • It’s very testable
  • It’s easier to understand

Conversely, if the function does all sorts of things, perhaps forwarding to the next one, in a chain of calls, then it’s harder to understand, debug and test… it’s probably harder to get right. It may also waste memory while it’s doing it.

Attacking the Inputs

Notwithstanding the idea that we may (occasionally) be passing an object down to a function for it to accumulate values into. We should be looking at how to avoid modifying the input parameters.

  • Don’t redefine an input parameter – if you need to iterate on something for which the input is the first one, then use an iterate to track current, rather than rewrite the input variable in a loop
  • Don’t mutate the inputs as this means you have a backwards relationship with your caller, who may naively assume they can reuse their input, but can’t – this may be unavoidable in some cases, but those cases should be clearly advertised and rare

The general rule is that it’s a special assumption that you control the state of an input object.

In a recent example, a calling function was using an iterator on a list while the function it called was receiving both the current item and the iterator. The subroutine was deleting items from the iterator as well as using the current item.

We could not explain to ourselves why this algorithm worked, though it appeared to.

Summary

Short, testable, single responsibility, testable functions use their inputs wisely.

3 comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s