lesscode.org


'Rails' Archives

Ruby, Rails and The Art of Software Development  3

Cat.: Rails
20. October 2005

Those of you working with Ruby/Rails may find this to be of some interest: I have posted the slides from my presentation, delivered to the Vancouver Ruby users group on September 27, 2005. You can view the slides if you go to my web site.

Fun with Fixtures  2

Cat.: Ruby, Rails
25. September 2005

My favorite part of Agile Web Development with Rails is the section on testing. I’ve found the framework around testing included with Rails to be a wonderful blend of simplicity and power and this chapter in the book is the perfect compliment. It’s based largely on the core Ruby Test::Unit module but adds some important features on top.

One of those features is Fixtures. Fixtures provide a simple, YAML-based file format for storing database state that should be loaded before test runs. The database is wiped and the fixtures are loaded before each individual test executes, providing consistent state for tests. See the section on fixtures in A Guide to Testing the Rails for more information. Here’s an example fixture from said section:

# low & behold!  I am a YAML comment!
david:
 id: 1 
 name: David Heinemeier Hansson 
 birthday: 1979-10-15 
 profession: Systems development

steve:
 id: 2
 name: Steve Ross Kellock
 birthday: 1974-09-27
 profession: guy with keyboard

The cool thing is that the top level fixture names (in this case, “david” and “steve”) become instance variables in your test case, allowing you to access fixture data in a very intuitively way from tests. The result of this is test code that reads like a story and is often almost humorous.

The book includes a sidebar with a little David head lamenting the importance of “Picking Good Fixture Names”:

Just like the names of variables in general, you want to keep the names of fixtures as self-explanatory as possible. This increases the readability of the tests when you’re asserting that @valid_order_for_fred is indeed Fred’s valid order. It also makes it a lot easier to remember which fixture you’re supposed to test against without having to look up p1 or order4. The more fixtures you get, the more important it is to pick good fixture names. So, starting early keeps you happy later.

But what to do with fixtures that can’t easily get a self-explanatory name like @valid_order_for_fred? Pick natural names that you have an easier time associating to a role. For example, instead of using order1, use christmas_order. Instead of customer1, use fred. Once you get into the habit of natural names, you’ll soon be weaving a nice little story about how fred is paying for his christmas_order with his invalid_credit_card first, then paying his valid_credit_card, and finally choosing to ship it all off to aunt_mary.

Association-based stories are key to remembering large worlds of fixtures with ease.

Taking this advice, I started in on testing a part of an application I’m working on now. The result is worth posting in it’s entirety (hint: it gets interesting towards the middle):

require File.dirname(__FILE__) + ‘/../test_helper’

class EnrolleeTest < Test::Unit::TestCase
  fixtures :coverage_types, :plans, :coverages, :plan_levels, :ppo_options,
           :elections, :enrollees, :enrollments, :tpas, :tpas_users, :users,
           :roles

  def setup
    @joe = Enrollee.find(@joe_the_policy_holder.id)
    @rita = Enrollee.find(@rita_the_spouse.id)
    @billy = Enrollee.find(@billy_the_dependent.id)
    @alice = Enrollee.find(@alice_the_dependent.id)
    @the_family = [@joe, @rita, @billy, @alice]
    @enrollment = Enrollment.find(@test_enrollment.id)
  end

  
  def test_common_attrs
    @the_family.each do |enrollee|
      assert_kind_of Enrollee, enrollee
      assert_equal @enrollment.id, enrollee.enrollment_id
      assert_equal @enrollment, enrollee.enrollment
      assert_equal @joe.id, enrollee.policy_holder_id
      assert_equal @joe, enrollee.policy_holder
    end
  end

  def test_get_gender
    assert_equal :male, @joe.gender, "Joe is a male"
    assert @joe.male?, "Joe is a male"
    assert_equal :female, @rita.gender, "Rita is a female"
    assert @rita.female?, "Rita is a female"
    assert !@billy.female?, "Billy is not a female"
    assert !@alice.male?, "Sally is not a male"
  end

  def test_set_gender
    [:female, ‘F’, 2].each do |tok|
      @joe.gender = tok
      assert_equal :female, @joe.gender, "Joe is now a female"
      assert @joe.save, "Joe could not be saved after sex change"
      @joe.reload
      assert_equal :female, @joe.gender, "Joe is now a female"
    end

    [:male, ‘M’, 1].each do |tok|
      @rita.gender = tok
      assert_equal :male, @rita.gender, "Rita is now a male"
      assert @rita.save, "Rita could not be saved after sex change"
      @rita.reload
      assert_equal :male, @rita.gender, "Rita is now a male"
    end

    # make sure that we can set it to nil
    @joe.gender = nil
    assert_equal nil, @joe.gender
    assert @joe.save(false), "Joe couldn’t be saved after neutering…"
    @joe.reload
    assert_equal nil, @joe.gender

    @joe.gender = ‘’
    assert_equal nil, @joe.gender
    assert @joe.save(false), "Joe couldn’t be saved after neutering…"
    @joe.reload
    assert_equal nil, @joe.gender
  end

  def test_marital_status
    assert_equal :married, @joe.marital_status
    assert @joe.married?, "Joe is married"
    assert !@joe.single?, "Joe is not single"
    assert @billy.single?, "Billy is single"
    assert !@billy.married?, "Billy is not married"
    assert_equal :single, @billy.marital_status
  end

  def test_set_marital_status
    [:married, 2].each do |tok|
      @billy.marital_status = tok
      assert_equal :married, @billy.marital_status
      assert @billy.save, "Billy could not be saved after he got married"
      @billy.reload
      assert_equal :married, @billy.marital_status
    end

    [:single, 1].each do |tok|
      @rita.marital_status = tok
      assert_equal :single, @rita.marital_status
      assert @rita.save, "Rita could not be saved after her divorce"
      @rita.reload
      assert_equal :single, @rita.marital_status
    end
  end
end

:)

lesscode … more docs?  21

Cat.: Ruby, PHP, First they ignore you.., Rails
20. September 2005

I’ll take it as a given that if you’re reading this then you agree that, for the sake of sanity and productivity, it’s time coders gave up on roll-your-own, and moved over to modern frameworks where one can concentrate on business logic rather than request parsing (and get all those AJAX goodies for free ;-) ).

I’ve been looking on with interest for the last year and a bit, and as I’ve watched the pioneers blaze their XP, RoR, lesscode trail across the web-firmament, I’ve begun to suspect that I must have missed something. Yes, it’s powerful stuff, and yes it isn’t all smoke and mirrors - there really is “gold in them thar hills…” - but, and for me it’s a big but, we seem to be missing the big picture. Where are the map makers? Where’s the documentation for the second (or third) wave?

Self-documenting code is all very well, and having a common vocabulary of design patterns helps when discussing solutions to individual problems. But what second-wavers really need (and I include myself here - no, actually, put me down as a third-waver) are more pictures. More exposition. Road maps.

Is there a way to add XD (eXtreme Documentation?) back into the XP mix? Writing elegant code is hard, and people who do it earn the admiration they received. But I would argue that writing good documentation is harder, and that it shouldn’t be left for the second-wavers to do.

People who’ve moved to XP have already gone thorugh the pain barrier of

  • write the tests
  • then write the code
  • (then refactor)

and have proved that in the long run, it means better code, less debugging, in less time. But having proved that that works, might there be some benefit in switching to;

  • write the spec
  • then write the tests
  • then write the code
  • (then refactor)
  • then write an overview!!!

Might this result in (my h-nought) more easily modfied code, quicker adoption by other coders, greater community support?

I’m genuinely interested in other people’s views on moving documentation down(?) the food-chain, so that it’s non-optional, and as integral to writing new code (and frameworks) as writing good tests. Yes, there are good auto-doc tools and methodologies out there, but that right now they still seem to be seen as secondary to the process by Joe Frontiersman, and they only deal with what’s in the file, not what’s in the coder’s/architect’s head. (There’s the nine diagrams of UML, yes, but who on the bleeding-wrist of open-source technology is actively using/sharing designs via UML?)

Let me know if I’ve missed a trick somewhere.

[A few thoughts for the pot: I believe the that the reason the Open Source model works because it’s based on non-coercive collaboration. But Source Forge is littered with unfinished, half-baked projects because someone didn’t think to check that there wasn’t already a project out there that they could use. (How many PHPUnits does the community really need?) Should there be a ‘requirement’ for documentation before a project gets listed? Perhaps it’s time for ‘ideaforge’, or ‘architectureforge”?]

History Repeats Itself  27

Cat.: Then they fight you..., F/OSS, Rails
22. August 2005

Jason Hunter (Jason Hunter), a renowned Java evangelist an the author of two highly popular books on J2EE technology (Java Servlet Programming, and Java Enterprise Best Practices, ) posted an interesting blog entry last week: The Innovator’s Dilemma: It’s Happening To Java. The “innovator’s dilemma” that Jason is talking about is expressed as follows: “you can listen to customers, provide them with what they want, but still lose out – because a cheaper, not-as-good but good-enough competitor comes in and eats your market.”

Kind of reminds me of the days when I was shopping for my home audio system. I used to visit lots of high-end shops, where knowledgeable sales personnel would engage me in detailed demos of various components, but at the end of the day I would walk across the street to some of those cheap outlets (Circuit City etc.) to see if I could get same or similar components for less.

The dilemma Jason is referring to is specifically related to Java. Here we have an exorbitantly expensive platform, that, ten years after its launch, had reached a point where it is too complex to be able to be used in any meaningful, let alone feasible fashion. So, in a way, we could say that the situation is similar to what was happening to the mainframes 15 - 20 years ago, when the businesses reached the end of their rope and realized that they need to adopt a more disruptive technology.

Jason’s thesis is that Ruby on Rails is this disruptive technology. Java is now being perceived as a sitting duck, similar to how mainframes were the sitting ducks of the early nineties. And similar to how client/server technology came about and claimed the market share traditionally reserved for the mainframes, RoR is today poised to eat into the Java’s market share (hence the ‘disruptive’ epithet).

One of the strongest arguments he makes about RoR’s threat is this one: “In programming these days, cheaper isn’t about price, it’s about mental effort.”

Now, anyone who’s ever tried to develop a web application using the J2EE frameworks, and then tried to to the same thing using RoR, will undoubtedly agree that RoR requires significantly less of a mental effort. And thus, RoR is significantly cheaper.

Ironically, it was this same quality that made Java so attractive 10 years ago. Due to the fact that Java was so much simpler than C++ (so much so that in its early days Java used to be called ‘C minus-minus’), it made huge inroads into the development community’s mind share, and overtook C++ as the language of choice when it comes to developing applications. Lowering the cost of software development is obviously a strong driving force in motivating the adoption of the new technology.

The mood in the Java camp nowadays is really strange. As is to be expected, the prevailing sentiment is the one of huge denial. This is similar to the mainframe crowd sentiment 15 years ago.

But the odd thing is that the same people who tend to shrug off RoR’s threat to Java seem to be at the same time working frantically on proving that Java can be concise too. Ironically, they are attempting to introduce simplicity into the Java platform by adding new features to it! This leaves an open question: since when is bloat to be regarded as simplification?

In the final analysis, it is extremely significant that a number of top-echelon Java evangelists are jumping into RoR heads first, and are buying into it hook, line and sinker. The worrisome aspect of all this is that, once RoR takes off and hits the mainstream, who’s going to do the new development? Most of the existing development workforce hadn’t managed yet to make the transition from procedural to object-based approach. The full fledged OO nature of Ruby, coupled with its dynamic nature, may prove to be too big of a challenge for the average application developer out there.

Giant solution in search of a problem  2

Cat.: Then they fight you..., Rails
15. August 2005

Twenty years ago I got involved in a course of AI (Artificial Intelligence) study. Soon afterwards, I’ve learned, much to my dismay, that this field has been, somewhat maliciously, dubbed ‘giant solution in search of a problem.’ Much as I’ve tried to convince myself (and the others) that AI has some pragmatic potential, I had to eventually abandon my efforts, and turn to some of those truly pragmatic solutions (such as RDBMS, for example).

History tends to repeat itself, and so (not surprisingly), I’ve ran into the same scenario (i.e. got involved with more than one ‘giant solution in search of a problem’, or GSISOP) throughout my meandering career.

The first major bump in the road was working with CASE (Computer Aided Software Engineering) tools. Those beasts used to be all the rage in the mid to early ‘80s, but witness the speed with which CASE turned into a dirty word in the early ‘90s. That utopia had to be abandoned promptly.

The next bump came in the form of ‘screen scrapers’ which were proposed as a GSISOP to bridge the gap between the monolithic mainframe apps and the burgeoning two-tier client/server enablers.

One of the biggest GSISOP bumps I’ve ever experienced was Lotus Notes, later dubbed Domino (does anyone even remember that unruly beast?) That platform was so ridiculously clunky, that even the biggest Domino zealots had extremely hard time explaining what is it that this product actually does?

Fast forward to 2005. What is the GSISOP we as a development community are forced to deal with today? CASE is dead as a doornail; screen scraping and client/server are dead as well; so is Domino. Does it mean that GSISOP is dead too? I wouldn’t bet the farm on that.

Ten years ago I’ve abandoned the world of two- and three-tier client server technology for the new kid on the block. That kid was then called the ‘nomadic code’. Remember the ‘network is the computer’ slogan? Or, for that matter, does anyone here remember the ‘PC killer’ – the NC (the network computer, or the glorified dumb terminal that was all the rage back in 1996)?

I remember how in those heady days me and some of my more idealistic colleagues firmly believed that the applications of the future will consist of modules of highly mobile code buzzing around the net, arriving ‘just in time’ to assist with some hairy, highly critical, highly demanding and customized behavior. We furthermore believed that these modules will live in a highly competitive environment, vying for the end-user’s attention, competing to deliver the best, most robust service, thus building their own reputation. Talk about GSISOP!

Yes, we were the Java evangelists. For us, Java was the way of the future.

We had to endure a lot of flack for our beliefs. But we’ve persisted, prevailed, and through Herculean efforts managed to bring Java into the corporate fold. Despite the false and doomsday claims that Java was ‘too slow’, that it ‘wouldn’t scale’, that it was ‘too complex’, today we see that Java is the bread-and-butter of the contemporary corporate computing.

So why am I telling you all this boring stuff? The reason is that today we finally have this ‘new kid on the block’ – Ruby on Rails. Similar to what Java was ten years ago, RoR today promises a completely new way of not only looking at things, but also on doing things.

And similar to the case with Java ten years ago, many people fail to see the true potential of RoR. Not surprisingly, because, same as Java from ten years ago, RoR is not a GSISOP.

Why am I convinced that RoR is not a GSISOP? First of all, it’s not ‘giant’ (same as Java was an agile, small footprint solution ten years ago). Secondly, it’s not a ‘solution in search of a problem’, because it deals with a very specific problem at hand – how to implement the principle of Occam’s Razor. And it does it extremely successfully.

So, if Java is not a GSISOP, why do we need another non-GSISOP? Doesn’t the principle of Occam’s Razor (‘entities should not multiply beyond necessity’) go directly against having two similar solutions?

You see, the problem is that Java WAS not a GSISOP, but (sadly) grew into one over the years. Today, I claim that Java slowly and maybe imperceptibly morphed itself into a GSISOP. One need go no further than examine the Struts framework, for example, if one would like to understand what a GSISOP really is.

As we all know, Java community is getting mighty agitated over the RoR promise. What’s particularly amusing to me personally is how the same people who had to endure unjustified attacks on Java some eight-ten years ago, are now using the same unjustified argumentation to attack RoR!

Of course, a number of Java supporters are now rushing out to perform what I like to call ‘putting a lipstick on a corpse’, in order to prove that Java is indeed capable of doing anything that RoR can do. These are sadly misplaced efforts, which eerily remind me of the long gone days of the screen scraping efforts. Same as the mainframe folks tried desperately to prove that Mainframes can do client/server computing without leaving their comfy OS, Java advocates are now wasting their time trying to prove that ‘Java can be concise too’! It resembles some political PR where a spokesperson of some dictatorial regime claims that their regime can be democratic too. Yes, there is no doubt that it can, but the real question is: why isn’t it? If Java can be concise too, then why isn’t it concise already? Why do we need Struts? If Java is by its nature concise, why did we end up with such monstrosities as Struts and Jetspeed and Expresso and Tapestry, etc., all of which harken back to the bad old days of mainframe programming?

In the future (if the future ever comes for me), I’m planning to discuss the shift in the philosophy of complex system development that RoR brings to the table. I’m planning to focus on the complex-vs-complicated dichotomy in particular.