Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Правила и рекомендации для разработчиков движка

Введение

Godot has a large amount of users who have the ability to contribute because the project itself is aimed mainly at users who can code. That being said, not all of them have the same level of experience working in large projects or in software engineering, which can lead to common misunderstandings and bad practices during the process of contributing code to the project.

Язык

Сфера применения данного документа - это список лучших практик, которым должны следовать участники, а также создание языка, который они смогут использовать для обозначения общих ситуаций, возникающих в процессе представления их вкладов.

While a generalized list of software development best practices might be useful, we'll focus on the situations that are most common in our project.

Доработки, в большинстве своём, можно классифицировать как: исправления ошибок (багфиксы), улучшения (доработки) или добавление новых функций. Чтобы абстрагироваться от этой классификации мы будем называть все доработки Решениями, потому что они всегда нацелены на решение чего-то определённого, того, что можно назвать Проблемой.

Правила работы

#1: Сначала проблема

Many contributors are extremely creative and just enjoy the process of designing abstract data structures, creating nice user interfaces, or simply love programming. Whatever the case may be, they come up with cool ideas, which may or may not solve real problems.

../../_images/best_practices1.png

These are usually called solutions in search of a problem. In an ideal world, they would not be harmful but, in reality, code takes time to write, takes up space and requires maintenance once it exists. Avoiding the addition of anything unnecessary is always considered a good practice in software development.

#2: Чтобы решить проблему, сначала убедитесь в её существовании

Это вариация предыдущего пункта. Добавление чего-то необязательного это плохая идея, но что значит "обязательный" и что таковым не является?

../../_images/best_practices2.png

The answer to this question is that the problem needs to exist before it can be actually solved. It must not be speculation or a belief. The user must be using the software as intended to create something they need. In this process, the user may stumble upon a problem that requires a solution to proceed, or in order to achieve greater productivity. In this case, a solution is needed.

Подход к разработке основанный на вере в то, что проблемы могут возникнуть в любой момент и программа должна быть готова их решить к тому моменту когда они появятся - называется "Разработкой на перспективу" и характеризуется такими идеями как:

  • Я думаю, в будущем, пользователям может быть полезно...

  • Думаю, пользователям в конечном итоге понадобится...

Как правило, это считается плохой привычкой, потому что попытка решить проблемы которых на самом деле не существует в настоящем, с большой вероятностью приведёт к тому что написанный код никогда не будет использован в будущем, или к тому что его поддержка и использование окажутся гораздо сложнее, чем предполагалось.

#3: Проблема должна быть сложной или частой

Software is designed to solve problems, but we can't expect it to solve every problem that exists under the sun. As a game engine, Godot will help you make games better and faster, but it won't make an entire game for you. A line must be drawn somewhere.

../../_images/best_practices3.png

Whether a problem is worth solving is determined by the effort that is required to work around it. The required effort depends on:

  • Сложность проблемы

  • Частота возникновения проблемы

If the problem is too complex for most users to solve, then the software should offer a ready-made solution for it. Likewise, if the problem is easy for the user to work around, offering such a solution is unnecessary.

The exception, however, is when the user encounters a problem frequently enough that having to do the simple solution every time becomes an annoyance. In this case, the software should offer a solution to simplify the use case.

It's usually easy to tell if a problem is complex or frequent, but it can be difficult. This is why discussing with other developers (next point) is always advised.

#4: Решение должно быть обсуждено с другими

Often, users will be immersed in their own projects when they stumble upon problems. These users will naturally try to solve the problem from their perspective, thinking only about their own use case. As a result, user proposed solutions don't always contemplate all use cases and are often biased towards the user's own requirements.

../../_images/best_practices4.png

For developers, the perspective is different. They may find the user's problem too unique to justify a solution (instead of a workaround), or they might suggest a partial (usually simpler or lower level) solution that applies to a wider range of known problems and leave the rest of the solution up to the user.

In any case, before attempting to contribute, it is important to discuss the actual problems with the other developers or contributors, so a better agreement on implementation can be reached.

The only exception is when an area of code has a clear agreed upon owner, who talks to users directly and has the most knowledge to implement a solution directly.

Кроме того, философия Godot заключается в предпочтении простоты использования и обслуживания над абсолютной производительностью. Оптимизация производительности будет рассмотрена, но она может быть не принята, если она сделает что-то слишком сложным в использовании или если она добавит слишком много сложности в кодовую базу.

#5: Каждой проблеме - своё решение

For programmers, it is always a most enjoyable challenge to find the most optimal solutions to problems. It is possible to go overboard, though. Sometimes, contributors will try to come up with solutions that solve as many problems as possible.

Ситуация часто меняется к худшему, когда для того, чтобы это решение выглядело еще более фантастическим и гибким, на сцену выходят проблемы, основанные на чистой спекуляции (как описано в #2).

../../_images/best_practices5.png

Основная проблема заключается в том, что в реальности так получается редко. В большинстве случаев написание индивидуального решения для каждой проблемы приводит к тому, что код становится более простым и удобным для сопровождения.

Additionally, solutions that target individual problems are better for the users. Targeted solutions allow users find something that does exactly what they need, without having to learn a more complex system they will only need for simple tasks.

Big and flexible solutions also have an additional drawback which is that, over time, they are rarely flexible enough for all users. Users end up requesting more and more functionality which ends up making the API and codebase more and more complex.

#6: Удовлетворяйте общие потребности, оставляйте дверь открытой для редких случаев использования

Это продолжение предыдущего пункта, которое объясняет, почему такой способ мышления и проектирования программного обеспечения является предпочтительным.

Как уже упоминалось ранее (в пункте #2), нам (людям, разрабатывающим программное обеспечение) очень сложно понять все будущие потребности пользователей. Попытка написать очень гибкие структуры, которые удовлетворяют сразу множество вариантов использования, часто является ошибкой.

We may come up with something we believe is brilliant but later find out that users will never even use half of it or that they require features that don't quite fit into our original design, forcing us to either throw it away or make it even more complex.

The question is then, how do we design software that both allows users to do what we know they need to do now and allows them to do what we don't yet know they'll need to do in the future?

../../_images/best_practices6.png

Ответ на этот вопрос заключается в том, что для того, чтобы пользователи по-прежнему могли делать то, что они хотят, мы должны предоставить им доступ к API низкого уровня, который они могут использовать для достижения желаемого, даже если это потребует от них больше работы, поскольку это означает повторную реализацию некоторой логики, которая уже существует.

В реальных сценариях такие случаи использования в любом случае будут редкими и нечасто встречающимися, поэтому имеет смысл написать индивидуальное решение. Вот почему важно предоставить пользователям основные строительные блоки для этого.

#7: Предпочитайте локальные решения

При поиске решения проблемы, будь то внедрение новой функции или исправление ошибки, иногда самый простой путь - добавить данные или новую функцию в основные слои кода.

Основная проблема здесь заключается в том, что добавление в основные слои чего-то, что будет использоваться только из одного места на большом расстоянии, не только сделает код более сложным для следования (разделение на две части), но и сделает основной API больше, сложнее, труднее для понимания в целом.

Это плохо, потому что читабельность и чистота основных API всегда чрезвычайно важна, учитывая, как много кода зависит от них, и потому что это ключевой момент для новых участников, как отправная точка для изучения кодовой базы.

../../_images/best_practices7.png

A common reason for wanting to do this is that it's usually less code to simply add a hack in the core layers.

Doing so is not advised. Generally, the code for a solution should be closer to where the problem originates, even if it involves additional, duplicated, more complex, or less efficient code. More creativity might be needed, but this path is always the advised one.

#8: Не используйте сложные готовые решения для простых проблем

Не каждая проблема имеет простое решение, и во многих случаях правильным выбором будет использование сторонней библиотеки для решения проблемы.

Поскольку Godot должен поставляться на большое количество платформ, мы не можем компоновать библиотеки динамически. Вместо этого мы связываем их в дерево исходных текстов.

../../_images/best_practices8.png

As a result, we are very picky with what goes in, and we tend to prefer smaller libraries (single header ones are our favorite). We will only bundle something larger if there is no other choice.

Libraries must use a permissive enough license to be included into Godot. Some examples of acceptable licenses are Apache 2.0, BSD, MIT, ISC, and MPL 2.0. In particular, we cannot accept libraries licensed under the GPL or LGPL since these licenses effectively disallow static linking in proprietary software (which Godot is distributed as in most exported projects). This requirement also applies to the editor, since we may want to run it on iOS in the long term. Since iOS doesn't support dynamic linking, static linking is the only option on that platform.