Why do the Alpha Geeks care about Erlang? The obvious conclusion points to processor speeds remaining static, and multi-core computers becoming mainstream. As of October 31st 2007 it is quite complex to create a well designed desktop application that takes advantage of multi-core processors using Java, C#, Ruby, etc. Alpha Geeks like to have several tools at their disposal. Having several tools available can ease solving a complex problem if the tool is designed with that problem in mind. Therefore, looking to see if Erlang provides a better solution for concurrent programming is an easy choice.
Why do CIOs care about Erlang? CIOs know that computing power is going in the direction of more cores, not faster processors. Knowing that Erlang is a language designed to take advantage of multi-cores is enough to drive interest. Other questions that I would expect from CIOs are: Reliability? Nine nines uptime[1]. Maturity? It's been around for 20 years. Who else is using it? Ericsson, Nortel, T-Mobile. The argument sounds compelling.
Why do I care about Erlang? I quite like the idea of running an entire test suite in parallel. Additionally, Procedural languages were mainstream years ago and several best practices emerged. These days, OO languages are mainstream and more lessons have been leared; however, the masses have never exploited the power of functional languages. I believe that if programmers start writing applications in Erlang to address the concurrency issues the best practices from the functional community will be given more attention. I hope that everyone can benefit from the diversified experience.
[1] The AXD301 has achieved a NINE nines reliability (yes, you read that right, 99.9999999%). Let’s put this in context: 5 nines is reckoned to be good (5.2 minutes of downtime/year). 7 nines almost unachievable ... but we did 9. (http://www.pragmaticprogrammer.com/articles/erlang.html)
Wednesday, October 31, 2007
Saturday, October 27, 2007
Rails: Unit Test without Rails
I've written in the past about How We Test without hitting the database in our unit tests. I recently joined a project where the team decided to unit test without loading the environment at all (Kudos to George Malamidis for pushing the team in that direction).
I like to test classes in isolation (when unit testing) so this was an easy transition for me. It also solved a problem that had been annoying me for a few projects: even when the unit tests are disconnected from the database, running a focused test (in TextMate) still takes several seconds to load the entire Rails environment.
On my last project we looked at a benchmark once and the test ran in .002 seconds, but the real time was 5.002 seconds. We generally put all of our require statements in environment.rb, which is great for maintainability; however, it lead to our environment taking up to 5 seconds to load. You may not care about 5 seconds, but taking a test that runs in .002 seconds and waiting 5.002 seconds several times over the life of a year long project, on a team of 16 developers, adds up to a bit of annoyance and a fair amount of wasted time
While I really liked the idea, I did have one complaint: Without Rails our codebase (and tests) needed to be littered by require statements. This was fairly easily fixed by requiring activesupport and calling a few methods on
At that point we could test all of our POROs very quickly. We ran a few benchmarks and never got a real time of more than .05 when running an individual test class. I also benchmarked changing the unit_test_helper to require environment.rb. When requiring environment.rb it took 10-12 times longer to run a unit test.
We were happy with the results, but without environment.rb ActiveRecord wasn't defined. Since we also wanted to unit test our AR::Base subclasses (where appropriate) we created AR::Base ducks that do nothing when AR::Base methods are called. Essentially they are struct objects that can read and write to their attributes, but also contain any behavior that you define in the subclasses. This code led to a new gem: arbs (ActiveRecord::Base Struct). The current release is the first release of arbs. This release only contains support for the methods that have been necessary for our current project. The README (the index page for arbs.rubyforge.org) contains a list of methods from ActiveRecord::Base that are supported. Patches are welcome.
I think an example is probably the best way to bring it all together. Image a project that has the following migration that creates a phone_numbers table.
The following PhoneNumber class is the object representation of the phone_numbers class.
Testing the PhoneNumber class to_formatted_s and value methods can be done without hitting the database or utilizing any of ActiveRecord's magic.
All of the above code is fairly boilerplate; however, unit_test_helper.rb is where the magic lies.
That's all there is to it. The PhoneNumber tests provide the following output on my box.
I like to test classes in isolation (when unit testing) so this was an easy transition for me. It also solved a problem that had been annoying me for a few projects: even when the unit tests are disconnected from the database, running a focused test (in TextMate) still takes several seconds to load the entire Rails environment.
On my last project we looked at a benchmark once and the test ran in .002 seconds, but the real time was 5.002 seconds. We generally put all of our require statements in environment.rb, which is great for maintainability; however, it lead to our environment taking up to 5 seconds to load. You may not care about 5 seconds, but taking a test that runs in .002 seconds and waiting 5.002 seconds several times over the life of a year long project, on a team of 16 developers, adds up to a bit of annoyance and a fair amount of wasted time
While I really liked the idea, I did have one complaint: Without Rails our codebase (and tests) needed to be littered by require statements. This was fairly easily fixed by requiring activesupport and calling a few methods on
Rails::Initializer
. After requiring activesupport I was able to remove all the require statements, follow standard Rails naming conventions, and get autoloading for free.At that point we could test all of our POROs very quickly. We ran a few benchmarks and never got a real time of more than .05 when running an individual test class. I also benchmarked changing the unit_test_helper to require environment.rb. When requiring environment.rb it took 10-12 times longer to run a unit test.
We were happy with the results, but without environment.rb ActiveRecord wasn't defined. Since we also wanted to unit test our AR::Base subclasses (where appropriate) we created AR::Base ducks that do nothing when AR::Base methods are called. Essentially they are struct objects that can read and write to their attributes, but also contain any behavior that you define in the subclasses. This code led to a new gem: arbs (ActiveRecord::Base Struct). The current release is the first release of arbs. This release only contains support for the methods that have been necessary for our current project. The README (the index page for arbs.rubyforge.org) contains a list of methods from ActiveRecord::Base that are supported. Patches are welcome.
I think an example is probably the best way to bring it all together. Image a project that has the following migration that creates a phone_numbers table.
class ReleaseMigration < ActiveRecord::Migration
def self.up
create_table :phone_numbers do |t|
t.column :value, :string
t.column :country, :string
end
end
def self.down
drop_table :phone_numbers
end
end
The following PhoneNumber class is the object representation of the phone_numbers class.
class PhoneNumber < ActiveRecord::Base
validates_presence_of :value
belongs_to :user
def value=(number)
write_attribute :value, number.gsub(/\D/,"")
end
def to_formatted_s
case country.to_sym
when :us then "(#{value[0,3]}) #{value[3,3]}-#{value[6,4]}"
# other formats
end
end
end
Testing the PhoneNumber class to_formatted_s and value methods can be done without hitting the database or utilizing any of ActiveRecord's magic.
require File.dirname(__FILE__) + '/unit_test_helper'
class PhoneNumberTest < Test::Unit::TestCase
test "to formatted s" do
assert_equal "(212) 555-1212", PhoneNumber.new(:value => "2125551212", :country => "us").to_formatted_s
end
test "strip non numbers" do
assert_equal "2125551212", PhoneNumber.new(:value => "(212) 555-1212").value
end
end
All of the above code is fairly boilerplate; however, unit_test_helper.rb is where the magic lies.
require 'rubygems'
require 'test/unit'
require 'dust'
require 'active_support'
require 'initializer'
require 'arbs'
RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + "/../../")
Rails::Initializer.run(:set_load_path)
Rails::Initializer.run(:set_autoload_paths)
ArbsGenerator.run(RAILS_ROOT + "/db/schema.rb")
That's all there is to it. The PhoneNumber tests provide the following output on my box.
focus:~/work/example/test/unit jay$ time ruby phone_number_test.rbChanging to requiring environment.rb yields the following results.
Loaded suite phone_number_test
Started
..
Finished in 0.000501 seconds.
2 tests, 2 assertions, 0 failures, 0 errors
real 0m0.396s
user 0m0.286s
sys 0m0.106s
focus:~/work/example/test/unit jay$ time ruby phone_number_test.rbThe results are significantly higher, but not 10 or 12 times. This is because the output comes from a newly created Rails application. I expect most Rails applications that load multiple gems and plugins would see results similar to those that my current project produces.
Loaded suite phone_number_test
Started
..
Finished in 0.043915 seconds.
2 tests, 2 assertions, 0 failures, 0 errors
real 0m1.862s
user 0m1.336s
sys 0m0.519s
Tuesday, October 23, 2007
DSL interview
At RubyConf 2006, Zak Tamsen and I were interviewed by Obie Fernandez. In the months leading up to the conference I worked with both Obie and Zak on different projects where a DSL was used by the customer to specify the business rules of an application. Both projects were among the more interesting of my career. The interview discusses how we approached the problem and the successes that followed.
Check out the interview on InfoQ: Jay Fields and Zak Tamsen on Domain Specific Languages
Check out the interview on InfoQ: Jay Fields and Zak Tamsen on Domain Specific Languages
Saturday, October 20, 2007
Ruby: Defining Class Methods
There are several ways to define class methods in Ruby.
This is the version that recent Java/C# converts seem to prefer. I'm not a big fan of this version because it requires me to change all the class method definitions if I change the name of the class.
I prefer this version. The syntax is concise and descriptive. When browsing a file of code, the use of
This is the version I use when I need to make the method protected. For more information on why this is necessary you can check my previous entry: Protected Class Methods
This version is by far the most complicated to write and read. The justification for using this version is that you can create class methods that declaratively define other class methods. This version requires the use of define_method instead of def because variables from the surrounding context are necessary. I tend to only use this version when I'm metaprogrammatically defining other class methods.
It's also possible to define class methods inside an instance_eval sent to a class. For an explaination of why this works check out instance_eval and class_eval method definitions. As the linked entry states, I have run into this by accident, but I don't think I've ever actually used instance_eval to define class methods on purpose.
Are there ways that you define class methods that I've left off. If so, please let me know how and why in the comments (with an explanation inline or a link to a blog post on your site).
class Person
def Person.find(id)
...
end
end
This is the version that recent Java/C# converts seem to prefer. I'm not a big fan of this version because it requires me to change all the class method definitions if I change the name of the class.
class Person
def self.find(id)
...
end
end
I prefer this version. The syntax is concise and descriptive. When browsing a file of code, the use of
self.
makes it very clear that the method is a class method. This is the version I use by default. class Person
class << self
protected
def find(id)
...
end
end
end
This is the version I use when I need to make the method protected. For more information on why this is necessary you can check my previous entry: Protected Class Methods
class Object # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
def meta_def name, &blk
(class << self; self; end).instance_eval { define_method name, &blk }
end
end
class Service
def self.responses(hash)
hash.each do |method_name, result|
meta_def method_name do
result
end
end
end
responses :success => 20, :unreachable => 23
end
Service.success # => 20
Service.unreachable # => 23
This version is by far the most complicated to write and read. The justification for using this version is that you can create class methods that declaratively define other class methods. This version requires the use of define_method instead of def because variables from the surrounding context are necessary. I tend to only use this version when I'm metaprogrammatically defining other class methods.
class Person
instance_eval do
def find(id)
...
end
end
end
It's also possible to define class methods inside an instance_eval sent to a class. For an explaination of why this works check out instance_eval and class_eval method definitions. As the linked entry states, I have run into this by accident, but I don't think I've ever actually used instance_eval to define class methods on purpose.
Are there ways that you define class methods that I've left off. If so, please let me know how and why in the comments (with an explanation inline or a link to a blog post on your site).
Sunday, October 14, 2007
Rails: Rise, Fall, and Potential Rebirth of the Presenter Pattern
The default architecture for Ruby on Rails, Model View Controller, can begin to break down as Controllers become bloated and logic begins to creep into view templates.And on it goes, the description for my RailsConf Europe 2007 talk. Unfortunately, this talk was the worst of my career. Pretty much everything went poorly. No one came in to make sure the microphone was working (it wasn't). They ran out of water bottles. I had a fever (103 degrees Fahrenheit, when checked later that evening). But, worst of all, I did a poor job of getting my message across. This post is an attempt to clarify what wasn't expressed well in Berlin.
The Presenter pattern addresses these problems in concert by creating a class representation of the state of the view...
This post assumes you've read the blog entry: Presenter Pattern
I first applied the presenter pattern to a Rails codebase in June of 2006. I had a complicated view that displayed several models aggregated into a single, readonly report. I was working on the code for a while and couldn't find an easy way to test that the view displayed what I was looking for. All of my models were being created and aggregated in the controller. There wasn't a single uber model that could have handled the aggregation, it simply didn't make sense to model it that way.
After spending a bit of time trying to make it work I decided that I needed a more testable solution. Instead of creating and aggregating all the data in the controller I created a PORO that assumed those duties. The presenter had clear responsibilities: find and manipulate the data so that the view can display it by simply calling @presenter.output. This solution turned out beautifully; it was easy to test and maintain. That project contained one presenter, the one spot where it made sense.
In November of 2006 I joined a new project. The new project was basically a wizard that collected several bits of data. Unfortunately, the views didn't easily map to the domain model. Some views needed to validate portions of a model and other views needed to validate multiple models. We decided to use presenters to aggregate and adapt the models to fit the views. The situation was different this time though; this time the views needed to accept post data. There were several implications that came with this choice. The presenters now needed to handle synchronization with the models instead of simply pulling data from the models. The presenters also took the responsibility of validating where it made sense. This experience led to another blog entry: Another Rails Presenter Example.
Presenters worked well on this project; however, the responsibilities of presenters had grown. At the time I didn't realize it, but they were only able to cope with the additional responsibilities because the application followed such a strict convention: Always post and move forward or backward. Like I previously mentioned, this was an application that was basically a wizard. Every page posted, checked for valid data and moved forward or backward. Because the behavior was so limited we were able to easily metaprogram that behavior into the presenters. As a result, we rarely had to do anything interesting in the presenter other than write the formatting, validation, and synchronization code. Again the pattern worked well, so I decided it was time to put out something describing the pattern. The Presenter Pattern blog entry was a result of the combined successes of applying the pattern.
At this point David and Jamis had added a few presenters to Highrise and Jamis had written several blog entries with a very similar idea. It seemed like a great time to submit the presenter pattern as a talk for RailsConf Europe 2007.
Then in April of 2007 I moved on to another project. This project was a more typical Rails application. It didn't follow the wizard pattern. It's views where both readonly and read/write. It often needed to validate something and do interesting things based on those validations. There was no easy convention for the views to follow. Presenters were being used when I joined the project, but they weren't proving to be a good fit. We struggled to find a canonical example within our codebase. We also struggled to find which responsibilities were a good fit and which weren't.
Then, Yogi Kulkarni joined the project. Yogi pointed out that our presenters were responsible for far too much. Yogi wasn't the first person to say this, but he was the first person to say what objects we were missing: Services (Domain Driven Design). We started adding services to the application and the presenters became slimmer and more easily testable. The suggested implementation from my previous blog entry had failed; however, we were able to remove the service related responsibilities and make use of the other benefits of using presenters. Ultimately, the svelte presenters provided a better solution.
That's where my RailsConf talk really fell down. I wasn't able to express that Presenters weren't a silver bullet, but they did seem to work well in various forms.
Several people came up to me after the presentation and said "I'm using presenters to... do you think that's a good idea?" My answer was yes to each query, and those people had found valid ways to use presenters to make their life easier. The key was figuring out how presenters helped you and limiting their responsibilities to those tasks.
Following my experience on my last project I was hesitant to look for a general solution similar to presenters. It's still a pain to test views and controllers, but adding another layer that also felt painful didn't seem like a good solution. Again, I think presenters have their place, but I wasn't sure that a general solution was available.
Then, at RailsConf Europe, Marcel Molina Jr showed me a version he was working on. He's currently using presenters in a non-intrusive way that allows you to use vanilla Rails by default, and add presenters where necessary. Marcels solution looks promising, but it's not publicly available. That's actually a good thing since he's maturing it a bit before releasing it.
I'm looking forward to Marcel's results, but in the mean time I think everyone can benefit from the experiences of the people who have begun blazing the presenter trail. In the blog entry Presenter Links I provide links to entries by Jamis and Courtney. Those are the more popular links, but several other people have written about their own experiences.
The conclusion I failed to express is this: If you are feeling pain testing views or controllers, you aren't alone. I haven't seen the silver bullet solution, but I have seen several solutions that worked very well for specific systems. I believe the current best solution is to read up on the experiences of others and see if anyone has solved a situation similar to yours; if so, try out their suggested implementation. If you find yourself with a unique problem, look for why the existing solutions worked well for their respective problems. Take what applies to you and form your own solution, then write about your experiences so that other people can benefit from your experience.
Saturday, October 13, 2007
Extending Rails
Rails is the silver bullet. It's not perfect, but it strives to be and does nearly every thing you'll need. Of course, the context is that you are building a web application with a small team of 5 or less and that 2 of you rarely work in the same area at the same time. Oh, and you don't mind a test suite that takes a few minutes to run, but that isn't a big deal because you TDD now and then, but you mostly test after anyway. And, most importantly, you have the authority to say "no" to features that turn out to be a bit too complicated to implement.
Fortunately, a lot of Rails applications are built in environments similar to the one above. Unfortunately, the impact of Rails will be limited as long as it only provides solutions for those environments.
I'm not one for reinventing the wheel, that's not what this post is about. This post is about using Rails in unintended ways and how to adapt the framework to make it more productive in those environments as well.
I like web apps and small teams, but I do have a different view on testing. I like testing, it makes my job easier. I prefer TDD, and I run the tests very, very often. Since my work style utilizes the test suite, I need it to run quickly. My style differs from many Ruby/Rails developers and I think that's okay. The standard Rails testing is significantly better than nothing and I think it's great for everyone who's happy using it. If you aren't happy with it, I might have a few ideas for you. What I find interesting is the violent reactions that appear when anyone suggests a solution that doesn't follow traditional Rails suggestions.
Obie recently quoted Zed.
I'm not sure how the community adopted the attitude. Rails clearly encourages you to extend it to your needs. The entire plugin system was designed to help you extend Rails. In fact, the plugin system has helped evolve Rails in many ways. Sexy Migrations began as a plugin announced on Err the Blog. Simply RESTful led the way for the Rails REST revolution. Despite the success stories of some plugins, many Ruby/Rails developers are very averse to extending Rails in anyway. Personally, I find this attitude disappointing and destructive. The next great feature to Rails core could come from any one. However, the "one true way" attitude may cause an unsure developer to remain quiet about their ideas, thus stifling innovation.
All applications are not created equally. Some are large and complex, others small and simple. Rails can be used to deliver in both environments; however, it's the customizations that can be the difference between delivering on time or far ahead of schedule. Rails is the foundation, but it's your responsibility to build on that foundation in the way that provides the most value. Sometimes that means adding your own patterns to help deliver for your specific domain. That's okay, in fact, sticking to vanilla rails at the price of productivity isn't a decision that I expect any good developer to make. There's a reason that David and Jamis introduced the presenter pattern into Highrise. They are good developers looking for each opportunity to improve their tools. Ultimately, David didn't like how the pattern worked for him; however, Marcel Molina Jr has a new presenter implementation that looks very promising. That version may make Rails core, or not, but that isn't the point. The point is that the Rails core team doesn't stick to vanilla Rails, and (provided you have a need) neither should you.
Fortunately, a lot of Rails applications are built in environments similar to the one above. Unfortunately, the impact of Rails will be limited as long as it only provides solutions for those environments.
I'm not one for reinventing the wheel, that's not what this post is about. This post is about using Rails in unintended ways and how to adapt the framework to make it more productive in those environments as well.
I like web apps and small teams, but I do have a different view on testing. I like testing, it makes my job easier. I prefer TDD, and I run the tests very, very often. Since my work style utilizes the test suite, I need it to run quickly. My style differs from many Ruby/Rails developers and I think that's okay. The standard Rails testing is significantly better than nothing and I think it's great for everyone who's happy using it. If you aren't happy with it, I might have a few ideas for you. What I find interesting is the violent reactions that appear when anyone suggests a solution that doesn't follow traditional Rails suggestions.
Obie recently quoted Zed.
If DHH ain't doing it, you don't fucking do it. (Seems every time some clever fellow gets into trouble it's because of that.) -- Zed ShawObie's post was a funny read, but there is almost always truth in jest. The "one true way" sentiment of the Rails community doesn't make sense to me.
I'm not sure how the community adopted the attitude. Rails clearly encourages you to extend it to your needs. The entire plugin system was designed to help you extend Rails. In fact, the plugin system has helped evolve Rails in many ways. Sexy Migrations began as a plugin announced on Err the Blog. Simply RESTful led the way for the Rails REST revolution. Despite the success stories of some plugins, many Ruby/Rails developers are very averse to extending Rails in anyway. Personally, I find this attitude disappointing and destructive. The next great feature to Rails core could come from any one. However, the "one true way" attitude may cause an unsure developer to remain quiet about their ideas, thus stifling innovation.
All applications are not created equally. Some are large and complex, others small and simple. Rails can be used to deliver in both environments; however, it's the customizations that can be the difference between delivering on time or far ahead of schedule. Rails is the foundation, but it's your responsibility to build on that foundation in the way that provides the most value. Sometimes that means adding your own patterns to help deliver for your specific domain. That's okay, in fact, sticking to vanilla rails at the price of productivity isn't a decision that I expect any good developer to make. There's a reason that David and Jamis introduced the presenter pattern into Highrise. They are good developers looking for each opportunity to improve their tools. Ultimately, David didn't like how the pattern worked for him; however, Marcel Molina Jr has a new presenter implementation that looks very promising. That version may make Rails core, or not, but that isn't the point. The point is that the Rails core team doesn't stick to vanilla Rails, and (provided you have a need) neither should you.
Thursday, October 11, 2007
Ruby: PORO
The term PORO (Plain Old Ruby Object) is being used a bit more often these days. In a comment on my last post someone expressed frustration that I didn't validate the acronym. After a quick Google search I noticed that no one has gone out of their way to point out it's meaning.
PORO isn't a term that was born in the Ruby community. In fact the original POXO was POJO.
PORO isn't a term that was born in the Ruby community. In fact the original POXO was POJO.
The term was coined while Rebecca Parsons, Josh MacKenzie and I were preparing for a talk at a conference in September 2000. In the talk we were pointing out the many benefits of encoding business logic into regular java objects...POROs, like POJOs, are often found in discussions about simplicity and testing.
POJO is an acronym for Plain Old Java Object, and is favoured by advocates of the idea that the simpler the design, the better. --WikipediaThere's plenty of discussion around POJOs on the web, most of which applies to POROs as well.
Sunday, October 07, 2007
Ruby: Convention is Important
Good programmers follow convention. Rails teaches that convention over configuration can result in great productivity gains. The two previous statements can apply to any language, but there are 2 other reasons why convention is even more important in Ruby applications.
Metaprogramming
Metaprogramming isn't exclusive to Rails. I recently joined a project where the class under test needed to be required from within the test. I've been spoiled by Rails, so having to write require statements was annoying to me. To solve the problem, I convinced the team to build their test directory structure as a mirror to the lib directory structure. I also convinced them that using dust to define tests was a good idea. Once we got all the tests using the
Removing require statements is nice, but it's also obviously a small win. However, it doesn't take long for several small metaprogramming wins to greatly increase the effectiveness of a team. A few projects ago, our small wins ended up becoming a domain specific framework built on top of Rails. A consequence of combining all the small wins was that adding to the application was very trivial. That team saw tremendous effectiveness gains with every story that required adding new a new screen.
Finding Behavior
Last week while pairing with Fred George I asked what he thought of adding a not method to improve readability. He liked the readability, but was concerned with being able to find the implementation of the
To find the implementation of
Looking in Connection will not provide the implementation of
At this point, life is easy. I only need to look in object_extensions.rb and then kernel_extensions.rb if necessary.
But, life was only easy because we follow conventions. I can easily see creating a readability.rb file seeming like a good idea. After all, object_extensions.rb doesn't do much in the way of describing intent. I am a big fan of software that focuses on intent, but I actually think it's destructive in this case if it means breaking convention. Of course, if my IDE could easily find method definitions I would favor an intentful filename.
People new to Ruby are generally afraid of Open Classes. Convention can go a long way to mitigating the risks of Open Classes. In January, I listed a few Class Reopening Hints. These days we follow roughly the same conventions and I still find myself spending very little time looking for implementation definitions; thanks mostly to convention.
- Following conventions can reveal opportunities for metaprogramming.
- Conventions make it easier to find where behavior is defined. This reason strongly applies as long as we have lacking IDE support.
has_many
and belongs_to
are perfect examples of something that needs to be done in several locations within a codebase, but can be succinctly done thanks to metaprogramming. Metaprogramming
Metaprogramming isn't exclusive to Rails. I recently joined a project where the class under test needed to be required from within the test. I've been spoiled by Rails, so having to write require statements was annoying to me. To solve the problem, I convinced the team to build their test directory structure as a mirror to the lib directory structure. I also convinced them that using dust to define tests was a good idea. Once we got all the tests using the
unit_test do .. end
syntax it was easy for me to use the binding of that block to get the path to the test. Since our test directory structure mirrored the lib directory, I was able to gsub
the path to the test and require the class under test behind the scenes. Removing require statements is nice, but it's also obviously a small win. However, it doesn't take long for several small metaprogramming wins to greatly increase the effectiveness of a team. A few projects ago, our small wins ended up becoming a domain specific framework built on top of Rails. A consequence of combining all the small wins was that adding to the application was very trivial. That team saw tremendous effectiveness gains with every story that required adding new a new screen.
Finding Behavior
Last week while pairing with Fred George I asked what he thought of adding a not method to improve readability. He liked the readability, but was concerned with being able to find the implementation of the
not
method. I think that's a valid concern, but one that can be mitigated by following good conventions. On our project we have a folder called "core_extensions" which groups files such as string_extension.rb, object_extension.rb, etc. I've found this convention helpful because I can generally find behavior after looking in a few classes. For example, I may stumble upon the following code.payment_connection.establish(:paypal) if payment_connection.not.active?
To find the implementation of
not
I'll look in the connection class first since the connection is the receiver of the not
message.class Connection
def establish(symbol)
...
@active = true
end
def active?
@active
end
end
Looking in Connection will not provide the implementation of
not
, but it does provide other valuable information. Notably, Connection is a PORO; therefore the ancestors of Connection are Object and Kernel.Connection.ancestors # => [Connection, Object, Kernel]
At this point, life is easy. I only need to look in object_extensions.rb and then kernel_extensions.rb if necessary.
But, life was only easy because we follow conventions. I can easily see creating a readability.rb file seeming like a good idea. After all, object_extensions.rb doesn't do much in the way of describing intent. I am a big fan of software that focuses on intent, but I actually think it's destructive in this case if it means breaking convention. Of course, if my IDE could easily find method definitions I would favor an intentful filename.
People new to Ruby are generally afraid of Open Classes. Convention can go a long way to mitigating the risks of Open Classes. In January, I listed a few Class Reopening Hints. These days we follow roughly the same conventions and I still find myself spending very little time looking for implementation definitions; thanks mostly to convention.
Saturday, October 06, 2007
Rails: Maintainable Code
Rails provides three ways to define a before save on an ActiveRecord::Base subclass.
The most important thing about having three choices is selecting one per project. I've been on a project where the decision wasn't formalized and I once found a class that had both version 1 and 3. You can blame that on a bad programmer, but good programmers follow conventions.
Personally, I prefer version 1. I like the fact that the balance check is done in a block of code that is clearly associated with a before save.
I've worked with colleagues who prefer version 2. Their justification is that when they read the class they don't care about how the balance check is done, so they want it hidden away in another method instead of being directly in the block. First of all, I don't think reading a method name that describes how a method works is any better than reading the code itself. Furthermore, if your code isn't readable on it's own, you probably have a bigger problem.
The following example is what I would expect as a rebuttal from fans of version two.
Version 4 does a decent job of renaming the method to the intent instead of what it's doing. In isolation this looks like a decent choice, but as the class grows it becomes a maintenance issue in my experience. The first problem generally occurs when the class becomes long enough that the before_save declaration and the implementation aren't found on the same page. Yes, I can scroll, but I shouldn't need to. And, I can keep the implementation next to the declaration, but then I end up reading that method first. If I'm reading that method when I first open the class, why not just use version 1 anyway.
I expect Version 2 fans will next point out that my example is too trivial to see the benefits. This argument doesn't get very far with me. If the code is doing anything interesting it's probably because it's a business rule. Complex business rules shouldn't be defined in hooks. A hook should be something simple that makes your life easier or the logic should be delegated to a proper object for processing (topic covered by Evans in Domain Driven Design). So imagine that the logic for verifying sufficient funds is more complex, the following example is how it can be handled.
Breaking the logic out into a class is valuable for two reasons: Any complex logic is generally more testable when it lives in a PORO, and moving the logic to a class signals that the code is important and should be treated as such. Whether the code is in another class or not, deleting it should cause a failing test. That's not a good enough reason for leaving the complex logic in the Transfer class. Moving the code to another class will allow the SufficientFundsPolicy tests to break when the business rule is being incorrectly enforced, which should increase maintainability.
Version 3 is my least favorite. Mostly anyone who knows Rails will know that Version 3 is acceptable; however, Version 3 doesn't stand out when skimming a class that has several methods defined. Hook methods are methods with special behavior; however, aside from the name, Version 3 doesn't look special in anyway. A special method masquerading as a common method provides no benefit, but does run the risk of being mistaken for a common method.
Personally, I believe that Rails has the opportunity to be a more declarative framework which would result in more maintainable applications. There are already several class methods that allow for declarative coding: validates_*, before_*, after_*, etc. However, there are other actions that are special and masquerade as common. For example, controller actions are defined as common methods, but could as easily be defined with a class method.
Declarative code can provide both the implementation and the intent. Well written declarative code creates Expressive Software which is inherently more maintainable.
# Version 1
class Transfer < ActiveRecord::Base
before_save do |record|
raise "Insufficient Funds" if record.original_account.balance - record.amount < 0
end
end
# Version 2
class Transfer < ActiveRecord::Base
before_save :raise_insufficient_funds_if_original_account_balance_minus_amount_is_less_than_zero
def raise_insufficient_funds_if_original_account_balance_minus_amount_is_less_than_zero
raise "Insufficient Funds" if original_account.balance - amount < 0
end
end
# Version 3
class Transfer < ActiveRecord::Base
def before_save
raise "Insufficient Funds" if original_account.balance - amount < 0
end
end
The most important thing about having three choices is selecting one per project. I've been on a project where the decision wasn't formalized and I once found a class that had both version 1 and 3. You can blame that on a bad programmer, but good programmers follow conventions.
Personally, I prefer version 1. I like the fact that the balance check is done in a block of code that is clearly associated with a before save.
I've worked with colleagues who prefer version 2. Their justification is that when they read the class they don't care about how the balance check is done, so they want it hidden away in another method instead of being directly in the block. First of all, I don't think reading a method name that describes how a method works is any better than reading the code itself. Furthermore, if your code isn't readable on it's own, you probably have a bigger problem.
The following example is what I would expect as a rebuttal from fans of version two.
# Version 4
class Transfer < ActiveRecord::Base
before_save :check_for_sufficient_funds
def check_for_sufficient_funds
raise "Insufficient Funds" if original_account.balance - amount < 0
end
end
Version 4 does a decent job of renaming the method to the intent instead of what it's doing. In isolation this looks like a decent choice, but as the class grows it becomes a maintenance issue in my experience. The first problem generally occurs when the class becomes long enough that the before_save declaration and the implementation aren't found on the same page. Yes, I can scroll, but I shouldn't need to. And, I can keep the implementation next to the declaration, but then I end up reading that method first. If I'm reading that method when I first open the class, why not just use version 1 anyway.
I expect Version 2 fans will next point out that my example is too trivial to see the benefits. This argument doesn't get very far with me. If the code is doing anything interesting it's probably because it's a business rule. Complex business rules shouldn't be defined in hooks. A hook should be something simple that makes your life easier or the logic should be delegated to a proper object for processing (topic covered by Evans in Domain Driven Design). So imagine that the logic for verifying sufficient funds is more complex, the following example is how it can be handled.
# Version 5
class Transfer < ActiveRecord::Base
before_save do |record|
SufficientFundsPolicy.validate(record)
end
end
Breaking the logic out into a class is valuable for two reasons: Any complex logic is generally more testable when it lives in a PORO, and moving the logic to a class signals that the code is important and should be treated as such. Whether the code is in another class or not, deleting it should cause a failing test. That's not a good enough reason for leaving the complex logic in the Transfer class. Moving the code to another class will allow the SufficientFundsPolicy tests to break when the business rule is being incorrectly enforced, which should increase maintainability.
Version 3 is my least favorite. Mostly anyone who knows Rails will know that Version 3 is acceptable; however, Version 3 doesn't stand out when skimming a class that has several methods defined. Hook methods are methods with special behavior; however, aside from the name, Version 3 doesn't look special in anyway. A special method masquerading as a common method provides no benefit, but does run the risk of being mistaken for a common method.
Personally, I believe that Rails has the opportunity to be a more declarative framework which would result in more maintainable applications. There are already several class methods that allow for declarative coding: validates_*, before_*, after_*, etc. However, there are other actions that are special and masquerade as common. For example, controller actions are defined as common methods, but could as easily be defined with a class method.
# traditional
def new
@menu_item = MenuItem.new
end
# declarative
action :new do
@menu_item = MenuItem.new
end
Declarative code can provide both the implementation and the intent. Well written declarative code creates Expressive Software which is inherently more maintainable.
Monday, October 01, 2007
Is it better than TextMate? (Ruby IDE redux)
A year and a few months ago I wrote what I considered to be the state of Ruby IDE choices. These days I'm still using TextMate to deliver Ruby applications. I think TextMate is a fine text editor, but almost every project team has a few developers who want IDE support at the level that IntelliJ provides to Java. After hearing those same complaints for over a year I'm fairly sure that, at this point, no one wants a more robust IDE than I do.
Unfortunately, there isn't a better option. "NetBeans has great debugging support." "The IntelliJ plug-in provides better searching options." Yes, I've heard many of the great features that the different IDE options provide. The problem is, they missed a few fundamental features: stability and speed.
Around fourty percent of all new projects at ThoughtWorks are Ruby projects. Each project starts with the question: What IDE are we going to use. Not every team is lucky enough to be given a choice concerning hardware selection, so TextMate isn't even an option for some of our projects. As of today, I'm comfortable saying that ThoughtWorks has tried every major Ruby IDE available. Unfortunately, I still haven't heard what I want to hear: [IDE] is better than TextMate.
I understand that the current IDE choices provide some features that TextMate does not, but they do it while other features are lacking, or it's too slow, or it crashes constantly. Not a single colleague I've spoken to has told me that another editor would be a better choice for a ThoughtWorks team. I know that some of my colleagues prefer IntelliJ, but most of those guys (admittedly) prefer it because it's familiar. Even those guys aren't ready to recommend that teams choose IntelliJ over TextMate when delivery is on the line. I'm optimistic about IntelliJ. I enjoyed using IntelliJ when it was the best option available to me. Of course, I think competition will make all the IDEs better, so I'm rooting for all the competitors also.
Specifically, here's what I'm looking for: Crashes no more than once a week. Responsive at all time. Provides all the features of the TextMate Ruby and Rails Bundles. Provides an additional few features that making preferring it over TextMate any easy decision.
Unfortunately, there isn't a better option. "NetBeans has great debugging support." "The IntelliJ plug-in provides better searching options." Yes, I've heard many of the great features that the different IDE options provide. The problem is, they missed a few fundamental features: stability and speed.
Around fourty percent of all new projects at ThoughtWorks are Ruby projects. Each project starts with the question: What IDE are we going to use. Not every team is lucky enough to be given a choice concerning hardware selection, so TextMate isn't even an option for some of our projects. As of today, I'm comfortable saying that ThoughtWorks has tried every major Ruby IDE available. Unfortunately, I still haven't heard what I want to hear: [IDE] is better than TextMate.
I understand that the current IDE choices provide some features that TextMate does not, but they do it while other features are lacking, or it's too slow, or it crashes constantly. Not a single colleague I've spoken to has told me that another editor would be a better choice for a ThoughtWorks team. I know that some of my colleagues prefer IntelliJ, but most of those guys (admittedly) prefer it because it's familiar. Even those guys aren't ready to recommend that teams choose IntelliJ over TextMate when delivery is on the line. I'm optimistic about IntelliJ. I enjoyed using IntelliJ when it was the best option available to me. Of course, I think competition will make all the IDEs better, so I'm rooting for all the competitors also.
Specifically, here's what I'm looking for: Crashes no more than once a week. Responsive at all time. Provides all the features of the TextMate Ruby and Rails Bundles. Provides an additional few features that making preferring it over TextMate any easy decision.