Chapter 3— Functions

dilrajio
Dev Genius
Published in
5 min readMay 11, 2020

--

Chez Vince — Disney’s Recess

Before you were probably born, Fortan dominated the charts in popularity for nearly 3 decades. You can imagine how much different the dynamics of Software has changed since then, but functions still prevail.

Today we are going to dive into cooking up nice, clean functions!

Small — The 1st Rule

You may have been given advice to keep your functions no bigger than a screen scroll.

Even Smaller — The 2nd Rule

While I cannot give you an exact number, 20 lines is more than enough. Enough — that it should hardly ever be 20 lines.

Blocks & Indentation

Blocks within indents should generally be ONE line. If you ever find yourself writing huge chunks of instructions between if statements or for loops, there is a good chance you can put that into a function of it’s own .

To illustrate, look at how many principles we are breaking. There is too much repetition, there is so many unnecessary comments since it is so confusing to read (hint, hint… the next chapter) and there is so much happening with blocks of indentation.

NOT GOOD.

Should Do One Thing. Should Do It Well. Should Do it ONLY.

Sounds simple, but what is one thing?

Suppose you want to submit an updated username by submitting the form the API. Roughly speaking, you will have to:

  1. Validate input is a String
  2. Get authenticated user token
  3. Fire XHR request with the input string data

Is this doing one thing… or three? It will take some time and experience to decipher, but a general rule of thumb is this; we create functions to decompose larger instructions of code. However, if you can extract another function, from within the function… there is a good chance you should write another function.

For example, if instead you were validating the input is a string and has x number of characters and validating special characters, you should create validateUsernameInput(username) function and call that.

Switch Statements

They are risky business when it comes to dealing with functions. If you’re like me, you know how kickass React Hooks/Context/Redux can be with switch statements.

Abstract Factory — Comic courtesy of refactoring.guru

Here’s the problem (according to Uncle Bob)… they violate Single Responsibility Principle (SRP). How the hell is there any sense of responsibility for a function that has unlimited reasons to change? In OOP, you can use switches in abstract factories to return polymorphic objects, but that does sound quite frightening —doesn’t it?

I will be back when I find a safe and appropriate way to invoke functions within switch statements.

Use Descriptive Names

This is important so I will get straight to the point:

  • Make them descriptive
  • Don’t lie
  • Take your time

These points can be extrapolated into a self-help book, but they apply to function names too. Hunting for a good name will take renames and refactors but it is worth it because it cementifies the direction and design of your software.

Easier said than done. Seriously.

Consistency

getStage(), fetchStage(), currentStage()! WELL… which one is the best name?! Is getStage a class method… or will it perform an HTTP Get request… or will it start computing integers? Having these patterns early on can be quite rewarding in the long run as you won’t have to second guess every time.

Arguments

Functions can take arguments and they can be very powerful!

Function signature + adjectives!

Dyadic Functions

It will always be easier to read:

// monadic
def add_hours(num_hours)

Then:

// dyadic
def add_hours(unix_time, num_hours)

The dyadic function is still pretty readable and understandable. Sure, the first one is nice and buttery; the dyadic function just takes a second longer. The problem is, one of the arguments tend to get overlooked. Eventually, developers are going to learn to intentionally skip that argument and just look at num_hours .

“The parts we ignore are where the bugs will hide.” — Martin (4.42)

When you do run into the scenario where you need to use a dyadic function, you, the arguments should appear natural; natural cohesion and natural ordering. For example, makeCircle(coordinate, radius) there is a naturalness to coordinate and radius, compared to a function like buyGasoline(octane, carTankSize) .

Triadic & Polyadic Functions

At this point, it may make sense to wrap it a separate Class. In MVC, you may want to create a new model to alleviate the widespread arguments.

If possible, using Objects in arguments can reduce the argument numbers as well:

Suppose we parse out some important information and now with this important info, we want to fire it somewhere!

What we are doing is relatively simple, but the arguments make it quite blurry.
EDIT: Don’t need to return `this`

You Don’t Need Flag Arguments

Boolean arguments in function signatures is a sign that the function is doing more than one thing.

Really, you should divide it into 2 separate functions.

No Side Effect! No Lies!

Can you spot the Side Effect?

This function should just validate whether the password is right. But because of the side effect (line 8) any time someone wants to validate their input password, they’ve unnecessarily created a Authorization Token.

It’s doing more than one thing. It’s lying. Thus, functions with side-effects are not clean.

You can obviously read these in greater detail in the Chapter 4 of Clean Code, but here are some important concepts developers should keep in mind:

One Level of Abstraction per Function: Basically, don’t mix complex and low level abstractions. Something like adding a .toString(2) after a complex calculation.

The Stepdown Rule: Your code should read from top to bottom like a narrative, or as if you are “walking through” the code layer by layer of abstraction.

Prefer Exceptions or Returning Error Codes: When returning custom error codes, you may end up in an if else hell. Martin argues it is preferable to straight up try, catch the (err) and return that.

Since we are talking about error handling, I would also argue that (almost) all responses should be handled in a separate function. Your function is one thing, dealing with successful response and errors is another thing.

Tip from last chapter: Maybe you’ve seen getProductInfo() when it could’ve easily have been getProduct(). General rule of thumb, words like data or info are disinformation, they don’t cause any confusion, but they don’t add any value either.

--

--

ੴ | Software Developer | building for beauty and accessibility. Looking for opportunities in Seattle.