Posts mit dem Label Rails werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Rails werden angezeigt. Alle Posts anzeigen

Samstag, 20. Februar 2010

Avoid Ruby 1.8.7 p248 and p249 with ActiveSupport

Yesterday I updated the stage environment of Zero X to ruby 1.8.7, but after that I suddenly couldn't login anymore. The problem was a Segmentation fault in Marshal.load used by ActiveSupport:

/usr/local/lib/ruby/gems/1.8/gems/activesupport-2.3.3/lib/active_support/multibyte/unicode_database.rb:37: [BUG] Segmentation fault

ruby 1.8.7 (2010-01-10 patchlevel 249) [powerpc-darwin8.11.0]

As described in the ticket the error occurs only in patchlevel 248 and 249. So I had to go back to p174 and now everything runs smoothly again.

Donnerstag, 24. September 2009

Migration auf Ruby 1.9.1

In den letzten Tagen habe ich mein Simulation Projekt auf Ruby 1.9 migriert. Leider verlief die Migration nicht ganz so einfach, wie ich mir das vorgestellt hatte. Teilweise muss nämlich eine exakte Version eines Gems installiert werden, ansonsten hagelt es Fehlermeldungen.
Um Ruby 1.8 und 1.9 parallel auf meinem Mac betreiben zu können, habe ich RVM installiert. Dies installiert alle zusätzlichen Ruby Versionen im Home-Verzeichnis unter .rvm. Zudem werden auch alle command line Befehle wie etwa 'rails' oder 'cucumber' separat gehandhabt. Unter RVM ist allerdings zu beachten, dass alle so hinzugefügten Gems nicht mit sudo installiert werden. Zudem musste ich eine frühere Version von Ruby 1.9, die ich noch unter /usr/local hatte, zuerst wegputzen.

Ich will hier nicht alle Leerläufe beschreiben, deshalb hier gleich die hoffentlich richtig Anleitung:

Um auf Ruby 1.9 zu wechseln:
rvm install 1.9
rvm use ruby 1.9
Darauf installiert RVM automatisch die aktuelle 1.9 Version.

Danach wenden wir uns gleich Rails selber zu. Die neuste Version 2.3.4 ist leider nicht lauffähig unter Ruby 1.9. Wenn auf die Session zugegriffen wird, erhaltet man folgenden Fehler:
undefined method `^' for "c":String (NoMethodError)
Deshalb muss auf 2.3.3 zurückgegriffen werden:
gem install -v='2.3.3' rails
Mein Projekt nutzt Cucumber und RSpec als Testframeworks. Hier können zwar die neusten Versionen installiert werden, jedoch muss auch Test-Unit mit der Version 1.2.3 und zwar exakt diese mitinstalliert werden:
gem install cucumber rspec rspec-rails webrat
gem install -v="1.2.3" test-unit
Als nächstes meldete Nokogiri, das von Webrat genutzt wird, einen Konflikt:
dyld: lazy symbol binding failed: Symbol not found: _rb_intern2
  Referenced from: /Users/adm/.rvm/gems/ruby/1.9.1/gems/nokogiri-1.3.3/lib/nokogiri/nokogiri.bundle
  Expected in: flat namespace

dyld: Symbol not found: _rb_intern2
  Referenced from: /Users/adm/.rvm/gems/ruby/1.9.1/gems/nokogiri-1.3.3/lib/nokogiri/nokogiri.bundle
  Expected in: flat namespace

Trace/BPT trap
Um diesen Konflikt zu lösen musste ich über Ports meine libxml Bibliothek aktualisieren und Nokogiri nochmals installieren:
sudo port install libxml2
sudo port install libxslt

gem install nokogiri
Danach startete mein Projekt endlich unter Ruby 1.9 auf. Meine eignen Konflikte mit 1.9 konnte ich dank meinen Testsuits innerhalb einer halben Stunde lösen. Gute Tests sind wirklich Gold wert.

Freitag, 6. Februar 2009

2 Wochen CakePHP

Nach 2 Wochen arbeiten mit CakePHP hier eine kurze Bilanz. Im Grossen und Ganzen versucht CakePHP die Ideen und Konzepte von Rails zu übernehmen, was auch in vielen Teilen des Frameworks gelingt.
Der grösste Kompromiss den CakePHP einging, ist auf PHP4 statt gleich auf PHP5 zu setzten. Dies hat leider weitreichende Konsequenzen:

Das beginnt schont bei ganz einfachen Sachen, wie etwa dass CakePHP kein Exception Handling kennt. Stattdessen werden E_USER_WARININGs und dergleichen ausgelöst.

Der grösste Unterschied zu Rails besteht jedoch in der Implementierung von ActiveReocrd. Das AR-Objekt wird in erster Linie als SQL Generator eingesetzt, die 'find' und 'read' Mehtoden geben keine Objekte zurück, sondern tief verschachtelte Arrays. Die Implementierung von CakePHP erinnert daher mehr an ein Table Data Gateway Pattern. Auch in CakePHP kennt Active Record die bekannten Callbacks wie 'beforeSave', aber auch hier wird mit Arrays gearbeitet, nicht mit Objekten.
Eine weitere Konsequenz daraus ist das CakePHP kein Single Table Inheritance oder deren polymorphe Variante kennt.

Zusammendfassend lässt sich aus meinen ersten Erfahrungen sagen, dass das Erarbeiten von Business Domain Objects in CakePHP wesentlich schwieriger fällt als in Rails. Das Active Record von CakePHP ist darauf ausgerichtet aus der Datenbank zu lesen und schreiben und die gewonnen Daten gleich auszugeben. Die Business Logik sollte gemäss dem Motto 'fat model, skinny controller' in die Model-Objekte abwandern, dies ist aber genau die Schwierigkeit, wenn diese mehrheitlich nur als Arrays daher kommen.
Trotzdem ist CakePHP eine gute Alternative, wenn man an PHP gebunden ist (oder wird). Zudem bieten heute alle Provider PHP, wer für ein einfaches Projekt einen billigen Host braucht ist CakePHP sicherlich eine Option. Für komplexere Projekte lohnt sich Ruby zu erlernen und auf ein durchgehend objekt-orientiertes Framework wie Rails zu setzten.

Donnerstag, 15. Januar 2009

Small Performance Test Rails vs. CakePHP

At my company we're currently evaluating a Web-Framework. Today we had a look at CakePHP and got some simple tutorial examples running. Because CakePHP is very close to Rails, I wrote one example also in Rails to see differences.
Just to get an impression about the performance of the two frameworks, I run ApacheBench to get some benchmarks.

But first things first, here some figures about the test environement:

  • iMac OS X 10.5.6, 2 GHz PowerPC G5, 1 GB RAM
  • PHP 5.2.6
  • CakePHP 1.2.0.7962
  • Ruby 1.8.6
  • Rails 2.2.2
  • MySQL 5.0.67
I wanted a very simple scenario, but one that effects all MVC components. I chosen to take an overview page, that displays a list of objects stored in the database. With Rails this task was accomplished by just using the scaffold generator. With Cake I could have also used the scaffold variable, but then I would have compared a static scaffolded page against a dynamic one. So I wrote the index function:
function index(){
  $jobs = $this->Job->find('all');
  $this->set('jobs', $jobs);
}
I put only 3 rows in the database table, so that reading from it takes virtually no time and we can better see the time consumed by the framework itself.
As one Mongrel can only handle one request at the time, I fired 50 requests in a row.
ab -n 50 -c 1 http://127.0.0.1:3000/jobs
Last thing I made, was a very small and straight forward PHP script, that does the same job. This way I had a benchmark of a script using only plain vanilla PHP with no framework overhead.
Here finally the results (see full reports below):
CakePHP                       Time per request:       365.572 [ms] (mean)
Rails (RAILS_ENV=development) Time per request:       105.029 [ms] (mean)
Rails (RAILS_ENV=production)  Time per request:        30.318 [ms] (mean)
Pure PHP                      Time per request:         9.026 [ms] (mean)
Honestly I was quite surprised. There's so much talk about Ruby being slow, which is surely true when compared to Java. Also PHP is faster in microbenchmarks. But it seems to me that PHP is only really fast when used as much as possible straight forward, this is what PHP was designed for. When it comes to build frameworks and OOP there're better tools.
Also the other known PHP Frameworks CodeIgniter and Symfony are not that different, CakePHP lies somewhere between them.
On the other hand Ruby really was designed as a pure OO language and it seems that this turns to be an advantage when building frameworks, also from a performance perspective.

The full results:
Rails (RAILS_ENV=development)
=============================

ab -n 50 -c 1 http://127.0.0.1:3000/jobs
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        Mongrel
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /jobs
Document Length:        3043 bytes

Concurrency Level:      1
Time taken for tests:   5.251 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      178251 bytes
HTML transferred:       152150 bytes
Requests per second:    9.52 [#/sec] (mean)
Time per request:       105.029 [ms] (mean)
Time per request:       105.029 [ms] (mean, across all concurrent requests)
Transfer rate:          33.15 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.8      0       6
Processing:    74  105  64.5     83     318
Waiting:       73  103  63.6     83     317
Total:         74  105  64.7     84     318

Percentage of the requests served within a certain time (ms)
  50%     84
  66%     86
  75%     88
  80%     91
  90%    237
  95%    304
  98%    318
  99%    318
 100%    318 (longest request)

RAILS (RAILS_ENV=production) 
============================

ab -n 50 -c 1 http://127.0.0.1:3000/jobs
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        Mongrel
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /jobs
Document Length:        3043 bytes

Concurrency Level:      1
Time taken for tests:   1.516 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      178236 bytes
HTML transferred:       152150 bytes
Requests per second:    32.98 [#/sec] (mean)
Time per request:       30.318 [ms] (mean)
Time per request:       30.318 [ms] (mean, across all concurrent requests)
Transfer rate:          114.82 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       3
Processing:    17   30  32.8     21     187
Waiting:       16   29  32.8     20     186
Total:         17   30  32.8     21     187

Percentage of the requests served within a certain time (ms)
  50%     21
  66%     24
  75%     25
  80%     26
  90%     34
  95%    138
  98%    187
  99%    187
 100%    187 (longest request)

CAKEPHP
=======

ab -n 50 -c 1 http://jobscake/jobs
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking jobscake (be patient).....done


Server Software:        Apache/2.2.9
Server Hostname:        jobscake
Server Port:            80

Document Path:          /jobs
Document Length:        4176 bytes

Concurrency Level:      1
Time taken for tests:   18.279 seconds
Complete requests:      50
Failed requests:        49
   (Connect: 0, Receive: 0, Length: 49, Exceptions: 0)
Write errors:           0
Total transferred:      217781 bytes
HTML transferred:       200781 bytes
Requests per second:    2.74 [#/sec] (mean)
Time per request:       365.572 [ms] (mean)
Time per request:       365.572 [ms] (mean, across all concurrent requests)
Transfer rate:          11.64 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       3
Processing:   329  365  42.2    355     570
Waiting:      329  364  39.6    355     543
Total:        329  365  42.4    356     572

Percentage of the requests served within a certain time (ms)
  50%    356
  66%    364
  75%    372
  80%    374
  90%    390
  95%    409
  98%    572
  99%    572
 100%    572 (longest request)

PURE PHP
========

ab -n 50 -c 1 http://localhost/develop/projects/Test/pure_php_jobs/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software:        Apache/2.2.9
Server Hostname:        localhost
Server Port:            80

Document Path:          /develop/projects/Test/pure_php_jobs/
Document Length:        1923 bytes

Concurrency Level:      1
Time taken for tests:   0.451 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      107200 bytes
HTML transferred:       96150 bytes
Requests per second:    110.80 [#/sec] (mean)
Time per request:       9.026 [ms] (mean)
Time per request:       9.026 [ms] (mean, across all concurrent requests)
Transfer rate:          231.98 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       1
Processing:     5    9   7.3      6      53
Waiting:        3    7   7.7      5      53
Total:          5    9   7.3      6      53

Percentage of the requests served within a certain time (ms)
  50%      6
  66%      8
  75%     10
  80%     12
  90%     13
  95%     16
  98%     53
  99%     53
 100%     53 (longest request)

Montag, 22. Dezember 2008

Nokogiri and Webrat

Today I made some more steps using RSpec. My new steps involved Webrat, a handy library for acceptance tests, which depends on Nokogiri. The installation guide of webrat only mentioned to require webrat in your helper. But I got the following error
NameError: uninitialized constant Nokogiri::CSS::XML
After a I while figured out, that you first have to require nokogiri explicitly. So my steps for webrat are now beginning with:
require 'nokogiri'
require "webrat/rails"

steps_for :webrat do
  
  When "visits '$link'" do |link|
    visits link
  end
  ...
To check your gem versions against mine, here an extract of my gem list:
Rails (2.2.2)
webrat (0.3.2)
nokogiri (1.1.0)
libxml-ruby (0.9.7)
libxslt-ruby (0.9.1)

Montag, 17. Dezember 2007

Roxanne bekommt Flügel

Kurz nach dem Release von Rails 2.0 kommt nun auch der neuste Release von Roxanne. In dieser neuen Version stand vorallem die Performance im Vordergrund:

Erstens wurde ActsAsTree durch ActsAsNestedSet ersetzt, genauer gesagt mit BetterNestedSet. Damit können nun ganze Content-Hierarchien mit einem Query geladen werden. Zum Vergleich, eine Seite mit etwa 250 editierbaren Elementen brauchte auf einem G4 1.42 GHz MiniMac im development Modus etwas über 9 sec (gähn!), im productive Modus etwa 3 sec. Jetzt braucht die gleiche Seite im development 6.5 sec, noch nicht gerade berauschend, aber im productive Modus nur noch 0.7 sec.

Zweitens setzt Roxanne nun auch Caching ein. Solange man auf der Site nicht eingeloggt ist, werden die Seiten direkt aus dem Cache geliefert. Das dauert dann gerade noch 0.0015 sec ;-) Und nicht zuletzt ist nun Roxanne auch Rails 2.0 ready.