Description

There are certain universal laws and principles in Software Development, that guides architects, programmers, and any other software professionals while developing a software application.

Every software professional must know and understand these principles.

Here is a list of some of the important principles.

1. KISS - Keep It Simple Stupid

KISS stands for "Keep It Simple Stupid".

  • Systems work best when they are kept simple rather than made complex, as they need less code, fewer bugs, easy to modify, and maintain.
  • It is believed and proven that perfection is reached not when there is nothing left to add, but when there is nothing left to take away, which can be easily achieved with simple systems.

So, always try to keep the system as simple as possible.

2. YAGNI - You Aren't Gonna Need It

YAGNI stands for "You Aren't Gonna Need It".

  • Don't implement something until it is necessary.
  • Anything that's only used by a feature that's needed tomorrow, must not be implemented, as it burns effort that can be used for something that's needed today.
  • It leads to code bloat, with unnecessary code, making the system bigger and more complicated.

So, always implement only the things that are really needed at the time of implementation.

3. Separation of Concerns (SoC)

Separation of Concern is a design principle, where we separate a program into distinct sections, each of them addressing a separate concern.

  • For example, Business Logic and User Interface are two different concerns, where changes to one of them should not impact the other.
  • It simplifies the development and maintenance of a software application.
  • Each of them can be developed and maintained easily.
  • Increases reuse components.

So, always break down a program functionality into separate modules, with no or very little overlap.

4. Keep things DRY

DRY stands for "Don't Repeat Yourself", whereas WET stands for "Write Everything Twice".

  • Each piece of functionality must be a single, unambiguous, authoritative representation within a system.
  • Each piece of functionality must be implemented just once and be shared across multiple programs if needed.
  • Duplication is a bad practice, which could lead to poor factoring, logical contradictions, and harder maintenance.
  • Put all the business rules, metadata, constants, common methods, etc., in one place and refer to them when needed.

Always apply the "Rule of Three", according to which we can write the same piece of code for the second time, but if we need to write it for the third time, we must extract such code into a common procedure.

Avoid duplication on any kind of asset, which can be code, documentation, tests, etc.,

5. Do the simplest thing that could possibly work

Try to ask yourself the question "What is the simplest thing that could possibly work?"

  • The answer makes us focus on the real problem.
  • Helps progress better towards its solution.

6. Code for the Maintainer

It is well known that maintenance is a far more expensive phase of any project.

  • Make sure you code software thinking as a maintainer.
  • Make sure you include enough comments, which should even help someone a few notches junior to easily pick up and maintain it.
  • Don't make a maintainer think.
  • Always think that you are coding for a maintainer.

7. Avoid Premature Optimization

Premature Optimization is the root of all evil.

  • Most programmers waste a lot of time thinking or worrying about the efficiency of non-critical parts of a program, and the attempts to improve its efficiency actually have a negative impact on when debugging and maintenance are considered.
  • Make sure you know how to determine what is and isn't premature.
  • Don't optimize until it's really needed, as it might be harder to read after optimization.

Always follow these steps in the same order.

  • Make It Work
  • Make It Right
  • Make It Fast (this is where the optimization is required)

8. Minimize Coupling

Coupling between the modules/components is their degree of mutual interdependency.

  • Lower the coupling, and lower the impact on one module when the other is changed.
  • Ripple effect on one another when one of the modules is changed.
  • Reduce inter-module dependency.
  • Tightly coupled programs are hard to test, maintain and modify, as they need more time to research the root cause.
  • Developers may hesitate to touch tightly coupled modules, as the changes may break something else.
  • Coupling can be reduced by hiding implementation details.

Always try to eliminate, minimize, and reduce the complexity of the necessary relationships between the modules/components.

9. Law of Demeter

It simply means "Don't Talk to Strangers".

  • It reduces coupling but might reveal too much of implementation details.
  • One such example is a method of an object calling only the methods below.
    • The object itself.
    • An argument of the method.
    • Any object created within the same method.
    • Any direct properties of the object.

10. Composition Over Inheritance

Composition reduces coupling between classes, whereas the inheritance may make subclasses make assumptions.

  • Use compose to relate two classes if there is a "has a" or "uses a" relationship.
  • Use inheritance to relate two classes if there is a "is a" relationship.

11. Orthogonality

The word Orthogonal means "related" in simple terms.

  • The things that are not related conceptually must be pulled out of a system.
  • It makes a system simple, less complex, has fewer issues, and less maintenance.

12. Robustness Principle

In simple words, be conservative in what you do, and be literal in what you accept from others.

  • All the modern system designs, a software communicates with several other services on different machines which communicate and exchange data between them.
  • Systems must be designed keeping these evolutions in mind.

So, code that sends data to other machines (or other programs on the same machine) should be according to the system specifications, but the code that receives the data should accept the data (even if it contains non-conformant data) as long as the meaning is clear.

13. Inversion of Control (or) Hollywood Principle

It is a design principle, which simply states "Don't call us, we'll call you", where custom-written portions of a computer program receive the flow of control from a generic framework.

  • It carries a strong connotation that the reusable code and the problem-specific code are developed independently though they operate together in an application.
  • It is used to increase the modularity of a program and make it extensible.
  • It decouples the task and its implementation.
  • Make modules free from assumptions about how other systems work, instead rely on the contracts with those systems.
  • Replacing a module becomes easy without any side effects.

This can be achieved using the below design patterns.

14. Maximize Cohesion

The cohesion of a single module/component is the degree to which its responsibilities form a meaningful unit.

  • Lesser cohesion makes the modules interlinked too much, where even a simple change in the domain affects multiple modules.
  • Higher cohesion makes the modules easy to understand, maintain, reuse, and enhance with new functionalities.

So, the higher the cohesion, the simpler the system.

Always, try to group related functionalities so that they share a single responsibility, like a class.

15. Liskov Substitution Principle

According to this principle, objects in a program should be replaceable with instances of their subtypes without altering the correctness of the program.

This is all about the expected behavior of objects.

16. Open/Closed Principle

According to this principle, the software entities (like classes) should be open for extension but closed for modifications, so that an entity's behavior can be modified without altering its existing source code.

  • Improves maintainability and stability, as it minimizes the changes to the existing code.
  • Always write classes that can be extended, instead of classes that can be modified.

Overall, expose only the moving parts that can be changed, and hide everything else.

17. Single Responsibility Principle

According to this principle, a software entity should have a single responsibility, which must be entirely encapsulated within the class.

Responsibility can be defined as a reason to change, so each entity should have one, and only one reason to change.

  • Each class or module should have only one reason for the change.
  • It makes the system maintainable as the changes become pretty straightforward and affect a single class or a module.
  • Try to apply Curly's Law.

18. Curly's Law

According to this law, there should be a single, clearly defined goal for every piece of code.

  • In short "Just Do One Thing".

19. Hide Implementation Details

A software module must hide the implementation details by providing an interface, which stops leaking unnecessary information.

  • When implementation changes, there won't be any effect on the interface clients.
  • It can be achieved by following the below steps.
    • Minimize accessibility of classes and members.
    • Don’t expose member data in public.
    • Avoid putting private implementation details into a class’s interface.
    • Decrease coupling to hide more implementation details.

Always make sure to hide the implementation details.

20. Encapsulate What Changes

Identify the hotspots that are most likely to change and expose them behind an API, so that when an anticipated change occurs, the modifications are kept local.

  • Try to separate the most frequently varies portion into its own module.
  • Encapsulate the functionality that varies and expose it as an API.

Always, keep an eye on what frequently changes in the system.

21. Interface Segregation Principle

According to this principle, a system must not contain fat interfaces, in case they exist, they must be separated into multiple smaller and more specific interfaces.

  • An interface must be dependent on the code that calls, and not on the code that implements it.
  • Avoid fat interfaces, by making classes following the Single Responsibility Principle.

Always, ask yourself "Is this method belong to this class?" when you need to add a method to a class.

22. Boy-Scout Rule

The Boy Scout Rule of America has a simple rule that can also be applied in software development, which states "Leave the campground cleaner than you found it".

  • When we make changes to existing code, the code quality tends to degrade, accumulating technical debt.
  • Always make sure not to degrade the code quality with each commit.
  • Always make sure the code is clear and understandable. In case, if someone sees code that is not clear, they should take the opportunity to fix it right there and then.

Always, make sure not to degrade code quality.

23. Command Query Separation Principle

According to this principle, each method should either be a command that performs some action or a query that returns data, but not both.

  • Query methods can be used anywhere and in any order as they do not mutate the state of an application.
  • Command methods must be carefully used as they mutate the state.
  • By clear separation of the type of methods, it gives additional confidence to the programmers while using them without knowing their implementation details.
  • Using proper method names that imply whether a method is a command or a query helps.

Always, try to implement methods as either a command or a query.

24. Murphy's Law

According to this law, "anything that can go wrong will go wrong, maybe now or later".

So, we need to think about all the possibilities, permutations, combinations, and an infinite number of trails when we develop an application.

25. Brook's Law

According to this law, "adding manpower to a late software project makes it later".

  • It is related to software project management.
  • In simple terms, it means that adding new developers to a late software project does not make them productive immediately, but takes time from other team members due to communication overhead.

Remember, not to add new members to a late software project and expect it to be delivered quickly.

26. Linus's Law

According to this law, "Given enough eyeballs, all bugs are shallow".

  • It is related to the software review process.
  • In simple terms, it means having a solid review process where multiple developers review the same piece of code before it is accepted or merged, making it bugs-free.

Remember, code review by multiple people makes the code more reliable.

Overall

We now know the most important programming principles that we need to remember.

Related Links