<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-25066620</id><updated>2008-07-23T12:17:36.600-05:00</updated><title type="text">Ruby, Rails, Merb blog: Snakes, Gems &amp;amp; Coffee</title><link rel="alternate" type="text/html" href="http://snakesgemscoffee.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default?start-index=26&amp;max-results=25" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/posts/default" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>97</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/SnakesGemsCoffee" type="application/atom+xml" /><feedburner:emailServiceId>1073261</feedburner:emailServiceId><feedburner:feedburnerHostname>http://www.feedburner.com</feedburner:feedburnerHostname><entry><id>tag:blogger.com,1999:blog-25066620.post-3875087204352500306</id><published>2008-07-22T18:51:00.005-05:00</published><updated>2008-07-22T18:58:14.395-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">LA Times Travel uses Twitter4R</title><content type="html">&lt;a href="http://travel.latimes.com/"&gt;LA Times Travel&lt;/a&gt; is now using &lt;a href="http://twitter4r.rubyforge.org" title="Twitter Ruby library"&gt;Twitter4R&lt;span style="display:none"&gt;&amp;nbsp;(Ruby library for the Twitter API)&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;You can see they sent messages via the Twitter4R for a few hours today (2008-07-22) on their &lt;a href="http://twitter.com/latimestravel"&gt;Twitter timeline&lt;/a&gt; before changing the Twitter4R configuration to not sure which library/application they are using (or just waiting to get Alex to approve their application source code).&lt;br /&gt;&lt;br /&gt;Please let me know if you see Twitter4R sightings being used by other well known or cutting edge applications.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/343020319/la-times-travel-uses-twitter4r.html" title="LA Times Travel uses Twitter4R" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=3875087204352500306" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/3875087204352500306/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3875087204352500306" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3875087204352500306" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F07%2Fla-times-travel-uses-twitter4r.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/07/la-times-travel-uses-twitter4r.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-8556085172217297724</id><published>2008-07-18T08:44:00.005-05:00</published><updated>2008-07-18T16:31:32.457-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="pradipta" /><category scheme="http://www.blogger.com/atom/ns#" term="serendipity" /><title type="text">Serendipity: An original Pradipta's Rolodex member</title><content type="html">Last night I got the &lt;a href="http://blog.reverberate.org/2008/07/17/416-random-people-with-ror-on-their-resume-reply-all-reverse-flash-mob/"&gt;Pradipta's Rolodex message&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Rock on Pradipta!:)&lt;br /&gt;&lt;a href="http://thepradipta416.com" title="Proud Member of the Pradipta 416"&gt;&lt;img src="http://thepradipta416.com/img/badge2.gif" alt="The Few, The Proud, The Pradipta 416"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/339074202/serendipity-original-pradiptas-rolodex.html" title="Serendipity: An original Pradipta's Rolodex member" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=8556085172217297724" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/8556085172217297724/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/8556085172217297724" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/8556085172217297724" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F07%2Fserendipity-original-pradiptas-rolodex.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/07/serendipity-original-pradiptas-rolodex.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-1920917351345516137</id><published>2008-06-30T22:04:00.003-05:00</published><updated>2008-07-01T10:13:53.471-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="rubyforge" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="github" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">Twitter4R Development Releases</title><content type="html">Over the last week or so I have been putting Twitter4R sources in GitHub and getting the on-the-fly GemSpec to work "safely" enough for GitHub servers.  Tonight (June 30) I decided I would announce Twitter4R development micro-releases available only via the GitHub gem server.  To setup your environment to install the latest development release of &lt;a href="http://twitter4r.rubyforge.org"&gt;Twitter4R&lt;span style="display:none"&gt;: the most complete Ruby client bindings for the Twitter.com REST API&lt;/span&gt;&lt;/a&gt;, please read &lt;a href="http://github.com/mbbx6spp/twitter4r/wikis/howto-install-github-development-releases"&gt;HowTo: Install GitHub Development Releases&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Official documentation will still exist through the official &lt;a href="http://twitter4r.rubyforge.org/"&gt;Rubyforge project site of Twitter4R&lt;/a&gt;, but any documentation related to current development tasks, features, bugfixes will now be documented on the &lt;a href="http://github.com/mbbx6spp/twitter4r/wikis"&gt;Official Twitter4R GitHub Wiki&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you want to keep an eye on the Git repository, feel free to &lt;a href="http://github.com/mbbx6spp/twitter4r/toggle_watch"&gt;watch the mbbx6spp/twitter4r&lt;/a&gt; GitHub repository.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/324138614/twitter4r-development-releases.html" title="Twitter4R Development Releases" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=1920917351345516137" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/1920917351345516137/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1920917351345516137" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1920917351345516137" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F06%2Ftwitter4r-development-releases.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/06/twitter4r-development-releases.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-6162266326860941502</id><published>2008-05-20T14:12:00.015-05:00</published><updated>2008-05-20T15:09:07.834-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="apple" /><title type="text">Rails rocks, X sucks: How Provincial</title><content type="html">I seem to be coming across more and more [Steve] Jobs-clones or simply no-thinking Apple fan boys lately.  I don't mind the Apple fans that thought themselves about why they love their stylish new Macbook Pro, I have just had enough of the no-thinking variety of Apple zealots.&lt;br /&gt;&lt;br /&gt;This part of the Rails community appears to be a large population unfortunately.  Because these fan boys are actually incapable of thinking on their own, they adopt other people's arguments and say things like: "Rails rules, X sucks because so-and-so said this...".  Hmmmm.   Need I say more?&lt;br /&gt;&lt;br /&gt;On the other side I recently came across a Django fan boy who tried to convince his non-technical manager that Rails "cannot scale period".  Hmmmm.  How original.  A blanket statement like this is not only misleading, it is actually in many ways technically incorrect.  This is why in middle school we learned how to qualify our arguments.  Why is it that supposed college graduates cannot do this in their 20s and 30s?  It is one thing to strip out technical jargon for non-technical managers to understand a situation, but it is quite another to over simplify and mislead them because you have your own tech-religion agenda.  Be passionate, but admit to yourself and others when passion is getting the better of you.&lt;br /&gt;&lt;br /&gt;Why is acknowledging your chosen solution's weakness bad?  Doesn't it actually make the solution implementation stronger if you have thought about scenario-based weaknesses?  &lt;br /&gt;&lt;br /&gt;How about we each try to &lt;b&gt;*qualify*&lt;/b&gt; our positions on technology solutions out there, rather than figuratively urinate all over others without any basic respect for them.  I encourage criticism, but criticize constructively.  Say why.  On the flip side, we should also accept constructive criticism too.  &lt;br /&gt;&lt;br /&gt;The first step to constructive criticism, need not necessarily be candy coating your critique, but having the right intentions behind your critique.  For example, if your motivation for giving criticism is to start a flame war (sorry that is probably a very out of date term now), then you will probably get what you want.  However, if you really want to help a project get better because you care, then that is the first step.  &lt;br /&gt;&lt;br /&gt;In addition, the way you word and tone statements (as Twitter's Alex Payne should have learned all too well by now) has a big impact.  For example, Alex Payne's statements about Rails and Ruby cost me a contract at a former Rails shop that had a conniving PHP zealot waiting in the wings to jump on anything and take issue with Rails to upper management.  Lucky for him, it worked and he had 3 to 4 months of leading a team to miserable failure using Drupal as a "platform".  Not necessarily a reflection of PHP (or Drupal for CMS applications since it was far from a CMS application), but a reflection of this calculating pseudo-coder's inability to lead a project.  A "technical" manager who thought the kernel version on his Fiesty Ubuntu laptop was 7.0.4.  Enough said!:)&lt;br /&gt;&lt;br /&gt;Overall, I hope we can start to have intelligent conversations about software stacks rather than "yours sucks ass".  Because the latter in the end favors nobody.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;PS Merb rulez and Rails suckz!:)  If you want to know why read my teaser entry titled &lt;a href="http://snakesgemscoffee.blogspot.com/2008/05/why-merb-is-delicious.html"&gt;Why Merb is delicious&lt;/a&gt;, though I plan on writing more soon.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;PPS Merb wouldn't be where it is today without Rails.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/294521045/rails-rocks-x-sucks-how-provincial.html" title="Rails rocks, X sucks: How Provincial" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=6162266326860941502" title="3 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/6162266326860941502/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/6162266326860941502" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/6162266326860941502" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F05%2Frails-rocks-x-sucks-how-provincial.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/05/rails-rocks-x-sucks-how-provincial.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-2355125211359606383</id><published>2008-05-06T08:49:00.010-05:00</published><updated>2008-05-06T09:15:31.222-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="merb" /><title type="text">Why Merb is delicious</title><content type="html">Below are the reasons why &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt; is more delicious than other MVC web frameworks I have worked with (including Rails):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;On a diet...&lt;/b&gt;It is lighter weight than most, but still has enough oomph to implement common features with minimal code&lt;/li&gt;&lt;li&gt;&lt;b&gt;Religion-free...&lt;/b&gt;It is ORM, JavaScript/AJAX and testing/speccing library agnostic.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The sum of it's parts...&lt;/b&gt;OK that was a lame segway, but &lt;b&gt;parts&lt;/b&gt; is a mightily useful feature where a plugin is just total overkill.  Just because Java calls something a "component" does not make it the general definition of a component in concept.  And now look at the Rails plugin debacle today.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Precious gems...&lt;/b&gt;Plugins are created, distributed and installed in the form of beautiful RubyGems as opposed to the Rails plugin catastrophe with Gigabytes of duplicate disk space and lame version/revision control&lt;/li&gt;&lt;li&gt;&lt;b&gt;It's exceptional...&lt;/b&gt;Merb actually thought about how to do exception handling in controllers before Rails came up with something and also came up with IMHO a better solution.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Speedy Gonzalez...&lt;/b&gt;Compared to especially Rails, Merb performs &lt;a href="http://www.webficient.com/2007/08/testing-various-configurations-of-rails.html"&gt;very nicely indeed&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Loose threads...&lt;/b&gt;Merb is thread-safe unlike Rails, so that means one process can handle multiple concurrent file uploads, where Rails cannot right now.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;All together I think most people will find Merb to be a much better thought out (conceptually) MVC framework than Rails.  Over the next few weeks I'll be talking a lot about Merb and it's delicious APIs, Plugins, etc. as it nears it's 1.0 release.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/284669159/why-merb-is-delicious.html" title="Why Merb is delicious" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=2355125211359606383" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/2355125211359606383/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2355125211359606383" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2355125211359606383" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F05%2Fwhy-merb-is-delicious.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/05/why-merb-is-delicious.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-2880256725987487057</id><published>2008-04-04T10:23:00.001-05:00</published><updated>2008-04-04T11:54:50.304-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="chicago" /><category scheme="http://www.blogger.com/atom/ns#" term="jug" /><category scheme="http://www.blogger.com/atom/ns#" term="cjug" /><title type="text">Comedy of Errors</title><content type="html">Does anyone else find it comical that the &lt;a href="http://cjug.org/uger/directory/list"&gt;Chicago Java Users Group&lt;/a&gt; website is written in Rails?  And apparently not very well if it is not only sending a HTTP 500 error, but still using the default Rails generated 500.html page.  Poor all around.&lt;br /&gt;&lt;br /&gt;An IM buddy mentioned it might be JRuby, but I do think it is still very ironic considering the hostility from the Java world regarding Rails in general (whether Ruby on Rails or JRuby on Rails).&lt;br /&gt;&lt;br /&gt;I just had to share!:)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; Someone fixed it shortly after I reported it to CJUG.&lt;br/&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; Actually it was only temporarily fixed, it is back to the default 500 Rails error page.&lt;br/&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; In addition they have exposed their SVN information.  See the &lt;a href="http://cjug.org/uger/.svn/entries"&gt;public entries&lt;/a&gt; and from that information you can find their &lt;a href="http://svn.oaktop.com/Uger/trunk/"&gt;non-password protected source code and check it out&lt;/a&gt; if you like.&lt;br /&gt;&lt;br /&gt;If anyone from CJUG is reading, you can fix this by reading my blog entry from two months back called &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-3.html"&gt;Preventing Information Leaks, Part 3&lt;/a&gt;.  Although it might be useful to read &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-1.html"&gt;part 1&lt;/a&gt; and &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-2.html"&gt;part 2&lt;/a&gt; as well.  Cheers!&lt;br /&gt;&lt;br /&gt;PS I also sent an email to &lt;code&gt;info at cjug.org&lt;/code&gt; and received an email delivery error.&lt;br/&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; I may have read too much into the SVN repository information exposure in this specific case since this is an open source Rails application project (I only just realized), thus the non-password protected repository, but I still stand by the rest!:)  It is also not good practice to expose such information from the outset of deploying an web application.&lt;br/&gt;&lt;br /&gt;&lt;b&gt;Update (1.5 hours after trying to notify JUG and posting the blog post):&lt;/b&gt; The site has been fixed now for over 5 minutes, so good job fixing it CJUG!:)&lt;br/&gt;&lt;br /&gt;&lt;b&gt;Update (8 minutes later):&lt;/b&gt; Ooooops!  It is back to the default Rails 500 error page.  Perhaps it is 2 out of three bad FastCGI processes that need to be killed on the server?  HTH someone at CJUG, but since I can't look at the system I can't say for sure.&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/264092508/comedy-of-errors.html" title="Comedy of Errors" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=2880256725987487057" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/2880256725987487057/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2880256725987487057" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2880256725987487057" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F04%2Fcomedy-of-errors.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/04/comedy-of-errors.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-125069007997943352</id><published>2008-04-01T10:34:00.007-05:00</published><updated>2008-04-01T10:58:22.947-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="php" /><category scheme="http://www.blogger.com/atom/ns#" term="coding" /><title type="text">Coding with Explicit Intentions</title><content type="html">Recently I have had the [mis]fortune to be working with PHP for integration purposes for a client.  A partner of my client's (in the advertising space) sent us some PHP code to add to our servers for resolving the content type of a file based on its extension.  The line of code in the PHP script they sent over that was supposed to determine the file extension was:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;  $ext = substr($file,-4);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;As you can see they are making a pretty big assumption - that the extension is exactly three letters long.  The media files that this script *may* support in the future are: Real Media (.rm), MPEG (.mpeg), Quicktime (.qt), etc.  These extensions are not exactly three letters long.  Why would someone want to write code that is quite likely to fail and also not communicate more explicitly their intentions?  &lt;br /&gt;&lt;br /&gt;This partner already doesn't support PHP &lt; 4.0.3, so why not substitute the line above with:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;  $ext = ".".pathinfo($file, PATHINFO_EXTENSION);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;It is standard, will never fail (unless there is a defect in the PHP version you are using for the standard function pathinfo, but what can you do about that?) and communicates the explicit intent of the original author, thus improving code maintainability.&lt;br /&gt;&lt;br /&gt;Anyway, just a pet peeve.  This is not by any means the only example I see on a day in day out basis, this just happened to be a great example for me to demonstrate my point.  While this example demonstrates a minor one-line demonstration, if developers introduce even only 2-3 of these un-explicit intentioned lines of code a day that do not always do what you might want it to do, then the codebase quickly becomes a mine field.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/262077055/coding-with-explicit-intentions.html" title="Coding with Explicit Intentions" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=125069007997943352" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/125069007997943352/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/125069007997943352" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/125069007997943352" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F04%2Fcoding-with-explicit-intentions.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/04/coding-with-explicit-intentions.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-8367580530705478249</id><published>2008-03-30T21:49:00.003-05:00</published><updated>2008-03-30T22:01:15.112-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="metafusion" /><title type="text">Waking Up From Hibernation</title><content type="html">Just a quick post to say that I will be waking up from OSS and blog hibernation at the beginning of May.  I have a stack of bug fixes to apply to Twitter4R for a pretty large 0.3.1 release (in terms of bug fixes and supporting Rails 2.x compatibility).  The next two major features on my Twitter4R v0.4.0 release radar are: (a) supporting Ruby 1.9 and (b) adding the newish "track" feature in some capacity (probably via XMPP instead of the REST API on Twitter.com).&lt;br /&gt;&lt;br /&gt;I also have a couple of minor features to add to the &lt;a href="http://rubyforge.org/projects/metafusion" title="Ruby Metafusion-Crypography gem"&gt;&lt;code&gt;metafusion-crypto&lt;/code&gt;&lt;/a&gt; gem and finally release the first version of &lt;code&gt;metafusion-rails&lt;/code&gt;.  Then I will probably abandon OSS work explicit to Rails and write numerous Merb plugins/extensions.&lt;br /&gt;&lt;br /&gt;The catch up work will likely take 2-3 weeks into May and then hopefully my new venture workload will be significantly smaller to sustain OSS development over the summer months.&lt;br /&gt;&lt;br /&gt;Thanks for all your patience!&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/261037426/waking-up-from-hibernation.html" title="Waking Up From Hibernation" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=8367580530705478249" title="4 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/8367580530705478249/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/8367580530705478249" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/8367580530705478249" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F03%2Fwaking-up-from-hibernation.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/03/waking-up-from-hibernation.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-6254672166042759920</id><published>2008-02-12T10:44:00.000-06:00</published><updated>2008-02-12T16:49:35.064-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="information leaks" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><title type="text">Preventing Information Leaks, Part 3</title><content type="html">In the third part of the &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-1.html"&gt;how to prevent information leaks&lt;/a&gt; blog post series, we will look for unguarded "hidden" files where we can garnish quite a bit of information.  &lt;br /&gt;&lt;br /&gt;Make sure you check out &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-1.html"&gt;part 1&lt;/a&gt; and &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-2.html"&gt;part 2 on how to prevent information leaks in web applications&lt;/a&gt; before continuing.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Seek Unguarded Hidden Files&lt;/h4&gt;&lt;br /&gt;For web applications that use deployment tools that pull code from code repositories, you can find out quite a bit of information about the code repository (e.g. host, path, usernames, file listings), by finding unguarded hidden files.  One obvious example especially in the SVN saturated Rails world is the path &lt;code&gt;/.svn/entries&lt;/code&gt; and similar URLs.&lt;br /&gt;&lt;br /&gt;You will want to make sure the following URIs are not accessible on your public sites if you use Subversion (SVN):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/.svn/entries&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/javascripts/.svn/entries&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/stylesheets/.svn/entries&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/images/.svn/entries&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If you are using a superior SCM for your project like Git you ought to be looking for the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/.git/config&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;strike&gt;/javascripts/.git/config&lt;/strike&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;strike&gt;/stylesheets/.git/config&lt;/strike&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;strike&gt;/images/.git/config&lt;/strike&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If your project is still in the stone-age using CVS, then check the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/CVS/Entries&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/javascripts/CVS/Entries&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/stylesheets/CVS/Entries&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/images/CVS/Entries&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Adapt these patterns for your application framework default structures.  The above is for Rails or Rails-based frameworks (e.g. Merb).  &lt;br /&gt;&lt;br /&gt;When I first tried this last week on the Rails top 10 sites, three out of ten of these sites exposed their SVN information (and last week I had only checked SVN, no Git or CVS URIs).  Since last week at least one of those sites have fixed the problem!&lt;br /&gt;&lt;br /&gt;What information is exposed in these files?  Quite a lot of information.  Do you want potential hackers knowing:&lt;br /&gt;&lt;ul&gt;&lt;/li&gt;code repository URL (host, port, protocol, path)&lt;/li&gt;&lt;li&gt;usernames of committers&lt;/li&gt;&lt;li&gt;code repository listings of files in a directory&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;All these things are not things you really want the potential hacker knowing.  On my travels investigating the top 100 Rails sites I found one top 20 site that exposed enough information from their SVN entries file that I found a prototyping directory that included a "specs.rtf" document, which I was able to download.  The document was not very uninteresting (at least not to me), but if they had written more in-depth specifications in the document, it may have served as a nice guide for a potential hacker to garnish enough information about their setup to take over!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Moral of this story?&lt;/b&gt; Guard hidden files.  I recommend "forbidding" access to all troublesome path regex patterns.  &lt;br /&gt;&lt;br /&gt;For example, one of the LigHTTPd servers I administer has the following at the top of the configuration file:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;$HTTP["url"] =~ ".*/\..*" {&lt;br /&gt;  url.access-deny = ("")&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For Apache httpd servers I use something like the following in the &lt;code&gt;httpd.conf&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;DirectoryMatch "^.*\..*"&amp;gt;&lt;br /&gt;  ErrorDocument 403 /403.html&lt;br /&gt;  Order allow,deny&lt;br /&gt;  Deny from all&lt;br /&gt;  Satisfy All&lt;br /&gt;&amp;lt;/DirectoryMatch&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nginx configuration might look something like:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;location ^~ /\..* {&lt;br /&gt;  deny    all;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This guards against URLs like: &lt;code&gt;/.svn/entries&lt;/code&gt;, &lt;code&gt;.git/config&lt;/code&gt; as well as &lt;code&gt;.htpasswd&lt;/code&gt;, etc.  This means that only some script-kiddie hackers will mistakenly think you are using one SCM system instead of another, but they will never be able to know for sure which SCM you use or any information about your code repository.  &lt;br /&gt;&lt;br /&gt;Forbidding access to all paths containing "/." somewhere in the URL is generally a good idea (IMHO) as sometimes people change web servers and leave "secret" files in the directory structure, but the new server doesn't know that, for example, &lt;code&gt;.htaccess&lt;/code&gt; or &lt;code&gt;.htpasswd&lt;/code&gt; is "special", so it will just serve it without thinking.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/233840598/preventing-information-leaks-part-3.html" title="Preventing Information Leaks, Part 3" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=6254672166042759920" title="4 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/6254672166042759920/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/6254672166042759920" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/6254672166042759920" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F02%2Fpreventing-information-leaks-part-3.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-3.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-8032118076093709950</id><published>2008-02-11T13:04:00.000-06:00</published><updated>2008-02-11T13:12:38.120-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="information leaks" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><title type="text">Preventing Information Leaks, Part 2</title><content type="html">Continuing the series that looks at &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-1.html"&gt;how to prevent information leakage&lt;/a&gt;, today we look at the information leakage from web server HTTP headers.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;HTTP Header Leakage&lt;/h4&gt;&lt;br /&gt;Let's look at the information potential hackers can get from HTTP headers from just a &lt;code&gt;GET /&lt;/code&gt; HTTP request.  Let us look at http://www.cnn.com:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ curl -I http://www.cnn.com&lt;br /&gt;HTTP/1.1 200 OK&lt;br /&gt;Date: Thu, 07 Feb 2008 15:22:32 GMT&lt;br /&gt;Server: Apache&lt;br /&gt;Accept-Ranges: bytes&lt;br /&gt;Cache-Control: max-age=60, private&lt;br /&gt;Expires: Thu, 07 Feb 2008 15:23:23 GMT&lt;br /&gt;Vary: Accept-Encoding,User-Agent&lt;br /&gt;Content-Type: text/html&lt;br /&gt;X-Pad: avoid browser bug&lt;br /&gt;Content-Length: 90458&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This example is pretty decent.  What you want to look for is the &lt;code&gt;Server&lt;/code&gt; HTTP header value.  In this case it is just "Apache".  Now it does identify the web server used, but it doesn't pinpoint the version being used.  Now I am going to try a popular Rails website:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;HTTP/1.1 200 OK&lt;br /&gt;Date: Thu, 07 Feb 2008 15:25:34 GMT&lt;br /&gt;Server: Apache/2.2.2 (FreeBSD) mod_ssl/2.2.2 OpenSSL/0.9.8b DAV/2 PHP/5.1.4 SVN/1.3.2 mod_vd/2.0 mod_fastcgi/2.4.2 proxy_html/2.5&lt;br /&gt;Last-Modified: Thu, 07 Feb 2008 14:58:58 GMT&lt;br /&gt;ETag: "4da437-36ac-b69b1080"&lt;br /&gt;Accept-Ranges: bytes&lt;br /&gt;Content-Length: 13996&lt;br /&gt;Vary: Accept-Encoding&lt;br /&gt;Content-Type: text/html&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In this case we can see what OS Apache is running on and the version of Apache.  Not only this, but we see all the enabled modules in Apache and their respective versions.  IMHO this is too much information especially considering this site supposedly (at least as far as I know) host the site on a fully controlled environment (either dedicated or VPS with root access).  Applications on shared hosts cannot help this much without assistance from the shared hosting company.  I have a couple of very small sites that get little traffic on a shared host, so I appreciate this obstacle.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Moral of this story:&lt;/b&gt; If you have full control over your environment you should always either change the "Server" HTTP header to something generic (e.g. "Apache" as in the CNN example) or disable it from being returned to the client.  This setting is very easy in Apache, LigHTTPd and NGinx.  I assume this wouldn't be difficult in LiteSpeed either, but I do not have configuration experience with LiteSpeed.&lt;br /&gt;&lt;br /&gt;Apache configuration:&lt;pre&gt;&lt;code&gt;Header unset Server&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;LigHTTPd configuration:&lt;pre&gt;&lt;code&gt;server.tag = ""&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;NGiNX configuration:&lt;pre&gt;&lt;code&gt;server_tokens off;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Also make sure there aren't any other headers that give away too much information.  Especially look at the &lt;code&gt;X-&lt;/code&gt; HTTP headers.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/233306691/preventing-information-leaks-part-2.html" title="Preventing Information Leaks, Part 2" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=8032118076093709950" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/8032118076093709950/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/8032118076093709950" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/8032118076093709950" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F02%2Fpreventing-information-leaks-part-2.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-2.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-7664632921932248120</id><published>2008-02-09T12:17:00.000-06:00</published><updated>2008-02-09T12:44:30.956-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="activerecord" /><title type="text">DataMapper vs. ActiveRecord</title><content type="html">Today I came across a thread on ruby-talk where I responded to the age old question of which Ruby ORM (specifically DM vs. AR).&lt;br /&gt;&lt;br /&gt;I responded based on my production use of AR, development use of DM and my understanding of Fowler's PoEA of the same names that I have applied in Java and Python countless times.&lt;br /&gt;&lt;br /&gt;As some readers of this blog might find this discussion interesting, I am linking to my response to the &lt;a href="http://www.ruby-forum.com/topic/141181#630493"&gt;DataMapper vs. ActiveRecord discussion here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The executive summary (for the infinitely lazy) is:&lt;blockquote&gt;It appears that if DataMapper (the Ruby library) is able to sufficiently hide enough database logic in more complex business logic scenarios, then the DM library might be more beneficial to use when using a legacy database schema where you are not able to create primarily isomorphic relationships between class attributes and table columns.  Whereas AR would be a slam dunk and simpler to use in isomorphic schema scenarios where you have control over the database schema.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I will be returning to the &lt;a href="http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-1.html"&gt;Preventing Information Leaks&lt;/a&gt; series on Monday/Tuesday (it is already written, I just need to publish).&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/232292026/datamapper-vs-activerecord.html" title="DataMapper vs. ActiveRecord" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=7664632921932248120" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/7664632921932248120/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7664632921932248120" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7664632921932248120" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F02%2Fdatamapper-vs-activerecord.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/02/datamapper-vs-activerecord.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-2670866589089477559</id><published>2008-02-07T10:04:00.001-06:00</published><updated>2008-02-07T10:39:05.086-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="information leaks" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><title type="text">Preventing Information Leaks, Part 1</title><content type="html">Before I start I want to mention that the techniques suggested in this blog post are for readers to use to secure their own web applications.&lt;br /&gt;&lt;br /&gt;This does not mean that you can take over the server with these techniques without further hacking, but these steps provide a lot of information about the environment the web application is deployed to or developed using, unless system administrators/engineers or software engineers prevent this information leakage.&lt;br /&gt;&lt;br /&gt;Some of these techniques exploit settings that are usually found in Rails when default settings are used, but web applications written in different frameworks may also use these settings, which leak information.&lt;br /&gt;&lt;br /&gt;This all just comes down to thinking through the security scenarios.  Just like developers need to consider the usage of their applications or APIs or frameworks from the user perspective, those tasked with securing up their applications need to consider how potential hackers might try to access key information to help them hack your systems.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Identifying the framework or "stack"&lt;/h4&gt;&lt;br /&gt;Let us check if your application smells too much like you are using a particular framework or another.  This may or may not be terrible, BUT if you can tell which version of the framework you are using from publicly accessible information on your site, then you are leaking too much information.  In fact, some firms/developers advertise very publicly which frameworks or stacks they use, but they usually try not to talk too much about the exact versions they use.&lt;br /&gt;&lt;br /&gt;For example, if an application responds with a 200 OK HTTP status for the majority of the following URLs, it is VERY likely it is a Rails application:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/javascripts/application.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/404.html&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/500.html&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;/422.html&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In the case of the last URL, we can identify that the application is written using Rails 2.0.  We can also look at the 404 to see if it looks like the default looking 404 file for different versions of Rails.  If &lt;code&gt;/422.html&lt;/code&gt; doesn't exist we might still be able to tell the difference between Rails 1.1 and 1.2 applications by what &lt;code&gt;/404.html&lt;/code&gt; looks like.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Moral of this story:&lt;/b&gt; At a minimum always change the default error pages in your Rails application to fit your design.  Also consider changing the URLs of the error pages too.  Not only does the redesign prevent potential hackers from identifying which version of Rails you might be using it also looks more professional and makes the user experience in case of an error a little more acceptable!&lt;br /&gt;If you are not using Rails, think about what files are created by default by your framework and change things around a little to prevent information leakage.&lt;br /&gt;&lt;br /&gt;I will continue this series in subsequent parts.  Stay tuned!&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/231097330/preventing-information-leaks-part-1.html" title="Preventing Information Leaks, Part 1" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=2670866589089477559" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/2670866589089477559/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2670866589089477559" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2670866589089477559" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F02%2Fpreventing-information-leaks-part-1.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/02/preventing-information-leaks-part-1.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-7235516009279821948</id><published>2008-01-31T09:23:00.000-06:00</published><updated>2008-01-31T11:01:12.074-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="stupid" /><category scheme="http://www.blogger.com/atom/ns#" term="sin" /><category scheme="http://www.blogger.com/atom/ns#" term="language" /><title type="text">Stupid Easy: 7 Deadly [Rails] Sins, Part 3</title><content type="html">This is the third and final part in the &lt;a href="http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-1.html"&gt;Stupid Easy: 7 Deadly [Rails] Sins&lt;/a&gt; series.  See &lt;a href="http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-1.html"&gt;part 1&lt;/a&gt; and &lt;a href="http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-2.html"&gt;part 2&lt;/a&gt; if you haven't already.&lt;br /&gt;&lt;br /&gt;I have left the most heinous sin to the end.  If you are a serious sinner in this aspect, there is little hope for you unless you take steps now to rectify your behavior in this aspect.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Stupid Easy Ruby&lt;/h4&gt;&lt;br /&gt;&lt;blockquote&gt;When in Rome, do as the Romans do&lt;/blockquote&gt;&lt;br /&gt;That's right.  This is the sin of not knowing how to really code in Ruby.  Sure some coders that move to Ruby can write code that does what they want it to do, but often at the severe expense of compromising project code maintainability (e.g. making things very unDRY, etc.) or even introducing significant performance issues by not understanding basics about the Ruby language.&lt;br /&gt;&lt;br /&gt;Instead I see people using Java, Perl, PHP, C# or even Python idioms in Ruby instead of understanding the essence of the language of Ruby, which is distinct from each of these languages in different ways.&lt;br /&gt;&lt;br /&gt;The same is true for any language/environment you work within.  I know former PHP people that moved to Java and do not have the first clue about basic Java idioms that work well.  This isn't just to pick on PHP heads as I imagine this occurs from any language migration path.  I have simply seen this sin committed most by former PHP coders moving toward Java, Ruby and Python.  However, I will say I see a LOT of former Java (massive static language proponents - Joshua Bloch you are a nonobjective snob) developers that do not understand or appreciate the non-static design mentality and they create large class hierarchies and don't understand what a Mixin is (or they pretend to be "cool" and talk alot of about these idioms, but don't really utilize them in the right way themselves).  The Ruby mindset is still different from it's more similar looking cousins: Python and Perl, but moving between Python, Perl and Ruby (in any direction) feels more intuitive (at least in my mind).&lt;br /&gt;&lt;br /&gt;Now I should stress that I can no longer code in Java without pulling my hair out because the thought of creating 5 interfaces and a factory for every three class implementations drives me temporarily insane.  The SPI design principle allows Java to be fairly flexible (especially for a statically typed language), but at the expense of my personal sanity now that I prefer to think the non-static way (yes, I still appreciate Python's strongly-typed ways).  This is why I prefer to use JRuby, Jython or Groovy scripting in Java environments.&lt;br /&gt;&lt;br /&gt;There is no magic bullet to stop sinning in this regard if you aren't willing to take a journey to learn and understand Ruby idioms (not just basic *knowledge*).  There are no shortcuts, it simply depends on how easily your brain can shift in gears.  This doesn't mean people who can't shift gears are "bad" developers, but not well suited to migrating to significantly different environments very often.&lt;br /&gt;&lt;br /&gt;Just remember the rules in Ruby aren't the same.  Think in terms of sending messages to objects that may or may not respond to the message you send, instead of expected interfaces and you are half way there if you are coming from Java, C++ and similar languages.  Think of Java as a big government structure with a complicated tax code and Ruby as minimal government with a simplified tax code &lt;b&gt;without&lt;/b&gt; loopholes accessible only to the rich!  That means in the Ruby world wild things such as adult services can legally be procured between consenting adults, so bend your brain to think that way when working in Ruby...almost anything is possible especially in the realm of metaprogramming that is not possible in the Java world.&lt;br /&gt;&lt;blockquote&gt;That government is best which governs least.&lt;br/&gt;--Thomas Paine&lt;/blockquote&gt;I personally happen to agree with Thomas Paine's statement (at least in the context of programming), but there are various programming philosophies that different languages cater for, so it comes down to your own preference.  Pick the ones you can live with at the time and think in terms of and you will be happier for it.&lt;br /&gt;&lt;br /&gt;Obviously in a programming context some people (e.g. Joshua Bloch, who is still a static language snob) will oppose legal procurement of "adult services".  They have a moral objection to these activities and thus do not appreciate the beauty of dynamic design.  If you have such moral reservations in programming, do everyone a favor and stay in the Java world or at least static languages!  This is the beauty of different opinions.  Nobody is right in absolute terms, but you need to make the right choice for yourself.  It is the zealots who only accept "absolute correctness" that we should be weary of (on any side of the argument, but including Joshua Bloch).&lt;br /&gt;&lt;br /&gt;My general philosophy when I had the Java Way ingrained in my brain was that as an API designer I had to protect stupid developers from their own stupidity.  Now my philosophy in the Ruby world is that I write APIs for smart developers and if you aren't [Ruby] smart, use at your own risk.  Of course, I oppose complication for the sake of appearing to be "smart".  But I try to write APIs that allow more advanced Ruby developers to take advantage of language features such as blocks, metaprogramming, etc. as opposed to providing an over-simplified, dumbed-down API that ends up looking ugly to the wiser Ruby developer due to being less DRY than might be possible without restriction.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Ruby Language Pointers&lt;/h4&gt;&lt;br /&gt;If you haven't acquainted yourself with &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/"&gt;the pickaxe book&lt;/a&gt; you should pay special attention to the following sections: &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/tut_containers.html#S2"&gt;Blocks&lt;/a&gt;, &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/tut_modules.html#S2"&gt;Mixins&lt;/a&gt;, &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/ospace.html#S1"&gt;Inspecting Objects&lt;/a&gt;, &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/tut_classes.html#S1"&gt;Inheritance &amp;amp; Messages&lt;/a&gt;, &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/tut_classes.html#UA"&gt;Inheritance &amp;amp; Mixins&lt;/a&gt;, &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/classes.html#S1"&gt;Classes &amp;amp; Objects Interacting&lt;/a&gt;, &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/language.html"&gt;The Ruby Language&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Then I would look at the source code of the ActiveSupport open source project (part of Rails) for techniques that are very useful.  Some of these techniques I have discussed in previous blog posts: &lt;a href="http://snakesgemscoffee.blogspot.com/2006/08/rubyisms-reopening-classes.html"&gt;Ruby Idiom: Reopening Classes&lt;/a&gt;, &lt;a href="http://snakesgemscoffee.blogspot.com/2006/07/rubyisms-forwardables.html"&gt;Ruby Idiom: forwardables&lt;/a&gt;, &lt;a href="http://snakesgemscoffee.blogspot.com/2007/04/injecting-understanding.html"&gt;Ruby Idiom: Inject-ing Understanding&lt;/a&gt;, &lt;a href="http://snakesgemscoffee.blogspot.com/2007/05/ruby-equality.html"&gt;Ruby Equality&lt;/a&gt;, &lt;a href="http://snakesgemscoffee.blogspot.com/2007/06/higher-order-messaging.html"&gt;Ruby Higher Order Messaging&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/226640522/stupid-easy-7-deadly-rails-sins-part-3.html" title="Stupid Easy: 7 Deadly [Rails] Sins, Part 3" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=7235516009279821948" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/7235516009279821948/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7235516009279821948" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7235516009279821948" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F01%2Fstupid-easy-7-deadly-rails-sins-part-3.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-3.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-4840965527902167268</id><published>2008-01-22T09:43:00.000-06:00</published><updated>2008-01-22T11:05:18.934-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="rubyonrails" /><title type="text">Stupid Easy: 7 Deadly [Rails] Sins, Part 2</title><content type="html">In the second part of &lt;a href="http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-1.html"&gt;Stupid Easy: 7 Deadly [Rails] Sins&lt;/a&gt;, we look at sins four through six and save the most heinous sin for last in the third part of this series.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;4. Stupid Easy Views&lt;/h4&gt;&lt;br /&gt;Everyone has seen spaghetti view code, either in the JSP, PHP, or other similar web templating environments.  So why do people honestly think (ok, only the no-thinkers) that when they use Rails that you can't violate MVC because it is built around the MVC "pattern".  Don't even get me started on the whole "pattern" thing...&lt;br /&gt;&lt;br /&gt;If you see a piece of view code like the following, then you are violating MVC.  Yes, even when using Rails:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;% &lt;br /&gt;if current_user &amp;&amp; current_user.admin?&lt;br /&gt;  @somevar = something goes here&lt;br /&gt;  # and do something else here&lt;br /&gt;else&lt;br /&gt;  @somevar = something else goes here&lt;br /&gt;end&lt;br /&gt;%&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This is a small (but very stupid) violation, but a violation none-the-less.  I have seen not just logic in view code, but oddly model-specific code (in one case I even saw some attributes of a model being updated at the END of the view template - go figure).  Now simply checking the admin flag of the &lt;code&gt;current_user&lt;/code&gt; to insert some view specific code, would not be violating MVC.&lt;br /&gt;&lt;br /&gt;There are various ways of making sure you don't make this mistake.  Some people think using a specialized templating language in place of eRB is the way to go (one of the many potential replacements that I happen to know about is &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;).  These specialized template languages basically make it virtually impossible to embed any kind of logic into the view code.  Others (pro-thinkers, rather than no-thinkers) don't believe that level of enforcement is necessary and just make a point of highlighting to the team (and then quickly refactoring) any violations in view code to educate all the team members about this sin.  &lt;br /&gt;&lt;br /&gt;I have even seen some Rake tasks written (ok, I may have written a couple) that flag any views that have specific keywords within the &lt;% %&gt; eRB brackets as potential violators so that we can look through the suspects and make judgments before a release is made (because you never want to release code that violate basic principles you believe in).  Another strategy is to only work with developers that you share a very similar development philosophy and know they wouldn't violate this basic rule of thumb in the first place.  &lt;br /&gt;&lt;br /&gt;In any case, you need to incorporate one of these strategies so you can be sure to be rid of the Stupid Easy View &lt;b&gt;faux pas&lt;/b&gt; in Rails projects.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;5. Stupid Easy Configuration (and Routes)&lt;/h4&gt;&lt;br /&gt;In Rails 2.0 there is absolutely ZERO excuse for this (with very nice initializer hooks available), but even pre-2.0 it is hard to justify an &lt;code&gt;config/environment.rb&lt;/code&gt; consisting of more than 30 lines (including basic Rails configuration minus comments).&lt;br /&gt;&lt;br /&gt;Separation of configuration into separate files that are required by &lt;code&gt;config/environment.rb&lt;/code&gt; were my personal preference in pre-2.0.&lt;br /&gt;&lt;br /&gt;On the &lt;code&gt;config/routes.rb&lt;/code&gt; side, I would often see the default routes still uncommented.  In Rails post-1.2 there is really no excuse since almost everyone should be using RESTful routes with RESTful controllers (even if the way Rails generates a ridiculous amount of code, when it could be refactored nicely into a mixin or base class, is pretty dumb) anyway.  In fact, default routes are almost always an invitation for troublemakers to hack into your site (especially if they know it is a Rails site).  I can't say I have never deployed a Rails 1.2.x site with default routes uncommented, but I certainly haven't in the last year since Rails 1.2's official release.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;6. Stupid Easy Library Code&lt;/h4&gt;&lt;br /&gt;For some reason numerous popular Rails plugins promote the idea of putting generated files into your &lt;code&gt;RAILS_ROOT/lib&lt;/code&gt; directory (e.g. acts_as_authentication, restful_authentication, etc.).  Instead of being a real plugin they are basically just Rails generators.  Now we could debate how generators could be better supported in Rails, but that is really a tangent to the point.  Don't be fooled by these popular "plugins" (remember they are really only generators).  &lt;br /&gt;&lt;br /&gt;If you have &lt;b&gt;significant&lt;/b&gt; code in your &lt;code&gt;RAILS_ROOT/lib&lt;/code&gt; that has the same focus (e.g. authentication, authorization, credit card processing, etc.), then you really ought to create your own plugin (even if it isn't going to be shared with other projects in the foreseeable future).  How you and/or your team defines &lt;b&gt;"significant"&lt;/b&gt; is a judgment call, but I personally think any unit of code that works together that is greater than 200 lines of elegant Ruby code is significant (minus empty lines and comments of course).  It isn't necessarily a hard or fast rule, but a general rule of thumb, which may have exceptions.&lt;br /&gt;&lt;br /&gt;The main purpose of this is twofold from my perspective.  When you have a lot of code in your &lt;code&gt;RAILS_ROOT/lib&lt;/code&gt; it is a harder to be more disciplined about organization.  Whereas with a plugin you know where plugin initialization code goes vs. mixin or other code.  Another big benefit (which is related to code organization) is testing/specing.  It is much easier to see (or specifically notice) test/spec-coverage shortcomings of plugins than holes in your tests/specs for &lt;code&gt;RAILS_ROOT/lib&lt;/code&gt; code.  &lt;br /&gt;&lt;br /&gt;Benefits of creating plugins include that it is forces you (the developer) to think more about:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Testing/specing your code&lt;/li&gt;&lt;li&gt;code organization from a maintainability perspective&lt;/li&gt;&lt;li&gt;what chunks of code go together (should this be one or two plugins)&lt;/li&gt;&lt;li&gt;the scope of your plugin vs. what needs to be defined or written in your application code&lt;/li&gt;&lt;li&gt;who is responsible for developing this functionality, maybe it is the infrastructure/core/framework development team who needs to be responsible for authentication or authorization code rather than application developers.  With plugins you can separate our these responsibilities very easily&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;In addition, a plugin is much more easily shareable across projects (in a more organized and disciplined way than just copying or even linking files/directories into your &lt;code&gt;RAILS_ROOT/lib&lt;/code&gt; directory).&lt;br /&gt;&lt;br /&gt;Of course, I also find the way Rails plugins are supported by Rails a hindrance, especially when RubyGems &lt;b&gt;could&lt;/b&gt; provide a many facilities to support this in a more elegant way, but that is a topic for another day!:)&lt;br /&gt;&lt;br /&gt;There is only one Stupid Easy Deadly [Rails] Sin left, which I will publish in the next two weeks.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/221132590/stupid-easy-7-deadly-rails-sins-part-2.html" title="Stupid Easy: 7 Deadly [Rails] Sins, Part 2" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=4840965527902167268" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/4840965527902167268/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4840965527902167268" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4840965527902167268" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F01%2Fstupid-easy-7-deadly-rails-sins-part-2.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-2.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-9132450953725179337</id><published>2008-01-12T10:46:00.000-06:00</published><updated>2008-01-12T11:39:27.629-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="stupid" /><category scheme="http://www.blogger.com/atom/ns#" term="sin" /><title type="text">Stupid Easy: 7 Deadly [Rails] Sins, Part 1</title><content type="html">Everyone has been talking about Rails for a few of years now as the framework that makes it "stupid easy" to create web applications.  The problem I have with this mentality is it creates a "stupid easy" sub-culture within the Rails community that promotes stupid laziness (as opposed to smart laziness).&lt;br /&gt;&lt;br /&gt;Over the last 3 Rails contracts, I have worked with supposedly experienced developers that have switched to Rails from OO languages like Java and C++ (as opposed to pretend OO languages like PHP).  The results have been VERY disappointing.&lt;br /&gt;&lt;br /&gt;The biggest problem I see is that some, even quite experienced developers, have the [stupid] lazy mentality burned into their brains.  They want to visit blogs and copy and paste code into their applications without thinking about it.  In fact, recently I found a ridiculous real world example of such madness.  No thought put into the pasted code AT ALL.  I could identify the blog posting on a popular Rails blog that had the EXACT same code.  The variables weren't EVEN renamed to be meaningful in the current application.  Instead a finance web application had references to customers and invoices in the controller and view code when there were no such entities/models involved in the application.  Not only is this a maintenance nightmare, it show how little thought went into the code just to get a small AJAX effect that (a) wasn't difficult to write from scratch (4 lines in total after refactoring from the 11 lines of code used) and (b) was probably not even that necessary from the user experience perspective.&lt;br /&gt;&lt;br /&gt;These are the developers I think ought to return to their no-thinking PHP or Java/JEE recipe books and leave the Ruby world alone.  Of course, the authors of "recipe" books should also bare some of the blame for encouraging the no-thinking hackers out there to join the Ruby world in the first place.  Is that really the type of mindset we wish to harbor in our community?&lt;br /&gt;&lt;br /&gt;Look at the PHP and Java universes today for a reference point of where we will end up very soon if we are not careful.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;1. Stupid Easy Schemas&lt;/h4&gt;&lt;br /&gt;One of the deadly sins I saw on my travels through their code was extending the "stupid easy" mentality in the form of not defining schema properly.  Sure they *used* Rails' migrations, but they didn't really create a usable schema based on the use stories and cross-story functional requirements.&lt;br /&gt;&lt;br /&gt;While you might not want to use database specific features like triggers, stored procedures, or even foreign keys (the latter assumes you are using Rails-based equivalents in place of FKs), you should still make your schema sensible.&lt;br /&gt;&lt;br /&gt;For example,&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# Migration code&lt;br /&gt;  create_table :countries do |t|&lt;br /&gt;    t.column :code, :string&lt;br /&gt;    t.column :name, :string&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;# Model code&lt;br /&gt;class Country &lt; ActiveRecord::Base&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In this example we created a table called &lt;code&gt;countries&lt;/code&gt; that has two string fields: &lt;code&gt;code&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;.  In this case the code is the ISO country code that the application is going to use for almost all country lookups in the database.  We knew that pretty much from the beginning because of the nature of our application.  (Note: this example is a little contrived as I had to change things so as not to expose too much about the application this is from).&lt;br /&gt;&lt;br /&gt;Not only do we know that the &lt;code&gt;Country&lt;/code&gt; model will almost always be looked up by its code (from the initial set of use(r) cases/stories we need to implement).  The ISO code is also always 3 characters long.  We also know that these ISO codes are unique for each country.  All these things we knew before we needed to create the schema.  This is the important information that is missing from the schema and the model is missing relevant validation.&lt;br /&gt;&lt;br /&gt;Before committing this new model and migration for &lt;code&gt;Country&lt;/code&gt; the developer writing the code (one of the developers I am thinking of loves to tout how XP/agile and great his code is), should have had the following code on initial checkin (there really is no excuse IMHO):&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# migration code&lt;br /&gt;  create_table :countries do |t|&lt;br /&gt;    t.column :code, :string, :limit =&gt; 3&lt;br /&gt;    t.column :name, :string # You may even decide to cap the length of the name field too, but this is more of a DBA style thing.&lt;br /&gt;  end&lt;br /&gt;  add_index :countries, :code, :unique =&gt; true&lt;br /&gt;&lt;br /&gt;# Model code&lt;br /&gt;class Country &lt; ActiveRecord::Base&lt;br /&gt;  validates_length_of :code, :is =&gt; 3&lt;br /&gt;  validates_uniqueness_of :code&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;While on my soapbox about this point, another developer I respect said this might be premature optimization.  In this specific case, I totally disagree, however, this is a good point to make in general.  You don't want to do premature optimization either.  This is something we all need to be careful about and to be aware.  &lt;br /&gt;&lt;br /&gt;This is the point where you need to &lt;a href="http://snakesgemscoffee.blogspot.com/2007/12/dont-outsource-your-thinking-process.html"&gt;think for yourself&lt;/a&gt;.  There is no cheat sheet on these types of thinking points.  The [stupid] lazy Rails developers should go back to hacking PHP senselessly or following J2EE/JEE blueprint patterns if they find thinking for themselves to develop their own rules of thumb too much work.  Remember [smart] lazy is the way to go.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;2. Stupid Easy Models&lt;/h4&gt;&lt;br /&gt;Another cardinal sin I often see in both client work I have inherited from others or open source projects is dumbing down models.  Instead of creating member methods of models that related to *what* they are and do, some Rails coders (usually not very experienced) write this functionality within the controller layer, which leads to drastic controller layer bloat.  Which is really ugly.  Remember if your code is starting to look ugly, do something about it.  The way to fix this is *almost* always to create relevant member methods on the corresponding models that this functionality works on.  &lt;br /&gt;&lt;br /&gt;One easy example of this might be to add an &lt;code&gt;authenticate&lt;/code&gt; method to the &lt;code&gt;User&lt;/code&gt; model instead of having extra logic in the &lt;code&gt;ApplicationController&lt;/code&gt;.  Think CRC instead of procedural.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;3. Stupid Easy Controller Methods&lt;/h4&gt;&lt;br /&gt;This is perhaps the most obviously harmful (from a security perspective) sin.  While traveling through the Supid Easy Rails universe of code, I almost always see unprotected controller methods that are used as filters or for utility purposes in some capacity.  This is a sin that I myself must confess to, though I haven't done so since the first 3 months of my Rails development around 2005 Q4.&lt;br /&gt;&lt;br /&gt;The following is typically what I see around:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# in SparksController&lt;br /&gt;  def check_permissions&lt;br /&gt;    return false unless current_user.has_permission?(:MANAGE_USERS)&lt;br /&gt;    true&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The problem with this is that we can do the following (unless using resource routes where default routes are taken out):&lt;br /&gt;&lt;pre&gt;GET /sparks/check_permissions?some_var=some_value&lt;/pre&gt;&lt;br /&gt;And perhaps hack into the web application.  In this case we may not be able to do anything too interesting, but there are other scenarios that this could create a very open hole in the web application.&lt;br /&gt;&lt;br /&gt;The way to fix this and keep your team's sanity from a maintenance perspective is to protect these filter or utility methods by scoping appropriate with &lt;code&gt;protected&lt;/code&gt; or &lt;code&gt;private&lt;/code&gt;, which is not difficult at all.  However, if you are a true Rubyist you will probably opt to keep your controller utility methods in &lt;code&gt;Acts::As&lt;/code&gt; mixins or similar.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/216203068/stupid-easy-7-deadly-rails-sins-part-1.html" title="Stupid Easy: 7 Deadly [Rails] Sins, Part 1" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=9132450953725179337" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/9132450953725179337/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/9132450953725179337" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/9132450953725179337" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2008%2F01%2Fstupid-easy-7-deadly-rails-sins-part-1.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2008/01/stupid-easy-7-deadly-rails-sins-part-1.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-3040156868168082852</id><published>2008-01-04T19:10:00.000-06:00</published><updated>2008-01-04T12:07:17.855-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="benchmarking" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">'Twas the night before launch...</title><content type="html">Oh fun times!  On such fateful nights you know you will find something that will screw things up unless immediately addressed.  It must be someone's law already, but if it isn't I call dibs on it and it should thus be called &lt;b&gt;"Potter's Law"&lt;/b&gt;:).&lt;br /&gt;&lt;br /&gt;On a night before launch that I recently experienced, I had a heart stopping moment.  The last 5 days of the sprint I had been churning out last minute changes based on usability feedback from the client.  In the process, I had neglected to include benchmarking and memory leak testing with the same discipline I prefer.  On the night before launch I ran my usual benchmarking scripts.  The results were pretty good except on one action.  We could have lived with that performance, but the real problem came when I ran tests to detect memory leaks in my Rails application.  Let the real fun begin!&lt;br /&gt;&lt;br /&gt;Before continuing, I should mention there is only thing I hate more than uber visual tasks (editing/creating graphics, layout tweaking, etc.) and that is debugging memory leaks.&lt;br /&gt;&lt;br /&gt;I ran the &lt;code&gt;ab&lt;/code&gt; (Apache Bench) utility on a few different types of pages in the staging environment and didn't notice any problems.  The Rails application was consistently teetering under 50M RAM.  Excellent!  Then I tried the second most requested type of page (this was a static site we were rewriting in Rails to create an easy to use domain-specific CMS - so we had live production web statistics) and my heart skipped a beat or three.&lt;br /&gt;&lt;br /&gt;Memory usage spiraled out of control.  From 49.5M the single mongrel process eventually grew to 250M after a few &lt;code&gt;ab -c2 -n100 ....&lt;/code&gt; runs.&lt;br /&gt;&lt;br /&gt;I first checked out the view since I knew the controller action code was only 6 lines (how much could go wrong there?).&lt;br /&gt;&lt;br /&gt;I tried removing different parts of the view code and rerunning my tests while monitoring the memory usage of the process.  Still no change.&lt;br /&gt;&lt;br /&gt;So I reluctantly looked in the controller and saw something like the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  def show&lt;br /&gt;    @eto = ExchangeTradedOption.find_active(params[:id])&lt;br /&gt;&lt;br /&gt;    respond_to do |format|&lt;br /&gt;      format.html # show.rhtml&lt;br /&gt;      format.xml  { render :action =&gt; "xml", :layout =&gt; false }&lt;br /&gt;      format.csv  { render :action =&gt; "csv", :layout =&gt; false }&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;What on earth was in the &lt;code&gt;ExchangeTradedOption.find_active&lt;/code&gt; method?&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    def find_active(id)&lt;br /&gt;      now = Time.now&lt;br /&gt;      find(&lt;br /&gt;        id,&lt;br /&gt;        :include =&gt; [:exchange, {:vendor_symbols =&gt; [:vendor]}],&lt;br /&gt;        :conditions =&gt; [&lt;br /&gt;          %{options.expires_at &lt;= ? AND options.active = 1 AND &lt;br /&gt;            vendor_symbols.effective_date &lt;= ? AND vendor_symbols.expiration_date &gt;= ?}, &lt;br /&gt;          now, now, now&lt;br /&gt;        ],&lt;br /&gt;        :order =&gt; 'vendor_symbols.effective_date DESC'&lt;br /&gt;      )&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Ouch!  The problem was that I still needed all vendor symbols and vendors for the view in question and didn't want to make the extra SQL queries for the Vendor on each VendorSymbol as that would have added between 5-10 extra SQL queries per action invocation.&lt;br /&gt;&lt;br /&gt;I guessed the nested includes in the find was most likely to be causing the issue.  So I refactored as followed:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# Controller action code: ExchangeTradedOptionsController#show&lt;br /&gt;  def show&lt;br /&gt;    @eto = ExchangeTradedOption.find_active(params[:id])&lt;br /&gt;    @vendor_symbols = VendorSymbol.find_active_for(params[:id])&lt;br /&gt;&lt;br /&gt;    respond_to do |format|&lt;br /&gt;      format.html # show.rhtml&lt;br /&gt;      format.xml  { render :action =&gt; "xml", :layout =&gt; false }&lt;br /&gt;      format.csv  { render :action =&gt; "csv", :layout =&gt; false }&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;# Model finder code: ExchangeTradedOption.find_active&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    def find_active(id)&lt;br /&gt;      now = Time.now&lt;br /&gt;      find(&lt;br /&gt;        id,&lt;br /&gt;        :include =&gt; [:exchange],&lt;br /&gt;        :conditions =&gt; [%{options.expires_at &lt;= ? AND options.active = 1}, now],&lt;br /&gt;      )&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;# The VendorSymbol.find_active_for method implementation is left as an exercise for the reader&lt;br /&gt;# but it is very, very simple!&lt;br /&gt;&lt;br /&gt;# Changed view to refer to @vendor_symbols array instead of @eto.vendor_symbols&lt;br /&gt;# This also helped reduce indirection and prevented Law of Demeter violations in the view code!&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Of course, I didn't leave it without verifying!  Never just guess that the problem is solved, you should always verify this with tests (either automated or manual).&lt;br /&gt;&lt;br /&gt;There were a few solutions, of course.  One is the one I provided above.  The second solution I thought of trying was removing the &lt;code&gt;vendor_symbols&lt;/code&gt; SQL conditions and sorting in Ruby.  This seemed a waste of CPU to me and extra lines of code I felt was unnecessary (remember the less code you write the less you need to maintain!).  The third solution was to execute an optimized raw SQL query myself.  I also didn't like this option as the first one presented about seemed cleaner and more maintainable going forward.  The first solution does cause more than one SQL query to be executed each time the action is run, but it is scalable as it remains constant at two queries per invocation.  In addition I added one extra instance variable, which is also not ideal, but again this didn't seem to me to be the worst problem at this stage with only two instance variables in the action being set for the view.&lt;br /&gt;&lt;br /&gt;The benchmarking results proved my assumptions correct regarding the various solutions.&lt;br /&gt;&lt;br /&gt;The moral of the story is find the best solution based on the context rather than attempting to apply a &lt;b&gt;one-query-per-action-invocation&lt;/b&gt; rule to the whole application, which might be ideal, but occasionally unrealistic and/or catastrophic.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/211241337/twas-night-before-launch.html" title="'Twas the night before launch..." /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=3040156868168082852" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/3040156868168082852/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3040156868168082852" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3040156868168082852" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F01%2Ftwas-night-before-launch.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/01/twas-night-before-launch.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5457698920128542166</id><published>2007-12-30T14:59:00.000-06:00</published><updated>2008-01-02T15:23:12.172-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="predictions" /><category scheme="http://www.blogger.com/atom/ns#" term="future" /><title type="text">2008 Predictions</title><content type="html">Since the end of the year is almost upon us close associates of mine have been asking my predictions for the new year.  While obliging them here I suspect in 12 months time I will review this blog posting in (most likely) absolute humiliation and horror as most that make predictions do.&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Web 2.0&lt;/b&gt; will die in 2008 and Web 3.0 will reach adolescence in comical fashion, but will not receive the same private equity interest of its predecessor.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Carbonless Datacenter&lt;/b&gt; will be the IT buzz phrase for a good part of 2008.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;SaaS&lt;/b&gt; will morph into yet another acronym (hopefully one that makes more sense in terms of capitalization) that will take into account yet another business model twist.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;DHH&lt;/b&gt; will continue to be perceived by many inside and outside the Ruby/Rails world as an arrogant a$$.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Lastly, I predict that Tony Blair will concede and sincerely apologize for his disastrous 2002 prediction that Weapons of Mass Destruction (WMD) exist in Iraq that has already caused a much higher death toll (that continues to mount) orders of magnitude higher than the unmistakable military fiasco of the Charge of the Light Brigade.  Sorry I forgot Mr Blair doesn't have a sincere atom in his body and this is only a tech prediction list.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/211241338/2008-predictions.html" title="2008 Predictions" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5457698920128542166" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/5457698920128542166/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5457698920128542166" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5457698920128542166" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F12%2F2008-predictions.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/12/2008-predictions.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5223703299928477663</id><published>2007-12-06T22:54:00.000-06:00</published><updated>2007-12-07T01:40:19.360-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="opinion" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="outsourcing" /><category scheme="http://www.blogger.com/atom/ns#" term="php" /><category scheme="http://www.blogger.com/atom/ns#" term="outsource" /><category scheme="http://www.blogger.com/atom/ns#" term="think" /><category scheme="http://www.blogger.com/atom/ns#" term="politics" /><category scheme="http://www.blogger.com/atom/ns#" term="apple" /><title type="text">Don't outsource your thinking process.  Think for yourself!</title><content type="html">In the wirlwind of political turmoil and occasional nuance of late with the upcoming primary elections almost upon us, I realized just how offensive the two-party primary elections ought to be to a "free" country.  Why isn't everyone else as outraged as I am?&lt;br /&gt;&lt;br /&gt;Traversing various circles I see Democrats hashing out their own political differences on foreign policy, social security and the overloaded and antiquated driver's license system to create a unified platform for the general election.  As if *ALL* Democrats think the exact same way.  Republicans on the other hand are dumb-founded and depressed by the lack of quality mainstream and viable candidate(s), not to mention trying to figure out what on earth their united platform is after a president that has probably done more to harm their party than any other individual in the last 25 years (hey, don't look at me or the Democrats, neither of us voted for him in the first place!:)).  Oh, I do enjoy being smug!&lt;br /&gt;&lt;br /&gt;Being a foreigner I always found it odd that Americans (generally) seem more willing to outsource their political reasoning to one of two political parties (at least in contrast with my European experiences).  I have witnessed the deferral of political reasoning to their parties without thinking on so many occasions I have lost count.  If their *party* is anti-war, then they need to be too, no questions asked.  Alternatively if they are with the *other party* they need to buy into the whole Cheney-masterminded war on terror doctrine, where we must "take the war to the enemy", whatever that means.&lt;br /&gt;&lt;br /&gt;Now back to the technical world (and this transcends borders).  I see the same type of decision/reasoning outsourcing.  In 1997, Apple coined the slogan "Think Different".  Fast forward 10 years and you have an ever growing Apple fan base that doesn't question (at least not Apple or Jobs), it just doesn't "think".  I am not saying Apple hasn't done anything good, but all you Apple fan boys (and girls) just think for yourselves once in a while, puh-lease!&lt;br /&gt;&lt;br /&gt;To be fair and candid, it is not limited to the Apple fan base.  The Linux community (of which I am party) has been a huge propaganda machine for just as long.  A friend of mine who is primarily a Windoze user (sorry, I just couldn't resist) suggests that the Linux community has been pushing Linux (or at least certain distributions of it) as "just as usable out of the box as Windows", which he thinks is a sad and pathetic misrepresentation.  To be honest, I agree with him.  I don't think any Linux distribution is quite as end-user friendly as Windows out of the box and to me Linux is definitely NOT about that.  The Ubuntu weekender geeks that desperately try to be the geekiest person in the room should take note (among others).  Forget pushing Linux propaganda on others (remember we don't like Jobs-indoctrinated fan boys/girls selling us the Apple way either).  Accept Linux for what it is: a more exclusive club that sets the bar higher than the others!  Why should we be trying to lower the bar or grade?  Let the newbies reach for the higher bar to get started, so we can attract a higher quality user base than the other two options.  The BSD community is a great example!&lt;br /&gt;&lt;br /&gt;I also feel this way on the Ruby front.  I do wish all those nuts-oh "Rails rulz" propagandists would steer clear of all the PHP and Java bashing and Rails hyping.  Do you really want all the subpar PHP and Java people (the ones that need hype so they can outsource their decision making to move over) in our world?  I personally only want to cherry pick the Java, PHP, Python, etc. developers that actually think for themselves and willingly and enthusiastically step over to the Ruby side.&lt;br /&gt;&lt;br /&gt;In summary, if you want someone else to think on your behalf go ahead it is a "free" country in that respect (if you aren't in a free country remember nobody owns your internal thoughts so you may as well abuse that freedom as much as you can:)!).  However, you should also realize that it is only the free-thinkers that don't conform to mass expectations and opinions that are the ones changing things (mostly for the better, but feel free to disagree with me and form your own opinion:)).&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/202433176/dont-outsource-your-thinking-process.html" title="Don't outsource your thinking process.  Think for yourself!" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5223703299928477663" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/5223703299928477663/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5223703299928477663" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5223703299928477663" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F12%2Fdont-outsource-your-thinking-process.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/12/dont-outsource-your-thinking-process.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-1165049990959760831</id><published>2007-11-10T07:29:00.004-06:00</published><updated>2008-06-29T23:35:30.209-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="scm" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title type="text">My .gitconfig</title><content type="html">&lt;pre&gt;&lt;code&gt;&lt;br /&gt;[user]&lt;br /&gt;  name = Susan Potter # make sure you change this&lt;br /&gt;  email = me@susanpotter.net # make sure you change this&lt;br /&gt;[color]&lt;br /&gt;  diff = auto&lt;br /&gt;  status = auto&lt;br /&gt;  branch = auto&lt;br /&gt;[diff]&lt;br /&gt;  rename = copy&lt;br /&gt;  color = auto&lt;br /&gt;[apply]&lt;br /&gt;  whitespace = strip&lt;br /&gt;[pager]&lt;br /&gt;  color = true&lt;br /&gt;[status]&lt;br /&gt;  color = auto&lt;br /&gt;[alias]&lt;br /&gt;  co = "checkout"&lt;br /&gt;  ci = "commit"&lt;br /&gt;  ciall = "commit -a -v"&lt;br /&gt;  unmerge = "reset --hard ORIG_HEAD"&lt;br /&gt;  lsbr = "branch -a" # list all branches, even remote ones&lt;br /&gt;  mkbr = "branch" # create branch if you specify a branch name after it, e.g. git mkbr upgrading_rails&lt;br /&gt;  # remove branch named after it, e.g. git rmbr upgrading_rails&lt;br /&gt;  rmbr = "branch -d"&lt;br /&gt;  # rename branch from one name to another&lt;br /&gt;  mvbr = "branch -m"&lt;br /&gt;  # &lt;br /&gt;  track = "branch --track"&lt;br /&gt;  # list all tags, to keep commands consistent, e.g. git lstag&lt;br /&gt;  lstag = "tag -l"&lt;br /&gt;  # create a new tag based on specified commit&lt;br /&gt;  mktag = "tag -a"&lt;br /&gt;  # remove existing tag by name&lt;br /&gt;  rmtag = "tag -d"&lt;br /&gt;  # rename tag from one name to another&lt;br /&gt;  mvtag = "tag -m"&lt;br /&gt;  # create new remote repository for project&lt;br /&gt;  mkrem = "remote add"&lt;br /&gt;  # list remote repositories&lt;br /&gt;  lsrem = "remote"&lt;br /&gt;  # show status, keep same as svn command I used most frequently&lt;br /&gt;  st = "status"&lt;br /&gt;  # another alias for status that some scripts might use&lt;br /&gt;  stat = "status"&lt;br /&gt;  # fetch and rebase from svn repository&lt;br /&gt;  spull = !git svn fetch &amp;&amp; git svn rebase&lt;br /&gt;  # push keeping each local commit as atomic.&lt;br /&gt;  spush = !git svn dcommit&lt;br /&gt;  # initialize all submodules&lt;br /&gt;  modinit = "submodule init"&lt;br /&gt;  # update all submodules&lt;br /&gt;  modup = "submodule update"&lt;br /&gt;  # show status of all submodules&lt;br /&gt;  modst = "submodule status"&lt;br /&gt;  # add new submodule, i.e. git modadd module-name url&lt;br /&gt;  modadd = "submodule add"&lt;br /&gt;  # show last 15 log entries&lt;br /&gt;  recentlog = "log -n 15"&lt;br /&gt;  # push local committed changes to rubyforge and origin (usually GitHub)&lt;br /&gt;  osspush = !git push rubyforge master &amp;&amp; git push origin master&lt;br /&gt;  # pull changes from rubyforge and origin (usually GitHub)&lt;br /&gt;  osspull = !git pull rubyforge master &amp;&amp; git pull origin master&lt;br /&gt;  # sync (pull then push) from rubyforge and origin (usually GitHub)&lt;br /&gt;  osssync = !git osspull &amp;&amp; git osspush&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Place your &lt;code&gt;.gitconfig&lt;/code&gt; file in your home directory, e.g. &lt;code&gt;/home/username&lt;/code&gt;&lt;br /&gt;Last updated: 2008-06-28&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/308850365/my-gitconfig.html" title="My .gitconfig" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=1165049990959760831" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/1165049990959760831/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1165049990959760831" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1165049990959760831" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F11%2Fmy-gitconfig.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/11/my-gitconfig.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-937334212437839340</id><published>2007-11-05T02:18:00.000-06:00</published><updated>2007-11-05T02:40:11.889-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="rubyforge" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">Twitter4R v0.3.0</title><content type="html">After Twitter.com added a few extra APIs for favoriting statuses in October, I finally got around to adding them to Twitter4R tonight.  Since there is new functionality I have released it as version 0.3.0.&lt;br /&gt;&lt;br /&gt;To install all you need to do is:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ sudo gem install twitter4r&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The Rubyforge mirrors might still be syncing if you are doing this soon after I post this message.&lt;br /&gt;&lt;br /&gt;The changes to the library include:&lt;ul&gt;&lt;li&gt;Added &lt;code&gt;Twitter::Client#authenticate?&lt;/code&gt; method that is a lightweight way to verify a Twitter user's credentials&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;em&gt;Favorites&lt;/em&gt;&lt;/b&gt;: allows Twitterers to add statuses to their favorites, list all their current favorites and remove any statuses from the list.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Example code for verifying a user would look like:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;gem('twitter4r', '&gt;=0.3.0')&lt;br /&gt;require('twitter')&lt;br /&gt;&lt;br /&gt;client = Twitter::Client.new&lt;br /&gt;unless client.authenticate?("macdeveloperthatlovesleopard", "iamasciolists")&lt;br /&gt;  puts "Password does not describe user well!"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if client.authenticate?("developerthatdoesnotpretendtobegraphicdesigner", "seriousdevelopernotfakestevejobswannabe")&lt;br /&gt;  puts "Password does describe user well!"&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Example code for using the favorites API:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;gem('twitter4r', '&gt;=0.3.0')&lt;br /&gt;require('twitter')&lt;br /&gt;require('twitter/console')&lt;br /&gt;&lt;br /&gt;client = Twitter::Client.from_config('some/path.yml')&lt;br /&gt;statuses = client.favorites&lt;br /&gt;ids = statuses.collect {|s| s.id }&lt;br /&gt;# clean favorites list by deleting&lt;br /&gt;statuses.each {|s| client.favorite(:remove, s) }&lt;br /&gt;&lt;br /&gt;# now add back first status id from original favorites list&lt;br /&gt;client.favorite(:add, ids[0])&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/202433177/twitter4r-v030.html" title="Twitter4R v0.3.0" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=937334212437839340" title="11 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/937334212437839340/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/937334212437839340" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/937334212437839340" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F11%2Ftwitter4r-v030.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/11/twitter4r-v030.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5015279754384886299</id><published>2007-10-30T23:11:00.000-05:00</published><updated>2007-10-31T00:00:41.551-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="cryptography" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><category scheme="http://www.blogger.com/atom/ns#" term="metafusion" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">The Democratic debate, Ann Coulter and cryptographic utilities for Ruby application developers</title><content type="html">An unlikely trio, but...&lt;br /&gt;&lt;br /&gt;After watching the flip flop of Clinton in the Democratic debate, the subsequent carcass ravaging by her competition, UFO spotting by spock (aka Kucinich) and two great stinging one-liners from Joe Biden about the presidential [dis]qualification of candidate 911, I stumbled across the infinitely dim and unimpressive Ann Coutler.  She was attempting to justify yet another deliberately outlandish statement she made last week, a desperate bid to remain in the limelight to which she is so addicted.&lt;br /&gt;&lt;br /&gt;At this point, I remembered I wrote a RubyGem a few weekends ago that might be able to decrypt these events and make sense of it all (well maybe!?).&lt;br /&gt;&lt;br /&gt;A few weekends ago I released &lt;code&gt;metafusion-crypto&lt;/code&gt; as a Ruby Gem.  I hadn't announced it yet as it got lost in the shuffle of some personal matters that forced me to take five days off work unexpectedly.  So here is the belated introduction to that small, humble Gem.&lt;br /&gt;&lt;br /&gt;This &lt;code&gt;metafusion&lt;/code&gt; sub-project is basically just two utility classes: &lt;code&gt;Metafusion::Crypo::PrivateKey&lt;/code&gt; and &lt;code&gt;Metafusion::Crypo::DigitalSignature&lt;/code&gt; for application developers that don't want to worry about twiddling bits.  To install you only need to do the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ sudo gem install metafusion-crypto&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;An example of &lt;code&gt;DigitalSignature&lt;/code&gt; usage might be:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;require 'metafusion/crypto'&lt;br /&gt;&lt;br /&gt;priv_key = Metafusion::Crypto.generate_key_pair&lt;br /&gt;# this returns OpenSSL::PKey::RSA object into priv_key&lt;br /&gt;&lt;br /&gt;include Metafusion::Crypto&lt;br /&gt;sig = DigitalSignature.from_keys('rsa_key.pub', 'rsa_key')&lt;br /&gt;original_text = "my clear text message"&lt;br /&gt;crypted_text = sig.encrypt(original_text)&lt;br /&gt;plain_text = sig.decrypt(crypted_text)&lt;br /&gt;puts "It worked - let's celebrate!" if original_text == plain_text&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;An example of &lt;code&gt;PrivateKey&lt;/code&gt; usage might be:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;include Metafusion::Crypto&lt;br /&gt;pkey = PrivateKey.new('mypassphrase')&lt;br /&gt;original_text = 'Yo yo yo.  What up dog?'&lt;br /&gt;crypted_text = pkey.encrypt(original_text)&lt;br /&gt;plain_text = pkey.decrypt(crypted_text)&lt;br /&gt;puts "Let's roll and celebrate - it worked" if original_text == plain_text&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I look forward to application developer's feedback.&lt;br /&gt;&lt;br /&gt;I promise to return to the  agile anti-pattern "series" soon.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; Since two people asked, I have stuck to my tradition of releasing with only 100% C0 code coverage of the project's RSpec examples.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/202433178/democratic-debate-ann-coulter-and.html" title="The Democratic debate, Ann Coulter and cryptographic utilities for Ruby application developers" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5015279754384886299" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/5015279754384886299/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5015279754384886299" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5015279754384886299" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F10%2Fdemocratic-debate-ann-coulter-and.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/10/democratic-debate-ann-coulter-and.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-2409759616232748903</id><published>2007-10-18T21:16:00.000-05:00</published><updated>2007-10-18T21:58:55.662-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="anti-patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="kaizen" /><category scheme="http://www.blogger.com/atom/ns#" term="agile practices" /><title type="text">Agile Anti-Patterns, Part 1</title><content type="html">In the last 12 months I had the fortune to work at a client that calls themselves "agile". In fact they use marketing blurbs similar to "on the cutting edge of agile Ruby on Rails development" (I said *similar* because I didn't want to identify them uniquely).  &lt;br /&gt;&lt;br /&gt;The problem is when I briefly worked on a project for them, the truth was very far from their marketing spiel.  At a minimum I can say that this was the case on the particular project I briefly worked on, but more likely to have been much more wide spread in the firm since the consulting manager managed all the client projects from what I could tell.&lt;br /&gt;&lt;br /&gt;Why was I fortunate?  Well first of all, it was a very brief encounter.  I just couldn't bring myself to work in that environment for long (and thus you will not find it on my resume at all - nice try).  Perhaps that says something about me too (I know it does - it is a liability, I realize this and plan to work on it, but on the other hand I feel as if I shouldn't have to compromise my professional values to the level of this case).  Secondly, like I imagine is the case with most people, I learn more from bad experiences than good experiences.&lt;br /&gt;&lt;br /&gt;I would also like to say this is by no means the only company that likely falls into this "let's talk about agile so much we pretend that in itself is being agile" trap.  I see 1,000s of job ads or consulting firm spiels saying agile-this, agile-that.  Probably only 10-20% of the spiels are decently aligned with reality (of course, I have no way of knowing or measuring this, but it seems like a sensible guess to me;)).&lt;br /&gt;&lt;br /&gt;Now, is any agile team perfect?  No.  At least not in my experience.  Maybe there are perfect teams and I am just a loser that has never experienced one, but since I have never met a perfect person ever, I imagine this to be improbable.  The reason for my deduction is that since software agility is based on people and relationships NOT just tools, then only a team with perfect members could even dream of producing the perfect dynamic.  The thing is, you don't need an agile team to be perfect.  That is the premise of each agile practice I follow personally.  If you think about it, agile practices assume people at their core are faulty some of the time in some way, because we are mere mortals, not software gods (though at times developers do get a God-complex, which is one of our many faults - I am guilty here too)!&lt;br /&gt;&lt;br /&gt;Ooops, tangent, but is serves a point here too.  I do not ever wish to imply that following the letter of all the agile practice "rules" will make you truly and *perfectly* agile.  I do not even think that is even the point.  For me it comes down to Kaizen, which in short means, to iteratively eliminate waste from a process each time you repeat and to break those iterations down into bite size pieces so you can track and measure progress (actually that is a very coarse way to describe Kaizen, which is a word I love so much I tattooed it on my body somewhere - just kidding.....or am I?).  Feel free to search the web for a better description (there are a few), but it is a word the more you read about (at least for me) the more you appreciate.  &lt;br /&gt;&lt;br /&gt;Perhaps we will never be perfect agile developers.  Perhaps we will never be perfect business analysts, coders, managers, deployers, system administrators, database administrators, etc.  That to me is almost irrelevant.  The idea is we just need to strive to simply "do better" each time and have the right attitude.&lt;br /&gt;&lt;br /&gt;This was really just the kick off piece (aka rant) for this "series" on anti-patterns relating to agile practices.  I'll have concrete examples coming soon in part 2, 3, etc.&lt;br /&gt;&lt;br /&gt;Stay tuned.&lt;br /&gt;&lt;br /&gt;PS If you are searching for an "agile" development post, don't despair, there are some decently agile places out there.  They may not be perfect, but hopefully better than the client project I will discuss.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/202433179/agile-anti-patterns-part-1.html" title="Agile Anti-Patterns, Part 1" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=2409759616232748903" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/2409759616232748903/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2409759616232748903" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2409759616232748903" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F10%2Fagile-anti-patterns-part-1.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/10/agile-anti-patterns-part-1.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-4685028030080506695</id><published>2007-10-11T21:16:00.000-05:00</published><updated>2007-10-11T23:17:29.571-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="cdbaby" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="dhh" /><title type="text">Coming out....in support of DHH [to some extent]</title><content type="html">Since today is &lt;a href="http://www.hrc.org/issues/coming_out.asp"&gt;National Coming Out Day&lt;/a&gt; in the US I thought I would use it somehow in my blog entry.  Yes folks I am "coming out" in support of [some of] DHH's decisions.&lt;br /&gt;&lt;br /&gt;Earlier today I noticed a lot of blog chatter regarding Rails and what various people think it *should* or should not be.  While I agree with some of these people's sentiments that DHH is an arrogant ass, I also think he has made *some* smart decisions (though on a number of mid/lower-level issues I think he has it totally wrong).  Now reread this paragraph until you get the point that I still think he is an arrogant ass with a God complex.&lt;br /&gt;&lt;br /&gt;Firstly, let's discuss the "Twitter" issue.  Yes, I use Twitter (occasionally), though I see it's biggest impact (for my personal interests) in marketing rather than tweeting every time I use the bathroom (note: I am not part of the look-at-me-NOW-Gawd-damn-it generation - I was a humble 70s baby).  In fact, the marketing potential is what drove me to develop &lt;a href="http://twitter4r.rubyforge.org"&gt;Twitter4R&lt;/a&gt; in the first place.  What I don't like about Twitter is due to their own lack of foresight they desperately tried to blame a framework!  An application framework because they couldn't get their act together to do the necessary scalability testing of their whole deployment environment (which includes many things, only one of them is the application framework) before hand.  This is the same application framework that got them rolled out into production earlier than they would have with other frameworks.  The same framework that allows them NOW to scale to crazy amounts of hits per second!  I attempted to follow the dialog between the Twitter developers and Rails Core team, though not too successfully because it occurred through non-interlinked blog posts and comments.  However, from what I could gather the Twitter folk seemed to think it should be up to the application framework to create an already baked in way for them to setup replication models.  If they were using a PHP framework, they wouldn't have bothered asking since all the DB code is in the view anyway!  Why is that the responsibility of the application framework?  Now if Rails has somehow prevented them from being able to create ActiveRecord extensions to do this, I might understand, but as far as I can see....this just isn't so.&lt;br /&gt;&lt;br /&gt;Secondly, the CDBaby rant.  If CDBaby took 2 years to release using Ruby/Rails, then they must have had much bigger problems than Rails itself!  Sorry to be blunt, but who takes that long anymore, even in a Java stack?&lt;br /&gt;&lt;br /&gt;Ok, now for some leveling.  I still think DHH is an ass and an extremely arrogant ass at that.  I still think he has ridiculous ideas about trademarking logos (that he didn't even pay for), definitions of what components are, how vendor/* is better than utilizing Ruby Gems in virtualized or dedicated environments (WTF?) and general dependency loading in Rails.  Plus, did I mention I think he is an arrogant ass?  Not to mention a former PHP programmer...enough said!&lt;br /&gt;&lt;br /&gt;Good night.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/202433180/coming-outin-support-of-dhh-to-some.html" title="Coming out....in support of DHH [to some extent]" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=4685028030080506695" title="3 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/4685028030080506695/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4685028030080506695" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4685028030080506695" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F10%2Fcoming-outin-support-of-dhh-to-some.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/10/coming-outin-support-of-dhh-to-some.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-4283818661445776536</id><published>2007-09-23T20:46:00.000-05:00</published><updated>2007-09-23T20:55:28.630-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="rubyforge" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">Twitter4R Announcements</title><content type="html">First off I have been meaning to post an entry letting people know of a recently released Rails application written by Sergio Santos called &lt;a href="http://twitternotes.com"&gt;TwitterNotes&lt;/a&gt; that is using the &lt;a href="http://twitter4r.rubyforge.org" title="Definitive Ruby bindings for Twitter REST API"&gt;Twitter4R&lt;/a&gt; gem.&lt;br /&gt;&lt;br /&gt;Thanks Sergio (and anyone else that worked on the project - sorry if I left you off).&lt;br /&gt;&lt;br /&gt;Also Sergio emailed yesterday requesting message paging support with a suggested patch (thanks for contributing back - &lt;b&gt;muchas gracias&lt;/b&gt;).  This evening I released Twitter4R version 0.2.5 that incorporates the necessary code changes for this support.&lt;br /&gt;&lt;br /&gt;What does this mean?&lt;br /&gt;&lt;br /&gt;Previously you would have only been able to get the last 20 sent/received direct messages from the Twitter4R bindings doing something like the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;messages = client.messages(:sent)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Now you can request specific pages like so:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;messages = client.messages(:sent, :page =&gt; 2)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The same is true for the &lt;tt&gt;:received&lt;/tt&gt; case.&lt;br /&gt;&lt;br /&gt;To install the Twitter4R RubyGem simply run the following in your terminal/console:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ sudo gem install twitter4r&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Give the Rubyforge mirrors a few hours to sync if you are only getting Twitter4R v0.2.4.&lt;br /&gt;&lt;br /&gt;Thanks and enjoy!&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/SnakesGemsCoffee/~3/202433181/twitter4r-announcements.html" title="Twitter4R Announcements" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=4283818661445776536" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://snakesgemscoffee.blogspot.com/feeds/4283818661445776536/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4283818661445776536" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4283818661445776536" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email></author><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=SnakesGemsCoffee&amp;itemurl=http%3A%2F%2Fsnakesgemscoffee.blogspot.com%2F2007%2F09%2Ftwitter4r-announcements.html</feedburner:awareness><feedburner:origLink>http://snakesgemscoffee.blogspot.com/2007/09/twitter4r-announcements.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-2211343703077995732</id><published>2007-09-21T00:45:00.000-05:00</published><updated>2007-09-21T12:34:11.882-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="data" /><category scheme="http://www.blogger.com/atom/ns#" term="activewarehouse" /><category scheme="http://www.blogger.com/atom/ns#" term="warehouse" /><category scheme="http://www.blogger.com/atom/ns#" term="activewarehouse-etl" /><category scheme="http://www.blogger.com/atom/ns#" term="ETL" /><category scheme="http://www.blogger.com/atom/ns#" term="datawarehouse" /><title type="text">Custom Processors for ActiveWarehouse ETL</title><content type="html">For anyone interested in extending &lt;a href="http://activewarehouse.rubyforge.org/etl/"&gt;ActiveWarehouse ETL&lt;/a&gt;'s features with custom pre/post processors, I thought I would share this piece of code that I wrote in August for a personal project I am working on.  The example should provide you with enough details for you to create your own custom processors.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# Written by Susan Potter &lt;mbbx6spp@rubyforge.org&gt; under open source MIT license.&lt;br /&gt;# August 12, 2007.&lt;br /&gt;&lt;br /&gt;require 'net/ftp'&lt;br /&gt;&lt;br /&gt;module ETL&lt;br /&gt;  module Processor&lt;br /&gt;    # Custom pre-processor to download files via FTP before beginning control process.&lt;br /&gt;    class FtpDownloaderProcessor &lt; ETL::Processor::Processor&lt;br /&gt;      attr_reader :host&lt;br /&gt;      attr_reader :port&lt;br /&gt;      attr_reader :remote_dir&lt;br /&gt;      attr_reader :files&lt;br /&gt; 