Constant crisis

In my Rails application, I have a file in

RAILS_ROOT/lib/pcm/web_services/constants.rb

On my development machine (OS X), I am able to reference items in this file/module using the prefix “PCM::WebServices::Constants” without having to require the file. Once deployed on Linux, however, this approach broke and I had to explicitly

require 'pcm/web_services/constants'

(or any other file I needed from the lib/pcm directory) for things to work. I suspected it had something to do with case sensitivity on Linux as opposed to not-so-case-sensitivity on OS X. I was wrong.

Upon further investigation, I find I can easily reproduce the problem, although I do not yet have an explanation.  The solution to the problems are (so far):

1) Explicitly require ‘pcm/web_services/constant’ wherever I need it.  No biggie, but I prefer the “less is more” philosophy where Rails automagically loads the constant without the explicit require.

More possible solutions coming soon…

—>8— cut here —>8—

1) Create a new Rails app, e. g. $ rails constant

2) Edit the environment.rb file to add your own module with
configuration constant default values with the idea you could
“override” these by specifying them in the specific environment file:

At the end of config/environment.rb, add:

module AppConstants
  IMPORTANT_VALUE = "x" unless defined?(AppConstants::IMPORTANT_VALUE)
end

3) Create a Ruby module in the file lib/app_constants/list.rb, noting
the “top level” name of the module matches the one specified in the
environment file:

module AppConstants
  module List
    LIST_CONSTANT = "list_constant"
  end
end

3) Fire up the console and probe the constant values:

Loading development environment.

>> AppConstants::List::LIST_CONSTANT
=> "list_constant"
>> AppConstants::IMPORTANT_VALUE
=> "x"

4) Quit from the console and add development-specific value for the
constant defined in the environment file:

At the end of config/environments/development.rb, add:

module AppConstants
  IMPORTANT_VALUE = "definitely_not_x"
end

5) Fire up the console again and probe the constant values:

Loading development environment.

>> AppConstants::List::LIST_CONSTANT
NameError: uninitialized constant
Rails::Initializer::AppConstants::List
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/
active_support/dependencies.rb:263:in `load_missing_constant'
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/
active_support/dependencies.rb:452:in `const_missing'
from (irb):1
>> AppConstants::IMPORTANT_VALUE
=> "definitely_not_x"
>> AppConstants::List::LIST_CONSTANT

NameError: uninitialized constant
Rails::Initializer::AppConstants::List
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/
active_support/dependencies.rb:263:in `load_missing_constant'
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/
active_support/dependencies.rb:452:in `const_missing'
from (irb):3

If it’s broke, fix it!

As I reach the end of the day at the end of the week, I run my tests one more time before checking them in, and … BANG! Failure!

Nuts. I wanted to check stuff in and call it a day. What do I do: check it in anyway, or take the time to fix it before checking it in?

Of course, if you’re even here, you know the answer: take the time to fix it. Here’s two reasons why:

1) If I leave it unfixed, it is more likely than not that something will prevent me from taking the time on Monday to fix it. Then Monday will pass by, and so will Tuesday… and by the end of the week a simple testing error becomes a burden to fix. Consequently, I no longer get the warm fuzzies and confidence of a clean test run at will. So, maybe I’ll just let the whole test suite decay since it’s obviously now broken. Not good — I’ve just given up the value of my entire test suite because I wouldn’t take the time to track down and fix an error in a test case that used to pass. And trust me — the longer you wait to fix something like this, the harder it becomes to get yourself psyched up to deal with it.

2) It took me so long to write #1 that I’ve forgotten #2. No matter — I did go ahead and fix the test case and I ended up with a better test anyway.

nginx + rails + PUT + curl = 411 Length Required

One of my RESTful resources supports a PUT in order to get the next item in the queue and dequeue it. It is a PUT as opposed to a GET because it changes the state of the queue, and we all know that GETs should be idempotent.

In order to test this, I was using the following sort of curl command:

$ curl -i -X PUT 'http://localhost:3000/resource_name.xml;dequeue'

Worked fine on localhost. However, when I setup this up in staging going through nginx and over https, I ran the same command and got an unexpected result:

411 Length Required
nginx/0.5.31

So, I knew it was nginx that was giving me grief as opposed to mongrel and/or Rails suddenly changing its mind. I found the following note on the subject and changed the command to include setting the Content-Length header to zero, resulting in the following successful form of the curl command:

$ curl -i -X PUT -H 'Content-Length: 0' 'https://staging/resource_name.xml;dequeue'

Do Not Forsake Me, Oh My localhost

I recently setup an nginx proxy to a mongrel cluster using only https. No big whoop, right? Although I could get a file from the public directory, whenever I tried to invoke something in Rails via the mongrel, it’d hang. The error in the log file was:

2007/09/21 18:17:52 [crit] 4104#0: *33 SSL_do_handshake() failed (SSL: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca) while reading client request line, client: 127.0.0.1, server: staging
2007/09/21 18:17:57 [info] 4104#0: *35 client 127.0.0.1 closed keepalive connection

Sure, I didn’t have a “proper” certificate for SSL, but what gives with the whole hanging thing? Why didn’t it just come screaming back with some professional handwringing(tm) and get on with things?

Well, somehow when this machine was configured it was done without a loopback interface. Consequently, when I tried something like “curl https://localhost/…” from the command line, it’d sit there for forever. So, I created the loopback interface by adding the following lines to /etc/network/interfaces:

# The loopback network interface
auto lo
iface lo inet loopback

Restarted the machine, fired everything back up, and it works great — no more hanging trying to access a https://localhost/… URL. Go figure.

Google Quickies

I already knew you could search for a stock quote on Google using the following format:  stock:ticker symbol, e. g. stock:AAPL.  On a whim, I tried looking up a word using:  define:word.  Lo and behold, it worked.  These are really convenient thanks to the Google search box in browsers these days.

Guess I think like the Google guys.  They oughta put me to work, huh?

SMC Barricade and iChat

OK, so until I figure out what sort of new and improved wireless router I’m going to use in my office, I figured I might as well continue using this old SMC Barricade I have. Problem was it wasn’t allowing iChat video conferencing. After some fiddling, I finally arrived at the following settings in the “Special Application” [sic] screen that allowed the magic to happen. Might be overkill, but it works, so don’t fix it:

Barricade Settings for iChat

You can see the final port number got truncated on lines 2 and 4. For reference (and copy and paste), the ports are:

Trigger Port: 5060

Lines 1 and 3: 5060, 5190, 5220, 5222, 5223, 5298

Lines 2 and 4: 5060, 5190, 5297, 5298, 5353, 5678, 16384-16403

 

Edit 01-Oct-2007:

 

OK, so iChat AV worked for a while, but then broke.  I think I had a red herring in the above configuration.  Stay tuned…

Option + Drag + Quote

Yet another reason I love TextMate:

 

You may or may not know that when you have text selected in TextMate and you press the quotation mark it will surround the selection with quotation marks (instead of replacing the selection with a single quotation mark).

 

Also, you may or may not know that you can select an arbitrary rectangle of text in your code by option-click-dragging across multiple rows/columns.  Then anything you type replaces what you’ve selected on every line.

 

Putting these two features of TextMate together, if you have option-selected some text on multiple lines, and some of the lines have trailing space selected, then you press quotation mark, it does the Right Thing by placing the quotation mark before the trailing space on each line, as opposed to at the end of the selection on every line.  Very cool.

 

OK, it doesn’t read very well, so try it out yourself to find out what I’m talking about.  In the case where I was copying data from a spreadsheet into my Ruby code and needed to quote the values that I copied in, it was a huge time saver.

Test First, Code Later

I just wrote the following missive to some of my colleagues. Then I realized it would make a good blog entry, so here ya go…

 

The seasons are turning here [in Central Oregon] and it’s a little gray outside. I actually had to turn on the heater in my office! So, I’m dragging a little bit as a result and am looking to “shake things up” a little bit in my little office world in order to keep making progress. So I am listing what I need to do on my current project in priority order:

 

1) Write test client for normal life cycle

 

 

Wow, two years ago, that would’ve been at the bottom of my list (and thus fallen off) of a project. Then my mind speeds off to how different that thinking is than the way I was taught (albeit that was 20+ years ago but probably unchanged until relatively recently). And I thought, if I were teaching an introduction to programming class (or intro to Ruby or Java or whatever), the very first topic of discussion and the first assignment would be:

 

Writing tests.

 

I can’t think of any other fundamental change during the life of my career other than the advent of object-oriented programming that has had such a positive impact on my code quality and productivity. Being able to write tests FIRST and then write code that satisfies those tests is a lot like having a simple coloring book that has the picture drawn — you just need to color inside the lines. Sometimes it’s “too much” to think about everything that comprises a programming problem, and I’ve found that I can get traction simply by writing a test and then making it work. I also discover TONS about how I want the code to look, and I find that by writing tests I don’t like the way I thought I was going to write it and now I can fix it. Finally, you end up with a PILE of test code as a happy side-effect which you can run any time and feel confident you haven’t fucked anything up along the way.

 

The net effect of Test Driven Development is:

– better quality code, by far

– faster resolution of problems

– ultimately faster time to completion

 

Let me underline that last point: faster time to completion. Typically when we’re “under the gun,” we think it’ll be faster to dive in and be “quick and efficient” to write something, obviating test code. Although this is true some of the time, I’d argue that it is not true the majority of the time.

 

I hope that my relentless preaching about testing eventually tires you all out enough that you start doing it if you haven’t already. There are very few things in my life that I am zealous about — TDD is one of them.