« Older Home
Loading Newer »

CodeJam@Thoughtworks Beijing

Ye Zheng wrote quite a detailed account (in Chinese) about our first CodeJam in the Beijing office already, so I’ll just be brief. I had a great time pairing with other colleagues that I haven’t worked with before. In hindsight I was quite amazed how much we accomplished and how smooth it went.

I saw many Agile practices condensed, surprisingly well, during this exercise. Examples:

  • story and bug wall: a great tool for the Business Analysts and the client to have conversations and prioritize them
  • TDD
  • stand-up meetings twice a day
  • a mini-retrospective without the voting but just bringing up suggestions to improve
  • switching pairs to spread the code knowledge (for me, 3 times during 2 days). Even for a short project like this, even though there isn’t a lot of historical knowledge. When my pair knew about the acts_as_authenticated plugin and how they tweaked it, and I knew about one model object, Textmate, and a few rake tasks, we both became much more efficient when working on the next story.
  • CruiseControl.rb was set up and reminded of files that I forgot to check-in

The client, the Director of IT of a non-profit organization dedicated to rural education in China, seemed to be very grateful for our volunteer work. The quality and the amount of value we delivered to him seemed to have exceeded his expectations too.

Quoting him: “What you guys did will definitely be of help to us, and I can’t thank you enough. You let them all know that!”

Don’t be a refactoring bigot (follow-up)

Thanks to Justin and the comments on his post (No, Be a jerk), for expanding on my blog post and taking the discussion to a much more sophisticated level than I started. Instead of “Don’t criticize code”, I think this will be more suitable title of the paragraph: “Give constructive criticism”. I agree completely with Justin that refactoring itself is a kind of criticism. And it’s the constructive kind.

I also agree with Clinton’s point regarding team dynamics. Communication is important to write better code might not be well-received by your pair if you make him/her defensive, even though your point is clearly uttered and makes total sense.

Depending on your pair’s personality, criticizing the code could sometimes lead to a healthy debate, but other times could lead to too much negativity and too much judging. I’d say that I’ll try to keep my pair engaged (being a jerk or not), do the necessary refactoring, while keeping a positive vibe. Then I think it’ll pay off well to the code base, and to the team, in the long run.

Services != Distributed Object

(The title quotes Joshua Graham’s comment here) I agree completely with Josh. In a casual conversation with Tim Cochran of Thoughtworks, we both felt that using RESTful controllers does not mean exposing all of your model objects, or database tables. Thoughts still need to go into designing the right interfaces.

In Rails, examples of RESTful controllers are usually CRUD controllers of ActiveRecord objects. (and the ActiveRecord objects are just straight mapping to database columns). My given example in the previous post is exactly like that, and that’s because script/generate and scaffolding just make it so easy.

However, that’s not an excuse not to think about what to expose, and what to hide. In our current project we have a rails app (say an HR app) that needs to obtain/update the Account information on another rails app (say an sales app). On the sales app side, let’s say Account is an ActiveRecord that has the following fields:

id: integer
number: integer
name:string
description: string
balance:integer
sales_person_number: integer

and there is already an AccountsController, with associated HTML forms, for CRUD-ing all the fields on an Account.

On the HR app, we are interested only in the sales_person_number of the account. So we instead implemented a brand new SalesPersonAssignmentsController on the sales app, to assign a sales person, so that

POST http://sales.app/sales_person_assignments params => {:sales_person_number => 666} # Give sales_person an account to look after

returns an empty HTTP response, with status code 201 CREATED, and the ‘Location’ header : "/sales_person_assignments/123"
# The sales app had given account #123 for the salesperson to look after

We haven’t implemented any security measures yet, to prevent the HR app to hit other actions on the sales app’s AccountsController. But at least the intention is that the HR app will only hit the SalesPersonAssignmentsController only, and nothing else, on the sales app. That hopefully limits the integration points, and make the change on one app have less impact on another app.

Conclusion: I think encapsulation, loosely-coupled systems, are good ideas. They don’t call me Captain Obvious for nothing :)

ActiveResource and handling a weird 204 response from a remote rails controller

In the examples given in ActiveResource Rails API, when ActiveResource does a PUT (e.g. update) to a remote RESTful rails controller, the rails controller is supposed to return a HTTP code of 204 (No Content).

But if the remote rails controller actually does that:
head :no_content #204

The Http response that ActiveResource receives is a Net::HTTPNoContent, with no body, but its Content-Length is, for some reason, “1″ !! So, ActiveResource will die in load_attributes_from_response(), when trying to call response.body.strip, but response.body is nil.

If you use Rails generated scaffolding for the remote rails controller though, the ‘update’ action that handles PUT request actually returns a 200 HTTP response:

head :ok

And in this case, everything is good.

I didn’t delve enough in ActionController and the ‘net/http’ stdlib to find out exactly why. I did notice that in net/http.rb:

class HTTPOK < HTTPSuccess # 200
HAS_BODY = true
end
class HTTPNoContent < HTTPSuccess # 204
HAS_BODY = false
end

I think ActiveResource should handle this weird behaviour of ‘net/http’ by doing a simple nil check of response.body in load_attributes_from_response(). I submitted a patch to
http://dev.rubyonrails.org/ticket/11066, so for the interested reader, you can verify my patch (that it works), or give suggestions to a better way of fixing this?

Trying out ActiveResource in 3 minutes

Recently I started using ActiveResource to talk to a RESTful controller (which is also done in Rails 2). It is very nice and simplifies a lot. With Rails 2, out of the box you can create a sample RESTful server and client in 3 minutes:

Server:

>> rails test_server
>> cd test_server
>> script/generate scaffold Account name:string balance:integer
>> rake db:migrate
>> script/server
-- hit localhost:3000 with a browser and create some accounts

Client:

>> rails test_client
>> cd test_client
-- create app/models/account.rb with the following:
class Account < ActiveResource::Base; self.site="http://localhost:3000";end
>> script/console
>> acc = Account.find(1) #script/console is now your text-based client :)

Voila! That’s all you need to try out the different methods on ActiveResource.

Don’t be a refactoring bigot

Developers want to write simple and elegant code. I do too, and so sometimes I catch myself being a little bit of a “refactoring bigot”, that when I came across code that I deemed not good, I became critical, or I just wanted to fix it all at once. Not very smart.

So here are a few things to consider, to avoid being a “refactoring bigot”:

Don’t criticize code by your team members

Code that is already written in your project, was written under constraints that you might not know about. It could have been a critical time pressure to finish the feature at hand. Or there might have already been a discussion between two developers pairing on it, and they reached a comprise based on other technical considerations. Or merely a difference of opinion: what I think will be prettier code might have its downfalls too. So, just like they say in Retrospectives: “… that everyone did the best job they could, given… the situation at hand.”

Do refactor, but do red-green-refactor

Don’t criticize, but do improve the code base when you see fit. Do the refactoring, but don’t be tempted to just go ahead and re-organize everything, and deviate from red-green-refactor cycle. You might come across a piece of code that you want to refactor while you’re trying to make a unit test pass. Make a note of it, make the test pass first, and then come back to do the refactoring. That way you can have the confidence that the tests will catch any errors during your refactoring. And the developer who’s pairing with you will be more engaged too, when there’s a clear boundary of making a test pass, and refactoring.

Still refactor to help understand code, and write more tests if necessary

One reason to refactor is to help oneself understand the code better. Especially when you delve into a new part of the code base, you might find it hard to read, whereas your pair might already be very familiar with it.  If there is room for simplification, refactor to make it easier for you and others to understand.

With dynamic languages like Ruby and Javascript, I haven’t been using a true IDE with refactoring support. So sometimes that means simple refactoring tasks like “Extract method” are a manual process. Here I sometimes diverge from classic refactoring (keep tests unchanged, change the code, and have all tests still pass), and write an extra test, say, for the extracted method, or the newly created class.

This also break down the refactoring process into smaller manageable chunks, and having smaller chunks help your pair to see where you’re heading too.

Conclusion

Don’t be a refactoring bigot: don’t criticize, red-green-refactor, keep your pair engaged, keep refactoring in smaller chunks.

JSON is valid YAML

I was searching for simple JSON parsing in Rails and found only the Rails 2.0 way: ActiveSupport::JSON.decode. In old version of Rails (1.2.6) there’s only JSON.encode…

So I googled and found here that you can do YAML::load ‘{”key”:”value”}’

A few things I learned about ActiveRecord after_create (and other callbacks)

1. after_create does not get inherited
class Animal < ActiveRecord::Base

after_create :feed_on_milk
def feed_on_milk

self.immunity_level += 1

end

end

class Cat < Animal
end

The after_create does not get inherited, and so our poor little cats won't get milk! To retain the after_create hook, you'll need to do:
class Cat < Animal

after_create :feed_on_milk

end

2. after_create is an array of symbols

If you call after_create on same symbol :foo twice, the ‘foo’ method will be executed twice. I had a bug in my code because I had something like:

class Animal < ActiveRecord::Base

after_create :feed_on_milk

end

and at the same time somewhere else I had something like:

klasses = [… ,Animal, …]
klasses.each do |klass|

klass.class_eval do

after_create :feed_on_milk

end

end

So, :feed_on_milk symbol got added to the array twice, and so the method got executed twice, and I had to do this instead:

klass.class_eval do

after_create(:feed_on_milk) unless self.after_create.include?(:feed_on_milk)

end

3. after_create is one of many ClassInheritableAttributes

The reason behind 1. and 2. is that Rails extends Class to have these “attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of their parents’ attributes, instead of just a pointer to the same.”

See vendor/rails/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb

TDD is good for your happiness and well-being

“Flow”, by Mihaly Csikszentmihalyi, is one of the pioneering books in the field of Positive Psychology, i.e. researching about what makes people happy and productive, instead of focusing of psychological diseases.

One of the key concepts in the book is that for an experience to be enjoyable, it has to be challenging at the right level, and in the process you experience growth and become more “complex”. Therefore, one of the criteria of an enjoyable activity is that it gives feedback about how well one is doing, so that one can evaluate progress, and adjust one’s course of action to improve.

That’s why TDD (Test Driven Development) is good for your happiness and well-being. By writing a test first, and then the code to pass the test, you’re getting feedback that you’re making progress. Then at the refactoring stage of the “Red-Green-Refactor” cycle, it is essentially a chance for you to not only improve the code base, but also improve yourself as a coder. During a work day, every passing test counts as a tiny win in my mind, and they add up positively.

Speaking from personal experience of coding without TDD, TDD has definitely made coding more enjoyable for me than ever before.

Learning Textmate shortcuts

As Nick Carroll said here, pairing with different IDEs means more shortcuts to remember. For our project we’ll be using jEdit and Textmate, so that motivated me to look up the equivalent for Textmate
: Ctrl-Cmd-T lists the actions in a Quicksilver manner.

During onboarding with new developers, it takes quite some efforts to learn the shortcuts too. When I was new to Textmate, I tried to use Keycastr to display what shortcuts my pair typed. It’s a really neat tool, but that seemed to annoy my pair :) I’ll try to use it again with settings that’s not as annoying (flash and disappear more slowly, and show for command keys only)