<?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>Atomic Spin - Home</title>
  <id>tag:spin.atomicobject.com,2010:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  
  <link href="http://spin.atomicobject.com/" rel="alternate" type="text/html" />
  <updated>2010-03-18T14:26:09Z</updated>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/atomic_spin" /><feedburner:info uri="atomic_spin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>42.955944</geo:lat><geo:long>-85.644983</geo:long><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/atomic_spin" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fatomic_spin" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Patrick Bacon</name>
      <uri>http://www.atomicobject.com/pages/Patrick+Bacon</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-03-18:43524</id>
    <published>2010-03-18T14:24:00Z</published>
    <updated>2010-03-18T14:26:09Z</updated>
    <category term="Languages" />
    <category term="Tips" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/c3s5DEdc22I/lazy-thread-safe-collections-in-java" rel="alternate" type="text/html" />
    <title>Lazy thread-safe collections in Java</title>
<content type="html">
            &lt;p&gt;I recently needed to update some Java code that was frequently making unecessary calls to an external web service. Depending on the particular UI component, or the item being displayed in that component, a large set of the data being retrieved ended up not being displayed. My task was to update the code so that it only made external calls to the web service when the data was going to be displayed.&lt;/p&gt;


	&lt;p&gt;My first thought was to pass along a flag from the &lt;i&gt;view&lt;/i&gt; layer that would indicate whether or not to retrieve the data in question.  This would require updating all of the UI classes that displayed the data, as well as passing the new flag through several additional method calls to prevent the data from being collected when it wasn’t needed.&lt;/p&gt;


	&lt;p&gt;I did not care for this solution because it meant changing several classes so that details of the view could be passed down into the data retrieval logic. Instead, I came up with an alternative solution, the crux of which is a generic, thread-safe, delayed evaluation &lt;code&gt;Map&lt;/code&gt;.&lt;/p&gt;


	&lt;p&gt;Instead of the business layer service returning a fully populated &lt;code&gt;Map&lt;/code&gt; of data, it returns a &lt;code&gt;Map&lt;/code&gt; that &lt;i&gt;will&lt;/i&gt; contain that data, if it is accessed. If no user interface components request the data for display, the data will never be retrieved. This meant that I did not have to change &lt;i&gt;any&lt;/i&gt; code outside of wrapping the logic for populating the Map with a new &lt;code&gt;LazyImmutableMap&lt;/code&gt;. Here is an example of how it is used:&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;5&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;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;public Map&amp;lt;String, String&amp;gt; getData(final Integer id) {&lt;tt&gt;
&lt;/tt&gt;  return new LazyImmutableMap&amp;lt;String, String&amp;gt;(&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    new Callable&amp;lt;Map&amp;lt;String, String&amp;gt;() {&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      public Map&amp;lt;String, String&amp;gt; call() throws Exception {      &lt;tt&gt;
&lt;/tt&gt;        return externalService.getSomeData(id);&lt;tt&gt;
&lt;/tt&gt;      }&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;  });&lt;tt&gt;
&lt;/tt&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The call to &lt;code&gt;externalService.getSomeData()&lt;/code&gt; will only be invoked if something tries to access an element in the &lt;code&gt;LazyImmutableMap&lt;/code&gt;. Implementing the class itself turned out to be extremely simple with the help of &lt;a href="http://code.google.com/p/google-collections/"&gt;Google Collections’&lt;/a&gt; &lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ForwardingMap.html"&gt;ForwardingMap&lt;/a&gt; (see this &lt;a href="http://spin.atomicobject.com/2010/02/23/better-java-with-google-collections"&gt;previous post&lt;/a&gt; for more on Google Collections) and the standard Java concurrency class &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html"&gt;FutureTask&lt;/a&gt;.&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;5&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;15&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;25&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;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;public class LazyImmutableMap&amp;lt;K,V&amp;gt; extends ForwardingMap&amp;lt;K,V&amp;gt; {&lt;tt&gt;
&lt;/tt&gt;  public static class AccessException extends RuntimeException {&lt;tt&gt;
&lt;/tt&gt;    public AccessException(Throwable cause) {&lt;tt&gt;
&lt;/tt&gt;      super(cause);&lt;tt&gt;
&lt;/tt&gt;    }&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  private final FutureTask&amp;lt;Map&amp;lt;K, V&amp;gt;&amp;gt; task;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  public LazyImmutableMap(final Callable&amp;lt;Map&amp;lt;K,V&amp;gt;&amp;gt; eval) {    &lt;tt&gt;
&lt;/tt&gt;    task = new FutureTask&amp;lt;Map&amp;lt;K,V&amp;gt;&amp;gt;(new Callable&amp;lt;Map&amp;lt;K,V&amp;gt;&amp;gt;() {&lt;tt&gt;
&lt;/tt&gt;      public Map&amp;lt;K, V&amp;gt; call() throws Exception {&lt;tt&gt;
&lt;/tt&gt;        return ImmutableMap.copyOf(eval.call());&lt;tt&gt;
&lt;/tt&gt;      }&lt;tt&gt;
&lt;/tt&gt;    });&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  @Override&lt;tt&gt;
&lt;/tt&gt;  protected Map&amp;lt;K, V&amp;gt; delegate() {&lt;tt&gt;
&lt;/tt&gt;    task.run();&lt;tt&gt;
&lt;/tt&gt;    try {&lt;tt&gt;
&lt;/tt&gt;      return task.get();&lt;tt&gt;
&lt;/tt&gt;    } catch (InterruptedException e) {&lt;tt&gt;
&lt;/tt&gt;      throw new AccessException(e);&lt;tt&gt;
&lt;/tt&gt;    } catch (ExecutionException e) {&lt;tt&gt;
&lt;/tt&gt;      throw new AccessException(e.getCause());&lt;tt&gt;
&lt;/tt&gt;    }    &lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The constructor creates a &lt;code&gt;FutureTask&lt;/code&gt; that when accessed will return an immutable copy of the &lt;code&gt;Map&lt;/code&gt; provided by the passed in &lt;code&gt;Callable&lt;/code&gt;.&lt;/p&gt;


	&lt;p&gt;Extending &lt;code&gt;ForwardingMap&lt;/code&gt; means that I only needed to implement the &lt;code&gt;delegate&lt;/code&gt; method to get a fully compliant &lt;code&gt;Map&lt;/code&gt; class. The &lt;code&gt;FutureTask&lt;/code&gt; takes care of preventing the passed in &lt;code&gt;Callable&lt;/code&gt; from being executed more than once, and it’s thread-safe, so any number of threads can access an instance of the map simultaneously.&lt;/p&gt;


	&lt;p&gt;Unfortunately Java’s checked exceptions add quite a bit of clutter to an otherwise very clean and simple class. The &lt;code&gt;AccessException&lt;/code&gt; is needed because the normal &lt;code&gt;Map&lt;/code&gt; interface does not allow for checked exceptions to be thrown. The &lt;code&gt;get()&lt;/code&gt; method on a &lt;code&gt;FutureTask&lt;/code&gt; can throw two different types of exceptions. They need to be handled differently, so they are both caught and properly wrapped in an &lt;code&gt;AccessException&lt;/code&gt; (a subclass of &lt;code&gt;RuntimeException&lt;/code&gt;) and re-thrown.&lt;/p&gt;


	&lt;p&gt;Using this technique I was able to retrieve the external data if and only if it was going to be displayed to the user. And I was able to do it without breaking the separation between the view and the business logic.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=c3s5DEdc22I:MDV4M1-sMpg:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=c3s5DEdc22I:MDV4M1-sMpg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=c3s5DEdc22I:MDV4M1-sMpg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=c3s5DEdc22I:MDV4M1-sMpg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=c3s5DEdc22I:MDV4M1-sMpg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=c3s5DEdc22I:MDV4M1-sMpg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=c3s5DEdc22I:MDV4M1-sMpg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=c3s5DEdc22I:MDV4M1-sMpg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/c3s5DEdc22I" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/03/18/lazy-thread-safe-collections-in-java</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Justin DeWind</name>
      <uri>http://www.atomicobject.com/pages/Justin+DeWind</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-03-15:43446</id>
    <published>2010-03-15T14:27:00Z</published>
    <updated>2010-03-15T15:10:23Z</updated>
    <category term="Technologies" />
    <category term="Tools" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/qd8b0SM10HA/environment-configurable" rel="alternate" type="text/html" />
    <title>Environment Configurable</title>
<summary type="html">&lt;p&gt;During our last big rails project, &lt;a href="http://www.bloomfire.com"&gt;Bloomfire&lt;/a&gt;, we found ourselves integrating with all kinds of external services. Because of this we had a diverse set of environment dependent configuration variables. A consistent pattern started to arise where we would extract our configuration variables into a &lt;span class="caps"&gt;YAML&lt;/span&gt; file and then wrap the configuration using a small class wrapper. This eventually gave rise to &lt;a href="http://github.com/atomicobject/environment_configurable"&gt;Environment Configurable&lt;/a&gt;, a library that makes environment dependent configuration easy in &lt;a href="http://rubyonrails.org/"&gt;rails&lt;/a&gt;.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;During our last big rails project, &lt;a href="http://www.bloomfire.com"&gt;Bloomfire&lt;/a&gt;, we found ourselves integrating with all kinds of external services. Because of this we had a diverse set of environment dependent configuration variables. A consistent pattern started to arise where we would extract our configuration variables into a &lt;span class="caps"&gt;YAML&lt;/span&gt; file and then wrap the configuration using a small class wrapper. This eventually gave rise to &lt;a href="http://github.com/atomicobject/environment_configurable"&gt;Environment Configurable&lt;/a&gt;, a library that makes environment dependent configuration easy in &lt;a href="http://rubyonrails.org/"&gt;rails&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;Add config.gem “environment_configurable” to your environment.rb file&lt;/li&gt;
		&lt;li&gt;rake gems:install&lt;/li&gt;
		&lt;li&gt;rake gems:unpack&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Usage&lt;/h2&gt;


	&lt;p&gt;Code:&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;5&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;&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;S3Helper&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  include &lt;span class="co"&gt;EnvironmentConfigurable&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  configure_with &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;config/s3.yml&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;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.connect!&lt;tt&gt;
&lt;/tt&gt;     &lt;span class="co"&gt;AWS&lt;/span&gt;::&lt;span class="co"&gt;S3&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;.establish_connection!(&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="sy"&gt;:access_key_id&lt;/span&gt;     =&amp;gt; config.access_key_id,&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="sy"&gt;:secret_access_key&lt;/span&gt; =&amp;gt; config.secret_access_key&lt;tt&gt;
&lt;/tt&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;&lt;span class="caps"&gt;YAML&lt;/span&gt;:&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;5&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;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;production: &amp;amp;DEFAULTS&lt;tt&gt;
&lt;/tt&gt;  access_key_id: ACCESS_KEY_ID&lt;tt&gt;
&lt;/tt&gt;  secret_access_key: SECRET_ACCESS_KEY&lt;tt&gt;
&lt;/tt&gt;  bucket: the-prod-bucket&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;staging:&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;&amp;lt;: *DEFAULTS&lt;tt&gt;
&lt;/tt&gt;  bucket: the-staging-bucket&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;development:&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;&amp;lt;: *DEFAULTS&lt;tt&gt;
&lt;/tt&gt;  bucket: the-development-bucket&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;test:&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;&amp;lt;: *DEFAULTS&lt;tt&gt;
&lt;/tt&gt;  bucket: the-test-bucket&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qd8b0SM10HA:YVfp1RZ1QW4:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qd8b0SM10HA:YVfp1RZ1QW4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=qd8b0SM10HA:YVfp1RZ1QW4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qd8b0SM10HA:YVfp1RZ1QW4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=qd8b0SM10HA:YVfp1RZ1QW4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qd8b0SM10HA:YVfp1RZ1QW4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=qd8b0SM10HA:YVfp1RZ1QW4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qd8b0SM10HA:YVfp1RZ1QW4:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/qd8b0SM10HA" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/03/15/environment-configurable</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Mike Karlesky</name>
      <uri>http://www.atomicobject.com/pages/Mike+Karlesky</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-03-14:43420</id>
    <published>2010-03-14T23:39:00Z</published>
    <updated>2010-03-15T14:40:50Z</updated>
    <category term="Books, Papers, Articles &amp; Links" />
    <category term="UI/UX" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/SfHJwy28MkM/the-dangers-of-engineer-thinking" rel="alternate" type="text/html" />
    <title>Engineer Thinking, Making People Feel Like Idiots &amp; The Failure of Empathy</title>
<content type="html">
            &lt;p&gt;&lt;a href="http://mattgemmell.com/2010/03/09/engineer-thinking"&gt;Matt Legend Gemmell on &lt;em&gt;Engineer Thinking&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;All too often, when faced with a decision about how to implement certain functionality, engineers take the extreme position that:&lt;/p&gt;

	&lt;ol&gt;
	&lt;li&gt;A feature must be exactly what 100% of users want.&lt;/li&gt;
		&lt;li&gt;If the above isn’t true (and it almost never is), the feature must be configurable.&lt;/li&gt;
	&lt;/ol&gt;


&lt;p&gt;This binary approach is gravely wrong, and unjustly offloads decision-making onto the user of the software. We’ve all seen where this approach ends up: multi-row sets of tabs, scrolling panes of checkboxes, nested radio-buttons and a general overload of configuration.&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;&lt;br /&gt;&lt;/p&gt;


&lt;p&gt;&lt;a href="http://37signals.com/svn/posts/2132-computers-shouldnt-make-people-feel-like-idiots"&gt;Matt Linderman (37signals) saying &lt;em&gt;Computers shouldn’t make people feel like idiots&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;For those of us surrounded by the minutiae of computers all day, it’s easy to forget there’s a world of people out there who just don’t get it. And it’s not their fault. It’s ours.&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;&lt;br /&gt;&lt;/p&gt;


&lt;p&gt;&lt;a href="http://weblog.muledesign.com/2010/02/the_failure_of_empathy.php"&gt;Mike Monteiro (Mule Design Studio) on &lt;em&gt;The Failure of Empathy&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;As an industry, we need to understand that not wanting root access doesn’t make you stupid. It simply means you do not want root access. Failing to comprehend this is not only a failure of empathy, but a failure of service.&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;p&gt;(via &lt;a href="http://ignorethecode.net/blog/"&gt;ignore the code&lt;/a&gt;)&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=SfHJwy28MkM:tHT02baBP8Y:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=SfHJwy28MkM:tHT02baBP8Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=SfHJwy28MkM:tHT02baBP8Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=SfHJwy28MkM:tHT02baBP8Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=SfHJwy28MkM:tHT02baBP8Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=SfHJwy28MkM:tHT02baBP8Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=SfHJwy28MkM:tHT02baBP8Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=SfHJwy28MkM:tHT02baBP8Y:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/SfHJwy28MkM" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/03/14/the-dangers-of-engineer-thinking</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Carl Erickson</name>
      <uri>http://www.atomicobject.com/pages/Carl+Erickson</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-03-13:43394</id>
    <published>2010-03-13T18:59:00Z</published>
    <updated>2010-03-13T19:02:29Z</updated>
    <category term="Agile Practices" />
    <category term="Business of Software" />
    <category term="Conferences" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/6J0cGnx2XD0/don-t-forget-the-basics-opening-keynote-of-the-michigan-agile-and-beyond-conference" rel="alternate" type="text/html" />
    <title>Don't forget the basics: opening keynote of the Michigan Agile and Beyond conference</title>
<content type="html">
            &lt;p&gt;The &lt;a href="http://mostlyfree.org"&gt;Michigan Agile and Beyond Conference&lt;/a&gt; brought 450 people together this weekend in Dearborn, Michigan to teach, learn and debate the broad subject of agile software development. The “beyond” part of the theme bothered me a little, for the same reason that it irritates me when I hear companies explaining that they do “practical agile”. Both statements miss the point that agile is about nothing more than delivering valuable software frequently and regularly. What can be more practical than that? Why do we need to move “beyond” that?&lt;/p&gt;


	&lt;p&gt;Ron Jeffries &amp; Chet Hendrickson offered the best advice I heard all day in their opening keynote. Namely, to go beyond, you must travel through. Their point was that if you’re not in the “agile space” now, successfully using the core practices, then get there before you start tinkering or adapting. It reminded me of the debate in the early 2000s of whether you had to use all (then) 13 practices of XP to claim you were doing XP. Someone (might even have been Ron) responded that you’re doing XP when you’ve mastered all 13 practices and figured out which ones you need and how to use them on your project.&lt;/p&gt;


	&lt;p&gt;Chet cut straight to the chase when he said it matters what you do, because  “agile isn’t any damn thing.” Ron followed that by quoting Emerson Codd: “The truth isn’t like a bunch of puppies running around where you chose your favorite.” Their talk was as casual, funny, and inspiring as always. They shared some of the simple truths about software development:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Software development is all about people (Funny Ron quote: “When I got into computing, it was not with the intention of hanging out with other people.”) Tools can’t replace or compensate for people.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Requirements need to get into the heads of the people building the software. Documents are a poor way of doing this.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;If you can’t ship working software every month, try two weeks. If you can’t do it in two weeks, try one week. You learn to build software by building and shipping working software.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Waterfall doesn’t give you accurate information until it’s too late.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;If your software isn’t bug free, you can’t trust your velocity.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;If you’re manually testing everything your need for testers grows at least linearly with the number of iterations. You’ve got to automate some of those tests.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;If you can’t refactor, you can’t do evolutionary design.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;They summarized by identifying the three non-negotiable core practices to being agile:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Ship software regularly&lt;/li&gt;
		&lt;li&gt;Test as you go&lt;/li&gt;
		&lt;li&gt;Refactor to evolve the design&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;While their message, at least to me, was fundamentally one of “don’t forget the basics”, Chet and Ron also addressed the “beyond” part of the conference. They cited relationship to management, human resources, and dealing with projects that don’t fit in a single room as challenges that are still beyond the scope of accepted agile thinking. Ron called out &lt;a href="http://www.pillartechnologies.com/"&gt;Pillar Technology&lt;/a&gt; and &lt;a href="http://atomicobject.com"&gt;Atomic Object&lt;/a&gt; as examples of companies pushing the boundaries of agile. They also reminded us that we have an obligation to share our experiments, both our failures and successes, to grow the body of agile knowledge. Chet added that these experiments push agile into new territory, but are still grounded in the simple statements of the &lt;a href="http://agilemanifesto.org"&gt;Agile Manifesto&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=6J0cGnx2XD0:sQggZMhy6Pg:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=6J0cGnx2XD0:sQggZMhy6Pg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=6J0cGnx2XD0:sQggZMhy6Pg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=6J0cGnx2XD0:sQggZMhy6Pg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=6J0cGnx2XD0:sQggZMhy6Pg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=6J0cGnx2XD0:sQggZMhy6Pg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=6J0cGnx2XD0:sQggZMhy6Pg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=6J0cGnx2XD0:sQggZMhy6Pg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/6J0cGnx2XD0" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/03/13/don-t-forget-the-basics-opening-keynote-of-the-michigan-agile-and-beyond-conference</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Michael Marsiglia</name>
      <uri>http://www.atomicobject.com/pages/Michael+Marsiglia</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-03-03:43096</id>
    <published>2010-03-03T19:53:00Z</published>
    <updated>2010-03-03T19:55:18Z</updated>
    <category term="Business of Software" />
    <category term="Project Management" />
    <category term="Tools" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/u8w6BQtTJvs/responsible-estimation-tool" rel="alternate" type="text/html" />
    <title>Responsible Estimation Tool</title>
<content type="html">
            &lt;p&gt;Many times during the sales process we are asked to give a &lt;a href="http://spin.atomicobject.com/2009/12/11/setting-the-budget"&gt;cost estimation&lt;/a&gt; based on our early understanding of an application’s core features. In order to responsibly and efficiently estimate, we conduct a &lt;a href="http://spin.atomicobject.com/2009/01/14/making-better-estimates-range-estimates"&gt;50/90 range analysis&lt;/a&gt;. We use this technique because we want to establish a responsible middle ground between our optimistic and pessimistic estimates. Our estimate is appropriately buffered for the risk we see in the defined tasks.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://spin.atomicobject.com/assets/2010/3/3/5090.jpg?1267644142" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;This spreadsheet is the &lt;a href="http://spin.atomicobject.com/assets/2010/3/3/50-90_estimator.xls"&gt;tool&lt;/a&gt; that we use to conduct our analysis. Tasks can be estimated in any time duration that you choose (i.e. hours, days, weeks). At the start of a large project we generally estimate tasks in days or weeks.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=u8w6BQtTJvs:PETfL3OTDCk:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=u8w6BQtTJvs:PETfL3OTDCk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=u8w6BQtTJvs:PETfL3OTDCk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=u8w6BQtTJvs:PETfL3OTDCk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=u8w6BQtTJvs:PETfL3OTDCk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=u8w6BQtTJvs:PETfL3OTDCk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=u8w6BQtTJvs:PETfL3OTDCk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=u8w6BQtTJvs:PETfL3OTDCk:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/u8w6BQtTJvs" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/03/03/responsible-estimation-tool</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Carl Erickson</name>
      <uri>http://www.atomicobject.com/pages/Carl+Erickson</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-28:43008</id>
    <published>2010-02-28T22:36:00Z</published>
    <updated>2010-02-28T22:50:30Z</updated>
    <category term="Business of Software" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/sXzo6ZYSSQ8/startup-weekend-in-grand-rapids" rel="alternate" type="text/html" />
    <title>Startup Weekend in Grand Rapids</title>
<content type="html">
            &lt;p&gt;I attended the tail end of &lt;a href="http://wmi.startupweekend.org/"&gt;Startup Weekend&lt;/a&gt; at &lt;a href="http://workthefactory.com/"&gt;The Factory&lt;/a&gt; this weekend. Kudos to Michael Boyink and Aaron Schaap for organizing this in West Michigan. &lt;a href="http://www.marcnager.com/"&gt;Marc Nager&lt;/a&gt;, one of two people who run Startup Weekends all over the country, commented on the energy in the room and the incredible willingness of strangers to get behind ideas and work together. Evidently what we lack in VC we make up for in hard work and generosity.&lt;/p&gt;


	&lt;p&gt;The final pitches were pretty good considering that some of these ideas weren’t even hatched until Friday afternoon. An app for helping people keep track of things that need to get done even had a pretty functional backend implemented over the weekend. It was great to see eight teams and 40 or so people challenging the economic doom and gloom of our state, putting their ideas out there, listening to others, and taking action to make them real.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=sXzo6ZYSSQ8:87gvcqBXDCc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=sXzo6ZYSSQ8:87gvcqBXDCc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=sXzo6ZYSSQ8:87gvcqBXDCc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=sXzo6ZYSSQ8:87gvcqBXDCc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=sXzo6ZYSSQ8:87gvcqBXDCc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=sXzo6ZYSSQ8:87gvcqBXDCc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=sXzo6ZYSSQ8:87gvcqBXDCc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=sXzo6ZYSSQ8:87gvcqBXDCc:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/sXzo6ZYSSQ8" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/28/startup-weekend-in-grand-rapids</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Matt Fletcher</name>
      <uri>http://www.atomicobject.com/pages/Matt+Fletcher</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-26:42943</id>
    <published>2010-02-26T22:42:00Z</published>
    <updated>2010-02-26T22:43:20Z</updated>
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/pYn2NabeD1A/git-deploy-to-three-servers-in-83-characters" rel="alternate" type="text/html" />
    <title>git-deploy to three servers in 83 characters</title>
<content type="html">
            &lt;p&gt;I smiled this morning when I typed this command to &lt;a href="http://github.com/mislav/git-deploy"&gt;git-deploy&lt;/a&gt; fresh code to three machines in quick succession.&lt;/p&gt;


&amp;lt;script src="http://gist.github.com/316265.js?file=gistfile1.txt"&gt;&amp;lt;/script&gt;

	&lt;p&gt;Sure, there’s nothing groundbreaking here that you can’t do with plenty of other tools. But it was still fun.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=pYn2NabeD1A:a0Fjscaqep4:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=pYn2NabeD1A:a0Fjscaqep4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=pYn2NabeD1A:a0Fjscaqep4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=pYn2NabeD1A:a0Fjscaqep4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=pYn2NabeD1A:a0Fjscaqep4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=pYn2NabeD1A:a0Fjscaqep4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=pYn2NabeD1A:a0Fjscaqep4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=pYn2NabeD1A:a0Fjscaqep4:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/pYn2NabeD1A" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/26/git-deploy-to-three-servers-in-83-characters</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Mike Swieton</name>
      <uri>http://www.atomicobject.com/pages/Mike+Swieton</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-24:42888</id>
    <published>2010-02-24T17:08:00Z</published>
    <updated>2010-02-24T21:12:19Z</updated>
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/r4Ri33DE7Ng/atomic-cookies" rel="alternate" type="text/html" />
    <title>Atomic Cookies</title>
<content type="html">
            &lt;p&gt;No, they won’t explode.&lt;/p&gt;


	&lt;p&gt;Resident cookie-master, &lt;a href="http://www.atomicobject.com/pages/Marissa+Christy"&gt;Marissa Christy,&lt;/a&gt; went the extra mile yesterday for the &lt;a href="http://spin.atomicobject.com/2010/02/24/all-input-is-evil-until-proven-otherwise-that-s-rule-number-one"&gt;SoftwareGR&lt;/a&gt; meeting. While our meetings always have great snacks, Marissa really raised the bar this time with Atomic Object logo cookies:&lt;/p&gt;


	&lt;p&gt;&lt;img title="Atomic Cookie" src="http://spin.atomicobject.com/assets/2010/2/24/cookies.jpg" alt="Atomic Object logo cookies" /&gt;&lt;/p&gt;


	&lt;p&gt;If you want some great snacks, and great information too, come to the next &lt;a href="http://www.softwaregr.org"&gt;SoftwareGR&lt;/a&gt; meeting.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r4Ri33DE7Ng:Xevrkr0OvWs:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r4Ri33DE7Ng:Xevrkr0OvWs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=r4Ri33DE7Ng:Xevrkr0OvWs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r4Ri33DE7Ng:Xevrkr0OvWs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=r4Ri33DE7Ng:Xevrkr0OvWs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r4Ri33DE7Ng:Xevrkr0OvWs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=r4Ri33DE7Ng:Xevrkr0OvWs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r4Ri33DE7Ng:Xevrkr0OvWs:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/r4Ri33DE7Ng" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/24/atomic-cookies</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Mike Swieton</name>
      <uri>http://www.atomicobject.com/pages/Mike+Swieton</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-24:42887</id>
    <published>2010-02-24T16:34:00Z</published>
    <updated>2010-02-24T16:37:29Z</updated>
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/YDHkyEQzNzA/all-input-is-evil-until-proven-otherwise-that-s-rule-number-one" rel="alternate" type="text/html" />
    <title>"All input is evil until proven otherwise. That's rule number one."</title>
<summary type="html">&lt;p&gt;Yesterday SoftwareGR hosted Dr. Richard Enbody from &lt;span class="caps"&gt;MSU&lt;/span&gt;. He spoke about security, and
    he quoted the above security rule from the book Writing Secure Code by Michael Howard and David LeBlanc (&lt;a href="http://www.microsoft.com/mspress/books/sampchap/5957.aspx"&gt;sample chapter.&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;The main topic of the talk was recent research performed by Richard’s team to develop a new security feature called Secure Bit.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Yesterday SoftwareGR hosted Dr. Richard Enbody from &lt;span class="caps"&gt;MSU&lt;/span&gt;. He spoke about security, and
    he quoted the above security rule from the book Writing Secure Code by Michael Howard and David LeBlanc (&lt;a href="http://www.microsoft.com/mspress/books/sampchap/5957.aspx"&gt;sample chapter.&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;The main topic of the talk was recent research performed by Richard’s team to develop a new security feature called Secure Bit.&lt;/p&gt;
&lt;p&gt;One of the biggest classes of vulnerabilities out there is the buffer overflow.
    Richard showed a list of vulnerabilities taken from &lt;span class="caps"&gt;CERT&lt;/span&gt;’s homepage the preceding day and showed us a slide full of recently discovered buffer
    overflows. He told us he’s always been able to fill a slide using just the first page.&lt;/p&gt;


	&lt;p&gt;Buffer overflows are caused by feeding the software some carefully crafted
    input that allows a malicious user to redirect the flow of execution. Richard’s
    research discovered that a vulnerability can be present even when the user
    can’t inject bad code – it turns out that taking over the execution is
    sufficient. &lt;a href="http://en.wikipedia.org/wiki/Buffer_overflow"&gt;Read more&lt;/a&gt; about buffer overflows on Wikipedia.&lt;/p&gt;


	&lt;p&gt;We heard about an interesting technique for finding these vulnerabilities:
    fuzzing. This is a way of partially automating an attack. It works by feeding
    the target software a randomized stream of inputs and waiting until a
    fault occurs. These faults (and the recent inputs) can be logged and analyzed to discover an attack – for both attacking systems and for fixing your own. Richard’s team developed an ingeniously simple defense against buffer
    overflows, called Secure Bit. It is a very simple algorithm:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Label all input as tainted.&lt;/li&gt;
		&lt;li&gt;Forbid jumps to a tainted address.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;This is accomplished with a combination of software and hardware changes.
    Richard adds a single bit to every word stored which indicates whether the
    input is tainted or not (called the secure bit). This addition can be done at
    the operating system level and is a relatively simple change. In the Linux
    kernel Richard’s team was able to make it happen in 4 lines of code. The jump
    protection is added at the hardware level in the processor. This was tested by
    making the change in a &lt;span class="caps"&gt;CPU&lt;/span&gt; emulator.
The simplicity of this approach means that the instruction set doesn’t have to
    change and the code stays binary-compatible. For this to be installed on a
    system, all it would need is the updated hardware and the kernel – no
    other software needs to be aware of it.&lt;/p&gt;


	&lt;p&gt;Richard’s test system ran Red Hat, and they tested out a number of known
    exploits against vulnerable targets and demonstrated that the Secure Bit
    approach does protect against malicious code execution.&lt;/p&gt;


	&lt;p&gt;Read all about it on &lt;a href="http://www.cse.msu.edu/~enbody/"&gt;Richard’s web site&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Software GR meets on the
    fourth Tuesday of the month from 6PM to 8PM at &lt;a href="http://www.atomicobject.com/pages/Find+Us"&gt;Atomic Object offices&lt;/a&gt;. The latest schedule can always be seen at &lt;a href="http://softwaregr.org"&gt;softwaregr.org&lt;/a&gt;. Meetings are
    always free and open to the public.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=YDHkyEQzNzA:j_URFwoirLk:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=YDHkyEQzNzA:j_URFwoirLk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=YDHkyEQzNzA:j_URFwoirLk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=YDHkyEQzNzA:j_URFwoirLk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=YDHkyEQzNzA:j_URFwoirLk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=YDHkyEQzNzA:j_URFwoirLk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=YDHkyEQzNzA:j_URFwoirLk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=YDHkyEQzNzA:j_URFwoirLk:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/YDHkyEQzNzA" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/24/all-input-is-evil-until-proven-otherwise-that-s-rule-number-one</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Patrick Bacon</name>
      <uri>http://www.atomicobject.com/pages/Patrick+Bacon</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-23:42853</id>
    <published>2010-02-23T01:59:00Z</published>
    <updated>2010-02-23T02:00:16Z</updated>
    <category term="Languages" />
    <category term="Technologies" />
    <category term="Tips" />
    <category term="Tools" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/8pnS7vG2QK0/better-java-with-google-collections" rel="alternate" type="text/html" />
    <title>Better Java with Google Collections</title>
<summary type="html">&lt;p&gt;Version 1.0 of the &lt;a href="http://code.google.com/p/google-collections/"&gt;Google Collections library&lt;/a&gt; was officially released December 30, 2009. I have been using the library for the past 6 months or so on a variety of Java projects, with great success. Today I gave a brown-bag talk to share with some interested &lt;a href="http://www.atomicobject.com/pages/Our+People"&gt;Atoms&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I have included below the sample code I used as presentation material, in case others are interested.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Version 1.0 of the &lt;a href="http://code.google.com/p/google-collections/"&gt;Google Collections library&lt;/a&gt; was officially released December 30, 2009. I have been using the library for the past 6 months or so on a variety of Java projects, with great success. Today I gave a brown-bag talk to share with some interested &lt;a href="http://www.atomicobject.com/pages/Our+People"&gt;Atoms&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I have included below the sample code I used as presentation material, in case others are interested.&lt;/p&gt;
&lt;p&gt;Note: As I was putting this post together I read that Google Collections is now part of Google’s &lt;a href="http://code.google.com/p/guava-libraries/"&gt;guava-libraries&lt;/a&gt; project, which has not been officially released yet.&lt;/p&gt;


&amp;lt;script src="http://gist.github.com/311753.js?file=gistfile1.java"&gt;&amp;lt;/script&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=8pnS7vG2QK0:U3cEoWK3ajE:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=8pnS7vG2QK0:U3cEoWK3ajE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=8pnS7vG2QK0:U3cEoWK3ajE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=8pnS7vG2QK0:U3cEoWK3ajE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=8pnS7vG2QK0:U3cEoWK3ajE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=8pnS7vG2QK0:U3cEoWK3ajE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=8pnS7vG2QK0:U3cEoWK3ajE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=8pnS7vG2QK0:U3cEoWK3ajE:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/8pnS7vG2QK0" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/23/better-java-with-google-collections</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Jeremy Anderson</name>
      <uri>http://www.atomicobject.com/pages/Jeremy+Anderson</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-17:42548</id>
    <published>2010-02-17T14:06:00Z</published>
    <updated>2010-02-17T14:13:56Z</updated>
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/NX0PtMj90S8/code-retreat-gr-recap" rel="alternate" type="text/html" />
    <title>Code Retreat GR Recap</title>
<content type="html">
            &lt;p&gt;On February 6th &lt;a href="http://www.atomicobject.com/pages/Jeremy+Anderson/" title="Jeremy Anderson"&gt;I&lt;/a&gt; hosted the first &lt;a href="http://coderetreat.ning.com/" title="Code Retreat"&gt;Code Retreat&lt;/a&gt; to hit West Michigan, and we really couldn't have asked for a nicer day for a Code Retreat.  Well, maybe a little bit warmer weather, but hey, it's February in Michigan, what do you expect?  So after a quick stop at Panera Bread to get some bagels, scones and muffins, I made my way down to &lt;a href="http://www.atomicobject.com/pages/Our+Historic+Building" title="Our Historic Building"&gt;Atomic Object HQ&lt;/a&gt; to start the coffee brewing in preparation for the attendees.  Shortly after sunrise, &lt;a href="http://agileshrugged.com/blog/" title="Agile Shrugged"&gt;Nayan Hajratwala&lt;/a&gt; showed up to help with any last minute preparations before everyone else showed up. &lt;/p&gt;

&lt;p&gt;&lt;img title="Code Retreaters pairing on Game of Life" src="http://spin.atomicobject.com/assets/2010/2/16/63951982.jpg" alt="Code Retreat GR" /&gt; &lt;/p&gt;

&lt;p&gt;Soon about 20 people from all parts of the region had showed up to practice TDD and learn with each other, including one guy who came all the way down from Marquette, MI just to attend.  He officially got the "I traveled the furthest" award for the day. We were also joined by &lt;a href="http://xprogramming.com/index.php" title="XProgramming"&gt;Ron Jeffries&lt;/a&gt; and &lt;a href="http://www.hendricksonxp.com/" title="Hendrickson XP"&gt;Chet Hendrickson&lt;/a&gt;, who had agreed to come and be my professional trouble makers for the day. Shortly after 9:00, once everyone had been sufficiently caffeinated, we decided to get started.  One of the attendees had mentioned something about &lt;a href="http://coreyhaines.com/" title="Corey Haines"&gt;Corey Haines&lt;/a&gt; putting together a &lt;a href="http://github.com/coreyhaines/practice_game_of_life" title="coreyhaines / practice_game_of_life @ github"&gt;set of Cucumber features&lt;/a&gt; at one of the previous Code Retreats in Chicago, so some of the pairs decided to give that a whirl.  After some yak shaving we managed to get through the first iteration of the morning and retrospected on what happened and continued on into the second iteration of the day.  &lt;/p&gt;

&lt;p&gt;My original plan was to just sort of float around, help facilitate, and observe everyone else pairing, however when I noticed Ron Jeffries didn't have a pair for the second iteration, I took the opportunity to pair with him.  Neither of us knew Cucumber very well, so we decided to give that a whirl. If ever you get the chance to pair with either Ron or Chet, don't think twice about it, just do it. Ron had at one point in the day managed to - as one participant described  "...[kick his] BDD mindset a bit out of place. . . " &lt;/p&gt;

&lt;p&gt;Before we knew it, lunch was upon us.  It turns out that Corey Haines was hosting another Code Retreat in Seattle that day, so we fired up Skype and greeted our fellow Code Retreaters on the west coast as they were just getting ready to start for the day.  Then we all proceeded to enjoy the taco bar that had been delivered for lunch and continued to retrospect on the days events so far.  When we were all finished stuffing our faces with Qdoba, Mike Sweiton and myself gave our participants a quick tour of Atomic Object HQ, showing off our open space, &lt;a href="http://spin.atomicobject.com/2010/02/08/information-radiators" title="Information Radiators"&gt;stoplight&lt;/a&gt;, CI server, and our embedded projects workbench.  &lt;/p&gt;

&lt;p&gt;Now that our food had a chance to settle, it was back to pairing for a few more iterations of Conway's Game of Life.  After one of the afternoon retrospectives, for a little bit of a distraction, we watched a video of someone implementing &lt;a href="http://www.youtube.com/watch?v=a9xAKttWgP4" title="Game of Life in APL"&gt;Conway's Game of Life in APL&lt;/a&gt;.  This was spawned by an email thread that circulated right before the Code Retreat about how to implement the &lt;a href="http://www.dyalog.com/dfnsdws/c_life.htm" title="Game of Life in single line of APL"&gt;Game of Life in a single line of APL&lt;/a&gt;, which still blows my mind.  &lt;/p&gt;

&lt;p&gt;Finally, by the time the end of the day had finally arrived, we had lost a few of our fellow coders and we were ready to call it a day. Those of us who were still left standing at the end of the day took a walk around the corner to &lt;a href="http://thegreenwell.com/" title="The Green Well"&gt;The Green Well&lt;/a&gt;, one of the many local establishments in the Eastown area, for some much needed unwinding. We continued to retrospect on the day's happenings over a few local microbrews and some delicious items from the menu.  All in all I would have to say this was a successful Code Retreat.  Everyone had a great time, we all got to pair program with some great folks we wouldn't normally get to pair with, and - most importantly - learning happened.  Though many of the Code Retreats in the past have used Java as their language of choice, in my opinion I think using Ruby for this Code Retreat was the right choice.  It afforded us much less yak shaving than would have probably been necessary had we been using Java.  I'm looking forward to hosting another Code Retreat later this year when the weather is a little warmer, and hopefully attending the upcoming &lt;a href="http://coderetreat.ning.com/xn/detail/2712512:Event:4161?xg_source=activity" title="Code Retreat Philadelphia"&gt;Code Retreat being hosted in Philadelphia&lt;/a&gt; by &lt;a href="http://sebastianlab.com/" title="Beards and Keyboards"&gt;Sebastian Hermida&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=NX0PtMj90S8:V3Ca45frHMA:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=NX0PtMj90S8:V3Ca45frHMA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=NX0PtMj90S8:V3Ca45frHMA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=NX0PtMj90S8:V3Ca45frHMA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=NX0PtMj90S8:V3Ca45frHMA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=NX0PtMj90S8:V3Ca45frHMA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=NX0PtMj90S8:V3Ca45frHMA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=NX0PtMj90S8:V3Ca45frHMA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/NX0PtMj90S8" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/17/code-retreat-gr-recap</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Marissa Christy</name>
      <uri>http://www.atomicobject.com/pages/Marissa+Christy</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-08:42510</id>
    <published>2010-02-08T15:23:00Z</published>
    <updated>2010-02-08T18:39:35Z</updated>
    <category term="Agile Practices" />
    <category term="Business of Software" />
    <category term="Test Driven Development" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/qOzXI77VCDk/information-radiators" rel="alternate" type="text/html" />
    <title>Information Radiators</title>
<summary type="html">&lt;div&gt;
  &lt;div class="imagebox"&gt;
  &lt;div&gt;
    &lt;img src="http://spin.atomicobject.com/assets/2010/2/8/_MG_6764_1.jpg?1265639551" alt="stoplight" /&gt;
  &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

	&lt;p&gt;For a business that by definition occupies a highly technical domain, we have some relatively low-tech means of conveying information internally. Sure we e-mail, &lt;a href="http://www.twitter.com/atomicobject"&gt;Twitter&lt;/a&gt;, &lt;a href="http://spin.atomicobject.com/2010/01/30/yammer-time"&gt;Yammer&lt;/a&gt;, and even &lt;a href="http://www.skype.com/"&gt;Skype&lt;/a&gt; with each other on a regular basis, but we also make use of yarn, note cards, cork boards, and old traffic equipment. I’m talking about our &lt;em&gt;information radiators&lt;/em&gt;, objects around our office that align the team by sharing important information in a fun and hard-to-miss way.&lt;/p&gt;</summary><content type="html">
            &lt;div&gt;
  &lt;div class="imagebox"&gt;
  &lt;div&gt;
    &lt;img src="http://spin.atomicobject.com/assets/2010/2/8/_MG_6764_1.jpg?1265639551" alt="stoplight" /&gt;
  &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

	&lt;p&gt;For a business that by definition occupies a highly technical domain, we have some relatively low-tech means of conveying information internally. Sure we e-mail, &lt;a href="http://www.twitter.com/atomicobject"&gt;Twitter&lt;/a&gt;, &lt;a href="http://spin.atomicobject.com/2010/01/30/yammer-time"&gt;Yammer&lt;/a&gt;, and even &lt;a href="http://www.skype.com/"&gt;Skype&lt;/a&gt; with each other on a regular basis, but we also make use of yarn, note cards, cork boards, and old traffic equipment. I’m talking about our &lt;em&gt;information radiators&lt;/em&gt;, objects around our office that align the team by sharing important information in a fun and hard-to-miss way.&lt;/p&gt;
&lt;p&gt;Perhaps the best example of this is the large traffic light positioned in the center of our office. The stoplight is rigged to our continuous integration monitor (which displays the integration status of all active projects), displaying an aggregate of this information. A red light points out a problem, a yellow light shows that we’re processing a recent change, and a green light means that everything is running smoothly.&lt;/p&gt;


	&lt;p&gt;Another information radiator is our Atomic Spin Blog visitor tracker, a large cork board positioned in the center of our office. Each day, after our &lt;a href="http://spin.atomicobject.com/2009/07/07/10-reasons-we-have-daily-stand-up-meetings"&gt;stand up meeting&lt;/a&gt;, I update the chart for the previous day, making any appropriate “annotations,” like the primary source of traffic for that day. I also like to add people’s photos to the board when they create a new blog post. Last month, for instance, our shooting star &lt;a href="http://www.atomicobject.com/pages/Scott+Miller"&gt;Scott Miller&lt;/a&gt; literally jumped off the chart with his &lt;a href="http://spin.atomicobject.com/2010/01/04/faster-better-cheaper-tdd-wins-in-a-simple-experiment"&gt;post on &lt;span class="caps"&gt;TDD&lt;/span&gt;&lt;/a&gt;.
&lt;br&gt;&lt;/br&gt;
  &lt;div&gt;
  &lt;div class="imagebox"&gt;
  &lt;div&gt;
    &lt;img src="http://spin.atomicobject.com/assets/2010/2/8/corkboard.JPG?1265640121" alt="cork" /&gt;
  &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;


These information radiators are not intended to be a sole source of information. The stoplight follows our continuous integration monitor, and the blog board is a somewhat artistic interpretation of the information already stored in &lt;a href="http://www.google.com/analytics/"&gt;Google Analytics&lt;/a&gt;, annotations and all. But these visual and dynamic sources of information are not just about the “what” but also about the “how.” The stoplight is able to represent in a very simple way a company value – creating high-quality, ridiculously good, tested and working software at each step. It also provides an opportunity for us to talk about our development methods with visitors to the office. In the same vein, if someone has a hugely successful blog post, what is the best way to share that information? Spam the office with a company-wide email? Tell everyone to access the analytics account themselves and keep tabs? Or is it to get out a ladder so that you can tack a big yellow star near the ceiling? There is something about yarn and stars that just works.

 &lt;div&gt;
  &lt;div class="imagebox"&gt;
  &lt;div&gt;
    &lt;img src="http://spin.atomicobject.com/assets/2010/2/8/Millerstar.JPG?1265639824" alt="scott's star" /&gt;
  &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

	&lt;p&gt;And how do I know? People have told me. “I really want to blog now – so I can get a star.” Okay, so that was probably sarcastic, but the chart nevertheless has the power to encourage all of us to pay attention and contribute to the blog. It makes it very easy to represent – for instance – the fact that this month’s line is higher than last month’s line, or that so-and-so’s blog posts contributed to that success. The chart provides a connection between blogging effort and the popularity of our blog. And it makes me do &lt;em&gt;my&lt;/em&gt; job better and promote our blog like crazy.&lt;/p&gt;


	&lt;p&gt;In sum, the information radiators do more than radiate information. They do it in a way that – because it’s highly visual and fun – is able to rally the team and create excitement about the various goals and objectives we have as a company.&lt;/p&gt;


	&lt;p&gt;PS – Help me get a star by sharing this article!&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qOzXI77VCDk:9VzaqBR_KJc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qOzXI77VCDk:9VzaqBR_KJc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=qOzXI77VCDk:9VzaqBR_KJc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qOzXI77VCDk:9VzaqBR_KJc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=qOzXI77VCDk:9VzaqBR_KJc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qOzXI77VCDk:9VzaqBR_KJc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=qOzXI77VCDk:9VzaqBR_KJc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=qOzXI77VCDk:9VzaqBR_KJc:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/qOzXI77VCDk" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/08/information-radiators</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Marissa Christy</name>
      <uri>http://www.atomicobject.com/pages/Marissa+Christy</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-05:42429</id>
    <published>2010-02-05T17:05:00Z</published>
    <updated>2010-02-16T14:47:00Z</updated>
    <category term="Conferences" />
    <category term="Professional Development" />
    <category term="Technologies" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/r1pVgdjoMos/shawn-anderson-to-present-at-la-rubyconf-and-scale" rel="alternate" type="text/html" />
    <title>Shawn Anderson to present at LA RubyConf and SCALE</title>
<summary type="html">&lt;p&gt;Later this month, &lt;a href="http://www.atomicobject.com/pages/Shawn+Anderson"&gt;Shawn Anderson&lt;/a&gt; will be going back to Cali, his previous home, to make back-to-back presentations at two different conferences:  &lt;a href="http://larubyconf.com"&gt;LA RubyConf&lt;/a&gt; and &lt;a href="http://www.socallinuxexpo.org/scale8x/" title="Southern California Linux Expo"&gt;&lt;span class="caps"&gt;SCALE&lt;/span&gt;&lt;/a&gt; (the second time in two years). For both, he is presenting on developing 2D games using Ruby and open source tools (including a library that he wrote).&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Later this month, &lt;a href="http://www.atomicobject.com/pages/Shawn+Anderson"&gt;Shawn Anderson&lt;/a&gt; will be going back to Cali, his previous home, to make back-to-back presentations at two different conferences:  &lt;a href="http://larubyconf.com"&gt;LA RubyConf&lt;/a&gt; and &lt;a href="http://www.socallinuxexpo.org/scale8x/" title="Southern California Linux Expo"&gt;&lt;span class="caps"&gt;SCALE&lt;/span&gt;&lt;/a&gt; (the second time in two years). For both, he is presenting on developing 2D games using Ruby and open source tools (including a library that he wrote).&lt;/p&gt;
&lt;p&gt;&lt;img title="Gamebox Logo" src="http://spin.atomicobject.com/assets/2010/2/5/logo.png?1265386748" /&gt;
From an early age, Shawn distinguished himself as one who enjoyed gaming. Unlike other kids who were “reading” or engaging in “outdoor sports,” Shawn was content to stay in and finish off King Hippo in &lt;em&gt;Punch-Out!&lt;/em&gt;. Over the last couple years he has renewed this early childhood interest. Since college, he has been using his free time to develop games in Ruby; he has even created his own library for gaming in Ruby – Gamebox. Gamebox was designed to spring board game development. It allows the developer to define business rules about a game very quickly without having to worry about resource loading, sound/music management, creating windows, or messing with viewports. Shawn says he wrote Gamebox  for two reasons: first, to aid in 48 hour game writing competitions and second, to allow him to write simple educational games for his kid(s). He is currently working on a game called Snelps &lt;span class="caps"&gt;RTS&lt;/span&gt; (noneducational, from what I’ve seen), and the slightly educational Free Radicals.

	&lt;p&gt;This workshop is intended for people who already know Ruby but are interested in writing games in Ruby.  At the end of the class the participants will have a basic understanding of how 2D games work and will have created a small space invaders clone with animation and sound.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://www.socallinuxexpo.org/scale8x/presentations/pew-pew-writing-games-ruby"&gt;Info for Shawn’s LA RubyConf Presentation&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://www.socallinuxexpo.org/scale8x/presentations/pew-pew-writing-games-rubyç"&gt;Info for Shawn’s &lt;span class="caps"&gt;SCALE&lt;/span&gt; Presentation&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://gamebox.rubyforge.org/docs/getting_started_rdoc.html"&gt;Getting Started with Gamebox&lt;/a&gt; (&lt;a href="http://github.com/shawn42/gamebox"&gt;Source Code&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Snelps Screenshot:&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://spin.atomicobject.com/assets/2010/2/5/latest_screenshot_1.jpg?1265387162" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Free Radicals Screenshot:&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://spin.atomicobject.com/assets/2010/2/5/freeradicalssmall.jpeg?1265389333" alt="" /&gt;&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r1pVgdjoMos:yCzMFsyhP3g:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r1pVgdjoMos:yCzMFsyhP3g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=r1pVgdjoMos:yCzMFsyhP3g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r1pVgdjoMos:yCzMFsyhP3g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=r1pVgdjoMos:yCzMFsyhP3g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r1pVgdjoMos:yCzMFsyhP3g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=r1pVgdjoMos:yCzMFsyhP3g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=r1pVgdjoMos:yCzMFsyhP3g:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/r1pVgdjoMos" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/05/shawn-anderson-to-present-at-la-rubyconf-and-scale</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Shawn Crowley</name>
      <uri>http://www.atomicobject.com/pages/Shawn+Crowley</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-01:42338</id>
    <published>2010-02-01T22:24:00Z</published>
    <updated>2010-02-02T13:50:48Z</updated>
    <category term="Agile Practices" />
    <category term="Business of Software" />
    <category term="Conferences" />
    <category term="Software Design" />
    <category term="UI/UX" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/yf2Db9RbvdE/beyond-ux-and-agile" rel="alternate" type="text/html" />
    <title>Beyond UX and Agile</title>
<content type="html">
            &lt;p&gt;Last weekend I had the privilege of attending a UX Agile Retreat at &lt;a href="http://www.cooper.com"&gt;Cooper&lt;/a&gt;. The retreat was an informal event where ~33 practitioners from the UX and Agile fields came together to discuss how we can better create effective and successful products. The event schedule was loosely defined and it self organized based on the trending topics. We used a variety of exercises and discussion techniques to voice our experiences, concerns and ideas to help build a vision of a better, collaborative future.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Where We’ve Been&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;The UX and Agile communities have been flirting with how they could integrate their practices more seamlessly and respectfully. Both groups respected one another yet remained uneasy about having to alter their respective approaches for an integrated vision and process. UX Designers were worried that some of their practices would be minimized or marginalized due to Agilistas’ strong belief of minimal upfront design. Fear existed that quality design would be sacrificed to the almighty iteration once an agile project was underway. Agilistas were worried about designers doing too much work up front without creating functioning software. Developers were ignorant of the UX Design process and the immense value it provides. Individuals, like &lt;a href="http://www.agileproductdesign.com/blog/"&gt;Jeff Patton&lt;/a&gt; and &lt;a href="http://www.linkedin.com/pub/lane-halley/0/17/358"&gt;Lane Halley&lt;/a&gt;, have been working very hard to increase knowledge and respect between the two groups. &lt;a href="http://www.andersramsay.com/"&gt;Anders Ramsey&lt;/a&gt; organized and dedicated himself to making last week’s event happen. He did an outstanding job. The UX and Agile camps are coming together because they recognize and respect each other’s dedication to the craft of creating high quality products.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Where We Are&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Most of our discussions during the retreat focused on vision, values and principles instead of outlining a strategy for collaboration. I’m glad the group was able to remain focused at such a high level because good process stems from alignment and a mutually shared vision.&lt;/p&gt;


	&lt;p&gt;We took a stand that the “Us and Them” mentality is dead and that we have to move forward as “We.” Management and business processes have kept our groups apart in the past due to a focus on efficiency and a misunderstanding of what it takes to create successful digital products. Management often times does not know how to ask us for what they want, nor do they know how to properly manage creative teams. We believe that we can create better products more efficiently by focusing on being effective. We believe that effectiveness is increased by working together closely.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;The Future&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;The new vision is forming. The retreat group is committed to evangelizing and furthering this vision. I left the retreat with strong feelings of alignment, momentum and excitement. We are the makers of amazing, complex things and we are taking a stand on how we’ll bring the dreams of others into the world. We’re building a case for businesses to employ design thinking at all levels, to focus on the satisfaction of their customers and and to let individuals who understand the creative process to manage it for effectiveness.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=yf2Db9RbvdE:xkH4j1zh4uU:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=yf2Db9RbvdE:xkH4j1zh4uU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=yf2Db9RbvdE:xkH4j1zh4uU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=yf2Db9RbvdE:xkH4j1zh4uU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=yf2Db9RbvdE:xkH4j1zh4uU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=yf2Db9RbvdE:xkH4j1zh4uU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=yf2Db9RbvdE:xkH4j1zh4uU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=yf2Db9RbvdE:xkH4j1zh4uU:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/yf2Db9RbvdE" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/01/beyond-ux-and-agile</feedburner:origLink></entry>
  <entry xml:base="http://spin.atomicobject.com/">
    <author>
      <name>Matt Fletcher</name>
      <uri>http://www.atomicobject.com/pages/Matt+Fletcher</uri>
    </author>
    <id>tag:spin.atomicobject.com,2010-02-01:42144</id>
    <published>2010-02-01T13:11:00Z</published>
    <updated>2010-02-01T14:08:44Z</updated>
    <category term="Software Design" />
    <category term="Tips" />
    <category term="Tools" />
    <link href="http://feedproxy.google.com/~r/atomic_spin/~3/ZvJncACrxtU/the-case-for-embedding-jruby-complete-into-your-application" rel="alternate" type="text/html" />
    <title>The case for embedding jruby-complete into your application</title>
<content type="html">
            &lt;p&gt;Why in the world would you want to embed JRuby into your application instead of relying on a regular Ruby or JRuby installation? I can think of three reasons.&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Note: this is a sister post to &lt;a href="http://spin.atomicobject.com/2010/02/01/running-a-ruby-application-with-jruby-complete"&gt;my description of the arguments needed to run JRuby via jruby-complete&lt;/a&gt;. Here I discuss the rationale for using JRuby like this.&lt;/em&gt;&lt;/p&gt;


	&lt;h3&gt;What’s the upside?&lt;/h3&gt;


	&lt;p&gt;&lt;strong&gt;You can bundle your Ruby runtime dependence into the application.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;If you don’t know what I’m talking about here then you should probably stop reading right now. An old post by &lt;a href="http://errtheblog.com/posts/50-vendor-everything"&gt;Err the blog&lt;/a&gt; summarizes the “vendor everything” principle quite well:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Quickly: fix it! Tell everyone to install the gem locally. Install the gem on your staging server. Carefully install the gem on your production server. Phew. Everyone’s got the same version, right? Right. Well, maybe. (At least the build works.)&lt;/p&gt;
	&lt;/blockquote&gt;


I like vendoring the Ruby runtime for several reasons:
	&lt;ol&gt;
	&lt;li&gt;I don’t want to ask my users to install anything outside of my application. I definitely don’t want to count on the end user having something installed. Depending on end users having a compatible version of Java is frustrating enough, let alone a JRuby installation. Depending on the JRuby installation can be annoying for developers as well. Take culerity as an example. You could spend a bunch of time screwing around with &lt;a href="http://github.com/langalex/culerity/issues#issue/13"&gt;getting your system-wide JRuby installation just right&lt;/a&gt;. Or you could &lt;a href="http://github.com/fletcherm/culerity"&gt;embed JRuby directly into culerity&lt;/a&gt; and be done with it.&lt;/li&gt;
		&lt;li&gt;I don’t need to worry about version incompatibilities between the various runtimes. Incompatibilities can mean features I depend on are unavailable, subtly different, or outright broken. An interesting example of “subtly different” came up in an application I recently developed. At one point the sort implementation in JRuby changed from a stable sort to an unstable sort. As far as I know, Ruby doesn’t guarantee sort stability one way or another, so the change was ok from a Ruby perspective. Not so much for me. It turns out my application assumed a stable sort. Had I been dependent on the user’s Ruby installation, my application may have been using either the stable or unstable sort implementation, which was a variance it could not tolerate. (I’m glad I had &lt;a href="http://spin.atomicobject.com/2010/01/29/testing-terminology"&gt;automated integration tests&lt;/a&gt; that revealed this problem to me. I eventually concluded that the application’s behavior was fine with either the stable or unstable sort.)&lt;/li&gt;
		&lt;li&gt;Using &lt;a href="http://code.google.com/p/jarjar/"&gt;JarJar&lt;/a&gt; and &lt;a href="http://spin.atomicobject.com/2008/07/02/rolling-a-jruby-desktop-application"&gt;a few tricks&lt;/a&gt; means you can distribute your Ruby application as a single jar file.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;&lt;strong&gt;Your application may need to run in a constrained environment where you can’t install much, but Java is available.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;A couple of years ago I started development on a new application for monitoring PeopleSoft services. Installing Ruby on the servers I was deploying to was not an option. Java was already there to support PeopleSoft. Thank goodness JRuby 1.0 had just been released.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Managing one file is easier than managing many files.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Copying around one jar file is easier than copying a directory with hundreds of files in it. Yeah, manipulating a directory isn’t always a pain, but the times where manipulating a big directory is a pain can be a &lt;em&gt;really big pain&lt;/em&gt;.&lt;/p&gt;


	&lt;h3&gt;What’s the downside?&lt;/h3&gt;


	&lt;p&gt;&lt;strong&gt;Your application gets bigger.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;jruby-complete is currently (as of version 1.4.0) sitting at around 11.5 megabytes. Do I care? Nope. This can be annoying but it generally doesn’t bother me. Especially when my application is already measured in tens of megabytes.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Figuring out and typing the correct commands to run your application isn’t trivial.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;This part sucks. Running commands through jruby-complete is tedious when you don’t have any help from something like Rake tasks. The &lt;span class="caps"&gt;JVM&lt;/span&gt; boot time sucks as well. For these reasons I don’t recommend using jruby-complete for everything: when running small, one-off scripts, there’s just too much overhead. Thankfully, when I do depend on jruby-complete, I’m already working on an application where I’m using Rake to automate all kinds of things. So running lengthly &lt;code&gt;java&lt;/code&gt; commands isn’t a big deal because my Rake support is already there.&lt;/p&gt;


	&lt;p&gt;Thankfully, &lt;a href="http://spin.atomicobject.com/2010/02/01/running-a-ruby-application-with-jruby-complete"&gt;this companion post&lt;/a&gt; is chock full of tips for alleviating the pain from those nasty commands.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=ZvJncACrxtU:P4XdZ5NS9Kg:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=ZvJncACrxtU:P4XdZ5NS9Kg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=ZvJncACrxtU:P4XdZ5NS9Kg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=ZvJncACrxtU:P4XdZ5NS9Kg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=ZvJncACrxtU:P4XdZ5NS9Kg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=ZvJncACrxtU:P4XdZ5NS9Kg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?i=ZvJncACrxtU:P4XdZ5NS9Kg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/atomic_spin?a=ZvJncACrxtU:P4XdZ5NS9Kg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/atomic_spin?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/atomic_spin/~4/ZvJncACrxtU" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://spin.atomicobject.com/2010/02/01/the-case-for-embedding-jruby-complete-into-your-application</feedburner:origLink></entry>
</feed>
