Tuesday, November 21, 2006

The Danger Of Best Practices

Every person has at some point experienced the phenomenon known as writers block. For programmers, this manifests as a block against writing code or getting into the flow of programming. Like all creative enterprises, this block often stems from a fear of creating. Our creative cogs get stopped up because we fear that what we create might not be good enough, correct, or otherwise valid.

In programming, this fear often manifests as "am I doing this the right way?" I sometimes have trouble getting into the flow of coding because I'm constantly thinking "Maybe I'm doing this wrong. Maybe there's a better way. Maybe maybe maybe." This fear can be debilitating and is a would be creator's biggest enemy. Unfortunately this problem can be compounded in the coding world by the existence of Best Practices.

Best Practices, which describe the "best" way to accomplish a given coding task, are usually useful and helpful to a programmer. The problem occurs when one begins to fear ever violating some ethereal Best Practice. It isn't a specific best practice which causes the problem, but the existence of Best Practices as a whole. Letting the fear of not doing something the "best" way restrict your creative flow is utterly pointless and self-defeating. The quest for best practices should be a relaxed one of new learning, not a frantic one of self-validation.

The fix to the problem is the same as it is in all creative ventures - damn the torpedos and full speed ahead. Ignore other concerns, other ways of doing things, other "best practices" and just do it. Write that program. Code that library. Going back and changing things later is easy. If you never write anything, you'll never have anything to change. Apply Best Practices after the fact. Refactor. Revise. If you happen to see a better way of doing something in the future, modify your source, run your tests, and check in a new revision. Never let "what could be" get in the way of "what can be right now."

Thursday, November 16, 2006

The Rails Path: Tracks (Part 1)

The amazing Jamis Buck has teamed up with Michael Koziarski to offer a new coding series called The Rails Way. Some of the comments in their first installment mention the fact that some people new to rails may not have a very strong grounding in Ruby. In order to help those people understand the Rails Way wisdom, I will be explaining parts of their post in the context of a basic beginner to Ruby/Rails.

Acts_as_name_part_finder
(original code here)
The acts_acts_as_name_part_finder macro adds a method called find_by_namepart that allows for one to search by an entire name or a piece of a name. It would be used like this:

You would then be able to do things like:

The point the Rails Way is making is that it is unnecessary to declare an entirely new acts_as_* macro just for the sake of adding a single function. An additional point is that this function is only ever used in one model. The lesson here is don't abstract code into a new macro/file if its only being used in one place. Wait until you see yourself copying and pasting the code into other places before you start abstracting it.


Modules
If you're learning Ruby/Rails, you really should know what modules are and how to use them. For those that need a quick refresher, a module is just a container around some pieces of code. Usually you define methods in a module and then use the "include" keyword to add those methods/code into your class. For example:

If find_by_namepart had been used in multiple places, it would have made sense to define the function inside a module and then use "include" in the places where you need that functionality.


Acts_as_todo_container
(original code here)
The first point the Rails Way makes is that a lot of the original code for the acts_as_todo_container was solely for the purpose of having the database automatically include associated 'has_many' models in a single db query. This allows for:

With this code, if I made a call to Context.find_not_done_todos I would get back a list of Todo's as well as their associated Projects. A great majority of the actual acts_as_todo_container deals with adding in this :find_todos_include functionality. By using the :include option in the has_many association, all of this code can be eliminated and the resulting code simplified to the point where a separate acts_as_todo_container is not necessary. Instead, the Todo handling code can be placed into a basic module and be "included" as normal.

Other Simplifications
Besides removing :find_todos_include, the Rails Way introduced a number of syntactical simplifications:

1. Replacing code like:

The ||= operator checks to see if @not_done_todos is nil. If it is, it sets it to find_not_done_todos. Otherwise it just evaluates (and returns) @not_done_todos. This is exactly what the previous code did in a more succinct form.

2. Replacing code like:

Instead of making a call to Todo.find and trying to manually simulate the has_many relationship through use of statements like "#{self.class.base_class.name.singularize.downcase}_id", they use the has_many association defined in the model to make the simple "self.todos.find" call. This is again a result of moving the :include parameter to the has_many association and allowing the built in rails macros to handle all the complex stuff.

That's everything for this post. If anyone has any questions (no matter how basic) please feel free to ask. To make things clear, I am not trying to steal the Rails Ways' thunder. My goal is to elaborate on their points so that people who don't have much of a Ruby/Rails background can still understand what's going on.