Monday, November 30, 2009

Great memory profiler

Just wanted to link up this post that's helping me solve a tough memory problem with a really lightweight bit of code.  If you've got some memory issues with any bit of code in your rails app, go check this out and make use of it:

http://scottstuff.net/blog/2006/08/17/memory-leak-profiling-with-rails

It's over three years old, but still works with the current version of rails quite well.

Thursday, November 19, 2009

How to be Humble

I installed the new Rails Best Practices gem today, and I have to admit it kind of kicked me in the fork. In a good way.

Sometimes it's good to be reminded of just how many things you've done wrong, as it can really motivate you to dig in and get some of that stuff fixed. As for me and my statup's codebase? I have 291 violations of the best practices that need to be addressed. Oh well, at least I've moved from blissful ignorance to gut-wrenching enlightenment.

Want to get schooled on your own code base? Need a good swift kick yourself? Follow these steps:

1) Install ruby_best_practices
sudo gem install rails_best_practices --source http://gemcutter.org

2) cd to your root directory of your rails project

3) execute this line:
rails_best_practices . --debug
(I used the debug flag because it tells you what file was just examined, that way if there's an explosive error and the process bombs, you'll know which file to investigate).

Happy self-humbling!

Wednesday, November 18, 2009

What to do with expensive and schema-less data in Rails

OK, the title for this post definitely needs work, but this is an important topic.

Scenario: I have some invoice that needs to be generated once a month for each customer in my database. Each invoice has a table on it that specifies the amount the customer is being charged for each category of services. incomplete ruby-code follows:

class Invoice
  def data_row(category)
    [category.name,
     category.description,
     self.expenses_for(category),
     self.expense_ratio(category)]
  end

  def invoice_data_table
    Category.all.map{|c| data_row(c)}
  end
end

for the sake of argument, assume that "expenses_for" and "expense_ratio" are both defined and are expensive calculations. Also, the categories list changes from month to month. Now, how do I store this data so that I don't need to re-calculate it if I need to re-print this invoice later?

1) static columns
This is probably the worst one, and the one I see most commonly in large corporate applications. Basically you write 50 new columns in your invoices table, each one looking like this: category_1_expense_ratio, category_1_expense, category_2_expense_ratio, etc, etc.

Retrieval is efficient, but every time the category list changes you have to add new columns to your database, and the code for populating these fields is probably ugly and repetitive.

2) child records in join table
Better, but still somewhat expensive in relation to it's purpose. We add an invoice_category_expenses table, and it's modeled as "category_id, invoice_id, expense_ratio, expenses".

This works, and is more robust in the face of change, but in order to reprint the invoice that means you have to fetch 20 other records besides just the invoice. They're not huge, so it's not a real performance problem, but it does feel wrong to me to grace this flat data table with all the trimmings of a full model class.

3) serialized data-structure

This is what I ended up going with, and I'm maddeningly happy with my decision. For readonly structured primitive data that just needs to be stored for possible re-examination (ie, no other behavior necessary) I don't think you can beat it.

Rather than stuffing it in another table, or making your invoices table a schema nightmare, you just add one more column: category_expenses_data. It's a text column with a large size limitation. Now in your invoice model you write the following:

class Invoice
  serialize :category_expenses_data,Array
end

This specifies to rails that this column is going to be a serialized Array (basically a string representation of an array that can easily be re-instantiated). Now when creating the invoice, you generate the expensive data table, and store it by saying "invoice.category_expenses_data = invoice.invoice_data_table". The expensive calculations are done once and stored in the database. When you need to reprint the invoice, you can just ask for "invoice.category_expenses_data" and it will give you back your array (deserialized from the database) ready to be used to generate your PDF again or whatever.

Tuesday, November 17, 2009

RubyMine 2.0

I've been using TextMate for Rails development ever since I started programming on a Mac. I've got to say, though, that after trying out the new RubyMine IDE, I'm considering upgrading. Don't get me wrong, I LOVE TextMate. It's been nothing but good to me, and I still plan on using it for Scala and other editing tasks. That being said, my first IDE when I was just starting to program was Eclipse, and in that regard RubyMine feels like I'm coming home.

Cool things I've liked so far:

1) GUI test running reminiscent of JUnit. Yeah, I know, it's just eye candy, but what can I say? I like it, and my preference should count for something if I'm the one doing the development.

2) GUI Git integration. Point and click, baby!

3) intellisense/code completion/inspection/warnings. These can be annoying if things are too bad. Your code looks like it's been torn apart by a highschool honors english teacher, past a certain point. But overall I really prefer having the analysis and information built visually into my editor (another eclipse throwback).

Somethings that make me want to stick with TextMate:

1) Speed Compared to RubyMine, TextMate is blazing fast. It loads quickly, searches quickly, and I definately feel more nimble.

2) Simplicity. TextMate is an editor, and a good one. Your screen isn't cluttered with a hundred helpful windows.

I guess I've got some thinking to do before I lay down any money, but I'll post what I decide when I get around to it.