Bonjour à tous,

Les microservices se sont développés de plus en plus depuis mi-2015 avec l’arrivée de langages tels que Angular, React, … Aujourd’hui mon but est de vous expliquer d’abord théoriquement puis concrètement comment développer un micro service ou migrer votre application vers une architecture en micro service et ce que cela va vous apporter. Pour cela je vais utiliser des langages simples : PHP en langage serveur et JavaScript / JAVA en langage client. C’est parti !

Qu’est ce qu’un micro service ?

Définition

Avant de comprendre comment fonctionne un micro service, il faut que je définisse ce qu’est un micro service :

En informatique, les microservices sont un style d’architecture logicielle à partir duquel un ensemble complexe d’applications est décomposé en plusieurs processus indépendants et faiblement couplés, souvent spécialisés dans une seule tâche. Les processus indépendants communiquent les uns avec les autres en utilisant des API

Il y a deux notions importantes dans la définition de Wikipedia :

  • “Un ensemble complexe d’applications est décomposé en plusieurs processus indépendants
  • “Les processus indépendants communiquent les uns avec les autres en utilisant des API”

Premièrement, nous savons qu’en programmation, lorsque nous sommes face à un problème, il faut le décomposer en sous-problèmes (fonctions, méthodes) afin de simplifier sa maintenabilité, son utilisation et son développement. Les microservices se bases sur le même principe, celui de décomposition. Nous allons donc devoir définir toutes les tâches que nous voulons que notre application puisse faire et les implémenter à travers une API.

Une API, ou en français “Interface de programmation” va nous permettre de faire communiquer notre application avec les micro service de son écosystème. Nous allons donc avoir notre application au centre et tout autour d’elle les actions qu’elle peut faire vont être des adresses (routes) différentes vers notre API. Mais je reviendrai plus précisément sur cela plus tard.

Avantages

Les avantages d’une architecture en microservices sont nombreux. Pour n’en citer que quelques-uns :

  • La maintenabilité : Si notre application est décomposée en tâches et que chaque tâche est gérée indépendamment les unes des autres alors lorsqu’un problème survient, il est simple d’identifier la tâche qui pose problème
  • La visualisation : Au lieu d’avoir des méthodes qui en appellent d’autres et ainsi de suite dans une application normale. En utilisant une API on doit fragmenter notre code et l’on possède un fichier pour chaque action. On peut par exemple construire un graphe ayant pour node chaque tâches réalisable.
  • L’évolutivité : Si l’on souhaite rajouter une action à effectuer par l’application, il suffit de créer une nouvelle interface (un nouveau fichier) à l’API et cela fonctionne directement.
  • La compatibilité : Nous allons le voir plus tard mais pour utiliser échanger les données entre une application et une API il faut normaliser le flux de données. Cela veut dire que l’on peut créer des applications sur toutes les plateformes que l’on souhaite du moment où ce langage accepte les expressions régulières.

L’architecture d’une application en microservice

Il y a une illustration que j’apprécie particulièrement à propos des microservices :

Cela nous montre bien que l’on a des applications d’un côté (sur différentes plateformes, en différents langages : iOS = Swift, Android = JAVA, Web = JS, PHP, …) ceux sont les clients. Au centre les méthodes de l’API (GET, POST, PUT, DELETE, …). Entre l’API et les clients des flux de données dans des langages de format de données textuel (JSON, XML). À droite, le serveur, celui qui stocke et process les données. Et entre l’API et le serveur un flux HTTP pour envoyer des requêtes et process les données.

Notre architecture

Maintenant que nous avons vu l’architecture d’une application en micro service, nous allons mettre cette théorie en application tout en explicitant les concepts que nous utiliserons.

Stocker les données

Dans un premier temps il faut nous demander comment nous allons stocker les données de notre application. Pour cela, rien de plus simple, une Base de Données MySQL fera l’affaire. Dans dans notre étude de cas (création d’un Chat) nous avons besoin de seulement deux tables :

Chat : ID | ID_table | ID_pseudo | pseudo | message | dateMessage  

Channel : ID | channel | dateCreate

Quelques explications :

La première table stockera l’ensemble des messages envoyés et les envoyeurs.

La seconde est dispensable mais permet de garder des stats sur les channels

Maintenant que l’on a un moyen de stocker nos données nous allons devoir comprendre comment communiquer avec cette base de données. Nous pourrions simplement connecter directement nos applications à cette base et exécuter les requêtes mais la notion de microservice perdrait de son sens. Il nous faut maintenant créer notre API.

Le flux de données – proposer les données

Notre API va nous service de protocole de communication avec notre base de données. Avant de construire notre API, il faut analyser les besoins que nos applications auront. On souhaite pouvoir :

  • Créer un channel
  • Rejoindre un channel
  • Voir tous les channels créés
  • Envoyer un message
  • Voir tous les messages envoyés à un channel.

Pour ces 5 actions nous allons créer 5 fichiers avec l’extension du langage serveur que nous souhaitons utiliser (ici PHP) :

  • createChannel.php
  • joinChannel.php
  • getChannels.php
  • sendMessage.php
  • getMessages.php

Nous allons maintenant voir toute la logique d’une API :

pour créer un channel. Sur une simple page WEB nous aurions créé un formulaire qui envoyait les paramètres au script PHP puis il aurait inséré les données dans la Base. Ici c’est le même principe que si le formulaire était de type “GET”. Je m’explique :

Avec PHP on peut récupérer les paramètres d’une URL après le nom de la page. Par exemple:

/createChannel.php?name=monSuperChannel

En PHP on pourra récupérer la valeur “monSuperChannel” avec $_GET[‘name’]. Vous devriez voir où je souhaite en venir. En JavaScript on peut récupérer les données d’une page WEB via la fonction fetch(…); Si avec cette fonction on accède à la page /createChannel.php?name=monSuperChannel Le script PHP ne fera pas la différence avec le cas où c’est un individu sur la page. Et donc le script va s’exécuter logiquement et insérer les données dans la Base.

Pour structure notre API il nous faut savoir les structure d’URL auxquels nous accèderons depuis nos applications client. Et ce que ces URL reverront comme données.

J’utiliserai {{nom_paramètre}} pour un paramètre que l’on placera dans nos clients.

- createChannel.php?name={{name}} 

renvoie 0 si le script s’est exécuté correctement,
1 sinon

- joinChannel.php?name={{name}}

renvoie le hash du nom du channel si le script s’est exécuté correctement,
rien sinon

- getChannels.php  

renvoie tous les channels présents dans la base de données. Nous verrons comment ensuite

- sendMessage.php?id_table={{hash_channel}}&pseudo={{pseudo_envoyeur}}&message={{message}}

renvoie 0 si le script s’est exécuté correctement,
1 sinon

- getMessages.php?id_table={{hash_channel}}  

renvoie tous les messages du channel

Je ne vais pas détailler dans cette formation comment utiliser PHP avec une base de données MySQL donc je vous laisse construire les scripts.

Le flux de données – normaliser les données

Maintenant que nos scripts sont en capacité de récupérer sous forme de requete (mysqli_query(…)) les données que l’on souhaite, nous allons devoir normaliser ces données afin de pouvoir les récupérer dans un autre langage. Pour cela nous allons utiliser le langage JSON qui est un langage de format de données textuel. PHP est bien conçu et possède une fonction qui permet de transformer un tableau de données PHP en une chaîne de caractère format JSON.

Pour cela :

$result = mysqli_query(...);
echo json_encode(mysqli_fetch_all($result));

mysqli_fetch_all($result); va transformer le résultat de la requête MySQL en tableau PHP et json_encode(…); va transformer ce tableau en une chaîne de caractères JSON, que l’on affiche sur la page.

Si l’on insère quelques lignes dans notre Base de données et que l’on accède à la page /getChannels.php vous devriez avoir un rendu comme celui ci :

[["1","testChannel","2019-04-07 15:35:42"],["16","testTable2","2019-04-07 15:40:36"],["17","MaTable","2019-04-07 16:19:14"],["18","tableTestAPI","2019-04-07 17:27:38"],["19","Table03","2019-04-07 18:50:28"],["20","test01","2019-04-08 14:43:16"]]  

Ces pages seront l’interface entre notre serveur et nos clients. Le langage JSON est un langage simple facilitant l’échange de données.

Le flux de données – récupérer les données

Maintenant que nos données sont mises à disposition sur des pages WEB prévues à cet effet, il va nous falloir récupérer ces données dans nos applications. Dans un premier temps nous allons le faire tel que depuis une page WEB avec JavaScript et nous le ferons ensuite avec JAVA.

Je vais vous donner le snippet (petit morceau de code réutilisable) que j’utilise pour toutes mes communications avec des APIs :

const messages = fetch (URL)
        .then (result => result.json())
        .then (data => {
               //votre code
});

Vous pouvez mettre dans la parenthèse du second .then les lignes de codes que vous souhaitez. Le tableau dans lequel sont contenu les données est appelé data. C’est une copie exacte du tableau que vous auriez eu en PHP.

Cette formation n’est pas là pour vous former sur le JavaScript, je vous laisserai donc faire ce que vous souhaitez de ces données. À titre d’exemple j’ai ceci pour /getChannels.php :

const messages = fetch ('/api/getTables.php')
        .then (result => result.json())
        .then (data => {
            document.getElementById('getTablesTD').innerHTML = "";
            for (var i = 0; i < data.length; i++) {
                    document.getElementById('getTablesTD').innerHTML += "ID : "+data[i][0]+" ; Name : "+data[i][1]+ " ; Date : "+data[i][2]+"<br />";
            }
});

La communication avec l’API par fetch(…) :

Par la commande fetch(), cela est comme si vous visitiez la page que vous “fetchez” par vous même. Il va donc falloir remplacer les {{paramètre}} que nous avions précédemment mis dans la construction de notre API par des variables / données JavaScript. Par exemple pour envoyer un message nous avions l’interface suivante :

sendMessage.php?id_table={{hash_channel}}&pseudo={{pseudo_envoyeur}}&message={{message}}  

Nous allons donc fetch la page de cette manière (supposant que id_table, pseudo et message sont des variables JavaScript et qu’elles contiennent le contenu que l’on souhaite transmettre) :

const messages = fetch("/api/sendMessage.php?id_table=" + id_table + "&pseudo=" + pseudo + "&message=" + message)
...

Vous savez désormais communiquer avec une API avec JavaScript

Utiliser les données dans une seconde application – Application en JAVA

Maintenant que vous savez communiquer avec une API avec JavaScript. Il est intéressant de voir un langage hors WEB et qui ne possède pas de fonction prédéfinie pour convertir un format JSON en un tableau.

Comme je le disais, JAVA ne possède pas nativement de fonction permettant de convertir une chaîne de caractères JSON en un tableau d’éléments utilisable. Il va donc nous falloir utiliser des expressions régulières pour extraire les données de la chaîne.

Cependant, nous devons dans un premier temps récupérer cette chaîne de données depuis le site web. Pour cela on va utiliser les librairies java.util.; et java.net.; de JAVA. Ces librairies font parties du JDK Java de base.

on écrit donc en premières lignes de fichier :

import java.util.*;
import java.net.*;

Puis voici mon snippet pour récupérer le code source d’une page WEB :

String content = null;
URLConnection connection = null;

try {
    connection =  new URL("/api/joinTable.php? 
    nameTable=tableTestAPI").openConnection();
    Scanner scanner = new Scanner(connection.getInputStream());
    scanner.useDelimiter("\\Z");
    content += scanner.next();
    scanner.close();
}catch ( Exception ex ) {
    ex.printStackTrace();
}

System.out.println("content : "+content);

Vous récupérez dans une chaîne de caractères nommée “content” le code source de la page à laquelle vous avez voulu accéder.

Maintenant nous ne pouvons pas entièrement généraliser l’extraction de données car l’expression régulière dépendra de la dimension du tableau et de la façon dont il est construit.

Voici une suite de code menant à l’extraction d’un tableau à deux dimensions (dans le cas de /getMessages.php par exemple)

String[] jsn = content.split("\\[");
String[][] jsn2 = new String[jsn.length-2][];

for (int i = 2; i < jsn.length; i++) {
    jsn[i] = jsn[i].replaceAll("\\],", "");
    jsn2[i-2] = jsn[i].split(",");
}

for (int i = 0; i < jsn2.length; i++) {
    for (int j = 0; j < jsn2[i].length; j++) {
        jsn2[i][j] = jsn2[i][j].replaceAll("\\]", "");
        jsn2[i][j] = jsn2[i][j].replaceAll("\"", "");
    }
}

Le tableau jsn2 que vous obtenez à la fin est une copie exacte du tableau PHP obtenu après la requête.

Vous savez désormais utiliser une API WEB avec JAVA.

Pistes d’améliorations

Afin que vous assimiliez bien les concepts autour des micro services et de leur utilisation, je vais vous donner quelques pistes d’amélioration de notre architecture actuelle :

API :

  • Afin de généraliser les données encore plus nous pourrions modifier les tableaux PHP afin qu’ils soient tous de deux dimensions avant encodage.
  • Nous pourrions sécuriser l’API en obligeant les utilisateurs à avoir un paramètre en plus : api_key. Et qui nous permettrait de vérifier le nombre de requêtes faites par clé.
  • Créer un ‘load balancer’ sur notre serveur qui permettrait de répartir la charge en cas de sur-utilisation du serveur principal

JavaScript :

  • Créer une fonction, qui une fois que l’on est connecté à un channel, actualise les messages du channel tous les 200 ms.
  • Si vous choisissez de le faire, vous pouvez sous-optimiser cela:
    • Récupérer depuis une troisième table la date de dernière modification du channel (dernier message envoyé) et comparer avec une variable locale qui stocke la dernière date d’actualisation du channel. Si vous avez un channel avec disons 2000 messages cela prendra beaucoup de réseaux à chaque fetch (5 par seconde disons, cela fait que vous récupérez 10 000 messages par secondes, si chaque message fait en moyenne 100 caractères = 100 bytes alors on utilise 1ko/s de la bande passante) alors que si vous optez pour la solution d’une troisième table qui stocke les modifications et qui retourne 1 ou 0 alors vous n’utilisez que 5 o/s de données (hors requête HTTP).

JAVA :

  • Utiliser la librairie qui ajoute JSONObject / JSONParser afin de simplifier l’utilisation du code; Je ne l’ai pas fait car je n’utilise jamais de librairie dans les formations que je propose.
  • Tester toutes les interfaces de l’API

Code Source

Les codes sources (API + JS + JAVA) sont disponibles à cette adresse :

https://kelou.fr/code-source-chat-micro-service/

Conclusion

Pour terminer, j’espère que cette formation vous aura plu et que vous aurez compris toutes les étapes du processus de la conception jusque l’utilisation de microservices. Vous aurez appris à concevoir un micro service de A à Z, à l’utiliser en JavaScript et JAVA, à le maintenir en PHP et le tout sans utiliser une seule librairie mais avec avec les concepts de bases qu’apportent chaque langage.

Si vous avez des questions, n’hésitez pas à me contacter dans les commentaire, par l’onglet contact du site, par mail ou encore sur LinkedIn (https://fr.linkedin.com/in/clement-castel).