By Robbert van Os
Posted on 2023-04-15T00:00:00.000Z

Which Is Better for Software Design: Simplicity or Complexity?

Discover the intricacies of software design and explore the balance between simplicity and complexity, and the role of NFRs and stakeholders in the process.

Nothing is as Easy as it Seems. To put it all into simple terms!

The observer is the one who decides what constitutes simplicity, just as one decides what constitutes beauty. If you agree with this and have never wondered "why someone is making something complex when it is so simple," then you don't need to waste your time on this thought dump as you already understand "Nothing is Simple," things simply appear to be Simple on the surface of it. You don't need to waste your time on this thought dump since you already understand "Nothing is Simple."

During the process of Code and Design Reviews, a significant number of ideas for design improvements are addressed with worries that the complexity would rise. The purpose of this brief is to debunk the widespread belief that developing a successful software system is simple or easy, even if the requirements appear to be plain.

Because the process of designing and developing software is intrinsically complex, many different concepts, rules, methodologies, and patterns have been developed to address this complexity. These include for example:

  • SOLID: Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. These principles are used to guide object-oriented design. Learn more.
  • GRASP: General Responsibility Assignment Software Patterns. These are a set of guidelines for assigning responsibilities to classes and objects in object-oriented design. Learn more.
  • DRY: Don't Repeat Yourself. This principle encourages code reuse and reduces duplication. Learn more.
  • DDD: Domain-Driven Design. This design approach emphasizes the importance of understanding the business domain in software development. Learn more.
  • Design Patterns: Reusable solutions to common software design problems, such as the Singleton pattern or the Observer pattern. Learn more.
  • Integration Patterns: Patterns used in designing and integrating software systems, such as the Message Channel pattern or the Message Router pattern. Learn more.
  • Anti-Patterns: Commonly occurring design problems that can lead to poor software quality and performance, such as the God Object or Spaghetti Code. Learn more.
  • MVC: Model-View-Controller. This software architecture pattern separates the application logic into three interconnected components. Learn more.
  • KISS: Keep It Simple, Stupid. This principle emphasizes the importance of simplicity in software design. Learn more.
  • YAGNI: You Ain't Gonna Need It. This principle advocates against implementing functionality that is not currently needed. Learn more.

and many more. The purpose of all of these is to act as a map for us to follow as we navigate the complexity of software design and development. This complexity can occasionally be traced back to the Functional Requirements (FRs), but more often than not, it can be traced back to the Non-Functional Requirements (NFRs).

Each of the software developers, designers, and architects must choose (depending on the circumstances) their own unique set of concerns (NFRs) to fulfill. What a developer considers to be straightforward may in fact be lacking in other areas that are outside of their purview. On the other hand, what others may see as being difficult could just be due to a lack of comprehension or vision. You can find a thorough case study on an e-commerce system here. The FRs for the system were presented as being simple, but the system itself was fundamentally complex, making it difficult to construct and maintain. When non-functional requirements (NFRs) like data privacy, security, scalability, and performance are taken into account, a straightforward chat program that allows users to communicate with one another can become complex.

Once the system is analyzed from the perspective of many stakeholders, such as Production Support workers, Customer Service personnel, Business Analytics and Reporting Teams, Infrastructure provisioning automation, Marketing Team, IT and Infra Security and more, further layers of complexity are added to the equation. A good number of these stakeholders do not even offer requirements at the beginning of the project; rather, these requirements are either found by experienced members of the project team while they are doing a stakeholder analysis or they are found much later.

It is possible for the final software system and its code to be simple, despite the complexity of the process of producing it; yet, as Leonardo da Vinci once observed, "Simplicity is the ultimate sophistication," and accomplishing simplicity may be an extremely difficult and complex task. Good software designers are able to get around this complexity and construct systems and code that have the appearance of being simple, yet building anything simple is not simple at all.

Code Generation with AI tools like GitHub Copilot and ChatGPT is one more method for developing software that is rising in popularity as a way to simplifying the development process. There are a lot of corporations out there, some vain managers, and some naive developers who regard these tools as a clear replacement for expertise and talents. Software development is not only about producing the required output as described in functional requirements. Instead, it takes a great deal more thinking and finding than writing code, and these tools are not capable of doing it on their own by themselves. They necessitate the involvement of a knowledgeable human to perform the thinking and provide the appropriate advice or inputs, as well as to analyze and alter the generated code in order to fulfill all of the requirements (both FRs and NFRs).

In conclusion, simplicity in software design is something to strive towards, despite the fact that doing this might be complex and difficult. The process of developing software entails overcoming the complexity of FRs and NFRs, conducting an analysis of the system from the point of view of a variety of stakeholders, and making decisions based on the context of the situation. Code generation tools can be helpful, but they are not a substitute for architects, designers, or developers with the necessary skills.