Friday, 8 January 2010

Migration from Qcodo to Rails

I am re-developing an intranet in Rails. It is currently written in PHP with Qcodo as framework. It is very new intranet, so why I should re-develop it with Rails? Well, I do not like to program with PHP anymore and I have found many problems in Qcodo and I realized that the way to develop with that framework is not the way I like it.

This is a list of aspects that I do not like in PHP:

Every variable has to use the dollar character, the semicolon in the end of a statement, curly braces for blocks.

Namespaces in PHP 5.3 has an horrible syntax, it is similar to a DOS path (same slash).

PHP 5.3 has the infamous goto! Is that a way to improve a language? Crazy!

PHP is loosely-typed, which means that converts values behind the scenes and you need to have a good knowledge of the language to understand what it might happen to your data.

Variables are case sensitive, functions are not. There is not a real naming convention in the primitives.

Every function must be declared with the 'function' keyword, how redundant!

PHP attracts bad programmers (although there are good programmes that use PHP).

Many famous programs written in PHP are not really OOP, they do not use design patterns, or something to similar to a clean code, see Drupal, Joomla & co.

There are other reasons, but I want to talk about moving from PHP to Rails.

Qcodo problems are:

QFroms, the form used by Qcodo are dependent form JavaScript, without it, your web site/application will not work.

The JavaScript used is bugged, does not use a mainstream JS framework.

QForm controls, such as text boxes, select lists, sometimes loose the status, so the data have nasty Ajax errors that block the page (it becomes non-responsive).

Ajax error just make the QForm dead. This is not acceptable.

It is an MVC framework, but you do not have a front controller, so forget to use a nice URL out of the box; you have to build a front controller by your own and use mod_rewrite.

It is event-driven too, which is not bad. But, you define all your controls as you do in a desktop-like application, like in VB (the first version was made in Visual Basic!). Lots of HTML is embedded in objects, you do not get the feeling of making a template but you just write just $object->render(). HTML templates should have HTML or tags, as in Java, Pythons or Rails frameworks.

You cannot add JavaScript in your tags, because you do not has tags, but just $object->render() (well you can do it but it is awkward). Instead you have to create a custom object to put your Javascript (official way to do it).

Because of the previous point, to write JavaScript in Qcodo is a pain in the a...

Qcodo is a dead project because the creator, Mike Ho, has blocked the commits to the source code for a lot of time. Now the project is on Github, but it has not changed a lot, for me it is too late and I cannot see anything positive in the roadmap, if there is one.

Qcodo has been forked by some guys because of the problem stated above. The fork is Qcubed. I left that community becouse of their mentality and the ignorance of that people, of course not all of them, but most of the core developers. BDD and DDD for them is something trendy, to make some bucks with consulting. They do not know the framework properly, they are not as good as Mike Ho, they are going in nowhere. Symfony is a much better alternative, but is still PHP.

Again, there are other reasons but I want to talk about how to migrate to Rails.

In the end after evaluating Java, Groovy and Ruby, JRuby, I chose Ruby. Of course I am using the most famous framework, Rails. But how start to use Rails in a corporate intranet near to be released? I decided to write new modules with Rails and leave the rest with PHP, at least for now.

I started by cleaning the CSS and HTML template. When the template was ready I have adopted the same template for Rails and PHP, so the user could not spot the difference that the intranet is using two different environments and languages. Well, before doing that I had installed Pushion Passenger and Ruby Enterprise Edition on the testing and production server (well, the server's admin installed Passenger there).

Then I integrated the sessions by using the PHPSESSID cookie. The user first logs in the PHP intranet, using LDAP, than I store the PHPSESSID value in the database with a corresponding email address, which is unique and it is the user name too. In the application controller (Rails) I get PHP session id (PHPSESSID) from the cookie and than I query an intranet's web service, passing the sessoin id and getting back the corresponding email address. With the email of the user I get the identifier that I need to integrate PHP with Rails, at least the user's credentials. But, why not performing a query directly to the database instead of using the web service. I already have a standalone application that use this solution, so I just cut and pasted the code, with very little modifications, otherwise I just could query the database table.

The tables of the database (MySql) do not follow Rails naming conventions. The first idea was to use another database, but I realized that I could use the same database and Rails' migrations could managed everything, at least the tables used by Rails. I have found several way to use a legacy database with PHP and Rails. Here are some notes during my braindumps:

use ActiveRecord's table_name and primary_key methods to cope with the old table names.

to move functionality and data from PHP-land to Rails-land, use Tim Riley's acts_as_importable plugin

Use views: CREATE VIEW departments as select deptID as id,`honcho_userID` as head,`parent_deptID` as parent_id,`ordinal` as position,`deptName` as name,`code`,`description`,`contact_us`,`display`FROM dept

Use a table prefix to differentiate Rails table from legacy tables: in your config/environment.rb you would add: config.active_record.table_name_prefix = 'rails_'

How to import a legacy data: http://openmonkey.com/articles/2009/05/importing-legacy-data-in-rails

How to protected legacy database access from Rails: http://github.com/jaz303/read_only_model

The above list was used by myself over the last month. It is confusing but makes sense to me. I decided to use views because is an easy way to use Rails naming conventions and helped my to refactor a little bit the database, since I have inherited it from another developer and has lots of ugly names and errors that brakes referential integrity. If you decide to prefix your Rails tables, remenber that there is a but in the testing framework and a table like this:

_users

will become:

__users

I was using an underscore as prefix, but when running 'rake test' the tables where created with two times the prefix. there is a fix for that but it is not included in new versions of Rails and it will never be, since the ticket in Trac has been closed. So I do not use and prefix, old tables use the singular notation, Rails one are plural, that is my way to separate Qcodo's tables form Rails' tables.

I decided to use Rails migrations for any database change, since Rails migrations are capable to do what I want so I get the real benefit to take advantage to version my database changed. I you need to do something that Rails migrations are not capable, just use the execute command and put your SQL as argument.

That's all for now but I will post other interesting things that I will discover in the future.