Whenever we talk about certain programming concepts, I think it’s important to take a step back out of whatever specifics we’re discussing and look at things in the context of the bigger picture.
For example, yesterday I briefly touched on the idea of programming side effects, but I did so when talking about using PSRs. And for those who are simply interested in aspects of programming in a more general sense, it’s important to understand them, too.
Remember, the idea of side effects as stated in PSR-1 is:
A file SHOULD declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it SHOULD execute logic with side effects, but SHOULD NOT do both.
In this post, I’m not so interested in discussing logic with side effects (because there are times where side effects will happen). Instead, I’m more concerned with understanding programming side effects (what they are, what to avoid, and so on).
After all, talking about side effects in one context may mean one thing whereas, in programming, it may mean another.
Programming Side Effects
Okay, so the whole idea or definition of a generic side effect is simple, right?
a secondary, typically undesirable effect of a drug or medical treatment.
Take out the whole treatment aspect, and you’re left with a “secondary, … undesirable effect.” Okay, so here’s the potentially confusing part:
- we opt to include a file,
- we know what the file does,
- thus, if we know what we’re including and what it does, how can it introduce something undesirable?
At least, that’s how I often hear it asked when it comes to talking about side effects. In programming, I’ve always generalized side effects as anything that alters the state of the program.
Easy enough, right?
Side Effects in WordPress
So let’s say you’re working with WordPress, because that’s what I do and write about 🙂, and we have a file that’s responsible for adding a submenu item to one of the existing top-level menus.
That class could be relatively simple in that it wraps the proper WordPress API call, it fires when attached to [the proper] hook, and then adds the submenu, as intended.
That would be a side effect in that it changes the state of the program.
What Should the Module Do?
That class itself should do one thing:
The single responsibility principle is a computer programming principle that states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class.
But when we introduce something that adds to what it’s supposed to do – when we add to its responsibility or change the single core thing it does – then we’ve introduced a side effect.
Remember, this isn’t inherently bad (as per the PSR-1 definition above), but it’s important to recognize when we’re doing it and when we’re not.
So How Do We Add Functionality?
I think the natural question is that if we want to add functionality to a program that alters its state, how do we do it (and is it wrong)?
First, no, it’s no wrong. I mean programs have different states based on a variety of things, right? Sometimes it happens when something is written to disk or a database; sometimes it happens when the user clicks on an element on the UI, and so on.
But how these states happen are where the nature of side effects come into play.
Take for example the idea of a submenu. It’s supposed to do one thing. It shouldn’t alter anything else but what we see on the screen.
- It shouldn’t write to the database,
- It shouldn’t set up an event listener for when another object adds a submenu,
- It shouldn’t alter the presentation of anything outside of itself.
- And so on.
Adding functionality works the same way: You introduce classes that are responsible for doing a specific thing and let them do it. When these components work in conjunction with one another, then you have a functional program in which each module (class/function/whatever) stays in its lane, so to speak.
What’s a Rule of Thumb?
I’m sure many of you reading this have your take on what side effects are and what they aren’t. And like you, I have my own.
Think of it this way:
If you call a method and it returns a value, and then you call a method again with the same set of data, it should return the same value.
That’s how you know your function, class, or generic module doesn’t have side effects.
And, as with anything, I’ve made these mistakes (and will likely continue) but it’s a matter of trying to get better at not doing it.
Eventually, it’ll become the new normal.