Active Record migration dependencies 2

Posted by Paul Pagel Sat, 14 Jun 2008 02:38:00 GMT

We had a new developer join our project recently, and he needed his computer to be setup with the project. “Here is the svn repository, when you check it out, run these rake tasks.” It unfortunately, is never that easy. This project setup revealed something about Active Record and migrations that I didn’t know about.

When I create a migration, I will often do data manipulation on the database, or pre-populate some fields with data needed for a lookup table. Lets look at a sample migration from a trivia game.

class CreateQuestions < ActiveRecord::Migration

  def self.up

    create_table :questions do |t|
      t.column :text, :string
      t.column :answer, :string
      t.timestamps
    end

    Question.populate
  end

  def self.down
    drop_table :questions
  end
end

I want to add some sample questions, so that even if you don’t have your own questions, you will still be able to play the game. I added the method to the populate model, because I use it elsewhere in the code, and I try to keep it DRY. The populate method on the question model looks like this:


class Question < ActiveRecord::Base
  belongs_to :game
  has_many :answers

  def self.populate
    Questions.create(:name => "What is your favorite color?", :answer => "I don't know")
    Questions.create(:name => "Who was the first President", :answer => "George Washington")
    Questions.create(:name => "Who was born Samuel Clemens?", :answer => "Mark Twain")
  end

end

So, later on, I decided to add a degree of difficulty to the questions, so the players can get more points for answering harder questions. Here is what the migration looked like.

class CreateQuestions < ActiveRecord::Migration

  def self.up
    add_column :questions, :rank, :integer
    Question.destroy_all #In case there are any old ones
    Question.populate
  end

  def self.down
    remove_column :questions, :rank
  end
end

Of which I had to change the populate method on the question class to:

class Question < ActiveRecord::Base
  belongs_to :game
  has_many :answers

  def self.populate
    Questions.create(:name => "What is your favorite color?", :answer => "I don't know", :rank => 1)
    Questions.create(:name => "Who was the first President", :answer => "George Washington", :rank => 3)
    Questions.create(:name => "Who was born Samuel Clemens?", :answer => "Mark Twain", :rank => 8)
  end

end

Then I ran my migrations, and continued development. Then when developer number 2 came across and checked out the project and ran the migrations, he got the error.

undefined method rank= for class Question (…or something very similar)

The problem is the old migration is dependent on the new model. All models in rails are just a mirror of the database, so the new model has a forward definition of the data. The code in the model knows about the rank field, but the schema of the database hasn’t caught up to create that portion of the mirror yet. This creates a little bit of a catch 22. The rails wiki (http://wiki.rubyonrails.org/rails/pages/UsingMigrations) about migrations tells you to redefine the class to stop name conflicts. This would require me to make my migrations model agnostic, inserting straight to the database. As a spoiled brat when it comes to databases and rails, I refuse to let go of my Active Record sugary syntax. Another solution I thought of is to just make the last change to question do the populate, and remove it from the previous versions. This will become a maintenance nightmare.

I came to the realization that I want to make a distinction between form and content when it comes to migrations. Form in this case is schema form, the changes to the database which reflect the data which the Active Records can potential hold. Content is the specific data which is in the database. This distinction allows for me to use the power of my model classes in my data migrations, which is the place it is useful. It maintains backwards compatibility, because before I go touching the data, I have to make sure my schema is right.

What does this look like in Rails? I am not sure yet. Possibly db/migrations/schema and db/migrations/data. Possible saving the data migrations in each migration as a block and executing those at the end, only when you have the schema is correct. I am going to try it out!

Code Less: A Language Keystroke Expirement 3

Posted by Paul Pagel Sun, 08 Jun 2008 18:06:00 GMT

When I first started writing code in ruby, it was a breath of fresh air after writing C# code for a year. Ruby had a thesis, a clear purpose, rather than a hodgepodge of features strung together. It was a language obviously written by someone who cared about what the code looked like. So I jumped into it and loved writing ruby code (still do!). Recently I had to write a project in Java using IntelliJ, and the powerful IDE was also a breath of fresh air after using text editors to write ruby code. The IDE helps me in the same way ruby helped me. I write less code that does the same thing, without loosing expressiveness or transparency of intent. Less code in this case meaning less keystrokes.

So, I am going to do a little experiment using two editors and languages: ruby with textmate and java with IntelliJ. I want to see how many lines of code I have to write. The application I am going to start is a simple baseball at bat scorer. First lets see the ruby version.



We have about 27 lines of code written, and other than the describe method, which I have a macro for, I typed them all by hand. Lets look at the java code. This is just the JUnit test I wrote, there is no production code yet.



It is about 16 lines of code, which I wrote all of but the import statement. By doing a few alt-enters on the squiggly lines, I can get a stub of a class looking like this.



That is 13 more lines of code, without really typing, just hitting enter a few times. Now, lets start to make the method pass. I am going to write the algorithm without worrying about all the type definition java wants. Here is what it looks like.



So the code written is around 4 lines of code. Lets use the IntelliJ autocomplete features to help us make a passing test, which looks like.



So roughly, the ruby version was 23 lines of written code and the java version was about 20 lines of written code. There is an expense to doing all of the alt-enters to auto-generate the method and variable stubs, but IntelliJ is pretty smart about what it generates. Also, I understand a single test doesn’t tell the whole story, but it is a good indication. I found as I wrote more tests for this application, a smaller amount of keystrokes was needed for the java version, and the same amount was needed for ruby. This is due to the refactoring tools, and intellisense. As applications get larger, I find the IntelliJ refactorings become more useful. Inversely, ruby refactorings become more painful, as they are mostly done by hand.

So, in the end the constraints on a static language allows the IDE to make the refactoring tools better. Specifically, when writing java code, I can lean on the IDE to generate all the uninteresting stubs for me. All I do is fill in the algorithms: the fun part. When I start to see places where my code can be cleaned up a bit, I can lean on the IDE again to do those refactorings for me once I recognize the need for them. Removing and optimizing the code is something which is easily deducible in static languages, as it is mostly pattern matching, with no monkey patches, meta-programming, and evals to worry about. This is a limitation which frustrates me as a developer who wants to have a large set of tools in my bag, but is helpful when it comes to developing a powerful IDE.

The number of lines of code I need to type isn’t the reason I choose a language over another. In fact, it would be pretty low on the list of deciding factors. However, it is interesting to see what each language and its sets of tools do best. Hopefully the ruby community can take some notes from them. I would rather solve the other end of the equation, get a powerful ruby IDE. I know Eclipse and Net Beans have some preliminary refactoring tools, but they are still aways from being as seamless as their java counterparts.

Wake up and code! 1

Posted by Paul Pagel Fri, 09 May 2008 00:34:00 GMT

The other day, I was with my team at an interview for an internship. After we had asked the candidate some questions, he started to reciprocate, asking each one of us a little about our development past. Every one of the developers stories went something like, I was at the wrong job, and had to get out. The candidate listened carefully to each story, sat for a minute, then asked the obvious perfect question, “What makes the right job?”

I heard responses like “Waking up in the morning and being excited to work, rather than counting the days until the weekend.” The reason this struck me as interesting was only when I reflected back to why I loved computers and programming in the beginning. It was all about the problem. I went to college, so I could join the CIA or some think tank which wrote software which monitored and defeated the enemies entire world. About every developer I went to college with got into computer science with some similar grandiose notion. Most of them were gamers that wanted to work on the next big game. Yet today, I know no developer who works on games, and I don’t work for a think tank. I know lots of developers who are more than qualified to do it, but choose not to. So, how does this relate to the right job question?

The answers about the right job question had nothing to do with the problem set being solved either. Nothing to do with WHAT applications were being written, but the culture and with whom they are being written. I think this is because each problem set worth application development proposes unique and interesting problems for a developer to solve. I have never been on a project which didn’t constantly keep me on my toes as far as problems to be solved. Even if the business domain is a bit bland, the development domain isn’t. I have seen developers to do lists get bigger and bigger from day one on a project, and never shrink. This has nothing to do with laziness, quite the opposite, it has to do with an insatiable drive to make things better than they are.

As a developer, my problem set isn’t the business/science problems I am solving, even though that might be interesting in itself. My problem set is development itself, the different patterns/practices I use to solve the world’s [software] problems. It is like many art forms where the beauty and creativity exists in the process of creation rather than the results. I am sure you could have asked Pablo Picasso to paint something he didn’t have any interest in, and he would have been passionate about it and done a wonderful job. I suspect it is because the importance is in the painting process and the choices you make during each step. How he chooses to depict the subject is more interesting more than the nature of the subject itself. I find the same true in development. The thought that goes into the different development choices I make on a daily basis is the part that drives me to love development.

Having the right results is only part of the equation (an essential part though). When I started my path as a developer craftsman, I learned the WHAT in applications is not as important as all the other variables. I suspect some of the other members on my team would agree, based on their answers to the right job question. Being part of a company that values the software for its own ends and spends the time and attention to do it right is a privilege to me. To me, that is the definition of the right job. I enjoy knowing my software will be used. Everything I write is valuable to the company for its longevity and success. It takes people who are similar in values for it to work, but it makes the work fun. It makes me wake up before my alarm, rather than snoozing.

Older posts: 1 2 3 4