Bonnes pratiques pour les contributeurs au moteur
Introduction
Godot a un grand nombre d'utilisateurs qui ont la capacité de contribuer, étant donné que le projet lui-même est principalement destiné aux utilisateurs ayant la capacité de faire de la programmation. Malgré cela, ils n'ont pas tous le même niveau d'expérience dans les grands projets ou dans le génie logiciel, ce qui peut entraîner des malentendus et des mauvaises pratiques au cours du processus de contribution au code du projet.
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.
Bien que qu'une liste généralisée des bonnes pratiques de développement logiciel peut être utile, notre intention est de nous limiter aux situations les plus courantes dans notre projet.
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.
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 ?
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.
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.
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.
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?
The answer to this question is that, to ensure users still can do what they want to do, we need to give them access to a low-level API that they can use to achieve what they want, even if it's more work for them because it means reimplementing some logic that already exists.
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.
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
Not every problem has a simple solution and, many times, the right choice is to use a third-party library to solve the problem.
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.
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.