When developing applications, we are constantly confronted with new approaches, languages and concepts. And constantly we rush about doubts “can I be on the wave, remain competitive, considering all the changes and trends?”. Let's think for a moment, remembering the phrase from my favorite film “Casablanca” - there are no new laws in love - that's how the light was created.
Everything related to love applies to the code. There are no new laws in the code. If you clearly understand the basic ideas of development, you are able to quickly adapt to new approaches. In this article I will tell you about three basic principles that, along with others, allow you to adjust the complexity of development. I will share my vision of the question, which I hope will help you in your daily work.
DRY - Do not repeat yourself (do not repeat yourself)
This principle is so important that it does not require repetition! It is usually referred to by the acronym DRY, which first appeared in the infamous book
The Pragmatic Programmer , but the concept itself was known for a long time. It belongs to the smallest parts of your software.
When you develop a large project, you often have to deal with redundant overall implementation complexity. People do poorly in managing complex systems, they are better able to find unusual solutions to certain problems. The easiest solution to reduce complexity is to divide the system into smaller, independent modules that are easier to manage.
')

The simplest approach to reducing complexity is to divide the system into manageable parts. 
For example, a part of any CMS is the component responsible for managing users. This component can be divided into other components, for example, the management of access levels that can work with other components of the security system.
In this way, by dividing the system into components deeper and deeper, you will reach the moment when each part of the system will be responsible for clearly defined actions. Such actions can be organized into classes. Classes will contain methods and properties. Methods represent algorithms that build the business logic of your system.

The principle of DRY requires that such pieces of information be met only once in your code. 
These parts should have one presentation.
Note the difference between the information (data) and its presentation. When we organize a connection to the database in our CMS, we will have a code that will raise the required driver, accept authorization, and store the pointer to the connection in a variable. Here, the code is information describing how we get something (connection). A variable with a connection pointer is a representation of this information that can be used anywhere in the system. If suddenly we change the authorization, we will need to change only the “data”, but not their presentation.

Each piece of data must have a clear, reliable representation in the system. 
In an ideal system, each part of the business logic encapsulates its data into a view — a variable or a class property. This variable is encapsulated in a class responsible for part of the architecture. A class is a part of a component that is an implementation of a part of the system functional.
Thus, we can get to the top of the system - a complex set of functional implementations. This approach of the organization is called a modular architecture, and, in turn, DRY, is an important part of it.
The task of the architecture is to manage complexity.
Stop repeating
There are quite a few ways to eliminate repetition. Hunt and Thomas offer code generators and data transformations. But DRY, as a result, is the philosophy of issuing logic through representations.
Each part of your application can be a view, each part provides a certain logic - the authorization control module gives access to your users, the user class contains information about the current user with a set of its properties. This class, in turn, receives data through the database view.

DRY is a philosophy that breaks the logic into representations. 
DRY and modular architecture require good planning. For the proper organization of the hierarchy of views, divide your system into small parts that can work together. If you are to manage a large project, you should consider the idea of organizing it with components using DRY. Try to follow these rules:
- Make a graphical diagram of your system, divide it into visual components. Complex projects may require such hierarchies for each component.
- If you are merging into an adjacent level of implementations (part of a common system), you can try using UML diagrams (or similar ones)
- Before writing code mark it in your graphic scheme, determine its role among other components of the system.
- Clearly define the views that your code will issue to other parts of the system, and which it must hide (private / public).
- Make sure your code is loosely coupled to other system views — hard links have a very bad effect on the overall architecture.
The database driver is a slightly lightened example, since it can contain many other levels of logic in real projects, and it has many more areas that can be divided into smaller components, especially with regard to modern design patterns. But even if you have only broken the implementation, do not forget about the important thing:

If suddenly you catch yourself on the fact that you have already written / met this code before, stop, think, and do not repeat yourself. 
In real projects to achieve 100% DRY is almost impossible. But, in turn, there are quite a lot of projects that are not-DRY at an unacceptable level and which are difficult to manage. And perhaps it will be a surprise for you - 50% of all our projects fail, if you look at their code.
Many people tend to think that bad programmers write bad code. My experience says that it is rather an exception. A little more often than always bad code is written by accountants. And yet, incorrectly set process management in companies, too, produces bad code.
Example
As an example, let's imagine that you were invited by a technical consultant to a company that has problems with the quality of the code and its management. You looked through the code and found out that there are a lot of hacks in it, and the code is not DRY. This is the first symptom of a bad code, but it is not its cause. You look at the history of komitov, you most likely find that these hacks are used in the later stages of the project - deadlines, milestones. After analyzing the story, you understand that some changes in the requirements caused these same hacks.

Rarely bad code is written by bad programmers. 
We remember that repeatability is eliminated by good planning. Urgent changes in the system entail urgent, non-optimal solutions in the code. As soon as the code undergoes bad decisions, the whole DRY principle for this solution stops working, until future changes.
If you look at the history of the most successful IT companies, many of them were created by people with an understanding of the problem - Bill Gates, Mark Zuckerberg, Steve Wozniak, Steve Jobs, Larry Page, Sergey Brin, Larry Ellison - these people knew that they had to overcome for solutions of a particular problem. But there are companies that transfer system management into the hands of accountants, and conceptual management into the hands of consultants. Neither can control these areas.

DRY is achieved by joint planning. 
That is why many solutions work only in Powerpoint, Photoshop, and 27 ”screens. It kind of worked in more or less static sites. But not today, in a world where a bunch of different interactive applications and devices.
And programmers who are the last in the chain are required to promptly correct errors in the system. If they are seasoned with accountants who are unable to resist the customer's every minute whims, all planning goes to hell and bad, very bad code is written. The code is no longer DRY.
This example is a bit pessimistic (although I often come across it), but it clearly shows that DRY is a concept that depends on many people. If suddenly you work in a company that is just as start-up, I advise you to suggest changes in the processes (for example, technical evaluation in the early stages of projects).
If you are asked not to stick your nose where you do not need, read on - the principle of YAGNI will save you!
KISS - keep it simple stupid (make things easier)
At the end of the 19th century, physicists were trying to find an explanation of how gravity, magnetic fields, and optics work at large distances — distances within our solar system. A theory was derived about the existence of a certain ether that acts on all those forces, and it cannot be explained. Later this theory was expanded by some experiments, but none of them explained the problem.

Often the simplest explanation is the right solution. 
A little later, Albert Einstein, an employee of the Swiss Patent Office, suggested to abandon this theory, neglect all distance calculations, and simply assume that time is not a constant — it is relative. Such a solution to the problem with the minimum number of dependencies is explained by the principle of "Occam's razor".
And similar concepts are found in many areas. In software development (and some others) we call it KISS. This acronym has many meanings, but they all boil down to one thing - you should try to make things as simple as possible.
Most of the progress in the history of mankind was achieved thanks to extraordinary thinkers.
HTTP
The HTTP protocol is often cited as an example of an ideal, simple solution - originally created for the transfer of hypertext documents, today it is the basis for many interactive applications. It is possible that sometimes we have to look for workarounds for the problems associated with the limitations of this protocol, and maybe in the future it will be replaced by another protocol. But today the fact remains: based on several methods of requests (GET / POST), status codes and simple text arguments, HTTP is quite flexible and reliable. That is why web developers are trying to squeeze the maximum out of it, and that is why this protocol is still in service.
The approach to making things easier is pretty obvious, but the history of software development is full of various bad, raw solutions. They are often called a separate word - bloatware, or DOA (dead on arrival) - dead at birth. Relative to such software, you can apply a theory similar to the theory of non-DRY code ... However, the success of the Internet can be explained by simple, effective solutions.
So how to achieve the highest possible, simple solution? It all comes down to the possibility of support, and detail in software development. That is why KISS should be applied at the requirements definition stage. Trying to implement customer requirements in your code, try to highlight the following:
- A functional that has an inappropriate relationship between costs and profit.
- Functional, which is strictly dependent on another.
- Functionality, which, with a high probability, tends to grow, and become more difficult.
Somehow I took part in a project where a client wanted to import Excel spreadsheets into his personnel management program. Good example. Excel is a proprietary application with a complex format. The format of the documents is complicated, because It implements a rich functionality - for example, you can add graphs and other chips that, in fact, were not needed by the client. He needed just numbers from the table. Thus, introducing imports from Excel, would have to spend a lot of time on unnecessary functionality. In addition, there are several versions of Excel, which every year more and more. Those. all this would be difficult to manage, and there were risks of additional costs in the future.
And we decided to implement import from CSV format. The solution took a few lines of code, was not overloaded with data (if you compare CSV and Excel formats), it was easy to manage and maintain. Excel can easily export data in CSV format (like many other programs that the client could use in the future). And, given the minimum cost of implementing this requirement, this solution is an excellent example of KISS.
Moral - try to consider things from the simple side if they look complicated. If a client tells you his requirements, the implementation of which seems difficult to you, you are right in any case. Even considering that some things are really difficult to implement, we often face solutions that are overloaded unreasonably. This happens because The development process involves some people who do not have the technical experience to correctly calculate the cost / benefit. And they just do not see the whole problem. Therefore, always double check customer requirements and make sure that this is exactly what they need. Discuss critical moments, explain to him why other solutions might be better suited.
You ain't gonna need it - you won't need it.
When Google launched Google+, Mark Zuckerberg, the founder of Facebook, was one of the first registered in the social network, which was designed to surpass its network. He wrote just one line in the “About Me” section - “I build things”. Personally, I think this is a brilliant proposal, revealing the whole essence of programming. Why did you choose the coder path? Enthusiasm in technical solutions? The beauty of efficiency? So that you do not answer, most likely it will not be “to build a 100,500th corporate website with standard functionality.” And yet, many of us earn precisely this. Wherever you work, you occasionally have to deal with boring, routine tasks.

I am programming. I build things. 
The principle “You will not need this” (YAGNI - you ain't gonna need it) is just meant to solve such problems.
This means that what is not conceived in the system should not appear in the code. For example, quite often access to the database is carried out through abstraction, which can be implemented for different drivers - MySQL, PostgreSQL, Oracle. If you are working on a site that is hosted on a LAMP stack - what is the likelihood that a client will change the database? Do not forget that the concept is always written under the budget - right?
If the budget does not provide an abstraction for the database - this abstraction should not be in the system. If suddenly the client needs to move to another database, it is quite obvious that this will entail the costs of changing the system.
You must have noticed the difference between YAGNI and DRY systems. The latter is designed to reduce complexity by dividing the system into manageable components, while the former reduces complexity by reducing the number of these components. The principle of YAGNI is similar to KISS - it tries to make things as simple as possible. But KISS is trying to find simple solutions, and YAGNI simply does not make any decisions!
Theodore Sturgeon, American science fiction, put forward the
law - "90% of everything is complete nonsense." Quite a radical statement, and not always applicable in real projects. Do not forget that "nonsense" can take a lot of time. There is an unspoken rule: approximately 80% of the time spent on development is spent on implementing only 20% of the system's functionality. Remember your projects. Every time I review my own, I am constantly convinced how the 80/20 rule works.
80% of the time spent on development is spent on the implementation of only 20% of the functionality of the system.
This strategy is very well applicable in a company where it is customary to keep deadlines mixed with not very clear concepts. No one will appreciate your database abstraction. There is even a chance that your boss has no idea what an abstraction database is.
Nevertheless, even if this approach may seem rather simple, it is often not so easy to separate the necessary parts from the unnecessary parts. For example, even if you have implemented an abstraction, it will not give you any gain when dumping the database. The key point is how we look at the software - we were taught to write code that is easy to maintain and will be profitable in the future. Those. we were taught to look ahead, considering all possible changes. Sometimes it is critical for large projects, but not for small ones. Stop thinking about the future! If suddenly a small site requires radical changes, it would be better to start from scratch. And this is not such a problem, given the overall investment.
Project planning
Starting planning a new project, try to consider the following:
- To achieve less complexity by reducing the level of abstractions
- Separate functionality from features
- Consider small non-functional requirements.
- Identify time-consuming tasks to get rid of them.
Let's break it down. On the first point, I already gave an example - you should not implement an abstraction to the database driver. Try to carefully evaluate everything that can add complexity to your system. Note that often many abstractions are implemented in third-party products and libraries. For example, depending on what language you write, Hibernate (Java), Doctrine (PHP) or Active Record (Ruby) all come with a level of abstraction around the database, and ORM. Each of these libraries adds complexity. And she will have to manage. Updates, patches, security fixes - all you have to do / apply in the future.
Every day we introduce new features that we think will be useful. Consequently, we think ahead and realize too much. For example, many customers want to have mobile versions of their sites. Mobility can be represented by many values, it is not necessarily a design decision. This is a usage scenario! People who use mobile sites are mobile. This means that they may need other information or functionality than those who use the desktop version. Imagine the cinema site - users on the way to the cinema, on the bus, will most likely want to see the start time of the session, rather than a 50-meter trailer.
With an adequate budget, you will try to make a separate analysis of the requirements for the mobile version. Without such an analysis, you simply give out the same information as for the desktop. And this may be enough for many projects. Because today, many mobile browsers are able to properly configure the look of the site, and here you can apply the radical approach of YAGNI - do not make a mobile version at all!

Bad concepts can often be identified by the absence of non-functional requirements. 
Non-functional requirements do not describe the behavior of the system, they describe additional properties by which you can evaluate the quality of the product. Because quality description implies product knowledge, bad concepts can often be identified by the absence of non-functional requirements. The ability to support, the level of documentation, the ease of integration are all examples of non-functional requirements. These requirements must be measurable. Those. “The site should load quickly” - too generalized, but “The site should load in 2 seconds during the performance test” - very concretely and clearly. If you want to apply the YAGNI approach, try to take into account some non-functional requirements, even if they are not included in the concept (or taken into account, but not very clear). When you write such a requirement, be realistic - a small site, with 20-50 visits per day, does not require a three-day performance tuning, because the site will load quickly and so, if the server is not overloaded. Even if the company will be able to increase its attendance, buy a more powerful hosting should not be a problem.
And finally, always remember the 80/20 rule. Try to identify time-consuming tasks. If such a task is mandatory for implementation, it will have to be done. The question will be just how to do it. Do we need another framework with a small community? Will you have to upgrade to the just-released version of the library if its documentation is still not updated? Is there a need to use a new CMS, if not all extensions to it workable? How deep analysis will have to spend to realize your task? The “always have to do this” approach is not very exciting, but it will help you solve the problem without surprises.
It is also important to understand that all this does not mean that you can sit down and write bad code flavored with hacks. You just write a
small application, not a
bad one ! However, the “you don't need it” approach is quite practical. If it helps to reduce several lines of code, I personally think that it is possible to bring this work into the budget, and a small non-DRY is quite acceptable. Those. one can agree not to slightly increased support costs - we live in the real world.
Let's go back to our main idea - we build things. Beethoven wrote “Diabelli Variations” on a contract. I do not think that he was going to compromise on the budget. He spent more time, but did not release bad music - he wanted to write the perfect one.
Of course, I do not mean that we are all geniuses, and that our genius should appear in every line of code, but I like to think of software architecture as a composition. I am a passionate developer, because I want to build perfect compositions, and I want to be proud of the things that I build.

If you want to be an experienced and sought-after developer, you need to hone your skills in principle YAGNI. If you want to keep your passion, you have to constantly resist it. 
Conclusion
Software principles are points of view on this software. For me, a good principle should be based on a simple concept that should evolve into a complex construction of ideas, colliding with other approaches and philosophies. What are your favorite software guidelines?