Rails plugin authors on OS X, beware!

  • Posted By Stuart Halloway on January 31, 2008

This morning I was troubleshooting a production problem with the simple_localization plugin. The code worked fine in development, had 100% passing C0 coverage in test, and worked fine in production on my local box. But on the staging box, we were getting the dreaded load error:

LoadError: Expected /simple_localization/lib/cached_lang_section_proxy.rb to define CachedLangSectionProxy

If you use Rails plugins and ever see this problem, read on...

A little background

In Ruby, you can load a Ruby source file from the load path by requiring it.

require 'my_class'

This is explicit, and easy to understand. But you might get tired of spelling things out all the time. So in Rails you can also load a class implicitly when it is needed:

MyClass

This is somewhat Java-like, in that magic happens to find the code based on some naming conventions, e.g. My::Namespaced::MyClass should be in a file namedmy/namespaced/my_class.rb somewhere on the load path. It is also Java-like in being difficult to debug, leading to errors like the LoadError above.

Workaround: ducking the issue

Knowing that the LoadError is a failed implicit load, the first step is to look at the point of failure in the file cached_lang_section_proxy. Here is is, elided for clarity:

module ArkanisDevelopment
  module SimpleLocalization
    class CachedLangSectionProxy

Ah hah, you say. The error is right on. This file doesn't define CachedLangSectionProxy, it defines CachedLangSectionProxy in the ArkanisDevelopment::SimpleLocalization module. So implicit loading can't work with the code as written. But we have a workaround: we can move this file (and probably several others) into a directory structure that matches Rails conventions. I am not going to do that, because...

Solution: getting deterministic

We can get implicit loading to work, but we still haven't tackled the real problem. Why did the code ever work on my local box to begin with? We know that implicit loading can't work, so somehow my local box must be explicitly loading the files, but in a machine-dependent way that fails on the staging box.

Rails plugins include an init.rb that runs during Rails startup, and is often used to explicitly load configuration and code. Here is that code from simple_localization:

Dir[File.dirname(__FILE__) + '/lib/*.rb'].each do |lib_file|
  require File.expand_path(lib_file)
end

This is broken, but if you develop on Mac OS X you may never notice. The plugin's internal dependencies are arranged in such a way that loading the files in alphabetical order works. In all of my experiments, Ruby's directory traversal APIs on the Mac return files in alphabetical order. However, this ordering is not required by the Ruby language. On Linux, the files can come back in any order.

Given that many Rails developers work on OS X, and deploy to Linux, this leads to an amusing variant of "It works on my box": It works on all developer boxes, and fails on all production boxes..

An easy fix is to sort the files explicitly:

Dir[File.dirname(__FILE__) + '/lib/*.rb'].sort.each do |lib_file|
  require File.expand_path(lib_file)
end

Better would be to organize init.rb so that the dependencies are clear (the fact that alphabetical order happens to work is a fragile coincidence).

Lessons learned

  1. If you write Rails plugins on Mac OS X, be careful how you use globbing APIs in init.rb. They will work deterministically on your box, but maybe not everywhere else.
  2. If you plan for your Ruby code to be used from Rails, follow the directory and naming conventions.
  3. Loading code is and always will be tricky. Many years ago, I thought that COM had solved many of the problems. I was so enthusiastic about Java's approach that I wrote a book about it. By the time .NET came out with yet another approach, I was a bit jaded and assumed it would have problems. (It did.) It's a hard problem.

On language aesthetics

Java and Ruby both have an explicit and implicit loading story. What is interesting is that in Java this story is implemented in the language, while in Ruby a significant part of the story is in the libraries. It is Rails, not Ruby, that implements implicit loading, and you can read much of that story in this source file (updated link: with syntax highlighting). Understand this file, and you will know much of what is best and worst in Ruby.

Arc is out

  • Posted By Stuart Halloway on January 29, 2008
arc> (prn "Arc is out!")

Paul and Robert have released Arc.

Blub paradox trolling contest

  • Posted By Stuart Halloway on January 29, 2008

Is there some kind of Blub paradox trolling contest going on this week? If so, I would like to nominate Lawrence Kesteloot. Lawrence's post stood out above a crowded field for several reasons:

  • Thinking that languages make code "production" or "toy". The noun he was looking for is developers.
  • Believing that expressiveness hurts readability.
  • Providing an example against something (Lisp) without an example for anything. This is an example of the Creationist Fallacy: Raise an objection to something (e.g. evolution) without providing any positive evidence for anything else, then declare victory.
  • Criticizing Paul Graham while documenting his own Blub level for all to see. Priceless.

No, Be a Jerk

  • Posted By Justin Gehtland on January 29, 2008

Ricky says “don’t be a refactoring bigot”. And I have to say, his very first point makes no sense to me. He says “don’t criticize code”, especially if it is already in your project. I say, be a jerk. A big fat jerk. A “your code is a ghetto” style jerk. And this is ESPECIALLY true for code that is already in your project.

Refactoring is itself a kind of criticism: criticism through action. When you say “this code could be more elegant”, you are implicitly saying that it is not as elegant as it could be. If you follow this advice to its logical conclusion, you would never refactor the parts of your codebase that need it the most, the parts written by team members under duress, without proper pairing and review, which load up your technical debt.

As I said a couple of weeks ago, if you have something to say, don’t be afraid to say it. Growth comes from understanding; you can’t help people understand a problem if you ignore it. As a person who has been told several times in the last week that my code could use some, shall we say, “up-elegantizing”, I can say without fear of contradiction that that criticism is the only thing that would have convinced me to try and up my game.

So, yeah, don’t just refactor every piece of bad code you see just for the sake of doing it. But by all means, when you ARE going to do it, be a jerk about it. Shorten the feedback loop. Don’t dance around the issue. Your pair will appreciate the honesty, and your project will be better off as a result.

EDRY, meet CoC

  • Posted By Stuart Halloway on January 29, 2008

Jay Fields has envisioned a beautiful future for software development with his EDRY dialect of Ruby. But what is Enhanced DRY without better CoC (Convention over Configuration)?

I have modified Jay's code to rely more on convention. Why have a distinct vocabulary for fields vs. mixins, when the right thing to do can be inferred from the types involved? The result is some really tight code:

C Enumerable, :first_name, :last_name, :favorite_color do
  d.complete_info? { nd(first_name,last_name) }
  d.white?.red?.blue?.black? { |color| favorite_color.to_s == color.to_s.chop }
end

I am including the full source at the bottom of this entry. Can you make it even DRYer and more convention-driven?

class Object
  def C(*args, &block)
    attrs = args.find_all {|arg| Symbol === arg}
    includes = args.find_all {|inc| inc.instance_of?(Module)}
    name = File.basename(eval("__FILE__", block.binding),".rb")
    klass = Struct.new(name.capitalize, *attrs)
    Kernel.const_set(name.capitalize, klass)
    klass.class_eval(&block)
    klass.send :include, *includes
  end

  def s
    self
  end
end

class Class
  def ctor(&block)
    define_method :initialize, &block
  end

  def i(mod)
    include mod
  end

  def d
    DefineHelper.new(self)
  end

  def a(*args)
    attr_accessor(*args)
  end
end

class DefineHelper
  def initialize(klass)
    @klass = klass 
  end

  def method_stack
    @method_stack ||= []
  end

  def method_missing(sym, *args, &block)
    method_stack << sym
    if block_given?
      method_stack.each do |meth|
        @klass.class_eval do
          define_method meth do
            instance_exec meth, &block
          end
        end
      end
    end
    self
  end
end

# http://eigenclass.org/hiki.rb?instance_exec
module Kernel
  def instance_exec(*args, &block)
    mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
    Object.class_eval{ define_method(mname, &block) }
    begin
      ret = send(mname, *args)
    ensure
      Object.class_eval{ undef_method(mname) } rescue nil
    end
    ret
  end
end

def nd(*args)
  args.each {|x| return false unless x}
  true
end

# convention: symbols are attributes, modules are to be included
C Enumerable, :first_name, :last_name, :favorite_color do
  d.complete_info? { nd(first_name,last_name) }
  d.white?.red?.blue?.black? { |color| favorite_color.to_s == color.to_s.chop }
end

Safe by default

  • Posted By Stuart Halloway on January 29, 2008

I met Luke Francl at Code Freeze last week, but we only had time to speak for a minute. It was enough to know we are of like mind: security should be on by default. Luke has written a new plugin, xss_terminate. It is inspired by acts_as_sanitized, but it has stricter defaults and more options. Nice.

Rails, The Cookie Store, and Security

  • Posted By Justin Gehtland on January 27, 2008

Tobi, Bob and David are all exactly dead spot on right. The Rails cookie store works as designed, data stored there should be tamper-proof and signed, and you are indeed the poorest kind of web programmer if you are assigning strong, valuable data into a cookie. Right, right, and right again.

However, the rub here is that:

  1. Rails is an awfully popular web framework,
  2. used by all kinds of developers, from neck-bearded Unix geeks down to baby-bottom-smooth-chinned highschool geeks,
  3. for all kinds of applications.

Given that the cookie store is the default session store, and that people either accidentally or on purpose store all kinds of goop in the session (often transiently, sometimes for the length of the session), then it behooves people to have a way to default to a more secure version. That’s all the EncryptedCookieStore is for: guaranteeing that if you screw up your app, you don’t also screw up your users.

So, in order to be clear: Relevance in no way suggests that you should store anything of any value in a cookie. In fact, we’ll shake our heads in disgust and drag you out behind the woodshed if we catch you doing it, you’re darn tootin’. But if you want to make sure that you don’t accidentally reveal something through this mechanism, defaulting it away might be useful.

And I did not mean to imply that the Rails team was either negligent, ignorant, or foolish for implementing the cookie store the way they did. I understand the reasoning well; our plugin is a safeguard against accidental misuse, not willful stupidity (we hope ;-) ).

Latest Relevance Open Source: encrypted cookie store

  • Posted By Justin Gehtland on January 27, 2008

Aaron just released our latest open source project, EncryptedCookieStore. It turns out that the default cookie session store for Rails is insecure in the worst way: it is simply Base64-encoded (which is French for “plain text”). It is slightly obfuscated, giving the uninitiated a false sense of security, but to anybody who was seen Base64 before, they can probably see the woman in the red dress without even squinting. So, enter the EncryptedCookieStore, a plugin that will truly encrypt the data you are shoving in the cookie. Check it out!

EDIT: Per accurate comments, I need to restate something. The default cookie store is not “insecure in the worst way”; it is, rather, “insecure for the worst developers”. It was not MEANT to be secure (from reads). My point was that, some developers might just assume that the default for sessions would be server side storage, and the element of surprise might lead some of them to Do Bad Things™. That is all; sorry for the confusion.

This week's yak shave: fuzzing dates

  • Posted By Stuart Halloway on January 26, 2008

We have been fuzzing our Rails applications to see what breaks, and finding some interesting things. This week, the continuous integration build started to break at random, but only on one application. Pull out the Yak clippers!

By looking at the test logs, we quickly isolated the problem. Rails date helpers let users input bad dates, e.g. February 30, 2008. (In almost all scenarios, we avoid the built-in date helpers anyway. But almost only works for horseshoes and hand grenades, and I don't want special cases that break.)

Obviously our fuzz generator will generate bad dates occasionally. Before you read further, test yourself: How does ActiveRecord handle such dates? How should it? The answer is in ActiveRecord::Base's execute_callstack_for_multiparameter_attributes, and it surprised me:

  • If you are using the Time class, the day overflows into the next month, so 2/29 magically becomes 3/1. Yuck.
  • If you are using Date, Ruby raises an error. Rails then wraps this error, and by the time it gets back to you the offending values are not easily accessible.

Neither of these approaches appeal to me. A bad date should be validation error. Matthew pointed me to a plugin that lets you, on a per model basis, monkey patch ActiveRecord to report bad Dates as validation errors.

I decided that I wanted to have a patch that overrode Rails' behavior for all models, so I have written the first_class_dates plugin. This gets our tests passing again, and it keeps bad data from raising application exceptions, but it is still a hack. A better solution would:

  • work consistently for Time and Date.
  • show the user the bad values they chose. (This is tricky since Date refuses even to enter a bad value state.)

The better solution would require a more substantial patch, and should be done in Rails itself. If others agree with the approach, we will submit the patch.

Groovy team cloning Ruby legends

  • Posted By Stuart Halloway on January 25, 2008

Groovy's inexorable rise to world domination continues. You think Ruby is better because Ruby has a David Black? Wrong! Groovy has a David Black too.

I hope they made a deep copy.

We're disgusting!

  • Posted By Justin Gehtland on January 24, 2008

The RailsEnvy guys mentioned our newest releases on their podcast this week and Jason said our SimpleServices plugin was “disgusting, and has no place in a Rails app”. That might be the best review anything we’ve ever touched has ever gotten.

We’d like to thank the Academy, and all the little people who made it possible. Sniff. Thank you everybody!

Seriously, thanks for the shout out, guys! Keep up the great work!

If all you have is a hammer

  • Posted By Stuart Halloway on January 23, 2008

If all you have is a hammer, then all problems start to look like ... thumbs.

Here's a good example. MapReduce and RDBs are about as orthogonal as it gets.

Announcing: SimpleServices

  • Posted By Justin Gehtland on January 18, 2008

During the recent Rails/Grails kerfluffle, one of the memes that came up over and over again was that Grails had a specific feature which Rails lacked and that it was a Big Deal™. Specifically, Grails defines a service layer with automatic transaction demarcation which allows you to remove complex domain manipulation code from your controllers, leaving them to deal with loading resources and redirecting to views.

As a thought experiment, we set out to find out what would need to happen to enable this in a Rails app. By the end, we’d written the plugin we are releasing today: SimpleServices. It amounts to about 12 lines of code, but that isn’t really a boast, as we’ll see in a minute.

Before we look at SimpleServices, we should discuss what makes up the service layer in Grails:

  • Services are classes which are, by default, singletons and are assumed to be stateless.
  • Their methods are wrapped in a transaction by default, though you can turn this behavior off (not sure why you would want to, but whatever)
  • Services are injected into controllers via standard Spring dependency injection methods
  • Services are singletons by default, but can be declaratively scoped to one of many other scopes: request, session, flash, etc. This would enable stateful services.
  • “Transactions”, in this case, are full-fledged container-managed transactions, which can involve database transactions, messaging system transactions, and any other resources that expose a transactional API and can be enlisted in a container-managed transaction.

When we wrote this plugin, we were attempting to get out the most robust implementation of the default use case, which is:

  • singleton, stateless services
  • ActiveRecord transactions
  • encapsulation of service creation details (obscuring their instantiation API)
  • encapsulation of complex domain logic, outside of your controllers

When you install the plugin, you can create a folder in RAILS_ROOT/app called “services”. Within this folder, you can define one or more service classes. A service class has a name that ends with “Service” and derives from Service::Base. The plugin causes these to be auto-loaded in the traditional Rails fashion. Each method in the service is automatically wrapped in a transaction, and any errors raised within the method will cause the transaction to rollback.

Within your controllers, you can declare which services you will be using in your actions. For each service you declare your need for, a method will be added to the controller in the form of ”#{service_name}_service” which hides all the service instantiation code.

class AccountController < ApplicationController

  services :account, :user, :security

  def update
    base_account = Account.find(params[:base_id])
    target_account = Account.find(params[:target_id])
    account_service.transfer(base_account, target_account, params[:amount])
  end
end

You aren’t forced to use services from controllers, either. If you want the declarative support, but in your models, you just include SimpleServices::ServiceInjection in whatever class you want. For example, you could include it in ActiveRecord::Base and have it available for all your models. Likewise, you can create instances of services directly, without declarative support, by calling AccountService.instance.

Known Issues

  • The plugin has a dependency on the Aquarium gem. In order to provide the wrapping, we needed a good aspect library. (Aspectr has fallen on hard times, and Aquarium seems to have a lot of activity and a very simple API.) Just install the gem before using SimpleServices.
  • We don’t provide support for scoping the services yet. It seems that most people use the stateless singleton model, and this was a straightforward case to implement. We’ll start looking into scoping the services next, and we’d love to hear from anybody who can make a good case for, say, a stateful, session-scoped service. I honestly can’t think of a good one.
  • We are limited in this 0.1 release to single-database ActiveRecord transactions. We are looking ahead to enlisting the transaction manager when you are running in JRuby, but that will be in a future release.

We’d love to hear if people in the Rails community find this useful. We are playing around with it in a couple of apps, and it does have the benefit of cleaning up the controller codebase and providing zero-thought transaction support. Yay, services! But, we’d love to hear from others on this, and on how it could be improved.

Good luck, and happy servicing.

I like turtles

  • Posted By Justin Gehtland on January 18, 2008

I read this post by Ramon Leon on why Smalltalk is a better environment for building DSLs than is Ruby (found via keith).

I generally agree with Ramon’s points, in that the C-based MRI prevents us from reaching into the guts of the platform and making modifications without having to drop down a layer and do it all in C. And, of course, that’s the point: if I want to make major modifications to the language I’m working in, I want to do it from that language. I don’t want to drop to C—it is the moral equivalent of reaching for a glass of milk, taking a sip, and finding out it is orange juice. The orange juice isn’t inherently evil, but in this context, it might as well be motor oil.

The problem I have with his post, and with most posts about X-vs.-Y language comparisons is that in conflates two ideas and reaches the wrong conclusion. Ramon is right: the MRI prevents Ruby programmers from being able to modify their own language to the extent that SmallTalkers can. However, there is nothing particular about Ruby the LANGUAGE that does.

For example, the Rubinius project will provide us a stack of turtles on which to perform linguistic gymnastics to our heart’s content. If you read the collected writings of the Rubinius team, you’ll see that they are in fact heavily influenced by the Smalltalk-80 architecture.

And I don’t think Ramon is ignorant of this fact, or that he is maliciously overlooking it, just that his prose doesn’t make the distinction explicit which might leave readers with less understanding of the Ruby ecosystem with the wrong idea. The same way that Ruby people often complain about Java and paint the language and the JVM with the same broad brush.

spec_converter released

  • Posted By Justin Gehtland on January 18, 2008

Muness just released spec_converter as part of the Relevance open source library. It converts Test::Unit tests to test/spec style. Check it out!

Never untaint

  • Posted By Stuart Halloway on January 17, 2008

For the last few weeks, Aaron and I have been worrying about the state of XSS security. As we have said before, input sanitization is not enough, you need something like SafeERB for all external data.

But after looking at XSS Shield, and thinking a bit more, I have concerns about SafeERB's approach to safety. Here's the problem:

  • External data is marked as tainted. Great care should be taken in using tainted data in any potentially executable context.
  • SafeERB sanitizes strings against XSS, and then untaints the strings so that you know they are safe in an HTML context.

Notice the subtle asymmetry. External data is dangerous in any executable context. SafeERB untaints data after making it safe for only one specific context--HTML. What if your freshly untainted string contains SQL? Shell script code? Or some DSL you never heard of?

You could argue that the data is being marked untainted in the view layer of an HTML MVC framework, so we don't have to worry about non-HTML dangers. I don't buy this at all. How can you be sure that none of your Rails code will ever be repurposed in another context? Sounds like a recipe for legacy to me.

XSS Shield takes a more cautious approach. Instead of calling untaint, XSS shield uses Ruby's open classes to define new methods such as mark_as_xss_protected. So you can leave a string tainted, but mark it as XSS safe.

Let me be clear: SafeERB is way better than doing nothing. But I am moving toward the conclusion that you should never untaint data. What do you think?

Slides Posted: Ending Legacy Code

  • Posted By Stuart Halloway on January 17, 2008

I have posted the slides for "Ending Legacy Code in Our Lifetime," which I will be presenting tomorrow at Code Freeze 2008. The slides include lots of pointers to interesting reading.

[Updated to fix the link. I replaced the file in Mephisto, and it replaced and renamed the file. Why does it do that? And why aren't the links from Keynote clickable when I generate the PDF?]

I call BS

  • Posted By Justin Gehtland on January 15, 2008

I’ll let Stu and Graeme continue to hash out the Rails/Grails who’s-framework-is-biggerh^hhhhbetter argument. I want to call bulls$%t on two things Graeme has said in the two posts so far:

The first, and I quote:

Rails has zero enterprise penetration, let’s put that out there right now.

I don’t even know how to call the right people to find the right people to help me identify candidates for dealers who could hook me up with stuff to make me high enough to take that seriously. I mean, you have to be completely blind to objective reality to even type in the words, let alone make the argument with a straight face.

The second, and I quote again:

Since [Relevance is] a Rails company…

Please stick to defining your own corporate niche, bucko. ;-) We’ve got a definition that’s working pretty well for us so far.

Wherefore the stable layer?

  • Posted By Stuart Halloway on January 14, 2008

Graeme has responded to my previous post. Let's start with where (I think) Graeme and I agree: The enduring difference between Rails and Grails is that Rails is built on Ruby, and that Grails is built on Groovy and Spring. Most of the other differences will be competed away, to the benefit of both frameworks.

So it comes down to this: In which layer should services and frameworks be built?

  • If you think that most services and frameworks should be implemented in the dynamic layer (and above), then you agree with me, and probably prefer Rails' architecture over Grails'.
  • If you think that most services and frameworks should be implemented in the stable layer, then you agree with Graeme, and probably prefer Grails' architecture over Rails'.

This only matters if you are primarily driven by architecture, i.e. you are Jane. Joe's worries are entirely different. I expect Grails to have significant growth and success helping Joe.

How to read reviews

  • Posted By Stuart Halloway on January 14, 2008

In my roles as author, columnist, instructor, track chair, I have gotten a lot of practice interpreting reviews. Here's a few rules of thumb:

  • If you are reading numeric scores, pay close attention to extreme deviation. I would rather see a talk that got 20 fives and 10 ones than one that got 30 fours. Ted Neward is a champion in this regard, consistently inspiring reviewers to write in new numbers on both ends of the scale.
  • If you are reading prose reviews, learn how to spot tells. If reviewer X says several illogical or ignorant things, then it is a reasonable optimization to stop crediting them on other subjects. This will not be 100% accurate, and may be unfair to individuals, but remember your time is limited.

I was reminded of all this by Giles's observation that

SICP has 82 5-star reviews on Amazon, 53 1-star reviews, and virtually nothing in between.

Of course I had to go read a few of the one-stars. The very first one begins:

I don't understand what others see in this book. I realize that it is *supposed* to be about foundations of good programming style, and not about any language in particular, but being language specific is exactly what it does. Many things it teaches can only be done in Scheme.

Apply the rules of thumb above...

Relevance welcomes Aaron Bedra

  • Posted By Stuart Halloway on January 14, 2008

We are happy to announce that Aaron Bedra has joined the Relevance Team. Aaron brings the ability to quickly ninja any application. His passion for spreading the security word via his blog is kicking off a new wave of security consciousness throughout the Ruby community and creating an avalanche of better development practices. His passion for exploring new technologies and traveling new roads has quickly shot him up through the Ruby industry and on to the Relevance team.

And, his blog is no longer on the back of a truck, so stop by and visit!

More XSS protection choices

  • Posted By Stuart Halloway on January 14, 2008

Should XSS protection use Ruby's built-in tainting to mark strings safe or unsafe, or should we have specialized XSS-safety metadata?

The lack of a clear winner becomes a real problem for plugins that include view helpers (like Streamlined). We'd like to conform to an XSS-protection scheme, but which one? Suggestions welcome.

How to pick a platform

  • Posted By Stuart Halloway on January 11, 2008

At the end of this post I will tell you whether to use Rails or Grails for web development. But first, let me tell a tale of two decision makers:

  1. Joe has a problem to solve. The problem is specific, the need is immediate, and the scope is well-contrained.
  2. Jane has a problem to solve. The problem is poorly understood, the need is ongoing, and the scope is ambiguous.

How should Joe and Jane think differently about software platforms?

  1. Joe's platform needs to be mainstream. It needs to offer immediate productivity, and the toolset should closely match the problem. Also, Joe doesn't want to climb a learning curve.
  2. Jane's needs are quite the opposite. Jane needs flexibility. She needs glue that doesn't set. She needs a way to control technical debt (Joe doesn't care.)

For my part, I am interested in Jane's problems. (And anyway, Joe often discovers he is actually Jane midway through projects.)

So how does this affect platform choice? If you are Joe, you care about specific details about what a toolset can do right now. Most of Graeme's Top 10 reasons are in the "Right here, right now" category. This is true regardless of whether you think he is right. (Sometimes he is, sometimes not.)

My advice to Joe: Know exactly what you need, and then pick the platform that comes closest to solving it out of the box. Depending on Joe's needs, either Rails or Grails might be appropriate (or neither!). A particular point in Grails' favor would be an established team of Spring ninjas.

If you are Jane, you care more about architecture. I mean this term in two senses:

  1. Architecture: the decisions you cannot unmake easily.
  2. Architecture: the constraints on how you think and work.

If you are Jane, you care about how and why the platform was assembled, because you are likely to have to adapt it quite a bit.

Most of the commenters on my earlier post (and Graeme in his addendum) correctly identified the real architectural difference between Grails and Rails. Rails builds on Ruby, while Grails builds on Groovy and Spring. Rails wins this architecture bakeoff twice:

  • Ruby is a better language than Groovy.
  • Spring does most of its heavy lifting in the stable layer, which is not the right place.

My advice to Jane: Rails over Grails.

Helping Graeme Make His Case

  • Posted By Stuart Halloway on January 10, 2008

Graeme has published his 10 reasons to switch from Rails to Grails. I think his case is overstated, but that doesn't mean there aren't some good reasons. To clarify, I have broken his list into three groups: reasons to switch, edge cases, and crap.

1. Reasons to switch from Rails to Grails

These are real issues in Rails applications we have built.

2. Edge Cases

These aren't issues for me, but they are important to some people.

  • Mixed source development made easy with the Groovy joint compiler. JRuby is enough for me, but YMMV.
  • IntelliJ's JetGroovy Plug-in. I am happy with TextMate for now, but if you are an IDE type check out NetBeans (start with Tor's blog).
  • A rich plug-in system that integrates Grails with technologies Java people care about like GWT, DWR, JMS etc. If you think it is hard to build a plugin system you are probably still having flashbacks to your bondage and discipline language.

3. Crap

Puh-leeze:

  • Grails 1.0 coming out within the month. Sorry, but "we've never shipped and when we do we'll only be three major releases behind" doesn't motivate me much.
  • Built on Spring, the ultimate Enterprise Application Integration technology. In other words, "We have one foot in the past, and leaky abstractions around every corner."
  • A buzzing and growing community with a larger traffic mailing list as opposed to a stagnating one. Graeme, I double dare you to say this with a straight face.
  • More books coming and being adopted by enterprise. I am a reviewer on some of these books, and they are good. But again, this is "Look--We're second-best and trying hard!" argument.

As a final note: One of the items above rightly deserves to be controversial, and represents the real, enduring difference between Rails and Grails. I think your opinion on that one item should drive most Rails/Grails adoption decisions. Can you spot it?

Java: the Duplo of Programming Languages?

  • Posted By Stuart Halloway on January 10, 2008

Nathan seems to think that Java is the Duplo of Programming Languages. He is beyond Java, of course:

After learning Ruby, various functional languages, and even C, I’d rather program in any of those than Java.

...But he thinks Java makes a great first language:

The thing that makes Java such a good first language is that the particular abstractions it provides are the ones that underlie the higher-level abstractions that are provided by higher-level languages... The most basic abstractions Java uses – variables and static methods - are a good basis because they correspond roughly to intuitions developed from algebra and other areas of human experience.

Apparently people who learn Java first think that static methods are a more basic abstraction than, well, functions.

Java as a first language is a bad idea. It misses what makes Java great, and why Java will still be great in five years.

The next big language

  • Posted By Stuart Halloway on January 09, 2008
Ola Bini thinks he knows what the next big language will be. His reasoning is spot on, and it is a welcome sign that our industry is maturing.

CodeFreeze 2008

  • Posted By Stuart Halloway on January 09, 2008
I will be giving one of the keynotes at the aptly-named CodeFreeze 2008 on January 17. The topic: Ending legacy code in our lifetime.

Is your Rails app XSS safe?

  • Posted By Stuart Halloway on January 09, 2008

Act 1. Making Rails Safe From XSS.

All web frameworks need to protect against XSS. Since Aaron got SafeErb to work on Rails 2.0, it seemed liked a good time for a quick spike to get SafeErb integrated with a live project. Aaron and I picked a small project and started to work.

Act 2. Need a little yak hair...

Our little application had a few RESTful controllers and models, nothing complicated. The functional tests already hit every line of Erb in the views, so we should be able to just install the plugin, run the tests, and see what happens...

Boom. A few dozen errors. They fall into several categories:

  • Rails' FormBuilder methods return tainted strings, so you would have to say f.text_field(:foo).untaint instead of f.text_field :foo.
  • error_messages_for returns tainted strings. This one is a little tricky. Most validations don't regurgitate user input, but nothing stops a custom validation from doing so. I'll untaint this too, and if a validation exposes tainted data that is the validation's problem.
  • number_with_delimiter returns tainted strings. Rails should call untaint for me. But if you look at the code, number_with_delimiter doesn't do any escaping at all. Evil script in, evil script out.
  • controller.action_name (used in scaffolds) is tainted. Since that code won't survive til production anyway, we will just untaint it.
  • url_for and friends return a tainted string, but only sometimes. Sigh. The app is pretty small now, so we will just manually untaint the ones that blow up.

Act 3. Shaving the yak.

Well, Act 2 didn't go so well. That was a pretty small app, and the changes we had to make were numerous, ugly, and not DRY at all. Most developers probably wouldn't bother. But without this kind of systematic protection, we'd always be wondering how many XSS holes we have.

But wait, this is Ruby! I can metaprogram my way out of anything. We'll just duck punch Rails so that its methods call untaint at appropriate times. Something like this:

def text_field_with_untainting(*args,  blk)
  # TODO: some kind of escaping of args!
  text_field_without_untainting(*args,  blk).untaint
end
alias_method_chain method, :untainting

Act 4. Set the clipper guard to zero and smoke the hairs!

The problem with the squeaky clean sanchez above is that there are so many methods to do. Ok, loops are easy:

  [
    :date_select, 
    :datetime_select, 
    :password_field,
    :text_field       # add others as needed
  ].each do |method|
    module_eval(<<-END)
def #{method}_with_untainting(*args, &blk)
  #{method}_without_untainting(*args, &blk).untaint
end
END
    alias_method_chain method, :untainting
  end

Ok, maybe not so easy. Problems:

  1. I would prefer to use def, but I used module_eval so I could interpolate strings inside the method definition.
  2. Why do I need to interpolate strings? Well, alias_method_chain needs to delegate back by name.
  3. Of course, I don't want to use alias_method_chain anyway. I would rather use a block-based approach to wrap methods. But I can't because Ruby won't let you pass blocks to blocks.

And of course this approach still doesn't make the application XSS safe. It merely insists that the Rails helpers are XSS safe even though in many cases they aren't. (I am ok with this as a temporary expedient. I want to get my tests passing--fixing the Rails helpers is a project for another day.)

Act 5. Safety taint easy!

I simplified the first four acts to keep this posting short. It turns out that some of my Rails plugins were duck punching the same helper methods, in such a way that my punches never landed. So I had to double-duck punch them! This introduced some plugin load-order dependencies, giving me a chance to take advantage of Rails 2.0's configurable plugin load order.

Thoughts for the day:

  • I bet very few people are doing XSS security right in Rails. It is tricky, verbose, or both.
  • Ruby's open nature makes it easy for duck punches to get in each other's way. I still prefer this to the alternative, but things can get quite tricky.
  • There are a bunch of Rails helpers (and plugins) that need to change to work effectively with SafeErb. Aaron and I plan to pursue making these patches, if there is interest.

function foo(x) { foo(x); }

  • Posted By Justin Gehtland on January 08, 2008

I too will not write about what other people are writing about anymore.

Mainstream programming in 2007

  • Posted By Stuart Halloway on January 08, 2008

Has Ruby on Rails become mainstream? Cedric says "no", TIOBE and Tim both seem to suggest yes.

For my part, I don't care. As a polyglot programmer, I find the language wars to be too coarse-grained. I am more interested in which ideas became mainstream. As a speaker at numerous Java and Ruby events, I get a chance to see what thousands of other developers are thinking about. 2007 was a great year--a lot of ideas that have bubbled slowly for a while finally came to a boil:

Ideas that went mainstream in 2007

BTW, Relevance is hiring senior developers. We're more interested in your ideas than in your language of choice.

I win!

  • Posted By Justin Gehtland on January 08, 2008

That’s what I shouted today when, using Mingle in Firefox 3 beta 2, I was unable to open a card. Or, in fact, do anything other than view a list of cards. And curse. And click harder.

Noticing, then, that Firebug was helpfully indicating an error, I opened Firebug to discover this message.

Then, I shouted “I win!” for I knew that nobody else would top my crazy-ass error message this day, no sir.

There is no such thing as security through obscurity, but hilarity on the other hand…

A resolution in two parts

  • Posted By Justin Gehtland on January 07, 2008

Via Keith Braithwaite, I came across this quote in a discussion of Patterns. Wait, let me make that more dramatic—of PATTERNS. Here’s the quote:

In certain programming cultures, people consider Design Patterns to be a core set of practices that must be used to build software. It isn’t a case of when you need to solve a problem best addressed by a design pattern, then use the pattern and refer to it by name. It’s a case of always use design patterns. If your solution doesn’t naturally conform to patterns, refactor it to patterns.

This quote bothered me immensely the first time I read through it; at that point, I had no idea who the quote was from (still don’t, actually) nor did I know where Keith was going with his post. I was, however, predisposed against the argument the person was making, and I couldn’t figure out why.

Then, I remembered THIS quote, which I had read the day before:

I think it’s worth imagining a certain scenario. Imagine the Democrats do rally around Obama. Imagine the media invests as heavily in him as I think we all know they will if he’s the nominee—and then imagine he loses. I seriously think certain segments of American political life will become completely unhinged. I can imagine the fear of this social unraveling actually aiding Obama enormously in 2008.

The second quote is from a political pundit named Jonah Goldberg, who is rather clearly and distinctly trying to dance around saying what is really on his mind: that African Americans will riot in the streets unless we elect Barack Obama. Which is ludicrous, absurd, and patronizing at least, and possibly racist at worst.

Hopefully, the parallels between the two quotes is obvious: the speaker is using vague descriptions (“certain programming cultures”, “certain segments of American political life”) to avoid directly saying what they mean (“Java programmers”, “African Americans”) while denigrating them to their face. This allows the author a bit of plausible deniability later (“no, I was talking about programmers I used to hang out with in the food court at the mall, not Java programmers!”) It is also a tactic I have seen quite a bit of in the language wars of the past couple of years, and in political writing generally. And I’ve grown quite unfond of it. If you are going to be unpleasant, then be unpleasant. Don’t dance around what you are trying to say, and don’t use codewords so you can back out of your argument later. I’ve been guilty of this far too often, so ….

My two part resolution:

Article I) I will, henceforth, not use weasel words when I write/speak/declaim about technology. If I have a problem with a person/company/community/cartel, then I will refer to them directly.

Article II) It would not matter in the least that I resolved Article I unless I was going to do some more bloviating this year. I’ve been awfully quiet in 2007 (not many conferences, precious few blog posts, only the one book and Stu wrote most of it), but that’s what happens when you start trying to grow a company and forget to leave time for anything not-growing-a-company. So, the second part is, I’ll be yammering away a lot more on this blog and trying to get out to more conferences in ‘08.