<?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 &#187; Technology</title>
	<atom:link href="http://www.2paths.com/category/blog/tech/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, 21 Jun 2010 20:53:06 +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>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>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>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>6</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>
		<item>
		<title>Visualizing Semantic Data using Javascript and the HTML Canvas Element</title>
		<link>http://www.2paths.com/2009/06/22/visualizing-semantic-data-using-javascript-and-the-html-canvas-element/</link>
		<comments>http://www.2paths.com/2009/06/22/visualizing-semantic-data-using-javascript-and-the-html-canvas-element/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 21:45:37 +0000</pubDate>
		<dc:creator>gord</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[rdf]]></category>
		<category><![CDATA[semantic]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1014</guid>
		<description><![CDATA[A work in progress visualization of freedb (RDF version of wikipedia).]]></description>
			<content:encoded><![CDATA[<p>So after trying a few existing javascript/canvas graph visualization libraries, I decided to try my hand at writing my own. We were doing a lot of stuff with RDF in the office at the time, so I decided that my visualization would be a graph of rdf data and relationships. Since I&#8217;d never done anything with the HTML canvas element before, I thought I&#8217;d give that a shot too.</p>
<p><strong>Graph Layout</strong></p>
<p>After looking at various existing graph layout algorithms, I decided to reinvent the wheel and developed my own approach. Each node has a mass based on its size, and I simply used gravity calculations to determine the (inverse, so they repel each other) force each node apples to each other node. You can see this in action when you mouse over a node, it gets bigger and other nodes retreat from it as its mass increases.</p>
<p>This allows each node to position itself in a way so it is visible. It&#8217;s not perfect, but it works okay and makes the graph feel responsive to the user.</p>
<p><strong>How to use it</strong></p>
<p>Double click on a node to load its relationships and related nodes. A node must be an rdf node to load properly, I haven&#8217;t implemented any way to handle normal web links yet. Basically, only click on links that look like <strong>h</strong><strong>ttp://dbpedia.org/resource/<em>something</em><span style="font-weight: normal;">, or that you know are rdf.</span></strong></p>
<div id="attachment_1016" class="wp-caption alignnone" style="width: 521px"><a href="http://staging.2paths.com:8080/deepsnow/" target="_self"><img class="size-full wp-image-1016" src="http://www.2paths.com/wp-content/uploads/2009/06/deepsnow1.png" alt="image of visualization in action, click for demo" width="511" height="300" /></a><p class="wp-caption-text">click for demo of the wikipedia article for baseball</p></div>
<p>If you&#8217;re just interested in the pretty pictures, stop here, if you want more technical information read on.</p>
<p><strong>Implementation</strong></p>
<p>I just used javascript and followed the <a href="http://www.whatwg.org/specs/web-apps/current-work/#canvasrenderingcontext2d" target="_blank">HTML5 docs for using the canvas element</a>. One thing I ran into was the fact that Firefox doesn&#8217;t yet have a full canvas implementation, specifically it doesn&#8217;t yet render text on the canvas. I tried doing some voodoo with absolute positioning divs containing text over the canvas, and after a brief descent into insanity, I found the excellent <a href="http://typeface.neocracy.org/">typeface.js</a> library which emulates the missing canvas calls for text.</p>
<p>As for the javascript code itself, I implemented a simple object graph that can contain vertices or edges, then a render loop just advances the object graph by a given amount of time and renders the scene to the canvas.</p>
<p>The back end serving up rdf was done quickly in grails using the <a href="http://jena.sourceforge.net/" target="_blank">Jena</a> framework to do all the heavy lifting. There is some minimal inference going on using the RDF data to determine if something is an image.</p>
<p><strong><strong>Disclaimer</strong></strong></p>
<p><strong><span style="font-weight: normal;">Keep in mind that this is a work of progress that I have not spent much time with. It has bugs, and it&#8217;s nowhere near usable for anything useful, but it serves its purpose as a proof of concept. I&#8217;m not sure if it will even run under IE, but it should run on any browser that has a decent javascript + canvas implementation.</span></strong></p>
<p><strong> </strong></p>
<p><strong>Conclusions</strong></p>
<p><strong><span style="font-weight: normal;">The canvas element is cool, and works well.</span></strong></p>
<p>Basically I hope you like it. Please leave any suggestions or feedback as comments. I realize it&#8217;s probably full of bugs, but that&#8217;s the nature of the beast.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/06/22/visualizing-semantic-data-using-javascript-and-the-html-canvas-element/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SolutionsIQ&#8217;s Certified Product Owner Course</title>
		<link>http://www.2paths.com/2009/06/19/solutionsiqs-certified-product-owner-course/</link>
		<comments>http://www.2paths.com/2009/06/19/solutionsiqs-certified-product-owner-course/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 16:17:59 +0000</pubDate>
		<dc:creator>Lorill</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[certification]]></category>
		<category><![CDATA[product owner]]></category>
		<category><![CDATA[scrum]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=1003</guid>
		<description><![CDATA[Working as both a Developer and as a ScrumMaster has skewed my perspective a bit to be dev-team centric, so I recently took SolutionsIQ&#8217;s Certified Product Owner course to learn more about the scrum software development process through the eyes of a Product Owner.
The course was laid out in a novel way &#8211; as a [...]]]></description>
			<content:encoded><![CDATA[<p>Working as both a Developer and as a ScrumMaster has skewed my perspective a bit to be dev-team centric, so I recently took <a href="http://www.solutionsiq.com/services/course-catalog.php#cspo">SolutionsIQ&#8217;s Certified Product Owner course</a> to learn more about the scrum software development process through the eyes of a Product Owner.</p>
<p>The course was laid out in a novel way &#8211; as a scrum project itself! As Product Owners we were asked to compose User Stories capturing what we hoped to learn from the course, and at the end of each &#8220;iteration&#8221; within the two-day course, were asked to re-prioritize these, knowing time was tight and we may not get to all topics. This helped us to have hands-on experience with Story creation and re-prioritization, with the added bonus of us each being personally invested in the outcome instead of it being a theoretical scenario.</p>
<p>One of the topics I was interested in was how to adapt the scrum process for a Product Owner that is not only not on site, but is overseas and in a different time zone. At 2Paths, one of our larger projects that was recently completed involved a client overseas. This project was very successful, and we accredited much of its success to our client&#8217;s buy-in and participation to our scrum process. We had, however, modified the traditional scrum process to accommodate our client&#8217;s schedule and time availability. Because they were quite busy with other projects, and due to the large time difference, the client didn&#8217;t attend our daily scrum as is recommended. Instead we had weekly phone check-ins which augmented our regular email communication to discuss issues as needed.</p>
<p>I was hoping in the course to see if there would be a more recommended way for this sort of Product Owner to be involved in a project, and how we could try to more closely follow the traditional scrum process. However, the course was more geared towards an internal Product Owner. This type of Product Owner would be a lot more hands on, would physically attend the daily scrum, and spend time sitting within the dev team to facilitate clearer communication. It also seemed that many of the other course attendees had similar project roles where the Product Owner was in-house. From what I could gather, I think we handled our process as well as we could given the circumstances.</p>
<p>The course was well organized, and the two presenters Bryan Stallings and Skip Angel were quite knowledgeable and helpful. We had many good group discussions and participants actively participated, sharing their own war stories. I&#8217;d recommend this course for other ScrumMasters wanting to get a better sense of what is required by a Product Owner, and how they fit into the scrum process.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/06/19/solutionsiqs-certified-product-owner-course/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AWS and large data sets</title>
		<link>http://www.2paths.com/2009/05/21/aws-and-large-data-sets/</link>
		<comments>http://www.2paths.com/2009/05/21/aws-and-large-data-sets/#comments</comments>
		<pubDate>Thu, 21 May 2009 16:59:44 +0000</pubDate>
		<dc:creator>Aaron</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Utilities]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[cloud computing]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=984</guid>
		<description><![CDATA[We&#8217;ve held back on going fully AWS as trying to get terabytes of data over to them would have been a colossal waste of time/money over a network connection.  Today, Amazon web services announced they can receive USB 2/esata devices up to 8U high if you want to load up large data sets into [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve held back on going fully AWS as trying to get terabytes of data over to them would have been a colossal waste of time/money over a network connection.  Today, Amazon web services announced they can receive USB 2/esata devices up to 8U high if you want to load up large data sets into their S3 service:</p>
<p><a href="http://aws.amazon.com/importexport/">AWS Import/Export</a></p>
<p>We haven&#8217;t analyzed the pricing but it is one more nail into the &#8220;let&#8217;s shut the dev cage down and go all cloud&#8221; debate.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/05/21/aws-and-large-data-sets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# features &#8211; LINQ primer</title>
		<link>http://www.2paths.com/2009/04/30/c-features-linq-primer/</link>
		<comments>http://www.2paths.com/2009/04/30/c-features-linq-primer/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 19:04:32 +0000</pubDate>
		<dc:creator>Geoff</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Under the hood]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[newbies]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=939</guid>
		<description><![CDATA[Language INtegrated Query (LINQ) adds extensions to the .NET framework which provide a domain specific language for querying and transforming collections right within C# (or VB for that matter). It provides syntax similar to other 4GL querying languages such as SQL, HQL or even OQL.
Below is a simple test case showing how to do LINQ [...]]]></description>
			<content:encoded><![CDATA[<p>Language INtegrated Query (<a href="http://msdn.microsoft.com/en-ca/library/bb308959.aspx">LINQ</a>) adds extensions to the .NET framework which provide a domain specific language for querying and transforming collections right within C# (or VB for that matter). It provides syntax similar to other 4GL querying languages such as SQL, HQL or even OQL.</p>
<p>Below is a simple test case showing how to do LINQ operations on a simple array:</p>
<pre class="brush: csharp">
        public void LinqArrayTest()
        {
            String[] names = { &quot;Burke&quot;, &quot;Connor&quot;, &quot;Frank&quot;,
                   &quot;Everett&quot;, &quot;Albert&quot;, &quot;George&quot;,
                   &quot;Harris&quot;, &quot;David&quot; };

            IEnumerable&lt;string&gt; query = from s in names
                               where s.Length == 5
                               orderby s
                               select s;

            List&lt;String&gt; results = query.ToList();

            Assert.AreEqual(3, results.Count);
            String[] expected = new String[] {&quot;Burke&quot;, &quot;David&quot;, &quot;Frank&quot;};
            for (int i = 0; i &lt; results.Count; i++)
            {
                Assert.AreEqual(expected[i], results.ElementAt(i));
            }
        }
</pre>
<p>It is also possible to create runtime LINQ queries using lambda expressions to qualify conditional logic:</p>
<pre class="brush: csharp">
        [TestMethod()]
        public void LinqLambdaTest()
        {
            String[] items = { &quot;cabbage&quot;, &quot;broccoli&quot;, &quot;carrot&quot;, &quot;parsnip&quot;, &quot;cauliflower&quot; };

            IEnumerable&lt;String&gt; query = items;

            // additive query generation using lambda expressions
            query = query.Where(item =&gt; item.StartsWith(&quot;c&quot;));
            query = query.Where(item =&gt; item.Length &lt; 8);
            query = query.OrderByDescending(item =&gt; item.ToLower());

            List&lt;String&gt; results = query.ToList();

            Assert.AreEqual(2, results.Count);
            String[] expected = { &quot;carrot&quot;, &quot;cabbage&quot; };
            for (int i = 0; i &lt; results.Count; i++)
            {
                Assert.AreEqual(expected[i], results.ElementAt(i));
            }
        }
</pre>
<p>LINQ provides a simple, generalised query framework for operating on data collections within the .NET stack. There are framework plugins to support LINQ backed by various datastore technologies, these include: <a href="http://msdn.microsoft.com/en-us/library/bb425822.aspx">LINQ to SQL</a>, <a href="http://msdn.microsoft.com/en-us/library/bb387098.aspx">LINQ to XML</a> and <a href="http://msdn.microsoft.com/en-us/library/bb386964.aspx">LINQ to Entities</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/04/30/c-features-linq-primer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# features &#8211; question mark syntax</title>
		<link>http://www.2paths.com/2009/04/28/c-features-question-mark-syntax/</link>
		<comments>http://www.2paths.com/2009/04/28/c-features-question-mark-syntax/#comments</comments>
		<pubDate>Tue, 28 Apr 2009 18:27:34 +0000</pubDate>
		<dc:creator>Geoff</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Under the hood]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[newbies]]></category>

		<guid isPermaLink="false">http://www.2paths.com/?p=919</guid>
		<description><![CDATA[Some recent project work in C# unearthed a few grains of syntactic sugar which I thought deserved a quick post. Not necessarily because they are ground breaking discoveries, but more because I found it difficult to find information via the usual channels (google) and wanted to share. I think the poor information discovery is a [...]]]></description>
			<content:encoded><![CDATA[<p>Some recent project work in C# unearthed a few grains of syntactic sugar which I thought deserved a quick post. Not necessarily because they are ground breaking discoveries, but more because I found it difficult to find information via the usual channels (google) and wanted to share. I think the poor information discovery is a result of said features being based on the question mark which is not an easy symbol to use for searches online.</p>
<h3>Single Question Mark &#8211; nullable types</h3>
<p>The single question mark syntax is somewhat obscure. Essentially it is short hand syntax for marking primitives as nullable. <code>System.Nullable</code> is a generic struct that is essentially a <a href="http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx">wrapper to signify nullability</a>. This can be used as shown below:</p>
<pre class="brush: java">
// a nullable type for int
int? thing = 12;

// is syntactically equivalent to
System.Nullable&lt;int&gt; otherThing = 12;

// can be any valid int value OR null
thing = -12;
thing = null;

// usage
//y is set to zero
int y = thing.GetValueOrDefault();
// but this will throw an exception as thing.HasValue == false
y = thing.Value;
</pre>
<h3>Double Question Mark &#8211; non null assignment precedence</h3>
<p>This one is a little obscure but can be quite handy, it is very similar to certain assignment constructs in Perl as it allows one to use precedence to assign a variable from other potential variables and is a nice way to deal with default values.</p>
<pre class="brush: java">
String thing = null;
String defaultThing = &quot;nothing&quot;;

// standard trinary syntax
String otherThing = (thing != null) ? thing : defaultThing;

// syntactic sugar for the above
String sugaredThing = thing ?? defaultThing;

// can also chain things
otherThing = null;

// the first non-null value is the result of the assignment
String anotherThing = thing ?? otherThing ?? defaultThing;

// if all potentials are null, then the assignement is null)
anotherThing = thing ?? otherThing;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.2paths.com/2009/04/28/c-features-question-mark-syntax/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
