Home
Tags Projects About
What Are The Best Software Engineering Principles?

What Are The Best Software Engineering Principles?

Tell me, dear developers - has anyone ever managed to create a working project in real life that complies with all Best Practices, has no shortcuts, has nothing to complain about? If so, why do you lie to yourself and others? Best Practices are only theory, which not only fail to translate into practical application but also begin to contradict themselves.

As people, not just developers, architects, or managers, we grapple with distractions, errors, personal issues, bad moods, and yes, cold coffee. This is why we need a small set of great underlining engineering principles to guide us.

Software Engineering Principles are recommendations that, when followed, help us craft beautiful, clear, and maintainable code. While no magic wand exists to transform a mishmash of variables, classes, and functions into perfection, there are a few core principles to help us determine if we’re on the right track.

Measure Twice, Cut Once

If there’s one principle to retain from this post, it’s this one.

To me, as an engineer, this means that before building functionality, you should carefully consider the problem, the approach, the tools, the team, and the metrics for measuring and monitoring the solution. Only then should you start implementing, even if you’re not completely certain. This is the heart of engineering.

Measure twice and cut once

Don’t Repeat Yourself

DRY is a straightforward but valuable principle. Repeating code in different places complicates maintenance because:

  1. Even small changes require updating the same code in multiple places, costing additional time, effort, and attention (it’s often trickier than it seems).
  2. There’s a risk of overlooking one of these updates, leading to errors in the application that can be especially frustrating if you thought a bug was already fixed.

So, as a rule, if any code appears more than twice, consider extracting it into a separate function. In fact, creating a separate function is often beneficial even at the second instance of repetition.

Keep It Simple, Stupid

“If you hear hoofbeats, think horses, not zebras.”

Some say KISS evolved from Occam’s Razor: don’t add complexity without necessity. Always ask if a new method, class, tool, or process brings genuine benefits beyond added complexity.

As Peter Hintiens put it, “Simplicity is always better than functionality”.

You Aren’t Gonna Need It

Developers are often tempted to preemptively add all necessary—and sometimes unnecessary—functionality. But according to YAGNI, implement only the essentials and expand later if needed. This saves time, effort, and reduces unnecessary debugging for features that might never be used.

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 correct and necessary process to refactor the application, speed it up, as well as to reduce the consumption of system resources. But everything has its own time. If you carry out optimization at the early stages of development it may do you more harm than good. First of all, this is related to the fact that the development of the optimized code requires more time and effort. Besides, you often have to constantly verify the correctness of the whole system using any kinds of regression tests.

That's why it is better to use a simple, but not the most optimal approach at first. And later on, you may decide to switch to a faster or less resource-intensive algorithm when you estimate to what extent this approach slows down the application. Moreover, while you are initially implementing the most optimal algorithm, the requirements may change and the code will be trashed. So you should not waste your time on premature optimization.

Principle of Least Astonishment

Your code should be intuitive and avoid surprising future developers. Minimize side effects and document them when unavoidable. For example, if a method is called making_cookies but returns Potato objects, it’s bound to confuse anyone. Aim for code that behaves as expected.

S.O.L.I.D.

SOLID is a group of object-oriented design principles, each represented by one letter:

  • Single Responsibility: Each module or class should handle a single aspect of functionality.
  • Open-Closed: Software entities should be open for extension but closed for modification.
  • Liskov Substitution: Derived classes should complement, not replace, the base class’s behavior.
  • Interface Segregation: Clients shouldn’t depend on methods they don’t use.
  • Dependency Inversion: Code should depend on abstractions, not concrete implementations.

These principles collectively create code that’s easier to maintain and extend over time.

Law of Demeter

The Law of Demeter advocates for clear responsibility boundaries between classes and recommends the following:

  1. Decoupling: Reduce interdependencies between classes.
  2. Cohesion: Related classes should be grouped together within a module, package, or directory.

Adhering to these principles makes applications more flexible.

Conclusion

Fellow developers, let’s be engineers! Let’s focus on designing and building robust, well-architected systems, rather than growing organic monsters. These principles are highly correlated and connected in their essence. Of course, I didn’t create them, a small reminder never hurts.

Additional materials



Buy me a coffee

More? Well, there you go:

7 tips to make an effective Python Style Guide

The Importance of Clear Software Requirements

How to Build High-Performance Engineering Teams