Notes about software design principles
Tags: development, softwareengineering, oop, beginners
Published: 2023-08-04 07:12:23

You might have different thoughts or want to hightlight some other principles. Feel free to share them in comments below.

**KISS**

Keep it simple, stupid. This means we should avoid overthinking and cut any unnecessary complexity. By doing so, we can keep the implementation as lean as possible.

**DRY**

"Don't repeat yourself" means avoiding duplication of code or functionality. Personal note here: When you see that it is easier to duplicate some part of the code with less complexity, don't hesitate too much and do it.

**SOLID**

These principles can help you build code that is more maintainable, scalable, and testable. I’ll not go to much in details as there’re tons of information and examples that help you understand.

**Single Responsibility**: Each class should solve a single problem or focus on a single functionality.

**Open Closed**: Open for extension (behavior can be extended) and closed for modification (the core functionality should not be changed).

**Liskov Substitution**: The ability to substitute a child type with a parent type without any extra changes in code. This principle intersects with the previous one in that a child type can extend parent behavior without modification.

**Interface Segregation**: You should not have one big interface with tons of methods, but several small ones that are more client-specific.

**Dependency Inversion**: Higher-level modules should not depend on lower-level ones, and both should depend on abstractions.

**YAGNI**

You ain’t gonna need it. It pretty much intersect with KISS and you need to go with minimal functionality when you’re trying to solve the problem or implement new feature.

**BDUF**

"Big Design Up Front" has both positive and negative aspects. It is important to ensure that it truly works for you and doesn't make your life harder.  The idea is to design the implementation in details upfront, with the goal of leaving only the "monkey job" to be done later. Honestly, I never seen that to be working that way. Instead, it can be helpful to have a meeting to summarize the project's goals and keep the team in sync, but leave the details to the person who will actually be implementing them.

**SSOT**

Single source of truth. The meaning behind that instead of having multiple copies of the same data you have single place where you keep that data and that’s exactly single source of truth. That also applies to code (particular service in microservice architecture or class/library in monolith). It makes easier to search information or troublshout the issue if you single source of truth. Even when you need to have the copy of the data for other service or have modified version in other place you still should rely on single source of truth and sync from them. 

**Worse is better**

Don't get me wrong, it doesn't mean you need to write ugly and hacky code. The idea is not to miss the point when your solution becomes overcomplicated or when you spend time on things that bring low value.

**Premature Optimization Is the Root**

Based on this principle, we should not waste time optimizing the code in the early stages. However, that should not be an excuse to neglect performance and quality. I think everythink depends how much effort it takes. When it comes to small cost and better value, I don't see any reason not to do it.

**Loose coupling**

The less components/elements depends on each in your system, the easier it is to maintain and improve that system. You can reduce coupling by following these two approaches:

- Try to choose composition over inheritance. By doing so, you won't depend on the parent type and can substitute a component without much effort.
- Cover your code with unit test. Unit tests are about testing particular unit/part of your system. So, when you struggle to add them that a sign something goes wrong.

**Occam's razor**

When choosing among competing hypotheses, it is best to select the one with the fewest assumptions. This means selecting a solution with fewer variables that can affect your implementation or hypothesis. For example, if you have several ideas in mind, start by investigating the one with the fewest variables and that is easiest to prove.

**Pareto Principle In Software Engineering**

The Pareto Principle states that often **80% of the results come from 20% of the causes**

- focus on the 20% of product features that make up 80% of the product’s value
- focus on the 20% of the bugs that cause 80% of user frustration
- focus on the 80% of product features take 20% of the total time to build
- focus on the 20% of pages that take 80% of the total time users spend on platform

**Murphy’s Law**

Murphy’s well-known law says that **whatever can go wrong, will go wrong**. You need to be ready for the worst case scenario, but make sure to not overthink. For example: you can use feature flags for new features to go back to original implementation if something goes wrong, create backups or write restore script to prevent data loss etc.