An Introduction to Software Development Design Principles
This introductory article talks about the things a software developer must keep in mind while developing any software. It also talks about what are some of key principles that one should consider while writing code on a daily basis.
Let’s begin topic with a question – In context of software development, what to be considered as a good design?
Most people believe there is no specific answer to this question! But what highlights when it comes to design is that cost and time of development and maintenance of a software should be minimum, more importantly, maintenance. Since IT industry goes through a lot of improvement and upgrades in Software, if cost and time of changing design are minimum, then it can be said it’s a good design. The reason is that it is quick with low cost to perform improvements and push for updates/upgrades.
While it could be a good approach for a good design but still there is a problem associated with this, and problem is when it comes time to change design, it realize it’s too late to change design. So now again question remains what to be considered as a good design?
To answer this question in a better way, let’s start subjecting design to change along way and see how design stands up? And if it doesn’t, let’s keep evolving and get closer to something which is easier to change, and this is what many experienced developers have done so far. So, software development design principles are a set of certain guidelines that are given by experienced developers which they have learned from their mistakes while they were in development phase of software.
It is almost impossible to get a good design for very first time.
Design Principles :
So far article talks about understanding concept of good design, Now let’s go in detail about set of guidelines available for good design.
1. Keep It Simple, Stupid (KISS) Principle :
It is very first principle, acronym stands for Keep It Simple, Stupid. The other famous alternate acronyms are
- Keep it simply stupid.
- Keep it short and simple.
- Keep it simple and straightforward.
- Keep it simple and smart.
It suggests not to involve complexity in your code, and try avoiding it as much as you can. This is because more complex code is written, more difficult it becomes to modify at any later point of time. There is a very well said quote phrased by Albert Einstein, that will give green light to what has been stated above – If you can’t explain it, you don’t understand it well enough. Therefore, simplicity should be our key goal in designing software.
The above image clearly illustrates that KISS principle objective is to achieve goal by making things as simple as possible and by using simplest solution, like a straight path instead of achieving goals by making things complicated and struggling to and fro.
Violation example of KISS –
One might have gone through a situation where he/she has written a messy code, either in early stage of programming career or somewhere in programming journey. Here messy code means writing solutions of multiple problems in one block, method, or class. This might leads to add some of unnecessary lines in code. There may also be a situation where there could be multiple solutions to one problem. For instance, in some cases, both switch statement and if-else statements provide solution to a problem. Now based on context which one to use and which one would be simpler solution, needs to be picked. Of course, this was just a simple example for illustration purposes. But in a day to day programming and development life one has experienced many such issues. It requires a pause to think properly and select a solution wisely.
The task of software development team is to engineer illusion of simplicity. – Grady Booch
Benefits of KISS –
- It helps in solving problem quickly.
- Since solution is simple, it helps in maintaining code.
- It provides flexibility to modify or refactor code.
- It provides solution of complex problems in fever lines of code.
- At the end it delivers high-quality code.
2. You Ain’t Gonna Need It (YAGNI) Principle :
YAGNI stands for You Ain’t Gonna Need It. That means if it won’t come handy later, don’t do it now. Being a programmer, developer usually implement so many things that they really don’t need. Implementing something which is not at all required now, will always consume cost, time, and effort. So, it is always a good practice to postpone stuff for future which is not required today. In short, YAGNI simply says don’t really do something, until you really find value in doing it.
This principle works behind extreme programming (XP) but it is applicable in all kinds of software development processes and methodologies. Implementing YAGNI saves time and delivers project efficiently. In short, this principle is against development of any features which are not required at present. So that developer can save time and focus on other pieces or components of a code.
3. DRY Principle :
The programmers usually write enormous duplicate codes accidentally or un-accidentally. This principle forces us to avoid this habit. It says Don’t Repeat Yourself. It means, every piece of knowledge in a system should have exactly one and unambiguous representation. Programmers can get rid of duplication of code by using tools like CPD and Simian. CPD stands for Copy Paste Detector. And, Simian means monkey, which naturally copies one thing or other.
Violation examples –
Programmer repeat codes again and again in many ways. Some of examples could be declaring excessive local variables for each assignment and initialization. Writing multiple methods and classes for the same task again and again. Consider a situation in which a method is written outside of service or data layer to fetch a set of users data from a repository, and some filtering needs to be applied on that set. Now if there is same type of requirement in another layer, logic needs to be written again because that layer is not accessible from this one. Generally, this kind of task resides in service/data layer. So that whenever same type of requirement is there, concerned method of that service or layer can be invoked.
How to Avoid DRY –
To avoid DRY, follow below-mentioned points.
- Reuse your code and never duplicate it
- Follow naming conventions and assign clear names of a method, variable, class and objects etc.
- Write code in appropriate layers, locations and services
Following naming conventions and adding code to a proper location helps to identify duplication in code.
4. SOLID Principle :
SOLID is a combination of below set of design principles, and from where It’s mnemonic acronym has been taken.
- Single Responsibility Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion
5. Single Responsibility Principle (SRP) :
This principle says that our code should be cohesive in nature. Here cohesive means, it should be focused, narrow, and does one thing and only one thing well. Which in turn means a cohesive code doesn’t take many responsibilities and it is focused on doing only one thing. In context of object-oriented design, it is well said that a class should have only and only one responsibility so that it has to change less frequently.
If a code is cohesive, it has one, and only one, reason to change.
So, if there is a piece of code that does several things, then that module has to change constantly which is more expensive because when a programmer comes to change it, he has to make sure that changes do not break other things and really being affected and it becomes very expensive. On the other hand when a piece of code is broken into several pieces where each piece does one and only one thing well, then cost of changing that piece is much easier.
When it says “a piece of code” think it as a Classes, methods, or functions. Violating Single responsibility principle increases difficulty level for a programmer, and it becomes hard to test, read, remember, and reuse code.
6. Open/Closed Principle (OCP) :
This principle says that a piece of code (in general class, module, or a component) should be open for extension and closed for modification. which means a Classes, methods, or functions should be written in a way that it is ready for adopting/adding new features but not interested in any modification. In the context of object-oriented design, this could be achieved with the concept of Abstraction and Polymorphism.
7. Liskov Substitution Principle (LSP) :
This principle says that function that uses references of parent classes must be able to use object of child classes as well without knowing it. It means methods that can use superclass type must be able to work with object of derived class without any issue.
The user of a base class should be able to use an instance of a derived class without knowing difference.
8. Interface Segregation Principle (ISP) :
This principle says that a client should not be forced to implement an interface if they don’t need it. This usually happens when an interface contains more than one function and client needs only one but not all. In this case client is forced to implement all functionality of that interface. which is insane and should be avoided.
Hence, one must always keep interface cohesive and narrow and focused on one and only one thing.
9. Dependency Inversion or Dependency Injection (DI) :
This principle talks about coupling. Coupling is degree of connectivity among things, that is how your piece of code is connected to each other. Crisp point to remember here is when our code is talking with other pieces of code, it always increases coupling. In short, coupling is something on what our code depends on. A great example could be traditional class-based inheritance.
Inheritance actually increases coupling quite a bit. Now as per this principle, either remove or minimize dependency to extent it could be. If you can’t remove all dependency then at least minimize it, and this is called loose coupling. In the context of object-oriented design, depending on a class is called tight coupling, whereas depending on an interface, it is called loose coupling.
A good design always ends with high cohesion and loose coupling
This principle works in tandem with OCP principle, To avoid OCP violation, use dependency inversion principle. The Dependency Injection oriented frameworks like Spring is a real-world example and implementation of this principle
It is not a design principle but instead a good practice that many developers or company follows. Once development of software or component is completed, it must go for a code review process before pushing it to next stage. This review could be done by anyone from your team.
Remember that humans are quick to judge others faults, but never point out their own.
Once it has been reviewed and review comments are available, keep our ego away and have a look onto it, and perform changes if required.
The above were some of highly discussed design principles, which are extremely important and helps us in avoiding duplicating code, efforts and helps us to keep complexity as minimum as possible. So you can apply these principles in our day to day coding life, whenever you are developing a piece of software or a component of it. It is also a good practice to discuss these principles among colleagues or teammates you are working with during designing and development process, So that if you are missing any of principles or violating it, it will be pointed out at earlier stage itself instead of making a blunder at later stage.