Up to date

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

Bonnes pratiques pour les contributeurs au moteur

Introduction

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.

Langage

L'objectif de ce document est d'établir une liste des meilleures pratiques à suivre par les contributeurs, ainsi que de créer un langage qu'ils peuvent utiliser pour se référer aux situations courantes qui surviennent dans le processus de soumission de leurs contributions.

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.

Les contributions sont la plupart du temps classées comme des corrections de bogues, des améliorations ou des nouvelles fonctionnalités. Pour résumer cette idée, nous les appellerons Solutions, car elles cherchent toujours à résoudre quelque chose qui peut être décrit comme un Problème.

Bonnes pratiques

#N°1 : Le problème vient toujours en premier

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 : Pour résoudre le problème, il faut d'abord qu'il existe

Il s'agit d'une variation de la pratique précédente. Ajouter quelque chose d'inutile n'est pas une bonne idée, mais qu'est-ce qui constitue ce qui est nécessaire et ce qui ne l'est pas ?

../../_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.

Coire que des problèmes puissent survenir à l'avenir et que le logiciel doit être prêt à les résoudre au moment où ils apparaissent est appelée "Future proofing " et se caractérise par des lignes de pensée telles que :

  • Je pense qu'il serait utile pour les utilisateurs de...

  • Je pense que les utilisateurs finiront par avoir besoin de ...

Ceci est généralement considéré comme une mauvaise habitude, car essayer de résoudre des problèmes qui n'existent pas réellement dans le présent conduira très souvent à du code qui sera écrit mais jamais utilisé, ou à un code qui est considérablement plus complexe à utiliser et à maintenir qu’il n’a besoin d’être.

#N°3 : Le problème doit être complexe ou fréquent

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:

  • La complexité du problème

  • La fréquence du problème

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.

#N°4 : La solution doit être discutée avec d'autres

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.

De plus, la philosophie de Godot est de privilégier la facilité d'utilisation et de maintenance plutôt que la performance absolue. Les optimisations de performance seront envisagées, mais elles peuvent ne pas être acceptées si elles rendent quelque chose trop difficile à utiliser ou si elles ajoutent trop de complexité au code.

#N°5 : A chaque problème sa solution

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.

La situation va souvent s'aggraver lorsque, pour rendre cette solution encore plus fantastique et flexible, les problèmes purement spéculatifs (comme décrit au point 2) font également leur apparition sur scène.

../../_images/best_practices5.png

Le principal problème est, qu'en réalité, cela fonctionne rarement de cette manière. La plupart du temps, écrire une solution individuelle à chaque problème permet d'obtenir un code plus simple et plus facile à maintenir.

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.

#N°6 : Répondre aux cas d'usage courant, laisser la porte ouverte aux cas rares

Il s'agit de la suite du point précédent, qui explique davantage pourquoi cette façon de penser et de concevoir les logiciels est préférée.

Comme mentionné précédemment (au point 2), il est très difficile pour nous (en tant qu'êtres humains qui conçoivent des logiciels) de comprendre réellement tous les besoins futurs des utilisateurs. Essayer d'écrire des structures très flexibles qui répondent à de nombreux cas d'utilisation à la fois est souvent une erreur.

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

La réponse à cette question est que, pour garantir que les utilisateurs puissent toujours faire ce qu'ils veulent, nous devons leur donner accès à une API de bas niveau qu'ils peuvent utiliser pour obtenir ce qu'ils veulent, même si cela représente plus de travail pour eux car cela signifie qu'il faut réimplémenter une certaine logique qui existe déjà.

Dans les scénarios de la vie réelle, ces cas d'utilisation seront tout au plus rares et peu fréquents de toute façon, il est donc logique qu'une solution personnalisée soit rédigée. C'est pourquoi il est important de continuer à fournir aux utilisateurs les éléments de base pour le faire.

#7 : Préférer les solutions locales

Lorsque l'on cherche une solution à un problème, qu'il s'agisse de mettre en œuvre une nouvelle fonctionnalité ou de corriger un bogue, la voie la plus simple consiste parfois à ajouter des données ou une nouvelle fonction dans les couches de code principales.

Le principal problème ici est que l'ajout aux couches centrales de quelque chose qui ne sera utilisé qu'à partir d'un seul endroit éloigné rendra non seulement le code plus difficile à suivre (divisé en deux), mais aussi l'API centrale plus grande, plus complexe, plus difficile à comprendre en général.

C'est une mauvaise chose, parce que la lisibilité et la propreté des API de base sont toujours d'une extrême importance étant donné la quantité de code qui en dépend, et parce que c'est un point de départ essentiel pour les nouveaux contributeurs dans l'apprentissage de la base de code.

../../_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.

#N°8 : Ne pas utiliser de solutions complexes pour des problèmes simples

Tous les problèmes n'ont pas une solution simple et, bien souvent, le bon choix est de faire appel à une bibliothèque tierce pour résoudre le problème.

Comme Godot doit être livré sur un grand nombre de plates-formes, nous ne pouvons tout simplement pas relier les bibliothèques de manière dynamique. Au lieu de cela, nous les regroupons dans notre arbre des sources.

../../_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.