Criteria for bad design

Life works quite simply: often, to be smart, you just need not to do stupid things. This also applies to software development: in most cases, in order to do something well, you just need to not do it badly.

Most programmers have had experience with parts of the system that were badly designed. But even more sadly, most of you will have the sad experience of realizing that you were the authors of such a system. We wanted the best, but it turned out as always.

Most developers don't aspire to bad architecture, and for many systems there comes a point where they start to say that its architecture is terrible. Why is this happening? Was architecture design bad from the start, or has it become bad over time?

The root of this problem is the lack of a definition of “bad” design.

It seems to me that it is the understanding of the quality of design and the reasons for its “decay” that are the most important qualities for any programmer. As in most other cases, the main thing is to identify the problem, and it will be a matter of technology to solve it.

Definition of “bad design”

If you decide to brag about your code in front of a fellow programmer, you will most likely get ridicule in response: “Who does this?”, 'Why is it like that?' and “I would do things differently.” This happens very often.

All people are different, but you still write the code for your fellow programmers, so in the process of developing each feature, you always need a review phase when other people look at your code.

But even if a lot of things can be done in different ways, there is a set of criteria that all developers would agree on. Any piece of code that satisfies its requirements but still exhibits one (or more) characteristics is bad design.

Bad Design:

  • Difficult to change because any change affects too many other parts of the system. ( Rigidity , Rigidity).
  • When changes are made, other parts of the system break unexpectedly. ( Fragility , Fragility).
  • The code is hard to reuse in another application because it's too hard to get it out of the current application. ( Immovability , Immobility).

And the funny thing is that it is almost impossible to find a piece of the system that does not contain any of these characteristics (that is, is flexible, reliable and reusable), meets the requirement, and at the same time its design is bad.

Thus, we can use these three characteristics to unambiguously determine whether a design is “bad” or “good”.

Causes of "Bad Design"

What makes a design rigid, brittle, and immovable? Rigid interdependence of modules.

A design is rigid if it cannot be easily changed. This rigidity is due to the fact that a single change to a piece of code in a woven system results in cascading changes in dependent modules. This always happens when one person is working on the code.

This immediately complicates the entire commercial development process: when the number of cascading changes cannot be predicted by the designer or developer, it is impossible to estimate the impact of such a change. Therefore, they try to postpone such changes indefinitely.

And this in turn makes the cost of change unpredictable. Faced with such uncertainty, managers are reluctant to make changes, so the design officially becomes rigid.

At some point, your project passes the “event horizon” and is doomed to fall into the “black hole” of rigid architecture.

Fragility is the tendency of a system to break down in multiple places after a single change. Usually new problems occur in places that are conceptually unrelated to the place of change. Such fragility seriously undermines confidence in the design and maintenance of the system.

This was usually the case when there were no private methods. It is enough to make all methods public, and you will be doomed to the appearance of a fragile architecture. Encapsulation helps to deal with this at the micro level. But at the macro level, you need a modular architecture.

When a project has a fragile architecture, the developers cannot guarantee the quality of the product.

Simple changes in one part of the application lead to bugs in other unrelated parts. Correcting these errors leads to even more problems, and the escort process turns into a famous dog chasing its own tail.

The design is immobile when the necessary parts of the system are strongly tied to other unwanted details. Too much of their own code, their own unique approaches and solutions.

Do you remember the JUL logger, whose developers came up with their own logging levels for no good reason? This is just the case.

To give a designer an idea of ​​how easy it is to reuse an existing design, it's enough to think about how easy it will be to use in a new application.

If the design is tightly coupled, then this designer will be horrified by the amount of work required to separate the required parts of the system from the unnecessary details. In most cases, such a design is not reusable, since the cost of separating it outweighs developing it from scratch.

Relevance

Everything changes, but everything stays the same. (Chinese proverb)

Very good questions have been raised above. What are the dangers of fragile and rigid systems? Yes, because the process of managing such a project becomes unpredictable and uncontrollable. And the price is exorbitant.

How can a manager give or not give the go-ahead to add some feature if he does not know how much time it will actually take? How to prioritize tasks if you can not adequately estimate the time and complexity of their implementation?

And how can developers pay off the same technical debt when we will rake in paying it, and we cannot understand how much we will rake until we rake?

Problems with code reuse or testing are also very relevant. Unit tests serve not only to test some assumptions about the unit under test, but also to determine the degree of its cohesion and can serve as an indicator of reuse.

Here is a quote from Bob Martin for this case: “In order to reuse your code, you need to make the effort of reusing it less than the cost of developing from scratch . ” Otherwise, no one will even bother with this matter.

The use of design principles and patterns serve one purpose - to make design good. If their use does not give you any benefit (or vice versa, violates the principles of “good design”), then something in your conservatory is not right and, perhaps, the tool has begun to be used for other purposes.