Reasons Why Keeping Your Code as Simple as Possible Should Always Be Your Primary Objective (and 6 Complexity Pitfalls to Avoid)

One thing I’ve learned while working in software development is the value of keeping things as simple as possible.

For the past two decades, I have been privileged to experience a career as a software developer, ranging from a Senior Software Engineer at Stack Overflow to the Chief Technology Officer at Intelligent Hack. During this time, I have had the unique opportunity to be part of Stack Overflow’s evolution as it has become the world’s premier developer community. It has been an incredible journey to witness the immense changes that have taken place there.

One guideline I use to all of my code regardless of the project, customer, or brief is this: keep it simple.

In this article, we will review the most recent Online Technical Workshop we had. Click here to see the whole presentation..

What’s the point of taking the easy route?

In accordance with Gall’s Law, as stated in John Gall’s book Systemantics: How Systems Really Work and How They Fail, it is imperative to be straightforward in order to yield successful results. Complex systems, if developed without a successful basic system, are nearly impossible to fix and rarely reach completion. This is why it is essential to start with a reliable and efficient foundation and build upon it. As Gall states, “You need to scrap the whole thing and start over with a basic system that really works.”

It is generally easier to comprehend, adapt, and repair a basic system, thus making it more effective. These systems work faster, and are accessible to a greater number of users. Furthermore, they are predictable and nothing is open to interpretation.

The complexity of modern systems can often be mystifying, leading to widespread confusion about the underlying causes of certain actions. When new users join and leave the system, it can be increasingly difficult to ensure that everyone involved has the knowledge needed to properly use the system. As a result, any gaps in knowledge can be a serious source of concern.

It is true that even simple systems are capable of performing complex tasks; take build and deployment as an example, which are often notoriously difficult. However, it is important to be aware of the potential for complexity unintentionally creeping into the system when organising and structuring code, selecting architectures, or deciding between flexibility and rigidity. Therefore, it is important that we strive for simplicity throughout the entire process, from setup to operation, monitoring and beyond.

Challenges posed by complexity

Consequently, where can complexity be found? In my estimation, accidental complexity is often introduced into a system through six main points of entry. By removing any complexity that is not necessary, you can focus your attention on what really matters -the essential complexity of the problems that your system is trying to address.

  1. Decoupling

    Decoupling code can be an excellent way to increase flexibility in certain situations. However, it is important to remember that it comes with a trade-off, as it can make comprehensive refactoring more challenging and add complexity to the system. Poorly implemented decoupling can lead to an architecture that lacks clarity, trapping engineers in designs that are difficult to change. As such, it is important to consider decoupling as a compromise between making a specific application easier and maintaining a system as simple as possible.
  2. Design patterns

    It is widely advocated by the Gang of Four that “composition over inheritance” should be prioritised when designing patterns. However, this is a rule that is frequently overlooked by programmers. Incorporating design patterns into a system can increase its complexity, as it will introduce new structures and interactions which may not necessarily be required. Thus, it is suggested that instead of trying to impose design patterns during the development phase, one should observe the code being created and look for design patterns that emerge naturally from it. This ensures that the design pattern that is employed is the most appropriate for the system, rather than one that may be used out of assumption.
  3. SOLID

    Many developers find themselves inspired by Robert C. Martin’s, commonly known as “Uncle Bob”, SOLID principles of object-oriented design. Nevertheless, it is important to consider the context in which these principles were formulated. Game and web development are vastly different from the telecom industry, each with its own unique set of constrictions and concepts. While SOLID is not inherently bad, it often does not apply to the current programming environment and can complicate matters when the situation does not call for it.
  4. Adequately abstracting too soon

    Having a strong understanding of code abstractions is essential for adhering to the DRY (Don’t Repeat Yourself) principle. To better illustrate this concept, we suggest waiting until three or four instances of a similar element have been identified before attempting to extract the commonalities. Additionally, when writing code, it is beneficial to avoid generic solutions and instead work with the existing code, only making modifications when absolutely necessary to meet acceptable expectations.
  5. Totally pointless programming language

    It is possible for any of us to be affected by the presence of superfluous code. Oftentimes, these small components are unknowingly introduced into our systems, including single-implementation interfaces, unnecessary design patterns, and other elements which do not serve a purpose. To avoid this issue, we should inspect our code for any elements that add unnecessary complexity, and take the necessary steps to remove them.
  6. Having too much faith in libraries

    The use of libraries in software development can be a double-edged sword. On the one hand, libraries can provide a great deal of convenience and may reduce the amount of development time necessary to complete tasks. On the other hand, they can also add complexity to your system and reduce your ability to customise your environment. Furthermore, they can create compatibility issues that can potentially slow down or crash your system. Therefore, it is important to consider the trade-offs and determine the amount of work that libraries should perform for you. If it is determined that you are adding substantial amounts of code that you are not utilising, then you should consider replacing the library with a few lines of code in order to achieve the desired outcome.

As a parting thought, keep in mind Gall’s Law.

When making decisions between simple and complex solutions, it is important to remember that there is no universal answer. Every development project has its own distinct needs and limits, which must be taken into consideration. It is necessary to keep the overall objectives in mind, be careful when attempting to reduce complexity, and stay informed of the emerging codes. In accordance with Gall’s Law, it is advisable to strive for simplicity from the beginning in order to create resilient and expansive systems.

Related Article: Looking for Software Developer Jobs? Learn How to Write Clean Code

Join the Top 1% of Remote Developers and Designers

Works connects the top 1% of remote developers and designers with the leading brands and startups around the world. We focus on sophisticated, challenging tier-one projects which require highly skilled talent and problem solvers.
seasoned project manager reviewing remote software engineer's progress on software development project, hired from Works blog.join_marketplace.your_wayexperienced remote UI / UX designer working remotely at home while working on UI / UX & product design projects on Works blog.join_marketplace.freelance_jobs