Suivez moi sur GitHub

Guirec Corbel

Mon blog

Benchmark : go vs crystal vs ruby

| Comments

Crystal est un nouveau venu dans le monde des langages de programmation. Le but de ce langage est d’avoir une synthaxe similaire à Ruby tout en ayant les performances du C. Dans cet article, je vous propose de faire une comparaison entre le langage populaire et rapide, Go, ce jeune langage, Crystal, et son inspiration, Ruby.

Resultats

Sans plus attendre, voici les résultats en image :

Benchmark Go vs Crystal vs Ruby

Comme Ruby a des performances bien en dessous de Go et Crystal, voici le même graphique en le retirant :

Benchmark Go vs Crystal

Plus de détails sur les tests par la suite.

Fibonacci

Comme premier programme, j’ai choisi de faire un benchmark avec un programme comptant selon la suite de Fibonacci. N’étant pas un développeur Go, j’ai trouvé le code ici et l’ai modifié pour faire ce que je souhaite, c’est-à-dire m’afficher uniquement le résultat selon la valeur passée en paramètre.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "math/big"
import "fmt"

func fibonacci(n int) *big.Int {
    first, second := 0, 1
    for i := 0; i < n; i++ {
        first.Add(first, second)
        first, second = second, first
    }
    return second
}

func main() {
    fmt.Println(Fibonacci(40))
}

Voici une implémentation similaire en Ruby :

1
2
3
4
5
6
7
8
9
def fib(n)
  first, second = 0, 1
  n.times do
    first = first + second
    first, second = second, first
  end
  return second
end
puts fib(40)

Et la voici avec Crystal :

1
2
3
4
5
6
7
8
9
def fib(n)
  first, second = 0, 1
  n.times do
    first = first + second
    first, second = second, first
  end
  return second
end
puts fib(40)

Ne cherchez pas de différence entre Ruby et Crystal, il n’y en a pas. Dans ce cas, Ruby et Crystal sont totalement similaires.

Voici les résultats :

1
2
3
4
5
go build fib.go && time ./fib

real    0m0.001s
user    0m0.000s
sys     0m0.001s
1
2
3
4
5
time ruby fib.rb

real    0m0.035s
user    0m0.029s
sys     0m0.006s
1
2
3
4
5
crystal build --release fib.cr && time ./fib

real    0m0.003s
user    0m0.001s
sys     0m0.002s

On peut voir que Go gagne suivi de Crystal et de Ruby. Cependant, dans ce test, les temps d’exécution sont tellement rapides que beaucoup d’autres facteurs peuvent entrer en jeu dans le temps d’exécution.

Fibonacci BigInt

Pour poursuivre les tests, j’ai voulu augmenter la valeur à calculer. Malheureusement, pour Go et Crystal, la taille des entiers n’est pas suffisante. Il a donc été nécessaire de modifier le code pour utiliser des BigInt.

Voici le code Go modifié :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "math/big"

func fibonacci(n int) *big.Int {
    first, second := big.NewInt(0), big.NewInt(1)
    for i := 0; i < n; i++ {
        first.Add(first, second)
        first, second = second, first
    }
    return second
}

func main() {
    Fibonacci(100000)
}

Et la même chose avec Crystal :

1
2
3
4
5
6
7
8
9
10
11
require "big_int"

def fib(n)
  first, second = 0.to_big_i, 1.to_big_i
  n.times do
    first = first + second
    first, second = second, first
  end
  return second
end
fib(1000000)

Et voici les résutats :

1
2
3
4
5
go build fib.go && time ./fib

real    0m3.831s
user    0m3.826s
sys     0m0.009s
1
2
3
4
5
time ruby fib.rb

real    0m11.188s
user    0m9.873s
sys     0m1.290s
1
2
3
4
5
crystal build --release fib.cr && time ./fib

real    0m19.414s
user    0m29.527s
sys     0m4.969s

Le résultat est un peu décevant. L’utilisation du BigInt en Crystal est lente. La raison de cette lenteur viens du faire que Crystal utilise GMP qui est manifestement plus lent que l’implémentation de Go. Vous pouvez voir une discussion sur la lenteur de Crystal ici.

Autres Benchmarks

Je n’ai pas voulu me laisser abattre au premier test et j’ai décidé d’en faire d’autres. J’ai trouvé ce projet. Malheureusement, les codes proposés ne fonctionnent pas toujours avec les dernières versions des langages. Je me suis contenté de faire une comparaison avec les scripts fonctionnant sans modifications.

Brainfuck

1
2
3
4
5
6
go build brainfuck.go && time ./brainfuck bench.b
ZYXWVUTSRQPONMLKJIHGFEDCBA

real    0m6.510s
user    0m6.514s
sys     0m0.011s
1
2
3
4
5
6
time ruby brainfuck.rb bench.b
ZYXWVUTSRQPONMLKJIHGFEDCBA

real    3m5.364s
user    3m4.724s
sys     0m0.586s
1
2
3
4
5
6
crystal build --release brainfuck.cr  && time ./brainfuck bench.b
ZYXWVUTSRQPONMLKJIHGFEDCBA

real    0m5.930s
user    0m5.924s
sys     0m0.005s

Havlak

1
2
3
4
5
6
7
8
9
10
11
12
13
14
go build havlak.go && time ./havlak
Welcome to LoopTesterApp, Go edition
Constructing Simple CFG...
15000 dummy loops
Constructing CFG...
Performing Loop Recognition
1 Iteration
Another 50 iterations...
..................................................
Found 76001 loops (including artificial root node) (3800050)

real    0m32.058s
user    0m53.207s
sys     0m1.433s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
crystal build --release havlak.cr  && time ./havlak
Welcome to LoopTesterApp, Crystal edition
Constructing Simple CFG...
15000 dummy loops
Constructing CFG...
Performing Loop Recognition
1 Iteration
Another 50 iterations...
..................................................
Found 76002 loops (including artificial root node) (3800100)

real    0m14.083s
user    0m20.487s
sys     0m0.186s

On peut voir que Crystal est deux fois plus rapide que Go. J’émets une petite réserve sur le code fait avec Crystal. Celui-ci a été fait à partir de celui fait en Python et ne respect pas la “Crystal way”.

Matmul

1
2
3
4
5
6
go build matmul.go && time ./matmul 1500
-143.500167

real    0m3.189s
user    0m3.156s
sys     0m0.049s
1
2
3
4
5
6
time ruby matmul.rb 1500
-143.5001666666568

real    4m51.220s
user    4m50.842s
sys     0m0.300s
1
2
3
4
5
6
crystal build --release matmul.cr  && time ./matmul 1500
-143.5

real    0m3.868s
user    0m3.879s
sys     0m0.024s

Encore une fois, Ruby est en retrait. Les performances entre Go et Crystal sont comparables bien que Go est légèrement plus rapide.

Conclusion

Pour conclure, je dirais que Crystal, bien que très jeune, offre des performances intéressantes. Le futur nous dira s’il s’agit d’un projet éphémère ou s’il fera ses preuves.

J’espère pouvoir faire d’autres tests sur Crystal très bientôt. Je pense essayer de faire une API. Suivez-moi sur Twitter pour rester au courant.

Benchmark : clever cloud vs scalingo

| Comments

Scalingo et Clever Cloud sont deux entreprises françaises proposant des services d’hébergement dans le cloud. Celles-ci proposent de retirer la gestion des serveurs aux développeurs et ceux avec un bon nombre de technologies comme Ruby, Go, Python ou PHP. Après avoir mis à l’épreuve Heroku, Digital Ocean et Scalingo, j’ai pu déterminer que Scalingo offrait la meilleure performance des trois. Qu’en est-il de Clever Cloud ?

Avant propos

Cet article se base sur l’article précédent. L’application testée, le code ainsi que les pages testées sont les mêmes que celles utilisées pour faire la comparaison entre Digital Ocean et Scalingo.

Je ne suis toujours pas administrateur système. Si vous constatez des irrégularités dans mes tests, n’hésitez pas à m’en faire part et je les corrigerais. Cependant, je pense utiliser une méthode simple se basant sur des faits afin d’avoir une analyse pertinente.

L’application

Les Collectionneurs Associés est une application Rails qui n’a pas été conçue uniquement pour des tests. Cela nous donne une meilleure idée du comportement des serveurs dans la réalité.

Les serveurs

L’offre la plus petite de Clever Cloud coûte 14,40€ par mois. Pour ce prix, nous avons 1 CPU et 1Gb de RAM. Pour le même prix, chez Scalingo, nous avons une machine avec 1CPU et 512Mb de RAM. Cependant, avec Scalingo, il est possible de descendre plus bas avec 256Mb pour 7,20€. J’ai choisi de prendre l’offre à 14,40€ dans les deux entreprises. Les deux serveurs se trouvent en France.

Le serveur à partir duquel je fais mes tests est un serveur fourni par Digital Ocean situé à Londres. Il est donc représentatif des clients de l’Europe de l’Ouest, incluant la France, évidemment.

Le code

Le code n’est probablement pas le meilleur que j’ai écrit de ma vie, mais est largement suffisant pour faire ce que je souhaitais.

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
require 'benchmark'
require 'net/http'
require 'openssl'

NUMBER_OF_THREADS = 10
NUMBER_OF_REQUESTS_PER_THREAD = 100
URL = 'https://stagingcollectionneurs.scalingo.io/fr/provider_registrations/new'

threads = []
NUMBER_OF_THREADS.times do
  threads << Thread.new do
    Benchmark.bm do |x|
      x.report do
        NUMBER_OF_REQUESTS_PER_THREAD.times do |i|
          uri = URI(URL)
          http = Net::HTTP.new(uri.host, uri.port)
          http.use_ssl = true
          http.verify_mode = OpenSSL::SSL::VERIFY_NONE
          http.start do
            http.request_get(uri.path) do |res|
              p res.code + " : " + i.to_s
            end
          end
        end
      end
    end
  end
end

Ce code permet d’entrer une adresse et de simuler un certain nombre de visites concurrentes faisant un certain nombre de requêtes. À la fin de l’exécution du programme, le temps de réponse de chaque processus est affiché. Ce code ne prend pas en compte le chargement des images et des assets. Dans mon cas, ces éléments sont stockés sur un CDN et sont donc indépendants du serveur où l’application se trouve.

Test 1

Ce premier test affiche une page simple avec 11 requêtes. Voici les temps de réponse :

Scalingo :

  126.364873
  126.482741
  126.609597
  126.741594
  126.857076
  126.988266
  127.107123
  127.235066
  127.356753
  127.469629

Clever Cloud :

  127.890590
  128.021063
  128.147565
  128.274117
  128.400284
  128.528602
  128.655974
  128.777820
  128.897637
  129.032317

Pour ce test, on s’aperçoit que les résultats sont quasiment identiques. La différence de 2 secondes est, pour moi, négligeable.

Test 2

Pour continuer, j’ai réexécuté le programme sur une page plus complexe. Voici le résultat :

Scalingo :

  762.209817
  762.938170
  763.748126
  764.493016
  765.395998
  766.176983
  767.026748
  767.746600
  768.578646
  769.388282

Clever Cloud :

  766.513019
  767.324059
  768.050523
  768.837619
  769.624915
  770.354487
  771.162319
  771.894288
  772.703604
  773.544202

Encore une fois, la différence des temps de réponse est négligeable. Pour le moment, les performances de l’application hébergée sur les serveurs des deux entreprises sont équivalentes.

Test 3

J’ai voulu poursuivre avec la page d’inscription, plus complexe.

Scalingo :

  415.211191
  415.640399
  416.049001
  416.437286
  416.847855
  417.337447
  417.744488
  418.145630
  418.528678
  418.999209

Clever Cloud :

  356.496478
  356.825021
  357.213072
  357.562785
  357.917548
  358.310875
  358.650679
  358.991046
  359.396792
  359.738898

Clever Cloud est légèrement plus rapide et, pour moi, ces résultats permettent de rattraper les légers retards enregistrés précédemment.

Conclusion

Voici une conclusion très ennuyante pour un article comparatif : les performances des deux offres sont équivalentes. Ces résultats ne me permettent pas de trancher entre l’un et l’autre.

Les deux entreprises offrent un très bon support, leurs interfaces d’administration sont très bien faites et l’utilisation est deux systèmes est très simple. Pour choisir, il n’y a pas d’autre solution que de tester vous-même et de faire votre propre opinion, kit à vous baser sur des notions plus subjectives.

Malgré tout, à la fois Scalingo et Clever Cloud sont plus performants qu’Heroku et Digital Ocean. Je leur donne une position qui serait décevante aux JO, la médaille d’or exequo.

Benchmark : digital ocean vs scalingo

| Comments

Il y a peu, j’ai parlé avec Yann Klis, de Scalingo, sur le forum de Human Coders. Suite à cette discussion, j’ai souhaité effectuer un benchmark pour comparer les performances de Digital Ocean et de Scalingo. Dans cet article, je vais exposer les résultats des tests ainsi que ma méthodologie.

L’application

Voici l’application testée : https://www.associatedartcollectors.com/fr. Il s’agit d’une application Rails optimisée, avec un système de mise en cache, des assets sur un CDN, etc. Il s’agit d’une vraie application (encore en développement). J’ai préféré l’utiliser plutôt que d’en faire une uniquement pour des tests afin de mieux représenter la réalité.

Les serveurs

Le serveur Digital Ocean est situé à Francfort et coûte 10$ par mois pour 1Go de RAM. Scalingo, quant à lui, est situé en France et coûte 14.40€ pour 512Mb. Scalingo est donc légèrement plus cher pour moins de puissance.

Scalingo étant beaucoup plus facile à gérer, je pense que le temps économisé au niveau de la gestion du serveur vaut largement le léger surplus de prix. En effet, dans son utilisation, Scalingo ressemble davantage à Heroku qu’a Digital Ocean. J’ai choisi de ne pas comparer Scalingo à Heroku, car, selon de précédents tests, Digital Ocean offre une meilleure performance. J’ai voulu comparer Scalingo au meilleur.

Note

Je ne suis pas administrateur système. Il est probablement possible de faire mieux que ce que j’ai fait sur Digital Ocean. Ceci dit, je suis probablement dans la même situation qu’un bon nombre de développeurs. L’intérêt des systèmes similaires à Heroku ou Scalingo est également ne pas s’occuper du système. On créer l’application en 2 minutes, on pousse l’application et ça marche. C’est tout.

Les tests

La plus grosse part de marché de Scalingo est située en France. J’ai souhaité commencer mes tests proches de la France. Pour cela, j’ai choisi de créer un droplet Digital Ocean à Londres.

Mon objectif a été de simuler un certain nombre de requêtes et ceux de manière concurrente. J’ai donc créé un code qui lance plusieurs processus simultanément. Chaque processus effectue un certain nombre de requêtes. Le temps effectué par chaque processus permet de comparer la performance. Plus les requêtes se sont complétées rapidement, plus le serveur est efficace.

Le code

Le code n’est probablement pas le meilleur que j’ai écrit de ma vie, mais est largement suffisant pour faire ce que je souhaitais.

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
require 'benchmark'
require 'net/http'
require 'openssl'

NUMBER_OF_THREADS = 10
NUMBER_OF_REQUESTS_PER_THREAD = 100
URL = 'https://stagingcollectionneurs.scalingo.io/fr/provider_registrations/new'

threads = []
NUMBER_OF_THREADS.times do
  threads << Thread.new do
    Benchmark.bm do |x|
      x.report do
        NUMBER_OF_REQUESTS_PER_THREAD.times do |i|
          uri = URI(URL)
          http = Net::HTTP.new(uri.host, uri.port)
          http.use_ssl = true
          http.verify_mode = OpenSSL::SSL::VERIFY_NONE
          http.start do
            http.request_get(uri.path) do |res|
              p res.code + " : " + i.to_s
            end
          end
        end
      end
    end
  end
end

Ce code permet d’entrer un nombre de processus simultané et le nombre de requêtes fait pour chaque processus. De plus, il permet d’indiquer la page appelée par le code. Pour les tests, j’ai choisi des pages différentes qui sont représentatives de l’application.

Le code permet également d’afficher le statut de la requête envoyé, afin de s’assurer qu’elles sont toutes valides, ainsi que le numéro de la requête effectuée, juste pour voir la progression.

J’ai eu un problème avec le protocole SSL sur Digital Ocean. Pour le test, j’ai simplement désactivé la vérification.

Test 1

Le premier test consiste uniquement à visiter une page. Pour l’affichage de cette page, 11 requêtes SQL sont exécutées.

Digital Ocean :

Threads : 10
Requests per thread : 100

Temps de réponse :
  163.755285
  163.906003
  164.070419
  164.222361
  164.379131
  164.520751
  164.717367
  164.894695
  165.059584
  165.245484

Scalingo :

Threads : 10
Requests per thread : 100

Temps de réponse :
  110.868637
  110.982509
  111.086731
  111.195775
  111.377322
  111.482194
  111.590034
  111.697870
  111.821420
  111.938271

Ce premier test montre clairement que Scalingo offre un temps de réponse plus rapide. Scalingo est quasiment deux fois plus rapide.

Test 2

Dans ce deuxième test, j’ai voulu tester le comportement avec plus de requêtes concurrentes.

Digital Ocean :

Threads : 100
Requests per thread : 10

Temps de réponse :
  150.062375
  150.365437
  150.532612
  165.780870
  165.941798
  166.111019

Scalingo :

Threads : 100
Requests per thread : 10

Temps de réponse :
   92.787676
   92.877818
   92.959175
  ...
  102.423316
  102.525122
  102.622236

Encore cette fois, Scalingo est nettement supérieur. Pendant que les tests s’effectuaient, je suis allé sur les deux sites avec mon navigateur. Même si cela ne se reflète par sur les résultats du benchmark, j’ai constaté une grande dégradation de performance pour les deux fournisseurs.

Test 3

Par la suite, j’ai souhaité tester une autre page un peu plus complexe. Sur cette page, plus de requêtes SQL sont effectuées et il y a plus de code à exécuter.

Digital Ocean :

Thread : 10
Request : 100

Temps de réponse :
  204.311959
  204.509295
  204.683958
  204.864534
  205.055946
  205.240614
  205.440767
  205.621924
  205.807302
  206.020173

Scalingo :

Thread : 10
Request : 100

Temps de réponse :
  143.032002
  143.170704
  143.322095
  143.458987
  143.596800
  143.742877
  143.877174
  144.017422
  144.161915
  144.303397

Sans surprise, le résultat est le même dans ce cas.

Test 4

Enfin, j’ai voulu tester une page encore plus complexe. Il s’agit du formulaire d’inscription d’un utilisateur. J’utilise des gems comme SimpleForm pour gérer le formulaire. Les listes des services, des pays et des régions sont disponibles ce qui correspond à autant de requête SQL et de donnée à traiter.

Digital Ocean :

Thread : 10
Request : 100

Temps de réponse :
  420.542306
  420.998163
  421.375207
  421.724786
  422.231918
  422.618054
  422.983907
  423.442330
  423.815438
  424.163915

Scalingo :

Thread : 10
Request : 100

Temps de réponse :
  669.174683
  669.800881
  670.571744
  671.256995
  671.949939
  672.582819
  673.282322
  673.983594
  674.634513
  675.310771

Cette fois, Digital Ocean est plus rapide. Je pense que c’est là que la différence de puissance du serveur se fait sentir. Étant donné qu’il y a plus de code a exécuter, le traitement nécessite plus de ressource, et donc, Digital Ocean est avantagé. Ceci dit, cette page n’est pas l’une des plus utilisées et je pense que la performance est plus importante pour les pages permettant uniquement l’affichage.

Conclusion

Je pense que Scalingo gagne le duel. En plus d’offrir une performance plus qu’honorable, la gestion du serveur est grandement simplifiée. Je conseille vivement d’essayer cet outil si vous n’avez pas besoin d’avoir un accès complet à la machine. Comme moi, les développeurs ne sont pas toujours des administrateurs systèmes. Je trouve beaucoup plus simple de laisser la gestion du serveur à quelqu’un d’autre. En plus d’être probablement mieux configuré que ce que j’ai fait, c’est également plus sécuritaire, car, si une faille de sécurité est découverte, le problème sera géré par des professionnels dans le domaine.

Pour cet article, mes tests ont été effectués depuis Londres afin de représenter la clientèle européenne. Pour ma part, je me situe au Québec. Dans une seconde étape, je vais tester depuis des serveurs en Amérique du Nord et à partir d’autres endroits dans le monde pour observer le comportement selon les lieux.

Dans un prochain article, je vais faire la comparaison entre Clever Cloud et Scalingo. Surveillez mes prochains articles pour connaitre les résultats de mon prochain benchmark.

Comment ça marche : le coeur d’activerecord

| Comments

Il y a quelque temps, je me suis lancé dans la lecture du code source de Rails. Mon but étant de mieux comprendre son mécanisme et, peut-être, de devenir un contributeur. J’ai choisi de commencer par ActiveRecord étant donné que je trouve que c’est le module le plus “magique” de Rails. J’ai donc voulu comprendre mieux cette magie apparente. Dans cet article, je vais tenter de comprendre et d’expliquer ce qu’il se cache derrière ActiveRecord::Base ainsi que le noyau d’ActiveRecord.

Comme dans les articles précédents, je vais utiliser Pry pour explorer. Je vous conseille fortement de lire le code en même temps que l’article.

Pour commencer, je vais reprendre le code servant à créer des issues dans ActiveRecord en y plaçant un breakpoint afin de pouvoir étudier le comportement du modèle.

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
unless File.exist?('Gemfile')
  File.write('Gemfile', <<-GEMFILE)
    source 'https://rubygems.org'
    gem 'rails', github: 'rails/rails', ref: '6a7ac40dab'
    gem 'arel', github: 'rails/arel'
    gem 'sqlite3'
    gem 'pry-byebug'
  GEMFILE

  system 'bundle'
end

require 'bundler'
Bundler.setup(:default)

require 'active_record'
require 'minitest/autorun'
require 'logger'

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :posts, force: true  do |t|
  end

  create_table :comments, force: true  do |t|
    t.integer :post_id
  end
end

class Post < ActiveRecord::Base
end

require 'pry'; binding.pry
puts 'Just a line to make pry stop'

ActiveRecord

Commençons par le commencement. Lorsque l’on charge la gem activerecord, le fichier activerecord.rb est inclus. Comme on peut le voir en lisant le code, celui-ci commence par chargé ses dépendances.

1
2
3
4
5
6
7
require 'active_support'
require 'active_support/rails'
require 'active_model'
require 'arel'

require 'active_record/version'
require 'active_record/attribute_set'

On comprend donc que ActiveRecord dépend d’ActiveSupport, ActiveModel et Arel. ActiveSupport est un module fournissant des fonctions utiles dans les autres modules de Rails. ActiveModel contient les informations spécifiques au modèle du design pattern MVC sans contenir les informations relatives à la base de données. Arel, quant à lui, permet de créer des requêtes SQL en Ruby.

Les premières lignes du module sont les suivantes :

1
2
3
  extend ActiveSupport::Autoload

  autoload :Attribute

Plutôt que de faire un require, ActiveRecord utilise le autoload d’ActiveSupport. ActiveSupport permet de déterminer le nom du fichier à charger en incluant le nom du module. Si l’on appelle autoload :Concern depuis le module ActiveSupport, “active_support/concern” est déterminé. Cette chaîne de caractère est ensuite envoyée à la fonction autoload de Ruby. De cette façon, les modules ne sont chargés qu’au moment où ils sont appelés. C’est uniquement lorsque l’on utilisera ActiveSupport::Concern dont le fichier sera chargé. Il s’agit d’un procédé permettant d’économiser la mémoire puisque l’on ne charge pas ce qui est inutile.

On continuant la lecture du code, on peut s’apercevoir que certain des modules sont chargé dans un block eager_load. Les chargements automatiques sont mis dans un tableau. Les modules contenus dans ce tableau seront chargés quand la fonction ActiveSupport.eager_load! sera appelée.

Certains des éléments sont chargés dans block autoload_under. Il s’agit, simplement, d’un block ajoutant un dossier au chemin chargé.

Dans le bas du fichier, la fonction eager_load! est définie. Celle-ci permet de forcer le chargement de sous-modules. Cette fonction à été introduit dans ce commit. D’après ce que je comprends, ce code peut-être utile quand on fait du multithreading ou pour être “CoW friendly”. J’avoue ne pas savoir ce que veut dire “CoW”. Si quelqu’un peut m’éclairer, ça me plairait!

La dernière partie consiste en deux “hook”.

1
2
3
4
5
6
7
ActiveSupport.on_load(:active_record) do
  Arel::Table.engine = self
end

ActiveSupport.on_load(:i18n) do
  I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
end

Ces appels vont activer des événements stockés dans des tableaux puis stock à nouveau pour une utilisation ultérieure.

ActiveRecord::Base

Tous les développeurs utilisant Ruby on Rails ont probablement fait un modèle héritant de ActiveRecord::Base. Quand on regarde le fichier base.rb, on s’aperçoit qu’il s’agit uniquement d’un fichier en incluant d’autres et faisant des include et des extend d’autres modules. Deux lignes sont intéressantes, ActiveSupport.run_load_hooks(:active_record, Base) et include Core.

L’avant-dernière ligne exécute les événements stockés précédemment. ActiveRecord est donc indiqué comme étant le moteur par défaut de Arel.

Conclusion

Voici donc le coeur d’ActiveRecord. Je vais tenter de poursuivre ma lecture du code et j’exposerai mes découvertes dans de prochains articles.

Comment ça marche : les associations dans activerecord

| Comments

Les associations sont une part importante d’ActiveRecord. Il s’agit d’éléments que l’on utilise dans les premières phases d’apprentissage de Rails. Bien que son utilisation soit simple, l’implémentation est assez compliquée. Je vous propose d’explorer le fonctionnement en observant le code exécuté à l’appel de l’association belongs_to afin de comprendre le mécanisme complexe.

Conserver les changements de valeurs grâce à activemodel::dirty

| Comments

Dans cet article, je vous propose d’observer le comportement d’ActiveModel::Dirty et d’en comprendre le fonctionnement en consultant le code source. ActiveModel::Dirty est l’un des modules méconnus de Rails. Celui-ci conserve l’historique des changements apportés aux attributs d’un objet et de revenir en arrière si besoin.

Exploration avec pry

| Comments

Les IDE traditionnels possèdent généralement des outils avec une interface graphique pour déboguer. Pry, quant à lui, offre les mêmes possibilités en utilisant des lignes de commande. Pry est un REPL (Read-Eval-Print Loop) qui permet de naviguer dans le code afin d’expliquer un bogue ou de comprendre le fonctionnement interne d’une Gem. Nous allons voir comment faire dans cet article.

Utiliser activerecord sans rails

| Comments

ActiveRecord est l’une des premières classes que l’on apprend à utiliser avec Rails. Dans la vie d’un Rubyste, il est possible que l’on souhaite l’utiliser sans Rails pour l’exécuter dans un programme en ligne de commande ou dans une application utilisant Sinatra par exemple. Nous allons voir comment faire en quelques lignes.