DEV Community

Cover image for What Are The Best Software Engineering Principles?
luminousmen
luminousmen

Posted on • Edited on

What Are The Best Software Engineering Principles?

Software Development Principles — it is a number of specific rules and recommendations, which engineers need to be followed during program implementation if they want to write beautiful, understandable and maintainable code. There is no magic wand, by which you can transform a mix of variables, classes, and functions into the ideal code, but there are some tips and hints, which can help the engineer to determine if he doing things right.

Let's look at this base recommendations. Some of the principles below are Python-specific, but most are not.

Measure twice and cut once

I think this is the most important principle of all. If you learn just one principle from this post - it should be this. We, developers/devops/architects/managers people struggle from lack of attention, from stupid mistakes and typos, from personal problems, from bad mood and cold coffee. That all is irrelevant - you need to solve a problem. For me as an engineer, this principle means choosing the right problem to solve, choosing the right approach to the problem, choosing the right tools to solve the problem, confidence in built solution.

But this confidence cannot go from the code itself, it should go from all kind of tests, from running them often, from building the right solution for the problem and so on. This is Engineering as it is. I think I myself is not ready to describe it in the right words.

Don’t Repeat Yourself (DRY)

It's a pretty simple, but very useful principle, which says that repeating the same code in different places is a bad idea. This is primarily due to the need to further maintain and modify the code. If some code snippet duplicates in several places within the program then there is a high probability of two disastrous situations:

  1. Making even small corrections into source code, you need to change the same code in several places. It will require additional time, effort and attention(sometimes that is not easy)
  2. From the first item follows the second. You or another developer from your team may accidentally miss one of the fixes and face subsequent errors in the application. That errors may be frustrating because you heard that such bug was already been fixed.

In this regard, there is a recommendation - if any code is found in the listing more than two times, then it should be placed in a separate method. This is a general recommendation, in fact, you need to think about creating a separate method, even if you meet the repetition a second time.

style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-4665632381152577"
data-ad-slot="7970039881">

Occam’s Razor

It is a very common idea which came into programming from philosophy. The principle got its name from english monk William of Ockham. This principle says: «Entities are not to be multiplied without necessity». In engineering, this principle is interpreted as follows - no need to create extra entities without the need for them. So, you always need to think first about the benefits of adding one more method/class/tool/process/etc. After all, if you add one more method/class/tool/process/etc and don't get any benefits but increasing complexity then what's the point?

Keep It Simple Stupid (KISS)

KISS

It is a very similar principle with the one above but it has a slightly different meaning. This principle says that code should be simple, without any complicated structures if possible, otherwise it will overcomplicate debugging and maintenance of the code. In addition, it will be more difficult for another programmer to understand the code logic, which in turn will also require additional time and effort. Therefore, always try to use simple constructions as possible which solves the problem without numerous branching, deep nesting, overengineered class structures. By doing this you will simplify life for yourself and for your colleagues because complexity breeds bugs. Remember what Pieter Hintjens said: "Simplicity is always better than functionality."

You Aren’t Gonna Need It (YAGNI)

A problem which a lot of programmers suffer. The desire to implement at once all necessary (and sometimes even unnecessary) functionality from the very beginning of the development process. That is when the developer from the very beginning adds all possible methods to the class and implements them, while in the future it may even never use them. Therefore, according to this recommendation, implement only what you need in the first place, and in the future, if necessary, increase the functionality. So you will save efforts, time and nerves on debugging code that is not really needed.

Big Design Up Front

Before starting to develop functionality it is necessary to think first about application architecture and design the entire information system up to fairly small details, and only then proceed to implement according to a previously prepared plan. The principle has the right to exist, but recently there is quite a lot of his criticism. This is primarily due to the obsolescence of the plan during design and development. In this connection, you still have to make subsequent changes. But it also has irrefutable advantages, with the proper design you can significantly reduce the cost of further debugging and fixing bugs. In addition, such information systems are usually more concise and architecturally correct.

Avoid Premature Optimization

"Premature optimization is the root of all evil (or at least most of it) in programming" - Donald Knuth

Optimization is a very right and necessary process that allows you to speed up the work of the program, as well as reduce the consumption of system resources. But everything has its time. If optimization is carried out in the early stages of development, then it can do more harm than good. This is primarily due to the fact that the development of optimized code requires more time and effort of the developer and it may be more complex. In this case, quite often it is necessary to first verify the correctness of the chosen development approach. Therefore, at first, it is more profitable to use simple, but not the most optimal approach. And in the future, assessing how much this approach slows down the work of the application, move to a faster or less resource-intensive algorithm. In addition, for the time while you initially implement the most optimal algorithm, the requirements may change and the code will go to the garbage. So there is no need to spend time on premature optimization.

Principle Of Least Astonishment

This principle means that your code should be intuitive and obvious, and not surprise another developer during code review. For example, if the method called "make cookies", but as a result, you get a potato than this code is bad (obviously).

style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-4665632381152577"
data-ad-slot="7970039881">

S.O.L.I.D.

SOLID

SOLID” is actually a group of object-oriented design principles. Each letter in “SOLID” represents one of the principles, which are:

  • Single responsibility states that every module or class should have responsibility for a single part of the functionality provided by the software and that responsibility should be entirely encapsulated by the class;
  • Open-closed states that software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification;
  • Liskov substitution states that the inherited class should complement, not replace, the behavior of the base class;
  • Interface segregation states that no client should be forced to depend on methods it does not use;
  • Dependency inversion says that programmer should work at the interface level and not at the implementation level.

When applied together, these principles help a developer create code that is easy to maintain and extend over time.

Law of Demeter

The main idea of this principle is to divide the areas of responsibilities between classes and encapsulate the logic inside the class, method or structure. From this principle we can highlight several recommendations:

  1. Classes or entities should be independent
  2. Need to try to reduce the number of connections between different classes(aka coupling)
  3. Related classes should be in the same module/package/directory (aka cohesion)

By following this principle, the application becomes more flexible, understandable and maintainable.

Conclusion

Fellow developers let’s be engineers! Let’s think about design and build robust and well-implemented systems, rather than growing organic monsters. Listed principles are highly correlated and connected in there essence. Of course, I didn't create them, but a small reminder does not hurt, at least my memory is definitely not perfect.


Thank you for reading!

Any questions? Leave your comment below to start fantastic discussions!

Check out my blog or come to say hi 👋 on Twitter or subscribe to my telegram channel.
Plan your best!

Top comments (13)

Collapse
 
fpuffer profile image
Frank Puffer

I agree that every developer should know these principles.

But it is at least as important to know that it is impossible to fully comply with all of these principles in practice. Especially when overdoing one of them, it is likely that you violate others.

One example: When applying DRY, you need to build abstractions, like moving the duplicate code to a function. This is fine to a certain extent but when you overdo it, the code will get harder to understand and violates the KISS principle.

Some of the principles are also highly subjective, for example SRP. During development, do you really know what a single resposibility is? Do you know which parts of the code are likely to change independently and which won't? Most of us are much worse than we think at predicting the future and that's where YAGNI comes from.

So in reality it is not that easy. Learning and obeying these principles will not automatically make you produce better code. You need to find a good compromise and that's much harder.

Collapse
 
romstar profile image
Rami

I agree with your comment completely. Even following Solid to the T can create overly complex code depending on the problem you're trying to solve, e.g. Business layer complemented with a repository layer and code bleed through.

Collapse
 
patzistar profile image
Patrick Schadler

Agree with all of them, but I would also add seperation of concerns as one of them.

Collapse
 
w3bist profile image
Webist

Here is my contribution

  • Declaring "abstract" classes is completely useless.
  • Composition over inheritance everywhere. With this you don't have to worry about Liskov principle, Cohesion.
  • Class is a bad word to build a communicating object. It should be named Cell. Assume that way.

Many more, but time is up for now.

Collapse
 
leightondarkins profile image
Leighton Darkins

As a person who spends a great deal of time evangelizing SOLID in particular, I totally agree.

Overly strict adherence to principles is just as bad as having no principles at all.

Collapse
 
codemouse92 profile image
Jason C. McDonald
Collapse
 
rachelsoderberg profile image
Rachel Soderberg

This is a fantastic list... I'm going to print it out and put it up in my cubicle when I get to work in the morning. <3

Collapse
 
luminousmen profile image
luminousmen

Thank you that means a lot

Collapse
 
twisted_code profile image
Twisted_Code

I was at first confused by the image for SOLID because I wasn't sure what "single repository principle" was supposed to mean.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.