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

<channel>
	<title>2Paths</title>
	<atom:link href="http://www.2paths.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.2paths.com</link>
	<description>Custom Software Technical Architecture, Design and Development in Vancouver, BC, Canada</description>
	<lastBuildDate>Mon, 09 Apr 2012 21:48:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Finding great people these days</title>
		<link>http://www.2paths.com/2012/04/09/finding-great-people-these-days/</link>
		<comments>http://www.2paths.com/2012/04/09/finding-great-people-these-days/#comments</comments>
		<pubDate>Mon, 09 Apr 2012 21:47:39 +0000</pubDate>
		<dc:creator>Gary</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[People]]></category>
		<category><![CDATA[.NET developers]]></category>
		<category><![CDATA[2Paths]]></category>
		<category><![CDATA[java developers]]></category>
		<category><![CDATA[web developers]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1377</guid>
		<description><![CDATA[Given the health and size of the tech world in Vancouver, the web developer scene in Vancouver is an interesting microcosm. In any labour market there are parallels with other markets, like real estate for instance, which Vancouver is all too familiar with. These days there is a seemingly insatiable demand for web developers, as [...]]]></description>
			<content:encoded><![CDATA[<p>Given the health and size of the tech world in Vancouver, the web developer scene in Vancouver is an interesting microcosm. In any labour market there are parallels with other markets, like real estate for instance, which Vancouver is all too familiar with. These days there is a seemingly insatiable demand for web developers, as organizations of all types and sizes continue to port their systems over to the internet or mobile platforms.</p>
<p>Lately in Vancouver we&#8217;ve seen the supply of developers tighten up as demand grows. Some developers, particularly those with more senior experience, are now in some cases getting multiple offers within a day or two. Whereas last year we could usually afford to spend several weeks in our screening and evaluation process, we&#8217;re finding we need to take less than a week or some good folks commit elsewhere. They can come off a project and be available only for a short time before being able to get onto another.</p>
<p>Having a history of doing interesting projects&#8211;especially for not only &#8220;feel-good&#8221;, but &#8220;do-good&#8221; causes such as global aid and development&#8211;has been helpful in finding good people or in some cases, having them find us. Having a track record for successful project conclusions of course helps as well. Conversely though, we are very picky about the skill level of people we bring on. This is reflected in part by our weighting on using mostly senior or sometimes intermediate developers in the vast majority of our projects. Using a technique common in many other industries, some development shops try to leverage the junior developers so they can maximize their profit&#8211;they cost less to employ, but bill out at high profit margins. However we&#8217;ve found that it&#8217;s better to sacrifice profit and ensure our quality is high. (No surprise that &#8220;profit&#8221; doesn&#8217;t appear in 2Paths&#8217; Core Values, Beliefs or Purpose!)</p>
<p>Is there a difference depending on the technology? For instance, some people in the industry say that demand is swinging more to open source and java, away from the Microsoft-y world and .NET. In our case, we&#8217;re not sure, but one thing we do know…we still have demand for development in both areas from our clients. Being technology agnostic has meant that some of our projects are open source-based, e.g. using java, whereas others may use .NET technologies. We continue to recommend the technology that best fits the client needs, regardless of the availability of resources.</p>
<p>In our view, those of us that focus on interesting yet challenging work and provide a great work environment will continue to find the talented folks they need.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2012/04/09/finding-great-people-these-days/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Interesting Vancouver on Oct 8th 2010</title>
		<link>http://www.2paths.com/2010/09/26/interesting-vancouver-on-oct-8th-2010/</link>
		<comments>http://www.2paths.com/2010/09/26/interesting-vancouver-on-oct-8th-2010/#comments</comments>
		<pubDate>Mon, 27 Sep 2010 01:15:46 +0000</pubDate>
		<dc:creator>Aaron</dc:creator>
				<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Events]]></category>
		<category><![CDATA[Featured]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1328</guid>
		<description><![CDATA[One of our colleagues, Mark Busse from Industrial Brand Creative, is helping to organize what looks to be a very&#8230;.interesting event:

	
“The plan is to have all sorts of speakers speak about all sorts of stuff. Not brands, advertising, blogging and twitter but interesting, unexpected, original things. I’m hoping to find fascinating people and to just [...]]]></description>
			<content:encoded><![CDATA[<p>One of our colleagues, <a href="http://twitter.com/markbusse">Mark Busse</a> from <a href="http://www.industrialbrand.com/">Industrial Brand Creative</a>, is helping to organize what looks to be a very&#8230;.interesting event:</p>
<blockquote><p>
	<a href="http://interestingvancouver.com/"><img src="http://evbdn.eventbrite.com/s3-s3/eventlogos/5479334/795576591.gif" alt="Interesting Vancouver" /></a></p>
<p>“The plan is to have all sorts of speakers speak about all sorts of stuff. Not brands, advertising, blogging and twitter but interesting, unexpected, original things. I’m hoping to find fascinating people and to just ask them to speak about something they care about. I want to replicate the experience of clicking from one really good blog to another, ranging across sciences, arts, musics, jokes and whatever.”</p>
<p>—Russell Davies, founder of Interesting</p>
</blockquote>
<p>The format is quite cool &#8211; a smallish number of speakers give 5 minute talks, and the rest of the night is unstructured.  The speakers are from quite the range of life and the topics look extremely thought provoking.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2010/09/26/interesting-vancouver-on-oct-8th-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cassandra Key-Value Store Primer</title>
		<link>http://www.2paths.com/2010/06/07/cassandra-key-value-store-primer/</link>
		<comments>http://www.2paths.com/2010/06/07/cassandra-key-value-store-primer/#comments</comments>
		<pubDate>Mon, 07 Jun 2010 17:56:55 +0000</pubDate>
		<dc:creator>Omar</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[cassandra]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[key-value store]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[thrift]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1286</guid>
		<description><![CDATA[The &#8220;no-sql&#8221; movement has been gaining strength over recent years. There is no denying that relational databases have their role and are highly effective in many cases. However, there are times when the scalability and availability of a relational database can become an issue. The &#8220;no-sql&#8221; movement is hoping to provide an alternative option to [...]]]></description>
			<content:encoded><![CDATA[<p>The &#8220;no-sql&#8221; movement has been gaining strength over recent years. There is no denying that relational databases have their role and are highly effective in many cases. However, there are times when the scalability and availability of a relational database can become an issue. The &#8220;no-sql&#8221; movement is hoping to provide an alternative option to relational databases. These options allow for the creation of data stores that do not necessarily require the creation of fixed schemas or the joining of tables and tend to focus on scaling horizontally. </p>
<p><strong>Apache Cassandra</strong><br />
<a href="http://cassandra.apache.org/">Cassandra</a> is a fairly recent addition to the &#8220;no-sql&#8221; movement. Initially developed by Facebook, Cassandra was open sourced in 2008 and is now housed and maintained by Apache.</p>
<blockquote><p>Cassandra is a highly scalable, eventually consistent, distributed, structured key-value store. Cassandra brings together the distributed systems technologies from Dynamo  and the data model from Google&#8217;s BigTable. Like Dynamo, Cassandra is eventually consistent. Like BigTable, Cassandra provides a ColumnFamily-based data model richer than typical key/value systems.</p>
<p>Cassandra was open sourced by Facebook in 2008, where it was designed by Avinash Lakshman (one of the authors of Amazon&#8217;s Dynamo) and Prashant Malik ( Facebook Engineer ). In a lot of ways you can think of Cassandra as Dynamo 2.0 or a marriage of Dynamo and BigTable. Cassandra is in production use at Facebook but is still under heavy development.</p></blockquote>
<p><strong>Data Model</strong><br />
The key difference between Cassandra and many of the other key-value stores is that it possesses the concept of a &#8220;Super Column.&#8221; For more information on what exactly a super column is (and an overview of the Cassandra data model in general) read the following blog post &#8220;<a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model">WTF is a SuperColumn? An Intro to the Cassandra Data Model</a>&#8221;</p>
<p><strong>Performance</strong><br />
Many may be curious about the performance of these key value stores. We found an article that compared <a href="http://blog.medallia.com/2010/05/choosing_a_keyvalue_storage_sy.html">Cassandra to Voldemort</a></p>
<p><strong>Interacting with Cassandra</strong><br />
Cassandra is developed in java however it does not allow access via JDBC. Instead it provides access to it&#8217;s repository via the &#8220;<a href="http://incubator.apache.org/thrift/">Apache Thrift</a>&#8221; framework which basically allows developers in any major language to gain access to a given service (in this case the Cassandra data store). For those like me who are used to JDBC, the thrift interface can be a bit confusing given that there isn&#8217;t much documentation for them. The Java client made available on the Cassandra website is rather rudimentary with no support for things like transactions, therefore many people choose to make use of a library called <a href="http://prettyprint.me/2010/02/23/hector-a-java-cassandra-client/">Hector</a> that provides many of the features necessary for any production worthy application making use of Cassandra.</p>
<p><strong>The Project </strong><br />
What I wanted to to do was use the Cassandra data store on a pet project that I&#8217;m working on in my spare time. I intend to use the datastore to do the following: </p>
<ol>
<li>Store messages being sent from one user to another</li>
<li>Track queries made by a given user</li>
<li>Store user complaints</li>
</ol>
<p><strong>Installation</strong><br />
Installation of the server is easy enough. Install Java 1.6 if you haven&#8217;t already. Edit <code>/bin/cassandra.in.sh</code> and change <code>JAVA_HOME</code> if you run a different version of java as your default<code> JAVA_HOME</code>. By default the server has an RMI port set to 8080, you can change the value in the <code>/bin/cassandra.in.sh</code> file as well.</p>
<p><strong>Configuration</strong><br />
Edit <code>/bin/storage-conf.xml</code> to define various key spaces and column families. The concept of a Keyspace is similar to the schema in a relational database, where as the ColumnFamily is analogous to a table. In defining the ColumnFamilies you are defining the key groupings and how they are sorted. Therefore, I defined the following:</p>
<pre class="brush: xml">
  &lt;Keyspaces&gt;
    &lt;Keyspace Name=&quot;Nikahfied&quot;&gt;

      &lt;ColumnFamily Name=&quot;Queries&quot;
                    Comment=&quot;User queries&quot;/&gt;

      &lt;ColumnFamily Name=&quot;Complaints&quot;
                    Comment=&quot;User complaints&quot;/&gt;

      &lt;ColumnFamily Name=&quot;Messages&quot;
                    ColumnType=&quot;Super&quot;
                    CompareWith=&quot;UTF8Type&quot;
                    CompareSubcolumnsWith=&quot;UTF8Type&quot;
                    RowsCached=&quot;10000&quot;
                    KeysCached=&quot;50%&quot;
                    Comment=&quot;Message threads between users of the system&quot;/&gt;

    &lt;/Keyspace&gt;
  &lt;/Keyspaces&gt;
</pre>
<p>I would be creating a schema named Nikahfied and three table are Queries, Complaints and Messages. As you will notice, there is no real structure to the ColumnFamilies other than what type of column and the CompareWith strategy as outlined in the &#8220;<a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model">WTF is a SuperColumn? An Intro to the Cassandra Data Model</a>&#8221; article. In this case we have one super column and two regular columns. In code I will ensure that each of the rows fore each ColumnFamily contain the same content however there is nothing forcing you to do so. As you will notice, we can configure each of the ColumnFamiles individually. Messages will need to handle heavy reads and writes where as Queries and Complaints will be more write intensive. Messages therefore have a caching scheme defined where as the others do not as they will primarily handle writes rather than reads.</p>
<p>When initially defining the column structure I was a bit confused. I was taking the definition of Cassandra as a &#8220;key value store&#8221; literally and was confused about there being a primary key and the secondary keys. When defining a basic Column I though it would simple have a key and a value. So things would be defined as <code>Nikahfied.&lt;ColumnFamily&gt;.key = value</code> where this is actually not the case. For a basic ColumnFamily, the structure is as follows: <code>Nikahfied.&lt;ColumnFamily&gt;.&lt;Primary key&gt;.&lt;Secondary Key&gt; = value</code>. In the case of a super column, this goes one level further <code>Nikahfied.&lt;ColumnFamily&gt;.&lt;Primary key&gt;.&lt;Secondary Key&gt;.&lt;Tertiary Key&gt; = value</code>. That had me puzzled for some time&#8230;upon re-reading the &#8220;<a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model">WTF is a SuperColumn? An Intro to the Cassandra Data Model</a>&#8221; article I realized my mistake so I though I&#8217;d point it out to anyone else who was confused about this construct.</p>
<p><strong>Data Structures:</strong><br />
<span style="text-decoration:underline">Queries:</span><br />
The structure of queries would be simple enough. I would store each query by date/time. To track which queries the user made when.</p>
<p><code>Nikahfied.Queries.UserId.&lt;Date/Time&gt; = &lt;Query&gt;</code></p>
<p><span style="text-decoration:underline">Complaints:</span><br />
There is only one type of complaint wherein a user can complain about another user. So I wanted to track who received the complaint, who complained and when. The structure of a complaint would be defined as follows:<br />
<code>Nikahfied.Complaints.&lt;Violator Id&gt;.&lt;Complainant Id&gt; = &lt;Date/Time&gt;</code></p>
<p><span style="text-decoration:underline">Messages:</span><br />
If there was ever a case to use a super column, a messages would be it. A user has a number of threads that contain one or more message. A user can receive and send messages. Messages themselves are the same, I simply need to track which threads contain messages that a user sent. I also need to keep track of which threads have unread messages within them. My initial design was the following:<br />
<code>Nikahfied.Messages.RecipientId.threads = A JSON Object that contains Threads defined in JSON Objects themselves. A thread being a group of<br />
                              .sent_ids = An array of thread id's that contain messages that the user has sent<br />
                              .unread_ids = An array of thread ids that contain unread messages</code></p>
<p>However, with this structure there was no need for a super column and I was determined on making use of one <img src='http://www.2paths.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . So I expanded out the thread structure as follows:</p>
<p><code>Nikahfied.Messages.RecipientId.threads.&lt;thread id&gt; = A JSON Object that contains an individual Thread<br />
                              .sent_ids = An array of thread id's that contain messages that the user has sent<br />
                              .unread_ids = An array of thread ids that contain unread messages</code></p>
<p>Now that we have the content structure defined I now need to create a hook between my application and the Cassandra key value store. For development I have decided to use the Grails Framework to speed up development. I have included the Hector library to access the framework but needed to define a CassandraService to be the central point of contact between various controllers and other services to the Cassandra key store. Both Cassandra&#8217;s Thrift interface and Hector have pretty poor documentation so I created a Grails service that makes the interaction with Cassandra a bit clearer (at least to me). <span style="text-decoration:underline;font-weight:bold">Note:</span> You will need to be using Java 1.6.</p>
<pre class="brush: groovy">
import me.prettyprint.cassandra.service.CassandraClientPool
import me.prettyprint.cassandra.service.CassandraClientPoolFactory
import me.prettyprint.cassandra.service.CassandraClient
import me.prettyprint.cassandra.service.Keyspace
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnPath;
import org.apache.cassandra.thrift.NotFoundException;

import org.apache.cassandra.thrift.SuperColumn

class CassandraService {

    boolean transactional = true

    def servers=[&quot;localhost:9160&quot;]
    def defaultKeyspace=&quot;Nikahfied&quot;
    private static final String NOT_FOUND = &quot;&quot;

    private execute(keyspaceName=defaultKeyspace,block){
        CassandraClientPool pool = CassandraClientPoolFactory.INSTANCE.get();
        CassandraClient client = pool.borrowClient(servers);

        try {
            Keyspace keyspace = client.getKeyspace(keyspaceName)
            return block(keyspace)
        } finally {
            pool.releaseClient(client);
        }
    }

    /**
     * Get a single super column
     * @param columnFamily
     * @param secondaryKey
     * @param key primary key
     * @return Matching super column
     */
    public SuperColumn getSuperColumn(String columnFamily, String key, String secondaryKey) {
        ColumnPath cp = new ColumnPath(columnFamily)
        cp.setSuper_column(secondaryKey.bytes)
        return execute {Keyspace keyspace -&amp;gt;
            SuperColumn sc = null;
            try {
                sc = keyspace.getSuperColumn(key, cp)
            } catch (NotFoundException nfe) {
                sc = null;
            }
            return sc
        }
    }

    /**
     * Get multiple super columns
     * @param columnFamily
     * @param secondaryKey
     * @param keys primary keys
     * @return matching super columns
     */
    public Map multigetSuperColumn(String columnFamily, List keys, String secondaryKey) {
        ColumnPath cp = new ColumnPath(columnFamily)
        cp.setSuper_column(secondaryKey.bytes)
        return execute {Keyspace keyspace -&amp;gt;
            Map scMap = keyspace.multigetSuperColumn(keys, cp)
            return scMap
        }
    }

    /**
     * Get multiple columns
     * @param secondaryKey secondaryKey
     * @param keys primary keys
     * @param columnFamily column family
     * @return results if any
     */
    public Map multigetColumn(List keys, String secondaryKey, String columnFamily) {
    	ColumnPath cp = new ColumnPath(columnFamily)
        cp.setColumn(secondaryKey.bytes)
        return execute {Keyspace keyspace -&amp;gt;
            Map cMap = keyspace.multigetColumn(keys, cp)
            return cMap
        }
    }

    /**
     * Get a single column and it&#039;s values
     * @param columnFamily
     * @param key primary key
     * @return matching column
     */
    public Column getColumn(String columnFamily, String key, String secondaryKey) {
        def cp = new ColumnPath(columnFamily)
        cp.setColumn(secondaryKey.bytes)
        return execute {Keyspace keyspace -&amp;gt;
            Column c = null;
            try {
                c = keyspace.getColumn(key, cp)
            } catch (NotFoundException nfe) {
                c = null;
            }
            return c
        }
    }

    /**
     * Sets the new value for this column path
     * @param cf Column family
     * @param secondaryKey secondary key
     * @param key primary key
     * @param value value
     */
    def setColumnPathValue(String cf, String key, String secondaryKey, String value){
        def cp = new ColumnPath(cf)
        cp.setColumn(secondaryKey.bytes)
        return setColumnValue(cp, key, value)
    }

    /**
     * Sets the new super column value for this column path
     * @param cf Column Family
     * @param sc Super Key Id
     * @param secondaryKey Secondary Key
     * @param key primary key
     * @param value value
     * @return the value of the Column requested
     */
    def setColumnPathValue(String cf, String sc, String key, String secondaryKey, String value){
        def cp = new ColumnPath(cf)
        cp.setSuper_column(sc.bytes)
        cp.setColumn(secondaryKey.bytes)
        return setColumnValue(cp, key, value)
    }

    /**
     * Set a regular column
     * @param cp Column path
     * @param key primary key
     * @param value value
     */
    private setColumnValue(ColumnPath cp, String key, String value){
        return execute{ Keyspace keyspace -&amp;gt;
            keyspace.insert(key, cp, value.bytes)
        }
    }

    /**
     * Batch insert content for a give key and it&#039;s values
     * @param key primary key
     * @param columnMap column key values
     * @param superColumnMap super column key values
     */
    public batchInsert(String key, Map&amp;lt;String, List&amp;gt; columnMap, Map&amp;lt;String, List&amp;gt; superColumnMap) {
    	return execute{ Keyspace keyspace -&amp;gt;
        	keyspace.batchInsert(key, columnMap, superColumnMap)
    	}
    }

}
</pre>
<p>Using this class I have created a MessageService, ComplaintsService and a QueriesService that interact with the CassandraService to retrieve and store data. There is an adjoining Message and Complaints controller where as the QueriesService is referenced by the SearchController. Hopefully this blog post will provide you with a better understanding of how to get started with Cassandra the CassandraService class should provide you with a jump start on integrating Cassandra into an existing Grails or Java project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2010/06/07/cassandra-key-value-store-primer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Leadership Excellence</title>
		<link>http://www.2paths.com/2009/11/09/leadership-excellence/</link>
		<comments>http://www.2paths.com/2009/11/09/leadership-excellence/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 23:38:35 +0000</pubDate>
		<dc:creator>Kari</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Culture]]></category>
		<category><![CDATA[People]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[leadership]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1268</guid>
		<description><![CDATA[About a year ago, we purchased a great learning package called &#8220;Lessons in Leadership&#8221; from the Business Source.  Besides receiving a Book Library (similar to the Coles&#8217; Notes) of the top Leadership and Financial Success books written, we also recieved five &#8211; 90 minute video modules  which include leadership sessions from five leadership gurus.
I once [...]]]></description>
			<content:encoded><![CDATA[<p>About a year ago, we purchased a great learning package called &#8220;Lessons in Leadership&#8221; from the Business Source.  Besides receiving a Book Library (similar to the Coles&#8217; Notes) of the top Leadership and Financial Success books written, we also recieved five &#8211; 90 minute video modules  which include leadership sessions from five leadership gurus.</p>
<p>I once heard Stephen Covey speak years ago and the main thing I remembered is that you don&#8217;t truly learn until you teach others.  So, throughout this past year, I&#8217;ve been able to take the learnings from the materials and adapt them to our needs so that our team could improve their communication skills and continue developing their leadership qualities.</p>
<p>In September of this year, I reviewed the module entitled &#8220;Leadership Excellence&#8221; which involved John Maxwell, author of <em>The 21 Irrefutable Laws of Leadership</em> and felt our entire team, technical or otherwise, would benefit from hearing some of the key messages John was imparting about the real measures of leaders and what causes people to truly connect and be inspired to follow a leader.   I decided to take the information presented in the video segment and reorganize it to create a condensed version of the learnings and attention span of  our team (under 30 minutes).  Those that attended our lunch hour &#8220;non&#8221; Techtalk, found it insightful and and useful.</p>
<p>I also reviewed another module called &#8220;How to be a more Influential and Persuasive Leader&#8221; presented by Kevin Hogan. This module, although similar in terms of overall topic, had a completely different approach and point of view. It really highlighted a variety of tactics people, and also leaders in a workplace, can use to influence behaviour of others (children, employees, potential customers, and hiring managers).  To share this knowledge with our team, I decided to send out daily leadership nuggets by email (less than 1 minute) that team members could read, digest and use as they felt relevant.</p>
<p>A third module I reviewed called &#8220;Becoming a Better Communicator (especially in crucial conversations)&#8221; presented by Ron McMillan, was also very interesting and involved the strategies master communicators use when having &#8220;crucial conversations&#8221; with team members.  I actually prepared a half-day workshop for our Support Crew including discussion time, and exercises, and was able to use some of the supporting materials from Ron McMillan&#8217;s organization www.crucialconversations.com to analyze the team&#8217;s individual and collective strengths in having these types of tough conversation.</p>
<p>The entire &#8220;Lessons in Leadership&#8221; package is certainly worth the cost and I encourage you to check out http://thebusinesssource.com/ for other products.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/11/09/leadership-excellence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>one-to-many relationships in Grails forms</title>
		<link>http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/</link>
		<comments>http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 01:35:25 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Featured]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1228</guid>
		<description><![CDATA[Here&#8217;s a scenario we see fairly often in our Grails applications.

 Parent object has a collection of Child objects
We want the Parent&#8217;s create and edit GSPs to allow us to add/remove/update associated Child objects
The controller should correctly persist changes to the collection of Child objects, including maintaining Child object ids so any other objects referencing [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a scenario we see fairly often in our <a href="http://www.grails.org/">Grails</a> applications.</p>
<ul>
<li> Parent object has a collection of Child objects</li>
<li>We want the Parent&#8217;s create and edit GSPs to allow us to add/remove/update associated Child objects</li>
<li>The controller should correctly persist changes to the collection of Child objects, including maintaining Child object ids so any other objects referencing them don&#8217;t get screwed up</li>
</ul>
<p>I found a really nice solution that avoids adding a lot of code to the controller to sift out added/changed/deleted collection members. The original page seems to have disappeared, so here are copies from <a href="http://web.archive.org/web/20080822094606/http://www.lxisoft.com/web/guest/grails">archive.org</a> (easier to read) and <a href="http://docs.google.com/gview?a=v&amp;q=cache:yNp_JSw97_gJ:www.ambersand.org/c/document_library/get_file%3Fp_l_id%3D10913%26folderId%3D11055%26name%3DDLFE-101.pdf">Google cache</a> (PDF).</p>
<p>I was disappointed that the original page is gone, and I found some small errors in the sample code, so I thought it would be nice to document here.</p>
<p>Here&#8217;s a sample project I created to go through this. Source code: <a href="http://www.2paths.com/wp-content/uploads/2009/09/one-many.tar.gz">one-many.tar.gz</a></p>
<p>The original example used Quest objects that can hold many Task objects. I&#8217;ll follow the <a href="http://www.grails.org/Quick+Start">Grails docs</a> and use Author objects that can hold many Book objects.</p>
<p>First, create the Author class.</p>
<pre class="brush: java">
    import org.apache.commons.collections.list.LazyList;
    import org.apache.commons.collections.FactoryUtils;

    class Author {

        static constraints = {
        }

        String name
        List books = new ArrayList()
        static hasMany = [ books:Book ]

        static mapping = {
            books cascade:&quot;all,delete-orphan&quot;
        }

        def getExpandableBookList() {
            return LazyList.decorate(books,FactoryUtils.instantiateFactory(Book.class))
        }

    }
</pre>
<p>(Here&#8217;s a minor correction I had to make to the original document&#8217;s code. They declared getExpandableBookList as returning a List, but that gave unknown property errors. Using a plain def fixed that.)</p>
<p>This adds a bunch of useful behaviour right away. The mapping block declares that books will be deleted when they&#8217;re removed from the Author.books collection, so we don&#8217;t need to clean up anything manually. By initializing books to an empty ArrayList when an Author object is created, and by using the getExpandableBookList() method, we can easily add and remove Book objects to the Author.books collection.</p>
<p>Next, the Book class is pretty simple.</p>
<pre class="brush: java">
    class Book {

        static constraints = {
        }

        String title
        boolean _deleted

        static transients = [ &#039;_deleted&#039; ]

        static belongsTo = [ author:Author ]

        def String toString() {
            return title
        }

    }
</pre>
<p>Nothing too fancy here, but pay attention to the _deleted property. That&#8217;s what we&#8217;ll be using to filter out Book objects that need to be removed from the Author.book collection on updates.</p>
<p>For the views, I like to combine the guts of the create and edit GSPs into a template that they can both render.</p>
<pre class="brush: html">
    &lt;div class=&quot;dialog&quot;&gt;
        &lt;table&gt;
            &lt;tbody&gt;
                &lt;tr class=&quot;prop&quot;&gt;
                    &lt;td valign=&quot;top&quot; class=&quot;name&quot;&gt;&lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;&lt;/td&gt;
                    &lt;td valign=&quot;top&quot; class=&quot;value ${hasErrors(bean:authorInstance,field:&#039;name&#039;,&#039;errors&#039;)}&quot;&gt;
                        &lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;name&quot; value=&quot;${fieldValue(bean:authorInstance,field:&#039;name&#039;)}&quot;/&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
                &lt;tr class=&quot;prop&quot;&gt;
                    &lt;td valign=&quot;top&quot; class=&quot;name&quot;&gt;&lt;label for=&quot;books&quot;&gt;Books:&lt;/label&gt;&lt;/td&gt;
                    &lt;td valign=&quot;top&quot; class=&quot;value ${hasErrors(bean:authorInstance,field:&#039;books&#039;,&#039;errors&#039;)}&quot;&gt;
                        &lt;g:render template=&quot;books&quot; model=&quot;[&#039;authorInstance&#039;:authorInstance]&quot; /&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            &lt;/tbody&gt;
        &lt;/table&gt;
    &lt;/div&gt;
</pre>
<p>That uses _books.gsp to render the editable list of books.</p>
<pre class="brush: html">
&lt;script type=&quot;text/javascript&quot;&gt;
    var childCount = ${authorInstance?.books.size()} + 0;

    function addChild() {
        var htmlId = &quot;book&quot; + childCount;
        var deleteIcon = &quot;${resource(dir:&#039;images/skin&#039;, file:&#039;database_delete.png&#039;)}&quot;;
        var templateHtml = &quot;&lt;div id=&#039;&quot; + htmlId + &quot;&#039; name=&#039;&quot; + htmlId + &quot;&#039;&gt;\n&quot;;
        templateHtml += &quot;&lt;input type=&#039;text&#039; id=&#039;expandableBookList[&quot; + childCount + &quot;].title&#039; name=&#039;expandableBookList[&quot; + childCount + &quot;].title&#039; /&gt;\n&quot;;
        templateHtml += &quot;&lt;span onClick=&#039;$(\&quot;#&quot; + htmlId + &quot;\&quot;).remove();&#039;&gt;&lt;img src=&#039;&quot; + deleteIcon + &quot;&#039; /&gt;&lt;/span&gt;\n&quot;;
        templateHtml += &quot;&lt;/div&gt;\n&quot;;
        $(&quot;#childList&quot;).append(templateHtml);
        childCount++;
    }
&lt;/script&gt;

&lt;div id=&quot;childList&quot;&gt;
    &lt;g:each var=&quot;book&quot; in=&quot;${authorInstance.books}&quot; status=&quot;i&quot;&gt;
        &lt;g:render template=&#039;book&#039; model=&quot;[&#039;book&#039;:book,&#039;i&#039;:i]&quot;/&gt;
    &lt;/g:each&gt;
&lt;/div&gt;
&lt;input type=&quot;button&quot; value=&quot;Add Book&quot; onclick=&quot;addChild();&quot; /&gt;
</pre>
<p>And that uses _book.gsp to render the individual records. It&#8217;s a bit overkill to call out to another template for only a few lines of HTML, but that&#8217;s how the original example did it and I&#8217;ll do the same for consistency.</p>
<pre class="brush: html">
    &lt;div id=&quot;book${i}&quot;&gt;
        &lt;g:hiddenField name=&#039;expandableBookList[${i}].id&#039; value=&#039;${book.id}&#039;/&gt;
        &lt;g:textField name=&#039;expandableBookList[${i}].title&#039; value=&#039;${book.title}&#039;/&gt;
        &lt;input type=&quot;hidden&quot; name=&#039;expandableBookList[${i}]._deleted&#039; id=&#039;expandableBookList[${i}]._deleted&#039; value=&#039;false&#039;/&gt;
        &lt;span onClick=&quot;$(&#039;#expandableBookList\\[${i}\\]\\._deleted&#039;).val(&#039;true&#039;); $(&#039;#book${i}&#039;).hide()&quot;&gt;&lt;img src=&quot;${resource(dir:&#039;images/skin&#039;, file:&#039;database_delete.png&#039;)}&quot; /&gt;&lt;/span&gt;
    &lt;/div&gt;
</pre>
<p>Here&#8217;s where I changed a bit more from the original example. I used <a href="http://jquery.com/">jQuery</a> because the selectors make things easy. Basically we render the books from the already-persisted author object, and keep track (using the _deleted field) of any that the user wants to remove. We also keep track of new objects to add.</p>
<p>One of the reasons I really liked this technique was how little impact there is on the controller. We just need to add this to the update method in AuthorController.</p>
<pre class="brush: java">
    def update = {
        def authorInstance = Author.get( params.id )
        if(authorInstance) {
            if(params.version) {
                // ... version locking stuff
            }
        authorInstance.properties = params
        def _toBeDeleted = authorInstance.books.findAll {it._deleted}
        if (_toBeDeleted) {
            authorInstance.books.removeAll(_toBeDeleted)
        }
        // ... etc.
</pre>
<p>The original example added similar code to the save method, but I don&#8217;t think it&#8217;s required for new objects (since they don&#8217;t have any already-persisted books to delete, only new books to create) so I only put it in the update method. I also changed it from find{} to findAll{} to guarantee that we get a list, and checked that we have objects to remove before calling the removeAll().</p>
<p>And it works great! Let&#8217;s look at some screenshots of the application in action.</p>
<p>First, we can create a new author and add some books right here instead of creating them separately and then matching them up.</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/1.png" alt="Create Author" width="285" height="383" class="alignnone size-full wp-image-1232" /></p>
<p>Hit &#8220;Create&#8221; and it creates the Author and Book objects.</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/2.png" alt="Show Author" width="281" height="354" class="alignnone size-full wp-image-1232" /></p>
<p>Edit the author we just created and see how we get a form that looks the same.</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/3.png" alt="Edit Author" width="285" height="373" class="alignnone size-full wp-image-1232" /></p>
<p>However, it&#8217;s worth noting that the books displayed here are the already-persisted ones, so the form is keeping track of their ids and whether we should keep them or delete them on update. Let&#8217;s delete the first one and add two more new books.</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/5.png" alt="Edit Author" width="279" height="400" class="alignnone size-full wp-image-1232" /></p>
<p>Now when we hit &#8220;Update&#8221; the controller has to be smart enough to remove that first book from the Author.books collection, then create two new Book objects and add them to the collection. And naturally, it is.</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/6.png" alt="Show Author" width="286" height="376" class="alignnone size-full wp-image-1232" /></p>
<p>In addition to creating and destroying Book objects, we can update them. For example, let&#8217;s change the title of that first book to be the long version.</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/7.png" alt="Edit Author" width="291" height="402" class="alignnone size-full wp-image-1232" /></p>
<p>No problem!</p>
<p><img src="http://www.2paths.com/wp-content/uploads/2009/09/8.png" alt="Edit Author" width="553" height="386" class="alignnone size-full wp-image-1232" /></p>
<p>So that&#8217;s one-to-many relationships in Grails forms. I hope it&#8217;s useful.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Show me the data!  Seminar on Innovative Approaches to Turn Statistics into Knowledge 2009 (OECD, US Census Bureau, World Bank)</title>
		<link>http://www.2paths.com/2009/07/28/show-me-the-data-seminar-on-innovative-approaches-to-turn-statistics-into-knowledge-2009-oecd-us-census-bureau-world-bank/</link>
		<comments>http://www.2paths.com/2009/07/28/show-me-the-data-seminar-on-innovative-approaches-to-turn-statistics-into-knowledge-2009-oecd-us-census-bureau-world-bank/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 00:37:33 +0000</pubDate>
		<dc:creator>Aaron</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[aaron.gladders]]></category>
		<category><![CDATA[barcamp.vancouver]]></category>
		<category><![CDATA[bcv09]]></category>
		<category><![CDATA[bls]]></category>
		<category><![CDATA[linked.data]]></category>
		<category><![CDATA[michal.urbanski]]></category>
		<category><![CDATA[OECD]]></category>
		<category><![CDATA[semantic web]]></category>
		<category><![CDATA[us.bureau.of.labor.statistics]]></category>
		<category><![CDATA[us.census.bureau]]></category>
		<category><![CDATA[world.bank]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1162</guid>
		<description><![CDATA[(Update 20091005 &#8211; I gave the same talk at the US Bureau of Labor Statistics and Barcamp Vancouver 2009, in case you end up on this page from either source)
We recently presented at the Turning Statistics Into Knowledge conference, jointly organized by the US Census Bureau, the OECD and the World Bank, on July 15-16 [...]]]></description>
			<content:encoded><![CDATA[<p>(Update 20091005 &#8211; I gave the same talk at the US Bureau of Labor Statistics and Barcamp Vancouver 2009, in case you end up on this page from either source)</p>
<p>We recently presented at the <a href="http://www.oecd.org/progress/ict/statknowledge">Turning Statistics Into Knowledge</a> conference, jointly organized by the <a href="http://www.census.gov/">US Census Bureau</a>, the <a href="http://www.oecd.org/">OECD</a> and the <a href="http://www.worldbank.org/">World Bank</a>, on July 15-16 in DC at the Census Bureau.  Here is a <a href='http://www.2paths.com/wp-content/uploads/2009/07/tsik.zip'>pdf</a> of it including our speaking notes, or you can click through it below, sadly without notes (goto the slideshare site to see the notes).</p>
<div style="width:425px;text-align:left" id="__ss_1776637"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/2Paths/show-me-the-data-turning-statistics-into-knowledge-2009" title="Show me the Data!  Turning Statistics Into Knowledge 2009">Show me the Data!  Turning Statistics Into Knowledge 2009</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=20090715-turningstatisticsintoknowledgerevised-090727160953-phpapp01&#038;stripped_title=show-me-the-data-turning-statistics-into-knowledge-2009" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=20090715-turningstatisticsintoknowledgerevised-090727160953-phpapp01&#038;stripped_title=show-me-the-data-turning-statistics-into-knowledge-2009" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/2Paths">2Paths</a>.</div>
</div>
<p>I promised a number of people links to non-technical to technical primers, here we go:</p>
<p><strong>Non-technical</strong></p>
<ol>
<li>Very straight-forward overview, very good for sharing with non-technical people:<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/OGg8A2zfWKg&#038;hl=en&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/OGg8A2zfWKg&#038;hl=en&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></li>
<li>Very quick one-pager, &#8220;<a href="http://ajbadd.wordpress.com/2009/06/09/the-semantic-web-a-low-fat-no-nonsense-introduction/">The “Semantic Web”: a low-fat, no-nonsense introduction</a>&#8221; by <a href="http://twitter.com/ajubdeen">@ajubdeen</a></li>
<li><a href="http://www.sciam.com/article.cfm?id=the-semantic-web&#038;print=true">Original article</a> from <a href="http://www.w3.org/People/Berners-Lee/">Tim Berners-Lee</a> showing his vision.</li>
<li>CNN <a href="http://www.cnn.com/2008/TECH/12/17/db.semanticweb/index.html?eref=rss_tech">Making sense of the &#8217;semantic Web&#8217;</a></li>
<li><a href="http://www.ted.com/talks/tim_berners_lee_on_the_next_web.html">Tim Berners-Lee 2009 TED talk on Linked Data</a></li>
</ol>
<p><strong>Semi-technical</strong></p>
<ol>
<li>Largely non-technical, injects a few buzzwords, &#8220;<a href="http://www.slideshare.net/mediasemanticweb/quick-linked-data-introduction">Quick Linked Data Introduction</a>&#8221; by <a href="http://mhausenblas.blogr.com/stories/">Michael Hausenblas</a></li>
<li><a href="http://www.readwriteweb.com/archives/understanding_the_new_web_era_web_30_linked_data_s.php">Understanding the New Web Era: Web 3.0, Linked Data, Semantic Web</a> by <a href="http://www.readwriteweb.com/archives/author/richard-macmanus-1.php">Richard MacManus</a>, summarizing a multi-part overview by <a href="http://twitter.com/gregboutin">Greg Boutin</a></li>
</ol>
<p><strong>Technical</strong></p>
<ol>
<li>An <strong>excellent</strong> overview &#8220;<a href="http://www.slideshare.net/mediasemanticweb/linked-data-michael-hausenblas-2009-03-05">Linked Data Tutorial</a>&#8221; by <a href="http://mhausenblas.blogr.com/stories/">Michael Hausenblas</a></li>
<li><a href="http://www.slideshare.net/iandavis/30-minute-guide-to-rdf-and-linked-data">30 Minute Guide to RDF and Linked Data</a> by <a href="http://twitter.com/iand">Ian Davis</a> and <a href="http://twitter.com/tommyh">Tom Heath</a></li>
</ol>
<p>After that, you&#8217;re off to the races!</p>
<p>(but as I said, just send us an email if you have questions or wanted to talk about it some more)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/07/28/show-me-the-data-seminar-on-innovative-approaches-to-turn-statistics-into-knowledge-2009-oecd-us-census-bureau-world-bank/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Groovy meetup  &#8211; Boats.com and SpringSource Groovy plugin for Eclipse</title>
		<link>http://www.2paths.com/2009/07/24/groovy-meetup-boatscom-and-springsource-groovy-plugin-for-eclipse/</link>
		<comments>http://www.2paths.com/2009/07/24/groovy-meetup-boatscom-and-springsource-groovy-plugin-for-eclipse/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 16:14:43 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1149</guid>
		<description><![CDATA[Last night was a great Groovy meetup at the Boats.com office here in downtown Vancouver. I got to use the new Burrard Bridge dedicated bike lanes, which is always fun, but it was the meetup content that I really enjoyed.
Yuri from Boats.com went through their experience of using Groovy and Grails for some real projects.

Using [...]]]></description>
			<content:encoded><![CDATA[<p>Last night was a great <a href="http://groovyvan.wordpress.com/2009/07/12/vancouver-groovy-grails-meetup-july/">Groovy meetup</a> at the <a href="http://groovyvan.wordpress.com/2009/07/12/vancouver-groovy-grails-meetup-july/">Boats.com</a> office <a href="http://maps.google.ca/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=1111+Melville+Street,+Vancouver,+Canada&amp;sll=49.891235,-97.15369&amp;sspn=33.830834,78.046875&amp;ie=UTF8&amp;ll=49.286647,-123.122213&amp;spn=0.008328,0.019054&amp;z=16&amp;iwloc=A">here</a> in downtown Vancouver. I got to use the new <a href="http://www.cbc.ca/canada/british-columbia/story/2009/07/13/bc-burrard-bridge-trial.html">Burrard Bridge dedicated bike lanes</a>, which is always fun, but it was the meetup content that I really enjoyed.</p>
<p>Yuri from Boats.com went through their experience of using <a href="http://groovy.codehaus.org/">Groovy</a> and <a href="http://www.grails.org/">Grails</a> for some real projects.</p>
<ul>
<li>Using Grails didn&#8217;t increase developer productivity, but it&#8217;s not the fault of Grails. Most of the holdups are non-technical &#8211; waiting for information, scope creep, redefining specs, etc.</li>
<li>Many tutorials show you can whip up a <a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> application in 5 minutes, but he doesn&#8217;t know anyone in the business of writing CRUD applications. Real applications involve a lot more, and Grails is certainly useful, but it&#8217;s not a simple &#8220;grails generate-my-whole-app&#8221; command like some of the tutorials seem to indicate.</li>
<li>There are lots of good plugins for UI elements, but you have to be careful to avoid Javascript hell. One plugin might use <a href="http://developer.yahoo.com/yui/">YUI</a>, another might use <a href="http://jquery.com/">jQuery</a>, another might use <a href="http://www.prototypejs.org/">Prototype</a>, etc. If you&#8217;re not careful, your web page might suddenty balloon to over a megabyte just for the sake of some rounded corners and accordion widgets. Not really surprising, but just something to be aware of.</li>
<li>Groovy and Grails add some layers of abstraction and they don&#8217;t come for free, so make sure your development machine has enough CPU and RAM (and especially disk IO speed, in my opinion) to handle it.</li>
<li>Because Java is mature, there are lots of nice power tools available for code analysis, etc. Groovy/Grails doesn&#8217;t have much of that yet.</li>
<li>Dynamic languages are cool and it was rewarding to try out.</li>
<li>Advertising their use of Groovy/Grails helped attract talented people.</li>
</ul>
<p>That last point was interesting. I had only thought about the stack from a technical/productivity point of view, but it turns out there&#8217;s a good human justification for trying it out. If you can bait people with shiny dynamic languages, it can pay off by increasing your developer talent pool.</p>
<p>Next, Andrew from <a href="http://www.springsource.com/">SpringSource</a> presented the Groovy plugin for <a href="http://www.eclipse.org/">Eclipse</a> that they hope to release very soon. Here at 2Paths, about half of us are using Eclipse for Grails development and about half are using <a href="http://www.jetbrains.com/idea/">IntelliJ IDEA</a>. Andrew walked through a demo showing off a bunch of work they&#8217;ve been doing.</p>
<ul>
<li>Support for lots of mixing between Java and Groovy. He declared a Groovy class in one file, then created a Java subclass in another file, and then a Groovy subclass of the Java subclass in a third file. Inheritance worked nicely and  the autocomplete magic appeared to be sufficiently magical.</li>
<li>There&#8217;s some code inspection happening so autocomplete knows about things like the findBy* methods on your Groovy objects. Declare a Foo property on the Bar class and autocomplete will know about Bar.findByFoo() automatically. Lots of incremental compilation happening everywhere.</li>
<li>Lots of improvements in communication between the Java and Groovy compilers. Apparently the old plugin managed the stub compilation with lots of temporary files, so it was constantly writing to and reading from the disk. The new plugin couples the two worlds better and does a lot in RAM, so it should be faster and not thrash the disk so much.</li>
<li>A working debugger! Conditional breakpoints work, but you have to watch out for all the casting that happens under the hood when checking values. There are still some bugs in setting and removing breakpoints, but it looks good so far. Andrew talked about how he&#8217;s still trying to decide how much of the Groovy stack frames and object decorations to show. They show up in IDEA, so you have to wade through many incomprehensibly named caller levels between your own method calls, but it&#8217;s all there in case you really want to know.</li>
<li>The plugin will be available from the same place on <a href="http://codehaus.org/">The Codehaus</a> as the old plugin and it should be a standard easy install. Once they have something they can release, they&#8217;re going to throw it over the fence to be an open source project and encourage outsiders to contribute.</li>
<li>They fiddle with the Eclipse compiling backend by patching in some behaviour that&#8217;s basically &#8220;if (groovy) { do new_thing } else { do normal_thing }&#8221; so the plugin will work with Eclipse 3.4.2 only. They&#8217;ve done a lot of testing to make sure their patch doesn&#8217;t hurt normal Java projects, but that version dependency could become frustrating.</li>
</ul>
<p>Personally, I switched to IDEA because of the debugging support, which works well in both running the application and the tests. I said that we&#8217;re pretty evenly split between IDEs at 2Paths and we compare notes every morning in a contest to see whose tools are the most annoying. It looks like this new plugin may push Eclipse back a few points on the annoying scale. Good work, Andrew and company.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/07/24/groovy-meetup-boatscom-and-springsource-groovy-plugin-for-eclipse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Grails 1.1 Testing &#8211; Unit, Integration &amp; Functional</title>
		<link>http://www.2paths.com/2009/07/20/grails-11-testing-unit-integration-functional/</link>
		<comments>http://www.2paths.com/2009/07/20/grails-11-testing-unit-integration-functional/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 21:50:28 +0000</pubDate>
		<dc:creator>dkoo</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Under the hood]]></category>
		<category><![CDATA[antbuilder]]></category>
		<category><![CDATA[controllerunittestcase]]></category>
		<category><![CDATA[functional test]]></category>
		<category><![CDATA[functional testing]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[grails 1.1]]></category>
		<category><![CDATA[grails testing]]></category>
		<category><![CDATA[grailsunittestcase]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[groovytestcase]]></category>
		<category><![CDATA[htmlunit]]></category>
		<category><![CDATA[integration test]]></category>
		<category><![CDATA[integration testing]]></category>
		<category><![CDATA[mockdomain]]></category>
		<category><![CDATA[unit test]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1138</guid>
		<description><![CDATA[Last Friday I gave a presentation to the team here at 2Paths on the testing capabilities in Grails 1.1.
As you Grails die-hards know, Grails 1.1 introduced the new GrailsUnitTestCase class which is a very useful extension of GroovyTestCase with support for mocking the dynamic properties and methods that Grails injects into various types of classes [...]]]></description>
			<content:encoded><![CDATA[<p>Last Friday I gave a <a href="http://www.slideshare.net/dkoo761/grails-11-testing-unit-integration-functional">presentation</a> to the team here at 2Paths on the testing capabilities in Grails 1.1.</p>
<p>As you Grails die-hards know, Grails 1.1 introduced the new <a href="http://grails.org/doc/1.1.1/guide/9.%20Testing.html#9.1%20Unit%20Testing">GrailsUnitTestCase</a> class which is a very useful extension of <a href="http://groovy.codehaus.org/Unit+Testing">GroovyTestCase</a> with support for mocking the dynamic properties and methods that Grails injects into various types of classes (domain, controller &amp; taglibs). Getting the team up to speed on this change was the original purpose of the presentation, but I decided to expand it to cover the full spectrum of testing capabilities in Grails 1.1 for those who might not have much exposure to it previously (including me!)</p>
<p>The presentation covered:</p>
<p>- the benefits &amp; drawbacks of each type of testing: <a href="http://en.wikipedia.org/wiki/Unit_testing">unit testing</a>, <a href="http://en.wikipedia.org/wiki/Integration_testing">integration testing</a>, <a href="http://en.wikipedia.org/wiki/Functional_testing">functional testing</a>.</p>
<p>- details on the new GrailsUnitTestCase and it&#8217;s extensions (ControllerUnitTestCase and TagLibUnitTestCase)</p>
<p>- a few &#8220;gotchas&#8221; &#8211; such as using mockDomain with inheritance hierarchies</p>
<p>- WebTest goodness &#8211; test organization &amp; re-use, Groovy step, passing params between Groovy &amp; WebTest contexts, a little dive into using HtmlUnit to test AJAX</p>
<p>- general recommendations for what types of tests to create for each artifact (domain classes, controllers, services, etc)</p>
<p>Here&#8217;s a link to the presentation on SlideShare.net (where you can view it online or download it):</p>
<div style="width: 425px; text-align: left;"><a title="Grails 1.1 Testing - Unit, Integration &amp; Functional" href="http://www.slideshare.net/dkoo761/grails-11-testing-unit-integration-functional">Grails 1.1 Testing &#8211; Unit, Integration &amp; Functional</a>  </p>
<div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/dkoo761">Dave Koo</a>.</div>
</div>
<p>Happy testing!<br />
Dave</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/07/20/grails-11-testing-unit-integration-functional/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>memcached and Grails</title>
		<link>http://www.2paths.com/2009/07/16/memcached-and-grails/</link>
		<comments>http://www.2paths.com/2009/07/16/memcached-and-grails/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 01:16:30 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Under the hood]]></category>
		<category><![CDATA[Utilities]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[scalability]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1122</guid>
		<description><![CDATA[I put together a Grails app to try out memcached. Like a lot of things in Grails, it was quite simple to integrate memcached once I found the right magic words. hibernate-memcached works nicely and has clear setup instructions.
Install memcached, which is simple if you use a Mac and have MacPorts installed.
$ sudo port install [...]]]></description>
			<content:encoded><![CDATA[<p>I put together a <a href="http://www.grails.org/">Grails</a> app to try out <a href="http://www.danga.com/memcached/">memcached</a>. Like a lot of things in Grails, it was quite simple to integrate memcached once I found the right magic words. <a href="http://code.google.com/p/hibernate-memcached/">hibernate-memcached</a> works nicely and has clear setup instructions.</p>
<p>Install memcached, which is simple if you use a Mac and have <a href="http://www.macports.org/">MacPorts</a> installed.</p>
<pre>$ sudo port install memcached</pre>
<p>Get the <a href="http://spymemcached.googlecode.com/files/memcached-2.3.1.jar">memcached jar</a> , the <a href="http://code.google.com/p/hibernate-memcached/downloads/list">hibernate-memcached jar</a> and the <a href="http://jdbc.postgresql.org/">PostgreSQL JDBC driver jar</a>, then  add them to the project.</p>
<pre>$ cp memcached-2.3.1.jar hibernate-memcached-1.2.jar postgresql-8.4-701.jdbc3.jar &lt;project_dir&gt;/lib/</pre>
<p>Configure memcached as the second-level cache by adding something like this to your DataSource.groovy.</p>
<pre><span class="pln">hibernate </span><span class="pun">{</span><span class="pln">
    cache</span><span class="pun">.</span><span class="pln">use_second_level_cache </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    cache</span><span class="pun">.</span><span class="pln">use_query_cache </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    cache</span><span class="pun">.</span><span class="pln">provider_class </span><span class="pun">=</span><span class="pln"> </span><span class="str">'com.googlecode.hibernate.memcached.MemcachedCacheProvider'</span><span class="pln">
    memcached </span><span class="pun">{</span><span class="pln">
        servers </span><span class="pun">=</span><span class="pln"> </span><span class="str">"localhost:11211"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>
<p>I wrote a simple test to generate a whole bunch of domain objects and shove them in the database, then go back and fetch them all again. I set the test to run the insert/load loops in batches of 1, 10, 100, 1,000, 2,000, 4,000, 7,000, and 10,000 objects. I expected that inserting the objects would take a little longer because of the memcached overhead but that loading the objects would be faster because they could be loaded from memcached instead of going out to the database.</p>
<p>I tested three persistence backend configurations.</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/HSQLDB">HSQLDB</a>, the default for new Grails projects and when running unit/integration tests. This is an in-memory database only, so data aren&#8217;t persisted permanently.</li>
<li><a href="http://en.wikipedia.org/wiki/PostgreSQL"> PostgreSQL</a> for a full-blown RDBMS setup. I set dbCreate to &#8220;create-drop&#8221; in <a href="http://docs.codehaus.org/display/GRAILS/Quick+Start">DataSource.groovy</a> so that each test started with an empty database.</li>
<li>PostgreSQL with memcached enabled. I should point out that in this test I had both PostgreSQL and memcached running on the same machine (my laptop) as the application, so it&#8217;s really not taking advantage of memcached&#8217;s parallelism strengths.</li>
</ul>
<p>My expectations held true for the inserts. The memcached case is a little slower but not that much.</p>
<div id="attachment_1123" class="wp-caption alignnone" style="width: 806px"><img class="size-full wp-image-1123 " title="db-compare-inserts" src="http://www.2paths.com/wp-content/uploads/2009/07/db-compare-inserts.png" alt="db-compare-inserts" width="796" height="516" /><p class="wp-caption-text">Comparison of object insert times using HSQL, PostgreSQL, and memcached+PostgreSQL for persistence backend</p></div>
<p>When I tested the load times, I was surprised. It looked like memcached wasn&#8217;t speeding things up at all. I was also surprised to see that it took less time to load 10,000 objects from the data store than 7,000 objects. I ran the test a few times to rule out the possibility of a load spike from something else running at the same time, but I got similar results every time.</p>
<div id="attachment_1124" class="wp-caption alignnone" style="width: 806px"><img class="size-full wp-image-1124 " title="db-compare-loads" src="http://www.2paths.com/wp-content/uploads/2009/07/db-compare-loads.png" alt="Comparison object load times using HSQL, PostgreSQL, and memcached+PostgreSQL for persistence backend" width="796" height="516" /><p class="wp-caption-text">Comparison of object load times using HSQL, PostgreSQL, and memcached+PostgreSQL for persistence backend</p></div>
<p>I then tried to improve my test setup by running memcached on a second machine (my desktop, connected by gigabit ethernet to the laptop). Using the PostgreSQL + memcached configuration for each test this time, I looked at three more scenarios.</p>
<ul>
<li>PostgreSQL running locally on the laptop, memcached running locally on the laptop.</li>
<li>PostgreSQL running locally on the laptop, memcached running remotely on the desktop.</li>
<li>PostgreSQL running locally on the laptop, memcached running on both the laptop and the desktop.</li>
</ul>
<p>There&#8217;s some overhead in going out to the network to retrieve data instead of fetching it from a process running locally, so I expected the memcached local instance to be faster than the memcached remote instance. I expected the third test, with two instances of memcached running in parallel, to be fastest because it splits the load between the two instances and frees up some CPU time on the laptop. Things didn&#8217;t play out that way, though.</p>
<div id="attachment_1125" class="wp-caption alignnone" style="width: 806px"><img class="size-full wp-image-1125" title="local-remote-inserts" src="http://www.2paths.com/wp-content/uploads/2009/07/local-remote-inserts.png" alt="Comparison of object insert times for various memcache setups" width="796" height="516" /><p class="wp-caption-text">Comparison of object insert times for various memcache setups</p></div>
<div id="attachment_1126" class="wp-caption alignnone" style="width: 806px"><img class="size-full wp-image-1126" title="local-remote-loads" src="http://www.2paths.com/wp-content/uploads/2009/07/local-remote-loads.png" alt="Comparison of object load times for various memcache setups" width="796" height="516" /><p class="wp-caption-text">Comparison of object load times for various memcache setups</p></div>
<p>I have to be honest that these were not great tests. For one, I should really have run those insert/load loops in parallel instead of sequentially. I&#8217;m guessing that the test spent a lot of time stalled waiting for data when it could have been sending out more requests. I would also like to test with a large group of memcached servers and a remote database, perhaps even a cluster of app servers with a load balancer to try the full meal deal. The <a href="http://code.google.com/p/memcached/wiki/FAQ#Memcached_is_not_faster_than_my_database._Why?">memcached FAQ</a> explains that running everything on one machine will not show off memcached&#8217;s scalability.</p>
<p>However, this gave me the opportunity to get my hands dirty with memcached and learn a few things.</p>
<ul>
<li>Integrating memcached is so simple and the performance penalty of just running it locally during development is so small that there&#8217;s no reason not to enable it.</li>
<li>It&#8217;s dead simple to install and set up. We could , for example, easily  install it on a bunch of test servers and run multiple instances on different ports &#8211; one for each developer (to prevent us from clobbering each other&#8217;s data).</li>
<li>Measuring performance and scalability realistically is tricky. It&#8217;s one thing to hand wave and say that running multiple instances of a database or a cache will speed things up, but it takes some work to set up a realistic simulation of high traffic application performance.</li>
<li>Adding memcached doesn&#8217;t automatically turn performance up to <a href="http://www.youtube.com/watch?v=EbVKWCpNFhY">11</a>. I need to learn more about what&#8217;s going on under the hood with my domain objects and how they&#8217;re being persisted through memcached.</li>
</ul>
<p>I look forward to using memcached more in the future and learning how to really take advantage of it.</p>
<p><strong>Update (2009-07-24)</strong>: Ray pointed out in the <a href="#comment-8792">comments</a> that I should have enabled <a href="http://www.grails.org/GORM+-+Mapping+DSL">caching</a> in my domain objects under test. I added &#8220;static mapping = { cache true }&#8221; to my domain class definition and re-ran the tests to compare the effect under 4 scenarios.</p>
<ul>
<li>no domain object caching (as before)</li>
<li>domain object caching with memcached running locally</li>
<li>domain object caching with memcached running remotely</li>
<li>domain object caching with memcached running both locally and remotely</li>
</ul>
<p>Not much difference with the inserts.</p>
<div id="attachment_1145" class="wp-caption alignnone" style="width: 806px"><img class="size-full wp-image-1145" title="cache-true-inserts" src="http://www.2paths.com/wp-content/uploads/2009/07/cache-true-inserts.png" alt="Comparison of object insert times with domain object caching enabled and disabled" width="796" height="516" /><p class="wp-caption-text">Comparison of object insert times with domain object caching enabled and disabled</p></div>
<p>However, the load times are slightly better with memcached enabled during heavy activity! The advantage disappears when I add the overhead of traversing the network, but it&#8217;s a start. Thanks for the pointer, Ray!</p>
<div id="attachment_1146" class="wp-caption alignnone" style="width: 806px"><img class="size-full wp-image-1146" title="cache-true-loads" src="http://www.2paths.com/wp-content/uploads/2009/07/cache-true-loads.png" alt="Comparison of object load times with domain object caching enabled and disabled" width="796" height="516" /><p class="wp-caption-text">Comparison of object load times with domain object caching enabled and disabled</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/07/16/memcached-and-grails/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Getting [On&#124;Off] the CouchDB?</title>
		<link>http://www.2paths.com/2009/06/30/getting-onoff-the-couchdb/</link>
		<comments>http://www.2paths.com/2009/06/30/getting-onoff-the-couchdb/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 00:13:39 +0000</pubDate>
		<dc:creator>Garrett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[MapReduce]]></category>
		<category><![CDATA[schema-free]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1066</guid>
		<description><![CDATA[Based on my recent experimenting with CouchDB I have conflicted feelings of whether to get on, or stay off the couch. I am intrigued by the notion of a schema-free document-based database, and how applications could be created to leverage such a technology. I am also reserved about its benefits to my current work environment. [...]]]></description>
			<content:encoded><![CDATA[<p>Based on my recent experimenting with <a href="http://couchdb.apache.org/" target="_blank">CouchDB</a> I have conflicted feelings of whether to get on, or stay off the couch. I am intrigued by the notion of a schema-free document-based database, and how applications could be created to leverage such a technology. I am also reserved about its benefits to my current work environment. Most of the relational data storage I&#8217;ve dealt with has been handled by Spring/Hibernate and now Grails/Hibernate. Does CouchDB buy anything that isn&#8217;t already easy to do with methodology like <a href="http://www.grails.org/GORM" target="_blank">GORM</a>? Let me attempt to dissect some of the pros and cons of CouchDB.</p>
<h3><em>PROS</em></h3>
<p>Probably the number one mentioned feature by anyone talking about CouchDB is that it&#8217;s schema-free. That means that each document is its own structure, that everything is based on a key-value pairing, where the value is typically a document, but can also be a base type. This is pretty cool when dealing with describing real world objects, as one can be more descriptive and hierarchical in storing the data. Also, updating your application&#8217;s domain model is much like evolution, as soon as you need something added to the model, just add it.</p>
<p>CouchDB&#8217;s RESTful HTTP service implementation is great for the many applications being created for today&#8217;s web. Send Javascript queries/requests to the service, and get JSON formatted data in return. This is great, since many front-end technologies can decipher JSON, and the format itself is even human readable if need be.</p>
<p>There is support for interacting with CouchDB data offline. One can access and edit data while not connected, and when back online can merge and update changes made while offline. This kind of support out of the box makes CouchDB a prime candidate for  web based applications like blogs, wikis, bug reporting, CRM, etc.</p>
<p>Another quality of CouchDB is its MapReduce implementation for handling large data sets. I&#8217;m going to redirect you to the author&#8217;s notes for this one: <a href="http://damienkatz.net/2008/02/incremental_map.html" target="_blank">MapReduce</a> and <a href="http://labs.google.com/papers/mapreduce.html" target="_blank">Google&#8217;s definition</a>.</p>
<h3><em>CONS</em></h3>
<p>Transaction management is non-existent. Relational database managements systems (RDBMS) provide mechanisms for things like transaction management, particularly unique constraints and locking. CouchDB is based on being &#8216;eventually consistent&#8217; and &#8216;available&#8217; (See the <a href="http://books.couchdb.org/relax/eventual-consistency" target="_blank">CAP Theorem section</a> for more), which although great for many things, doesn&#8217;t lend itself to transaction management.</p>
<p>Data security is also a concern. A somewhat old article describes this issue quite well: <a href="http://www.automatthew.com/2008/01/planned-security-model-for-couchdb.html" target="_blank">Planned Security Model For CouchDB</a>. The CouchDB team has been working on <a href="http://jchrisa.net/drl/_design/sofa/_show/post/couchdb_edge__security_and_vali" target="_blank">security and validation</a> but are still early in their development.</p>
<p>To a less important degree, but still worth mentioning, is that personally I really don&#8217;t find the out-of-the-box UI for CouchDB to be all that useful. It feels clunky to navigate your key/document pairs, and too feature-light for managing the database.</p>
<h3><em>Conclusion</em></h3>
<p>If you&#8217;re looking to create a document based web application, then this may be a worthwhile technology to use. CouchDB has a number of very impressive features. However, for now at least, I believe I&#8217;ll be staying off the couch.</p>
<hr />
<h5><em>Aside</em>:</h5>
<p>When testing out CouchDB I went through the process of manually installing the application. I had to resolve the dependencies, and deal with compilation errors on my own. I kind of wish I&#8217;d found <a href="http://jan.prima.de/~jan/plok/archives/142-CouchDBX-Revival.html" target="_blank">this site</a> earlier. Follow that link if you&#8217;re a MacOSX user and want an installer for CouchDB.</p>
<p>For me, this was pretty much the  only useful tutorial on getting started with CouchDB: <a href="http://jan.prima.de/~jan/plok/archives/108-Programming-CouchDB-with-Javascript.html" target="_blank">Programming CouchDB with Javascript</a>.</p>
<hr />
<h5><em>Resources</em>:</h5>
<ul>
<li><a href="http://couchdb.apache.org/" target="_blank">http://couchdb.apache.org/</a></li>
<li><a href="http://books.couchdb.org/relax/" target="_blank">http://books.couchdb.org/relax/</a></li>
<li><a href="http://www.eflorenzano.com/blog/tag/couchdb/" target="_blank">http://www.eflorenzano.com/blog/tag/couchdb/</a></li>
<li><a href="http://labs.google.com/papers/mapreduce.html" target="_blank">http://labs.google.com/papers/mapreduce.html</a></li>
<li><a href="http://damienkatz.net/2008/02/incremental_map.html" target="_blank">http://damienkatz.net/2008/02/incremental_map.html</a></li>
<li><a href="http://jan.prima.de/~jan/plok/archives/142-CouchDBX-Revival.html" target="_blank">http://jan.prima.de/~jan/plok/archives/142-CouchDBX-Revival.html</a></li>
<li><a href="http://www.automatthew.com/2008/01/planned-security-model-for-couchdb.html" target="_blank">http://www.automatthew.com/2008/01/planned-security-model-for-couchdb.html</a></li>
<li><a href="http://jchrisa.net/drl/_design/sofa/_show/post/couchdb_edge__security_and_vali" target="_blank">http://jchrisa.net/drl/_design/sofa/_show/post/couchdb_edge__security_and_vali</a></li>
<li><a href="http://jan.prima.de/~jan/plok/archives/108-Programming-CouchDB-with-Javascript.html" target="_blank">http://jan.prima.de/~jan/plok/archives/108-Programming-CouchDB-with-Javascript.html</a></li>
<li><a href="http://www.infoq.com/CouchDB" target="_blank">http://www.infoq.com/CouchDB</a></li>
<li><a href="http://www.infoq.com/news/2007/11/the-rdbms-is-not-enough" target="_blank">http://www.infoq.com/news/2007/11/the-rdbms-is-not-enough</a></li>
<li><a href="http://www.infoq.com/news/2008/11/Database-Martin-Fowler" target="_blank">http://www.infoq.com/news/2008/11/Database-Martin-Fowler</a></li>
<li><a href="http://code.google.com/p/couchdb-lounge/wiki/SettingUpTwoCouchInstances" target="_blank">http://code.google.com/p/couchdb-lounge/wiki/SettingUpTwoCouchInstances</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/06/30/getting-onoff-the-couchdb/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

