Thinking Clearly About Problem Solving and Design.
P.S. - This article has many references from other people who are pioneer in the field of software architecture and design. I have added my perception and my idea of design principles and problem solving. Please take what you feel is relevant for you and leave the rest as we say in Software Design "No one design will fit all the use cases".
A little intro about myself : I am currently working as an SDE 2 at Amazon. While preparing for the interviews at amazon, I came across the design principles and architecture semantics. In our day-to-day jobs, we often tend to ignore these principles, but once you start thinking about writing the code or even adding the new functionality for that sake while keeping these principles in mind, you will be amazed to see how they can drastically influence our design choices.
Here I am going to include some of the principles which has helped me :
Problem decomposition:
Decompose the problem you are trying to solve into smaller chunks which are easy to reason about. for example when you are trying to design a Library Management system from scratch , don't directly jump into the designing the library, but understand the mental model of the client .
- Client may not be thinking of books library but only thinking about the audio library.
- Client may not be thinking of only library but some library cum coffee studio.
This will also help you reduce the change blast radius. for example : According to today's requirements, you are asked to have in-memory queue as the data source, but let's say tomorrow you want to have DB as your data source. So if you have thought clearly about the data source while understanding the client requirements and defined segregation of duties for each of the module, you will be able to easily change the data source without much change in your actual application logic.
Also it helps in software evolution. So you incrementally build your design and add new features which is the case when we are designing applications, for example first we design MVP (Minimum Viable Product) and then go on to incrementally build the product.
Abstractions:
So when we think of abstraction, first thing that comes into out mind is OOPS principles. But frankly speaking Abstraction is much more than that.
Abstraction is an ART, and to be a good Software Engineer/Architect, everyone must learn this art. There are many ways to decompose a problem, but always decompose the problem according to the client's requirements and the domain. Naming has a major role while doing abstractions. for example : A room with the chairs will be called as classroom. now to the same room you can add gas and stove. Now there are many possible options to name this: a. 1 bhk house b. small restaurant c. Cullinary Classroom. So choose the names wisely.
One way/ Two way doors:
This principle refers to the reversible and irreversible decisions. Any one way door can become two way door given proper time and thought. for example : Incorrect Abstractions, not writing unit tests, going with the static configuration instead of dynamic are all examples of one way doors. If you have lot of choices, make your decisions independent of choices. look out for decomposition and trade off's of each of the choice and then decide according to your use- case.
Flexibility:
There is one principle which we should swear by: for every complex problem, find an easy solution. Find the solution which is as easy as possible and as hard as required. There are mainly 2 ways to manage complexity: Modularity and Flexibility . Flexibility is achieved via Configurations. for example : A simple use case can be port no where you want your tomcat server to come up. today you want to use 8080 but after sometime you want to change that to some other port as 8080 is used by some parallel module. So if the configuration is stored in config file it is very easy to change. Recently I can across the code base where configurations were stored in S3 file so as to have dynamic configurations(Although this may have other consequences).
Elements for Reuse :
Always design your system thinking of extensibility and reuse. for example: keep your client layer, business logic, Accessor layer separate so that changing one won't have an effect on the other. In this case design principles generally comes in rescue but be diligent while applying the correct design principle which adheres to your use case.
In the end, I would like to conclude by saying always have some design tenets in mind while designing the system
Thanks for Reading.
P.S: I will write the next article on the choice of design principles to continue . Stay Tuned.