Should you always write accessors? (SHOULD YOU!?)
Yesterday, my colleague Ticabri wrote an article about Vuex store and getters. Now, I really like Ticabri. I like discussing with him. He has generally interesting views on our profession and he usually knows what he’s talking about. But this particular article bothered me a little bit and we’ll see in what way soon.
But first things first: what is this fuss all about!?
Well, Ticabri, as far as I understand, states that, when using a Vuex store in a Vue project, you should always write getters and access your data through them rather than accessing them directly. And this statement, furiously reminded of me Java’s so-called “good practice” to always write accessors. The usual argument is: you won’t break your code if you need to change the internal representation of your data and add transformation when serving or mutating it. Other are bolder and say: “it’s about encapsulation, if you don’t do that, your not doing OOP!”. But this rant is already covered by another article.
So, is it right? Should you always use getters? Is is a code smell not to?
Well, my answer will be the same than for the Java’s accessors rule: no. More generally, this is my general answer to anybody telling me that I should write code this or that way while not being able to give me the slightest good reason to do so. That’s what I used to tell my teachers in engineering school, that’s what I’m telling my colleagues today. But let’s look at those justifications and why I think they are not good, shall we?
A Java argument
“This avoids coupling”: is the shittiest argument I’ve ever heard. I mean: the whole fucking point of computer science is coupling. You write code to do things. You group things into functions to reuse them. You group functions into libraries to reuse them. The whole point of writing code is to use it somewhere to do things. Using code is coupling it to other parts of code. You can turn things any way you want: you’ll have a coupling at one time or another. If you don’t have coupling at some point, your code is not used. I mean: it’s litterally useless.
So, ok, you may tell me: “it good to reduce the coupling surface”. The thing is: I’ve
never met anyone who was able to define me what a good coupling surface is. And my guess
is: nobody fucking knows. Even the priests of the Java church. Most of the time,
it’s nothing more than a general rule of thumb but the risk is always there. Otherwise, what is the whole
point of @Deprecated
?
That is the reality of our profession: the moment you write code, nobody is able to guaranty that you won’t have to break things in the future. You can try but you’ll find yourself spending a huge amount of resources for a goal that is unattainable. Every language tried. Every language failed. Ask the Python dev team about Python 2 and Python 3. Even though Python is one of the most stable languages I know.
Trying to avoid coupling and break things, you will find yourself introducing very weird design patterns and construction in your library/framework/language.
By the way, most of the time when you change the internal representation of your data, you end up changing the name of your accessor to reflect that. Oopsie…
In other languages
This general rule of always write an accessor has always made me unconfortable bacause it
feels like a dogma. And the dogmas in Java have evolved, over time. 15 years back, the Java
community was all about factories. Factories everywhere! And interfaces! When I started my career,
I used Java 7 and met some in the Java standard library. But things where changing. Now,
the Java community was all about builders. Factories were old already. Then Java 8 was introduced.
builders were old, too. Now, the clean code was all about hiding constructor behind .of
static
functions.
Then I left Java and started writing Groovy and Python. I eventually knew why these rules were
no clean code. I was able to argue why they were just dogmas. Factories, builders, .of
static
functions are all here because Java still doesn’t supported named and default arguments. Groovy
has supported them since 2003, Python has supported them since 1990, Scala has supported them since
2003, and Kotlin supports them.
As for getters and setters, they also exist because Java still doesn’t have a property construct. Kotlin has it, Groovy has it, Scala — in a sense — has it, Python has it, etc. Java still forces you through a function call… It’s only a syntax away to mimic a direct property access through an invisible accessor. But it’s still not there.
And the result is a shitload of boilerplate.
Which increases your maintenance cost.
Which is bad.
What about Vuex, then?
So, this is all good and stuff. But we still haven’t talked about Vuex. Is this article just a bunch of hooey? Is it just another rant against Java?
No. It isn’t.
But My answer for Java is still valid here: Your force developpers to write getters everywhere, you increase boilerplate, you increase maintenance cost. In the case of Vuex, though, there’s nothing you can do to levarage this throught the syntax. It’s not a language. So is my arguments so far are invalid, aren’t they? what if the data change? What if a need to add logic appears?
Well, first, changing data rarely happens when dealing with HTTP APIs. That is the whole point
of having versions of them. If you need to change your client implementation because the
topology of your data changed, this means a bad architecture. Which can happen.
And it’s ok: everyone can take a bad decision. Take Python 2, for instance! But if it happens,
you write a second version and you slowly deprecate the old one, giving time to the clients to adjust.
This is what we do everywhere else. And if it happens, if you still have to change from a direct
store access to a getter, you still have your IDE’s search and replace function.
Or sed
in the worst case. Nothing here justifies to always write a getter. Especially,
when the data has the correct form and can be used as is.
There another point that bothers me: resource cost. Obviously, always write Vuex getters means more code lines. Hence more code to download and parse while the JS community is slowly while the JS community is slowly breaking this habit.
But it also means more computation and more memory load.
Why? Because Vuex getters work exactly the same way than Vue computed properties: as soon as the data changes, getters invalidated, recomputed, and the result is cached. For every single getter. Even the one that just return the raw data. Which means your data is stored in memory twice. You don’t want to do that. Never.
Vuex getters are a really nice feature and a double-edged sword. You should really use them sparingly.
Conclusion
So, no, you should not always write accessors. Whether it is in Java, in Vuex or anything else. But, don’t get me wrong: I’m not saying that writing accessors is a code smell or a fail. I’m not even saying that always write them is a code smell. What I’m saying is: do what you want! Just stop repeating dogmas you’ve heard elsewhere like this is the truth. Because it’s really not. If you prefer to always write accessors in your development team, well good for you.
But not systematically writing accessors is not code smell. Things are more complex.