Archive for the 'Writing Reliable, Bug-Free Code' Category

Ruby on Rails Basics

Wednesday, May 21st, 2008

Sometimes, it’s worth stating the basics for all to see:

  • Follow the Model-View-Controller paradigm.  In particular, your views house your user-interface, your models handle the application and your controllers mediate between the two.  Controllers do not contain rules, conditionals dealing with business conditions, queries looking for objects related to the one in question.  All those things belong in the models.  
  • Use ActiveRecord conventions at all times.  It may not be the most efficient thing in the world but for most of you out there, it doesn’t matter.  
  • Use ActiveRecord and migrations to define and manage your database.  All your business related stuff stays in one place – the models – including defining relations (associations), validations and rules.  In particular, ActiveRecord associations makes some tasks easy (very simple many to many relations) and gives you things (such as polymorphic associations) that you can’t safely define using straightforward SQL.  With judicious use of validations you can ensure that the data stays safe.  
  • Use RESTful designs in your controllers.  This means that your controller very rarely grows beyond seven actions (index, show, new, create, edit, show, destroy) – and RESTful routing ensures that GETs and POSTs go to the right places.  If you need to extend things then add a sub-controller.  For example, if you were transferring an employee to another, you could have a route: /employees/1 for the employee him/herself, /employees/1/transfers/new to let the user define which company the employee is moving to and /employees/1/transfers/create to actually do the transfer.  And if you’ve defined your model correctly, the implementation of /employees/1/transfers/create should be as simple as @employee.transfer_to(@company)
  • Write your tests (or specs) first.  One – this gives you a series of small wins, which is good for your self-esteem.  Two – it helps to clarify your thinking.  ”I need to write something that does X and Y, resulting in Z … oh hang on, do I really need Y?  What about U and V?”
  • Use mock objects when testing your controllers.  Why bother coming up with lots of test data when all you really need to say is “if I the model saves correctly then redirect to X, if it doesn’t save then show Y”.  In the “transferring employees” example above, you only need to test that the controller calls “transfer_to” on your model.  Of course, your model will have already tested that transfer_to does what is expected of it.  
  • If you find yourself repeating a bit of code, or writing something similar then STOP and refactor.  Add methods to the application controller, create a new controller descendant, stick it in a view helper, add a module to your models, write a partial (and if it needs parameters, write a helper that takes a set of parameters and does the call to render :partial for you)
  • Did I say write tests and specs first?
  • Oh, and if it starts getting complicated you’re almost definitely doing it wrong.  

Cross Platform Development – testing on both platforms

Friday, January 25th, 2008

Internet Explorer versus CaminoLike a growing number of computer users, 3hv is an Apple Mac based company. Sometimes, this can lead to problems … most people use Microsoft Windows, which looks and works differently.

Never fear – since Apple switched to using Intel processors, companies such as VMWare and Parallels make it possible to run Mac software alongside Windows software. Making cross-platform testing a breeze.

Weird behaviour involving controllers, modules, namespaces and functional tests

Monday, December 10th, 2007

Weird one here.

I was working on some code that had controllers within a namespace (Admin::ThingyController). The controller descended from an Admin::BaseController. And Admin::BaseController included a module (include GenericStuff), which in turn was defined within the Admin namespace.

So far, so good.

The code-base was actually somebody elses and the time came for me to add a new controller into the Admin namespace. So away I went: ruby script/generate controller admin/another_controller, editing the file so that Admin::AnotherController descends from Admin::BaseController.

Then, as I do, I filled out my functional tests, made them pass (ruby test/functional/admin/another_controller_test.rb) and then built up some (reasonably) nice views and examined them in my browser.

All good. The views worked, the tests passed, the controller did what it was supposed to.

One final check before committing to svn – rake. Bugger. A whole load of failures. What have I broken? Eh? It’s AnotherController that is failing. Check it in the browser. All good. Check the test individually. Row of dots. Try rake test:functionals. Blam!

To cut a long story short (actually the story is pretty short, it was the investigation that was long) the cause was the included module in the BaseController. What is particularly weird is that it was only AnotherController that had the failures, even though all the controllers within the admin namespace were defined the same way. Adding the new controller had upset the rake loader somehow.

And the fix? Change the include in BaseController from include GenericStuff to include Admin::GenericStuff (even though the admin prefix is not necessary as both GenericStuff and BaseController are within the same namespace). Now they all work – tests, rake and in the browser.

Incorrect Test Fixtures lead to Weird Testing Results

Friday, November 16th, 2007

After recently praising test fixtures as an important (but time-consuming) part of building your tests, there is something to watch out for.

If you get one of your foreign key references wrong in your fixture data you can get odd results. In particular I had a test that passsed when run using ruby test/unit/my_test.rb but failed when run using rake test:units.

The cause? Simple. I had two fixtures files, :orders and :work_items – where work_items have a detail relationship to orders (with a foreign key order_id). My orders fixtures looked something like this:

  id: 1  
  some_field: whatever
  id: 2  
  some_field: thingy
  id: 3  
  some_field: wotsit

My work_items fixtures looked something like this:

  id: 1
  order_id: 1 # daves first order
  some_field: fish
  id: 2
  order_id: 1 # daves first order
  some_field: gerbil
  id: 3
  order_id: 4 # georges important order
  some_field: giraffe

Spot the error? It took me a while – and as I say, the only symptom was this odd behaviour where the test passed in one case but not in the other.

It turns out that the fault was this – one part of the test was creating a new order from scratch and assigning work_items to it. When run via rake the test database was torn down and rebuilt, matching the structure of the development database. Also meaning that every time the test was run, MySql new to give the next record in the orders table an id of 4. So the typo in the work_items fixture file (where first_line_of_georges_important_order has an incorrect order_id of 4) meant that the work_item pointed at the wrong order – leading to a cascade of further failures. For some reason, when run without rake the test passed as the order_id of 4 actually resolved to :georges_important_order (although I’m still not sure why).

The moral of the story? If you get odd behaviour, where your tests behave inconsistently, then examine your fixtures files in great, great detail.

Dog by kufrik

Test Driven Development is not about testing

Wednesday, November 14th, 2007

People who practice test-driven development are doing design. It’s important – actually, it’s critical – to understand that. If you fall into the trap of thinking that TDD is about unit testing, then you’ll probably miss the point.

Too many teams believe they’re doing TDD, but are actually just writing unit tests for code they’ve already written, or writing one unit test and then writing 500 lines of production code before they move on to the next unit test.

Absolutely. Applications that have unit tests written before the actual code tend to have looser coupling, cleaner design and concentrate purely on what is required (rather than evolutionary dead ends).

rake db:fixtures:load

Friday, November 9th, 2007

rake db:fixtures:load is probably one of the most useful commands I have used recently.

You see, I was meeting some people about some potential work. They wanted to see an example – preferably related to payment systems. I had some code but unfortunately, the service that is part of had been switched off (a number of reasons, none of which connected to my supreme stylings). I had a copy of said code on my machine, but no database and I had no time to prepare.

So how could I demo it? Easy peasy.

cd ~/Source/my_app
rake db:migrate
rake db:fixtures:load
ruby script/server

And then start Camino.

Because the application had been developed test-first I knew that there was a decent set of data within those fixtures. Data designed to show all the edge cases, all the complexities of the application. From users and logins through to payment records and customers.

It is fair to say that when writing your applications, test-first, the fixtures are the hardest thing. It can take ages and it is detailed, painstaking work. Especially if you are trying to build a narrative (:dave logs in, selects a :cucumber, goes to the :checkout, pays with his :expired_credit_card which is rejected).

But the benefit is there. Building a narrative helps you when you come back to the code in six months time. Defining a wide-range of test fixtures helps you when you make changes and need to ensure that it won’t break a feature over there. And it helps you demo your code in front of a prospective client when faced with the unexpected.

Data Highway by KLatham.

If you find this useful then please take a look at some of my other writing – or recommend me on Working with Rails. Cheers.

A method for successful software development

Wednesday, October 3rd, 2007

I’m just thinking out loud here – based on stuff I’ve done well in the past. But this is no rigorous scientific method – just a set of notes for me to refer back to.

* Write a couple of paragraphs describing the application. Note down keywords (especially important nouns and verbs) and maybe a “what, who, why and how” type analysis (when and where may or may not be applicable, depending upon the application).
* Show this to other people and get their feedback.
* Sketch out the UI. On paper, with a 6B pencil and an eraser, or on a whiteboard, with a camera. Do a flowchart for each of your major tasks (look at the verbs from before) and then a quick sketch of the pages involved. As you sketch out the pages you will probably find that you need to change the flowcharts. Think long and hard about it and then change if you must.
* Show this to other people and get their feedback.
* Create a new project and add it into subversion.
* Take your flowcharts and decide which controllers will be involved in each task. [I'm not sure about this point - but I reckon you probably don't want a single controller to be involved in more than one task - however each task will probably require many controllers].
* Generate the controllers and then use them to create static HTML/CSS mockups of your UI. The only “active” portion of these mockups should be links navigating through the task. As you do the mockups you will probably think of new functionality – add these to your flowchart immediately – if it becomes apparent when you have actual pages in front of you it’s probably valid (as opposed to the “up in the air” additions above).
* Get your mockups to respond to a parameter: mockup_style; if this is blank then show the page, if this is “empty” then show the “blank slate” page, if this is “error” then show the “error” page. In other words, think about how it looks in those three important states up-front.
* Show these mockups to people and get their feedback.
* Write functional tests for your controllers. Deal with things like showing the blank slate page when there is no data to display (I like to use assert_select to search for a div called “whatever_blank_slate”).
* Dealing with each controller in turn, get the functional tests to pass. In order to do this, you will probably have to create models. As you create the model add unit tests and test fixtures – and then use these to make the functional tests actually work with real data in a real database.
* Do the bare minimum to the models, fixtures and unit tests to get the functional tests to pass. Even if you know the next controller will need a new method adding to the model, don’t add it in early. You never know – your boss may change his mind and decide that that function is not needed (or more likely, can wait till version 1.1) – in which case, why make things complicated before it is needed?
* Whenever you find yourself writing code that is similar to code elsewhere within the project stop and refactor it into a helper, a method on the controller, a base (inheritance) model class or a mixin module. Don’t Repeat Yourself.
* Related to the above, put business functionality into the models (unit tested) – for example if your view needs to show the last four invoices but one, add a method to your customer class called “last_four_invoices_but_one”. Don’t get your controller to grab all the invoices and slice the array itself.
* Once all your functional test passes, run the app in at least two (preferably three) browsers. In theory, if your functional tests are any good, you should see pretty much a working task. Any bugs you find should be reproduced in the tests, if at all possible, and then fixed.
* Show this to people and get their feedback.
* Refactor your controller and models to tidy them up. Remember you have very high test coverage so you should not break anything without being alerted to the problem.
* Move on to the next functional test.
* When they are all done – you should have a working application!
* When the inevitable changes requests come in, you should have full coverage of unit and functional tests, making change management easier than it would be without those tests.

As I say this is thinking out loud – I’ve never done all of these at the same time – but I’m certainly planning on following this process on one of my own projects in the near future.

Gears by csotelo.

The advantage of testing first

Saturday, September 22nd, 2007

I really like Test-Driven Development. Think about what you need to write, write a test (that fails), then make it pass. Repeat. Refactor.

Obviously, the major benefit is that further down the line you can be sure that what you are writing today won’t break what you (or someone else) wrote six months ago. The tests also serve as a type of documentation (why is that method on the invoice class so complicated? let’s simplify – oh, that test fails – it appears you can’t allow the invoice value to be less than £3 on a Wednesday) – especially if you are using RSpec.

But one advantage, that I feel is often overlooked, is because you are starting from the point of view of a user of your code, your method names and parameters are automatically designed from the user’s perspective, not the implementor’s perspective.

One of my favourite examples is

dave.hit nail, :on => :head, :with => hammer.

This makes your method definition look like

def hit target, options
place = options[:on] || :head
object = options[:with]

In other words the method definition does not reflect how the caller would actually use your method. If you started from the method definition you would probably come up with

def hit target, place, object

This makes much more sense from the implementers point of view, but our call becomes

dave.hit nail, :head, hammer

which is slightly less readable from the point of view of someone examining the call in six months time. And those tiny annoyances add up without the reader realising it, till they are tired, the last few lines of code didn’t really sink in and they think fondly back to that other chunk of code that was a joy to read. “Why can’t all code read like that?” they think.

Well, it takes a switch of perspective – one that test-driven development encourages and most other “methodologies” don’t even acknowledge.

Rails is not a silver bullet

Sunday, September 2nd, 2007

Ruby on Rails won’t make you a better coder.
Ruby on Rails won’t deliver a bug-free project.
Ruby on Rails won’t ship your release on time.
Ruby on Rails is not a silver bullet.

I love Ruby on Rails.

I can work faster, more reliably, using “cool” technologies like Unix and Macs and get more done with less grief than any other technology I have ever used.

But Rails is not a silver bullet.

It is still possible to screw things up. Ugly code, buggy sites, slow applications. Rails may make it easy to do things the “right way” but old habits die hard.

Ultimately, what you need, more than anything, is a pervasive set of automated tests. And it’s easier to have a pervasive set of tests if you write them before you write your code.

Why is this important?

Tests give you confidence that the code you just wrote, over here, does not break the code you wrote last month, over there.
Tests give you confidence that the complex, interactive web page that you wrote does not break when you decide to change the way that it works.
Tests give you the ability to go back and tidy up that code that was written at 4:59 on a Friday afternoon – turning it from ugly to beautiful.
Tests become a living, breathing specification of your client’s requirements. Why oh why did we write that code that way? To make sure that “test_customer_order_value_must_not_be_negative” always passes.

So, if you’re just starting out with Rails, please bite the (silver) bullet and write those tests, unit, functional and, if necessary, integration. It may seem to slow you down today but you will not regret it tomorrow.

form_test_helper and AJAX (update)

Tuesday, April 24th, 2007

Jason Garber has updated his excellent form_test_helper plug in to support XmlHttpRequests.

Rather than the clumsy code I showed before you can now test your Ajax form with a simple and elegant:

# test in non AJAX mode
thingy = Thingy.find 1
get :edit, :id =>
assert_response :success

submit_form do | form |
form['thingy[field]'] = 'wotsit'
assert_redirected_to thingy_path(thingy)
assert_equal 'wotsit', thingy.field

# test in AJAX mode
xhr :get, :edit, :id =>
assert_response :success
assert_rjs :replace_html, "thingy_panel"

submit_form :xhr => true do | form |
form['thingy[field]'] = 'doodah'
assert_response :success
assert_rjs :replace_html, "thingy_panel"
assert_rjs :visual_effect, :highlight, "thingy_panel"
assert_equal 'doodah', thingy.field

Note: the fantastic example above also uses Kevin Clark’s ARTS plug in for testing the RJS responses.

So what are you waiting for? Fire up that subversion client and get downloading.

Thanks Jason.