This one is pretty obvious, but I’m going to say it anyway: Do not, I repeat, do not, rely on model validations to protect your database integrity!

My example for this is a relatively minor one, but it could easily have been much worse:

During the early development of an app I worked on, we installed acts_as_taggable_on_steroids to handle tagging. The tag model, as defined in tag.rb has this line:

validates_uniqueness_of :name

Makes sense, right? Because to have duplicates of any given tag would negate the effectiveness of tagging on a whole. Well, depending on how you had things set up anyway.

Enter problem:

One feature of the app was the ability to do a bulk import of a CSV file, including tags. Any of you who have tried to do bulk imports in Rails will probably know that the first thing you do after writing a working prototype, is to factor out any and all usage of ActiveRecord, because, as beautiful and powerful as ActiveRecord is, it’s dog slow when you’re trying to import and save a few thousand records.

For those of you who haven’t realized where this is going, circumventing ActiveRecord means that all of those neat little model validations never fire. Which means duplicate tag records just kept on piling up, until we finally noticed it and I had to waste time writing a migration to consolidate the tags and their associations.

What’s the solution?

Database constraints!

Are you using validates_uniqueness_of? Add a unique index to the table!**

* No, it’s not my first mistake, but the first in what I’m sure will be many posts featuring stupid mistakes I’ve made that you should learn from.
** This message brought to you by the DBA in me. Rails is fantastic, but I miss me some SQL.

none

The principle of fat models and skinny controllers is one that I first learned when I was initiated into the Rails community about a year and a half ago. Every single one of my fellow developers repeated it, almost like a mantra. The only problem was that no one seemed to be able to articulate the why of it. Don’t get me wrong, I think they knew; I just think that they had lived with it so long that the reasons had become an afterthought.

Being the curious sort, I needed to know the why of it. Not understanding the reasons behind the thing made it difficult for me to adopt it. I would fill the controller and view with logic, telling myself the whole time that once I had it working I could clean it up and move it into the model. I’m sure a lot of you are shaking your heads as you read this, because you know what I’m going to say next. That ever elusive “clean up” session never happened. The obvious result being that my code was functional, but ugly. I was fast up front, but when it came time to make changes, things would slow down quite a bit. Especially if I wasn’t the developer assigned to make the change.

There are a lot of good articles out there about maintainability and the like. Ultimately, though, it’s about a lot more than that. Skinny controllers and fat models, as a principle, is the glue that holds pretty much all of the good coding practices together.

  • TDD: Controllers are a pain in the ass to test. Ideally, all you want to have to test in controllers is that the right template is being rendered, the right action is being taken. The minute you have to start testing assignation of values, etc… That’s the minute you stop wanting to test at all.
  • DRY: It’s a lot easier to spot duplicate code if it’s all in the same place, and with fat models that’s much more likely to be the case. Also, if a function you need is sitting at the bottom of some controller, it starts to get a lot easier to just copy and paste it, rather than trying to share it.
  • Maintainability: The previous 2 points kind of play into this one. If you have good test coverage, and don’t have to worry so much about changes having unforeseen (and untraceable) effects in other parts of your app, you’ll be a lot less hesitant about refactoring your code. If your code is DRY, you won’t have to worry so much that the change you make here, might not show up there.
  • Readability: Let’s face it, the code that’s easiest to read, isn’t DRY. It’s linear, it’s all in one place, it doesn’t make function calls that you have to hunt down (”Is that function in the helper? No, I think it’s in a lib file. No, wait, maybe it’s in this included module…”). The problem is, that this code also isn’t maintainable at all. With the kind of setup I just described, one little text change is likely to require a dozen different files to be altered. So, short of that kind of readability, you want to have everything be easily locatable. Sure, an IDE can help with that, but for those of us using TextMate and vim, we have to resort to keeping things as concise as possible. And DRY does help with that. As does keeping as much of the logic in the model (i.e. in one place) as possible.
  • Design: Skinny controllers and fat models… You know what’s left out of that equation? The views. One of the nice side effects of keeping as much logic as possible in the model is that it also stays out of the view. Once you start filling the controller with unnecessary code, it’s really easy to start doing a bunch of if and case statements in the view. (”Oh, and we need this record, too, but only in this one little spot that may not even be rendered… I’ll just put the Class.find here at the top of the partial.” And so it goes.) The more you can keep code out of your view, the easier it will be for your designer to go in and integrate his or her newly chopped comp.

All of it is made easier by sticking to the skinny controller/fat model ideal. And, conversely, all of it is a lot easier to allow to fall by the wayside if you don’t.

Of course, I realize I’m not really saying anything new here, or maybe I’m just not saying anything that most rails developers don’t already know. But sometimes it helps to say it out loud, even if you’re repeating yourself.

none

I’ve noticed that my Windows XP image in VMWare occasionally drops its shared connection. I’ll be plugging away, happily checking cross-browser compatibility (okay, that’s a lie, I’m miserable when I check cross-browser compatibility, which only makes it worse when it stops working) when all of a sudden, nothing is sudden anymore.

Pages will either not load at all or load so slowly that I’d almost prefer to get a “Page cannot be displayed” error. Usually this happens for a while before it occurs to me that the connection has dropped. Then I have to go find this post, which helpfully provides the terminal command that will restart the connection:

sudo  "/Library/Application Support/VMware Fusion/boot.sh" --restart

All of a sudden, the connection is whip-quick (well, you know, as whip-quick as IE gets, anyway). Problem solved.

none

Categories

Links

my tweets

Powered by Twitter Tools

archives

tag cloud

Most commented