ActiveRecord as an implementation of a design pattern straight out of the book

ActiveRecord has been built straight from the Martin Fowler's Single Table Inheritance design pattern. Period. This is fine for simple applications with that can live with the database design imposed by the application framework.

Once the developer tries to think throughly the database design, he immediately hits the limits of the STI paradigm. Here's an example.

One common method to define a hierarchical relation in Object-Relational Mapping where a child can have only one parent is to put the reference to the parent in the child table. This is a common and very efficient way to map a class hierarchy into database tables in Hibernate, for instance. The resulting tables can then look as follows:

  `id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`id`)
  `id` int(11) NOT NULL auto_increment,
  `foo_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
  `id` int(11) NOT NULL auto_increment,
  `foo_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)

Note that this table structure allows to efficiently retrieve bars and bazs from foos, as well as ascend to foos from bars and bazs.

If you are bound to ActiveRecord, it imposes a solution with one table having one additional id to identify the parent and a string to identify the type of the child. All fields belonging to bars and bazs will appear in the same table, intermixed.

Who benefits from the service vouchers (dienstcheques, titres-services)

PHBs, stay away. This is as complicated as the Type C work permit gamble, Type B vs. immigration legal loophole or the intrinsics of the payslip calculation.

Here is the idea of service vouchers in a 100 words. A few years ago, you could find someone to clean your house or iron your shirts by a word-of-mouth. After the job was done, you paid them in cash 8 € per hour and you were done. Nowadays, you first buy service vouchers from a multinational, state-assigned monopoly at the price of 6.70 €. You then call a service provider which is a company licensed by the state to accept service vouchers for house holding services. They make you sign a contract and they send their employee to you. Every visit, you give the cleaner as many service vouchers as the hours worked. The cleaner returns the service vouchers to his employer and the employer claims from the state 20 € per voucher. You, as a customer are not done yet as well, you can subtract the amount you paid for service vouchers in your personal yearly tax form, which decreases the real price of service vouchers down to 4,69 €.

At first sight, there's a clear gain from the customer's point of view. The service gets cheaper. However, the customer loses time in paperwork and is somewhat bound by the contract from now on. There's also an intuitive expectation of decreased service quality, as the service becomes less personal.

On the other hand, the state clearly loses 13,30 € per working hour, and some more money in personal taxes, which makes the service vouchers program look slightly unrealistic. Where's the catch?


A nasty trick the belgian payslip can play to you

Nearly everyone gets one surprisingly small monthly pay during his 1st year or so in a company.

In order to understand what happens, one has to know that workers earn their holidays this year for the next year. Once someone quits an employer, he gets a nifty paycheck which includes the monetization of the earned holidays that the employee did not take, yet. Now, once he decides to spend those holidays next year, he usually forgets that they have already been paid by the previous employer. That is, he actually takes an "unpaid" holiday from his current employer, instead of a paid one. Naturally, these days have already been paid before, but who cares, when the money is gone ;-)

All this is a prelude. Here is a nasty trick that makes the payslip look awfully unjustified.

The general rule is to adjust the monthly salary to take into account those "unpaid" holiday days not on a month-by-month basis, but once in a year, the month when the employee has taken more than 50% of the amount of the days off he was entitled to take.

Here's an example. You leave your old employer on December, 31. Next year, you take 5 days off during the first half of the year and then leave on vacation for 10 working days in August. Suppose this August had 20 working days. By the end of August, you will receive your salary for ~ 5 working days, as the salary calculation this month will take into account all the 15 "unpaid" days you have taken off so far.


Some more ActiveRecord bashing

This time, it took me around 8 working hours since the start of a new ruby-based project before I stumbled upon what seems to be a serious bug. The first time I tried to extend an association, activerecord failed with

associations.rb:1368:in `const_set': wrong constant name FooBar::FooBarsAssociationExtension (NameError)

which can be easily reproduced running the following code:
{syntaxhighlighter brush:ruby}
require 'rubygems'
require 'activerecord'

module FooBar
class Foo

ActiveRecord and the DRY3 principle

ActiveRecord is a beautiful piece of software. But just step aside of the prescribed road, and you are guaranteed to have problems.

This time, my problems began when I started to design the model first. I quickly laid out a couple of screens of objects, wrote the connection line and ran the code.

class SubjectLocator  "String"

# a dozen more objects follow...

  :adapter  => "mysql",
  :host     => "localhost",
  :username => "test",
  :password => "test",
  :database => "activerecord"

It has not come as a surprise that ruby replied with an exception.

Table 'activerecord.subject_locator' doesn't exist: SHOW FIELDS FROM `subject_locator` (ActiveRecord::StatementInvalid)

What surprised me is that after half an hour of search on the internet, I found no way to boostrap a DB schema out of the model. There were discussions on the rails mailing list. They even went as far as suggesting non-destructive automatic migrations, a feature that exists in Hibernate for at least 5 years already. None dared to implement either.

I am now left with one solution. Apply the DRY3 principle, aka "Do Repeat Yourself 3.times" and start writing the migrations script for my models (repeat!), as well as an SQL schema for my MySQL database that would keep indexes, views and triggers in addition to what I will boostrap from migrations (repeat again!)

Авторское право vs. всенародное обсуждение

Тут Лукьяненко поставил ссылку на высказывание об авторском праве Романа Афанасьева. Что симптоматично, у обоих комментарии отключены. К чему бы это?

ЗЫ: Назовите меня идиотом, но чтобы найти ссылку на этот постинг Лукьяненко, пришлось прошерстить 431 страничку, от id предыдущего постинга до id следующего. Примерно вот так:

for i in `seq 304622 305053`; do
done |grep gringrin *html

Интересно, есть ли какой-нибудь более прямой способ ставить линки на постинги с отключенными комментариями?


rubygems as the biggest obstacle to Ruby's adoption

Everyone and his friend is already aware that installing rubygems to a non-default location was a nightmare just until very recently (that is, version 0.9.5, produced on 2007-11-19).

Now, suppose we try to do something simpler, like err... uninstalling a gem. gem remove mygem yields no results. I do gem --help and... there is nothing about removing a gem in the command line help. Fine. Before deleting manually, let's look it up on the internet. RubyGems User Guide says it should be gem uninstall mygem. How nice!

OLPC: Omnipresent Loyalty Protection & Control

Тут abbra пишет про удачное внедрение OLPC и ненароком сообщает статистику испльзования этих компьютеров детьми. Это значит, что кто-то, даже не родители, а в лучшем случае учителя мониторят детские компьютеры на предмет того, что и когда они написали.

А вы бы хотели, чтобы в ваш комп заглядывали без спросу?