Aller au contenu principal
Ingénierie

Rust ou Go pour votre backend : comment nous choisissons

9 min de lecture

Les deux sont modernes, rapides et compilés. La vraie question n'est pas de savoir lequel est « meilleur », mais lequel convient au problème que vous avez devant vous. Voici comment nous tranchons en pratique.

Nous construisons des systèmes de production en Rust comme en Go, et notre propre produit repose sur les deux : Go là où la vitesse d'itération compte, Rust là où la latence et la sûreté mémoire ne se négocient pas. Alors quand on nous demande quel langage choisir pour un nouveau backend, notre réponse est : ça dépend, et quiconque vous répond en un mot cherche à vous vendre quelque chose.

Cet article est la comparaison que nous aimerions voir plus souvent. Il laisse de côté le duel de benchmarks et s'intéresse aux compromis concrets qui décident du choix sur de vrais projets.

Ce qu'ils ont en commun

Commençons par les points d'accord, car ils sont nombreux. Les deux compilent en code natif, les deux sont assez rapides pour que le langage soit rarement votre goulot d'étranglement, les deux produisent un binaire statique unique, trivial à déployer dans un conteneur, et les deux offrent une concurrence de premier ordre et un écosystème en bonne santé. L'un comme l'autre est un choix défendable pour un service backend. Vous regretterez d'avoir pris le « mauvais » bien moins que les débats en ligne ne le laissent croire.

Là où Go l'emporte

Go optimise avant tout une chose : rendre une équipe productive et la garder ainsi. Le langage est assez petit pour s'apprendre en une semaine, la bibliothèque standard couvre l'essentiel des besoins d'un service, et les goroutines rendent le code concurrent abordable plutôt qu'effrayant. La compilation est quasi instantanée, ce qui garde la boucle de rétroaction courte.

  • Les services backend classiques : API REST et gRPC, microservices, services d'orchestration, workers.
  • Les équipes qui doivent avancer vite et intégrer rapidement de nouveaux ingénieurs.
  • Les services réseau à forte concurrence, où les goroutines brillent et où le runtime fait le plus dur.
  • Tout ce qui privilégie la simplicité et la lisibilité plutôt que de grappiller les derniers pourcents de performance.

Le revers : Go utilise un ramasse-miettes. Pour l'immense majorité des services, ce n'est pas un problème, car le collecteur est excellent. Mais cela implique des pauses occasionnelles et moins de contrôle sur la disposition en mémoire, ce qui compte pour une catégorie précise de travaux sensibles à la latence.

Là où Rust l'emporte

Rust offre des performances dignes du C, une sûreté de la mémoire et des threads garantie à la compilation, et aucun ramasse-miettes. Le borrow checker qui frustre les débutants est précisément le mécanisme qui empêche de livrer des catégories entières de bugs : use-after-free, data races, déréférencements de pointeur nul. Quand la justesse et la vitesse comptent autant l'une que l'autre, cette garantie vaut bien une courbe d'apprentissage plus raide.

  • Les logiciels système et réseau : protocoles, proxys, agents, plan de données.
  • Les pipelines temps réel où une pause du ramasse-miettes est inacceptable, comme les médias en direct.
  • Les composants critiques pour les performances au sein d'un système plus large, souvent via FFI ou sous forme de service ciblé.
  • WebAssembly, où Rust est un citoyen de premier rang pour livrer au navigateur du code à vitesse native.

Le coût est réel : Rust demande plus de temps pour l'apprendre, pour écrire le code et pour le compiler. Une équipe qui le découvre sera plus lente pendant les premiers mois. Cet investissement est rentable dans le bon domaine et n'est qu'un surcoût dans le mauvais.

Comment nous choisissons vraiment

Sur notre propre plateforme, la répartition s'est faite naturellement : Go là où la vitesse d'itération et la lisibilité comptent le plus, Rust là où la latence et la sûreté mémoire ne se négocient pas. Nous n'avons pas choisi de camp ; nous avons adapté l'outil à la tâche.

Prenez Rust quand un plantage, une data race ou une pause du collecteur est vraiment inacceptable. Prenez Go pour presque tout le reste. La plupart des backends relèvent de « tout le reste ».

Une bonne règle par défaut : démarrez un nouveau backend en Go, sauf raison concrète de faire autrement, et introduisez Rust de manière chirurgicale pour les composants qui en ont vraiment besoin. Inutile de choisir un seul langage pour tout le système : un service Go avec un composant Rust derrière une FFI, ou un petit service Rust derrière une API Go, est une architecture parfaitement sensée.

Si vous pesez ce choix pour un vrai projet et souhaitez un second avis fondé sur l'expérience de livrer avec les deux, c'est exactement le genre de conversation que nous aurons plaisir à avoir.