Software development principles are a set of specific rules and recommendations that engineers should follow during program implementation if they want to write beautiful, clear and maintainable code. There is no magic wand that can turn a mishmash of variables, classes, and functions into perfect code, but there are a few tips and hints that can help an engineer determine if he is doing the right thing.
Let's take a look at these basic recommendations. Some of the principles below are Python-specific, but most are not.
Measure twice and cut once
I think that's the most important principle of all. If you learn only one principle from this post, it should be this one. We,
developers /architects/ managers people struggle with lack of attention, stupid mistakes and misprints, personal problems, bad moods, and cold coffee. None of this is relevant — the problem has to be solved. For me as an engineer, this principle means choosing the right solution to the problem, choosing the right approach to the problem, choosing the right tools to solve the problem, confidence in the built solution. Choosing here means putting some thought into it, find the necessary resources, put together the right team, thinking about design, thinking about the approach, set tasks, control the result and bear responsibility for this. This is "Engineering as is". I think that I myself am not ready to describe it with correct words.
Don’t Repeat Yourself (DRY)
It's a rather simple but very useful principle which says that repeating the same thing in different places is a bad idea. First of all, it is related to the necessity of further support and modification of the code. If some code fragment is duplicated in several places inside a program, there is a high probability of two catastrophic situations:
- When making even small changes to the source code, you need to change the same code in several places. It will require additional time, effort and attention(often it is not easy).
- The first item follows the second one. You or another developer from your team may accidentally miss one of the changes(it can happen simply by merging branches in vcs) and face the subsequent bugs in the application. These bugs can be frustrating to you because you have heard that such a bug has already been fixed.
In this regard, there is a recommendation — if any code is found in the listing more than twice, it should be placed in a separate way. This is a general recommendation. In fact, you should think about creating a separate method even if you encounter a repetition a second time.
It's a very common idea, which came to programming from philosophy. The principle got its name from the English monk William of Oakham. This principle says: "Entities are not to be multiplied without necessity". In engineering, this principle is interpreted as follows: there is no need to create unnecessary entities without necessity. Thus, it is always a good idea to think first about the benefits of adding another method/class/tool/process, etc. After all, if you add another method/class/tool/process etc. and you don't get any advantages other than increased complexity, what is the point?
Keep It Simple Stupid (KISS)
This is a very similar principle to the above, but it has a slightly different meaning. This principle says that the code must be as simple as possible without complex structures, otherwise it will complicate debugging and maintenance of the code. Besides, it will be more difficult for another programmer to understand the code's logic, which in its turn will also require additional time and effort. That's why you should always try to use simple constructs that solve the problem as much as possible without numerous branches, deep nesting and excessively overloaded class structures. By doing this, you will make life easier for yourself and your colleagues, because complexity generates bugs. Remember what Peter Hintiens said: "Simplicity is always better than functionality".
You Aren’t Gonna Need It (YAGNI)
A problem that many programmers suffer from. The desire to implement at once all the necessary (and sometimes even unnecessary) functionality from the very beginning of the project. That is, when a developer adds all the possible methods to the class from the very beginning and implements them, and may even never use them in the future. Thus, according to this recommendation, first of all, implement only what you need, and later, if necessary, extend the functionality. This way, you will save effort, time and nerves on debugging the code which is not really needed.
Big Design Up Front
Before starting to develop functionality, you should first think about application architecture and design the entire system to sufficiently small details, and only then proceed to implementation according to a predefined plan. Principle has a right to exist, but lately, there has been quite a lot of criticism of it. It is first of all connected with the obsolescence of the plan during designing and working out. In this connection, it is necessary to make the subsequent changes still. But it also has undeniable advantages, at correct designing, it is possible to reduce considerably cost of further debugging and correction of errors. Besides, such information systems, as a rule, are more laconic 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 correct and necessary process to speed up the program as well as to reduce system resources consumption. But everything has its own time. If optimization is carried out at the early stages of development, it can do more harm than good. First of all, it is connected with the fact that the development of an optimized code requires more time and effort for development and support. In this case, you quite often have to check the correctness of the chosen development approach at first. That's why at first it is more profitable to use a simple but not the most optimal approach. And later on, when estimating how much this approach slows down the work of an application, move on to a faster or less resource-intensive algorithm. In addition, for as long as 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 waste time on premature optimization.
Principle Of Least Astonishment
This principle means that your code should be intuitive and obvious, and not surprise another developer when reviewing the code. For example, if the method is called "making cookies" but you get potatoes as a result, that code is bad (obviously). Besides, you should try to avoid side effects and document them if you cannot avoid them.
“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 basic idea of this principle is to divide the areas of responsibility between classes and encapsulate the logic within a class, method or structure. Several recommendations can be distinguished from this principle:
- The classes or entities should be independent
- You should try to reduce the number of connections between different classes (so-called coupling).
- The associated classes must be in one module/package/directory (also known as cohesion.
Following those principles, the application becomes more flexible, understandable and easy to maintain.
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 their essence. Of course, I didn't create them, but a small reminder does not hurt, at least my memory is definitely not perfect.