Plateforme Eclipse
Règles d'engagement des API
Version 0.15 - Dernière révision : 12:00, 30 mai 2001
Les règles d'engagement énoncées ci-après concernent les clients des API de la plateforme Eclipse (et d'autres composants).
Qu'est-ce qu'une API ?
La plateforme Eclipse définit les éléments d'une API destinés à être utilisés par ses clients, à savoir les fournisseurs indépendants de logiciels qui écrivent des plug-in. Ces plug-in peuvent en retour définir des éléments d'API pour leurs clients, et ainsi de suite. Les éléments d'API sont le côté public : ils portent une spécification sur ce qu'ils sont supposés faire et comment ils doivent être utilisés. Les éléments d'API sont supportés : l'équipe responsable de la plateforme Eclipse corrige les bogues d'implémentation lorsqu'il y a déviation du comportement prévu. Du fait que les modifications d'API s'associent souvent à des coûts élevés, l'équipe responsable de la plateforme Eclipse tentera également de faire évoluer les éléments d'API élégamment via d'importantes éditions successives.
Comment distinguer une API de ce qui n'en est pas une ?
De par leur nature, les éléments d'API sont documentés et ont une spécification, par opposition aux éléments non API qui sont des détails d'implémentation interne généralement sans aucune documentation, ni spécification publiée. Ainsi, si vous ne parvenez pas à trouver la documentation de quelque chose, ceci indique souvent qu'il ne s'agit pas d'une API.
Pour tirer un trait plus clairement, la base du code de la plateforme est séparée en packages d'API et non API, tous les éléments d'API étant déclarés dans les packages d'API désignés.
-
Package d'API : package Java contenant au moins une classe API ou d'interface d'API. Les noms des packages d'API sont indiqués dans la documentation de chaque composant. Lorsque cela est possible, tous les autres packages contenant uniquement des détails d'implémentation comporte le terme "internal" dans leur nom. Les noms des packages d'API peuvent légitimement apparaître dans le code client. Pour la plateforme Eclipse, les noms peuvent être comme suit :
-
org.eclipse.foo.* : par exemple, org.eclipse.swt.widgets,
org.eclipse.ui ou org.eclipse.core.runtime
-
org.eclipse.foo.internal.* : packages d'implémentation interne non API
-
org.eclipse.foo.examples.* : exemples non API
-
org.eclipse.foo.tests.* : suites de test non API
-
Classe ou interface d'API : classe ou interface publique dans un package d'API, ou membre de classe ou d'interface publique ou protégée déclaré dans ou hérité par une autre classe ou interface d'API.
Les noms des classes et des interfaces d'API peuvent légitimement apparaître dans le code client.
-
Méthode ou constructeur d'API : méthode ou constructeur public ou protégé déclaré dans ou hérité par une classe ou une interface d'API. Les noms des méthodes d'API peuvent légitimement apparaître dans le code client.
-
Zone d'API : zone publique ou protégée déclarée dans ou héritée par une classe ou une interface d'API. Les noms des zones d'API peuvent légitimement apparaître dans le code client.
Tout le reste est considéré comme du détail d'implémentation interne et hors limites de tous les clients. Le code client légitime ne doit jamais faire référence au nom des éléments non-API (même pas en utilisant la réflexion Java). Dans certains cas, les règles d'accessibilité au nom en langage Java sont utilisées pour interdire des références illégales.
Cependant, il existe de nombreux cas dans lesquels ceci n'est tout simplement pas possible. L'observation de cette simple règle évite complètement le problème :
-
Utilisez uniquement les API officiellement documentées. Seuls les packages référencés sont documentés dans le Javadoc des API publiées du composant.
Ne faites jamais référence à un package appartenant à un autre composant dont le nom contient "internal", car il ne s'agit jamais d'une API. Ne faites jamais référence à un package pour lequel aucun Javadoc des API publiées n'existe, il ne s'agit pas non plus d'API.
Règles générales
La spécification des éléments d'API est générée à partir des commentaires de Javadoc dans le code source Java de l'élément. Pour certains types d'éléments, la spécification est de la forme d'un contrat. Par exemple, dans le cas des méthodes, le contrat est entre deux parties : l'appelant de la méthode et le réalisateur de la méthode. La règle de base fondamentale est la suivante :
-
Honorer tous les contrats. Les contrats sont décrits dans la publication de Javadoc pour les éléments d'API que vous utilisez.
Le terme "must" (doit), lorsqu'il est utilisé dans un contrat d'API, signifie qu'il incombe à la partie de s'assurer que la condition est toujours satisfaite. Tout manquement à cette règle serait considéré comme une erreur de programmation avec des conséquences non spécifiées (et peut-être imprévisibles).
-
Vous devez honorer votre "devoir". Faites particulièrement attention aux conditions dans lesquelles le terme "must" (doit) est utilisé.
Autres règles de bon sens :
-
Ne vous fiez pas à un comportement fortuit. Un tel comportement est observé par l'expérience ou la pratique, mais n'est pas garanti par une spécification d'API.
-
Ne traitez pas la valeur "null" comme un objet. "Null" signifie plus le manque d'objet.
Présumez que tout est différent de "null" sauf si la spécification de l'API indique le contraire.
-
Ne tentez pas de tricher avec la réflexion Java. L'utilisation de la réflexion Java pour circonvenir les vérifications du compilateur Java ne vous apporte rien de plus. Il n'y a pas de contrat d'API supplémentaire pour les utilisations de la réflexion. Cette dernière ne fait qu'augmenter l'éventualité de se reposer sur un comportement non spécifié et des détails d'implémentation interne.
-
Utilisez vos propres packages. Ne déclarez pas de code dans un package appartenant à un autre composant. Déclarez toujours votre propre code dans vos propres packages.
Appels de méthodes d'API publiques
Pour la plupart des clients, la majeure partie des API Eclipse prend la forme de méthodes publiques sur des interfaces ou des classes d'API, fournies au client pour effectuer des appels au moment approprié.
-
Assurez-vous des conditions préalables. Assurez-vous réellement que les conditions d'une méthode d'API sont satisfaites avant d'appeler la méthode. Réciproquement, l'appelant peut
présumer en toute sécurité que les conditions suivantes de la méthode seront immédiatement
satisfaites au retour de l'appel.
-
Paramètres "null". Ne transmettez pas la valeur "null" comme paramètre à une méthode d'API, sauf s'il est explicitement documenté que cette valeur peut être appliquée au paramètre. C'est peut-être l'erreur de programmation la plus fréquemment commise.
-
Limites des appelants. N'appelez pas une méthode d'API documentée comme étant disponible uniquement pour certains appelants, à moins que vous ne soyez l'un d'eux. Dans certains cas, les méthodes doivent faire partie de l'API publique au bénéfice d'une certaine classe d'appelants (souvent interne). L'appel de ces méthodes au mauvais moment peut avoir des conséquences non spécifiées, voire imprévisibles.
-
Débogage des méthodes. N'appelez pas une méthode d'API libellée "à des fins de débogage uniquement". Par exemple, la plupart des méthodes toString() sont dans cette catégorie.
-
Capture de paramètre. Ne transmettez pas de tableau, de collection ni d'autre objet modifiable comme paramètre à une méthode d'API en modifiant ensuite l'objet transmis. Ceci ne peut qu'entraîner des problèmes.
Instanciation des classes d'API de la plateforme
Toutes les classes d'API concrètes ne sont pas destinées à être instanciées par quiconque.
Les classes d'API ont un contrat d'instanciation indiquant les termes selon lesquels les instances peuvent être créées. Le contrat peut également couvrir des choses telles que les responsabilités d'initialisation résiduelle (par exemple, la configuration d'une certaine propriété avant que l'instance soit totalement active) et les responsabilités du cycle de vie associé (par exemple, l'appel de dispose() pour libérer des ressources du système d'exploitation liées à l'instance). Les classes conçues pour être instanciées par des clients sont explicitement identifiées dans le commentaire de la classe du Javadoc (par des mots tels que "Clients may instantiate.").
-
Limites des instanciateurs. N'instanciez pas une classe d'API documentée comme étant disponible uniquement pour certaines parties, à moins que vous ne soyez l'une d'elles.
Dans certains cas, les classes doivent faire partie de l'API publique au bénéfice d'une certaine partie (souvent interne). Une mauvaise instanciation de ces classes peut avoir des conséquences non spécifiées, voire imprévisibles.
Sous-classification des classes d'API de la plateforme
Seul un sous-ensemble des classes d'API a été conçu pour être sous-classé. Les classes d'API ont un contrat de sous-classification indiquant les termes selon lesquels les sous-classes peuvent être déclarées. Ce contrat couvre également les responsabilités d'initialisation et celles du cycle de vie. Les classes conçues pour être sous-classées par des clients sont explicitement identifiées dans le commentaire de la classe du Javadoc (par des mots tels que "Clients may subclass.").
-
Limites des sous-classifications. Ne sous-classez pas une classe d'API qui n'est pas destinée à être sous-classée. Traitez ces classes comme si elles avaient été déclarées finales. (Elles sont parfois appelées classes "soft final".)
Appels de méthodes d'API protégées
Les appels de méthodes protégées héritées et publiques de l'intérieur d'une sous-classe sont généralement autorisés. Cependant, une attention toute particulière est souvent requise pour appeler correctement les méthodes publiques de l'extérieur de la hiérarchie.
Substitution de méthodes d'API
Seul un sous-ensemble des méthodes d'API publiques et protégées ont été conçues pour être substituées. Chaque méthode d'API a un contrat de sous-classification indiquant les termes selon lesquels une sous-classe peut être substituée. Par défaut, la substitution n'est pas permise.
Il est important de vérifier le contrat de sous-classification sur l'implémentation réelle de la méthode substituée. En effet, les termes de ces contrats ne sont pas automatiquement transmis lorsque la méthode est substituée.
-
Ne substituez pas une méthode d'API publique ou protégée à moins que cela ne soit explicitement autorisé. Sauf indication contraire, traitez toutes ces méthodes comme si elles avaient été déclarées finales. (Elles sont parfois connues sous le nom de méthodes "soft final").
Si le type de substitution autorisé est :
- "implement" : la méthode abstraite déclarée sur la sous-classe doit être implémentée par une sous-classe concrète.
- "extend" : la méthode déclarée sur la sous-classe doit invoquer la méthode sur la super classe (une fois seulement).
- "re-implement" : la méthode déclarée sur la sous-classe ne doit pas invoquer la méthode sur la super classe.
- "override" : la méthode déclarée sur la sous-classe est libre d'invoquer la méthode sur la super classe comme elle le veut.
-
Assurez-vous des conditions suivantes. Assurez-vous en retour que les conditions suivantes spécifiées pour la méthode d'API sont satisfaites par l'implémentation.
-
Vérifiez les conditions préalables de manière proactive. Ne présumez pas du fait que les conditions préalables spécifiées pour la méthode d'API ont été nécessairement satisfaites lors de la saisie. Bien que l'implémentation de la méthode soit dans ses droits de ne pas vérifier les conditions préalablement fixées, il est généralement préférable de les vérifier (lorsque cela est faisable et raisonnablement peu onéreux) afin de stopper les appelants au comportement incorrect.
-
Résultat nul. Ne renvoyez pas la valeur "null" comme résultat d'une méthode d'API à moins qu'il ne soit explicitement documenté (sur l'interface ou la super classe de spécification) que le résultat "null" est permis.
-
Renvoyez des copies. Ne renvoyez pas de tableau, de collection ou tout autre objet modifiable irremplaçable comme résultat d'une méthode d'API. Renvoyez toujours une copie pour éviter les inconvénients dus à des appelants pouvant modifier l'objet.
Implémentation des interfaces des API de la plateforme
Seul un sous-ensemble des interfaces d'API a été conçu pour être implémenté par les clients. Les interfaces d'API ont un contrat indiquant les termes selon lesquels elles peuvent être implémentées. Les interfaces conçues pour être implémentées par des clients sont explicitement identifiées dans le commentaire de la classe du Javadoc (par des mots tels que "Clients may implement"). Un client peut déclarer une sous-interface d'une interface d'API si et seulement si, il est autorisé à l'implémenter.
-
Limites des classes d'implémentation. N'implémentez pas une interface d'API documentée comme étant disponible uniquement pour certaines parties, à moins que vous ne soyez l'une d'elles. Dans de nombreuses situations, les interfaces sont utilisées pour masquer les détails d'implémentation interne de la vue.
Implémentation de méthodes d'API publiques
Reportez-vous à la section "Substitution des méthodes d'API".
Accès aux zones des classes et des interfaces d'API
Les clients peuvent lire des zones d'API, dont la plupart sont finales. Certains objets comparables à des structures peuvent ne pas avoir de zone publique non-finale que les clients puissent lire et écrire, sauf indication contraire.
-
Zones nulles. N'attribuez pas la valeur "null" à une zone d'API, à moins que cela ne soit explicitement permis.
Transtypage d'objets d'un type d'API connu
Un objet d'un type d'API connu peut être transtypé en un type d'API différent (ou transtypé conditionnellement avec instanceof) uniquement si cela est explicitement autorisé dans l'API.
-
Cast et instanceof. N'utilisez pas les expressions "instanceof" et "cast" pour augmenter la connaissance d'un objet au-delà de ce que l'API supporte.
Une utilisation incorrecte expose à des détails d'implémentation fortuits, non garantis par l'API.
Et, bien sûr, le transtypage d'un objet en classe ou interface non-API est toujours inappropriée.
Manquement aux règles
Que cela soit fait volontairement ou non, la transgression des règles a des répercussions. Il serait sans doute plus simple pour toutes les personnes impliquées qu'il existe une réglementation des API qui "attrape" ceux qui ne respectent pas les règles. Cependant, ce n'est pas le cas.
Pour la plupart, la conformité des API s'opère sur l'honneur, chaque client étant responsable de connaître les règles et de s'y conformer.
Les contrats sur les éléments d'API délimitent le comportement supporté. Du fait que la plateforme Eclipse évolue, ce sont les contrats d'API qui guident le mode d'évolution. En dehors de ces contrats, rien n'est supporté et tout est sujet à changement, sans avertissement préalable et à tout moment (même en milieu d'édition ou entre différentes plateformes de système d'exploitation). Le code client qui outrepasse les règles énoncées ci-dessus risque d'échouer avec des versions et des niveaux de correctifs différents de la plateforme, ou lorsqu'il est exécuté sur des systèmes d'exploitation sous-jacents différents, avec un jeu différent de plug-in co-résidants ou une autre perspective de plan de travail, etc. Bien sûr, personne n'est particulièrement intéressé par la spéculation visant à savoir exactement comment la transgression reviendrait s'en prendre à vous. Pour ceux qui choisissent d'ignorer les règles, ne venez pas dire que vous n'aviez pas été prévenu. Et ne vous attendez pas plus à un sympathique "on vous l'avait dit".
D'un autre côté, le code du plug-in client qui vit des règles ci-dessus doit continuer à fonctionner sur les différentes versions et niveaux de correctifs de la plateforme, sur les différents systèmes d'exploitation sous-jacents et également co-exister avec les autres plug-in sans problème. Si chacun respecte les règles, la plateforme Eclipse fournira une base stable et supportée sur laquelle de nouveaux produits fantastiques pourront être générés.