web-dev-qa-db-fra.com

Devriez-vous écrire votre back-end en tant qu'API?

J'ai eu une discussion animée aujourd'hui sur notre application MVC. Nous avons un site Web écrit en MVC ( ASP.NET ), et il suit généralement le modèle de faire quelque chose dans la vue -> appuyez sur le contrôleur -> le contrôleur construit un modèle (appelle un gestionnaire qui obtient le données, construit le modèle dans la méthode du contrôleur lui-même) -> le modèle va voir -> rincer et répéter.

Il a dit que notre code était trop étroitement couplé. Par exemple, si nous voulions également une application de bureau, nous ne pourrions pas utiliser notre code existant.

La solution et les meilleures pratiques, a-t-il dit, consistent à créer une API, puis à créer votre site Web au-dessus de votre API, puis à créer une application de bureau, une application mobile, etc., est très simple.

Cela me semble une mauvaise idée pour diverses raisons.

Quoi qu'il en soit, je n'arrive pas à trouver quoi que ce soit en recherchant sur Google qui pourrait discuter de cette pratique. Quelqu'un a-t-il des informations sur les avantages, les inconvénients, pourquoi vous devriez, pourquoi vous ne devriez pas ou plus de lecture?

Quelques raisons pour lesquelles je pense que c'est une mauvaise idée:

  • C'est beaucoup trop abstrait pour exécuter votre backend à partir d'une API. Vous essayez de le rendre trop flexible, ce qui en fera un gâchis ingérable.

  • Tous les éléments intégrés à MVC semblent inutiles, comme les rôles et l'authentification. Par exemple, [Autoriser] les attributs et la sécurité; vous devrez rouler le vôtre.

  • Tous vos appels API nécessiteront des informations de sécurité attachées, et vous devrez développer un système de jetons et ainsi de suite.

  • Vous devrez écrire des appels API complets pour chaque fonction de votre programme. Presque toutes les méthodes que vous souhaitez implémenter devront être exécutées à partir d'une API. Un Get/Update/Delete pour chaque utilisateur, plus une variante pour chaque autre opération, par exemple mettre à jour le nom d'utilisateur, ajouter un utilisateur à un groupe, etc. etc. et chacun serait un appel d'API distinct.

  • Vous perdez toutes sortes d'outils comme les interfaces et les classes abstraites en ce qui concerne les API. Des trucs comme WCF ont un support très ténu pour les interfaces.

  • Vous disposez d'une méthode qui crée un utilisateur ou effectue une tâche. Si vous souhaitez créer 50 utilisateurs, vous pouvez simplement l'appeler 50 fois. Lorsque vous décidez de faire cette méthode en tant qu'API, votre serveur Web local peut se connecter à des canaux nommés et aucun problème - votre client de bureau peut le frapper aussi, mais soudainement, votre création d'utilisateur en masse impliquera de marteler l'API sur Internet 50 fois, ce qui n'est pas pas bon. Vous devez donc créer une méthode en bloc, mais vous ne faites que la créer pour les clients de bureau. De cette façon, vous finissez par a) modifier votre API en fonction de ce qui l'intègre, et vous ne pouvez pas simplement l'intégrer directement, b) faire beaucoup plus de travail pour créer une fonction supplémentaire.

  • YAGNI . À moins que vous ne prévoyiez spécifiquement d'écrire deux applications fonctionnant de manière identique, une application Web et une application Windows par exemple, cela représente un énorme travail de développement supplémentaire.

  • Le débogage est beaucoup plus difficile lorsque vous ne pouvez pas passer de bout en bout.

  • Beaucoup d'opérations indépendantes qui nécessiteront beaucoup de va-et-vient, par exemple, du code peut obtenir l'utilisateur actuel, vérifier que l'utilisateur est dans le rôle d'administrateur, obtenir la société à laquelle l'utilisateur appartient, obtenir une liste des autres membres, les envoyer tous un email. Cela nécessiterait beaucoup d'appels API, ou l'écriture d'une méthode sur mesure pour la tâche spécifique que vous souhaitez, où le seul avantage de cette méthode sur mesure serait la rapidité mais l'inconvénient serait qu'elle serait inflexible.

  • Probablement quelques autres raisons pour lesquelles ce sont juste au-dessus de ma tête.

Il me semble que sauf si vous avez vraiment besoin de deux applications identiques, cela n'en vaut vraiment pas la peine. Je n'ai jamais vu une application ASP.NET construite comme celle-ci non plus, vous devez écrire deux applications distinctes (l'API et votre code) et les contrôler également par version (si votre page utilisateur obtient un nouveau champ, vous '' Je dois mettre à jour l'API et votre code consommateur simultanément pour éviter tout effet indésirable ou consacrer beaucoup de travail supplémentaire à sa robustesse).


Edit: Quelques bonnes réponses, commençant vraiment à avoir une bonne idée de ce que tout cela signifie maintenant. Donc, pour développer ma question, comment structureriez-vous une application MVC pour suivre cette structure d'API?

Par exemple, vous avez un site Web qui affiche des informations sur un utilisateur. Sous MVC, vous avez:

Vue - Page (CS) HTML qui affiche un contrôleur UserViewModel - Appelle GetUser () et crée un UserViewModel qu'il transmet à la classe View Manager (sorte de votre API) qui a une méthode GetUser.

Le contrôleur utilise GetUser () mais vous voulez également une application de bureau. Cela signifie que votre GetUser doit être exposé via une sorte d'API. Vous voudrez peut-être une connexion TCP, soit WCF, soit Remoting. Vous voulez également une application mobile qui sera RESTful car les connexions persistantes sont irrégulières.

Alors, écririez-vous ensuite une API pour chacun, un service Web WCF qui a une méthode GetUser () et le code fait juste return new UserManager().GetUser()? Et une méthode API Web MVC 4 qui fait la même chose? Tout en continuant d'appeler GetUser directement dans votre méthode de contrôleur MVC?

Ou choisiriez-vous la solution qui fonctionnerait pour les trois (api web REST) et construisez tout sur cela, de sorte que les trois applications effectuent des appels API (ceux mvc, vers la machine locale) .

Et est-ce juste un scénario théorique parfait? Je peux voir de gros frais généraux dans le développement de cette façon, surtout si vous devez développer d'une manière qui vous permettra d'effectuer des opérations de manière RESTful. Je pense que certains de ces éléments ont été traités dans les réponses.


Edit 2: Après avoir lu plus de choses, j'ai mis un commentaire ci-dessous qui, je pense, pourrait l'expliquer. La question est un peu une question piège, je pense. Si vous écrivez votre back-end en tant qu'API, je pensais qu'il devait y avoir un seul service Web que tout (application mvc, application de bureau, application mobile) appelle pour faire des choses.

La conclusion à laquelle je suis arrivé est que ce que vous devez vraiment faire est de vous assurer que votre couche logique métier est correctement découplée. En regardant mon code, je le fais déjà - le contrôleur appellera GetUser() sur un gestionnaire, puis créera un modèle de vue à partir de celui-ci pour le rendre avec une vue. Donc, vraiment, la couche de logique métier est une API. Si vous souhaitez l'appeler à partir d'une application de bureau, vous devrez écrire quelque chose comme un service WCF pour faciliter l'appel. Même avoir une méthode WCF appelée GetUser() qui contient le code return MyBusinessLayer.GetUser() serait suffisant. Ainsi, l'API est la logique métier, et WCF/API Web, etc. ne sont que des morceaux de code pour permettre aux applications externes de l'appeler.

Il y a donc des frais généraux, dans la mesure où vous devez encapsuler votre couche de logique métier dans différentes API en fonction de ce dont vous avez besoin, et vous devrez écrire une méthode d'API pour chaque opération que vous souhaitez que vos autres applications fassent, plus vous devrez trier un moyen de faire l'authentification, mais pour la plupart, c'est la même chose. Collez votre logique métier dans un projet distinct (bibliothèque de classes), et vous n'aurez probablement aucun problème!

Espérons que cette interprétation soit correcte. Merci pour toutes les discussions/commentaires qu'il a généré.

330
NibblyPig

Oui tu devrais.

Il rend non seulement votre back-end réutilisable mais permet plus de sécurité et une meilleure conception. Si vous écrivez votre backend dans le cadre d'un système unique, vous créez une conception monolithique qui n'est jamais facile à étendre, à remplacer ou à améliorer.

Un domaine où cela est populaire en ce moment est dans Microservices . Lorsque le backend est divisé en de nombreux petits (voire grands) services qui fournissent chacun une API que le système client consomme. Si vous imaginez utiliser de nombreuses sources de données tierces dans votre application, vous réalisez que vous le faites peut-être déjà.

Un autre avantage est que la construction et la maintenance de chaque service peuvent être confiées à une équipe différente, ils peuvent y ajouter des fonctionnalités qui n'affectent aucun autre produit producteur d'équipe. Ce n'est que lorsqu'ils ont terminé et libéré leur service que vous commencez à ajouter des fonctionnalités à votre produit pour les consommer. Cela peut rendre le développement beaucoup plus fluide (bien que potentiellement plus lent dans l'ensemble, vous auriez tendance à obtenir une meilleure qualité et compréhensible)


Edit: OK je vois votre problème. Vous considérez l'API comme une bibliothèque distante. Ce n'est pas. Considérez le service comme un service fournissant des données. Vous appelez le service pour obtenir des données, puis effectuez des opérations sur ces données localement. Pour déterminer si un utilisateur est connecté, vous devez appeler "GetUser", puis consulter le 'logged on' valeur, par exemple. ( YMMV avec cet exemple, bien sûr).

Votre exemple pour la création d'utilisateurs en masse ne fait que des excuses - il n'y a pas de différence ici, tout ce que vous auriez pu faire dans un système monolithique peut toujours être fait dans une architecture de service (par exemple, vous auriez passé un tableau d'utilisateurs à créer en masse, ou un seul à créer. Vous pouvez toujours faire exactement la même chose avec les services).

MVC est déjà basé sur le concept de services isolés, seuls les frameworks MVC les regroupent en un seul projet. Cela ne signifie pas que vous perdez quoi que ce soit, sauf les assistants fournis par votre framework. Utilisez un cadre différent et vous devrez utiliser différents assistants. Ou, dans ce cas, lancez le vôtre (ou ajoutez-les directement à l'aide d'une bibliothèque).

Le débogage est également facile - vous pouvez tester l'API de manière approfondie de manière isolée afin de ne pas avoir à déboguer dedans (et vous pouvez déboguer de bout en bout, Visual Studio peut s'attacher à plusieurs processus simultanément).

Des choses comme un travail supplémentaire pour implémenter la sécurité est une bonne chose. Actuellement, si vous regroupez tout le code dans votre site Web, si un pirate y accède, il a également accès à tout, DB inclus. Si vous le divisez en une API, le pirate peut faire très peu avec votre code, à moins qu'il ne pirate également la couche API - ce qui sera incroyablement difficile pour eux (vous êtes-vous déjà demandé comment les attaquants obtenaient de vastes listes de tous les utilisateurs du site Web ou les détails de cc? C'est parce que ils ont piraté le système d'exploitation ou le serveur Web et il avait une connexion directe à la base de données où ils pouvaient exécuter "select * from users" avec facilité).

Je dirai que j'ai vu de nombreux sites Web (et applications client-serveur) écrits comme ça. Lorsque je travaillais dans le secteur des services financiers, personne n'écrirait jamais un site Web tout-en-un, en partie parce que cela représente trop de risque pour la sécurité, et en partie parce qu'une grande partie du développement consiste en de jolies interfaces graphiques sur un traitement de données principal stable (c'est-à-dire hérité) systèmes. Il est facile d'exposer le système DP en tant que site Web en utilisant une architecture de style de service.

2ème édition: Quelques liens sur le sujet (pour l'OP):

Notez que lorsque vous en parlez dans le contexte d'un site Web, le serveur Web doit être considéré comme la couche de présentation, car c'est le client qui appelle les autres niveaux, et également parce qu'il construit les vues de l'interface utilisateur qui sont envoyées au navigateur pour le rendu. C'est un gros sujet, et il existe de nombreuses façons de concevoir votre application - centrée sur les données ou centrée sur le domaine (je considère généralement que le domaine centré est "plus pur", mais YMMV ), mais tout se résume à coller un niveau logique entre votre client et votre base de données. C'est un peu comme MVC si vous considérez que le niveau intermédiaire, l'API, le niveau est équivalent à votre modèle, seul le modèle n'est pas un simple wrapper pour la base de données, il est plus riche et peut faire beaucoup plus (par exemple, agréger les données de 2 sources de données, publier - traiter les données pour les adapter à l'API, mettre en cache les données, etc.):

286
gbjbaanb

Vous ne pouvez pas éviter de construire une API . Même si vous créez "juste un site Web", il devra quand même obtenir ses données de votre serveur. Quelle que soit votre décision, c'est votre API de facto.

Sachant cela, la vraie question n'est pas de savoir si construire une API, mais comment la construire . Vous pouvez le faire à la volée comme une chose ad hoc -et en effet, de nombreux sites Web sont construits exactement de cette façon- ou vous pouvez le concevoir soigneusement pour être utilisable dans d'autres contextes. Dans ce contexte, il devient assez clair que votre collègue a raison: vous devez d'abord faire l'API, puis construire votre site par-dessus.

Néanmoins, cela soulève certaines préoccupations, comme vous le signalez. Pour les aborder:

C'est beaucoup trop abstrait pour exécuter votre backend à partir d'une API. Vous essayez de le rendre trop flexible, ce qui en fera un gâchis ingérable.

Cela dépend de la façon dont vous le faites. Comme George Pólya le souligne dans son excellent texte Comment le résoudre , souvent "le problème plus général peut être plus facile à résoudre". C'est ce qu'on appelle le Paradoxe de l'inventeur. Dans le cas de la programmation, cela fonctionne souvent par séparation des préoccupations: votre backend n'a plus à se soucier du format des données qu'il entre et sort, et donc son code peut être beaucoup plus simple. Vos analyseurs et rendus de données n'ont plus à se soucier de ce qui arrive aux données qu'ils créent, ils peuvent donc aussi être plus simples. Tout cela fonctionne en décomposant le code en morceaux plus faciles à gérer.

Tous les éléments intégrés à MVC semblent inutiles, comme les rôles et l'authentification. Par exemple, [Autoriser] les attributs et la sécurité; vous devrez rouler le vôtre.

J'avoue que je trouve extrêmement difficile de sympathiser avec des gens qui refusent d'apprendre leurs outils. Ce n'est pas parce que vous ne comprenez pas que leur utilisation est inutile, et cela ne signifie certainement pas que vous devez lancer la vôtre . Bien au contraire; vous ne devriez pas aller rouler vos propres outils jusqu'à vous comprenez les alternatives, de sorte que vous pouvez être sûr de résoudre les mêmes problèmes qu'eux (même si ce n'est qu'à votre manière).

Considérez Linus Torvalds , qui est le plus célèbre pour avoir écrit Linux , mais qui a également écrit git : maintenant l'un des systèmes de contrôle de version les plus populaires de le monde. L'un des facteurs moteurs de sa conception était une opposition profonde à Subversion (un autre extrêmement populaire VCS , et sans doute le plus populaire au l'heure à laquelle git a été écrit); il a résolu de prendre tout ce que Subversion pouvait, et dans la mesure du possible, résoudre ces problèmes différemment. Pour ce faire, il a dû devenir un expert de la Subversion à part entière , précisément pour pouvoir comprendre les mêmes domaines problématiques et adopter une approche différente.

Ou, dans le processus d'apprentissage de vos outils, vous pourriez vous retrouver à trouver qu'ils sont utiles tels quels et n'ont pas besoin d'être remplacés.

Tous vos appels API nécessiteront des informations de sécurité attachées, et vous devrez développer un système de jetons et ainsi de suite.

Oui. Ça devrait être comme cela.

Vous devrez écrire des appels API complets pour chaque fonction de votre programme. Presque toutes les méthodes que vous souhaitez implémenter devront être exécutées à partir d'une API. Un Get/Update/Delete pour chaque utilisateur, plus une variante pour chaque autre opération, par exemple mettre à jour le nom d'utilisateur, ajouter un utilisateur à un groupe, etc. etc. et chacun serait un appel d'API distinct.

Pas nécessairement. C'est là que des architectures comme RESTE entrent en jeu. Vous identifiez les ressources avec lesquelles votre application fonctionne et les opérations qui s'appliquent à ces ressources, puis vous les implémentez sans trop vous soucier des autres .

Vous perdez toutes sortes d'outils comme les interfaces et les classes abstraites en ce qui concerne les API. Des trucs comme WCF ont un support très ténu pour les interfaces.

Au contraire, les interfaces deviennent beaucoup plus importantes lorsque vous utilisez une API, pas moins . Ils ressortent dans les représentations dans lesquelles vous les rendez. De nos jours, la plupart des gens spécifient un format basé sur JSON , mais vous pouvez utiliser n'importe quel format que vous souhaitez, tant que vous le spécifiez bien. Vous restituez la sortie de vos appels dans ce format sur le backend, et l'analysez dans ce que vous voulez (probablement le même type d'objet) sur le frontend. Les frais généraux sont faibles et les gains de flexibilité sont énormes.

Vous disposez d'une méthode qui crée un utilisateur ou effectue une tâche. Si vous souhaitez créer 50 utilisateurs, vous pouvez simplement l'appeler 50 fois. Lorsque vous décidez de faire cette méthode en tant qu'API, votre serveur Web local peut se connecter à des canaux nommés et aucun problème - votre client de bureau peut le frapper aussi, mais soudainement, votre création d'utilisateur en masse impliquera de marteler l'API sur Internet 50 fois, ce qui n'est pas pas bon. Vous devez donc créer une méthode en bloc, mais vous ne faites que la créer pour les clients de bureau. De cette façon, vous finissez par a) modifier votre API en fonction de ce qui l'intègre, et vous ne pouvez pas simplement l'intégrer directement, b) faire beaucoup plus de travail pour créer une fonction supplémentaire.

La création d'une version en vrac d'une méthode existante n'est guère quelque chose que j'appellerais "beaucoup plus de travail". Si vous n'êtes pas préoccupé par des choses comme l'atomicité, la méthode en vrac peut ne pas être beaucoup plus qu'une interface très mince pour l'original.

YAGNI . À moins que vous ne prévoyiez spécifiquement d'écrire deux applications fonctionnant de manière identique, une application Web et une application Windows par exemple, cela représente un énorme travail de développement supplémentaire.

Non, YANI (vous en avez déjà besoin). Je l'ai expliqué comme ci-dessus. La seule question est de savoir combien de travail de conception y mettre.

Le débogage est beaucoup plus difficile lorsque vous ne pouvez pas passer de bout en bout.

Pourquoi ne pourriez-vous pas passer de bout en bout?

Mais plus précisément, le fait de pouvoir examiner les données en va-et-vient dans un format facilement reconnaissable qui supprime tous les problèmes d'affichage a tendance à rendre le débogage plus facile, pas plus difficile.

Beaucoup d'opérations indépendantes qui nécessiteront beaucoup de va-et-vient, par exemple, du code peut obtenir l'utilisateur actuel, vérifier que l'utilisateur est dans le rôle d'administrateur, obtenir la société à laquelle l'utilisateur appartient, obtenir une liste des autres membres, les envoyer tous un email. Cela nécessiterait beaucoup d'appels API, ou l'écriture d'une méthode sur mesure pour la tâche spécifique que vous souhaitez, où le seul avantage de cette méthode sur mesure serait la rapidité mais l'inconvénient serait qu'elle serait inflexible.

RESTE résout cela en travaillant sur des objets complets ( ressources, pour utiliser REST termes de la théorie), plutôt que les propriétés individuelles des objets . Pour mettre à jour le nom d'un utilisateur, vous OBTENEZ l'objet utilisateur, changez son nom et REMETTEZ l'utilisateur. Vous pouvez également apporter d'autres modifications en même temps que vous modifiez le nom d'utilisateur. Le problème plus général devient plus facile à résoudre, car vous pouvez éliminer tous ces appels individuels pour mettre à jour les propriétés individuelles d'un objet: il vous suffit de le charger et de l'enregistrer.

À certains égards, cela n'est pas différent des architectures RISC côté matériel. L'une des principales différences entre RISC et CISC (son prédécesseur) est que les architectures CISC ont tendance à inclure de nombreuses instructions qui fonctionnent directement sur la mémoire, tandis que les architectures RISC ont tendance à fonctionnent principalement dans des registres: dans une architecture purement RISC, les seules opérations sur la mémoire sont LOAD (copier quelque chose de la mémoire dans un registre) et STORE (prendre une valeur dans un registre et la mettre en mémoire).

On pourrait penser que cela impliquerait de faire beaucoup plus de déplacements des registres vers la mémoire, ce qui ralentirait la machine. Mais en pratique, l'inverse se produit souvent: le processeur (client) fait plus de travail entre les trajets vers la mémoire (serveur) , et c'est là que l'accélération vient de.

Pour faire court: votre collègue a raison. C'est la voie à suivre. En échange d'un petit travail initial, cela simplifiera considérablement le code de votre site Web et permettra une meilleure intégration avec d'autres sites Web et applications. C'est un prix à payer.

Lectures complémentaires:

  1. Conception de l'API REST - Modélisation des ressources
91
The Spooniest

Je sais que les microservices font fureur en ce moment, mais ils n'en valent pas toujours la peine. Oui, le code à couplage lâche est l'objectif. Mais cela ne devrait pas se faire au détriment d'un cycle de développement plus douloureux.

Un bon compromis serait de créer un projet de données distinct dans votre solution. Le projet de données serait une bibliothèque de classes .NET. Votre projet ASP.NET MVC ajouterait alors une référence à la bibliothèque de données et tous les modèles seraient extraits du projet de données. Ensuite, lorsque le moment est venu de créer une application de bureau ou mobile, vous pouvez référencer le même code. Il ne s'agit donc peut-être pas d'une API officielle, mais elle fonctionnera comme telle. Si vous souhaitez le rendre accessible en tant qu'API, vous pouvez créer un projet Web simple qui agit comme un wrapper sur le projet de données.

Microsoft a fait la promotion de ce concept, qu'ils appellent Bibliothèques de classes portables .

63
fotijr

Non, vous ne devriez pas. Si vous n'avez pas de plans immédiats pour créer d'autres frontaux (comme des applications mobiles ou de bureau ou une application Web distincte) qui accèdent au même backend, vous ne devez pas introduire de couche de service Web. YAGNI .

Un couplage lâche est toujours souhaitable (avec une cohésion élevée), mais c'est un principe de conception et ne signifie pas que vous devez séparer physiquement les objets sur différents serveurs! Et une API de service mal conçue peut créer un couplage étroit au-delà des frontières du serveur, donc avoir une API ne garantit pas un couplage lâche.

Si le besoin d'une API de service devait survenir à l'avenir, vous pouvez toujours l'introduire à ce stade. Tant que vous gardez votre code bien en couches (accès aux données et logique métier de la logique d'interface utilisateur distinctement séparée), il ne sera pas plus difficile à introduire plus tard qu'il ne l'est maintenant. Et la conception résultante sera bien meilleure lorsqu'elle est conçue pour répondre aux besoins réels.


Remarque Je suppose que la question est de savoir si vous devez créer une API de service Web ou non. La question dit simplement API, mais API peut également signifier simplement l'interface d'une bibliothèque, et bien sûr, chaque couche aura une API par définition. L'essentiel, c'est que votre logique métier et vos couches d'accès aux données doivent être parfaitement séparées de la logique de l'interface utilisateur au niveau de la conception, mais vous ne devez pas introduire de couche de service Web si vous n'en avez pas besoin.

34
JacquesB

Mon entreprise a une application construite comme ça. Initialement, nous avons été chargés de construire un back-end avec API pour un frontal qu'un autre développeur était en train de créer. Lorsque l'autre développeur n'a pas pu développer ce front-end, nous avons également été chargés de construire le front-end. S'il y a certainement des avantages à cette approche, il y a un énorme inconvénient: le coût. La construction initiale sera considérablement plus coûteuse et la maintenance continue sera plus coûteuse, en raison de plus de code à maintenir et du déploiement de deux systèmes distincts. En raison du coût supplémentaire, cela devrait toujours être une décision commerciale, non prise sur un caprice par les développeurs.

Pour mettre un chiffre là-dessus, j'estime que le projet que je mentionne ci-dessus coûte 20% de plus en raison de cette approche. Vous ne décrivez pas le type de projet sur lequel vous travaillez, pour quel type d'entreprise vous travaillez, mais si vous êtes une start-up qui construit son produit, ce coût supplémentaire pourrait être la différence entre l'expédition de quelques fonctionnalités supplémentaires qui font de votre produit un succès.

Une autre raison de ne pas le faire, du moins pas universellement, est que si ou lorsque vous décidez de créer cette deuxième interface, il y a rarement un mappage un à un des fonctionnalités. Si vous créez une application mobile, par exemple, elles ont généralement moins de fonctionnalités. Cela signifie que certaines de vos méthodes API ne seront jamais réutilisées. Par conséquent, un compromis avec votre collègue pourrait être de décider entre vous les appels les plus cruciaux/critiques et de les ajouter à une API, et d'utiliser des méthodes plus traditionnelles pour tout le reste.

Un autre point à considérer est que votre collègue dit que vous ne pourrez pas réutiliser votre code existant, ce qui n'est pas vrai si vous avez une certaine séparation de votre logique métier. Il vous suffit de créer un wrapper de service Web fin autour de vos API internes, ce qui n'est pas une tâche particulièrement importante. Il serait naïf de penser que vous pourriez réutiliser une couche de service Web pour un autre frontal de toute façon sans aucune modification.

29
Ian Newson

Cela dépend du type d'application et du type de marché sur lequel vous vous trouvez.

Il y a des compromis et des avantages à suivre cette voie. Ce n'est pas une réponse claire qu'une façon est meilleure que l'autre.

Je vais parler d'expérience personnelle. C'est moi qui ai décidé de prendre la base de code sur laquelle je travaille dans ce sens en 2007. Cette base de code est quelque part de l'ordre d'un million de lignes de code, dont la moitié est du code serveur caché derrière une énorme quantité de services Web. API, l'autre moitié est une flottille de clients, natifs de bureau, web de bureau, mobiles, intégrations back-end, etc ... Cette décision n'était pas sans inconvénients, mais avec du recul 20/20, je peux dire que je le referais . Permettez-moi d'indiquer certains des compromis impliqués.

Avantages

  • Souplesse. Qu'il s'agisse d'une demande de création d'une application mobile pour améliorer l'expérience de bureau ou d'une demande d'intégration avec le back-end de SAP, tout devient plus facile lorsque vous avez déjà une API à appeler. Lorsque vous obtiendrez suffisamment de ces demandes, vous évoluerez organiquement vers une API, et la seule question est de savoir si elle a un service Web standard en face d'elle, ou s'il s'agit d'une API interne où les services Web sont faits sur mesure.

  • Évolutivité (de l'équipe). Dans notre cas, nous avons de nombreux groupes de développeurs différents qui s'appuient tous sur cette API. Nous avons même des équipes API dédiées, qui parlent aux différents groupes, résument les besoins et en construisent une API polyvalente. On en est arrivé au point où on ne nous dit même plus que les gens construisent des trucs au-dessus de l'API, et pas tous ceux qui le font travaillent pour notre entreprise.

  • Sécurité. Une séparation claire entre les parties dangereuses et sûres de votre base de code est utile pour raisonner la sécurité. Brouiller l'interface utilisateur et le code principal a tendance à confondre les choses.

compromis

  • Souplesse. Vous devez faire le travail pour construire "correctement" quelque chose dans l'API. Il n'est pas possible d'exécuter rapidement une requête DB depuis l'intérieur du code de l'interface utilisateur pour résoudre un problème spécifique. De plus, les API qui sont réellement réutilisables doivent tenir compte de tant de cas d'utilisation que la solution rapide n'est généralement pas la bonne solution. L'API devient moins flexible pour évoluer, d'autant plus qu'il y a déjà beaucoup de code client (nous passons à une API versionnée pour cette raison).

  • Vitesse de développement initiale. Il est plus lent de développer API-first, sans l'ombre d'un doute. Vous ne le récupérez que lorsque vous avez suffisamment de clients intégrés à l'API. Mais vous constatez ensuite que vous avez besoin de 3 implémentations client différentes avant que votre API ait évolué pour être suffisamment générique. Nous avons constaté que la plupart de nos conceptions initiales d'API étaient erronées et ont dû revoir fortement nos directives sur la façon de créer des services Web.

Harengs rouges

Vous en avez mentionné un tas. Ils n'ont pas vraiment d'importance dans la pratique.

  • Abstraction. Votre API devient suffisamment abstraite pour couvrir tous les cas d'utilisation que votre produit doit servir, et rien de plus. Même sans services Web, vous aurez soit une API interne qui le fait, soit beaucoup de code en double. Je préfère l'abstraction à la duplication.

  • Abandon de la pile MVC côté serveur. De nos jours, presque tous les systèmes auront besoin d'une application mobile après un certain temps. Lorsque vous créez ensuite des services Web pour répondre à cette application mobile, vous devrez de toute façon déterminer comment effectuer l'authentification et l'autorisation dans un contexte d'API. C'est en fait moins de travail lorsque vous n'avez qu'une seule façon de le faire, la façon dont vous le faites dans vos services Web.

  • Opérations en vrac. Généralement résolu en créant une API en bloc qui lance un travail principal et renvoie un identifiant de travail pour la requête d'état. Ce n'est pas si grave.

  • Débogage. J'ai trouvé que dans l'ensemble, il est devenu un peu plus facile de dépanner le système. Vous pouvez toujours définir des points d'arrêt dans le code frontal et principal, donc dans la pratique, ce n'est pas si difficile à parcourir, et vous avez la possibilité de créer des tests d'api automatisés et d'instrumenter l'api pour surveiller les systèmes de production.

  • Beaucoup d'opérations indépendantes. Cela dépend de la façon dont vous concevez les choses. Si vous insistez pour avoir une API CRUD pure, alors oui, vous souffrirez de ce problème. Mais avoir des API CQRS à augmenter est généralement une bonne idée, et si vous vous êtes assuré d'avoir une API interne pour laquelle les services sont frontaux, vous pouvez facilement réutiliser cette API interne pour construire des services pour ces spécifiques scénario.

En résumé

Dans un système utilisé dans suffisamment de contextes différents, une API évoluera naturellement car c'est le moyen le plus simple de répondre à tous les besoins. Mais il y a certainement un cas de YAGNI en cours. Il y a des compromis et cela n'a de sens que lorsque cela a du sens. L'essentiel est de ne pas être dogmatique et de rester ouvert aux différentes approches architecturales pour répondre aux besoins évolutifs du produit.

22
Joeri Sebrechts

Ce que votre collègue décrit est une architecture orientée services. Cela peut être un moyen extrêmement évolutif, testable et sensé de coder, mais cela dépend vraiment de ce que vous faites.

Il y a quelques avantages significatifs à SOA, que j'essaierai d'énumérer:

Évolutivité

Étant donné que votre back-end est découplé, votre front-end devient juste une série de modèles, même des fichiers plats. Les fichiers plats sont extrêmement rapides et bon marché à servir à partir de n'importe quel CDN. Ils peuvent être minifiés et précompilés en HTML statique, puis remplis de données côté client.

Votre API doit rester cohérente, mais peut être échangée contre une technologie plus rapide sans casser votre pile si vous devenez trop grand pour votre technologie existante. Vous pouvez le refaire dans Go par exemple. Vous pouvez le reconstruire au coup par coup et répartir la charge sur les serveurs. Tant que l'interface reste la même, la technologie est abstraite.

Testabilité

MVC démarre généralement propre, mais dans la pratique, les contrôleurs restent rarement concentrés sur une seule ressource. Plus vos méthodes de contrôleur font de choses, moins elles deviennent testables.

Une API contourne ce problème. Chaque appel d'API extrait une ressource et la sert. Propre et testable.

Séparation garantie des préoccupations

Votre extrémité avant et arrière sont entièrement divorcées. Vous pouvez confier l'interface à un autre développeur ou à un concepteur. C'est MVC porté à un autre niveau. Je suis sûr que vous ne voudriez pas abandonner MVC. SOA est MVC mais plus encore.

Inconvénients

Il y a bien sûr certains inconvénients. Un monolithe est souvent plus rapide à démarrer. C'est peut-être ce à quoi vous êtes habitué. Il peut s'intégrer mieux dans votre pile. Vos outils peuvent être optimisés pour la création de monolithes.

À mon avis, aucune de ces raisons n'est particulièrement bonne et vous voudrez peut-être envisager de vous réorganiser si elles s'appliquent à vous.

10
superluminary

Il y a beaucoup de bonnes réponses ici, je vais donc simplement ajouter mon expérience de mise en œuvre.

Voici comment je fais les choses:

  • Créez une couche d'accès à la base de données qui gère toutes/uniquement les interactions de base de données (généralement, le SQL manuel est utilisé pour la vitesse et le contrôle, pas d'ORM) . Insérer, mettre à jour, supprimer, sélectionner ...
  • Créez un interface (virtual class) qui expose/applique les fonctions API dont j'ai besoin. Une fois implémentés, ils utiliseront les fonctions DBAL hautement spécialisées pour obtenir les résultats. Cela m'aide également à appliquer l'API au niveau du compilateur, donc je m'assure que l'implémentation Server + API possède toutes les fonctions intégrées.
  • Créez une deuxième couche qui implémente l'interface (il s'agit de l'API réelle) et applique les restrictions de sécurité. Vous interagissez également avec des API externes ici.
  • Le site Web utilisera directement la deuxième couche (pour les performances) sans passer par une API accessible à distance (comme SOAP , JSON) .
  • Un serveur autonome est construit qui implémente l'interface et expose la deuxième couche comme une véritable API accessible à distance aux clients de bureau/mobiles externes (accès non-site Web) . Il ne fait que décoder les demandes et coder les réponses et gérer/déconnecter les clients. Il prend également en charge les capacités de pushback pour informer en masse les clients des événements générés par d'autres pairs connectés (fonctionnalité dont un site Web n'a généralement pas besoin) .

Donc, techniquement, l'API est la deuxième couche. Vous l'utilisez directement avec le site Web et l'exposez à des clients distants via un serveur. Le code est réutilisé et aucun morceau de code réutilisable n'est jamais en ligne. (vivre et mourir selon cette règle et tout est génial) Aide à la maintenabilité, aux tests ... tout.

Vous ne connectez jamais le site Web au serveur API de bureau/mobile (sauf si votre site est AJAX et fonctionne sur JSON) Mais si le site affiche du contenu dynamique dans le balisage, le passage à une API intermédiaire améliorera vos performances. Le site Web doit être rapide! L'accès client à distance peut être un peu plus lent.

PS : Oui, la maintenance est un peu plus complexe car plus de roues fonctionnent ensemble mais c'est plus facile à long terme. Donc, si votre projet est destiné à vivre pendant un certain temps et est légèrement complexe, ayez toujours une API. Il est également beaucoup plus facile de tester chaque couche par elle-même.

7
CodeAngry

Le point de discorde n'est pas si vous devez utiliser une API, mais ce qu'est réellement une "API". La seule alternative à l'utilisation d'une API conçue est d'utiliser une API qui est un désordre de code aléatoire. Vous écrivez qu'une API rend les choses "trop flexibles", ce qui à son tour rend les choses ingérables. Cela indique une incompréhension complète et approfondie de ce qu'est une API. Si ce malentendu n'est pas partagé entre vous et votre collègue, alors vous avez perdu beaucoup de temps en argumentant sur des choses complètement différentes.

En n'utilisant pas une API bien définie, vous pouvez faire ce que vous voulez. Par définition, c'est l'option la plus flexible. De plus, par définition, "faites ce que vous voulez" est toujours une API. Le travail niquement d'une API consiste à supprimer la flexibilité. En supprimant la flexibilité, une bonne API encourage un utilisateur à faire des choses similaires de manière similaire.

Bien sûr, une mauvaise API peut fournir trop ou trop peu de flexibilité, voire les deux en même temps. Une API vraiment mal conçue peut tuer un projet encore plus rapidement que l'approche "n'importe quoi". Cependant, la meilleure pratique consiste simplement à avoir des programmeurs compétents qui développent et font évoluer l'API parallèlement à votre application.

Exemple

• Beaucoup d'opérations indépendantes qui nécessiteront beaucoup de va-et-vient, par exemple, du code peut obtenir l'utilisateur actuel, vérifier que l'utilisateur est dans le rôle d'administrateur, obtenir la société à laquelle l'utilisateur appartient, obtenir une liste des autres membres, les envoyer tout un e-mail. Cela nécessiterait beaucoup d'appels API, ou l'écriture d'une méthode sur mesure pour la tâche spécifique que vous souhaitez, où le seul avantage de cette méthode sur mesure serait la rapidité mais l'inconvénient serait qu'elle serait inflexible.

Le nombre d'appels d'API que cela nécessiterait sur une API décente serait probablement de 1. Oui, c'est inflexible, mais pourquoi voudriez-vous qu'il soit flexible?

7
Peter

Version courte: Votre contrôleur est effectivement une API quoi qu'il arrive; bien qu'ASP.NET puisse masquer cela.

Version plus longue:

Pensez à une application Web MVC de base qui fournit des informations sur la bière et vous en vend éventuellement une. À quoi ressemblent les itinéraires?

/sign_in
/sign_out
/beer
/beer/{beer_name}
/order
/order/{order_number}

Dans une application Web normale, il existe probablement quelques itinéraires auxiliaires comme:

/beer/new
/beer/{beer_name}/edit
/beer/{beer_name}/delete
/order/new
/order/{order_number}/edit
/order/{order_number}/delete

Dans une API Web, ceux-ci ne sont pas requis, car ils sont déduits de la méthode HTTP.

Compte tenu de la symétrie ci-dessus, je pense que cela démontre que votre API et votre contrôleur sont si proches qu'ils pourraient tout aussi bien être la même chose.

Après avoir creusé, j'ai déterminé que ceci pourrait être l'état des choses pour vous selon la version d'ASP.NET que vous utilisez. Les anciens MVC 5 et antérieurs manquent des conventions et de l'interface pour unifier solidement les deux implémentations. Dans les anciennes versions, Web App renvoie remplit une vue tandis que l'API donne une HttpResponse. Dans les deux cas, cependant, ils génèrent la exactement la même réponse sémantiquement.

Si vous utilisez MVC 6, vous obtenez les deux dans une classe de contrôleur unifiée qui peut être intelligente sur ce qu'elle retourne. Je n'ai pas trouvé de bon code ASP exemple pour ce modèle, mais j'ai trouvé du code Rails avec le même modèle. Considérez ce contrôleur pour les "likes" du projet Diaspora . Chaque méthode de contrôleur a des routes définies par une "convention ingénieuse" ici qui équivalent au LCRUD dans une API.

Si vous lisez les implémentations, cependant, chacune peut éventuellement répondre au HTML, au HTML mobile ou au JSON. Ceci, combiné à une convention pour trouver les vues, unifie complètement l'application Web et l'API Web. Vous remarquerez également que toutes les méthodes ne fournissent pas réellement chaque réponse (ce qui est logique, car l'interface utilisateur peut nécessiter des méthodes que l'API ne propose pas, et vice versa).

Il s'agit d'un décalage d'impédance car ASP.NET a tout compris tardivement alors que Rails a embrassé la symétrie depuis un certain temps et le rend très clair.

Spéculation:

Votre collègue a probablement raison et tort, selon la version ASP que vous utilisez. Sous l'ancienne version MVC, la différence entre l'API et l'application en faisait probablement une "meilleure pratique") pour construire l'API à l'avance parce que le modèle d'ASP.NET ne permettait pas vraiment une bonne réutilisation du code.

Avec le plus récent, il est plus logique d'utiliser du code unifié car il a été plus facile de réutiliser le code avec la classe de base du contrôleur unifié.

Dans les deux cas, cependant, le contrôleur est effectivement l'API.

4
Jayson

Il a dit que notre code était trop étroitement couplé. Par exemple, si nous voulions également une application de bureau, nous ne pourrions pas utiliser notre code existant.

Eh bien, vous? Sinon, alors c'est une déclaration assez peu pertinente.

Je dirais que si vous prévoyez de créer une application nouvelle en 2015, alors examinez sérieusement quelque chose avec une interface utilisateur qui implique une API et non des pages HTML générées par le serveur. Il y a des coûts clairs mais aussi des avantages clairs.

Mais si vous avez un site existant sans plans concrets pour avoir plusieurs interfaces différentes (pour autant que je sache), alors ses commentaires sont tout simplement hors de propos.

4
RemcoGerlich

Lorsque j'ai commencé ma carrière en 2006, ce type d'architecture faisait fureur dans le monde .NET. J'ai travaillé sur 3 projets distincts conçus au milieu des années 2000 avec un service web entre la couche logique métier et le frontend web. Bien sûr, ces jours-ci, les services Web étaient SOAP mais c'est toujours la même architecture. Les avantages supposés étaient la possibilité de basculer entre le front ou le backend et même de développer un programme de bureau. En fin de compte, YAGNI s'est avéré être vrai . Je n'ai jamais rien vu de tel. Pendant tout ce temps, je n'ai vu que le coût du fractionnement du projet de cette façon. J'ai même fini par arracher le service Web de l'un des projets (il a fallu six mois pour le supprimer étape par étape tout en faire d'autres choses) et toute l'équipe était heureuse. Je n'ai jamais essayé cette approche depuis et je ne le ferai pas à moins d'avoir une raison très précise. 5 ans d'expérience en essayant cette architecture m'ont appris que je n'en aurai pas besoin et pas beaucoup d'experts me dire le contraire va me convaincre que je le ferai. Seul un projet où j'en ai besoin peut le faire.

Cela étant dit, je m'efforce de développer une couche entre la logique métier et les contrôleurs/présentateurs. Par exemple, j'ai une couche de service, je n'expose jamais de requêtes, j'utilise des interfaces pour tous mes services et je les injecte dans des contrôleurs avec IoC. Si jamais j'ai besoin d'un service Web dans mon architecture, je pourrai l'introduire à un coût raisonnable. Je ne veux tout simplement pas payer ce coût à l'avance.

De plus, j'aime bien l'idée des microservices mais ma compréhension est que les microservices signifient des modules verticaux plutôt que des couches horizontales. Par exemple, si vous créez Facebook, la fonction de chat sera un service distinct déployé séparément sur ses propres serveurs, etc. C'est le type de services indépendants que j'encouragerais.

2
Stilgar

Des tiers l'utiliseront-ils? Oui, vous devriez.

Vous prévoyez de le réutiliser dans un avenir pas si lointain? Oui, vous devriez.
Vous serez votre tiers , ayant un documenté - ou documentable - ou utilisable par -Les API tierces vous fourniront une réutilisabilité et une modularité solides.

Vous êtes pressé? Non, vous ne devriez pas.
. Il est plus important d'avoir quelque chose qui fonctionne (même avec une mauvaise conception interne, car elle peut et sera refactorisée) que de ne rien avoir du tout. (mais avec un design interne incroyable , wohoo)

Le front-end pourrait ne jamais voir le jour pour des raisons? Oui, vous devriez.
J'ai ajouté cette raison parce que, bien, cela m'est arrivé beaucoup.
Et au moins je me retrouve avec mes composants pour réutiliser et redistribuer etc.

2
ZJR

Il y a de bonnes réponses ici. Je poste cela comme une réponse partielle; ce serait peut-être mieux comme commentaire. Cependant, coller le même commentaire sur de nombreux messages n'est pas bon.

On ne peut pas prétendre que YAGNI est une raison pour ne pas créer d'API.

L'API est un point de terminaison de test naturel et logique. Ainsi dès le jour 0, il y a deux applications qui utilisent l'API: l'interface utilisateur et la suite de tests. L'un est destiné aux humains, l'autre aux machines. Ils sont nécessairement différents. Tester le comportement frontal est une tâche très différente de celle de tester le comportement principal. Ainsi, les techniques, et probablement les outils, sont complètement différents. L'API permet d'utiliser le meilleur outil pour le travail. De plus, avec la séparation offerte par l'API, les testeurs frontaux n'ont pas à tester la fonctionnalité principale.

L'API permet également de garder les codeurs frontaux à l'écart des préoccupations du codeur principal, et vice-versa. Ce sont des compétences très différentes dans notre entreprise; l'API nous permet de nous concentrer là où nous sommes les plus forts.

1
Tony Ennis