Les frameworks Back-end
Le Back-end est la part du développement du site qui concerne le serveur.
Dans le cas d'un site web, l'objectif peut souvent se résumer à ceci : recevoir des requêtes HTTP
et traiter ces requêtes pour renvoyer du contenu au client.
Le traitement de ces requêtes passe souvent par de la gestion d'une base de données afin d'enregistrer
des informations et/ou de les restituer.
De nombreux frameworks ont vus le jour dans le but de simplifier le développement côté Back-end. Dans ce chapitre, nous allons en présenter trois : Symfony, Django et Express.js.
Symfony
Symfony est un framework PHP assez populaire dont la philosophie est de permettre d'éviter de
« réinventer la roue » chaque fois qu'on développe un site Web.
En effet, les problématiques du développement Back-end sont souvent très similaires d'un site Web à l'autre.
Symfony propose donc des fonctions toutes faites permettant de n'écrire que l'essentiel.
Exemple de problématiques que Symfony permet de résoudre facilement :
- Gestion des utilisateurs (Inscription, connexion, gestion des droits)
- Création et validation de formulaires
- Gestion de la base de données
L'architecture MVC
Symfony organise les fichiers du projet suivant l'architecture Modèle-Vue-Contrôleur. Ce principe est très répandu dans le développement de sites web. Il consiste à découper les différentes couches du projet en 3 parties :
- Le Modèle : son rôle est de gérer les données. Il contient la structure des données et les fonctions permettant d'intéragir avec : lecture, enregistrement, modification. Dans le cas de gestion d'une base de données, ce sera lui qui fera les appels à SQL.
- La Vue : il se charge d'afficher la page à l'utilisateur. Sa fonction est purement graphique : aucun traitement n'est effectué ici. Il prend en argument des données et va, à partir de ces données, générer le code HTML correspondant.
- Le Contrôleur : c'est le « chef d'orchestre » de l'application. Il reçoit une requête HTTP de l'utilisateur et doit lui retourner la page correspondante. Pour cela, il fait appel au modèle afin de gérer les données à traiter, puis il passe ces données traitées à la vue.
Source : formget.com
Le schéma MVC est très répandu dans le développement d'applications, et se révèle en particulier bien adapté pour la création de sites Web. En effet, les 3 logiques Modèle-Vue-Contrôleur sont souvent bien séparées les unes des autres, et cette architecture, si elle est bien respectée, permet d'avoir un code organisé et facile à lire.
C'est pour cette raison que Symfony adapté cette organisation. Au delà des bénéfices intrinsèque à l'architecture MVC, un des principaux intérêts de ce framework est d'apporter une gestion simplifiée des 3 couches :
- Gestion du modèle : avec Symfony, les tables SQL sont matérialisées par des classes PHP, les attributs de la classe étant les champs de la base de donnée. Symfony propose alos un système en amont (appelé ORM) permettant d'accéder aux attributs directement via les getters et setters de la classe. L'idée est de ne pas avoir à écrire une seule requête SQL. Les jointures sont également gérées de cette façon : un simple appel au getter renverra l'instance vers le modèle de la classe reliée.
- Gestion des vues : Symfony utilise un moteur de template appelé Twig qui permet de générer facilement du HTML. Il permet de faire des opérations simples : conditions, boucles, etc. On peut également créer des blocs afin de réutiliser un même composant dans des pages différentes (pour faire un menu par exemple). Enfin, on peut faire des appels implicites aux getters et aux setters des modèles (user.name à la place de user.getName() par exemple), ce qui permet d'alléger la syntaxe.
- Gestion du contrôlleur : Symfony utilise un système de routes permettant, à partir d'une URL donnée, d'appeler la bonne fonction avec les bons paramètres. Par exemple, si je rentre l'URL /annonce/10, une méthode annonceAction($id) sera automatiquement appelée où $id vaudra 10. Le contrôlleur peut alors directement utiliser ce paramètre pour récupérer l'annonce correspondante.
Exemple de code
Un code vaut mieux qu'un long discours : voyons Symfony en action !
Voici un code permettant d'afficher la liste des amis d'un utilisateur.
Modèle : Message.php
class User {
// Déclaration des attributs.
// Les directives @ORM permettent de définir le type de champ dans la BDD
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @ORM\ManyToMany(targetEntity="UserBundle\Entity\User", cascade={"persist"})
*/
private $friends;
// [...] En pratique, il y a aussi les getters et setters, mais ils sont générés automatiquement
}
Contrôleur : UserController.php
public function friendsAction($userID) {
$em = $this->getDoctrine()->getManager(); // Chargement de l'ORM
$user = $em->getRepository('UserBundle:User')->find($userID); // Récupération de l'utilisateur
$friends = $user->getFriends(); // Récupération des amis
return array('user' => $user, 'friends' => $friends); // Envoi des données à la vue
}
Vue : friends.html.twig
{% extends '::layout.html.twig' %} {# Héritage de la page principale #}
{% block title %} Messages {% endblock %} {# Balise <title> #}
{% block content %} {# Contenu de la page #}
<h1>Liste des amis de {{ user.name }} ({{ friend|length }})</h1>
<ul>
{% for friend in friends %}
<li>{{ friend.name }}</li>
{% endfor %}
</ul>
{% endblock %}
Résultat :
Liste des amis de Timothé (6)
- Antoine
- Julien
- Florent
- Alexandre
- Sophie
- Guillaume
On voit que le code se lit facilement, et est surtout bien organisé grâce à l'architecture MVC.
Django
Django est un autre framework Web écrit cette fois-ci en Python. Son principe est très proche de Symfony, la présentation de ce framework sera donc beaucoup plus courte. Parmi les simillarités avec Symfony, on peut relever :
- Le même genre de simplification des problèmes récurrents du Web. Création de formulaires, gestion des utilisateurs... Tout ceci est géré par Django.
- Tout comme Symfony, Django repose sur une architecture de type MVC. On retrouve le système de classes pour gérer la base de données, un moteur de template proche de Twig pour les vues, et un contrôleur permettant de lier les deux.
- Django propose aussi un système de routage permettant d'associer une URL au contrôleur correspondant.
Si ces deux frameworks sont similaires, lequel choisir ? En réalité, ayant eu l'occasion de tester les deux, j'ai ressenti quelques différences. Et de façon générale, je trouve Django plus agréable à manier. Voici quelques arguments en sa faveur :
-
Une syntaxe plus légère : cela se ressent principalement lors de la création des modèles.
En Django, un champ = une ligne de code.
En symfony, un champ = une ligne de code, des annotations, un getter et un setter.
Les noms de fonctions sont également plus courts (voir code ci-dessous). -
L'espace admin de DjangoPrésence d'un espace administrateur pour gérer la base de données facilement, sans connaître le modèle SQL sous-jacent. Avec Symfony, on est contraint de passer par une interface de base de données telle que PHPMyAdmin, ce qui est moins pratique.
- Simplification de l'organisation des fichiers : en Symfony, les fichiers sont hiérarchisés à l'extrême, dans des sous-sous-dossiers, ce qui fait qu'on s'y perd facilement et que la navigation entre les fichiers n'est pas pratique. Pour vous donner une idée, voici à quoi ressemble un chemin d'accès à un fichier : /src/UserBundle/Resources/config/friends.html.twig. En Django, les fichiers essentiels sont regroupés dans un dossier, et la recherche est ainsi plus facile.
- Enfin, Django récupère les avantages de Python : une clarté du code, et de nombreux modules tout faits très faciles à installer grâce au gestionnaire de paquets PIP.
Exemple de code
Voici l'équivalent Django du code Symfony présenté précédemment :
Modèle : models.py
class User(models.Model):
name = models.TextField()
friends = models.ManyToManyField(User)
Contrôleur : views.py
def getFriends(request, id):
user = User.objects.get(id=id)
friends = user.friends
return render(request, 'friends.html', {'user': user, 'friends' : friends})
Vue : friends.html
{% block title %} Messages {% endblock %}
{% block content %}
<h1>Liste des amis de {{ user.name }} ({{ friend|length }})</h1>
<ul>
{% for friend in friends %}
<li>{{ friend.name }}</li>
{% endfor %}
</ul>
{% endblock %}
Comme vous pouvez le voir, le code est très simillaire (il est même identique pour la vue). Malgré tout, Django a cette simplicité supplémentaire qui le rend à mon avis préférable. Bien sûr, cet avis est subjectif, et les différences sont de l'ordre des détails.
Express.js
Express.js est un autre framework Back-end basé sur Node.js. Ce framework se distingue des deux précédents par le fait qu'il est beaucoup plus bas niveau. Sa philosophie est en effet très différente : il se veut minimaliste et rapide.
L'environnement Node.js
Comme dit plus haut, express.js est un framework utilisant Node.js.
Il s'agit d'un environnement permettant de réaliser des applications Web en javascript.
Node.js est devenu très populaire ces dernières années.
Pourquoi cet engouement ?
L'idée est que Node.js permet de réaliser des applications beaucoup plus rapides que ce qui existait jusqu'à présent.
D'où vient cette rapidité ?
Premièrement, Node.js est basé sur le moteur Javascript V8.
À l'origine, ce moteur a été écrit par les développeurs de Google Chrome pour interpréter et exécuter le JS du navigateur.
Il a été très optimisé par ces développeurs afin de rendre l'exécution du JS très rapide.
Parmi les moyens d'optimisation, on peut citer la compilation Just-in-time, qui permet de transformer à la volée
le code interprété en code machine pour ne pas avoir à réinterpréter si on repasse une 2e fois
dans le même bout de code.
Mais ce n'est pas le seul procédé d'optimisation utilisé. Inline expansion, copy elision...
De nombreux moyens complexes ont été mis en œuvre pour rendre l'exécution la plus rapide possible.
Node.js utilise le même moteur pour interpréter le js, et hérite donc de cette rapidité.
Une autre raison de la rapidité de ce langage est son fonctionnement asynchrone.
En effet, supposons qu'on soit amené à faire plusieurs requêtes à un serveur externe
(très fréquent lorsqu'on utilise des APIs tierces par exemple).
Avec un framework classique tel que symfony par exemple, voici la procédure qu'on sera amené à réaliser :
request('http://api.com/request1');
request('http://api.com/request2');
Ce qui n'est pas optimisé, puisqu'on est obligé d'attendre la réponse de la requête 1 avant d'exécuter la requête 2.
Avec Node c'est différent, on utilise la notion de callbacks.
Les callbacks sont des fonctions appelées une fois qu'une tâche est finie.
Voici à quoi ressemblerait le code ci-dessus en Node :
request('http://api.com/request1', function(response) {
// Fonction appelée lorsque la requête 1 a abouti
});
request('http://api.com/request2', function(response) {
// Idem pour la requête 2
});
Ici, la méthode request est non-bloquante, c'est-à-dire que la suite du programme est exécutée pendant que la 1re requête est traitée. Le traitement est donc parallélisé, ce qui permet d'aller quasiment deux fois plus vite !
(Source : Openclassrooms)
Un autre intérêt de Node est le langage utilisé : le javascript. En effet, ce langage étant déjà présent dans la partie « client » du développement d'un site, un développeur Web n'aura pas de nouveau langage à connaître pour faire du Back-end en Node. Enfin, Node utilise un gestionnaire de paquets relativement pratique appelé NPM, qui permet d'installer des modules en une ligne de commande (npm install). Et la communauté JS étant très active, il existe des paquets pour à peu près tout !
Retour à Express.js
Et express.js dans tout ça ? Il s'agit simplement d'un module NPM rajoutant certaines fonctions utiles pour faire du routage. En effet, Node est un langage assez bas niveau, à tel point que certaines fonctions qu'on pourrait considérer comme basiques ne sont pas implémentées :
-
Association d'une URL à une fonction. C'est impossible par défaut.
On est donc amené à écrire du code comme cela :
Ce qui est inimaginable si on veut réaliser une application un peu grosse.if (page == '/') { // ... } else if (page == '/sous-sol') { // ... } else if (page == '/etage/1/chambre') { // ... }
-
Chargement du HTML à partir d'un fichier.
En Node sans framework, le HTML doit être écrit directement dans le code :
Ce qui, là encore, est très moche, et impossible à relire.res.write('<!DOCTYPE html>'+ '<html>'+ ' <head>'+ ' <meta charset="utf-8" />'+ ' <title>Ma page Node.js !</title>'+ ' </head>'+ ' <body>'+ ' <p>Voici un paragraphe <strong>HTML</strong> !</p>'+ ' </body>'+ '</html>');
Express.js vient combler ces lacunes en ajoutant implémentant ces fonctions basiques pour nous.
Routage
Avec express.js, il est possible de lier assez facilement une url avec une fonction. La syntaxe est la suivante :
app.get('/', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('Vous êtes à l\'accueil, que puis-je pour vous ?');
});
app.get('/sous-sol', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('Vous êtes dans la cave à vins, ces bouteilles sont à moi !');
});
app.get('/etage/1/chambre', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('Hé ho, c\'est privé ici !');
});
Ce qui règle le 1er problème.
Templates
Express.js propose un moteur permettant de faire du rendu de template d'une manière assez proche de Twig
(mais en plus bas niveau), au moins dans le principe :
prend en argument un tableau de données et génère le document HTML correspondant.
Plus précisément, il est possible d'insérer du JS interprété par le serveur dans le HTML
(un peu à la manière de PHP).
Encore une fois, un exemple de code vaut mieux qu'un long discours :
app.js
app.get('/compter/:nombre', function(req, res) {
var noms = ['Robert', 'Jacques', 'David'];
res.render('page.ejs', {compteur: req.params.nombre, noms: noms});
});
page.ejs
<h1>Je vais compter jusqu'à <%= compteur %></h1>
<p><%
for (var i=1;i<=compteur;i++) {
%>
<%= i %>...
<% } %></p>
<p>Tant que j'y suis, je prends un nom au hasard qu'on m'a envoyé :
<%= noms[Math.floor(Math.random()*noms.length)] %>
</p>
Résultat :
Je vais compter jusqu'à 42
1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12... 13... 14... 15... 16... 17... 18... 19... 20... 21... 22... 23... 24... 25... 26... 27... 28... 29... 30... 31... 32... 33... 34... 35... 36... 37... 38... 39... 40... 41... 42...
Tant que j'y suis, je prends un nom au hasard qu'on m'a envoyé : Robert
Le framework Express est donc en soi assez basique, et c'est aussi une des philosophies de Node : être bas niveau. Si vous voulez des fonctionnalités plus haut niveau, il suffit d'installer les packages dont vous avez besoin. Notamment, Express pourra être couplé à d'autres frameworks, un exemple typique étant la stack MEAN, qui consiste à relier Express à Angular et MongoDB (outils que nous verrons dans les parties suivantes).
Comparaison
Nous avons pu voir 3 frameworks différents, l'objectif est maintenant de chercher quels sont les avantages et les inconvénients de chacun, et qu'est-ce qui fait que l'on prendra plutôt l'un ou l'autre sur un projet réel. Nous allons comparer les frameworks sur plusieurs critères.
Maintenabilité
La maintenabilité est un facteur important lorsque l'on développe un projet à long terme. L'idée est que si on veut ajouter des fonctionnalités à un site existant, on voudrait éviter d'avoir à passer du temps sur ce qui a été fait précédemment.
Organisation
Dans ce contexte, Symfony et Djano sortent clairement gagnants :
ils imposent une organisation du code assez robuste, avec l'architecture MVC et
une structure de projet qui oblige à coder proprement.
Un développeur qui reprendrait un projet dans ces frameworks n'aurait donc pas de mal à s'y retrouver.
À l'inverse, Express.js se veut beaucoup moins contraingnant en terme d'organisation,
ce qui peut s'avérer risqué sur les projets à long terme.
En effet, n'ayant pas de structure imposée, le code peut très vite se retrouver
désordonné et difficile à relire (code "spaghetti").
Simplicité de développement
C'est sur ce point qu'Express devient un avantage. Très facile à mettre en place et à appréhender, le tutoriel officiel d'Express peut se lire en moins d'une heure. La learning curve est très douce, ce qui s'avère agréable. Réciproquement, Symfony et Django sont plus difficiles à maîtriser. Il faut un peu de temps avant de comprendre et de s'habituer à leur logique. Une nuance sur Django qui se révèle probablement plus facile à appréhender que Symfony, pour les raisons citées plus haut.
Vitesse
La vitesse est également un critère qui peut avoir son importance.
Comme vu précédemment, Express se veut basique et bas niveau, et on s'attend donc à
ce qu'il soit plus rapide sur une application réelle.
Mais cette différence est-elle significative ? C'est ce que nous allons voir maintenant.
Pour cela, un test a été réalisé avec les 3 frameworks sur une même tâche :
lire un CSV volumineux depuis le disque dur, trier chaque ligne, et renvoyer le résultat
dans le format JSON.
Ce test a l'avantage de mélanger lecture sur un disque dur, traitement des données, et
renvoi d'un résultat, des opérations typiques que l'on ferait en Back-end.
On obtient les résultats suivants :
- Express : 90 ms
- Django : 980 ms
- Symfony : 2500 ms
On constate effectivement une différence significative entre une application Node et les autres frameworks : on gagne en rapidité d'un facteur de plus de 10, ce qui est loin d'être négligeable. Symfony apparait bon dernier, ce qui met en évidence un des caractères de ce framework : sa lourdeur.
Popularité
La popularité d'un framework est également une bonne mesure de son intérêt. Au delà du simple bon sens (si tant de personnes utilisent tel framework, c'est un signe qu'il a du bon), un framework beaucoup utilisé signifie une forte communauté et donc de bonnes chances de trouver des réponses aux questions que l'on recherchera sur internet, ainsi que de nombreux modules faits pour ce framework.
Le site hotframeworks.com donne un bon indicateur de la popularité des frameworks au fil du temps. Son indice de popularité est basé sur le nombre de posts sur StackOverflow liés au framework, ainsi que le nombre de "Stars" sur le projet GitHub du framework (lorsque celui-ci est effectivement sur GitHub). Nous utiliserons ce site dans la suite pour comparer les différents frameworks.
On obtient les scores de popularité suivants :
On constate que Django a une avance relativement importante par rapport à Symfony et Express
quit sont à peu près au même niveau. Cela confirme là-encore la simplicité de ce premier.
Tableau récapitulatif
Symfony | Django | Express | |
---|---|---|---|
Avantages |
|
|
|
Inconvénients |
|
|
|
Utilisé par |
En bref : Django et Symfony feront de bons framework pour les gros projets, là où Express sera plus adapté sur des projets à court terme où on recherche surtout la simplicité, et pour les applications temps réel où la performance est cruciale. Django semble être un meilleur compromis que Symfony, même si ce dernier reste malgré tout un bon framework, notamment si vous êtes déjà famillier avec PHP.