<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Ruby Best Practices</title><link>http://blog.rubybestpractices.com/</link><description>Increase your productivity -- Write Better Code</description><language>en-us</language><item><title>James will be right back after these interruptions</title><description>&lt;h1&gt;James will be right back after these interruptions&lt;/h1&gt;
&lt;h3&gt;How many times has this happened to you?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;[&lt;span class="caps"&gt;WAY&lt;/span&gt;-&lt;span class="caps"&gt;TOO&lt;/span&gt;-&lt;span class="caps"&gt;LOUD&lt;/span&gt; TV &lt;span class="caps"&gt;VOICE&lt;/span&gt;]: You&amp;#8217;re working on some code, making good progress, solving a particular issue, when Oh No!,  &lt;br /&gt;
you&amp;#8217;ve run into a new bug.  Now what?&lt;/p&gt;
&lt;p&gt;You could open a browser, go to your issue tracker, and open a ticket. But that could take several minutes!&lt;/p&gt;
&lt;p&gt;Your train of thought would be derailed, code momentum lost, and time wasted!  But you can&amp;#8217;t just let that bug slide away!  Don&amp;#8217;t you wish there was an easier way to handle this?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As far as I know there have been no late-night TV commercials selling solutions to software developers, but there are times we could use them.  The problem of staying focused on one task, while not ignoring others, is a real one, at least for me, and I suspect many others.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what happens: You pick a bug to fix or feature to add, and set out to complete it.  Almost inevitably, though, you encounter other issues or interests.  If it looks to be minor, it&amp;#8217;s tempting to fix it right then. Sometimes this is trivial; a typo in the UI text in the file you&amp;#8217;re working on.  These are the cases where even adding a &lt;span class="caps"&gt;FIXME&lt;/span&gt; or &lt;span class="caps"&gt;TODO&lt;/span&gt; to the code would be about as much work as just fixing the problem.&lt;/p&gt;
&lt;p&gt;Other times, though, it&amp;#8217;s obvious that this new concern will take a bit of time. Or, maybe worse, there&amp;#8217;s no simple way to quickly judge how much work would be needed.  Dropping what you&amp;#8217;re doing to fix something else isn&amp;#8217;t a recommended practice.  Given that each task is prone to uncover a new task, you&amp;#8217;re doomed from the start to never finish anything.&lt;/p&gt;
&lt;p&gt;That leaves two (admittedly broad) options.  One is to ignore everything that isn&amp;#8217;t immediately related to the immediate task.  The other is to stop what you&amp;#8217;re doing and make a note of the problem.  But how long is &lt;strong&gt;that&lt;/strong&gt; going to take?&lt;/p&gt;
&lt;h3&gt;Now watch this!&lt;/h3&gt;
&lt;p&gt;Lately I&amp;#8217;ve been interested in focus and attention.  Like many people my ability to focus often varies.  For tasks that don&amp;#8217;t have an intrinsic lure (e.g. bug fixing) I work best if I stick to well-defined tasks over specific durations.  (This is an approach sometimes referred to as time boxing. Some formal examples are the &lt;a href="http://www.pomodorotechnique.com"&gt;Pomodoro Technique&lt;/a&gt;  and the &lt;a href="http://www.markforster.net/autofocus-system"&gt;Autofocus System&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;An important aspect is to really spend that time doing that specific task.  If it leads to assorted sub-tasks,  it matters how much time those things take, since time is limited.  If necessary digressions take too long, the whole &amp;#8220;do one thing&amp;#8221; plan falls apart, as does one&amp;#8217;s focus.&lt;/p&gt;
&lt;p&gt;So now we have two problems.  One, the code distraction that just appeared, and two, the need for a way to quickly and effectively record it. Here&amp;#8217;s what I&amp;#8217;ve been doing about that second one, which leads to solving the first one.&lt;/p&gt;
&lt;p&gt;I first started looking into the idea  of rapid notation when I was working a contract job that needed some detailed time tracking.  After spending two hours adding what seemed like a simple feature to a Java Web app I wanted to be able to look a back a see just where the time went.&lt;/p&gt;
&lt;p&gt;I started by using a plain text file.  Every so often, when I found myself doing something that didn&amp;#8217;t seem to be directly adding to a solution (for example, rebooting the app server to fix &lt;span class="caps"&gt;JVM&lt;/span&gt;  out-of-memory issues) I made a note.&lt;/p&gt;
&lt;p&gt;It worked OK, but it was a bit slow.  There was a lot of friction on opening the file, adding text, and saving it.  Even leaving the file open all the time was not helpful enough.  As I usually work at the command line I wrote a small Ruby script to let me write my notes right from the terminal.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;

    #!/usr/bin/env ruby

    @data_file = "/home/james/data/_at-today-please.txt" 

    def ts; Time.now.to_s; end

    def edit
      IO.popen "gvim #{@data_file} &amp;amp; "
    end

    def add
      msg = ARGV.join( ' ' ).to_s.strip
      File.open(@data_file, "a") do |f|
        f.print "--- #{ts}:\n\t#{msg}\n\n\n"
      end
    end

    ARGV.empty? ? edit : add
 &lt;/pre&gt;
&lt;p&gt;I&amp;#8217;m not making any claims for this code other than follows the principal of &lt;span class="caps"&gt;WFJ&lt;/span&gt;: Works for James.  I have it in a file at ~/bin/@; adding a short note is about as simple as it gets.  If I need to add something complex (or something that just doesn&amp;#8217;t play well at the command line), I pass no arguments and edit the file directly.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s flawed, of course.  Depending on the shell, different chracters (quote marks, for example) can throw things off.  But it works good enough for quick time-stamped notes.&lt;/p&gt;
&lt;h3&gt;But wait, there&amp;#8217;s more!&lt;/h3&gt;
&lt;p&gt;Some time after this hack I found myself working with &lt;a href="http://trac.edgewall.org"&gt;Trac.&lt;/a&gt;  It does a good job of coordinating source code, issues, project planning, and assorted other goodies.  Entering bugs, though, was a drag.  The Web UI meant entering text in multiple fields and selecting values from a few dropdown lists.   Once again, to keep from getting too distracted  while developing I wrote some code to post tickets from the command line.  The project was called Tracula (because the key to any project is a clever punny name) and helped my development process by removing some of the friction of tracking issues uncovered during development.  Usage hit some snags when different versions of Trac required somewhat more gnarly means of athenticating &lt;span class="caps"&gt;HTTP&lt;/span&gt; posts, while my use of Trac dropped in favor of other project management tools.&lt;/p&gt;
&lt;p&gt;Nonetheless, the general idea stayed with me, and when picking any tool I look to see if there&amp;#8217;s a simple &lt;span class="caps"&gt;HTTP&lt;/span&gt; interface that allows for automation and custom command-line driven clients.&lt;/p&gt;
&lt;p&gt;I now have &lt;a href="http://github.com/Neurogami"&gt;several projects on GitHub.com&lt;/a&gt;, which has become much like a hosted Trac, but with more ass-kickery. Each repo can have an issue tracker, and I&amp;#8217;ve just started using it for my &lt;a href="http://github.com/Neurogami/rhesus/tree/master"&gt;Rhesus&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;Rhesus is yet another &lt;span class="caps"&gt;WFJ&lt;/span&gt; tool that has been evolving as I use it.  I had been making notes about the code in various places when I realized there was an actual bug tracker available.  I added a few issues, and immediately wondered if there was an &lt;span class="caps"&gt;API&lt;/span&gt; for this.  And &lt;a href="http://develop.github.com"&gt;there is&lt;/a&gt; (thanks, Engine Yard!).&lt;/p&gt;
&lt;p&gt;With Tracula there were three key options: fetch a list of open tickets; post a single new ticket; do a batch post of mulitple tickets.  How to do these with the GitHub &lt;span class="caps"&gt;API&lt;/span&gt;?  Well, fetching tickets is really easy, since there&amp;#8217;s no need for any authentication.  If you have &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt; installed, it&amp;#8217;s a just a well-crafted &lt;span class="caps"&gt;URL&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;    http://github.com/api/v2/json/issues/list/Neurogami/rhesus/open&lt;/pre&gt;
&lt;p&gt;will give you a list of open Rhesus issues.  Very slick, but since the results are a &lt;span class="caps"&gt;JSON&lt;/span&gt; string, maybe not the easiest thing to read. You can change that to &lt;span class="caps"&gt;XML&lt;/span&gt; or &lt;span class="caps"&gt;YAML&lt;/span&gt; if you like, but for better control, how about using some Ruby to slurp it in and present it in a more refined manner?&lt;/p&gt;
&lt;h3&gt;And if you call &lt;span class="caps"&gt;RIGHT&lt;/span&gt; &lt;span class="caps"&gt;NOW&lt;/span&gt; &amp;#8230;&lt;/h3&gt;
&lt;p&gt;A basic approach to showing the current set of open issues might be: make a call to the GitHub &lt;span class="caps"&gt;API&lt;/span&gt;; parse the results into some useful Ruby structure; selectively show the details to avoid overcrowding the screen.  One thing you need to consider, though, is just how often will the list of issues change relative to the number of times you want to see it.  In my case, I&amp;#8217;ll likely want to see the list way more often than it will change.  To make life easier both for me and for GitHub, I want my code to cache the list of issues and render that cache by default.   I&amp;#8217;m also going to make this a Rake task, and I&amp;#8217;ll allow for a parameter to indicate that the cache should be updated.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;

  namespace :issues do
    desc 'Open issues'
    task :open do
      paged_issues ENV['GH_NO_CACHE']
    end
  end
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;page_issues&lt;/code&gt; method will grab the set of issues and render them one by one:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;

  def ___
    warn "\n" + '_' * 30
  end

  def paged_issues no_cache = false
    ARGV.clear # Otherwise the call to gets will immediately find input
    warn "Hit &amp;lt;enter&amp;gt; after each issue to see the next one."
    issues(no_cache).each do |issue|
      ___
      warn "Title: #{issue['title']}"
      warn "Details: \n#{issue['body']}"
      ___
      gets
    end
    warn "\nThat's it!"
  end
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;issues&lt;/code&gt; method will either pull from the cache or fetch anew from GitHub&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;

    def issues no_cache = false
      issues_cache = 'issues.yaml'
      if no_cache || !File.exist?(issues_cache)
         warn "Reloading issues from GitHub ..."
         File.open( issues_cache, 'w'){ |f| f.puts get_issues }
      end
      YAML.load(IO.read(issues_cache))['issues']
    end
&lt;/pre&gt;
&lt;p&gt;This allows for&lt;/p&gt;
&lt;pre&gt;rake issues:open&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;rake issues:open  GH_NO_CHACHE=true&lt;/pre&gt;
&lt;h3&gt;Operators are standing by!&lt;/h3&gt;
&lt;p&gt;What about adding a new issue?  The docs say that an authorized &lt;span class="caps"&gt;POST&lt;/span&gt; is needed.  And what&amp;#8217;s an authorized &lt;span class="caps"&gt;POST&lt;/span&gt;? It&amp;#8217;s an &lt;span class="caps"&gt;HTPP&lt;/span&gt; &lt;span class="caps"&gt;POST&lt;/span&gt; with parameters for your user name (&lt;code&gt;login&lt;/code&gt;) and your authorization token (&lt;code&gt;token&lt;/code&gt;).  The latter may be found on your GitHub account page.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;

     namespace :issues do
      # ...
      desc 'Create a new issue'
      task :create do
        issue_details = ENV['DETAILS'].to_s.strip
        if issue_details.empty?
          warn "No issue details!"
        else
          title, body =  issue_details.split(' -- ', 2)
          create_issue  title, body 
        end
      end
    
     # ...
     end
&lt;/pre&gt;
&lt;p&gt;Rake is not the most friendly when it comes to passing arguments, so to (somewhat) simplify things I decided to use one parameter that employed a delimiter to set off the issue title and body.  The code that does the actual ticket creation is oblivious to this, and could easily be used in a regular Ruby app.  The choice of making something a Rake task or a stand-alone executable depends on how you expect to use it.  With Rake, it&amp;#8217;s easy to get a reminder of what tasks are available using &lt;code&gt;rake -T&lt;/code&gt;.  The downside is that argument handling is not so nice.&lt;/p&gt;
&lt;p&gt;(Were this more than demo code, though, I would ultimately make the core code a library so that having both a Rake task and a standalone app would be equally easy.  And, in fact, some folks have been working on &lt;a href="http://github.com/fcoury/octopi/tree/master"&gt;GitHub &lt;span class="caps"&gt;API&lt;/span&gt; Ruby libraries.&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Doing a &lt;span class="caps"&gt;POST&lt;/span&gt; is a bit more complex than just reading from a &lt;span class="caps"&gt;URL&lt;/span&gt;, but no big deal:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;

      def create_issue title, body
        require 'net/http'
        require 'uri'

        token = ENV['GH_AUTH_TOKEN']
        url = 'http://github.com/api/v2/yaml/issues/open/Neurogami/rhesus'
        res = Net::HTTP.post_form(URI.parse(url),
                                  {'title'=&amp;gt; title, 
                                      'body' =&amp;gt; body,
                                      'login' =&amp;gt; 'Neurogami',
                                       'token'=&amp;gt; token }
                                 )
        warn res.body

      end
&lt;/pre&gt;

&lt;p&gt;Note that the code pulls the authentication token from an environment variable. That&amp;#8217;s done to avoid having to embed it in the code or some config file that may inadvertently reach the wrong eyes.&lt;/p&gt;
&lt;p&gt;As for bulk posting of issues, well, better add a ticket for that.&lt;/p&gt;
&lt;h3&gt;But that&amp;#8217;s not all;  you&amp;#8217;ll also get this!&lt;/h3&gt;
&lt;p&gt;I must confess that I&amp;#8217;ve been writing the code as I wrote this post.  It&amp;#8217;s an amazingly useful way to get some code written.&lt;/p&gt;
&lt;p&gt;I thought about the whole &amp;#8220;Oh, if you were really doing this right, you&amp;#8217;d make this a library&amp;#8221; thing, and, well, I made this a library thing.&lt;/p&gt;
&lt;p&gt;You can get the code here: &lt;a href="http://github.com/Neurogami/ghissues/tree/master"&gt;http://github.com/Neurogami/ghissues/tree/master&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s basically the above code, with some provisions for reading a local config file that defines the repo, repo owner, and a file for saving a cache of the repo issues.   (A down-side of coding-for-content is that certain niceties, like docs and tests, may fall by the wayside.  The code, however, is pretty simple.)&lt;/p&gt;
&lt;p&gt;Re-doing the Rake tasks using this gem is left as an exercise for the reader.&lt;/p&gt;
&lt;h3&gt;Don&amp;#8217;t wait; act now!&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve written a few other apps along these lines. One lets me add items to my list at &lt;a href="http://todoist.com"&gt;Todoist.com.&lt;/a&gt; I can even set reminders to pester me to do something later.  Very handy; the improved speed in setting a reminder or adding a new bug ticket is well worth the time spent coding up such tools.  There are numerous existing apps out there for things like this as well.  (Check out &lt;a href="http://news.ycombinator.com/item?id=770064"&gt;this thread on Hacker News.&lt;/a&gt;).  See if one doesn&amp;#8217;t help you do more with less friction.&lt;/p&gt;
&lt;p&gt;But if you can&amp;#8217;t find one that really works for you, consider writing your own.  It&amp;#8217;s not hard, and there&amp;#8217;s a real payoff in having something that fits your style and keeps you moving.&lt;/p&gt;</description><author>james.britt@gmail.com (James Britt)</author><pubDate>Sun, 30 Aug 2009 13:00:00 +0000</pubDate><link>http://blog.rubybestpractices.com/posts/jamesbritt/James_will_be_right_back_after_these_interruptions.html</link><guid>http://blog.rubybestpractices.com/posts/jamesbritt/James_will_be_right_back_after_these_interruptions.html</guid></item><item><title>"And your Mom, too."  Ruby-talk best practices.</title><description>&lt;p&gt;Mailing lists (and bulletin boards and forums and so on) are important parts of becoming a better developers. Even the best programmers need help, and a mailing list such as &lt;a href="http://www.ruby-lang.org/en/community/mailing-lists"&gt;ruby-talk&lt;/a&gt;  (or the Usenet version, comp.lang.ruby) is the traditional place to go.&lt;/p&gt;
&lt;p&gt;Mailing lists are also a good place to get better at your craft; watch the list, and try to answer questions. Think of it as pop quizzes at Ruby U.&lt;/p&gt;
&lt;p&gt;Mailing lists are also good place to toss out ideas, conjecture about the future of Ruby, and have general Ruby-related discussions.&lt;/p&gt;
&lt;p&gt;There are, however, right and wrong ways to go about this.  The canonical source for what is termed &amp;#8220;Netiquette&amp;#8221; is Internet Engineering Task Force &lt;a href="http://tools.ietf.org/rfc/rfc1855.txt"&gt;&lt;span class="caps"&gt;RFC&lt;/span&gt; 1855&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You should read it.  However, it&amp;#8217;s somewhat lengthy, and some aspects dated.  Here, I&amp;#8217;d like to focus on a few key items as they relate to Ruby and ruby-talk.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;RFC&lt;/span&gt; 1855 in a Nutshell&lt;/h2&gt;
&lt;p&gt;For the &lt;a href="http://www.urbandictionary.com/define.php?term=tl;dr"&gt;tl;dr&lt;/a&gt; crowd: Don&amp;#8217;t be a complete jerk.&lt;/p&gt;
&lt;p&gt;I can&amp;#8217;t suggest not being any kind of jerk at all in anyway, because it&amp;#8217;s impossible.  The Web is a big place.  No matter what you say or do, there is every chance that someone, somewhere, will take offence, or think you stupid, or in some way take you the wrong way.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s not much you can do about that, but you can be mindful of some general decency.  For Rubyists, the key is &lt;span class="caps"&gt;MINASWAN&lt;/span&gt;: Matz is nice, and so we are nice.&lt;/p&gt;
&lt;p&gt;This doesn&amp;#8217;t mean not being critical, or not pointing out mistakes, or not offering bold opinions.  It means directing your comments to ideas, not personalities.  It means understanding that being wrong doesn&amp;#8217;t make a person bad or stupid, just wrong.  And being wrong on one thing does make make  a person wrong on everything.&lt;/p&gt;
&lt;p&gt;It also means not jumping down someone&amp;#8217;s throat because their sense of humor doesn&amp;#8217;t jibe with yours.&lt;/p&gt;
&lt;p&gt;Discussions on ruby-talk can get heated, and the temptation can be strong to let loose with snark and bile.  Typically it ends up counter-productive, but it&amp;#8217;s understandable.&lt;/p&gt;
&lt;p&gt;Threads would likely be much less fun if everything was sanitized.  However, the line needs to be drawn at personal attacks and comments.&lt;/p&gt;
&lt;p&gt;Ideas can be foolish; people are not fools simply for expressing a foolish idea.  Code can be bad; people are not bad for writing such code.&lt;/p&gt;
&lt;h2&gt;It&amp;#8217;s About Code and Ideas&lt;/h2&gt;
&lt;p&gt;Few people post to ruby-talk to make personal attacks (barring trolls, who should never ever be fed), but it happens. Before letting loose that little bit of one-upmanship, consider what you are really trying to accomplish.  If the goal is hurt someone: Please remember &lt;span class="caps"&gt;MINASWAN&lt;/span&gt;. If you cannot, then please go elsewhere.&lt;/p&gt;
&lt;p&gt;If the goal is to see Ruby improve, or to express an idea, or to get help with some code, or to offer help, then stop and think.&lt;/p&gt;
&lt;p&gt;That brief moment of satisfaction will fade, and you will have failed in your larger intent.&lt;/p&gt;
&lt;p&gt;Ruby-talk has a tradition of being very welcoming to newcomers, with many people willing to help answer even the goofiest of questions.  I&amp;#8217;ve asked a fair number of those goofy questions, and the help I received encouraged me both to stick with Ruby and to try to return the favor. Please support that.&lt;/p&gt;
&lt;h2&gt;A Random Set of Guidelines&lt;/h2&gt;
&lt;p&gt;Assorted do&amp;#8217;s and don&amp;#8217;ts.  If you can think of more, please add them in the comments.&lt;/p&gt;
&lt;h3&gt;Don&amp;#8217;t top-post&lt;/h3&gt;
&lt;p&gt;See &lt;a href="http://www.caliburn.nl/topposting.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before retorting with how this or that mail reader or client makes top-posting the default, consider this: the idea is to make things easy for the readers, not for you, the poster.&lt;/p&gt;
&lt;p&gt;If the goal is have people read, and understand, what you are posting, then place you reply in context, and trim away irrelevant text.&lt;/p&gt;
&lt;p&gt;If you are unpersuaded by arguments against top-posting (and many are), know that many people will simply not bother with what you post.&lt;/p&gt;
&lt;h3&gt;Do your homework&lt;/h3&gt;
&lt;p&gt;Ruby is a great language, fairly intuitive to many people, but sometimes you get stuck trying to figure something out. It may seem easy to dash off a note to ruby-talk asking, &amp;#8220;How do I do foo?&amp;#8221;, but first apply some due diligence.  Use Google.  Use ruby-doc.org (Handy tip: Ruby-doc.org uses a custom Google search focused on Ruby sites.  There&amp;#8217;s a special search &lt;span class="caps"&gt;URL&lt;/span&gt; as well: http://www.ruby-doc.org/q/your+search+terms+here.)&lt;/p&gt;
&lt;p&gt;Search the ruby-talk archives:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;http://groups.google.com/group/ruby-talk-google&lt;/li&gt;
	&lt;li&gt;http://www.nabble.com/ruby-talk-f13890.html&lt;/li&gt;
	&lt;li&gt;http://blade.nagaokaut.ac.jp/ruby/ruby-talk/index.shtml.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you do post, explain what steps you&amp;#8217;ve taken to solve the matter on your own.  This serves two purposes. First, it shows people you are diligent, making more people more likely to want to help you. It also avoids wasting time with people suggesting things you&amp;#8217;ve already done or know about.&lt;/p&gt;
&lt;p&gt;Whenever possible, show your code.  If you have more than a dozen lines or so, use a pastie site, such as &lt;a href="http://gist.github.com/"&gt;Gist&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Be specific&lt;/h3&gt;
&lt;p&gt;If you have a problem, give details about your environment.  What operating system? What version of Ruby?&lt;/p&gt;
&lt;p&gt;Know, too, that there are specialized mailing lists for many Ruby tools and applications. For example, if you have a problem with Rails or Ramaze, please ask on the Rails or Ramaze mailing lists. You are more likely to get a faster, more accurate response on the proper list.&lt;/p&gt;
&lt;p&gt;Ask concrete questions.  Explain what you are trying to do, what results you get, and how those results differ from what you want or expected.&lt;/p&gt;
&lt;h3&gt;Don&amp;#8217;t threadjack.&lt;/h3&gt;
&lt;p&gt;That is, do not reply to a post with starting a new topic.   If a thread starts to drift off-topic, please consider starting a new thread with a more appropriate topic.&lt;/p&gt;
&lt;h3&gt;Repetition is not an argument&lt;/h3&gt;
&lt;p&gt;Don&amp;#8217;t expect anyone to change their opinion because you&amp;#8217;ve repeated your same points over and over. Accept that sometimes people will never, ever, agree with you. I know, it&amp;#8217;s weird, but true.&lt;/p&gt;

&lt;h3&gt;Watch for perma-threads&lt;/h3&gt;
&lt;p&gt;There are some topics that come up at regular intervals. Adding static typing to Ruby.  Best &lt;span class="caps"&gt;GUI&lt;/span&gt;  toolkit.  Best &lt;span class="caps"&gt;IDE&lt;/span&gt;.  Adding significant indentation.&lt;/p&gt;
&lt;p&gt;Before posting, see if you are not simply repeating what has been said.  Check the archives.  If you really feel you have something new to add, post, but please show that you are familiar with prior discussion.&lt;/p&gt;
&lt;p&gt;Conversely, if you see a post that looks to be a perma-thread, don&amp;#8217;t assume it has been discussed to death (although that is possible). Certain topics, such as &lt;span class="caps"&gt;GUI&lt;/span&gt; tools or IDEs, see new additions and advancements over time.  It doesn&amp;#8217;t help to direct people to a thread from last year as the final word on evolving technology.&lt;/p&gt;
&lt;h3&gt;Walk the walk&lt;/h3&gt;
&lt;p&gt;People often ask for one or another change to the Ruby language or standard library. This is good, this is how languages evolve.&lt;/p&gt;
&lt;p&gt;Well-considered change requests should be posted to the ruby-core mailing list.&lt;/p&gt;
&lt;p&gt;Before proposing any change, see if someone hasn&amp;#8217;t already implemented it as a library.  There are a few libraries, such as &lt;a href="http://facets.rubyforge.org"&gt;Facets&lt;/a&gt;, that provide many extensions.&lt;/p&gt;
&lt;p&gt;If there is no existing code, see if you can first implement it yourself.&lt;/p&gt;
&lt;p&gt;For example, you may think it be would super cool awesome if the Array class could tell you what elements were of a certain size:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;
  a = %w{ foo bar bar thisoneisdiffernt }
  short_words = a.length_is 3
&lt;/pre&gt;
&lt;p&gt;Before arguing in the abstract just how magical this would make life, code it yourself:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;
  class Array
    def length_is length
      self.select{ |i| i.size == length }
    end
  end
&lt;/pre&gt;
&lt;p&gt;Make it a gem, or a gist pastie, or otherwise available for others to try.  Then explain why it needs to be added to the language rather than used as a gem.&lt;/p&gt;
&lt;p&gt;If, for whatever reason, you cannot implement it (even a weak version), explain why.&lt;/p&gt;
&lt;p&gt;The bottom line is this: Many, many suggestions have been made, many with the presumption that someone else is expected to do the heavy lifting, swayed only by rhetoric. That&amp;#8217;s unfair, and unproductive..&lt;/p&gt;
&lt;p&gt;When first attempting to code it yourself, certain results are likely:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;You discover that there is no need to build it into the language, since it is trivial to add (e.g. using a gem)&lt;/li&gt;
	&lt;li&gt;You discover that it is not so easy to add as-needed, but you now have the code for it, so adding it to the language would be that much easier&lt;/li&gt;
	&lt;li&gt;You discover that, now that you have a working version, you don&amp;#8217;t use it as you expected anyway&lt;/li&gt;
	&lt;li&gt;You find out that some things are hard to do&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Best of all, the effort should make you a better Ruby programmer.&lt;/p&gt;</description><author>james.britt@gmail.com (James Britt)</author><pubDate>Wed, 10 Jun 2009 21:59:00 +0000</pubDate><link>http://blog.rubybestpractices.com/posts/jamesbritt/and_your_Mom_too.html</link><guid>http://blog.rubybestpractices.com/posts/jamesbritt/and_your_Mom_too.html</guid></item><item><title>Solve the problem, not just a problem</title><description>&lt;p&gt;So you decide you want a way for a number of people to post short articles to a Web site, and maybe allow for other people to leave comments. What do you do?  That&amp;#8217;s easy: jump to the white board and start sketching out a vast array of boxes, blobs, and arrows that define a sophisticated content management system with multi-level admin roles, content versioning, threaded discussion boards, syntax highlighting, the works.&lt;/p&gt;
&lt;p&gt;Right?&lt;/p&gt;
&lt;p&gt;Don&amp;#8217;t be too quick to judge.  It&amp;#8217;s easy to fall into the trap of defining the wrong requirements for a project.&lt;/p&gt;
&lt;p&gt;Part of the reason is that building software is (or should be) fun, and often bigger projects are more fun. There is also the tendency to think about &amp;#8220;what if&amp;#8221;, imagining all the things that maybe one day who knows you never can tell might be needed.&lt;/p&gt;
&lt;p&gt;People also tend to think in terms of what&amp;#8217;s familiar, of how things have been done in the past or by others.&lt;/p&gt;
&lt;p&gt;There are many ways to satisfy the needs described in the first paragraph.  Some don&amp;#8217;t require writing any software at all.&lt;/p&gt;
&lt;p&gt;For the Ruby Best Practices blog, the general goals were modest.  Allow a core set of people to easily add new content.  Allow other people to contribute content as well, but only with the OK from someone in that core group. (&lt;span class="caps"&gt;BTW&lt;/span&gt;, there are eight of us in the &lt;span class="caps"&gt;RBP&lt;/span&gt; blog team.  See &lt;a href="http://img509.imageshack.us/img509/2944/rbpdharmainitiative.jpg"&gt;here&lt;/a&gt; for my take on the &lt;span class="caps"&gt;RBP&lt;/span&gt; team logo)&lt;/p&gt;
&lt;p&gt;We wanted to allow the use of Textile, and not make people use a browser for editing.  Basically, turn simple flat files into a Web site with minimal fuss.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/sandal/korma/tree/master"&gt;Korma&lt;/a&gt; takes an interesting approach to building Web sites.  The whole app is ~230 lines of Ruby. Its key function is to take content from a Git repository, run it through some templating, and write out the site files.&lt;/p&gt;
&lt;p&gt;Relying on Git for that back end is stunningly perfect. Git provides versioning, access control, and distributed contributions.&lt;/p&gt;
&lt;p&gt;It becomes the database layer common to most blogging tools. For free.  Right off the bat, no need to write any admin tools or content versioning code  .&lt;/p&gt;
&lt;p&gt;At the heart of Korma is the &lt;a href="http://github.com/mojombo/grit/tree/master"&gt;grit&lt;/a&gt; gem. As the project blurb says, &amp;#8220;Grit gives you object oriented read/write access to Git repositories via Ruby.&amp;#8221;  Very sweet.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;korma.rb&lt;/code&gt; file takes two arguments.  The first is required, and is the path to a git repository.  The second argument is optional; it tells Korma what directory to use for the generated content, and defaults to &amp;#8216;www&amp;#8217;, relative to where you invoke the program.&lt;/p&gt;
&lt;p&gt;The app uses grit to reach into the current contents of the repo and parse the needed files. Files have to be committed to be accessible to Korma.&lt;/p&gt;
&lt;p&gt;There is a configuration file that describes some basic site metadata, such as the base &lt;span class="caps"&gt;URL&lt;/span&gt;, the site title, and the author list.  When called, &lt;code&gt;korma.rb&lt;/code&gt; grabs this config file, sets some &lt;code&gt;Korma::Blog&lt;/code&gt; properties, and then writes out the static files.&lt;/p&gt;
&lt;p&gt;An early version of Korma used &lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt;; basically, Korma was a lightweight Web app to serve the blog posts. But as simple as it was, it was overkill, since there was no real dynamic content.  It made no sense to have the Web app regenerate the &lt;span class="caps"&gt;HTML&lt;/span&gt; on each request, since it changed so infrequently.&lt;/p&gt;
&lt;p&gt;A next version replaced the Web app part with static files, making it a straightforward command-line program.   This solved another problem: how to automate the regeneration of files. The answer: use Git&amp;#8217;s post-commit hook to invoke the program.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;
   #!/bin/sh
   # File .git/hooks/post-commit   
   /usr/local/bin/ruby /home/james/data/vendor/korma/korma.rb /home/james/data/vendor/rbp-blog /home/james/data/vendor/korma/www
&lt;/pre&gt;
&lt;p&gt;Early versions also used Haml for site-wide templates.  Not being a fan of Haml, I added in a configurable option to use Erb.  It was nice and all, but it was a feature without a requirement. No one was asking for configurable templating, so that option was dropped and Erb replaced Haml as the default.&lt;/p&gt;
&lt;p&gt;If you are wondering why working code was removed, consider that any code you have is something you have to maintain. As bug-free and robust as you may like to think it, no code is easier to maintain than &lt;em&gt;no&lt;/em&gt; code.  Configurable templating was simply not a problem we were needed to solve, and a smaller, simpler code base is more valuable than a maybe &amp;#8220;nice to have.&amp;#8221;&lt;/p&gt;
&lt;p&gt;There was some discussion about the need or value of allowing comments.  In the end they were deemed good, but there was no good argument for hosting them as part of the blog site itself.  That meant a 3rd-party solution (in this case, &lt;a href="http://disqus.com/"&gt;Disqus&lt;/a&gt;) was perfectly acceptable. Again, a goal was to have comments, not to write a commenting system (as entertaining as that may be).&lt;/p&gt;
&lt;p&gt;Using Git allows for yet another feature for free: easy one-off  contributions.  In many systems, allowing anyone to contribute means creating an account, granting some sort of access, managing all the new user annoyances. Or, an existing user has to play proxy, accepting content and entering it into the system on behalf of the real author.  That&amp;#8217;s work!  With git, one can clone the repo, add new content, and issue a pull request back to the master branch.  Anyone with commit rights to the master can then merge it in (or politely decline).   No-code features &lt;span class="caps"&gt;FTW&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;None of the blog design requirements are written in stone, and they may change tomorrow, but by identifying the real needs, addressing what was deemed essential, offloading what we could, and skipping the feature bling, we have a system that is easy to understand, easy to maintain, and easy to change.&lt;/p&gt;</description><author>james.britt@gmail.com (James Britt)</author><pubDate>Mon, 13 Apr 2009 20:11:00 -0000</pubDate><link>http://blog.rubybestpractices.com/posts/jamesbritt/2009-04-13-solving-the-problem.rc.html</link><guid>http://blog.rubybestpractices.com/posts/jamesbritt/2009-04-13-solving-the-problem.rc.html</guid></item></channel></rss>