Archive for the 'Beautiful Code' Category

Rails 1 – 0 Smalltalk

Friday, April 20th, 2007

One thing has struck me over my recent Rails-beautification tangent.

My fictional resource-routes example:

  map.resources_called(:course_templates,     :adding => [      GetMethod.called(:build_courses, :on => :members),       PostMethod.called(:do_build_courses, :on => :members)    ],     :nesting => map.resources_called(:course_details)  )

looks better than the fictional Smalltalk example.

Likewise my (real) Markaby view example looks better than the (real) Seaside/Smalltalk example.

Things are not so bad in the world of Rails …

markup.become(:beautiful)

Thursday, April 19th, 2007

In my brief exploration of Seaside one of the points that caught my eye was that the components render themselves in HTML.

 html table:    [html tableRow:        [html tableData: [html bold: 'Name'].         html tableData: person name].     html tableRow:        [html tableData: [html bold: 'Age'].         html tableData: person age]]

Two points: firstly – I read in one interview (sorry, can’t find the link) that this leaves the designer to control the CSS and the programmer to control the HTML. This immediately struck me as a good thing – for the HTML to be properly CSSable it needs to be well-structured and semantically rich. Which you should do anyway but it’s easy to forget. And secondly, that code snippet above looks great compared to your typical .rhtml file (I think it’s something to do with the angle brackets in HTML which make it hard to read).

So, in the interests of making my application more beautiful, I started investigating how to do something similar in Rails. Which lead me to Markaby – Markup in Ruby. Install the plug-in and, instead of creating rhtml views you create mab views.

Which look like this:

div.contents! do  error_messages_for :booking  form_for :booking, :url => booking_path(@public_course, @booking).to_s, :html => {:method => :put} do | form |    h3 "Customer Details: "    p do       label "Contact: "      collection_select :booking, :contact_id, @contacts, :id, :name    end    p do      label "Notes: "      text_area :booking, :notes, :rows => 5    end    p.explain "Add any arbitrary notes here"    p do      blank_label      submit_tag "Save"      text " or "      link_to "cancel", booking_path(@public_course, @booking), :confirm => 'Are you sure?'    end  endend

Doesn’t that make you feel good? Especially the p.explain (which outputs a P tag with the class “explain”) – immediately you can see how semantic markup becomes integral to your views.

I did have a few problems with the helper methods – I had to set @output_helpers = false and I switched from using the form.text_field :method helpers to the old-style text_field :object, :method helpers (which also meant losing my labelled_form_builder). But it’s a small price to pay for such superior looking markup.

Stay Beautiful

Tuesday, April 17th, 2007

Mr Hansson has been winding people up recently, with his Twitter Controversy. But one of his more polite recent posts is about Seaside – a Smalltalk web framework that uses stateful objects on the server to allow a modal-style flow of control within your web application. One component receives a callback as the user clicks a link, it calls into another component and sits and waits until the second component returns control to the first – just like calling a subroutine.

I’ve made no secret of my love of Smalltalk – it’s what attracted me to Ruby and Rails in the first place. There’s a beauty about Smalltalk code (although please forgive any typos in the code below as I’ve not done any for a while) that you rarely see anywhere else, although Rails has it in places. I could go on for hours about:

  under21s:= people collect: [ person | person under21 ].  

Is that better than:

  under_21s = people.collect do | person |     person.under_21?   end

Not much in it. Ruby has the question mark – I like that as it makes the code read better. But Smalltalk has less superflous punctuation to make it read better still. And I love the full-stop to finish the sentence.

How about:

  nail needsHitting ifTrue: [ nail hitOn: #TheHead with: aHammer ].

Versus:

  nail.hit(:on => :the_head, :with => hammer) if nail.needs_hitting?

Ruby has the if at the end of the sentence, which I really like – and it’s even better when using unless. And Smalltalk has its slightly weird “everything is an object or message” ifTrue: method on the true and false instance variables that lead to something that is a bit less readable than the Ruby. But Smalltalk doesn’t need the parenthesis. And blocks are passed as normal objects (not weird add-ons that may or may not be tacked on to the end and sometimes implicitly converted to Procs). And if is not a reserved word.

Recently I’ve noticed the Smalltalk creeping into my Ruby style. Things like:

  validate(course, :against => template, :on => this_date)

Which is reasonable. But the brackets just kill me.

And then I had to write this:

  form_for(:course_template,     :url => course_template_path(@course_template),     :html => {:method => :put} do | form |     # form.stuff  end

It’s awful (yeah, yeah, I need SimplyHelpful).

What about, in config/routes.rb:

  map.resources(:course_templates,     :member => {:build_courses => :get, :do_build_courses => :post}) do | course_template |    course_template.resources(:course_details)  end

They really ought to read:

  courseTemplates:= map resourcesCalled: #CourseTemplates;    withAnAdditional: #GetMethod :called #BuildCourses :on #Members;    withAnAdditional: #PostMethod :called #DoBuildCourses :on #Members;    nesting: (map resourcesCalled: #CourseDetails).

Note: the nested call to resourcesCalled is actually sent to map, not to a nested object as in the Ruby original.

A literal translation would be:

  map.resources_called(:course_templates).with_an_additional(    :get_method, :called => :build_courses, :on => :members).with_an_additional(    :post_method, :called => :do_build_courses, :on => :members).nesting(      map.resources_called(:course_details)    )

The semi-colon chains method calls together (assuming each call returns the original return value from map.resources_called. But it’s really really ugly in Ruby.

The closest I can think of for this is:

  map.resources_called(:course_templates,     :adding => [      GetMethod.called(:build_courses, :on => :members),       PostMethod.called(:do_build_courses, :on => :members)    ],     :nesting => map.resources_called(:course_details)  )

which is a lot better but still pretty ugly (nested brackets – urgh).

Of course, map.resources is probably an instance of DHH’s syntactic vinegar – I’m sure that in his mind you should never add extra calls as it breaks the nice clean REST architecture. Well tough. I think myserver.com/course_templates/23;build_courses describes what I want very succinctly.

It’s definitely something that’s on my radar now … I want my Ruby and Rails code to be beautiful. Otherwise I may just be looking at Seaside in more depth.

Ruby on Rails is the MacOS to Java/.Net’s Windows

Tuesday, March 20th, 2007

Pierre Igot rants about the user interface for Apple’s Mail.

John Gruber rants about click-through in background windows in OSX.

Both of these (and there are many more if you search the interweb) show the extremely high standards that Apple is held to when it comes to user-interface details. You don’t often see criticisms of Linux or Windows applications that go into such intricate detail:

If you select “Sending…” while Mail is in the process of sending the message, Mail continues to display your list of sent messages, excluding the message currently being sent. In other words, not only does the text label temporarily display a status message instead of the text that should normally describe its contents, but on top of it that temporary message misleads you into thinking that you will be able to see the message that Mail is currently in the process of sending by clicking on it, when actually it does not show you that message.

The reason I mention it is not in some sense of Apple vs Microsoft superiority (I’ve not used Vista or Office 2007 and they are supposed to be OK on the UI front – although I bet you could find a folder caption being used to display a status message if you looked hard enough) but more a sense of Rails vs everything else superiority.

I was talking to another developer today about what I should call a method on one of my objects. My colleague is one of the most talented developers I have ever met but he has never used RoR.

I said “I’m not sure if I should call it account.number_of_events_remaining or account.number_of_remaining_events“. He said either would be fine – “if the name reads right then that’s good enough“. To which I replied “but no matter which one I choose I seem to type the other name“. To Nick this was “operator error” – a problem of typing. To me it was symptomatic of something deeper. The words didn’t feel right. And as we all know if it doesn’t feel right it probably isn’t right. It was a folder caption being misused as a status label.

I could alias the method names – in other words use both. Nick said programmers need consistency. I agreed – aliasing is useful but I think it just adds unnecessary confusion in this case. He suggested I choose one and type it out one hundred times so it becomes imprinted in my brain. This proved to me that the name was wrong – “if i have to force myself to do all of that just to get a property name right then it’s the property that’s at fault – not me“. Plus if we have five developers, with a hundred properties, think how much typing that is before you even write a line of code!

Esoteric discussion by developers with too much time on their hands (I wish)?

In a way, yes; no paying customer will ever see that property (apart from indirectly through the UI).

But, looking deeper, it’s important. Vitally important. Because it’s all about meaning and understanding. When you are looking for the status message do you look to the status bar or your folder list? When you are trying to find out how many events you have left do you have to try different combinations of valid words?

Is it designed so that you “get it” straight away or do you have to rehearse it till you understand?

(In the end, I went with account.remaining_event_allowance)