Programming: one programming story
Perhaps, this article may not present any new or fresh ideas, besides, I'm sure you have often read something like this somewhere else. This post even does not claim the fact to be true. Its content is the fruit of my own experience, mistakes, and the knowledge that I have gotten from my colleagues. I'm sure that many people will be able to find themselves in my article. Probably, the first stage is not very typical for the programmers who are not involved in the Olympic programming, but the following stages do not independent from this factor at all.
Stage 1. Birth
"I'm a programmer, and I know what a small “o” means. Also, I know what a large "O" is. I understand the difference between "N-squared" from "Factorial N ", and why they both hide from "N-logarithm-N". In addition, I know the algorithm of Knuth-Morris-Pratt! And here you can save one comparison of lines on equality! What if this recursion to nest in a cycle, then by saving method calls and memory allocation in the stack ... What is going on? Does the program get slower? Now, I am going to look at the code...! Look, here, you can use one cycle instead of two nested cycles and binary search instead of the internal".
So this is the first stage. The coder thinks about how to write a quick code. This coder is obsessed with the quick code. Unfortunately, the quick code does not always make the quick software in general.
The coder just rewrote a piece of code that is executed once at the start of the Web server, and that did not affect the overall performance. The coder rewrote a piece of code, which was changed more than 10 times due to some changes in the project. Its algorithm is run in linear time, while the old is run in quadratic. In addition, the old one run a single request to the database, and new one makes that for any iteration. The coder does not know that the web project is run by many users at the same time, and the usage of static data could be fraught with serious consequences ...
The main problem of the coder is that he uses a couple of classes or methods, and he does not quite aware of what is going on around this part of the project. His thinking is limited to the code and algorithm of its work, namely, how the program works, but not what it should do. However, this stage rarely lasts that long, so the coder would not be able to screw up the project. The coder gets aware pretty quickly that something is wrong in this project, and he starts to learn.
Stage 2. Idealism and self-confidence
"I am a developer. Yes, that's right. I'm the software developer, and not a programmer. My task is to develop a product that will work steadily and contain the correct code. The code that I write, at first should work properly, and then it should be quick. The code should be structured and with the comments, perhaps it will be supported by the other developers. Object-oriented programming (OOP) is my main tool, and I can analyze the subject area and allocate the class hierarchy in it. I try to use the templates and the generics whenever it is possible, and also I use declarative programming, because this tool makes the code readable and understandable. I use only new technologies. I spend a lot of time in discussions with my colleagues, what pattern, technology or approach is best suited for the task implementation ... "
This is the second stage. The programmer grew up during the previous stage. Knuth's aphorism that the premature optimization is the root of all evil is understood. Now, the coder does not care about a speed anymore, but the beauty of code.
Giant trees cover the project with the class hierarchies including special attributes, generics, and interfaces. The objects, callback functions, observers, iterators, visitors, controllers, and other members are in the midst of these trees. Somewhere the code is generated in the depths of the forest, which generates another code that generates the code that generates XSLT-template that generates the user interface. This beautiful code has a lot of different comments on how to use it properly, and what it does. The projects that have the non-trivial object-oriented structure cause some delight for the coder. In general, requirement changes are often accompanied by large-scale refactoring, which elevates to another abstract level that uses the new techniques and approaches. After reading the article about defensive programming the coder starts using assertions in all the methods. After learning about caching data in memory, the coder caches all the data in the project. After reading about TDD, the coder writes a bunch of tests for elementary logic prior to writing this logic. The fruit of his work is monumental, and it causes the delight for the colleagues that are on the same stage. The coder truly believes that the language, which he uses, is ideal, and the technology is most modern. Often the coder starts a blog where he writes about how to write the proper code or use a specific framework.
When the coder is faced with the fact, that his product is slow, he uses a profiler and tries to figure out the call tree. Sometimes it works out and the problem is solved ... well, by using one more abstract level with additional caching. Or rather, the part of logic is transferred to the database server in the form of stored procedures.
When approaching the project deadlines, the coder suddenly realizes that a lot of things have not been ready yet, and the time is spent for the constant refactoring and debates about what pattern to choose for that project. The coder sleeps at work in order to turn this project on time, and sometimes he succeeds. However, after the project completion it still must be supported, there are needed some new features for the next version, and here, it turns out that the new functionality is almost impossible to fit into the project monolith without destroying its foundations. As there is no time for the total product destruction and the product is already working, and this bug should have been fixed last Friday, the code begins to grow quick and dirty patches with the comments like “to do: fix this later”.
The coder's problem is that he lost the content of the form. He writes the code as an artist paints a painting with the enthusiasm and admiration, he is in love with this code, and often forgets that the goal of his work is not to write a beautiful code, but write a product that will work quickly and easy to be supported. Also, he often forgets that the software is the product that has to find its buyer, who absolutely does not care of what is the concentration of the patterns on the line in the code. But this user is willing to pay money for the product that will be add a new feature, which no one knew when writing the first version, by the way adding of this feature should not screw up any other features of the project, and this process should take minimum time.
Stage 3. Enlightenment
"It seems I was wrong. No, definitely, I'm wrong. "
The third stage is the awareness of coder that he is in the second stage and the understanding of his own drawbacks and mistakes. Awareness of these things leads to healing.
The class hierarchy rarely exceeds two or three levels of inheritance in the project, and the methods contain no more than a few dozen lines. The code does have the comments, except for the external interfaces that can be worked by third-party developers who do not have access to the code. Surprisingly, the lack of comments will not make the code unreadable, as the correct names of variables and methods, a clear code-convention, and a small amount of code can do real miracles. If the action can be written simply and without the usage of complex design patterns, then it will be written in this way.
Declarative programming is used in places where it does not affect the performance. The code is generated, but only where it saves the developers time. Unit tests cover only a part of the code, but this is the part that may be affected in the event of an error, when making the new functionality or fixing a bug. Before the caching data will be add from the database, the coder has to think carefully about how much it is necessary, as it should not damage the scalability, just as it is in the case of transfer of the logic in the stored procedure code on the database server. The coder understands that buying another server can eventually be cheaper than rewriting and testing of the project. By the way, in places where optimization can provide significant performance gains ... it is not done for some time, but the code is written in such way that if it is necessary, it can easily speed up its execution. The coder understands that each tool is good for a certain class of tasks, and therefore he does not participate in discussions about "dynamic languages vs. static”, ”Java vs. . Net vs. C + + “, etc. The coder tries new languages and technologies for his own projects, but he decides to use them in production code only after careful reviewing of all the "pros" and "cons". Also, the coder is critical to everything new, trying to identify their advantages and disadvantages. He knows several languages and technologies that help him to do any task. If the coder understands that in some cases his own bike can be more effective than existing technologies, he invents and writes his own bike, but only if he can prove himself the necessity of it.
If the bike gives him pleasure by its aesthetics and clever solutions, and it is not contradicting the agreement with the employer, he can post this code under an open-source license or at least in his blog.
Instead of an epilogue
Actually, I have written about a modular spherical image that lives deep in the vacuum of space. This image tells about my friends, colleagues, and their own experience. I hope this post will be very useful for people who are interested in my writing.
Thank you very much!
|Vote for this post
Bring it to the Main Page