<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>Bryan Helmkamp - Home</title>
  <id>tag:www.brynary.com,2009:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  
  <link href="http://www.brynary.com/" rel="alternate" type="text/html" />
  <updated>2009-04-22T18:24:28Z</updated>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/brynary" /><feedburner:info uri="brynary" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>40.765714</geo:lat><geo:long>-73.985607</geo:long><entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-04-22:1137</id>
    <published>2009-04-22T18:23:00Z</published>
    <updated>2009-04-22T18:24:28Z</updated>
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/dNu51UAHM-4/rack-bug-debugging-toolbar-in-four-minutes" rel="alternate" type="text/html" />
    <title>Rack::Bug debugging toolbar in four minutes</title>
<content type="html">
            &lt;p&gt;Here’s a quick screencast demonstrating Rack::Bug, a new Rack middleware for inspecting requests to any Rack-compatible web application.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.brynary.com/RackBug.mov"&gt;Download the screencast&lt;/a&gt;&lt;/strong&gt; (12 MB, 4:00)&lt;/p&gt;


	&lt;p&gt;The source is on &lt;a href="http://github.com/brynary/rack-bug/tree/master"&gt;GitHub&lt;/a&gt;. It ships with nine panels:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Rails Info&lt;/li&gt;
		&lt;li&gt;Resource Usage&lt;/li&gt;
		&lt;li&gt;Rack Env&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;SQL&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;AR Objects&lt;/li&gt;
		&lt;li&gt;Memcached&lt;/li&gt;
		&lt;li&gt;Templates&lt;/li&gt;
		&lt;li&gt;Log&lt;/li&gt;
		&lt;li&gt;Memory Usage&lt;/li&gt;
	&lt;/ul&gt;


&lt;pre&gt;&lt;code&gt;./script/plugin install git://github.com/brynary/rack-bug.git&lt;/code&gt;&lt;/pre&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# config/initializers/middleware.rb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rack/bug&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;Dispatcher&lt;/span&gt;.middleware.use &lt;span class="co"&gt;Rack&lt;/span&gt;::&lt;span class="co"&gt;Bug&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sy"&gt;:ip_masks&lt;/span&gt;   =&amp;gt; [&lt;span class="co"&gt;IPAddr&lt;/span&gt;.new(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)],&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sy"&gt;:secret_key&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;epT5uCIchlsHCeR9dloOeAPG66PtHd9K8l0q9avitiaA/KUrY7DE52hD4yWY+8z1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sy"&gt;:password&lt;/span&gt;   =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rack-bug-secret&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/dNu51UAHM-4" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/4/22/rack-bug-debugging-toolbar-in-four-minutes</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-04-18:1136</id>
    <published>2009-04-18T01:22:00Z</published>
    <updated>2009-04-20T16:28:47Z</updated>
    <link href="http://feedproxy.google.com/~r/brynary/~3/aAswswQmwbI/webrat-slides-from-gogaruco" rel="alternate" type="text/html" />
    <title>Webrat slides from GoGaRuCo</title>
<content type="html">
            &lt;p&gt;I finally got an internet connection (on the plane wifi) to upload my slide from GoGaRuCo 2009 about Webrat. Couldn’t get them up to SlideShare yet, so I’ll add that tomorrow. (&lt;em&gt;Update:&lt;/em&gt; Slides are now up on SlideShare and embedded below.)&lt;/p&gt;

&lt;p&gt;Thanks again to Josh and Leah for organizing GoGaRuCo. I had a great time in SF meeting a lot of cool people and learning about all sorts of new technologies I want to try out soon.&lt;/p&gt;

&lt;div&gt;&lt;a href="http://www.slideshare.net/brynary/webrat-rails-acceptance-testing-evolved?type=presentation" title="Webrat: Rails Acceptance Testing Evolved"&gt;Webrat: Rails Acceptance Testing Evolved&lt;/a&gt;&amp;lt;object height="355" width="425"&gt;&amp;lt;param /&gt;&amp;lt;param /&gt;&amp;lt;param /&gt;&amp;lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=1316406&amp;amp;#38;rel=0&amp;amp;#38;stripped_title=webrat-rails-acceptance-testing-evolved" height="355" width="425"&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;div&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/brynary"&gt;brynary&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.brynary.com/assets/2009/4/20/GoGaRuCo_Final.pdf"&gt;Download the slides&lt;/a&gt;&lt;/strong&gt; as a &lt;span class="caps"&gt;PDF&lt;/span&gt; (1.9 MB)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; The talks were recorded, so a full video of my presentation should be online soon.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/aAswswQmwbI" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/4/18/webrat-slides-from-gogaruco</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-04-06:1129</id>
    <published>2009-04-06T18:36:00Z</published>
    <updated>2009-04-06T19:28:27Z</updated>
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/7jrZFRUvodk/switching-webrat-to-selenium-mode" rel="alternate" type="text/html" />
    <title>Switching Webrat to Selenium mode</title>
<content type="html">
            &lt;p&gt;Ryan Bates did a great job &lt;a href="http://railscasts.com/episodes/156-webrat"&gt;covering Webrat in Railscast #156&lt;/a&gt;, and I’d recommend anyone who hasn’t used Webrat check it out. It’s a clear demonstration of how you can start using Webrat in a few minutes today with Rails built-in integration testing framework. Webrat works with RSpec, Cucumber, Shoulda, etc. too, but they aren’t required.&lt;/p&gt;


	&lt;p&gt;Unfortunately, during the screencast some Webrat bugs prevented running the tests in Selenium mode. Webrat has worked with Selenium for some time, but there have been some lingering rough edges around getting it up and running that I’ve been meaning to resolve. Today I’m happy to report those issues are now fixed, and &lt;em&gt;getting started using Selenium with Webrat should now be drop-dead simple&lt;/em&gt;.&lt;/p&gt;


	&lt;p&gt;Give it a try by checking out &lt;a href="http://github.com/ryanb/railscasts-episodes/tree/master/episode-156"&gt;the full Episode #156 source code&lt;/a&gt;, then make the following changes:&lt;/p&gt;


&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# config/environments/test.rb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;config.gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;webrat&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:version&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;=0.4.4&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="c"&gt;# was 0.4.3&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# test/test_helper.rb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ActiveSupport::TestCase&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# ...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.use_transactional_fixtures = &lt;span class="pc"&gt;false&lt;/span&gt; &lt;span class="c"&gt;# was true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# ...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Add these lines:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  setup &lt;span class="r"&gt;do&lt;/span&gt; |session|&lt;tt&gt;
&lt;/tt&gt;    session.host! &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;localhost:3001&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Webrat&lt;/span&gt;.configure &lt;span class="r"&gt;do&lt;/span&gt; |config|&lt;tt&gt;
&lt;/tt&gt;  config.mode = &lt;span class="sy"&gt;:selenium&lt;/span&gt; &lt;span class="c"&gt;# was :rails&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;Running the test again should pop open a Firefox window for the running tests and print output like this:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;$ rake test:integration
(in /Users/bhelmkamp/p/railscasts-episodes/episode-156/authenticator)
Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
Started
==&gt; Waiting for Selenium RC server on port 4444... Ready!
==&gt; Waiting for rails application server on port 3001... Ready!
..
Finished in 11.679288 seconds.

2 tests, 2 assertions, 0 failures, 0 errors&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Success!&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; I just pushed Webrat 0.4.4, so it might not be available on all the gem sever mirrors yet. If not, you can install it with the following commands:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;git clone git://github.com/brynary/webrat.git
cd webrat
rake install_gem&lt;/code&gt;&lt;/pre&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/7jrZFRUvodk" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/4/6/switching-webrat-to-selenium-mode</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-03-31:1128</id>
    <published>2009-03-31T01:12:00Z</published>
    <updated>2009-03-31T01:16:18Z</updated>
    <category term="Rails" />
    <category term="Random" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/Zlbb6dDQ8e0/speaking-about-webrat-at-gogaruco" rel="alternate" type="text/html" />
    <title>Speaking about Webrat at GoGaRuCo</title>
<content type="html">
            &lt;p&gt;Thanks to all those kind attendees who voted for my talk proposal, I’ve been invited to speak at &lt;a href="http://gogaruco.com/"&gt;GoGaRuCo&lt;/a&gt; in San Francisco on April 17-18th. My talk is titled &lt;a href="http://gogaruco.com/schedule/index.html#helmkamp"&gt;Webrat: Rails Acceptance Testing Evolved&lt;/a&gt;, and I’m especially excited for two reasons:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;The conference looks like it will be excellent. There are lots of talks I’m looking forward to seeing, Josh and Leah are doing a great job as organizers (harder than it looks!), and it’s in a cool city I haven’t visited before.&lt;/li&gt;
		&lt;li&gt;This is the first time I’ll be giving a talk about Webrat specifically, rather than covering Webrat as part of a broader topic. The project is almost a year and a half old now, and there’s plenty of interesting bits to talk about these days.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;The conference is sold out, but if you’re going you should say hello. I’m always up for chatting about Ruby, scaling or testing, and grabbing a beer. Should be easy to find, and you can message me as &lt;a href="http://twitter.com/brynary"&gt;@brynary&lt;/a&gt; on Twitter.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/Zlbb6dDQ8e0" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/3/31/speaking-about-webrat-at-gogaruco</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-03-05:1112</id>
    <published>2009-03-05T04:14:00Z</published>
    <updated>2009-03-05T04:16:31Z</updated>
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/X63QEDzAa8g/rack-test-released-a-simple-testing-api-for-rack-based-frameworks-and-apps" rel="alternate" type="text/html" />
    <title>Rack::Test released: Simply test any Rack-compatible app</title>
<content type="html">
            &lt;p&gt;Today I’m happy to announce the first release of a new library I’ve been cooking up: &lt;a href="http://github.com/brynary/rack-test"&gt;Rack::Test&lt;/a&gt;. It’s a simple &lt;span class="caps"&gt;API&lt;/span&gt; for issuing fake requests to any Rack app (e.g. Rails, Sinatra, Merb, etc.) similar to what you might be familiar with in Rails’ integration tests or Merb’s request specs. Basically, I extracted Merb’s request helper code into a small, reusable, framework agnostic library. Here’s an example:&lt;/p&gt;


&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rack/test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;HomepageTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Test&lt;/span&gt;::&lt;span class="co"&gt;Unit&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  include &lt;span class="co"&gt;Rack&lt;/span&gt;::&lt;span class="co"&gt;Test&lt;/span&gt;::&lt;span class="co"&gt;Methods&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;app&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;MyApp&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;test_redirect_logged_in_users_to_dashboard&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    authorize &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;bryan&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;secret&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    get &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    follow_redirect!&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    assert_equal &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://example.org/redirected&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, last_request.url&lt;tt&gt;
&lt;/tt&gt;    assert last_response.ok?&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;While developing Webrat, I started to realize all of the Ruby web frameworks were reinventing boilerplate code to create a test environment for issuing fake requests. They all have to:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Convert params hashes into encoded strings (something the browser handles for normal requests)&lt;/li&gt;
		&lt;li&gt;Maintain a simulated cooke jar to enable sessions&lt;/li&gt;
		&lt;li&gt;Generate multipart requests (to support test file uploads)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Through discussions with Josh Knowles and Yehuda Katz, it became apparent that an abstracted layer for these concerns would be valuable.&lt;/p&gt;


	&lt;p&gt;With Rack::Test, we hope to make it easy for frameworks to encourage their users to write tests by making it trivial to provide a testing environment. We’d like to foster compatibility between Ruby web app testing environments (especially important as ideas like multi-framework apps become more prominent). The philosophy is the library should stay small and extendable so frameworks can layer on additional functionality they want to offer without modifying Rack::Test’s core behavior or resorting to monkeypatching.&lt;/p&gt;


	&lt;h2&gt;The Rack::Test &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/h2&gt;


	&lt;p&gt;The &lt;a href="http://gitrdoc.com/brynary/rack-test"&gt;full RDoc is available&lt;/a&gt; on gitrdoc, but I’ve reproduced some of it below. It should feel familiar if you’re used to Rails integration testing or Merb request specs:&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Rack::Test.initialize(app)&lt;/strong&gt; — Initialize a new session for the given Rack app&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#get(uri, params = {}, env = {})&lt;/strong&gt; — Issue a &lt;span class="caps"&gt;GET&lt;/span&gt; request for the given &lt;span class="caps"&gt;URI&lt;/span&gt; with the given params and Rack environment. Stores the issues request object in #last_request and the app’s response in #last_response. Yield #last_response to a block if given.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#post, #put, #delete, and #head&lt;/strong&gt; —  Behave like #get but specifying a different &lt;span class="caps"&gt;HTTP&lt;/span&gt; method&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#request(uri, env = {})&lt;/strong&gt; — Issue a request to the Rack app for the given &lt;span class="caps"&gt;URI&lt;/span&gt; and optional Rack environment. Stores the issues request object in #last_request and the app’s response in #last_response. Yield #last_response to a block if given.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#follow_redirect!&lt;/strong&gt; — Rack::Test does not follow any redirects automatically. This method will follow the redirect returned in the last response. If the last response was not a redirect, an error will be raised.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#header(name, value)&lt;/strong&gt; — Set a header to be included on all subsequent requests through the session. Use a value of nil to remove a previously configured header.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#authorize(username, password)&lt;/strong&gt;— Set the username and password for &lt;span class="caps"&gt;HTTP&lt;/span&gt; Basic authorization, to be included in subsequent requests in the &lt;span class="caps"&gt;HTTP&lt;/span&gt;_AUTHORIZATION header.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#last_request&lt;/strong&gt; — Return the last request issued in the session. Raises an error if no requests have been sent yet.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;#last_response&lt;/strong&gt; — Return the last response received in the session. Raises an error if no requests have been sent yet.&amp;lt;/macro:code&gt;&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; Thanks to the people who helped get Rack::Test off the ground: The Merb Team for their request helper code; Yehuda Katz and Josh Knowles for guidance, encouragement and support; Simon Rozet and Pat Nakajima for early code contributions.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/X63QEDzAa8g" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/3/5/rack-test-released-a-simple-testing-api-for-rack-based-frameworks-and-apps</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-02-03:1106</id>
    <published>2009-02-03T04:09:00Z</published>
    <updated>2009-02-03T04:09:58Z</updated>
    <category term="BDD" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/DIPVUVgnLR8/cucumber-step-definition-tip-stubbing-time" rel="alternate" type="text/html" />
    <title>Cucumber step definition tip: Stubbing time</title>
<content type="html">
            &lt;p&gt;When writing Cucumber scenarios, you'll occasionally need to describe a behavior that is dependent on time passing. For example, at weplay we want to ensure that a password reset link expires after one week.&lt;/p&gt;

&lt;p&gt;In a RSpec code example, you might be used to stubbing time in this situation:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;now = &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Time&lt;/span&gt;.stub!(&lt;span class="sy"&gt;:now&lt;/span&gt;).and_return(now + &lt;span class="i"&gt;8&lt;/span&gt;.days)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;This doesn't work out-of-the-box in a Cucumber step definition. By default, Cucumber doesn't include any of RSpec's mocking or stubbing support. This makes sense because Cucumber is a tool for acceptance testing (full stack), where stubbing and especially mocking should be discouraged and only used for very specific purposes (like stubbing time!).&lt;/p&gt;

&lt;p&gt;If you find yourself in this situation, you can enable RSpec's stubbing support in your Cucumber step definitions by adding the following code to env.rb:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;spec/mocks&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Before&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$rspec_mocks&lt;/span&gt; ||= &lt;span class="co"&gt;Spec&lt;/span&gt;::&lt;span class="co"&gt;Mocks&lt;/span&gt;::&lt;span class="co"&gt;Space&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;After&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;begin&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="gv"&gt;$rspec_mocks&lt;/span&gt;.verify_all&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;ensure&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="gv"&gt;$rspec_mocks&lt;/span&gt;.reset_all&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Now you can go ahead and create a time_steps.rb like this:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;When&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^(&lt;/span&gt;&lt;span class="ch"&gt;\d&lt;/span&gt;&lt;span class="k"&gt;+) minutes pass$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |minutes|&lt;tt&gt;
&lt;/tt&gt;  now = &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Time&lt;/span&gt;.stub!(&lt;span class="sy"&gt;:now&lt;/span&gt;).and_return(now + minutes.to_i.minutes)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;When&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^(&lt;/span&gt;&lt;span class="ch"&gt;\d&lt;/span&gt;&lt;span class="k"&gt;+) hours pass$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |hours|&lt;tt&gt;
&lt;/tt&gt;  now = &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Time&lt;/span&gt;.stub!(&lt;span class="sy"&gt;:now&lt;/span&gt;).and_return(now + hours.to_i.hours)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;When&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^(&lt;/span&gt;&lt;span class="ch"&gt;\d&lt;/span&gt;&lt;span class="k"&gt;+) days pass$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |days|&lt;tt&gt;
&lt;/tt&gt;  now = &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Time&lt;/span&gt;.stub!(&lt;span class="sy"&gt;:now&lt;/span&gt;).and_return(now + days.to_i.days)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;RSpec will clear your time stub at the end of each scenario.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/DIPVUVgnLR8" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/2/3/cucumber-step-definition-tip-stubbing-time</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-01-30:1105</id>
    <published>2009-01-30T04:36:00Z</published>
    <updated>2009-01-30T04:36:46Z</updated>
    <category term="BDD" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/3Q2bcPOvpOE/the-rspec-book-is-now-in-beta" rel="alternate" type="text/html" />
    <title>The RSpec Book is now in Beta</title>
<content type="html">
            &lt;p&gt;&lt;a href="http://www.pragprog.com/titles/achbd/the-rspec-book"&gt;&lt;img src="http://www.brynary.com/assets/2009/1/10/rspec-book.jpg" alt="The RSpec Book" /&gt;&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;I’m very happy to report that &lt;a href="http://www.pragprog.com/titles/achbd/the-rspec-book"&gt;The RSpec Book&lt;/a&gt;, which I’ve been collaborating on, is now available for sale as a Beta Book from the Pragmatic Bookshelf. David Chelimsky posted an &lt;a href="http://rubyforge.org/pipermail/rspec-users/2009-January/011931.html"&gt;announcement&lt;/a&gt; 
to the rspec-users mailing list which sums it up quite well. To quote:&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;On behalf of all the authors, I’d like to extend a special thank you  
to all of you who have contributed to the software and the  
conversation around RSpec, Cucumber, and &lt;span class="caps"&gt;BDD&lt;/span&gt; in general. RSpec would  
be nothing without the community that has evolved around it, so thank  
you, thank you, thank you.&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;Enjoy! And if you do pick it up, please let us know what you think. We’re eager to improve it based on the feedback we get.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/3Q2bcPOvpOE" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/1/30/the-rspec-book-is-now-in-beta</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2009-01-20:1104</id>
    <published>2009-01-20T19:10:00Z</published>
    <updated>2009-01-20T19:11:23Z</updated>
    <category term="Agile" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/0R-WMQURwwY/features2cards-released-convert-cucumber-feature-files-to-pdf-task-cards" rel="alternate" type="text/html" />
    <title>features2cards released: Convert Cucumber feature files to PDF task cards</title>
<content type="html">
            &lt;p&gt;Today I’d like to announce the first real release of features2cards 0.1.1. The code has been sitting in my &lt;a href="http://github.com/brynary/features2cards"&gt;GitHub repository&lt;/a&gt; for awhile now, but I thought it was time to give it a formal release announcement.&lt;/p&gt;


	&lt;p&gt;features2cards is a simple tool to generate a printable &lt;span class="caps"&gt;PDF&lt;/span&gt; of scenario cards from Cucumber feature files. At weplay, we use this at the start of each sprint to get out Scrum task board up-to-date. Interally, features2cards uses the Cucumber feature parser and Prawn for &lt;span class="caps"&gt;PDF&lt;/span&gt; generation (in native Ruby!).&lt;/p&gt;


	&lt;p&gt;I’ve uploaded the gem and you should be able to install it off RubyForge very soon:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;sudo gem install features2cards&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;Here’s how you use it:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;features2cards features/scale_rails.feature&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;This will generate a file called cards.pdf in the current directory. Open that up, print it, and you’ve got cards ready to be chopped up and stuck to your Agile task board.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://www.brynary.com/assets/2009/1/20/cards_pdf.jpg" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;That’s all there is to it for now. Fork away. It’s only 150 lines including whitespace. I’d be happy to add additional formats, color support and other enhancements.&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="http://www.lukemelia.com/"&gt;Luke Melia&lt;/a&gt;. His &lt;a href="http://www.lukemelia.com/blog/archives/2007/12/29/pdf-storycards-001-released-my-first-gem"&gt;pdf-storycards&lt;/a&gt; project inspired this.&lt;/em&gt;&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/0R-WMQURwwY" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2009/1/20/features2cards-released-convert-cucumber-feature-files-to-pdf-task-cards</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-09-01:1094</id>
    <published>2008-09-01T00:48:00Z</published>
    <updated>2008-09-01T00:49:48Z</updated>
    <category term="Agile" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/OT36Wb_nhLA/setting-the-git-commit-author-to-pair-programmers-names" rel="alternate" type="text/html" />
    <title>Setting the git commit author to pair programmers' names</title>
<content type="html">
            &lt;p&gt;Are you using git? Are you writing all your code that needs to be maintained in pairs? Great. Your commits probably look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;commit a5ab4d39be608280fbea6ba9710aea4593f20bc6
&lt;b&gt;Author: Bryan Helmkamp &amp;lt;bryan@brynary.com&amp;gt;&lt;/b&gt;
Date:   Fri Aug 29 18:47:29 2008 -0400

    Some important refactoring &lt;b&gt;LM/BH&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Subversion has limited support for tracking authors, so we used to manually add the initials of the programmers working on a changeset for future reference. With git, however, we can specify arbitrary author names for each commit. Now our commits look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;commit a5ab4d39be608280fbea6ba9710aea4593f20bc6
&lt;b&gt;Author: Luke Melia and Bryan Helmkamp &amp;lt;developers@weplay.com&amp;gt;&lt;/b&gt;
Date:   Fri Aug 29 18:47:29 2008 -0400

    Some important refactoring&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To simplify updating the git author configuration as we switch pairs, I whipped up a quick Ruby shell script called &lt;code&gt;pair&lt;/code&gt;. Called with a list of developers' initials, it configures the git author name and email fields. Called with no arguments, it unsets the per-project git author configuration so your global settings take effect.&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/usr/bin/env ruby&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Configures the git author to a list of developers when pair programming&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Usage: pair lm bh (Sets the author to 'Luke Melia and Bryan Helmkamp')&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#        pair       (Unsets the author so the git global config takes effect)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Author: Bryan Helmkamp (http://brynary.com)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#######################################################################&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## Configuration&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;PAIR_EMAIL&lt;/span&gt; = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;developers@weplay.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;AUTHORS&lt;/span&gt; = {&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;bh&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Bryan Helmkamp&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;lm&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Luke Melia&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# ...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;}&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## End of configuration&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#######################################################################&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.exists?(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.git&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;This doesn't look like a git repository.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  exit &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;authors = &lt;span class="pc"&gt;ARGV&lt;/span&gt;.map &lt;span class="r"&gt;do&lt;/span&gt; |initials|&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="co"&gt;AUTHORS&lt;/span&gt;[initials.downcase]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;AUTHORS&lt;/span&gt;[initials.downcase]&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Couldn't find author name for initials: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;initials&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    exit &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;if&lt;/span&gt; authors.any?&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; authors.size == &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    authors = authors.first&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;elsif&lt;/span&gt; authors.size == &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    authors = authors.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt; and &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    authors = authors[&lt;span class="i"&gt;0&lt;/span&gt;..&lt;span class="i"&gt;-2&lt;/span&gt;].join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt; and &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + authors.last&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git config user.name '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;authors&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git config user.email '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;PAIR_EMAIL&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;user.name = &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;authors&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;user.email = &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;PAIR_EMAIL&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git config --unset user.name&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git config --unset user.email&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Unset user.name and user.email&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; If you're using &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt;, it's important to choose a &lt;code&gt;PAIR_EMAIL&lt;/code&gt; value that &lt;em&gt;does not&lt;/em&gt; correspond to a GitHub account. Otherwise, GitHub will resolve the email address to a GitHub user and display their username instead of the value of the &lt;code&gt;author.name&lt;/code&gt;. We just made one up.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/OT36Wb_nhLA" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/9/1/setting-the-git-commit-author-to-pair-programmers-names</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-08-03:1082</id>
    <published>2008-08-03T20:49:00Z</published>
    <updated>2008-08-10T21:39:42Z</updated>
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/zqcrpNAJO44/our-git-deployment-workflow" rel="alternate" type="text/html" />
    <title>Our Git deployment workflow</title>
<content type="html">
            &lt;p&gt;At weplay, we recently switched to pure git version control from &lt;code&gt;git-svn&lt;/code&gt;.
Now that we've had a couple weeks for the dust to settle, I'd like to
share our workflow for managing deployments to our staging and production
clusters.&lt;/p&gt;

&lt;p&gt;We started by outlining the goals of our system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;All code that's pushed to our staging and production environments must be in &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;. Nothing
goes straight from a local repository to our servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any developer can deploy our most recent work to staging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any developer can deploy the code on staging into production. We (try to) avoid
deploying anything to production that hasn't been pushed to staging first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any developer can see a diff between "What is deployed" and "What I'm
about to deploy."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any developer can branch from the production codebase for time sensitive
tweaks and fixes. These need to be staged before they're deployed to
production too.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That functionality is available in an automated, safe, easy to use form.
(Hint: rake)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We ruled out having "production" and "staging" tags because updating tags
across a tree of remotes doesn't seem to work smoothly. We also ruled out
doing git merges from master into our staging branch. Our staging server/codebase jumps
around from the latest changes to the production code (up to a week old)
based on what we need to test, so we really just want to replace it.&lt;/p&gt;

&lt;p&gt;We settled on using remote git branches for production and staging on origin
and hard resetting them to other branches to simulate a copy. We treat these
branches more like tags and never commit to them directly. This has worked
great so far.&lt;/p&gt;

&lt;p&gt;Here's what our rake tasks look like:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;77&lt;tt&gt;
&lt;/tt&gt;78&lt;tt&gt;
&lt;/tt&gt;79&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;80&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;81&lt;tt&gt;
&lt;/tt&gt;82&lt;tt&gt;
&lt;/tt&gt;83&lt;tt&gt;
&lt;/tt&gt;84&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;85&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;86&lt;tt&gt;
&lt;/tt&gt;87&lt;tt&gt;
&lt;/tt&gt;88&lt;tt&gt;
&lt;/tt&gt;89&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;90&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;GitCommands&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;diff_staging&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git fetch&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    puts &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git diff origin/production origin/staging&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;tag_staging&lt;/span&gt;(branch_name)&lt;tt&gt;
&lt;/tt&gt;    verify_working_directory_clean&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git fetch&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git branch -f staging origin/staging&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git checkout staging&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git reset --hard origin/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;branch_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git push -f origin staging&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git checkout master&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git branch -D staging&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;tag_production&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    verify_working_directory_clean&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git fetch&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git branch -f production origin/production&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git checkout production&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git reset --hard origin/staging&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git push -f origin production&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git checkout master&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git branch -D production&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;branch_production&lt;/span&gt;(branch_name)&lt;tt&gt;
&lt;/tt&gt;    verify_working_directory_clean&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git fetch&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git branch -f production origin/production&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git checkout production&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git branch &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;branch_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git checkout &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;branch_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git push origin &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;branch_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;protected&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;verify_working_directory_clean&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;return&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;git status&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt; =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;working directory clean&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    raise &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Must have clean working directory&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;namespace &lt;span class="sy"&gt;:tag&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;lt;&amp;lt;-DESC&lt;/span&gt;&lt;/span&gt;&lt;span class="s"&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt;    Update the staging branch to prepare for a staging deploy.&lt;tt&gt;
&lt;/tt&gt;    Defaults to master. Optionally specify a BRANCH=name&lt;/span&gt;&lt;span class="dl"&gt;&lt;tt&gt;
&lt;/tt&gt;  DESC&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  task &lt;span class="sy"&gt;:staging&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    branch_name = &lt;span class="co"&gt;ENV&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;BRANCH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;] || &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;master&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;GitCommands&lt;/span&gt;.new.tag_staging(branch_name)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Update the remove production branch to prepare for a release&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  task &lt;span class="sy"&gt;:production&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;diff:staging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;GitCommands&lt;/span&gt;.new.tag_production&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;namespace &lt;span class="sy"&gt;:diff&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Show the differences between the staging branch and the production branch&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  task &lt;span class="sy"&gt;:staging&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;GitCommands&lt;/span&gt;.new.diff_staging&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;namespace &lt;span class="sy"&gt;:branch&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Branch from production for tweaks or bug fixs. Specify BRANCH=name&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  task &lt;span class="sy"&gt;:production&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    branch_name = &lt;span class="co"&gt;ENV&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;BRANCH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;    raise &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;You must specify a branch name using BRANCH=name&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; branch_name&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;GitCommands&lt;/span&gt;.new.branch_production&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;namespace &lt;span class="sy"&gt;:deploy&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Tag and deploy staging&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  task &lt;span class="sy"&gt;:staging&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tag:staging&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;cap staging deploy:long&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;The last one (&lt;code&gt;rake deploy:staging&lt;/code&gt;) simply wraps up the common task of tagging
our latest code to be pushed to staging and initiating a staging deploy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; To use most of these commands, your local working directory must be clean. If we have outstanding changes in our tree when we need to run them, we use &lt;code&gt;git-stash&lt;/code&gt; to temporarily move them out of the way. &lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="http://jointheconversation.org/"&gt;Scott Chacon&lt;/a&gt; for helping us work this out. Be sure to check
out his &lt;a href="http://www.gitcasts.com/"&gt;GitCasts&lt;/a&gt; and &lt;a href="http://peepcode.com/products/git-internals-pdf"&gt;Git Internals PDF&lt;/a&gt;.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/zqcrpNAJO44" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/8/3/our-git-deployment-workflow</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-06-30:1081</id>
    <published>2008-06-30T05:02:00Z</published>
    <updated>2008-07-22T18:45:24Z</updated>
    <category term="Random" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/u8SUji6f-0Q/how-i-got-started-programming" rel="alternate" type="text/html" />
    <title>How I got started programming</title>
<content type="html">
            &lt;p&gt;&lt;a href="http://www.pauldix.net/2008/06/how-i-got-start.html"&gt;Mr. Paul C. Dix tagged me&lt;/a&gt; to answer these...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How old were you when you started programming?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I started to understand the concept of programming around age nine or ten. I remember how amazing I thought it was that making the computer do new things didn't require rooms full of special equipment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How did you get started programming?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lot of my experiences around this time are blurred together.&lt;/p&gt;

&lt;p&gt;My parents got me into a beginner programming course for kids at the local community college. The instructor taught the basics of variables and control structures while the students swapped QBasic games they downloaded at home.&lt;/p&gt;

&lt;p&gt;The first program I distinctly remember working on calculated golf handicaps from a series of scores. I wrote it with an elementary school friend in his basement using a copy of Borland C++ he found. We fumbled around with functions like getch and cout without any idea that they stood for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was your first language?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Beginners All-purpose Symbolic Instructional Code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was the first real program you wrote?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I joined the website development team at my high school half way though the ninth grade, I took on the task of creating a system to post football scores and statistics to our website. After a frustrating first attempt in Perl, I discovered PHP and rewrote it.&lt;/p&gt;

&lt;p&gt;The program allowed our statistician to enter the numbers into a form, saving the web team from having to manually enter all the data from paper print outs. It calculated simple averages and YTD totals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What languages have you used since you started programming?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In no particular order: QBasic, Visual Basic, Bash, Java, JavaScript, C, C++, Ruby, Perl, PHP, Python, and SQL.&lt;/p&gt;

&lt;p&gt;So far, Ruby is my favorite hands down. I'm fortunate enough to say I've never written a line of real production code in either Java or .NET.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was your first professional programming gig?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The summer before my senior year of high school, I interned in a local government IT applications department. The other developers were doing mostly ASP work, but I built their first PHP application which I deployed on their first Linux server.&lt;/p&gt;

&lt;p&gt;Unsatisfied with the maintainability of PHP apps I had built in the past, I developed a Struts-like framework in the process. At this point I was feeling pain with the PHP language and the lack of a suitable web development framework. After a brief exploration into Python, I would soon find relief in Ruby and Rails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If there is one thing you learned along the way that you would tell new developers, what would it be?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Engage in the community, both locally and online, as much as possible. Attend user group meetings, contribute to mailing lists, blog, go to conferences that look interesting. Surround yourself with other programmers, especially those you admire. You won't regret it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the most fun you've ever had programming?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Solving interesting problems with great developers while building applications with an impact. 'Nuff said.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Up Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's entirely optional, of course.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://jackbaty.com/go/blog"&gt;Jack Baty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.leebankewitz.com/"&gt;Lee Bankewitz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://metaclass.org/"&gt;Wilson Bilkovich&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;âˆš &lt;a href="http://blog.davidchelimsky.net/2008/7/1/how-i-got-started-programming"&gt;David Chelimsky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.lukemelia.com/devblog/"&gt;Luke Melia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;âˆš &lt;a href="http://boxornot.com/2008/07/21/how-i-became-a-programmer/"&gt;Noah Davis&lt;/a&gt; (&lt;em&gt;Edit:&lt;/em&gt; Added Noah after he started a blog)&lt;/li&gt;
&lt;/ul&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/u8SUji6f-0Q" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/6/30/how-i-got-started-programming</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-04-26:1078</id>
    <published>2008-04-26T18:09:00Z</published>
    <updated>2008-04-26T18:09:55Z</updated>
    <category term="Agile" />
    <category term="BDD" />
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/LfWBT60gH3E/story-driven-development-slides-posted" rel="alternate" type="text/html" />
    <title>Story Driven Development slides posted</title>
<content type="html">
            &lt;p&gt;Just wrapped up my Story Driven Development talk at GoRuCo 2008. There were some great questions at the end, and I'm looking forward to more hallway track conversations about SDD.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.brynary.com/uploads/Story_Driven_Development.pdf"&gt;Download the slides&lt;/a&gt;&lt;/strong&gt; as a PDF (1.6 MB)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; Confreaks is recording the talks today, so a full video of my presentation should be online soon.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/LfWBT60gH3E" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/4/26/story-driven-development-slides-posted</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-03-26:1074</id>
    <published>2008-03-26T06:49:00Z</published>
    <updated>2008-03-26T06:50:04Z</updated>
    <category term="Rails" />
    <category term="Random" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/m4YY-kKzkl0/weplay-launches" rel="alternate" type="text/html" />
    <title>weplay launches</title>
<content type="html">
            &lt;p&gt;The online community for youth sports I’ve been working on for the last month or so, &lt;a href="http://weplay.com/"&gt;weplay&lt;/a&gt;, is now in public beta. It’s been a roller coaster, but entirely worth it.&lt;/p&gt;


	&lt;p&gt;As part of this launch, we’re set to appear on the front page of the New York Times business section in tomorrow’s paper. The &lt;a href="http://www.nytimes.com/2008/03/26/technology/26caa.html"&gt;online version of the article&lt;/a&gt; is already available, and we’ve been busy all night responding to our first production load…. ever.&lt;/p&gt;


	&lt;p&gt;Check it out, don’t mind a few bumps and bruises as we settle in, and expect more to come soon. Oh, and be sure to checkout &lt;a href="http://www.weplay.com/users/bryan"&gt;my weplay profile&lt;/a&gt;.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/m4YY-kKzkl0" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/3/26/weplay-launches</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-02-09:955</id>
    <published>2008-02-09T22:12:00Z</published>
    <updated>2008-02-09T22:14:01Z</updated>
    <category term="Agile" />
    <category term="BDD" />
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/40LXBp06p0c/presenting-at-goruco" rel="alternate" type="text/html" />
    <title>Presenting at GoRuCo in NYC</title>
<content type="html">
            &lt;p&gt;I just received word that my proposal to speak at &lt;span class="caps"&gt;NYC&lt;/span&gt;’s very own second annual &lt;a href="http://2008.goruco.com/"&gt;GoRuCo&lt;/a&gt; has been accepted. The conference is set for Saturday, April 26th at Pace University downtown. My topic will be the same as my &lt;a href="http://www.brynary.com/2008/1/31/presenting-at-scotland-on-rails"&gt;Scotland on Rails presentation&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I’m really excited to have the opportunity to present at home, in front of many of my friends and colleagues. Now I just need to make sure I don’t suck. Better get back to working on my slide deck…&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/40LXBp06p0c" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/2/9/presenting-at-goruco</feedburner:origLink></entry>
  <entry xml:base="http://www.brynary.com/">
    <author>
      <name>bhelmkamp</name>
    </author>
    <id>tag:www.brynary.com,2008-01-31:952</id>
    <published>2008-01-31T17:44:00Z</published>
    <updated>2008-01-31T17:47:14Z</updated>
    <category term="Agile" />
    <category term="BDD" />
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feedproxy.google.com/~r/brynary/~3/c1AIjmE9mjo/presenting-at-scotland-on-rails" rel="alternate" type="text/html" />
    <title>Presenting at Scotland on Rails</title>
<content type="html">
            &lt;p&gt;I’m going to be presenting on Story Driven Development at the first Scottish Ruby on Rails conference, &lt;a href="http://scotlandonrails.com/"&gt;Scotland on Rails&lt;/a&gt;. I’ll be exploring the concept of Story-first development from both an agile process and implementation standpoint.&lt;/p&gt;


	&lt;p&gt;Topics will include:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Collaborating with the product owner on stories&lt;/li&gt;
		&lt;li&gt;What makes good stories and scenarios?&lt;/li&gt;
		&lt;li&gt;Driving stories with a browser simulator like Webrat&lt;/li&gt;
		&lt;li&gt;Potential pitfalls and ways to avoid them&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;If you’re going to be in Edinburgh for the conference, let me know.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/brynary/~4/c1AIjmE9mjo" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.brynary.com/2008/1/31/presenting-at-scotland-on-rails</feedburner:origLink></entry>
</feed>
