Difficulty in the work of a programmer



Today I want to speculate about the complexity surrounding us (people) and about our ability to work with it. Not about the complexity that they write about in the statuses of marital status in social networks, like “everything is complicated”, but about the complexity in organizational and technical systems (by the way, in my opinion, it turned out a good name for a university specialty). I don’t pretend to be original and, moreover, I don’t pretend to be true (especially since, at least half, I’m here going to demean, tinker and fool around). Some of this reasoning I have already made somewhere in the comments, but for me this question is not closed. Therefore, life always throws me various illustrative examples that encourage me to think further. Despite Friday, it was not meant to be entertaining reading, there will be no funny pictures, if anything - I warned you. If you only want to read one sentence,and go to read the rest of the fun Friday articles - here it is: "Simplify complexity where it can be done, deal with complexity where it cannot be simplified, and gain experience and the ability to distinguish the first case from the second." Fits like a Friday toast.



A few quotes from the greats:



To understand is to simplify.



To simplify is not to understand.



Simplicity requires design and good taste.



Keep it as simple as possible, but not simpler.




Complexity is everywhere around us. We use sophisticated technical devices, we honor a complex criminal code, inside us a complex immune system fights the coronavirus, the simplest single-celled living beings carry amazingly complex organelles, Newton's simplest law turns out to be a simplification of a much more complex law at non-relativistic speeds, and about the complexity of the Standard Models and all sorts of different quantum mechanics, I generally keep quiet.



Complexity is always a certain order, a certain system of interacting elements, and in full accordance with the definition of this basic concept, complexity grows when the number of elements increases and when the number and variety of connections between these elements grows. Perhaps complexity is synonymous with order, the antithesis for chaos?

Life in general is a spontaneous increase in complexity inside us due to a decrease in complexity outside, as it should be for any decent dissipative system. At the same time, energy is redistributed so that to increase the complexity, some of it needs to be spent, but the resulting organization, the resulting order, gives "access" to large amounts of energy. This is, I think, the evolutionary reason for the "spontaneous" increase in the complexity of life.



Complex systems around us, the complexity of the organization of matter and energy around, which one wants to dissipate, lead to an increase in the complexity of the consumer, and further along the chain. A flower in which you can get to the nectar only with the help of a long trunk causes the pumping of the lips with silicone complication, lengthening and specialization of the trunk in those butterflies who decided on such a design solution.



We are programmers, we create software systems that, like that butterfly's trunk, must be tricky to automate solutions similar to tricky complex processes in life.



We are programmers, we create complexsoftware systems, and no matter what they say, we like to create this complexity, but there is one nuance that distinguishes us from the creators of any other complex technical systems.



The creator of a complex material and technical device is limited by strength, friction and other materials that slightly muffle the flight of his imagination. The friction force of the programmer does not care or limit (unless he is the developer of the world's best hydraulic fracturing simulator ), the strength and weight of the device, too, and from here, in my opinion, the main problem arises.



And it lies in the fact that it is too easy for us programmers to create complexity. It's too easy for us. Ctrl + C and Ctrl + V, a new function, a new module, a new library, a new abstraction layer, macros-shmakros, preprocessors-postprocessors, adapters, converters and facades - all this will work, you just have to add more frequency and RAM, and no no friction reducer needed. In the created physical world, everything is not so simple. Where in industrial production are analogues not only of genetic programming, but even of simple Lisp macros?



Again. It is too easy in programming to add complexity, and too difficult in programming to reduce complexity. In addition, no one ever likes those who reduce complexity in programming, because they always break everything during refactoring.



I am not saying that complex code is a bad thing. The code automates a real life task, it reflects it in its data models, the code cannot be simpler than life. The complexity of the code grows with the complexity of the problem, but an illiterate developer adds much more complexity to the code than the complexity of the problem.



A competent developer restrains himself from introducing complexity into the code. No wonder the greats said that since debugging is more difficult than writing code, you will not be able to debug the code that you wrote at the limit of the complexity available to you. But I would also say that a competent developer does not create solutions more difficult than 84% of their ability to cope with complexity.



The inability to design future unpredictable changes in the requirements of life leads to the fact that the code has to be rewritten and reworked. Hello, I am your Cap. But you can't rewrite complex software systems from scratch just because you don't like them for their complexity.



Complexity and confusion are two different things. As I always say to students who brought someone else's lab and are sure that they understood it (recently, two frames even said that they thought they should learn to explain someone else's code, and not write their own - explain, Karl, not even edit and develop! ), it is impossible to understand that you do not understand something if you do not understand it. On this side of the inductive threshold, the situation “I think I understood” is indistinguishable from the situation “I really understood”.



If someone comes to you and says: "It's too difficult for you here, we will write from scratch" - you must not let him in to write, you must first demonstrate that he can refactor the old system. If you cannot cope with the complexity that you already have, by the method of gradual refactoring, then when you start writing yourself, you will twist the complexity even worse and in the end you will not solve the problem. And why? Because it is impossible to understand what exactly you do not understand and underestimate, by definition.



Exaggerating: even inventing the right bicycle won't work the first time. The first bike will be curved and oblique, with three gears connected in pairs, as in the classic pictures of girls designers. But it will take you up to the level of difficulty you need to work with when building it, and the second bike will already come out sensible. They write their own class of strings not in order to learn the syntax, but in order to get a life-giving portion of complexity.



The complexity of one and the same piece of code, of the same solution, very much depends on how complex it is already in the system, and the complexity of the system is not the sum of the complexities of the subsystems. And this is part of the problem when working with a customer or any other outside observer. You have probably heard many times: "It's easy to do, it's just {action X} {inside system Y}, there it already exists {inside system Z}!". This is the result of underestimating the systemic complexity, when a person believes that if something is easy to do separately from everything else, then it is easy to do it inside a ready-made large system. If the program needs to implement A, B, C, D, E and F, and they are all approximately the same in complexity, then it would be a strong underestimation to think that they will be built in the same time.



The main thing for an experienced programmer is the ability to manage complexity. Usually we just add complexity (you can't just refactor), but woe to someone who doesn't get to refactoring (in fact, simplification!). Then, instead of putting things in order and simplifying, such a developer winds crutches on crutches and cannot stop, because crutches are easier to write. Over time, it becomes more and more difficult to write crutches, but the trick is that at each moment of time it is more and more difficult to write another crutch, but it is still always easier than clearing the stables and putting things in order. And there is always this illusion that due to deadlines, the optimal solution is to write crutches. Alas, this is the optimal solution at the moment, but very sub-optimal in the long run. Greedy programming.



The ability to cope with complexity, anticipate the consequences and see relationships outside the object in question is in itself a great professional value, this is how programmers get into managers and bosses. In a sense, predicting the behavior of a complex system, anticipating the consequences of new emerging systemic connections, "mental debugging" and "testing for extreme cases", "what will this lead to", as a professional skill of programmers, encourages their growth into managers, along with general skills of abstraction, induction and deduction. True, reflection and introspection, introversion, like a number of other professional skills of programmers, on the contrary, limits them in this growth.



How do you learn to deal with complexity? I have no recipe other than advice to learn to see what works for this skill and what works against it. But in any case, I think it all starts with the most basic education. Studies. Repetition is the mother of learning. I am a teacher, I have a professional deformation: to repeat the same thing twice. I am a teacher, I have a professional deformation: to repeat the same thing twice. I train shallow natural neural networks that do not suffer from overfitting , and all neural networks need to be sampled several times. Repetition is also a way to deal with complexity, it is with repetition that the mental model of reality is refactored, and nothing else.



There are often many complaints about teaching in general and teaching at school and university in particular about the fact that teaching is being done to something irrelevant, the brains are stuffed with unnecessary knowledge and skills. My daughter had such hollow cubes with holes of different geometries, and only smaller figures of the corresponding shape fell inside. Is there anyone who thinks that a child who is taught to pick a key of the desired geometric shape will need the skills of a bugbear in adulthood?



I think that a very serious part of education, and right from scratch to the defense of the first dissertation, is training the brain to cope with complexity. When a child at school learns to multiply three-digit numbers in a column on a piece of paper, no one in their right mind will think that this skill will be useful to him in life. Correctly multiplying two three-digit numbers in a column is an exercise in the ability to strain the brain, keep a couple of numbers in mind, and not lose concentration for a given period of time. First add in a column, then multiply, then divide. By increasing complexity. The ability to strain, the ability to work.



Is this the right quality? It depends on who you want to create! If it is a "qualified consumer", then it is unnecessary. If "a creator man", then, I think, is necessary. In life, the ability to multiply in a column is not useful, in life it is useful to be able to multiply the same numbers on the phone, if you need an exact answer - and the ability to leave only 1 significant digit from each number in your mind without a phone and estimate the order of the resulting value. And this, by the way, is also nothing more than the ability to work with complexity: quickly make decisions on complex data, simplifying the input data and using rough estimates. But if someone believes that in his work he will not need to concentrate and without mistakes perform some similar routine operations, then most likely he is not going to work with his head in this life.



Concluding this, of course, a poorly ordered stream of thoughts, I just want to repeat once again the appeal made in the very first paragraph. Learn to simplify complexity where it can be done, learn to deal with complexity where it cannot be simplified, and develop experience and the ability to distinguish the former from the latter.



All Articles