Réconcilier les développeurs mobiles avec votre SI (BFF, API-Gateway et GraphQL à la rescousse)

Olivier Gauthier
BeTomorrow

--

Dans notre entreprise nous développons principalement des applications mobiles pour des clients tiers. Généralement c’est pour s’intégrer avec leurs services développés en interne et nous rencontrons très souvent les mêmes problèmes. Regardons cela de plus près avec un cas d’école.

IMDb veut une nouvelle application mobile

Imaginons, par exemple, qu’IMDb vienne nous voir pour développer une application mobile. Cette application devra faire à peu près la même chose que leur site mais présenté différemment. En effet si nous regardons la page d’accueil d’IMDb, il y a énormément de choses et tout ne va pas rentrer sur un écran de smartphone. De plus certaines fonctionnalités ont plus d’importance pour un utilisateur nomade comme trouver un cinéma pas loin de sa position, ou lancer un itinéraire pour aller au cinéma qui passe le film qui nous intéresse. Ayant développé leur site web avec des technos “récentes”, IMDb bénéficie maintenant d’APIs REST développées pour le site. Naturellement ils veulent que nous les réutilisions pour développer notre application.

L’application

Pour l’exemple nous allons prendre juste une petite partie de l’application : la recherche. Les graphistes se sont lâchés et nous ont sorti un truc en flat design qui reprend les codes à la mode, avec des résultats de recherche sous forme de cartes contenant des informations assez complètes comme le titre, les notes, la date de sortie, les 3 principaux acteurs, l’affiche du film et un début de synopsis.

Le développement et ses problèmes

Pour composer cet écran nous avons besoin de plusieurs informations et toutes ne sont pas retournées par l’API de recherche. En effet, pour les besoins du site, seuls l’affiche, le titre et l’année sont renvoyés. Il nous manque quelques informations qu’il va falloir aller chercher ailleurs.

Tadaaaaaaa. Les problèmes commencent.

Tout d’abord, pour aller chercher ces informations, nous allons devoir faire plusieurs appels à une autre API. Dans un monde idéal, un seul aurait suffi. D’autre part, la recherche ne renvoie pas que des films mais aussi des articles, des acteurs, des séries, des show TV, etc. Nous allons devoir filtrer les résultats nous-même. En soi ce n’est pas plus dérangeant que ça, en revanche l’utilisateur va télécharger plein de données pour rien. De plus un utilisateur mobile passe rarement par une connexion fibre ultra stable mais se déplace, change de routeur etc. Bref, plus nous utilisons le réseau plus nous nous donnons de chances d’avoir des erreurs de connexion. Nous pouvons en passer certaines sous silence mais pour d’autres, comment les gérer ? En tant qu’utilisateur, avoir une popup nous disant qu’il y a eu une erreur réseau et qu’il faut réessayer plus tard alors que le téléphone nous montre 5 belles bûchettes bien pleines, c’est vraiment énervant. De plus la partie réseau sur un mobile est assez énergivore, plus nous l’utilisons, plus notre application vide les précieux mAh si chers à nos utilisateurs.

Nous en parlons à IMDb qui décide de faire ajouter les informations dans les résultats de recherche et de rajouter un paramètre pour que nous puissions sélectionner uniquement les réponses de type films. Vu leur cycle de développement cela prendra un peu de temps avant d’arriver sur l’environnement de test ce qui nous retardera un peu.

Quelques mois plus tard nous sortons l’application et tout fonctionne à merveille. Mais IMDb souhaite maintenant modifier sa façon de noter les films et séparer la note en 2 pour avoir la note spectateur et la note presse, un peu comme sur Allociné. Ils décident alors de changer la réponse renvoyée par le service de recherche et de remplacer le champ “rating” par “users_rating” et “press_rating”.

Tadaaaaaaa. Les problèmes continuent.

IMDb est habitué à changer et déployer ses APIs en même temps que le site et à ne pas avoir de problème de cohérence entre les 2. Seulement voilà, côté mobile nous ne maîtrisons pas le changement de l’application. Même si nous mettons à jour au même moment notre application, les utilisateurs eux feront la mise à jour uniquement quand ils le décideront. De plus Apple impose une phase de revue pendant laquelle les 2 versions de l’application doivent cohabiter (la nouvelle pour la revue Apple, l’ancienne pour les utilisateurs). Dès le début nous avons bien mis un système permettant de bloquer l’utilisation de l’application à distance et inciter l’utilisateur à la mettre à jour mais nous trouvons que c’est trop agressif pour les utilisateurs et préférons éviter de l’utiliser. IMDb va laisser 3 champs “rating” dans la réponse pour ne pas bloquer les utilisateurs de l’application mobile.

Résumons un peu tous les problèmes :

  • ❌ Récupération de données inutiles
  • ❌ Multiplication de requêtes
  • ❌ Latence entre les équipes serveurs et mobiles
  • ❌ Évolution des APIs
  • ❌ Plus grand nombre d’erreurs réseau possibles
  • ❌ Consommation de la batterie

En conclusion faire cohabiter plusieurs “clients” offrant des expériences utilisateurs différentes sur une même API n’a pas l’air d’être une bonne idée. Mais comment peut-on faire mieux ? D’ailleurs comment font les autres ?

Backend For Frontend (BFF)

C’est une solution mise en place dans des sociétés comme Netflix, SoundCloud et d’autres. Derrière ce nom se cache une stratégie assez simple qui consiste à se remettre dans la situation qu’IMDb avait au départ lorsqu’elle a développé son site web et ses APIs. Une application/expérience utilisateur/client implique une nouvelle API spécifique. Avec cette solution, le site continue d’évoluer à sa vitesse dans son coin avec ses propres APIs. De nouveaux besoins pour la partie mobile ne nécessitent pas de nouveaux développements sur les APIs du site ni de phase de test et de recette de celui-ci. Seules de nouvelles APIs sont développées pour les besoins de l’application mobile, et hébergées indépendamment du reste. De plus l’équipe de développement des APIs fait partie intégrante de l’équipe Mobile et développe les nouvelles APIs conjointement avec le mobile.

Reprenons notre liste de problèmes précédente :

  • Récupération de données inutiles : La nouvelle API ne renvoie que ce qui est utile
  • Multiplication des requêtes : La nouvelle API nous renvoie les résultats de la recherche en une seule requête
  • Latence entre les équipes serveur et mobile : Les développeurs des APIs font partie de l’équipe mobile et développent les APIs au besoin. Cependant lorsqu’il y a besoin de nouvelles fonctionnalités serveur, nous retrouvons de la latence
  • Évolution des APIs : Il n’y a plus de dépendance entre le site et l’application mobile. L’évolution de l’un n’impacte pas l’autre.
  • Plus grand nombre d’erreurs réseau possibles : Nous avons limité la taille des données et le nombre de requêtes. Il faut quand même gérer les problèmes réseaux dans l’application mais on limite le nombre d’occasion d’en avoir
  • Consommation de la batterie : Nous avons limité notre utilisation du réseau et la consommation de la batterie sur cette partie.

Cette solution peut parfois être compliquée à mettre en place en fonction des projets. Pour commencer il va falloir convaincre le client que c’est la bonne solution et que réutiliser ses APIs, même si ça parait être une manière évidente de gagner du temps, finira par faire l’inverse. Ensuite il peut être difficile d’intégrer les développeurs d’APIs dans l’équipe mobile, cela nécessite des accès aux services internes qui eux mêmes doivent exposer les données et les opérations dont nous avons besoin.

Certains diront que nous n’avons fait que déplacer le problème. En fait nous déplaçons une partie du problème et nous le réduisons. Même si, lorsqu’il nous manque une donnée, nous allons retrouver notre latence initiale dans le développement côté services internes, cela ne représente qu’un seul point parmi les problèmes listés précédemment. De plus côté API nous allons pouvoir cacher les données aussi bien en entrée qu’en sortie et alléger la charge aussi bien sur nos APIs que sur notre SI.

API-Gateway

Vous avez peut-être déjà entendu parler d’API-Gateway et vous ne voyez pas très bien la différence avec le BFF ? Et bien c’est normal, en fait le BFF est une variante du pattern API-Gateway.

Le but de l’API-Gateway est de rendre accessible notre multitude de services internes à des clients externes sans qu’ils aient besoin de savoir où ils se trouvent, comment ils fonctionnent etc. Le pattern définit une passerelle servant de point d’entrée et expose tout ça généralement via des APIs REST. Cela va permettre de centraliser des aspects comme l’authentification, la sécurisation ou bien la facturation.

GraphQL

Une autre solution qui pourrait convenir est GraphQL.

Facebook collecte énormément de données et chacun peut créer de nouveaux usages en les exploitant au travers d’une API unique. Ne maîtrisant pas les clients, Facebook se devait de définir une API flexible qui convienne à tous. Ils ont donc commencé à mettre en place la GraphAPI en 2012 et en ont fait une spécification en 2015. Il existe aujourd’hui des implémentations pour une grande variété de langages.

Pour faire simple GraphQL définit des données et leurs liens entre elles. Il va permettre ensuite de personnaliser le format de la réponse souhaitée directement dans la requête que le client envoie. De cette façon c’est un peu comme si le développeur mobile était aussi le développeur API. Il peut décider de ce que va lui retourner chaque requête pour correspondre au mieux à son besoin. Dans notre exemple précédent l’API de recherche depuis le site ne renverrait que ce qu’il affiche et la même API de recherche depuis l’application mobile renverrait une réponse beaucoup plus complète, sans avoir à modifier le serveur. De plus GraphQL vient avec “Graphiql”, un outil d’exploration et de documentation d’APIs très complet, ce qui est un vrai plus lorsque plusieurs équipes doivent travailler avec vos APIs.

Si nous reprenons notre liste de problèmes précédente voici ce que l’on obtient :

  • Récupération de données inutiles : GrapheQL ne renvoie que les données demandées
  • Multiplication des requêtes : GrapheQL nous permet de composer entre les différentes données et de récupérer tout un tas d’objets différents en une seule requête. Ça va même plus loin que le BFF puisque nous pouvons faire plusieurs requêtes GraphQL en un seul appel réseau.
  • Latence entre les équipes serveurs et le mobile : C’est le développeur mobile qui définit ce dont il a besoin lorsqu’il développe sa fonctionnalité. En revanche si la donnée n’est pas définie par la GraphQL, il faudra demander à la rajouter et nous retrouvons la latence initiale.
  • ➕ Évolution des APIs : Pour notre cas rien ne change, si nous changeons les notes, il faudra conserver les 3 pour la cohabitation des clients. Mais le site et la nouvelle version de l’application ne recevront plus le champ obsolète dans leur réponse.
  • Plus grand nombre d’erreurs réseau possibles : Nous avons limité la taille des données et le nombre de requêtes. Il faut quand même gérer les problèmes réseaux dans l’application mais nous limitons le nombre d’occasions d’en avoir.
  • Consommation de la batterie : Nous avons limité notre utilisation du réseau et la consommation de la batterie sur cette partie.

Comme nous pouvons le voir la situation est nettement améliorée. Cela implique quand même une mise en place côté serveur qui peut s’avérer un peu compliquée. Il faudra être vigilant dans la façon de récupérer les données et mettre en place des caches intermédiaires.

Pour donner un exemple, dans notre recherche nous récupérons des informations sur les films renvoyés par la recherche. Par défaut, GraphQL itérera un à un sur les films renvoyés par le service de recherche pour composer la réponse, ce qui peut créer une charge non négligeable. On peut néanmoins mettre en place les DataLoader de GraphQL pour charger tous les films en un coup au lieu de le faire un par un, ce qui peut améliorer considérablement les performances.

Conclusion

A l’heure du SCRUM et de l’agilité, favorisant des itérations courtes de 2 ou 3 semaines, il est important que les APIs puissent évoluer rapidement. C’est un vrai problème de devoir commander des changements d’APIs qui ne seront disponibles que dans plusieurs mois, surtout si l’application est fortement dépendante du SI. Nous pouvons bien évidement mocker le serveur mais cela nous éloigne de l’esprit Agile, et nous force à trainer des retours et bugs potentiels pendant plusieurs mois.

Nous avons vu qu’il existe plusieurs solutions pour cela. Elles ne sont pas sans impact. D’un point de vue technique, en fonction de la solution choisie, cela nécessitera probablement :

  • De l’infrastructure pour gérer ces passerelles d’APIs
  • De revoir les technologies utilisées pour fournir ces APIs
  • De standardiser ses échanges entre APIs et SI.

Mais le plus dur sera sûrement de faire accepter cette solution par les différents intervenants :

  • Le client, devra accepter de réinvestir dans des APIs qu’il pensait avoir déjà payées.
  • Les équipes serveur, devront lâcher un peu leur bébé et accepter que quelqu’un d’autre s’occupe de la partie API. Ou bien ils devront remettre en question leurs acquis et accepter d’abandonner le standard REST au profit du GraphQL.

Malgré tout, ne pas le faire, déporte et complexifie cette problématique sur l’équipe mobile et nuit à l’expérience utilisateur finale.

Si vous faites beaucoup de lectures sur votre SI, le GraphQL peut être avantageux. Si en revanche il y a beaucoup d’écritures et d’opérations avec le SI, le GraphQL perd un peu de son intérêt et l’approche BFF est peut-être plus appropriée.

Alors, qu’allez-vous utiliser pour votre prochaine API ? Backend For Frontend ? API-Gateway ? GraphQL ? Autre ?

--

--