<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Justin Leitgeb &#187; Rails</title>
	<atom:link href="http://justinleitgeb.com/category/rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://justinleitgeb.com</link>
	<description>Perspectives on Ruby and OOP from a developer in NY</description>
	<lastBuildDate>Tue, 27 Sep 2011 15:40:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Easy application-wide SSL configuration in Rails 3.2</title>
		<link>http://justinleitgeb.com/2011/09/easy-application-wide-ssl-configuration-in-rails-3-2/</link>
		<comments>http://justinleitgeb.com/2011/09/easy-application-wide-ssl-configuration-in-rails-3-2/#comments</comments>
		<pubDate>Tue, 27 Sep 2011 15:38:46 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=148</guid>
		<description><![CDATA[Rails 3.1 offers a handy way to secure your entire application behind https: just add config.force_ssl = true in your environment configuration file, and all requests will be directed to https.  Under the covers this handy snippet of code is loading the Rack::SSL middleware.  What happens if you want to exclude certain URL patterns from this restriction? [...]]]></description>
			<content:encoded><![CDATA[<p>Rails 3.1 offers a handy way to secure your entire application behind https: just add config.force_ssl = true in your environment configuration file, and all requests will be directed to https.  Under the covers this handy snippet of code is loading the <a href="https://github.com/josh/rack-ssl" target="_blank">Rack::SSL</a> middleware.  What happens if you want to exclude certain URL patterns from this restriction?  The Rack::SSL middleware accepts options that allow you to do this &#8211; you can pass it a Proc containing a regular expression which will alter the behavior of Rack::SSL on particular requests.</p>
<p>For example, if instead of using config.force_ssl = true, you used the following snippet your code it would not force ssl on pages under the path /public:</p>
<blockquote>
<pre>require "rack/ssl"
config.middleware.insert_before ActionDispatch::Static, Rack::SSL, :exclude =&gt; proc { |env| env['PATH_INFO'].start_with?('/public') }</pre>
</blockquote>
<p>Instead of jumping through these hoops in your configuration file, I thought that Rails should allow you to pass options to Rack::SSL. <a href="https://github.com/rails/rails/pull/3141" target="_blank"> I submitted a pull request</a> with my changes which was promptly accepted by José Valim, so if you&#8217;re either using edge Rails or 3.2 when it comes out you&#8217;ll be able to do the following to configure SSL in your application:</p>
<blockquote>
<pre>config.force_ssl = true
config.ssl_options = { :exclude =&gt; proc { |env| env['PATH_INFO'].start_with?('/public') } }</pre>
</blockquote>
<p>I hope that this change makes configuring your application to be safe a bit easier. Happy SSL&#8217;ing!</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2011/09/easy-application-wide-ssl-configuration-in-rails-3-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing &#8216;propel&#8217;: push to your project the right way</title>
		<link>http://justinleitgeb.com/2011/05/introducing-propel-push-to-your-project-the-right-way/</link>
		<comments>http://justinleitgeb.com/2011/05/introducing-propel-push-to-your-project-the-right-way/#comments</comments>
		<pubDate>Tue, 17 May 2011 16:05:41 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=140</guid>
		<description><![CDATA[At Stack Builders, we&#8217;re big on following best practices in our projects.  We use continuous integration, and pushing to a remote repository generally involves the following steps: Check to see if the continuous integration build is passing Pull any upstream changes Run the local test suite Push to the remote repository if the local tests [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://stackbuilders.com" target="_blank">Stack Builders</a>, we&#8217;re big on following best practices in our projects.  We use continuous integration, and pushing to a remote repository generally involves the following steps:</p>
<ol>
<li>Check to see if the continuous integration build is passing</li>
<li>Pull any upstream changes</li>
<li>Run the local test suite</li>
<li>Push to the remote repository if the local tests are passing</li>
</ol>
<p>Often, we skipped the first step, since it was annoying to check the CI server manually, and running the local test suite is generally a good enough indication that the world is OK before pushing.  However, when the local build takes upwards of 20 minutes you may not want to wait to see a local failure to find out that CI was failing.  Ideally, you want to check if the remote build is failing, and if it is, wait until it passes before pulling and running the build.</p>
<p>I wrote a gem, <a href="http://rubygems.org/gems/propel" target="_blank">propel</a>, that encapsulates this logic into a single command.  It currently works with Jenkins, CI Joe, and Team City, and support for other CI servers is easy to add.  You can have it abort if the CI build is failing, or have it wait for you while someone else fixes the build.</p>
<p>Additionally, it tries to be helpful if you encounter anomalous situations while pushing your changes &#8211; if you ended up with a detached HEAD, it aborts with a helpful message before any harm is done to the repository.</p>
<p>Installation is easy &#8211; just &#8216;gem install propel&#8217;.  You can run it by simply typing &#8216;propel&#8217; inside of your local project repository.  Configuring the url of the CI server can be done via the command line, or it can be saved in a .propel file at your project root.</p>
<p>Propel is still pretty new, but it has been working well for us on a few projects.  Check it out and let us know what you think.  Happy propelling!</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2011/05/introducing-propel-push-to-your-project-the-right-way/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NYC Amazon Web Services Meetup Talk</title>
		<link>http://justinleitgeb.com/2010/11/nyc-amazon-web-services-meetup-talk/</link>
		<comments>http://justinleitgeb.com/2010/11/nyc-amazon-web-services-meetup-talk/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 03:56:04 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Cloud Computing]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=131</guid>
		<description><![CDATA[I just finished giving a talk to the NYC Amazon Web Services meetup.  I enjoyed talking with those attending, and learning from Matt Tavis, an AWS Solutions Architect, who also presented on AWS&#8217; offerings and application scaling on the cloud in general.  My slides from the talk (with just a few additions to the NYC.rb [...]]]></description>
			<content:encoded><![CDATA[<p>I just finished <a href="http://www.meetup.com/AWSnewyork/calendar/14940424/" target="_blank">giving a talk</a> to the <a href="http://www.meetup.com/AWSnewyork" target="_blank">NYC Amazon Web Services meetup</a>.  I enjoyed talking with those attending, and learning from Matt Tavis, an AWS Solutions Architect, who also presented on AWS&#8217; offerings and application scaling on the cloud in general.  My slides from the talk (with just a few additions to the <a href="http://nycruby.org/wiki/" target="_self">NYC.rb</a> talk I gave yesterday evening) are <a href="http://justinleitgeb.com/wp-content/uploads/2010/11/Scalable_web_site_antipatterns_AWS_Meetup.ppt">available for download</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2010/11/nyc-amazon-web-services-meetup-talk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NYC.rb talk: Scalable web site anti-patterns</title>
		<link>http://justinleitgeb.com/2010/11/nyc-rb-talk-scalable-web-site-anti-patterns/</link>
		<comments>http://justinleitgeb.com/2010/11/nyc-rb-talk-scalable-web-site-anti-patterns/#comments</comments>
		<pubDate>Wed, 10 Nov 2010 03:21:10 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=123</guid>
		<description><![CDATA[This evening I gave a brief talk on &#8216;Scalable web site anti-patterns&#8217; to the NYC.rb meetup.  You can download the slides from the discussion.  Tomorrow, I&#8217;ll be giving the full version of this talk on problematic web architectures at the AWS meetup.  I&#8217;ll post the slides from that talk, and I hope to see some [...]]]></description>
			<content:encoded><![CDATA[<p>This evening I gave a brief talk on &#8216;Scalable web site anti-patterns&#8217; to the NYC.rb meetup.  <a title="slides from nyc.rb talk on scalability anti-patterns" href="http://justinleitgeb.com/wp-content/uploads/2010/11/Scalable_web_site_antipatterns_nyc_rb.ppt" target="_blank">You can download the slides from the discussion</a>.  <a href="http://www.meetup.com/AWSnewyork/calendar/14940424/" target="_blank">Tomorrow, I&#8217;ll be giving the full version of this talk on problematic web architectures at the AWS meetup</a>.  I&#8217;ll post the slides from that talk, and I hope to see some Rubyists in the crowd as well if you can make it!</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2010/11/nyc-rb-talk-scalable-web-site-anti-patterns/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 3.0 upgrade: Watch out for differences in mass assignment checks on has_many :through associations</title>
		<link>http://justinleitgeb.com/2010/09/rails-3-0-upgrade-watch-out-for-differences-in-mass-assignment-checks-on-has_many-through-associations/</link>
		<comments>http://justinleitgeb.com/2010/09/rails-3-0-upgrade-watch-out-for-differences-in-mass-assignment-checks-on-has_many-through-associations/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 04:43:23 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=115</guid>
		<description><![CDATA[Please see comment below &#8211; looks like this has been taken care of in Rails 3.0.1. While porting a small Rails application, Listable, to Rails 3.0, I found an interesting difference in the behavior of the two frameworks: attr_accessible on a model used for a join relation between two entities works when using &#8216;&#60;&#60;&#8217; to [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Please see comment below &#8211; looks like this has been taken care of in Rails 3.0.1.</strong></p>
<p>While porting a small Rails application, Listable, to Rails 3.0, I found an interesting difference in the behavior of the two frameworks: attr_accessible on a model used for a join relation between two entities works when using &#8216;&lt;&lt;&#8217; to add records in Rails 3.0, while in Rails prior to 3.0 it is silently ignored.   It took me a moment to figure out what was happening, so I figured I&#8217;d leave a note here in case it helps someone else in porting their app to the newest Rails framework.</p>
<p>Taking a step back, here is a simple case that demonstrates the difference between Rails version 2 and Rails version 3 with respect to &lt;&lt; (aliased as &#8216;concat&#8217; and &#8216;push&#8217; in the ActiveRecord framework) when adding to a collection established using has_many :through.  Given three models: User, List, and UserListLink (which has foreign keys for user and list):</p>
<pre>class User &lt; ActiveRecord::Base</pre>
<pre style="padding-left: 30px;">has_many :user_list_links, :dependent =&gt; :destroy</pre>
<pre style="padding-left: 30px;">has_many :lists, :through =&gt; :user_list_links</pre>
<pre>end</pre>
<pre>class List &lt; ActiveRecord::Base</pre>
<pre style="padding-left: 30px;">has_many :user_list_links, :dependent =&gt; :destroy</pre>
<pre style="padding-left: 30px;">has_many :users, :through =&gt; :user_list_links</pre>
<pre>end</pre>
<pre>class UserListLink &lt; ActiveRecord::Base</pre>
<pre style="padding-left: 30px;">belongs_to :user</pre>
<pre style="padding-left: 30px;">belongs_to :list</pre>
<pre>end</pre>
<p>In both Rails 2 and 3, the following works:</p>
<pre>u = User.create</pre>
<pre>l = List.create</pre>
<pre>u.lists &lt;&lt; l</pre>
<p>However, if you add attr_accessible [] to UserListLink, under Rails 3 the UserListLink that is automatically generated will have nil/null values for both list_id and user_id. You&#8217;ll see the expected message in the Rails log, &#8220;WARNING: Can&#8217;t mass-assign protected attributes: list_id, user_id&#8221;, which indicates that Rails uses mass assignment to create this intermediary object. In my case, removing the attr_accessible line in my code allowed &#8216;&lt;&lt;&#8217; to work as it did before upgrading to Rails 3.</p>
<p>I&#8217;m not sure how I feel about the change in behavior in ActiveRecord 3 where mass assignment protection is triggered by the &#8216;concat&#8217; method on a has_many :through relationship.  I suppose whether or not this is &#8216;correct&#8217; behavior depends on whether there is a chance for user-generated data to be passed into the attribute hash used to construct the intermediary object.  If so, this is probably a nice fix in ActiveRecord 3.    Otherwise, though, it may help to bypass the mass assignment check when saving intermediary objects using concat.</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2010/09/rails-3-0-upgrade-watch-out-for-differences-in-mass-assignment-checks-on-has_many-through-associations/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>In the Kitchen: What&#8217;s behind Clean.ly</title>
		<link>http://justinleitgeb.com/2009/12/in-the-kitchen-whats-behind-clean-ly/</link>
		<comments>http://justinleitgeb.com/2009/12/in-the-kitchen-whats-behind-clean-ly/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 12:13:40 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=103</guid>
		<description><![CDATA[The App that I submitted for the NYC BigApps contest has been getting some attention after it was mentioned in Wired and I wanted to write about the technology that I used to create it.  The core of the application is built using Ruby on Rails, and it talks to a MySQL database using ActiveRecord. [...]]]></description>
			<content:encoded><![CDATA[<p>The App that I submitted for <a href="http://www.nycbigapps.com/" target="_blank">the NYC BigApps contest</a> has been getting some attention after <a href="http://www.wired.com/epicenter/2009/12/new-york-citys-best-apps/" target="_blank">it was mentioned in Wired</a> and I wanted to write about the technology that I used to create it.  The core of the application is built using Ruby on Rails, and it talks to a MySQL database using ActiveRecord.  More interestingly, though, I added some other technologies to make pages load fast and to help scale the searching engine beyond what MySQL is able to achieve.  For this, I leveraged <a href="http://www.sphinxsearch.com/" target="_blank">Sphinx search</a> as well as <a href="http://varnish.projects.linpro.no/" target="_blank">varnish page caching</a>.</p>
<p>First, my goal in creating <a href="http://clean.ly" target="_blank">Clean.ly</a> was to add a layer of information on top of the NYC restaurant data to make them more interesting and useful.  Geocoding the restaurant addresses was a first step in this process, which was easily accomplished using the Google API.  Next, I grabbed some other information about the restaurants, including type of food, from other freely available sources on the web.</p>
<p>For these data mining tasks, I needed to serialize a bunch of operations to make sure I didn&#8217;t go over API quotas.  I also wanted to create a system that could accept data from different inputs without much trouble later.  To meet these needs, I used a Kestrel queue to serialize HTTP retrievals from various providers.</p>
<p>Once I had the necessary data in place, Sphinx was an obvious choice to bring these data in front of the user on demand.</p>
<p>For those of you who have used the fulltext searching engine in Sphinx, it&#8217;s easy to envision how restaurant searching based on name or &#8220;tag&#8221; (such as type of food) would work.  A lesser known fact about Sphinx is that in the newest releases, simple geodistance calculations are supported.  The only real trick in implementing this part of the Clean.ly was that the latitude and longitude obtained from Google had to be converted to radians before piping them to the Sphinx indexer.  After that, I had near-instant results with distance calculations from an input address, making it possible for users to search for restaurants close to where they want to eat.</p>
<p>Once I had geodist calculations in Sphinx working, I wanted to make sure that pages loaded quickly.  Since Clean.ly doesn&#8217;t really have user-modifiable content, I immediately thought of page caching.  In other work that I&#8217;ve done scaling high-performance web sites, I had implemented Varnish, a reverse page caching daemon, and had great success.  It&#8217;s an extremely elegant and easy-to-use program which I&#8217;d highly recommend checking out for anyone interested in scaling high volume web sites.</p>
<p>Implementing Varnish for Clean.ly turned out to be a fairly straight-forward task. Clean.ly only has one server, a small instance on EC2 that I also use to host a variety of other small Rails projects.  Varnish proxies port 80 on this instance to another port where Apache is listening, and it short-circuits and returns results for pages stored in the page cache.</p>
<p>In another post, I&#8217;d like to go into more detail on using Varnish with Rails applications.  For now, though, I hope that you enjoy using <a href="http://clean.ly" target="_blank">Clean.ly</a>.  Be sure to check it out, as well as <a href="http://www.nycbigapps.com/application-gallery" target="_blank">the other great submissions</a> to the NYC BigApps contest.</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2009/12/in-the-kitchen-whats-behind-clean-ly/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Rails tip: keep rake tasks short</title>
		<link>http://justinleitgeb.com/2009/09/rails-tip-keep-rake-tasks-short/</link>
		<comments>http://justinleitgeb.com/2009/09/rails-tip-keep-rake-tasks-short/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 12:00:49 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[rake]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=51</guid>
		<description><![CDATA[Writing short Rake tasks that operate on objects in your codebase rather than defining long task bodies with supporting procedural methods often requires a shift in thinking about your Rake tasks and how it relates to the objects in your codebase.  The effort is worthwhile, however, as you add new classes and more precisely define the interfaces of existing classes in your system in order to achieve a more maintainable system.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rake.rubyforge.org/" target="_blank">Rake (Ruby Make)</a> is often used in Rails projects for tasks that don&#8217;t need to be invoked through a web interface.  Examples of when it may come in handy include running data import tasks manually by administrators or automating tasks through cron.  Since it is so easy to start adding piles of code to a rake task to get a particular chore accomplished, two things often happen which decrease the quality of a project&#8217;s code: 1) tests are left by the wayside and 2) opportunities to expand the flexibility of classes and the project code base itself are lost as code is added to the body of the rake task.</p>
<p>In other words, software engineering best-practices often go out the window as Rake tasks are built, leading to missed opportunities for software reusability and increased maintenance costs.  In my experience, it&#8217;s only a bit more effort to turn the effort of writing a one-off Rake task into an opportunity to expand on the reusable components already in your system.</p>
<p>When I&#8217;ve coded maintenance scripts in Rake, two of the signs that a task needs refactoring are length of the task itself and the number methods that have to be defined in the namespace to support the method.  A task, just like any other method, should do just one thing.  If the Rake task is so long that it scrolls off the screen, opportunities for error are high and the next person working on the code is much more likely to start from scratch rather than sort things out in the method body.</p>
<p>The same applies to Rake tasks that require the presence of lots of other methods defined loosely inside of the namespace.  Defining methods in the Rake namespace for munging data or doing other task setup usually means that these methods aren&#8217;t formally tested anywhere.  In many cases, it also indicates that opportunities to hide complexity by using an Object-Oriented interface are being lost.</p>
<p>I&#8217;ve found that Rake tasks often descend into a mass of procedural code to manage data.  Part of the strength of Ruby is the set of tools it provides for defining objects that we can use to hide complexity, leading to more maintainable code.  It&#8217;s a shame to not use these tools when it only takes a short amount of time to think about how your task could be decomposed into a set of methods to be invoked on new or existing objects.</p>
<p>It takes some practice to think about writing good object-oriented code in short Rake tasks.  One of the hurdles is thinking of your task in terms of the existing objects in your codebase.  These may be existing models, in which case you have a pre-existing place to put code that would be more <a href="http://en.wikipedia.org/wiki/Cohesion_(computer_science)" target="_blank">cohesive</a> than just including it in the namespace of your Rakefile.  In other cases, you may have to define new classes (often under the &#8220;lib&#8221; folder of your project) to best encapsulate the data that you have to act upon.</p>
<p>Writing short Rake tasks that operate on objects in your codebase rather than defining long task bodies with supporting procedural methods often requires a shift in thinking about your Rake tasks and how it relates to the objects in your codebase.  The effort is worthwhile, however, as you add new classes and more precisely define the interfaces of existing classes in your system in order to achieve a more maintainable system.</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2009/09/rails-tip-keep-rake-tasks-short/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Improve Rails code by fixing abusive or underused subclasses</title>
		<link>http://justinleitgeb.com/2009/08/improve-rails-code-by-fixing-abusive-or-underused-subclasses/</link>
		<comments>http://justinleitgeb.com/2009/08/improve-rails-code-by-fixing-abusive-or-underused-subclasses/#comments</comments>
		<pubDate>Sun, 23 Aug 2009 10:58:38 +0000</pubDate>
		<dc:creator>Justin Leitgeb</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://justinleitgeb.com/?p=21</guid>
		<description><![CDATA[Code quality in Rails projects can often be improved by identifying and fixing cases where inheritance is poorly implemented.  These cases can be divided broadly into those where subclasess are "abusive" and those where subclasses are underused.  I'll clarify what I mean by both of these cases and give tips on what can be done to improve code maintainability and extensibility by cleaning up poor inheritance relationships.]]></description>
			<content:encoded><![CDATA[<p>Code quality in Rails projects can often be improved by identifying and fixing cases where inheritance is poorly implemented.  These cases can be divided broadly into two groups: those where subclasses are &#8220;abusive&#8221; and those where subclasses are underused.  I&#8217;ll clarify what I mean by both of these cases and give tips on what can be done to improve code maintainability and extensibility by cleaning up poor inheritance relationships.  These tips are based on thoughts about writing good object oriented code from prominent figures in the software engineering community.  I&#8217;ll reference some of their ideas as they can be applied to straightening out object hierarchies in Ruby projects.</p>
<p>It may seem to be hard to articulate beyond an intuitive impression that subclasses are stepping beyond their bounds in particular cases.  In my own work, I&#8217;ve found it helpful to think through <a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle" target="_blank">Barbara Liskov&#8217;s notion of substitutability</a> of subclasses in creating a clean inheritance hierarchy in Rails projects.  Essentially, Liskov substitution says that we should be able to replace a parent class with any subclass without changes in the interface or the exceptions that are raised.  If this rule is being violated, it&#8217;s a sign that the renegade classes may need to be reigned so they adhere to the contract established by the parent, or put into a different pattern if they&#8217;re really just bursting out at the seams.  There are many more implications of this rule expressed succinctly on the page linked above, so it&#8217;s worth a read as you think through this issue in your own project.  Once this rule is thought through, it often exposes numerous cases where an inheritance relationship can be improved or refactored into a different form.</p>
<p>The <a href="http://en.wikipedia.org/wiki/Design_Patterns_(book)">Gang of Four</a> describes how inheritance can easily be overused.  I&#8217;ve frequently seen this in Rails projects.  Specifically, you should watch out for cases where subclasses become entangled with the parent classes through modification of instance variables or private methods.  The GoF book notes that we should tend to favor composition of simple objects to create a software ecosystem instead of relying on inheritance hierarchies. Generally the problem noted in the GoF book is that inheritance is essentially at odds with encapsulation.  In Ruby, as with other dynamic languages, this problem isn&#8217;t easy to resolve, though <a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/11458">some thought has been given to the matter at the level of language implementation</a>.  The GoF book reminds us that delegation is always an alternative to inheritance in more complex cases.</p>
<p>Thoughts on inheritance from GoF as well as the principle of Liskov substitution are extremely useful in identifying cases where inheritance is poorly implemented through subclasses that are doing too much (essentially stepping out of line from their parents).  I&#8217;m sure that most Rails programmers reading this post will be able to think of a case that could be improved by considering these ideas.</p>
<p>Since abusive subclasses can take many forms, it is difficult to provide a path to clean code that works universally in all Rails projects.  An approach that works well in many cases, though, is to find behavior that can be extracted in the overloaded subclasses to a pattern such as delegation.  This gives the classes room to be more substantially different without having to worry about straying too far from the requirements established by the parent object.  If you&#8217;re new at Rails it may be helpful to remember that you&#8217;re not locked into expanding the functionality of your project by creating increasingly complex models.  In fact it&#8217;s often easier to build small classes for different functionality and project subcomponents.  They can stay in the &#8220;lib&#8221; folder of your project.  This also makes tests easier to maintain when all of these minor classes have their own spec files.</p>
<p>On the other side of the spectrum&#8211;from classes that abuse inheritance by the mechanisms above&#8211;are classes that don&#8217;t do enough.  These were called &#8220;lazy classes&#8221; at least as early as Martin Fowler&#8217;s book, &#8220;<a href="http://martinfowler.com/books.html#refactoring" target="_blank">Refactoring: improving the design of existing code</a>.&#8221;  Fowler defines lazy classes as classes that don&#8217;t pull their own weight.  These classes can be found independent of their inheritance relationship, but Fowler talks about the special common case of subclasses that don&#8217;t do much.  Since this problem is succinctly expressed by Fowler I&#8217;ll quote the short section from the Refactoring book in its entirety before discussing how Rails projects often fall into this trap:</p>
<blockquote><p>Each class you create costs money to maintain and understand.  A class that isn&#8217;t doing enough to pay for itself should be eliminated.  Often this might be a class that used to pay its way but has been downsized with refactoring.  Or it might be a class that was added because of changes that were planned but not made.  Either way, you let the class die with dignity (Fowler 83).</p></blockquote>
<p>I&#8217;ve lost count of the number of cases that I&#8217;ve seen where subclasses dangle uselessly off the end of an inheritance chain, and I inevitably think of applying Fowler&#8217;s object-oriented &#8220;tough love.&#8221;  Remember that with ActiveRecord::Base STI it&#8217;s easy to remove the type column after pulling their behavior up into the parent classes.  After that, they&#8217;re a prime candidate for the refactoring that Fowler anarchistically labels &#8220;collapse hierarchy.&#8221;</p>
<p>One Ruby-specific way to see from outside of a class that a class may be underused is if you find code that acts based on a class type with the method &#8220;is_a?&#8221;.  For example, if you have a STI relation where Car has subclasses RedCar and BlueCar, you might have in your code somecar.is_a?(RedCar).  Note that this isn&#8217;t really considered good Ruby code anyway, since most programmers prefer duck-typing to asking a class what it is.  That is, asking what it respond(s)_to? is considered better as it&#8217;s more versatile if the object given is of a different type. In this case, it isn&#8217;t likely that we really need colored cars to be their own object types&#8230; giving them an attribute &#8220;color&#8221; should suffice without the confusing presence of classes that don&#8217;t do much.</p>
<p>As you can see, there is an abundance of material from software engineering that can be applied to Ruby and Rails projects to clean up inheritance hierarchies.  In my own experience applying refactorings to inheritance hierarchies along the lines described above can really help Rails projects grow and accommodate new features.  There are certainly some cases where inheritance is the correct choice.  It is clear, though, that Rails and Ruby projects benefit greatly in terms of maintainability and extensibility when programmers consider whether inheritance is abused or subclasses are underused.</p>
]]></content:encoded>
			<wfw:commentRss>http://justinleitgeb.com/2009/08/improve-rails-code-by-fixing-abusive-or-underused-subclasses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

