Ruby off Rails
Building web applications with Ruby doesn't imply Rails.
Although it's not a just-released document, the Ruby off Rails presentation is a great roundup of available options, in order to build a web site with today's most suitable components.
Thin: a fast and simple Ruby web server
If you are looking for an alternative to Mongrel, here's a very good one : Thin
It's as stable as Mongrel, just lighter and faster.
Next Internet Explorer to pass the Acid 2 test ?
According to the IE Blog, Internet Explorer 8 passed the Acid 2 test - more on this.
It will obviously take years before it is released and people actually leave IE 6 and 7 for it, but still, it shows that Microsoft seems to be on the right track.
So rejoy, web developpers, maybe some day it will finally be possible to write XHTML/CSS code without ugly tricks in order to work around IE bugs and limitations. Maybe. There's hope.
Ruby on Rails 2 is out!
The final release of Ruby on Rails is now available.
Check out what's new in Rails 2
(for french freaks, Nicolas has un bon résumé en français des nouveautés de Rails 2 )
Or if you are looking for a lightweight and faster alternative to Rails, check out MERB (More about MERB and More again about MERB)
Hot news in the Ruby on Rails world
If you didn't watch the Ruby On Rails weblog lately, you missed hot news from the press:
- The previous release of Rails 2.0 is out. Sexy migrations, an SQL cache, performance enhancements, automatic security enhancements (anti-XSRF / XSS, etc), a real debugger... Rails is still on top.
- Scaling a rails application from the bottom up is an extremely interesting paper by Joyent, telling everything about their scalable hardware and software architecture. Even if you don't use Rails, this paper is a must read if you ever have to face scalability issues. It covers everything, absolutely everything. Probably the best paper I've read seen on the subject. If you are a CEO, CTO, developper or sysadmin, read this. Skip the first pages if you aren't interested in Rails, but all the rest is really worth reading.
- Want a free book about Rails? Get the Patrick Lenz book for free. The giveaway will expire in less than 2 months.
Swiftiply: boost your framework-driven web applications
It's not a new project, but if you never heard about it, have a look at Swiftiply :
"Scaling your web applications should be easy. Start small, then when you need more capacity, just add it. Another process. Another machine. More capacity, instantly. Without additional configuration or software restarts.
That is what you get with Swiftiply.
Swiftiply is a backend agnostic clustering proxy for web applications that is specifically designed to support HTTP traffic from web frameworks. It is a very fast, narrowly targetted clustering proxy. In back to back comparisons of Swiftiply to HAProxy, Swiftiply reliably outperforms HAProxy (tested using IOWA, Rails, and Ramaze backend processes) and, depending on your web framework, you may not even need to put a traditional web server into your architecture at all.
Swiftiply is a clustering proxy server for web applications. What makes it different from other clustering proxies, however, is that it expects the backend processes to connect to it. That is, the backend processes are clients of the Swiftiply server, as are the browsers out in userland. The advantage of this is that it permits the back ends to maintain a persistent connection with the proxy server, which eliminates socket setup/teardown costs. And even more importantly than that, it permits backend processes to be started up or shut down without requiring any notification or configuration of the proxy. So, if more capacity is needed, all one needs to do is start the processes. It will immediately be available and will begin to be utilized."
I finally tested it with Rails and it works as advertised. Performance is immediately doubled, and it's a breeze to install. Swiftiply rocks.
Playing with Ruby 1.8, Ruby 1.9 and PHP
Today, I wanted to give a try to the latest Ruby 1.9 snapshot.
After disabling the set_thread_priority() call, it compiles and installs fine on OpenBSD. My test host is an Athlon 64 3400, running OpenBSD-current/amd64.
Before all, I wanted to benchmark it against Ruby 1.8.
Here's a simple and stupid test script I wrote, just to have something that iterates over arrays, calls methods, use a class-scoped counter, and does common tests:
class String
@@counter = 0
def testfunc2
array = self.split
str = ""
array.each do |word|
str << word unless word.empty? or @@counter < 0
@@counter += 1
end
end
def testfunc!
self << "abc "
testfunc2.join("-")
end
end
str = "initial string"
5000.times { str.testfunc! }
Very simple. It takes a string, it adds "abc " to that string, it transforms it into an array of words, it iterates over every word and add each word to a new string with two useless tests by the way, it increments a class-wide counter, it returns the array of words, then all these words are joined by a dash. That happens 5000 times.
Here we go for the bench:
- Ruby 1.8: 0m23.06s
- Ruby 1.9: 0m11.65s
That's pretty cool. Ruby 1.9 is more than twice as fast as Ruby 1.8 here!
Out of curiosity, I wanted to translate that simple example to PHP in order to see how it would compare. Unfortunately, adding methods to strings is something PHP is unable to do. PHP doesn't let you extend strings, numerics, nor functions. So in order to do something similar to the previous test scripts, we have to reinvent the wheel, we have to invent a "String" class. Woah. And we can't even use that class as a string, because unlike any object-oriented language from the past 20 years, PHP is not even able to overload operators. It's why we have to invent a method ("set_value") just to set the content of the string. Ok, here we go for the PHP version of the above script :
class String {
var $str;
protected static $counter = 0;
public function set_value($str) {
$this->str = $str;
}
public function __construct($str) {
$this->set_value($str);
}
public function __toString() {
return $this->str;
}
public function testfunc2() {
$array = split(' ', $this);
$str = "";
foreach ($array as $word) {
if (!(empty($word) || self::$counter < 0)) {
$str .= $word;
}
self::$counter++;
}
return $array;
}
public function testfunc() {
$this->set_value($this . "abc ");
implode($this->testfunc2(), "-");
}
}
$str = new String("initial string");
$i = 5000;
do {
$str->testfunc();
} while (--$i !== 0);
All those "$this->" and "self::" are boring and useless, they don't bring anything but ugly source code. PHP loves to annoy programmers by forcing them to write symbols like "$", "_", "->" and "::" everywhere. You have to write them over and over again, for everything you need in the current object, or you will get that wonderful error: "syntax error, unexpected TPAAMAYIMNEKUDOTAYIM".
Okay, let's benchmark the PHP script:
- Ruby 1.8: 0m23.06s
- Ruby 1.9: 0m11.65s
- PHP 5.2.3: 1m36.46s
Yes, that's one minute and 36 seconds. You got the codes, try them yourself. The PHP script is not only ugly, it's also dog slow.
Please stop calling PHP a serious object-oriented language and please stop benchmarking languages over a function that computes prime numbers.
An age is not a duration
Once you know the birth date, how to compute how old someone is?
A common belief for computer geeks is that an age is a duration. Here's a typical function that illustrates this.
require "time"
DURATION = 1461 * 24 * 60 * 60 / 4
def age(d)
((Time.now - Time.parse(d)) / DURATION).floor
end
Let's see:
age "1977-04-13"
=> 30
It seems to work. But it actually doesn't.
For non-computer geeks, birthdays are about dates. Someone born on April 13 will celebrate his birthday on April 13. This is the day he will legally get older.
Let's change a bit the function in order to enter arbitrary dates:
def age(a, b)
((Time.parse(a) - Time.parse(b)) / DURATION).floor
end
Ok. I'm born on 1999-02-02. How old will I be on 2000-02-02?
age "2000-02-02 00:00:00", "1999-02-02"
=> 0
WRONG. On 02-02 I will be 1.
I'm born on 2000-02-28. How old will I be on 2001-02-27?
age "2001-02-27 06:00:00", "2000-02-28"
=> 1
WRONG AGAIN. On 2001-02-27 I will still be 0. I will be 1 on 02-28. Yes, ask mum.
I'm born on 1999-03-01. How old will I be on 2000-02-29?
age "2000-02-29 06:00:00" "1999-03-01"
=> 1
WRONG AGAIN. If my birthday is on 03-01, I will celebrate it on 03-01, not on 02-29.
For the record, here's a simple way to get the correct age (adapted from a code snippet by Marc Love):
def age(d)
date = Time.parse(d)
now = Date.today
age = now.year - date.year
if now.month < date.month ||
(now.month == date.month && date.day >= now.day)
age = age - 1
end
return age
end
lighttpd 1.4.15 has been released
A new maintenance release of the stable branch of lighttpd is now available.
Here's the changelog
If you are still using Apache, please give it or try, or alternatively, try Nginx, you won't look back.
Here you can download the port diff I made for OpenBSD-current.
Works fine so far.
Why are lightweight markup languages so heavy?
Forums, blogs and other community-based web sites need ways to let their users add some fun to the text. Smileys, bold, italic, paragraphs, alignments, colors, links and images are the basic stuff any user wants to have.
As the final rendering is usually HTML, using HTML in order to post new messages would obviously be the most efficient way.
But HTML is considered insecure, complicated and not error-proof.
This is why alternatives languages were invented. BBCode, Textile and Markdown are the most common ones.
So, an user enters text written with one of those alternative markup languages, and a complex parser transforms that into HTML. Since the user might edit the text later, the original (not HTML) text must be stored.
And since rendering Markdown (for instance) to HTML is a complex and CPU-intensive operation, applications usually save both the HTML version and the Markdown version. This is a big waste of database resources, but this is required in order to save a lot of CPU cycles.
In fact this is actually required because current implementations of HTML renderers for BBCode, Textile and Markdown are slow like hell.
Please give me pointers if you know of any C or C++ implementation, but all implementations I could find were in Ruby, PHP, Perl and Python. While I love these languages, I really think that rendering markup languages should be as fast as possible, ie. written in optimized C, C++ or even assembler. This is a critical part of any community web site and a main performance bottleneck.
Trying to avoid the side-effects of a slow implementation with caches and duplicated data is nothing but brain-damage, and it only shifts the performance bottlenecks to the database. And maintaining these caches and duplicated data adds another layer of complexity.
Why not just forget that and work on optimized rendering engines? No need to duplicate data, just keep one version and render the HTML (or the original) version as needed.
Here are three proposals:
- Write a fast rendering engine. Sure, playing with strings in C is not fun, but one week of work to get a fast engine is probably worth the try, considering the money it will save by making real-time rendering a reality.
- or: write the rendering engine in Javascript. Javascript implementations are fast enough for this, and you can always deliver an alternative version (SEO-optimized) for search engines.
- or: combine both. Have the C engine create the basic HTML structure, and have the javascript engine handle stuff like links and embedded videos.
I'm currently working on the three ways and so far, the results are very exciting.