📜 ⬆️ ⬇️

Behavior patterns

(This note is the end of a series of posts, which included "Technical debt" , "Refactoring Syndrome" and "Effect of the second system" )

What are the benefits of design patterns? (*) This is, above all, the reuse of proven architectural solutions, as well as the simplification of communication between developers. But besides design patterns , there are a lot of other patterns: there are patterns of coding, testing, code modification (aka refactoring), there are architectural patterns and many others. Since we, in fact, rarely do anything truly new, proven standard solutions exist for a huge number of areas. And since most of the problems faced by development teams are also not diverse, then the behavior of these people is also very monotonous.

“Technical duty” , “refactoring syndrome” and “second system effect” are typical situations that the development team encounters from time to time. And the main advantage of them is precisely to see the problem and prove its existence to the right people. If you yourself understood that the technical debt of the project is too large, using the money metaphor it will be much easier to prove the importance of this problem to the manager or customer. And then carefully show him alternative ways of development of events: (1) leave everything as it is; (2) reduce technical debt by reasonable refactoring; or (3) rewrite all nafig.

')
Similarly, if you know about the problems of your developers, such as the desire for overwriting or the tendency to over-complex solutions, then it will be much easier to use the available resources in the most optimal way. By combining developers so that the advantages of one developer compensate for the shortcomings of another, you can reduce the risk of falling into extremes.

In addition to using the right people for the right tasks and sensible pragmatism, there are still a few thoughts that you should think about to reduce all sorts of risks and make inadequate technical solutions.

Risk Management and Encapsulation

John Robbins , if you didn’t know before becoming a famous bugslayer served as a green beret in the United States Army; and although, as he himself admits, it is difficult to recognize a brave warrior in him now, he has learned to use some of the “tricks” learned when planning combat operations in the development of software products and risk management.

Yes, perhaps questions like “What if Vasily gives an oak before he finishes the analysis or requirements gathering phase?” (**) may be too harsh and hardly be applauded by colleagues, but questions like “What if our current decision turns out to be wrong? ”can be very helpful.

For example, you choose a database interaction model, an interprocess communication library, a DBMS, or a library for creating a user interface. Each time, when making such a decision, it is not a big deal to ask yourself, “What will happen if this decision turns out to be wrong and we have to give it up?”

The main idea of ​​minimizing the risk of such errors is to encapsulate such solutions in the minimum number of modules. This will minimize the number of modules that will have to change in case of an error and will reduce both technical debt and the cost of subsequent changes.

For example, if you decide to use WCF for interprocess communication, this does not mean that services should stick out of all holes and business logic should be placed directly in the classes of services. Or, if you use a custom interaction protocol, be it a protocol for working with third-party equipment, a manual implementation of RPC, etc., then you do not need to smear information about this with a thin layer throughout the application. Or suddenly you still like COM (even though Don Box cannot already look at it), then you shouldn’t wrap every object in COM.

This may seem so banal that one shouldn’t even talk about it (well, or write too), but, unfortunately, such examples come across too often to think that everyone knows about it.

Encapsulation is not only the private fields of a class (that is, data hiding), but also information hiding in the broader sense of the word. So the encapsulation of using WCF in a separate module is exactly the same encapsulation from an architectural point of view, as well as a closed field with an int type in your class, from a design point of view.

Higher-level abstractions (such as assemblies / modules / any other crap higher level than classes) just as well consist of a public interface (abstraction) and implementation (hidden details). The notion of abstraction and encapsulation, which describe the tip of the iceberg - abstraction, and its underwater part - encapsulating implementation details, are equally applicable to an assembly or module, as well as to a particular class, although they are usually less formal.

Returning again to the interprocess communication module, we can select the open interface of this interaction and hide WCF as much as possible as part of the implementation. I do not doubt at all that nothing will come of this venture to 100% anyway, and according to the “leaky abstraction law” information about low-level implementation details will leak into other levels or modules. But at least an attempt to answer the simple question “What will happen if this crap does not take off and you have to refrain from the current decision?”, Should reduce the consequences if all of a sudden this crap really doesn't take off.

One head is good and two is a mutation.

There are lots of decisions that one person should take. It is unlikely that something will come out traveling, if the designer will run and ask the opinion of all fifteen developers and try to please each of them. In this case, get such a crap that Windows 3.11 in our days seems the height of design art and ergonomics. And if the application architect will ask the advice of everyone and everyone who has his own opinion about the system architecture (and, as you know, each project participant has it), the result of such work will not take long to wait either.

The kolkhoz management model, when a collective meeting makes a decision on which ORM to use, has a lot of flaws; but after all, the benefits of the management model, in which technical decisions are made by one person without discussion, snot, saliva and appeals, are also very doubtful.

It often happens that the team has the most experienced “pepper”, which makes all the important architectural (and not so) decisions alone. This situation is useful for this very “pepper” (ČSV, it is ČSV), but it’s not that useful for the whole project, especially if the “pepper” is not eager to ask others for advice.

The first problem is connected with the fact that people slowly develop a habit that the “pepper” is right, while the “pepper” itself has such a habit. As a result, everyone goes with the flow, no one disputes important decisions, because his decisions are trusted. As a result of this attitude, the quality of these decisions falls.

The second problem is that there are a number of decisions that simply cannot be made independently. I personally do not know more than one person to whom I would entrust the design of a corporate library (I would not trust myself to myself alone) (***). The problem is that the concept of reuse, although it has been around for decades, is still one of the most difficult tasks in our field. When designing libraries, which even a dozen people will use, you need to make completely different compromises and make decisions that you would never make when designing a regular application. It ’s simply impossible to do without “corridor testing” , because what you think is simple and clear to use will certainly not be so for a person whose brain is not in your head.

If the team does not have full-fledged number 2, then this will necessarily lead to a decrease in the quality of decisions for a very simple reason. The number one (our “pepper”) stupidly has no one to talk to check our decisions for lice, as a result of which the team can go for a long time in the wrong direction, but since the team is boiling in its juice, it is very difficult to notice.

In addition, an experienced "pepper" can convince the team and make a frankly wrong decision, simply because of their experience. If the interlocutors are in different weight categories, then a more experienced person will have no difficulty in persuading the interlocutor in his point of view, no matter how adequate it is. In any dispute, such as what is better with C ++ or C #, there is a mass of arguments on each side and a more experienced “pepper” can simply call some arguments and hold back others. As a result, a decision will be made in the interests of the “pepper”, and not in the interests of the project.

In most teams, even a review of someone else's code is extremely rare, and there is no reason to talk about a review of a specification, architecture or design. But it is even intuitively clear that the sooner a mistake is found, the cheaper its correction. The very idea that the gaze of a stranger will fall on “my creation” additionally disciplines and improves the quality of the decision.

Finita

Surely there are plenty of other ways that can mitigate the problems described in the previous notes, but it seems to me that although some tips will not get rid of these problems, they can greatly reduce the risk of their occurrence. So, here they are in short form:

1) Pragmatism rules (no need extremes); this advice is applicable always and everywhere, and it also helps to avoid problems, such as “refactoring syndrome” and “second system effect”

2) Do not cut down your decisions in the stone (there are chances that you have ruined somewhere, and then you have to take up the chisel again)

3) Reasonably consult with reasonable colleagues, for looking from the outside is always helpful.

--------------------------------------

(*) Besides the benefits, design patterns can be detrimental. The thoughtless and unreasonable use of any even the most useful tool or technology will lead to "absurdity and corruption." How many times have you encountered the problem of “overengineering”, when a dozen design patterns were used to implement a simple concept? In general, this is another example of the fact that pragmatism and common sense, as always, is the best choice, and design patterns are no exception.

(**) According to John himself, he asked this very question at one of his first meetings. Literally, his question was: “What if Bob dies before we finish the requirements gathering phase?”, Feel free to contact the original: “Debugging Applications. NET 2.0 Applications” , section “The“ Code First, Think Later ” Approach ”.

(***) I'm not talking about the libraries of ala MiscUtils by John Skit . Firstly, his library “grew up” in solving real problems, and secondly, I’m just sure that John made a lot of changes to it based on feedback from colleagues and users. If you want at least a little to learn about the complexities of designing large libraries, look through the Abrams and Qualina “Framework Design Guidelines” , there are a lot of interesting thoughts about this.

Source: https://habr.com/ru/post/123070/


All Articles