KISS principle in development

    The next report with Pixonic DevGAMM Talks, which we have deciphered, is a bit philosophical - this is a speech by Konstantin Gladyshev. He was a Lead Game Programmer at 1C Game Studios and talked about the principle of managing development complexity in the context of the entire product, rather than individual features. And he showed with examples why the most important thing in development is to determine what is not to be done. For other reports, you can read the links at the end of the article.

    I wanted to tell you about the north, but decided to make a philosophical report on what should be done easier. I worked on Postal III, Indestructible, War Robots and now I am doing Caliber - a session online shooter from 1C and Wargaming.

    Why did we decide to talk about KISS (Keep it simple, stupid)? Because even seniors with 20 years of experience or CTO often continue to sculpt and invent something. And you need to make it easier. In fact, there is more about YAGNI (You ain't gonna need it) and a bit of philosophy.

    Immediately, I note that we are not talking about completely idiotic solutions, such as “find x”, we are talking about more or less simple solutions.

    Why is it sometimes too difficult? It all begins with good intentions, and they, as you know, lead to hell. Here is a comic about this.

    The reasons for this are about the same, but I called them differently:

    • Universal solutions . There is some kind of feature and we immediately make a library out of it, a million extra cases. And then suddenly our shooter will turn into a farm? Or "I will do another exact same shooter next time." It is unlikely, most likely it will change with you.
    • Future proof . Practically the same is non-existent problems. “And if I have a million users at once, do I need to endure 22 intermediate servers?” Etc. To start earning, one server is enough for everything.
    • Using the wrong tools . When you use tools that do not fit and persist in their delusion.
    • And the well-known premature optimization .

    We had an example when Caliber was made. The guys who helped us then decided to immediately make a super-serializer in the last C ++.

    In the end, he did not work as he wanted, it was inconvenient to send a partial state, because the templates do not really understand where it is necessary and where it is not, or you make some flags. Over time, even the author did not understand the bugs that were in this template code.

    Then one of the programmers literally in two hours rewrote all this stuff into one page of C code, which did only what we needed right then. And it worked wonderfully.

    Another example. We had Postal III and it was made on the Source engine. There is such an open world, you can walk between the cards, a third-person camera, many one-story American-style houses with windows, bots can run around and open doors in panic. As a result, the whole BSP did not work. It was considered for a very long time, a million sectors were obtained from the windows and still did not do anything. It took a lot of memory and was loaded for a long time.

    Half-Life, for which the engine was made, is a first-person shooter, and from the third it was inconvenient to do some things. All useful from Half-Life did not suit us at all. It was also assumed a large number of animation, because from the third person you need to climb, etc. It was necessary to change the engine, but then there was no option.

    What to do when everything is bad, difficult, and we are driven? First, doing the features in the right order, because optimizing ahead of time is one of the problems. Some begin to paste straziki before they sew a dress, and then they can not sew, because straziki interfere.

    First, make the simplest piece so that it just works, then stabilize it, and then optimize it. In that order, everything else is wrong.

    By visualization, we mean that it is minimally working, i.e. MVP (minimum viable product).

    Further you estimate its potential. Let's say game designers come up with features, the programmer resorts and says “I will do well, I won't do it badly, so draw the fun game design right away”. But how does he know? He did not play, does not know whether this is good or bad. Therefore, ideally, you make a feature, play, if it is normal, then you do it further. Not normal - thrown out, not sorry.

    A thousand years ago, Sun Tzu said that to win in 100 battles is not the top, the top is to win without a battle. Those. Do not do what you can not do.

    Stabilization. You made the features and then stabilize it without any extras. Need a wheel on a tree, on a rope? It hangs. Nothing else.

    Accordingly, if you suddenly discovered (without any future proof) that the feature should change - start over. Just make a prototype, stabilize, and not try to guess ahead. Still not guess.

    Well, premature optimization. It is always bad. You need to optimize at the very end, when you know for sure that this feature is important, it should be optimized and it will not fundamentally change in the near future.

    Because optimization is a set of special cases. The readability of the code is deteriorating, abstractions are broken, and portability, as a rule, is also deteriorating.

    This is a provocative slide, because in fact crutches are bad. But here a situation is shown, when there is a bunch of dull features and prototypes, everything is bad, and it seems that everything will collapse. But it is not. Look - it is a formwork, concrete is poured into it, and the “crutches” are supported while it is drying. Those. the situation is absolutely normal, the “crutches” are then removed, but not immediately, without panic.

    Briefly about philosophy. There are no universally correct solutions. Do not try to make the framework 100 years ahead or for all occasions.

    Better make a lot of small pieces that do their job well. Throw out unnecessary as soon as possible, do not try to do this. And when writing code, make it explicit. Sometimes it's better to write explicit code that you serialize with your hands, instead of reflex or something else. Using the dependency action when you don't need it is also a bad idea. It is very hard to read, half the errors in runtime. Explicit is better than implicit. And make it as simple as possible to avoid mistakes when someone did not understand something or forgot it altogether.

    As Bruce Lee said, simplicity is the highest degree of art. One day, the actor he taught to his Jeet Kune-Do asked him: “What is the essence of your martial art Jeet Kune-Do?”. At this point, Bruce Lee dropped the wallet, the actor picked up and Bruce Lee said: "You see, you just bent down and picked up the wallet, and if you stood in the rider's position, you made katy - you would never have picked it up."

    Questions from the audience

    - You said that premature optimization is evil. Is it worth writing premature tests when the project is just beginning?

    - In my understanding, in general, all premature is harmful. In tests, I'm not very strong, because in game devs (in many cases) tests are closer to the end of development. At first, everything is changing so quickly that while you write a test, the game designer will change everything. I believe that it is bad to spend energy on the test of what will change in two hours. This should be done at the stage of stabilization. But not at the prototype stage. But if a team can write tests quickly, this is probably good. If not, then no.

    - You mentioned that the crutches will be removed, but there is a wonderful thesis - there is nothing more permanent than temporary. We all work in game devs, we have terms, producers, then a new feature, and so on. How often have you seen a situation when you cleaned out crutches? And whether they removed them to zero?

    - At zero, probably not. If the project is alive, you will always have some crutches. It all works if they are cleaned systematically. Those. you made a feature - immediately fixed.

    - Ie Should a process be built in a company? Type of crutches official cleaning phase?

    - Yes, I think that this should be included in the task. Those. if you need to refactor in the process of task, you will refactor. Roughly speaking, even the word refactoring is not - it is inside the task.

    - Is it possible to do this in practice? You come to the producer and speak on the planning of a new iteration, that we need two weeks to clean up, refactor, etc. And he says that business value is zero, now we are doing feature x, and this you will clean later one night after work. How to be in this situation?

    - We succeed. The producer is aware that there are some debts that you correct, but in a timely manner. Not that you have a new release, there is not a single new feature in it, but here is some kind of refactoring. Just choose the right producer.

    - With experience comes understanding, the simpler - the better. But novice programmers are trying to create complex, scary, large and giant systems. Question: how to keep them from this, except for a hard "no"?

    - I think this is a learning problem. It is necessary to show as soon as possible which solutions work, which do not, and why. When you have experience and you can explain why it is not necessary to do this, you can just give a lot of examples and it works well. Show your example and constantly make sure that everything is simple. Plant on prototypes so that they rewrite more often - when you rewrite often, you don’t feel like writing a lot and they write easier and easier.

    - If there is already something very complicated that is used on several projects, and this complexity no longer helps, but rather prevents - how is it easier to proceed to simple solutions?

    - My opinion, just start doing it again. Ideally, a separate team, straight from scratch. You will most likely recover 80% of the functionality very quickly. On a new and clean library. And then you will catch up.

    - For example, there is some kind of powerful serializer and game logic editor, so it’s rather outdated ...

    - These are the most inconvenient tools. Take comfortable. Unity, for example.

    - Tell me, what is your planning in the code, how detailed is it? The main programmer solves all small questions, all problems?

    - We have such anarchy, a fairly flat structure, not very many people. We trust everyone and simply distribute who will take the prototype and who will not. This can be any arbitrary person.

    More reports from Pixonic DevGAMM Talks

    Also popular now: