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

During my experience in software development, I’ve understood the significance of maintaining simplicity.

It is my privilege to have served as a software developer for over two decades, starting as a Senior Software Engineer and progressing to the position of Chief Technology Officer at Intelligent Hack. Throughout my career, I have been blessed to have worked with exceptional companies like Stack Overflow, which I have seen grow into the world’s leading community for developers. I have been fortunate to be a part of this remarkable journey and witness its immense progress.

I adhere to a universal principle in all my coding assignments – simplicity is key, regardless of the project, client, or requirements.

In this article, we will discuss our latest Technical Workshop, which took place online. You can view the entire presentation by clicking here.

What is the significance of choosing an effortless path?

According to Gall’s Law cited in the book “Systemantics: How Systems Really Work and How They Fail” by John Gall, a simplified approach is crucial for achieving successful outcomes. Complex systems without a sturdy foundation are challenging to rectify and rarely achieve completion. Therefore, it is imperative to commence with a reliable and efficient groundwork before moving forward with further development. Gall aptly advises, “You need to abandon the outdated system and start anew with a simple and effective foundation.”

In general, simple systems are more comprehensible, adaptable, and reparable, resulting in increased efficiency. They execute processes faster, catering to a wider audience, and are predictable with no room for ambiguity.

Contemporary systems can be perplexing, leading to widespread bewilderment concerning the underlying reasons for certain operations. As new users are added or removed from the system, it becomes increasingly strenuous to ensure that all participants possess the necessary knowledge to operate it sufficiently. Consequently, any gaps in knowledge can lead to significant apprehension.

It is factual that even simple systems can execute complex tasks, such as the troublesome procedures of build and deployment. Nevertheless, it is crucial to recognise the possibility of inadvertent complexity seeping into the system while structuring and organising code, choosing architecture, or balancing flexibility and rigidity. Hence, it is vital to aim for simplicity throughout the entire process, from initial setup to ongoing operation, monitoring, and further development.

Issues posed by complicated processes

Hence, where can one find complexity? In my opinion, unintentional complexity usually infiltrates systems through six primary points of entry. By eliminating any unnecessary intricacy, one can concentrate on what truly matters – the fundamental difficulties that the system intends to resolve.

  1. Decoupling

    Decoupling code can improve adaptability in specific scenarios. However, it is imperative to recognise the consequence, as it can complicate comprehensive refactoring and generate intricacy within the system. Ineffective decoupling practices can produce an obscure architecture, fixating developers on designs that are tough to alter. Thus, it is crucial to consider decoupling as a balance between enhancing a particular application’s functionality and preserving system simplicity.
  2. Design patterns

    The Gang of Four advocates prioritising “composition over inheritance” when creating design patterns, although many programmers overlook this guideline. Incorporating design patterns into a system can increase its complexity by introducing unnecessary structures and interactions. Consequently, it is recommended to avoid enforcing design patterns during the development phase and instead observe the code being produced to identify any patterns that emerge naturally. This guarantees the use of the most appropriate design pattern that suits the system, rather than resorting to an assumption-based one.
  3. SOLID

    Robert C. Martin’s, also known as “Uncle Bob”, SOLID principles of object-oriented design have inspired many developers. Nonetheless, it is crucial to acknowledge the circumstances under which these principles were conceived. Game and web development possess significantly distinct limitations and ideas from the telecommunication industry. Though SOLID is not fundamentally unsuitable, it frequently proves inapplicable to the current programming milieu, complicating matters when unnecessary.
  4. Premature abstraction

    Comprehending code abstractions is vital for upholding the DRY (Don’t Repeat Yourself) principle. To put forth this notion, a suggestion is to wait until three or four examples of a corresponding element are recognised before trying to extract their commonalities. When writing code, it is advantageous to shun generic resolutions and instead collaborate with the current code, proceeding with modifications only when essential to meet satisfactory standards.
  5. Unnecessary programming languages

    Superfluous code can impact any of us. Small components, such as futile design patterns, single-implementation interfaces, and other unserviceable elements, are frequently added to our systems without our knowledge. To prevent this predicament, we must inspect our code for any elements that contribute to unnecessary complexity and remove them promptly.
  6. Overreliance on libraries

    The use of libraries in software development can present a two-sided outcome. On one hand, libraries can offer significant convenience and reduce the duration needed to accomplish tasks. However, it can complicate your system and diminish your ability to personalise your environment. Furthermore, it may generate compatibility problems that can potentially decelerate or crash your system. Therefore, it is crucial to weigh the benefits against the drawbacks and determine the extent to which libraries should function. If you are integrating a vast amount of redundant code, it is recommended to substitute the library with a few lines of code to obtain the anticipated results.

As a closing remark, recall Gall’s Law.

While deciding between simple and complex resolutions, it is crucial to recognise the absence of a universal answer. Each development project has its specific requirements and constraints, which must be evaluated. We must bear in mind the overarching objectives, exercise prudence when attempting to decrease complexity, and keep up to date with new codes. Upholding Gall’s Law, it is wise to pursue simplicity from the onset to generate sturdy and expansive systems.

Related Article: Seeking Software Developer Jobs? Acquire the Skill to Write Clean Code First

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