Table of Contents
Pourquoi la conception de l'API exige le principe de séparation de l'interface
Les systèmes logiciels modernes vivent ou meurent par leurs API. Que vous construisiez un service RESTful, un paramètre GraphQL ou un ensemble de SDK pour la consommation interne, les décisions que vous prenez dans votre cascade de conception d'interface dans chaque client qui les touche. L'une des façons les plus efficaces de garder votre API propre, durable et convivial pour le développeur est d'appliquer le Principe de séparation d'interface (ISP).
ISP est le quatrième des cinq principes SOLID du design orienté objet, initialement introduit par Robert C. Martin à la fin des années 1990. Bien que le principe ait été encadré pour les classes et les interfaces dans des langues comme Java ou C++, ses conseils sont directement transférables — et peut-être encore plus critiques — au design API.
En termes d'API, cela se traduit par la conception de terminaux et de contrats étroits et ciblés plutôt que d'interfaces monolithiques, tout-en-un. Ce faisant, vous réduisez le couplage, améliorez la clarté et permettre à chaque client d'interagir uniquement avec les parties de l'API qui lui importent. Cet article prend une plongée profonde dans ce que signifie pour les concepteurs d'API, comment le mettre en œuvre efficacement, et pourquoi éviter la tentation des interfaces graisseuses paiera des dividendes à long terme.
Comprendre le principe de séparation des interfaces
Origines et idées fondamentales
Le principe de séparation des interfaces est ressorti de l'observation selon laquelle les interfaces --fat--- ont tendance à accumuler des responsabilités au fil du temps. Une interface unique qui gère la lecture, l'écriture, la mise à jour, la suppression, l'authentification, l'enregistrement et l'audit oblige chaque consommateur à connaître et à mettre en oeuvre toutes ces méthodes, même si elles ne nécessitent que des opérations de lecture.
ISP préconise de diviser ces interfaces gonflées en contrats plus petits, role spécifiques. Au lieu d'une interface `DataManager`, vous pourriez avoir `DataReader`, `DataWriter`, `DataDeleter` et `Auditor`. Les clients dépendent alors uniquement des interfaces qui correspondent à leurs besoins exacts. Cela réduit l'effet d'entraînement des changements et rend le système plus facile à comprendre et à évoluer.
FAI dans le contexte de la conception de l'API
Lors de la conception des API, pensez à une interface -- comme le contrat entre votre service et ses consommateurs — que ces consommateurs soient des applications front-end, d'autres microservices ou des développeurs tiers.Une ressource API REST avec des dizaines de paramètres, ou un schéma GraphQL avec un seul type de mutation massive, peut devenir une interface ---fat.
ISP vous aide à vous demander : - Puis-je le caser en contrats plus petits et indépendants ?- La réponse conduit souvent à une version plus propre, à des tests plus faciles et à une meilleure évolutivité. Par exemple, une API orientée public pourrait exposer une interface légère et optimisée pour les clients mobiles tout en offrant une interface d'écriture plus riche en fonctionnalités pour les outils d'administration interne.
Principaux avantages de l'application du FSI dans votre API
Expérience améliorée du développeur (DX)
Les interfaces étroites sont plus simples à apprendre et à utiliser. Les développeurs nouveaux dans votre API peuvent rapidement localiser les paramètres ou les opérations pertinents à leur tâche sans perdre de vue les fonctionnalités non pertinentes. Cela réduit la charge cognitive et accélère l'intégration. Par exemple, une passerelle de paiement qui expose des interfaces distinctes pour l'autorisation, la capture, le remboursement et le vide est beaucoup plus intuitive qu'un seul paramètre `/transaction` qui nécessite des charges utiles complexes pour distinguer les opérations.
Flexibilité et evolvabilité améliorées
Si vous devez ajouter une nouvelle capacité à l'interface de lecture — par exemple, des options de pagination ou de filtrage — l'interface d'écriture reste intacte. De même, si un paramètre particulier nécessite des changements de rupture, vous pouvez déprécier ou version seulement ce petit contrat plutôt que l'API entière.
Amélioration de la viabilité et de la vérifiabilité
Pour les équipes de back-end, cela signifie que vous pouvez tester chaque contrat de fin de course sans faire tourner la pile d'application. Pour les équipes de côté client, les contrats étroits réduisent la surface pour les tests d'intégration. Le résultat est des boucles de rétroaction plus rapides et moins de défauts.
Couplage réduit et perte de dépendance
Une application mobile qui n'a besoin que de lire les profils utilisateurs ne devrait pas dépendre d'une bibliothèque ou d'une couche de transport qui inclut des capacités d'écriture et de suppression. ISP réduit ce couplage, ce qui rend plus sûr d'évoluer indépendamment de l'API et de ses consommateurs.
Mise en œuvre du PSI dans la conception de l'API : stratégies pratiques
1. Identifier les rôles des clients
La première étape consiste à comprendre qui sont vos clients API et quelles opérations ils effectuent réellement. Les rôles communs comprennent:
- Consommateurs en lecture seule (p. ex., applications mobiles affichant des données)
- Consommateurs uniquement écrits (p. ex., transformateurs de lots qui importent des dossiers)
- Consommateurs administratifs[ (p. ex. tableaux de bord qui nécessitent des capacités de suppression et de vérification)
- Les développeurs tiers qui peuvent avoir besoin seulement d'un sous-ensemble de fonctionnalités
Tracer chaque rôle aux opérations spécifiques dont il a besoin, ce qui révèle les limites naturelles de la ségrégation.
2. Utiliser des points de fin ou des ressources distincts
Dans REST, créer des paramètres spécifiques pour des responsabilités distinctes. Au lieu d'un seul `/api/orders` ressource de tout gérer, envisager de diviser:
- `GET /api/orders` – commandes de liste (lecture)
- `POST /api/orders` – créer l'ordre (écrire)
- `GET /api/orders/{id}/status` – état de vérification (lecture, spécialisation)
- `PACH /api/orders/{id}/annuler` – annuler l'ordre (écrire, scoped)
Chaque point final devient une mini-interface avec sa propre sémantique. Il s'agit d'une application directe de FSI au niveau des ressources.
3. Composition du levier (pas héritage) pour les interfaces
Lors de la conception de contrats d'API internes (par exemple, dans un SDK ou une couche de service), favoriser les petites interfaces qui peuvent être composées.
interface OrderReader {
getOrder(id: string): Promise<Order>;
listOrders(filter: OrderFilter): Promise<Order[]>;
}
interface OrderWriter {
createOrder(data: CreateOrderInput): Promise<Order>;
updateOrder(id: string, data: UpdateOrderInput): Promise<Order>;
}
// A composite interface for admin use
interface OrderAdmin extends OrderReader, OrderWriter {
deleteOrder(id: string): Promise<void>;
}
Ce modèle permet aux clients de ne dépendre que de ce dont ils ont besoin. Les services peuvent mettre en œuvre uniquement les interfaces pertinentes, évitant ainsi les talons de méthode inutilisés.
4. Modèles distincts de lecture et d'écriture (CQRS)
Pour les domaines complexes, envisagez d'adopter Command Query Responsibility Segregation (CQRS)[. CQRS est un style d'architecture qui fait naturellement appliquer ISP en séparant les modèles de lecture (requêtes) des modèles d'écriture (commandes).Votre API expose des paramètres ou canaux distincts pour les requêtes et les commandes.
5. Utiliser les autorisations granulaires avec accès par rôle
ISP s'applique également à la sécurité. Au lieu d'une seule clé d'API monolithique accordant toutes les capacités, émettre des jetons scoped ou des clés d'API qui limitent l'accès à des interfaces spécifiques. Par exemple, un client public peut seulement avoir la permission d'appeler `GET /products`, tandis qu'un système interne peut également appeler `POST /products`. Cela fait appliquer ISP à la couche d'autorisation et empêche une exposition inutile.
Exemples de FSI en action dans le monde réel
API RESTful: GitHub, Twilio, Stripe
Les principaux fournisseurs d'API sont de grands exemples de FAI. GitHub=2 L'API a des paramètres dédiés pour les repos, les problèmes, les tirages et les actions — vous n'avez jamais besoin de consommer une méthode pour gérer les demandes de tirage lorsque vous voulez seulement lister les problèmes. Twilio=2 L'API sépare la messagerie, la voix et la vérification en différents paramètres. Stripe offre des API distinctes pour les paiements, la facturation et la connexion.
Envisagez de visiter Stripe , référence API pour voir comment ils évitent les interfaces graisseuses.
GraphiqueQL et FSI
GraphQL pourrait initialement sembler violer ISP parce qu'un seul paramètre expose l'ensemble du schéma. Cependant, les API de GraphQL bien conçues appliquent ISP au niveau du champ. Le schéma définit des types et des requêtes distincts pour différentes préoccupations, et les clients peuvent demander seulement les champs dont ils ont besoin. Des outils comme Apollo Federation vont plus loin en composant un graphique unifié à partir de plusieurs sous-graphes, chacun responsable d'un contexte délimité — un ISP de niveau microservice.
Microservices et contextes consolidés
Dans les architectures de microservice, chaque service expose sa propre interface (API). L'authentification des utilisateurs n'a pas besoin de connaître les mises à jour des stocks. En gardant les services petits et concentrés, vous adhèrez naturellement à ISP. Selon Martin Fowler , article sur les microservices, cette décomposition est la clé de la déployabilité et de l'évolutivité indépendantes.
SDK et conception de la bibliothèque
Lorsque vous fournissez un SDK client pour votre API, appliquez ISP dans l'API publique de la bibliothèque. Par exemple, au lieu d'une classe centrale `ApiClient` avec des centaines de méthodes, offrez des classes spécialisées comme `OrdersClient`, `ProductsClient` et `Client Clients`. C'est exactement ce que fait le AWS SDK pour JavaScript – chaque service obtient sa propre classe client.
Pièges courants et comment les éviter
Surségrégation
Le fait de ne pas être granulaire peut créer une multitude d'interfaces minuscules qui confondent pour naviguer et maintenir. L'objectif n'est pas d'avoir une interface par méthode, mais de regrouper des opérations liées logiquement qui changent ensemble. Une bonne règle de pouce : si deux opérations sont toujours utilisées ensemble par le même client, elles appartiennent probablement à la même interface.
Granularité prématurée
Ne pas trop sur-enginerer les interfaces avant de comprendre les besoins du client. Commencez par une interface légèrement plus grande, et ne la divisez que lorsque vous voyez des preuves concrètes de différents rôles du client ou de pressions de changement.
Ignorer la compatibilité avec l'arrière
Lorsque vous divisez une interface existante, les clients existants peuvent se casser s'ils dépendent de l'ancien contrat. Toujours déprécier progressivement. Pour REST, vous pouvez versionner vos paramètres (par exemple `/v1/orders`, `/v2/orders/read`). Pour les interfaces internes, utilisez les modèles d'adaptateur pour relier les anciens contrats et les nouveaux contrats.
Outils et documentation - Surpasse
Plus d'interfaces signifient plus de documentation. Investir dans de bons outils de documentation API (comme OpenAPI/Swagger ou introspection GraphQL) et s'assurer que chaque interface est clairement décrite. L'effort rapporte en confiance du développeur et adoption.
ISP et autres principes SOLID
Principe de responsabilité unique (PRS)
SRP dit qu'un module devrait avoir une raison de changer. SRP s'assure qu'une interface a une responsabilité — servir un rôle client. Lorsque vous suivez SRP au niveau du module, vous finissez souvent avec des interfaces déjà séparées.
Principe de substitution de Liskov (LSP)
En fait, les petites interfaces facilitent la création d'implémentations substituables. Si une interface n'a que deux méthodes, toute implémentation qui remplit ces méthodes peut être échangée en toute confiance. Les interfaces Fat tentent souvent les développeurs de lancer des méthodes non mises en œuvre (par exemple, lancer `NotImplementedException`), qui violent le LSP.
Principe ouvert/fermé (POC)
Les interfaces séparées supportent OCP parce que vous pouvez ajouter de nouveaux comportements en créant de nouvelles interfaces plutôt que de modifier celles existantes. Par exemple, ajouter une opération par lots ne nécessite pas de modifier les interfaces de lecture/écriture existantes — vous créez une nouvelle interface `BatchProcesseur` que le client peut choisir d'implémenter.
Principe d'inversion de la dépendance (DIP)
ISP travaille main dans la main avec DIP: les abstractions (interfaces) ne doivent pas dépendre des détails; les détails doivent dépendre des abstractions. Lorsque ces abstractions sont très cohérentes et séparées, vous obtenez une flexibilité maximale dans les dépendances de câblage.
Tester les API avec ISP dans l'esprit
L'application de l'ISP simplifie les tests à plusieurs niveaux :
- Chaque petite interface peut être mâchée facilement. Un test pour un client en lecture seule doit seulement mâchier l'interface du lecteur, et non l'API entière.
- Tests d'intégration:[ Vous pouvez tester les paramètres en isolation.Un test d'écriture des paramètres n'a pas besoin d'exercer les paramètres de lecture.
- Avec des interfaces étroites, les tests contractuels (p. ex., en utilisant le Pacte) deviennent plus ciblés. Chaque pacte de consommateurs ne couvre que les interactions qu'il utilise, réduisant ainsi la probabilité de faux positifs.
- L'isolement des chemins de lecture et d'écriture vous permet de simuler plus précisément les modèles d'utilisation du monde réel.
Mesure de l'impact des FSI
Comment savez-vous si votre conception d'API est bien séparée? Recherchez ces indicateurs:
- Faible --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Rares changements aux interfaces partagées — si une interface change souvent pour des raisons sans rapport avec son client principal, elle est probablement trop large.
- Peu de méthodes obsolètes — si votre API accumule de nombreuses -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Court temps de navigation pour les nouveaux développeurs — une API étroite est plus facile à apprendre.
Conclusion
Le principe de séparation des interfaces n'est pas seulement une ligne directrice académique — c'est un outil pratique pour construire des API qui résistent au test du temps. En écrivant de petites interfaces spécifiques au rôle, vous réduisez le couplage, améliorez l'expérience du développeur et rendez votre système plus résistant au changement. Que vous conceviez des paramètres REST, des schémas GraphQL ou des SDK, demandez à mon client Est-ce que cela vous est vraiment nécessaire?
Rappelez-vous, ISP n'est pas sur des règles rigides mais sur l'intentionnalité. Commencez par une perspective centrée sur le client, itérer basé sur des modèles d'utilisation réels, et ne pas avoir peur de refactor interfaces à mesure que votre compréhension grandit. Le résultat sera une API avec laquelle les développeurs aiment travailler, qui peut évoluer sans briser le monde.
Pour plus de détails, explorez l'article du FSI sur Wikipedia et Robert C. Martin=s écrit sur SOLID.Ces ressources fournissent une profondeur supplémentaire sur la relation entre le FSI et d'autres heuristiques de conception.