IOC & DI en Ruby

code 21 juin 2025
🎯 Objectif ; mettre en place un découplage fort et éviter l'effet "boite à outils"

Cas d'étude, l'anti-pattern

 Un composant quelconque doit logger ses actions; l'anti-pattern pour  : 

class Composant  
  
  def initialize  
    @log = open('composant.log', 'a')  
  end  
  
  def action  
    # a process  
    puts 'action made'  
    @log.puts "action made"  
  end  
  
end  

Constat :

  • ❌ le log est instancié directement
  • ❌ le log est implémenté dans le composant

Un pas en avant loin d'être suffisant

 Ne pas implémenter le Logger, mais l'utiliser, Utiliser la solution dédiée et sortir du composant "boite à outils"

class Composant  
  
  def initialize  
     @log = Logger.new('logfile.log')  
  end  
  
 def action  
   # a process  
   puts 'action made'  
   @log.puts "action made"  
 end  
  
end  

 Constat :

  • ❌ le log est toujours instancié directement
  • ✅ le log n'est plus implémenté dans le composant

Vers le pattern

class Composant  
  
  attr :log  
  
  def initialize(log: Logger.new('logfile.log'))  
     @log = log  
  end  
  
  def action  
    # a process  
    puts 'action made'  
    log.info 'action made'  
  end  
  
end  

Constat : 

  • ✅ le log n'est plus instancié directement dans le composant et devient substituable
  • ✅ le log n'est plus implémenté dans le composant

 On vient de réaliser une réduction du couplage et une inversion de contrôle

 L'approche injection de dépendance

Un gem qui implémente la DI de façon simple :

require 'rubygems'  
require 'micon'  
require 'logger'  
  
micon.register(:logger){Logger.new STDOUT}  
  
class Application  
  inject :logger  
  
  def run  
    logger.info 'running ...' if Application.respond_to? :logger  
  end  
end  
  
class Application2  
  inject :logger  
  
  def run  
    logger.info 'running twice...'  
  end  
end  
  
Application.new.run  
  
Application2.new.run  

 On voit en plus que l'injection permet de proposer un accès à un unique à un service pré-instancié

Pour aller plus loin

Pour aller plus loin on peu utiliser un container leger avec une registry de services injectable :

GitHub - Ultragreen/carioca: Carioca : Configuration Agent and Registry with Inversion Of Control for your Applications

Mots clés

Romain GEORGES

Open Source evangelist & Ruby enthousiast