Posts dealing with coding

A bad way to start the day

Committed revision 666.

Strong is a weakness

Just ran across Is Weak Typing Strong Enough?, one of Steve Yegge's rants. It might be old news, but what a great comparison. First, he provides an argument for either side, one I totally agree with.

Above all, we need stability. We have enormous scale and massive business complexity. To create order out of inevitable chaos, we need rigorous modeling for both our code and our data. If we don't get the model and architecture mostly correct in the beginning, it will hurt us later, so we'd better invest a lot of effort in up-front design. We need hardened interfaces — which means static typing by definition, or users won't be able to see how to use the interfaces. We need to maximize performance, and this requires static types and meticulous data models. Our most important business advantages are the stability, reliability, predictability and performance of our systems and interfaces. Viva SOAP (or CORBA), UML and rigorous ERDs, DTDs or schemas for all XML, and {C++|Java|C#|OCaml|Haskell|Ada}.

Above all, we need flexibility. Our business requirements are constantly changing in unpredictable ways, and rigid data models rarely anticipate these changes adequately. Small teams need to be able to deliver quickly on their own goals, yet simultaneously keep up with rapid changes in the rest of the business. Hence we should use flexible, expressive languages and data models, even if it increases the cost of achieving the performance we need. We can achieve sufficient reliability through a combination of rigorous unit testing and agile development practices. Our most important business advantage is our ability to deliver on new initiatives quickly. Viva XML/RPC and HTTP, mandatory agile programming, loose name/value pair modeling for both XML and relational data, and {Python|Ruby|Lisp|Smalltalk|Erlang}

But then he follows that up with

The first camp only resorts to dynamic typing when they're backed into a corner.

The second camp only resorts to performance optimizations and interface/schema lockdowns when backed into a corner.

Now, it seems so obvious which is the more logical approach.

  • With strong, you're forced to create a weaker system when (not if) unexpected requirements come up. The problem is, those weak spots are guaranteed spread through the system, causing a clash of philosphies all over your code.
  • With weak, you simply beef up error handling a bit or choose another technology when necessary. Because the entire system was built with a weak mentality, you haven't lost any additional stability.

So next time this argument comes up, just figure out what you're really building and choose the right one. I bet 99 out of 100 times you'll go weak.

  • July 1, 2006
  • Dealing with coding

Endurance test

I challenge you to watch the entire demo of Reverse engineering a Seam application from a database. Bonus points for not laughing and/or crying.

I seriously can't tell if it's a screen capture or if it was animated by hand. The pacing reminds me far too much of actually working in Eclipse.

Via In Relation To...

A stack of books I no longer need

So long!

Here's the stack of books I sold to Powells today. Man, that felt good.

I traded for The Work of Charles and Ray Eames, By Design and Scandanavian Design to fuel my recent interest in modern furniture and architecture.

Adding that to the recently purchased The Elements of Typographic Style and The Elements of Style (1959 printing!) gives me quite a pile of reading to do.

Careful what you name things

On Friday I decided to create a new class called Failure. A Failure is stored anytime an unexpected exception is raised in our application. There are various subclasses to indicate many specific types of failures such as FrontendFailure and BackendFailure, each of which has different behavior. For example, FrontendFailure might send e-mail after_save. Other failure classes represent expected but unhandlable errors like "your template code is wrong". In those cases we can e-mail the user. We could even look through the failures to see if the user's problem has been fixed yet.

The failures table. (data is a serialized OpenStruct so subclasses can store anything they like)

create_table :failures do |t|
  t.column :type, :string
  t.column :exception_class, :string
  t.column :exception_message, :string
  t.column :backtrace, :text
  t.column :message, :string
  t.column :data, :text
  t.column :status, :integer
  t.column :created_at, :datetime
  t.column :updated_at, :datetime
end

Sample usage.

begin
  do_something_big_and_complicated
rescue ComplicatedError => e
  ComplicatedFailure.occurred e, "it happened again"
end

Ok, so this works great. No problems. The problem was more subtle. Really subtle.

As I worked on this bit of code and started using it to debug various features, I started getting depressed. Not slit-your-wrists depressed but definitely bummed. Having just read Malcolm Gladwell's excellent Blink I can only say it was from constantly reading, typing, and thinking about "failure" over the course of a few hours.

Hacking Dispatcher without DI

For reasons I won't get into, it became necessary to make Rails go faster. But only for a couple url's, and without need for the majority of the framework. For a while, we ran these scripts with raw FCGI and a simplified Dispatcher that let you work with the request and response directly, bypassing the main Rails workflow.

But now we have the wonderful RailsFCGIHandler, with graceful signal handling, app reloading and more. I wanted our custom dispatcher to benefit from that too.

So, we want to use the RailsFCGIHandler but handle requests with our stripped down Dispatcher before Rails gets to it. My first thought was to override FCGIHandler#process_request

class CustomRailsFCGIHandler
  def process_request(cgi)
    MyDispatcher.dispatch(cgi)
    # Dispatcher.dispatch(cgi)
  rescue Object => e
    raise if SignalException === e
    dispatcher_error(e)
  end
end

CustomRailsFCGIHandler.process!

That's ok, but we've duplicated some tricky exception handling logic. Even worse, it's treating Ruby like a static language. We can do much better. First, there's no need to subclass RailsFCGIHandler. Simply opening the class and redefining process_request would do the same thing.

But, here's the cool part. We don't have to modify RailsFCGIHandler at all! The only functionality we need to change is in Dispatcher, so let's just modify it.

class Dispatcher
  class <<self
    alias :old_dispatch :dispatch
  end
  def self.dispatch(cgi)
    SimpleDispatcher.dispatch(cgi,false) do |request, response|
      case request.path
        when "/one" then Tracker::Controller.process(request, response, :one)
        when "/two" then Tracker::Controller.process(request, response, :two)
        else old_dispatch(cgi)
      end
    end
  end
end

RailsFCGIHandler.process!

That's it. Now our two high-availability url's are handled while still supporting Rails' normal workflow.

Here's SimpleDispatcher for reference. All it does is instantiate Rails' request and response objects, yield them, then take care of session propagation and write a response.

class SimpleDispatcher
  def self.dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
    request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
    begin
      yield request, response
    rescue
      response.body << $!.to_s
    ensure
      request.session.update if request.session && !request.session.kind_of?(Hash)
      response.out unless response.body.empty?
    end
  end
end

Back to Dependency Injection. In a static language, hardcoding Dispatcher.dispatch(cgi) would have been a sin. It forever ties us to a specific implementation. Design patterns help - template method or factory method come to mind. Or using a DI container with setter injection. But each of these techniques causes excess overhead in both usage and design.

The Ruby way gives us a simple (almost naïve) implementation that's as flexible as the most complicated architectural patterns.

This point is worth repeating. Without any coding or design overhead, the result is highly flexible. Sure you can accomplish the same result in Java, et al but how many more lines of code+config+tests did it take?

It's just not that complicated

When I worked in Java, dependency injection was a really cool, life saving technique. When I first came to Ruby, I immediately wondered about libraries for DI, Mock Objects and other such things.

It quickly became obvious that none of these things are all that necessary. Jim Weirich sums it all up perfectly in Dependency Injection: Vitally Important or Totally Irrelevant?

Why PostgreSQL

Or: How I Learned To Stop Worrying And Love The Database.

Timothy Johnson asks in the last post

Can you tell us why the switch from mySQL to postgre? I am not a db-guy (a ui designer) but I would like to hear from a switcher about the differences between the 2. ... Is postgre part of the logical progression? I have made all the same tool changes you have besides this one

I'm not really a "db-guy" either but this is why I switched:

  1. One of my projects needs a really good db with stored procedures. A friend who knows much more than I recommends Postgres.
  2. I dread installing, setting up, and learning yet another application,
  3. But, I download, install from source and have Postgres running in no time at all. Everything just works.
  4. I started looking at the documentation and ended up reading almost the entire thing. I can't explain it but the docs have a great quality. Simple, to the point, but with enough examples to get you going. (ok, I only read sections I-III, and skimmed the rest, but still...)
  5. I tell my wife "this is like, the Ruby of databases!"
  6. I start getting giddy when I find PL/Ruby and the possibility of writing stored procedures in Ruby

Like Ruby, it's the little things that impressed me. Example: having used MySQL for years and not known about the "references" syntax, I'm a little embarassed. But that's the point, Postgres got me to a better place in less time and hassle. Knowing that it's top-notch behind the scenes is icing on the cake, but right now it's more about that good feeling.

That said, I wouldn't really consider Postgres part of the logical progression. MySQL and others are equally good. There's tradeoffs, and I'm sure real db-guys could give you the lowdown.

Btw, if anyone has experience with PL/Ruby or knows where to find more information besides this page, please let me know!

New friends

Little did I know when I jumped headfirst into Ruby that I'd also be switching out just about every tool in the toolbox. It was a huge undertaking all at once, but one I've thoroughly enjoyed. Last week I made another switch, from MySQL to PostgreSQL. This pretty much rounds out the whole spectrum.

I can honestly say I'm happier and more productive now. The time and energy spent learning all this stuff was well worth it. And honestly, it wasn't that bad.