Now granted, if you’re talking about some super simple code that doesn’t need more than a glance to understand, sure, fair enough, make it as concise as you like. But let’s also be adults here, how often do we have the luxury of working on applications where the code is really simple, so simple that you don’t need to sit there & really think about things for a reasonable length of time? Most real world projects I’ve encountered tend to consist of many small bits of code, sure, but they add up to essentially create a lot of complexity, even if it isn’t overengineered.
It’s possible to keep your code relatively concise with the use of clean code & when I use the term clean code, I mean using common sense, I’m not necessarily referring to Uncle Bob’s clean code. On small & simple applications, sure, you might have the luxury of being able to write really small, really concise functions that might only need a minute number of tests & they’re self documenting because they’re so simple. But again, when you’re working on real world projects, it usually doesn’t take long until concepts such as DDD become a necessity.
If you were to try & avoid verbosity in such applications, I think you’d essentially be pointing a loaded gun at your foot. I recommend in complex situations, you embrace verbosity, I’d even argue in complex applications, verbosity can add some degree of self documentation, sometimes it can even make it somewhat easier to test.
Let’s consider concepts such as railway programming for a second here, this sorta goes against the idea that verbosity is bad, because you need to adopt a very defensive approach to writing code & in my humble opinion, that’s a good thing.
Let’s consider the likes of an email address & the validation that you might want to do on an email address & so on. If you take a look at this video made by Milan Jovanović, he proves my point. He refactors some code that technically requires less code to have more code. This might sound nuts at first, but as complexity builds up & up in your application, this simply put becomes more & more of a critical part of the evolution of the code base. As more features are added & as more product centric complexity is added into the mix, if you were to use ternary operators or an endless number of if statements, the code would quickly become a lovely bit of spaghetti code.
Now let’s consider a silly scenario, let’s consider a school grading system, where we just take some data regarding an exam & we calculate the grade against the outcome of the exam. Sounds simple enough at first right?
Most of you who’ve come across standard opinions & practices in the world of software engineering may straightaway say that this should be turned into a switch condition, etc, sure, why not? But then there’s some people that would go for making it even more concise by using nothing but ternary operators, etc. So it might look a little something like this:
Now this example by itself looks fine, however, I think most people would agree that this is somewhat of an agile approach where we value working software & we’re okay with applying what we know now & respond to change. But in the real world, to the best of my personal knowledge, grading systems aren’t this simple.
Often in the real world there’s a lot more that comes into the mix when it comes to having some grading system, and for arguments sake, let’s ignore how scores or results are calculated, otherwise we could delve into a rabbit hole. So let’s stay focused on grading systems alone for the time being, we all know that in reality it depends. It depends on the course, whether or not there are different classes, like in the UK at GCSE (or whatever they may be called now) level, you might have foundation tier & higher tier.
So quickly, this code needs to be rebuilt, or at the very least refactored, with the if else condition, it’s not so bad, you can just have a ‘parent’ if statement looking at the tier of the exam perhaps. Like so, now granted, I’m not saying that this is clean code, heavens no, but my point is that it’s not too hard to understand what’s going on.
Now let’s look to remove some of the ‘verbosity’ here, we might end up with something like this, which granted, it doesn’t look too bad. In my humble opinion, it’s not so clean anymore that you can see what’s going on at a glance, but give it a minute & I’d be able to figure it out.
Now that we’ve included the concept of a tier, let’s now consider the academic year, let’s consider the academic subject, maybe we consider the exam body? You can see how things can quickly build up & impact how the grade is calculated.
A Better Solution
In my opinion in this kinda situation, I’d probably start to take advantage of OOP, I’d consider using something like a grading factory. Now again, I’m not saying this is the ideal solution, but instantly, it’s a lot easier to see the purpose of each class. It’s really easy to see what’s going on within the scope of each class, now granted, considering I am doing a really silly/small example, you could argue that it’s somewhat overkill, but you get the idea, this could include more & more & more features. I.E. You could even hook it up to a database & deal with things that way, which would make a lot of sense in my opinion, since non technical people like admin staff could update the exam boards that the academic institute offers. They could update the grading for the different subjects & different tiers if they wanted to.
But, for the sake of this subject matter, let’s just ignore all of that & consider that our only option is to do it via code, we might not even have the luxury of using configuration, etc. You can see that yes, there’s a lot of classes, however, each class is really small, each class can easily be tested in isolation, etc. If you were to continue down the path of relying on one function or one method, of even one class to implement all of the above, it would very quickly become pretty messy to maintain, pretty messy to unit test & so on. And as always, as software systems rarely decrease in complexity, as technology advances, people’s requirements & expectations also advance, so you can quickly see how just relying on the likes of a ternary operator to ‘simplify’ your code quickly becomes redundant.
Sure, there are a million different ways in which you could implement that code, you could consider a nice DDD approach or something like that, but I won’t bother delving into that rabbit hole. The fundamental point is that as you want your code base to be able to grow easily, without having to fundamentally change everything. Using some really concise method would just make it so much harder to maintain & test, etc.
Even having some solution like this, in my opinion, it’s yet again somewhat more complex to test, granted with my original solution, you’d have to write more tests to cover more classes, but with this approach, you’re relying greatly on configuration, thus I’d imagine that there’s more room for error.
Even with my revised solution, you can see that you’re maybe saving what? 30 lines of code, give or take. In my opinion, going with the original solution is better, fundamentally it is better, it’s easier to unit test, each class has a well defined single purpose, etc & in my humble opinion, there’s a lot less room for error. Even in the event of an error, I personally believe that it is also better with regards to the error messages as opposed to the revised solution.
Don’t hate on verbosity for the sake of it, verbosity can be your friend, just looking at compiled languages compared to weakly typed languages, you know what data type a given variable is before you’ve done anything. Again, in terms of maintainability & readability, I honestly believe that this adds value to the overall developer experience. Which in turn means that it’s easier to add more & more product oriented complexity, into the technical space, whereas over simplifying things can cause for some technical debt headaches further down the line, resulting in delayed deliveries & potentially even resulting in a loss in profits & so on. As I’ve also mentioned, with the solution that essentially contains an array of ‘factory’ patterns glued together, it’s super simple & to write unit tests for, it’s also super, duper simple.
All in all I hope you’ve found this useful to some extent, I know that in the past, I myself have been a victim of trying to follow the rule that less code is better. Experience tells me otherwise, granted, going too far the other way & having verbosity in places for the sake of it may be just as bad, if not worse. But using some common sense & going for a solution that can actually scale well over the course of time, that’s simply put within the realm of reaching the ideal solution. It doesn’t need to be perfect, if you’re going to follow agile philosophy, one can state that the highest priority is delivering working software. Yes, the agile philosophy does also put an emphasis on technical excellence, so that doesn’t mean use regular expressions everywhere to the moon & back, but I really think it boils down to being pragmatic & simply using some common sense.