“Rails is 100% magic with 0% design”

January 22nd, 2008
Posted in Ruby | 2 Comments

After delving into Ruby and Rails, I have felt the following but never got around to writing about it. I have since abandoned the adoption of Rails, but I recently stumbled upon a newsgroup post that expresses what I think about the framework (but with examples that I would not have produced without more experience):

Newsgroups: comp.lang.lisp
From: Maciej Katafiasz
Date: Mon, 21 Jan 2008 12:47:45 +0000 (UTC)
Local: Mon, Jan 21 2008 7:47 am
Subject: Re: OT: Rails is shitty
[was top down programming in a bottom up language]
Den Mon, 21 Jan 2008 06:08:27 +0000 skrev Sohail Somani:

> On Mon, 21 Jan 2008 04:10:19 +0000,
> Maciej Katafiasz wrote:
>> Let’s not. Rails is a really shitty way of doing things.

> I don’t really care either way, but Rails has gotten
> Ruby usage. This might be because it is quite Mickey
> Mouse… But why is Rails a really shitty way of doing
> things?

First, I completely agree with what Slava said. Now to expand that a bit with my own thoughts:

Rails is 100% magic with 0% design. It sports all the great quality and consistency you’ve come to expect from PHP, except with loads more magic. There’s no overarching design or scheme of things, it’s just a bucket of tools with some glue poured in. This has a couple of important consequences:

– There’s no reasoning about Rails — more familiarity won’t give you better chances of figuring out something new because that’s what follows from the design, only because that’s how it usually ends up being implemented and because you have memorised more things, so your guesses are better. In essence, being better in Rails means being better at grepping the internet.

– There’s no thought given to the general problem to solve, it’s just improved PHP + “ActiveRecord, lol”. This means Rails doesn’t have solutions that are particularly good or scalable or make sense, only hacks that happened to solve someone’s specific problem at a time and were implementable in 5 minutes or less. Rails is heaps better than PHP, but it’s still only good for what PHP is good, and that’s not writing webapps. This permeates Rails all the way down: it’s got hacky modules that only solve particular problems, those modules have hacky functions that only solve particular problems and those functions only do hacky things that solved someone’s particular problem.

Some examples:
* AR’s find family of functions. It’s a horrible hack, for instance, they support the :group clause, which has semantics (“return a collection of groups of things”) incompatible with find’s base semantics (“return a collection of things”). Rails answer? It implicitly relies on MySQL’s retarded interpretation of SQL and the fact that given a table with two columns, id and colour, it will silently interpret “SELECT * FROM table GROUP BY colour” as “SELECT FIRST(id), colour FROM table GROUP BY colour”. End result? A valid combination of clauses in AR will generate incorrect SQL Postgres will (correctly) choke on.

* AR’s find again, it supports :join (which documentation hilariously describes as “rarely needed”), except that it doesn’t return real objects then, but make-believe fake readonly objects that will only have some attributes filled in (because they have no backing with physical rows), but will *still* have the base type and all the methods of the class you queried on! So if you go with that and try to call one of the methods that depend on unfilled attributes, you die horribly.

– Reading and, in general, understanding Rails is horribly difficult, since it’s no design and layers upon layers of magic. Very often you will find 5-7 layers of functions delegating the work deeper and deeper in, until you arrive to a completely undocumented internal function that in turn splits the work to three other, unrelated internal functions. Given that each of those 10 functions takes a hash called “options”, each layer altering it subtly, but none having the complete picture, and that 9 times out of 10 that hash is not documented on any level, figuring out what your choices are is pure hell. It’s made even more fun by the fact that different parts of Rails are accessible at various points of handling the request, and you can’t just jump in and poke things from the console, since it won’t have 99% of the things that only magically spring to life once a request is live.

– As a rule, there’s no quality assurance, and the average quality is very low. Because it’s such a patchwork, it will only have parts of things implemented, some other (not necessarily overlapping) parts documented, and a whole load of missing things just dangling and waiting for you to run into them. For example, the docs for text_field_with_auto_complete discuss how you can use options to make it complete only parts of entries (which was exactly what I needed, to show “foo (123)” in the popup, but only insert “foo” in the text field). What it doesn’t tell you, however, is that none of the stock completion-generating methods will prepare such splittable data for you, and you’re supposed to copy their code and hack it on your own instead. It took me half a day to finally understand that it wasn’t me being stupid and unable to find it, but it was actually Rails documenting interfaces that _weren’t there_.

– And to stress the first point again, Rails never concerns itself with the big-picture problem of “writing webapps”. It only thinks as big as “outputting HTML strings” and “querying the DB for a list of things”. This means the important, actually hard stuff like handling the stateless nature of HTTP, or sanitising and escaping the user input is just not adressed at all, and you only learn about them when one day you discover 84 possible XSS injection points (actual number from a Rails app I’m somewhat famililar with).

I’m a huge fan of innovative frameworks like Weblocks, because they actually stopped and thought about the whole thing for a moment, and try things that will address the problem as a whole. And even if some specific things will turn out to be harder to do that by just churning out raw HTML, and there will be abstraction leaks, it’s still better because they try out new things to find a solution that has a chance work. Rails doesn’t, because its entire culture seems to be fundamentally incapable of thinking more than 5 minutes into the future.

Cheers,
Maciej

Creating a VNC Connection to Existing X Session

January 3rd, 2008

Either it has been a really slow news week, or I’ve gotten faster at processing news from multiple news aggregators. I’ve been getting to the office early in the morning, and the content of /. and other popular news sites just did not give me my fill of reading for the morning. I began wondering what was going on at Efnet #C++. I had an IRC connection within a continually open X session at home, and I didn’t want to fire up another IRC client, so trying to get VNC to work with an X session was something that was worth attempting.

I did the following for a machine running CentOS 4.4 LiveCD to get it going:

1. Download the x11vnc RPM. I downloaded
   x11vnc-0.9.3-1.el4.rf.i386.rpm.
2. # rpm -ivh x11vnc-0.9.3-1.el4.rf.i386.rpm
3. $ x11vnc -storepasswd
4. $ x11vnc -usepw
Reference: x11vnc HOWTO

Searching for a 2008 Wall Calendar

December 19th, 2007

The year is almost over, and I’ve been searching through the usual office supply stores for a type of calendar. I saw a vertical year planner, similar to this during my last trip to Germany. I thought that something like this could be found easily at my local store, but neither officedepot.com nor staples.com seem to carry it. It looks like a good tool for planning to me.

Developing Amidst Change

December 12th, 2007

Lately, I have been working as a lead developer on a software module for a reasonably sized project. What seemed to be a task that appeared to require no more than three weeks has turned into something that has spanned four months and may include an additional two months for the provision of integration support. There is a notable difference between a software project that can be completed by an individual and one that requires multiple teams that are spread across the world.

Getting a feel for the project was a major factor in increasing the likelihood of delivering my modules on time. I was able to observe the development of other software modules for the current project, before I was assigned to work on my own. The tool set was noticeably unstable. Not only were the tools not functioning as expected, the tools that were available changed as updates to the tools were required and additional tools were introduced. The overall system design was unstable and the module interfaces were not set. Responsibilities were being shifted between modules. The project’s susceptibility to change is something that must be acknowledged from these observations, and development practices must be adopted to accommodate such changes.

Noting the high level of malleability in the developing software system, my software module was designed with insulation from external module changes in mind. Specific function signatures for my module were provided to me when I began my low-level module design. My module depended on the services that were provided by other modules, some of which have not been well-established. The gist of my module’s responsibilities was adequately conveyed, and the introduction of responsibilities into my module was rightfully resisted through a Socratic series of questions. The new responsibilities would have kludged the elegance of the design by introducing a distinct behavior to the module for a very special case. With much success in preventing drastic changes within my module, the development effort was placed on dealing with changes to the overall system design.

Distinct program entities were introduced at the entry points and exit points of my module. The module interface functions dispatched requests to the inner module functions. This allows the interface to the module to be easily changed without necessitating a risky modification to the module’s core. Also, proxies for the services of external modules were introduced for the module core functions to use. Instead of having several parts of my module make direct calls to external modules, my module’s core channels its requests through the proxy function, which forwards it to the appropriate external module. Although it may have been subconscious while I was designing my piece of software, it is clear now that this is an example of reducing module coupling. My attempt to isolate my module from changes in other parts of the system apparently resulted in a design that approximates good designs that are prescribed in academic texts on software engineering.

Compartmentalization was also employed within the module. Functions were introduced, for example, to isolate the code in the module’s core from the representation of data transferred between my module and other modules. In one situation, a change in the format for the data transferred between my module and another module required changes in only a handful of my module functions. Changes in a part of my module do not significantly affect any other parts, and as changes to my module became required, the changes were implemented in a way that minimized the impact to the rest of the module.

Know Your Nomenclature

November 25th, 2007

It’s very hard to discuss software engineering topics with respect to a given language when there’s some confusion between “function overloading” and “function overriding.”