Are You Writing Too Much Code?
For many beginners, code is the act of writing if else
statements and trying to figure out how to make things work. During this process, the code produced becomes a convoluted mammoth with unexpected plot twists that rival the Red Wedding from “Game of Thrones.”
More code isn’t always better code. Sure, it made sense at the time you were writing it — until you look back and try to unravel the mystery novel you unintentionally created, with no sense of clear direction, structure, and major plot holes that trip up linear processes.
Bugs occur when there’s a gap in the developer’s knowledge, mostly born out of being unaware of efficient and effective patterns in code. The bliss of structural oblivion often does last long, even after the code produced is working. Over time, however, it contributes to the frustrations that arise out of things being too jumbled.
Here are some questions to help you structure your logic and bring awareness to important patterns in software development.
How Functional Is It?
As much as we love the idea of object-oriented patterns, functional ideologies can also exist within classes and methods. Functional programming deals with how data is processed based on the given situation and has a strong aversion to dependencies.
Dependencies aren’t bad, but too many can result in an unwanted spiderweb.
The chaining effect caused by dependency injections reduces the modularity of the code. You’re depending on the previous item to work correctly, creating a series-circuit effect.
Functional patterns transform the way you code into sets of parallel states that can exist on their own, thus increasing modularity — which is the act of isolating and creating clear domains of logic. When code is modular, it won’t break as much or as often.
Dependancies can also exist within the function itself, creating redundancies, despite the logical ring-fencing created. This often comes in the form of repeated values under different names, loops within loops, or nested logic. If this occurs, the best quick fix is to flatten your logic and abstract it out.
Does It Need to Be Public?
Not everything has to be a global state or exist as a public function. Sometimes, code privacy is a good thing; it can prevent scope creep and create security for your variables.
It’s easy to make everything public but that’s not the point of accessibility scoping.
When you make everything public, the code inside your services and factories becomes prone to external mutability. This increases the scope of change and takes it beyond your potential and expected cases.
In JavaScript, everything is technically accessible and global. But with the advent of TypeScript and its growing, widespread usage, creating clear distinctions in public and private variables and functions gives your code robustness against unwanted access and change.
Are You Over- or Under-Abstracting?
Sometimes, we get carried away in the act of codifying business requirements. We become obsessed with the idea of modularity, or simply become too engrossed in trying to capture a complex idea.
Over-abstracting occurs when we try to make our code too modular because we’ve been told that it’s the way to do things. Under-abstracting is when we are faced with a complicated set of rules that we haven’t quite figured out how to simplify yet. By the end of the exercise, abstraction is simply too mentally taxing to refactor out or we’ve just run out of time.
So what exactly is the right amount of abstraction?
The purpose of abstraction is to extract out clear boundaries of repeatable code. The right amount of abstraction occurs when we don’t over-plan potential usage, nor write the same logic again but in a different scope space.
Nesting is usually the first sign of under-abstraction. Multiple injections and calling of numerous external functions is a key marker for over-abstraction.
Are Your Names Actually Useful?
When it comes to code, complex code is not sexy code. You’re not trying to peacock your way into the favors of future developers reading what you’ve written.
Long names with redundant descriptions often contribute to the noise of unnecessary code. Short acronyms that make no sense to the uninitiated bode future disasters, because meaning is no longer explicit and rests with humans who may leave the company, never to be seen or heard of again.
It only takes one generation for knowledge to be lost to any civilization. It only takes the departure of one developer from a company to lose whatever implicit information the function tracusboo
is supposed to represent.
So write useful names. Tell it like it is. If the name gets too long, it means you are trying to capture too much information and things may need to be abstracted out. Your code is not a Hollywood “Matrix” screen, so don’t write it like one.
Have You Written This Before?
Some things repeat themselves over and over again. Sometimes, we recognize the patterns in our code and realize that we’ve already written something before, but in another function, class or method.
Or perhaps someone else wrote it in another place. This is where abstraction and refactoring become necessary for maintaining the cohesion of your code and preventing repetition.
If it looks familiar, chances are, it’s because you’ve already written the same patterns somewhere else. Refactoring is the act and process of restructuring code to meet the growth of the codebase and maintain the long term stability of cohesive executions.
Refactoring itself doesn’t have to be on a grand scale. Micro-refactoring often occurs on the fly when we’re writing our own code and taking time to make efficient the inefficiencies that arise from the process of capturing business logic.
What, Exactly, Are You Trying to Capture?
Code always has a purpose. It exists to represent something. The question becomes, what, exactly, does your code represent?
What is the expected output? How do we get to that expected output? Being vague in our names and functional processes will result in flaky code that has no clear boundaries or purpose for existing.
When business requires new elements to be added, that’s a change caused by growth. Will this growth break the original component? Or is it isolated enough, with clear boundaries, to receive minimal impact?
Flexible code isn’t about how much ground it can cover. Rather, it’s about how resilient it is to change. When you know what the expected outputs are, it’s easier to ring-fence and protect it through a single-responsibility methodology.
Final Thoughts
Creating consistent, clean code is a process that takes practice. The more we clean up after ourselves, the easier it becomes to recognize our personal flawed patterns and habits.
Sometimes, it takes learning something new and overcoming your resistance to writing easier, but potentially flaky, code. We tend to fall back on what we know best, but that doesn’t always mean it actually is the best pattern or method.
In fact, there is no such thing as “best” in code. Rather, it’s what is most efficient and effective for your project’s requirements based on time constraints and resources available.