• Contenu
  • Bas de page
logo ouidoulogo ouidoulogo ouidoulogo ouidou
  • Qui sommes-nous ?
  • Offres
    • 💻 Applications métier
    • 🤝 Collaboration des équipes
    • 🛡️ Sécurisation et optimisation du système d’information
    • 🔗 Transformation numérique
  • Expertises
    • 🖥️ Développement logiciel
    • ♾️ DevSecOps
    • ⚙️ Intégration de logiciels et négoce de licences
      • Atlassian : Jira, Confluence, Bitbucket…
      • Plateforme monday.com
      • GitLab
      • SonarQube
    • 📚​ Logiciel de CRM et de gestion
    • 🎨 UX/UI design
    • 🌐 Accessibilité Numérique
    • 🗂️​ Démarches simplifiées
    • 📝 Formations Atlassian
  • Références
  • Carrières
    • 🧐 Pourquoi rejoindre Ouidou ?
    • ✍🏻 Nous rejoindre
    • 👨‍💻 Rencontrer nos collaborateurs
    • 🚀 Grandir chez Ouidou
  • RSE
  • Ressources
    • 🗞️ Actualités
    • 🔍 Articles techniques
    • 📖 Livres blancs
    • 🎙️ Interviews Clients
Nous contacter
✕
Gemini, l’avenir du Web ?
Gemini, l’avenir du Web ?
9 avril 2021
MJML, un framework simple pour des mails simples
MJML, un framework simple pour des mails simples
22 avril 2021
Ressources > Articles techniques > Ruby 3, les nouveautés

Ruby 3, les nouveautés

Article écrit par Nicolas Cavigneaux

Le 25 décembre 2020, la version 3.0 de Ruby a officiellement été publiée. Beaucoup de Rubyistes l’attendaient avec impatience tant elle s’annonçait prometteuse.

Voyons aujourd’hui ce qu’elle nous apporte d’excitant à utiliser.

Performances

La nouveauté la plus discutée depuis longtemps concernant cette nouvelle version était le fameux « Ruby 3 × 3 » qui promettait que Ruby 3 serait 3 fois plus performant que Ruby 2. Je dis dit bien que Ruby 2 et pas Ruby 2.x parce que les différentes améliorations de performance ont été distillées tout au long du développement de Ruby 2.x.

Cette promesse a été tenue et les performances sont au rendez-vous. Cette promesse a toujours été relative à un cas d’usage bien précis qui servirait de référence tout au long du développement. Il s’agissait de faire tourner un émulateur NES à 60 FPS. Il faut savoir que Ruby 2.0 n’arrivait qu’à 20 FPS.

Ces gains de performances sont dus à de nombreuses optimisations mais surtout à la mise en place du compilateur JIT. JIT signifie « Just In Time » compilation qui est une technique fréquemment utilisée pour améliorer les performances d’un langage. Il s’agit de faire en sorte que le code applicatif puisse être compilé pendant son exécution, au runtime. C’est une approche dynamique de la compilation classique des sources. On a donc, à la fois, du code interprété et compilé, ce qui permet d’avoir le meilleur de deux mondes : un code rapide à exécuter mais qui reste très flexible et dynamique.

Mémoire

Le compactage du garbage collector avait été ajouté dans Ruby 2.7.

Il faut distinguer ici garbage collection et garbage compaction. Le premier permet de nettoyer les allocations redondantes en mémoire pour gagner de l’espace et pouvoir en allouer à de nouvelles choses. Quant à celui qui nous intéresse ici, le compactage, il regroupe les objets éparpillés dans la mémoire, laissant ainsi des espaces mémoire assez gros pour en allouer à des objets plus lourds plus facilement.

Il était possible de le déclencher manuellement en invoquant GC.compact. Ruby 3 déclenche désormais ce compactage de manière totalement automatisée. Le compactage se fait aux moments les plus adéquats pour assurer que la mémoire reste la plus défragmentée possible tout au long de l’exécution de l’application.

Il n’est donc plus nécessaire de le gérer à la main pour assurer les meilleures performances possibles.

Typage

Ruby n’est pas un langage typé. Ce choix a été fait pour permettre aux développeurs de pouvoir prototyper plus rapidement et plus facilement.

Ceci étant, il est parfois bien utile de pouvoir typer son code pour gagner en robustesse. C’est notamment vrai lorsqu’il s’agit de maintenir de grosses applications.

Avec Ruby 3, il est maintenant possible de jouer un peu dans les deux camps. La notion de vérification statique de type (static type checking) a officiellement été intégrée.

On peut donc, si on le souhaite, documenter ses classes et méthodes pour faire connaître à l’interpréteur vos intentions quant à l’utilisation de votre code. Grâce à cela il est possible de découvrir des incohérences beaucoup plus tôt.

Ce système de typage s’appelle RBS et peut donc être utilisé pour décrire le fonctionnement de vos classes, méthodes, variables d’instance, modules et constantes.

La description du typage de votre code ne se fait pas directement dans le code source Ruby. Les signatures sont stockées dans des fichiers .rbs ce qui permet de typer une application existante après coup sans avoir à en modifier son code source. Cette fonctionnalité est donc rétro-compatible.

Voici un exemple de déclaration :

class Message   attr_reader id: String   attr_reader string: String   attr_reader from: User | Bot   attr_reader reply_to: Message?    def initialize: (from: User | Bot, string: String) -> void    def reply: (from: User | Bot, string: String) -> Message end 

Cette nouvelle fonctionnalité nous permettra de

  • trouver plus facilement des bugs (comme des undefined, des valeurs nil là où c’est théoriquement impossible…), Il est également possible de déclarer des interfaces
  • optimiser l’intégration dans les éditeurs en améliorant la complétion, en reportant les erreurs en temps réel ou encore en aidant au refactoring
  • mettre en place du duck typing de manière plus sûre grâce à la déclaration d’interfaces

Parallélisme et concurrence

La gestion de la concurrence en Ruby a toujours été un sujet sensible. Jusque-là nous ne pouvions qu’utiliser les threads qui ont malheureusement beaucoup de défauts et sont assez difficiles à gérer correctement.

Ruby 3 nous apporte de nouvelles façons de mettre en place de la concurrence.

Fibers

Les fibers sont une alternative légère aux threads. Elle permet la mise en place de « concurrence coopérative ».

Elles consomment moins de mémoire et permettent un contrôle plus fin que les threads.

Ce n’est plus la VM qui décide de quand un morceau de code concurrent doit être arrêté et repris. On laisse le développeur s’en charger.

Ruby 3 apporte le Fiber Scheduler qui est capable d’intercepter les opérations bloquantes (I/O) et de les jouer de manière concurrente. On peut donc avoir une boucle d’événements qui sera séparée du code applicatif.

Le scheduler est une interface, il faut donc l’intégrer dans un wrapper. Des gems telles que Async ou EventMachine intègrent déjà cette interface.

On peut donc, par exemple, télécharger plusieurs fichiers en même temps avec de la vraie concurrence.

puts "1 : c'est parti"  # On crée une nouvelle fibre f = Fiber.new do   puts "3: on entre dans la fibre."   Fiber.yield # On met la fibre en pause   puts "5: la fibre a été redémarrée." end  puts "2: on démarre la fibre" f.resume  puts "4: on reprend là ou la fibre s'était arrêtée." f.resume  puts "6: c'est fini." 

Ractors

Le verrou global qui existe sur la VM Ruby nous empêche d’avoir des threads Ruby (green threads) qui travaillent en parallèle. L’utilité globale des threads est donc assez limitée.

Ractor est une réponse à cette problématique. Ractor se base sur le modèle Acteur que les utilisateurs d’Elixir connaissent bien.

Ractor est aussi lourd en termes de ressource que les threads mais a l’avantage de ne pas souffrir du verrou global de la VM. Chaque Ractor s’exécute en parallèle.

Avec ce modèle il devient beaucoup plus facile d’être thread safe. Le fonctionnement même de ce modèle incite à écrire les tâches concurrentes d’une manière qui évite ce problème. Les informations ne sont pas partagées entre Ractor contrairement aux threads. Dans le modèle Acteur, les différents acteurs se communiquent les informations en s’échangeant des messages.

ractor1, ractor2 = *(1..2).map do   Ractor.new do     arg = Ractor.receive     "opération longue #{arg}"   end end  # On envoie le paramètres à nos instances ractor1.send 1 ractor2.send 2  p ractor1.take #=> "opération longue 1" p ractor2.take #=> "opération longue 2" 

Pattern matching

Le pattern matching avait été mis à disposition de manière expérimentale avec Ruby 2.7 mais est officiel depuis Ruby 3.

Le pattern matching permet d’associer automatiquement des valeurs d’une structure à des variables (si la structure passée correspond à l’attendu).

Pour ceux qui avaient déjà commencé à l’utiliser, sachez que la syntaxe a changée :

# Ruby 2.7 { name: "Jon", role: "CTO" } in {name:} p name # => 'Jon'  # Ruby 3.0 { name: "Jon", role: "CTO" } => {name:} p name # => 'Jon' 

On peut également utiliser le pattern matching dans les case :

users = [   { name: "Jon", role: "CTO" },   { name: "Marcel", role: "Manager" },   { role: "Client" },   { name: "Lucie", city: "Lille" },   { name: "Nico" },   { city: "Paris" } ]  users.each do |person|   case person   in { name:, role: "CTO" }     p "#{name} est le CTO."   in { name:, role: designation }     p "#{name} est #{designation}."   in { name:, city: "Lille" }     p "#{name} vit à Lille."   in {role: designation}     p "Un inconnu est #{designation}."   in { name: }     p "#{name} n'a pas de rôle."   else     p "Aucun pattern ne correspond."   end end  "Jon est le CTO." "Marcel est Manager." "Un inconnu est client." "Lucie vit à Lille." "Nico n'a pas de rôle." "Aucun pattern ne correspond." 

Définition courte de méthode

Un sucre syntaxique a été ajouté permettant d’avoir une syntaxe concise lorsqu’il s’agit de définir une méthode courte.

def: foo(bar) = puts bar  foo("ruby") #=> "ruby" 

except

Pour les nombreux d’entre vous qui utilisent Rails, vous avez déjà sûrement utilisé la méthode except fourni par ActiveRecord et qui permet d’obtenir un Hash dénué d’un ou plusieurs de ses éléments.

Cette méthode a été intégrée directement à Ruby !

user = { name: "Jean", city: "Lille", role: "Dev" } user.except(:role) #=> {:name=> "Jean", :city=> "Lille"} 

Conclusion

Comme vous pouvez le voir, les nouveautés intéressantes sont nombreuses. Elles devraient encore nous faciliter la vie et nous permettre d’écrire du code avec toujours autant de plaisir.

De nouveaux outils sont mis à notre disposition et nous ouvrent de nouvelles portes notamment côté performances et concurrence.

Je n’ai fait part dans cet article que des fonctionnalités qui m’ont le plus marquées, mais je vous invite à consulter la liste des changements si vous voulez connaître l’ensemble des changements qui ont eu lieu.

Je vous conseille également de lire cette interview de Matz qui nous parle des nouveautés de Ruby 3 et notamment de comment faire le choix entre Ractor et Fiber lorsqu’on a besoin de mettre en place de la concurrence.

À lire aussi

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique

Lire la suite

intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 

Lire la suite

Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 

Lire la suite

image miniature les nouveautés Atlassian
26 février 2025

Les nouveautés Atlassian en 2025

Lire la suite

Articles associés

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique


Lire la suite
intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 


Lire la suite
Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 


Lire la suite

À propos

  • Qui sommes-nous ?
  • Références
  • RSE
  • Ressources

Offres

  • Applications métier
  • Collaboration des équipes
  • Sécurisation et optimisation du système d’information
  • Transformation numérique

Expertises

  • Développement logiciel
  • DevSecOps
  • Intégration de logiciels et négoce de licences
  • Logiciel de CRM et de gestion
  • UX/UI design
  • Accessibilité Numérique
  • Démarches simplifiées
  • Formations Atlassian

Carrières

  • Pourquoi rejoindre Ouidou ?
  • Nous rejoindre
  • Rencontrer nos collaborateurs
  • Grandir chez Ouidou

SIEGE SOCIAL
70-74 boulevard Garibaldi, 75015 Paris

Ouidou Nord
165 Avenue de Bretagne, 59000 Lille

Ouidou Rhône-Alpes
4 place Amédée Bonnet, 69002 Lyon

Ouidou Grand-Ouest
2 rue Crucy, 44000 Nantes

Ouidou Grand-Est
7 cour des Cigarières, 67000 Strasbourg

  • Linkedin Ouidou
  • GitHub Ouidou
  • Youtube Ouidou
© 2024 Ouidou | Tous droits réservés | Plan du site | Mentions légales | Déclaration d'accessibilité
    Nous contacter