Larry Price

And The Endless Cup Of Coffee

On the Futility of Man and Trying to Divide a Sinatra App Into Separate Controllers

| Comments

Oh, Sinatra. You’re oh-so-very dear to me. You made it so easy for me to write my first web apps. All I had to do was write a couple routes and throw together a few HTML-like files and I had a web app. I used pattern matching to reduce the web-facing code for Capital Punishment from ~500 lines of code to <100 lines of code. You are perfect for writing small-time web applications.

But what about large web applications? What about a web app that has normal users and admin users, makes lots of database reads and writes (my previous apps only did reads from a user-facing perspective), and has to be able to show the history of everything, forever, to the authorized users who request it?

You see, Sinatra is kind of an MVC framework, but not exactly. In Sinatra, you have Views (your HTML inter-mixed with Ruby code in your desired DSL) and you have Controllers (each of your routes). When a database is involved, you can use something like ActiveRecord or Mongoid or DataMapper and you have yourself Models.

So every route is kind of a Controller. Every. Route. In Capital Punishment, there were once 8 routes (there are now 7). In the project I’ve been working on recently, there are currently 56 routes. 56 routes in the language described above means I kind of have 56 controllers.

That’s been pretty overwhelming, especially since the traditional way of creating routes in Sinatra is to shove them all in the same file. There are a few ways I could think of to address this. The way we chose six months ago (for better or worse) was found on StackOverflow, and involves creating a bunch of different files where you shove all related routes. So you get this situation:

app.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class App < Sinatra::Base
end

require_relative 'controllers/helpers'

Dir.glob("#{File.dirname(__FILE__)}/controllers/*.rb").each do |file|
  require file.chomp(File.extname(file))
end

class App
  get '/' do
    erb :home
  end
end
controllers/reports_controller.rb
1
2
3
4
5
6
class App
  get '/reports/user_bills' do
    erb :user_bills_report
  end
  ...
end

And so on and so forth. This works fine for a while, but we’ve ended up with 13 “controller” files, many of which are not trivial. This also makes the App class quite large since its controllers handle most of the logic for the app. This also doesn’t enforce any kind of URL-naming logic, so if a developer is working hard (s)he may create both /reports/user_bills and user_info_reports without realizing the inconsistency (s)he just injected into the system.

In hindsight, this method is not perfect. I think that the Rails method of individual controllers is significantly better for large apps. Some people have been using other methods for trying to make Sinatra more MVC, such as sinatra-mvc. To be frank, sinatra-mvc pretty much does the same thing we’ve done, but with more structure.

I think what I’ve learned is that you should use a tool for its intended purpose. Sinatra was written to quickly create web apps in Ruby with minimal effort. Once you have more than 10-15 routes, you should reconsider whether your app can still be called “minimal effort.” Sinatra may fly you to the moon, but you’re unlikely to see what spring is like on Jupiter or Mars.

Beware of Group Projects

| Comments

Relying on other people is hard. I’ve always found it difficult to understand that other people aren’t me. Don’t get me wrong, working with others can be really rewarding. Maybe “Beware of Group Projects” is not the best title. More like “Be Wary that Working with Others is Not the Same as Working with Yourself.” But that’s a pretty long title, and reading (like working with others) is hard.

I’ve been spending a lot of my spare time collaborating on a project with a small group of other developers. I normally do this kind of thing on my own. I started thinking about the differences in working by myself and collaborating with other devs. Then I decided that it would look good in a list format comparing each circumstance from both sides. I was wrong, but couldn’t think of a better way to present it.

Let’s Start a New Project!

As an Individual: This project is going to help me! I can use this new technology and I’ll learn so much!
As a Group: This project is going to help our customer! We can use this new technology and everyone will learn so much!

Let’s Work!

As an Individual: I’ve got 5 minutes, that’s enough time to make those adjustments I’ve been thinking about…
As a Group: We’ve got 5 minutes, but once we find a conference room, set up the projector, and update our branch I’ll have to go pick up my wife. Pass.

Let’s Not Work

As an Individual: I could work, or I could just play Prison Architect all weekend. …I’ll have the happiest inmates this side of Alcatraz by Monday morning!
As a Group: We’ve set aside these times to meet, you should come help! There might be pizza if you stay long enough.

Knowledge

As an Individual: Now I know how to do X.
As a Group: Now I know how to do X. Now you know how to do X, and you know how to do X, and you know how to do X! I’m the Oprah of Knowing X!

Coding Standards

As an Individual: Whoops, I mixed camelCase and under_scores when naming my classes. Oh well.
As a Group: For the love of Linux Torvalds, how do you not remember to prefix your public member variables with ‘pub_’ and postfix your private member variables with ‘_private’?

Testing

As an Individual: Pfft.
As a Group: TEST ALL THE THINGS! It’s the best way we can guarantee that our code changes don’t break existing functionality.

I’m Bored

As an Individual: Forget the months of work spent on X, I think I’ll work on Y now.
As a Group: If we finish, we’ll have made something useful. Someone needs us this! You’ll be happy you kept working on it in a few weeks.

We’re Done!

As an Individual: I made an app that let’s you draw circles. A job well done, if I do say so myself. I believe I’ll have a beer.
As a Group: We invented the warp drive, but it hits a theoretical limit at approximately 9.5 warp. Beer all around! We start work on version 2.0 next week!

The point is that working with others is not bad. In fact, working with others helps give me a sense of responsibility in what I’m working on, and motivates me to continue even when I’m in a lull. I’ve thrown out so many individual side-projects because I just wasn’t motivated, or was no longer convinced of its usefulness. It’s also (theoretically) easier to build bigger projects with groups because there are more arms to swing more hammers.

“Beware of Group Projects” if you don’t have time, or if you can’t compromise, or if you don’t care. Otherwise, just be wary that working with others is not the same as working with yourself.

The Trouble With Time Zones (Aka Learn From My Mistakes Part 1)

| Comments

As a user, my data’s LastModifiedDate should not be updated when I Export it, and it should be in UTC.

That’s the gist of the story I was tasked with a few weeks ago. Seemed easy enough: just set the “LastModifiedDate” field of each XML node to the LastModifiedDate pulled from the database converted to UTC. I can do the development and write up some Cucumber tests in an hour, two hours tops. Find a few small caveats along the way, get it out of development and through code review by the next morning. Push it to the mainline and watch the build go green. All done, dust off my hands and move on to something else.

When has anything ever been that simple? Certainly not in the fantastical world of software development! About ten minutes after the build server confirmed a successful build of my code on the tip of our main branch, a face popped up over the cube wall. “Hey, why’d you break the build?” My teammate was having trouble running my LastModifiedDate tests. All of his time comparisons were off by an hour. My computer (and the build server) were in one time zone; his was in another. I immediately realized the exact lines of the code that weren’t dealing with time zones. We agreed to let the code remain on the build server instead of backing it out since the build server was green, and I created/tested/pushed a couple of patches to fix the problem. Green build on the build server. Green build amongst all my time-disabled peers. The next morning I had a panic attack in the shower thinking about how some of my test data could be affected by the switch to UTC. I rushed into work early and put in another patch, this one slightly changing the format of some of my test data. After doing this, I realized that what I had done was completely unnecessary and decided I should probably get my blood pressure checked.

Then: silence. I was satisfied I’d seen the end of my time zone issues which I’d spent nearly as much time patching as I had developing the initial solution. Two weeks pass. Monday morning there’s an email from another country in my inbox, “This test was written that only works in American time zones! Who is fixing this?” After quite a few emails and chats I found that their main branch had merged in a version of our main branch between my original solution and my patch. The developer agreed to be patient until his team could start using the newer version of our branch. Four hours later I get another email from developers on another continent. I sent them the patches I made previously compressed into one to keep them working.

Was this a small mistake? On a project with a small, local team the answer is definitely yes. This project in particular involves a large number of developers who don’t all test in the same time zone and who work on a number of different branches that feed into each other in weekly chunks. Despite that, I think this error could have gone greatly unnoticed had I simply backed out the original changes and pushed the patches and original solution together. My confidence (hubris?) really bit me on this one. Initially only a single developer seemed to be affected by my oversight; fate selected a build between my original solution and my patches to push to the other branches to make sure more people noticed my mistake.

In hindsight, The Right Thing to Do was to assume fault and back out immediately. One developer having build issues is still one more than should have been affected. Here’s hoping this bit o' hindsight today leads to better foresight tomorrow.

Effective C++

| Comments

The Gist

Effective C++ is a list of ways to write not-your-average-bear C++ code. The author, Scott Meyers, outlines 8 specific topics for improving code, and a few more miscellaneous tips.

My Opinion

Lots of good can come from reading this book. I borrowed it from a more-experienced co-worker and noticed many of the interesting coding standards this co-worker used came directly from this book. And I agree with it. I’ve been actively trying to follow the lessons learned in this book from the moment I picked it up.

I learned C++ the hard way: I was thrown into an internship where I didn’t really have enough skills to contribute to the project, and my “boss” didn’t really have anywhere to put me. So I was handed a book, pointed to this wonderous website, and I wrote some little helper apps for the project. I wasn’t taught anything about form or any of that formal business. Then I took a C++ class in college, and never bothered to learn any of the coding standards because I had enough previous knowledge to get by my own way (and appear to be really good while doing it).

So this book showed me a lot of the why certain things in C++ are the way they are. It explained to me that a copy constructor is called every time you pass an object directly through a function, and how assignment operators are used whenever an equals sign appears. It told me why my destructors need to be virtual. It explained a lot about smart_ptr and auto_ptr that I never thought to think about.

Admittedly, there are parts of the book that are hard to follow. I consider Chapter 7 (Templates and Generic Programming) and Chapter 8 (Customizing new and delete) to be extremely technical chapters not meant for the faint of heart, and the lessons learned in these chapters are not necessarily useful in day-to-day programming. Chapter 9 is simply called Miscellany, and it delivers no new information for improving one’s C++ skills.

Who Would Like This

C++ Programmers should have this book (at least the first 6 chapters) crammed down their throats and into their squishy pink brains. After learning all the “basic” concepts of C++, the lessons this book teaches in design and the nature of C++ should be taken into consideration.

Joel on Software

| Comments

We’re programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We’re not excited by incremental renovation: tinkering, improving, planting flower beds.

– Joel Spolsky, “Things you Should Never Do, Part I”

The Gist

Joel On Software is a collection of blog posts by the great Joel Spolsky. He has risen to Internet Fame after his experience working for Microsoft and eventually starting his own company. The “chapters” (blog posts) provide insight into picking a language for your codebase, recruiting engineers, managing programmers, fixing bugs, paper prototyping, and how Microsoft works.

My Opinion

Joel Spolsky is a god sent down from Mount Olympus to calmly explain to us why we are sometimes terrible people and then goes on to tell us it’s okay and we should learn from our past. I loved this book, especially since I read it at the same time as some really terrible books (namely The Inmates are Running the Asylum and Enterprise Games; I do not recommend these books).

Spolsky talks a lot about specs in the first part of the book, and at first I thought that he was stating too much of the obvious; but then why don’t we do specs in this obvious way? Instead, we resign ourselves to write a tiny portion of the spec, start programming, and then implicitly change the spec while only haphazardly updating our documentation. I’ve been on projects before where we would have greatly benefitted from having a solid spec; we knew exactly what needed to be done, because we were rewriting a successful product the company had released several years ago. With an ever-changing spec, we programmed ourselves into a hole, and struggled for at least half a year to claw our way back out. I have to wonder if more pre-planning would have saved us from ourselves.

Spolsky’s advice on hiring people is invaluable (The Guerrilla Guide to Interviewing). In fact, I wish that I had read some of these blog posts while I was interviewing. Spolsky says that recruiters should ask “impossible questions” and not worry about what the answers given are, just that the recruit comes up with something. He says to stop asking trivia questions. He talks about relying on all interviewers equally: if any two interviewers say “No” to a candidate, the candidate is toast. He talks about asking candidates about projects and looking for passion, which is almost always the sign of a good programmer.

Spolsky talks about the commodity market of software/hardware. To sum it up, the supply of one drives the demand of the other. This section made me think about the current PC market: hardware is cheap and software is cheap. Not only is software cheap, but it’s often free. Prices for hardware haven’t been going down at nearly the rate it used to, but that seems natural as the price approaches the cost of labor and parts. Most of the hardware innovation right now seems to be aimed at the tiny computers in our pockets (or on our face, soon enough). Google’s software makes money by displaying ads using its search engine, so Google has entered the market of making software that is compatible with all kinds of different hardware. Google has played the commodities game like a champ, getting hardware running their software into hundreds of millions of pockets.

Some of the weaker parts of the book are when Spolsky talks about .NET. I’m not going to go into detail, but when he wrote these posts, .NET was just entering the market. Spolsky starts by bashing .NET for making all the old Windows API code unusable, but in later blog posts falls hard for .NET and starts thinking about ways to rewrite his entire life in .NET.

Who Would Like This

I believe that programmers are the main audience for this book, and I am a programmer who loved reading it. Spolsky does not talk down to the reader, nor does he dumb down the nitty-gritty technical blog posts.

Programmers who intend to become managers may get added benefit from this book, as Spolsky discusses some interesting recruiting techniques and ways to deal with programmers. My company uses some of Spolsky’s advice when hiring engineers (quite a bit of it, thinking back to my interview), and we’ve been hiring only the best and brightest cowboys in the Midwest for years.