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 certains puissent trouver utile d'étendre cela au développement de logiciels en général, 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

De nombreux contributeurs sont extrêmement créatifs et apprécient simplement le processus de conception de structures de données abstraites, la création d'interfaces utilisateur agréables ou aiment tout simplement la programmation. Quel que soit le cas, ils proposent des idées intéressantes, qui ne résoudront peut-être pas des problèmes réels.

../../_images/best_practices1.png

Celles-ci sont généralement appelées Solutions à la recherche d'un problème. Dans un monde idéal, ils ne seraient pas nocifs mais, en réalité, le code prend du temps à écrire, prend de l'espace comme source et binaire et nécessite une maintenance une fois qu'il existe. Éviter l'ajout de tout élément inutile est toujours considéré comme une bonne pratique dans le développement de logiciels.

#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

La réponse à cette question est que le problème doit exister avant de pouvoir être réellement résolu. Il ne doit pas être une spéculation ou une croyance. L'utilisateur doit utiliser le logiciel comme prévu pour créer quelque chose dont il a besoin. Dans ce processus, l'utilisateur peut tomber sur un problème qui nécessite une solution pour continuer ou pour atteindre une plus grande productivité. Dans ce cas, une solution est nécessaire.

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

Les logiciels sont conçus pour résoudre des problèmes, mais on ne peut pas s'attendre à ce qu'ils résolvent tous les problèmes qui existent sous le soleil. En tant que moteur de jeu, Godot résoudra les problèmes pour vous, donc il vous aide à rendre les jeux meilleurs et plus rapides, mais il ne fera pas le tout le jeu pour vous. Une limite doit être tracée quelque part.

../../_images/best_practices3.png

Le fait qu'un problème mérite d'être résolu est déterminé par la difficulté qu'a l'utilisateur à le contourner. Cette difficulté peut être exprimée sous la forme :

  • La complexité du problème

  • La fréquence du problème

Si le problème est trop complexe pour la plupart des utilisateurs, le logiciel doit offrir une solution toute faite pour le résoudre. De même, si le problème est facile à contourner pour l'utilisateur, il est inutile de proposer une telle solution et c'est à l'utilisateur de le faire.

L'exception, cependant, est lorsque l'utilisateur se heurte à ce problème suffisamment souvent pour que le fait d'avoir à faire chaque fois la solution simple devienne une gêne. Dans ce cas, le logiciel doit proposer une solution pour simplifier ce cas d'utilisation.

Selon notre expérience, dans la plupart des cas, il est généralement évident de dire quand un problème est complexe ou fréquent, mais il peut y avoir des cas où il est difficile de tracer cette ligne. C'est pourquoi il est toujours conseillé de discuter avec d'autres développeurs (point suivant).

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

Il arrive souvent que lorsque les utilisateurs tombent sur des problèmes, ils ne sont qu'immergés dans leur propre projet, de sorte qu'ils tentent naturellement de résoudre le problème de leur propre point de vue, en ne pensant qu'à leur cas d'utilisation.

C'est pourquoi les solutions proposées par les utilisateurs ne tiennent pas toujours compte des autres cas d'utilisation dont les développeurs sont souvent conscients, et sont donc souvent biaisées en fonction de leurs propres exigences.

../../_images/best_practices4.png

Pour les développeurs, la perspective est différente. Ils peuvent trouver le problème de l'utilisateur trop unique pour justifier une solution (au lieu d'un contournement par l'utilisateur), ou bien ils suggéreront une solution partielle (généralement plus simple ou de niveau inférieur) qui s'applique à un plus large éventail de problèmes connus, et laisseront le reste de la solution à l'utilisateur.

Dans tous les cas, avant de tenter une contribution, il est important de discuter des problèmes réels avec les autres développeurs ou contributeurs, afin de parvenir à un meilleur accord sur la mise en œuvre.

La seule exception, dans ce cas, est lorsqu'un domaine de code a un propriétaire clair (accepté par les autres contributeurs), qui parle directement aux utilisateurs et qui a le plus de connaissances pour mettre en œuvre une solution directement.

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

Pour les programmeurs, c'est toujours un défi très agréable de trouver les solutions les plus optimales aux problèmes. Cependant, il arrive que les choses débordent et que les programmeurs tentent de trouver des solutions qui résolvent le plus grand nombre possible de problèmes.

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.

En outre, les solutions qui ciblent des problèmes individuels sont meilleures pour les utilisateurs, car ils trouvent quelque chose qui fait exactement ce dont ils ont besoin, sans avoir à apprendre et à se souvenir d'un système plus complexe dont ils n'auront besoin que pour des tâches simples.

Les solutions de grande taille et flexibles présentent également un inconvénient supplémentaire, au fil du temps, elles sont rarement assez souples pour tous les utilisateurs, qui demandent sans cesse l'ajout de nouvelles fonctions (et rendent l'API et la base de code de plus en plus complexes).

#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.

Nous pouvons trouver quelque chose que nous pensons être brillant, mais lorsqu'il est réellement utilisé, nous constatons que les utilisateurs n'en utiliseront même pas la moitié, ou qu'ils auront besoin de fonctionnalités qui ne correspondent pas tout à fait à notre conception originale, ce qui nous oblige à le jeter ou à le rendre encore plus complexe.

La question est donc de savoir comment concevoir un logiciel qui donne aux utilisateurs ce dont nous savons qu'ils ont besoin, mais qui est suffisamment souple pour leur permettre de faire ce dont nous ne savons pas qu'ils pourraient avoir besoin à l'avenir ?

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

Le raisonnement courant pour vouloir faire cela est qu'il y a généralement moins de code à ajouter simplement un hack dans les couches centrales.

Malgré cela, cette pratique n'est pas conseillée. En général, le code d'une solution doit être plus proche de l'origine du problème, même s'il implique plus de code, s'il est dupliqué, plus complexe ou moins efficace. Plus de créativité peut être nécessaire, mais cette voie est toujours conseillée.

#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

Par conséquent, nous sommes très pointilleux sur ce qui entre et nous avons tendance à préférer les petites bibliothèques (en fait, celles à en-tête unique sont nos préférées). Ce n'est que dans les cas où il n'y a pas d'autre choix que nous finissons par regrouper quelque chose de plus grand.

De plus, les bibliothèques doivent utiliser une licence suffisamment permissive pour être incluses dans Godot. Quelques exemples de licences acceptables sont Apache 2.0, BSD, MIT, ISC et MPL 2.0. En particulier, nous ne pouvons pas accepter les bibliothèques sous licence GPL ou LGPL car ces licences interdisent effectivement les liens statiques dans les logiciels propriétaires (forme sous laquelle Godot est distribué comme dans la plupart des projets exportés). Cette exigence s'applique également à l'éditeur, puisque nous pourrions vouloir l'exécuter sur iOS à long terme. Comme iOS ne supporte pas les liens dynamiques, les liens statiques sont la seule option sur cette plate-forme.