<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>The Shine Technologies Blog</title>
	
	<link>http://blog.shinetech.com</link>
	<description>Thoughts from the Shine team</description>
	<lastBuildDate>Fri, 10 Feb 2012 09:43:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain="blog.shinetech.com" port="80" path="/?rsscloud=notify" registerProcedure="" protocol="http-post" />
<image>
		<url>http://0.gravatar.com/blavatar/6b531261b8d086fb4ffbdf82064fb878?s=96&amp;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>The Shine Technologies Blog</title>
		<link>http://blog.shinetech.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.shinetech.com/osd.xml" title="The Shine Technologies Blog" />
	
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/shinetech/blog" /><feedburner:info uri="shinetech/blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://blog.shinetech.com/?pushpress=hub" /><feedburner:browserFriendly></feedburner:browserFriendly><item>
		<title>Processing Huge JSON Files with Jackson</title>
		<link>http://blog.shinetech.com/2011/12/23/processing-huge-json-files-with-jackson/</link>
		<comments>http://blog.shinetech.com/2011/12/23/processing-huge-json-files-with-jackson/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 02:41:34 +0000</pubDate>
		<dc:creator>Grant Ruwoldt</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[jackson]]></category>
		<category><![CDATA[json]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1585</guid>
		<description><![CDATA[A couple of months ago I was asked to build a processor that would take a JSON file; perform a few elementary checks and transformations and upload the resulting records into a Couch DB. I hadn&#8217;t done any JSON, or &#8230; <a href="http://blog.shinetech.com/2011/12/23/processing-huge-json-files-with-jackson/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1585&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div id="attachment_1628" class="wp-caption alignnone" style="width: 310px"><a href="http://shinetechblog.files.wordpress.com/2011/12/weirdal.jpg"><img src="http://shinetechblog.files.wordpress.com/2011/12/weirdal.jpg?w=300&#038;h=209" alt="" title="weirdal" width="300" height="209" class="size-medium wp-image-1628" /></a><p class="wp-caption-text">Weird Al&#039;s not the only one who knows how to go large with Jackson</p></div>
<p>A couple of months ago I was asked to build a processor that would take a JSON file; perform a few elementary checks and transformations and upload the resulting records into a Couch DB. I hadn&#8217;t done any JSON, or Couch and, naturally, the whole thing had to be done yesterday &#8211; but at first glance it didn&#8217;t look like much of a challenge.</p>
<p>However, looking a little deeper, my processor was going to be part of a replication process across two databases housed in separate enterprises. The replication was going to be based on a daily snapshot &#8211; each JSON file would be a copy of the entire database &#8211; and a few back-of-the-envelope calculations suggested that the files may become rather large (40+GB) over time.<br />
<span id="more-1585"></span><br />
There was also a fairly tight processing window within which the upload had to be complete. Repressed memories of chasing down and remediating an old DOM based XML project plagued with OutOfMemoryExceptions and very slow processing times warned that some thought was required. </p>
<p>Obviously I wasn&#8217;t going to be able to be able to read the whole file into RAM to transform it and fortunately, I didn&#8217;t need to &#8211; the file was a collection of a couple of million simple objects with no cross references. So to minimize the amount of memory required by the processor, I simply needed to parse the large file into a stream of objects and transform them either individually or in small collections.</p>
<h2>Jackson</h2>
<p>Key &#8220;JSON Parsing&#8221; into your favourite search engine and you find about thirty different technologies competing for your attention. Also about a hundred different opinions as to which was &#8220;the best&#8221;. After a brief review, Jackson recommended itself though the <a title="tutorial" href="http://wiki.fasterxml.com/JacksonInFiveMinutes" target="_blank">tutorial</a> which indicated that it included a Streaming API, as well as a DOM like Tree Model and JAXB style object bindings.</p>
<p>Given the memory and time concerns above, my first concept was to use the Streaming API to identify object boundaries within the input file to break it down into small chunks and to then use a JAXB style object binding to do the simple transformations required (mostly field name changes). The object binding piece was beautifully trivial:</p>
<p><pre class="brush: java;">
public class Business {
    @JsonView({ BriefView.class, FullView.class })
    private String businessId;

    @JsonView({ BriefView.class, FullView.class })
    private String name;

    @JsonView({ FullView.class })
    private String address;

    ...
}
</pre></p>
<p>Using the JsonView concept, I was able to use the same value class to render different JSON requests for various external services supporting the checking and transformations required.</p>
<p>The Streaming API piece wasn&#8217;t going so smoothly. Although it was straight-forward to identify the object boundaries in the JSON token stream, there didn&#8217;t seem to be a natural (i.e. easy) way of accessing the underlying character stream in order to create the smaller work unit for the object bindings to use.  A re-think was necessary.</p>
<p>The object bindings were giving me an easy way of creating a collection of value objects in memory from a JSON stream &#8211; and conversely of creating a JSON stream from a collection of value objects. If I could get the Jackson object binding to create a stream of value objects, then I could dispense with the streaming API altogether. Some trawling through the Jackson API soon showed this wasn&#8217;t only possible, but easy:</p>
<p><pre class="brush: java;">
JsonFactory f = new MappingJsonFactory();
JsonParser jp = f.createJsonParser(reader);

do {
    Business business = jp.readValueAs(Business.class);

    if (business == null) {
        handler.complete(context);
        break;
    }

    numberOfBusinessesReceived++;
    handler.handleBusiness(business, context);

} while (true);
jp.close();
</pre></p>
<p>The object handler here applies some cheap validation rules and aggregates a bunch of objects into a file for later (in memory) processing and upload to Couch. The context object carries some extra information &#8211; like the name of the file being processsed.</p>
<p>The magic provided by Jackson is the readValueAs method, which reads enough of the stream to create an object. Pushing a 10GB of two million records file through the processor running on an ordinary desktop with 256M of heap space yielded a processing time of 6 minutes &#8211; well within the required processing time window.\</p>
<h2>Conclusion</h2>
<p>The creators of Jackson have learnt the lessons from XML parsing well. Jackson offers a range of parsing approaches that allows developers to choose the right approach to the task at hand. In short, Jackson eats massive JSON files &#8211; without raising a sweat.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1585/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1585/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1585/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1585/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1585/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1585/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1585/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1585/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1585&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/12/23/processing-huge-json-files-with-jackson/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1d553d32dad28c30ad164220150e4119?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">grantruwoldtshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/12/weirdal.jpg?w=300" medium="image">
			<media:title type="html">weirdal</media:title>
		</media:content>
	</item>
		<item>
		<title>Yow! Developer Conference Brisbane.</title>
		<link>http://blog.shinetech.com/2011/12/12/yow-developers-conference-brisbane/</link>
		<comments>http://blog.shinetech.com/2011/12/12/yow-developers-conference-brisbane/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 05:46:48 +0000</pubDate>
		<dc:creator>Alistair Sutton</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1564</guid>
		<description><![CDATA[Yow! Brisbane 2011 I recently had the pleasure of attending the Brisbane Yow! Conference.  This was a great conference with talks to interest developers across many languages platforms and experience. This blog is a summary of the more interesting talks &#8230; <a href="http://blog.shinetech.com/2011/12/12/yow-developers-conference-brisbane/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1564&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h1 style="text-align:center;"><a href="http://shinetechblog.files.wordpress.com/2011/12/photo-2.jpg"><img class="alignnone size-medium wp-image-1572" title="photo-2" src="http://shinetechblog.files.wordpress.com/2011/12/photo-2.jpg?w=300&#038;h=225" alt="" width="300" height="225" /></a></h1>
<h1 style="text-align:center;">Yow! Brisbane 2011</h1>
<p>I recently had the pleasure of attending the <a href="http://yowaustralia.com.au/YOW2011/index.html">Brisbane Yow! Conference</a>.  This was a great conference with talks to interest developers across many languages platforms and experience.</p>
<p>This blog is a summary of the more interesting talks that I attended and my thoughts on them.<br />
<span id="more-1564"></span><br />
<strong>Keynote – <a href="http://yowaustralia.com.au/YOW2011/general/details.html?speakerId=2312">Top 10 JVM Erroneous Zones</a> – Cameron Purdy</strong></p>
<p>The opening talk of day one was a very technical discussion from an Oracle VP, taking us through what he thought were areas that can/could/should be improved in the Java Virtual Machine.  It was a reasonably low level talk for a Keynote but this was a developer’s conference so not entirely unexpected.</p>
<p>Purdy spoke about low-level extensibility in terms of abstracting on primitive types and the limitations of building word length into compilers.  He also touched on precision, lack of continuations support and made comparisons with other languages such as C++ and Scala to support his points.</p>
<p>These points were then used to relate back to development work being done at Oracle on the JVM.  The case was made that since Oracle took over JVM development and maintenance, many improvements and efficiencies in the language have been made. As Java remains a flagship product for Oracle they will continue to do so going forward.</p>
<p>What I took from the talk was that someone driving development is being constructively critical of the language, which is undergoing a lot of criticism in  light of the popularity of dynamic languages such as Groovy.</p>
<p><strong>Lean and Agile  &#8211; <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3490">Continuous Design –</a> Mary Poppendieck</strong></p>
<p>This talk from the Lean Luminary was not quite what I expected. It focused more on a wider view of product design from conception to market place whereas I thought it would be covering incremental design, how best to manage that within an agile environment and how best to integrate that with a continuous delivery approach.</p>
<p>Although the talk was a little broader than I expected, Mary continually reaffirmed the 3M philosophy of make a little, sell a little and learn a little.  This was then discussed in terms of product cycles and how important design conception is and how it can then be refined through iterations of testing and using the design to the point that it can be taken to market.</p>
<p>A lot of comparisons were made between Google, Apple and Dropbox in terms of defining and refining products before they go to market and what comes after go live in terms of design.</p>
<p>An interesting point was her discussion on enabling toggling of features in production so that unfinished features do not disrupt the continuous delivery cycle. She discussed doing small releases via load balancing to test out new features on a smaller audience in case they fail and drive people away.</p>
<p>Overall this was a great talk to be listening to if you were taking a new product to market or worked within a start up type environment.   Of course it was quite a privilege to hear Mary Poppendieck present and she is an excellent presenter.</p>
<p><strong> DevOps – <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3613">We’re all Developers Now</a> – Julian Simpson</strong></p>
<p>This talk eventually got underway after a few technical hitches with the speaker’s laptop not co-operating with the projector.  You definitely don’t want technical difficulties in front of a room full of developers.</p>
<p>Once the talk began, it was basically a quick overview of DevOps and then mainly a comparison of Puppet and Chef.  Both Puppet and Chef are automation tools for Sys Admins.   The talk was very interesting showing how a sys admin would manage the installation of an application using the Nginx web server and Jetty.  Examples of how this is configured in Puppet and Chef where then shown illustrating how the configuration is then version controlled to provide change control management and one version of truth.</p>
<p>The power of this was demonstrated very well as Julian discussed how the configuration defined where specific components were to be installed across many virtual servers, allowing the administrator to roll out changes very quickly to a scalable number of machines.  Very powerful and quite dangerous – all the more reason for source control and proper change control!</p>
<p>DevOps is a fast growing and very interesting development in the industry and is leading to more responsibility for the developer as the gap between development and production is closing….</p>
<p>I thought this was a very good talk and I am looking closely at the various DevOps movements within our clients.</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/12/photo9.jpg"><img class="alignright size-medium wp-image-1571" title="Action shot -  Yow! Brisbane 2011" src="http://shinetechblog.files.wordpress.com/2011/12/photo9-e1323658432449.jpg?w=225&#038;h=300" alt="Action shot - Yow! Brisbane 2011" width="225" height="300" /></a></p>
<p><strong>Transitioning To The Cloud – <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3585">Challenges Transitioning To The Cloud</a> – Rod Johnson</strong></p>
<p>A very interesting talk from Rod Johnson, the founder of Spring.  This talk was Rod discussing what he sees as the issues and challenges facing the drive of software into the cloud.</p>
<p>He defined the differences between Infrastructure as a service (IaaS), Platforms as a service (PaaS) and Software as a service (SaaS) and then spoke of the trends he thinks will happen with these.  These were namely that there will be more growth in PaaS and likened it to the second coming of the main frame.  He talked about a standardized stack such as a Ruby or a Java stack, which might see developer’s choice narrow and will also see the tools as part of the platform.</p>
<p>It was very interesting hearing someone of Rod’s experience and foresight discussing the cloud and what he saw it meaning for developers in the future.</p>
<p><strong>The Interactive Web &#8211; <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3254">The Live Web</a> – Dan Ingalls.</strong></p>
<p>Dan Ingalls is one of the founders of Smalltalk so it was quite surreal to have him present a demonstration on a JavaScript web IDE for building HTML 5 applications.</p>
<p>The Living Kernel is a component architecture for HTML and runs in the browser.  It lets developers build and compose with existing components in a canvas like fashion and then tie them together with events, animations and scripting to quickly pull together visual applications.</p>
<p>While the examples shown in the talk were all relatively lightweight there was some scope of the power of this show when he quickly generated a graph based on Unix output to show CPU utilization of a server.  This would then be saved as a HTML report.  His entire presentation was also built using the tool, which showed its versatility.</p>
<p>What was missing in this talk was the business benefits of these tools.  He mentioned towards the end that they generate some reporting for come clients using this but it was only mentioned in passing.</p>
<p><strong>Better Testing for Less Work – <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3598">QuickCheck</a> – John Hughes<br />
</strong></p>
<p>This very entertaining talk was based around the speakers experience using QuickCheck.</p>
<p>QuickCheck is a testing tool, which based on a set of rules will then generate a specified number of tests with random data.  If an error is found, then the tool will focus on reproducing that error as many times as possible to determine the simplest cause of the error from the random data it generated.</p>
<p>John Hughes explained the tool at a high level and briefly showed how to specify a property rule but the basis of his talk was his experiences using QuickCheck in industry.  He discussed the use of the tool in car industry software and how he identified an issue in a production database.</p>
<p>John Hughes was such an entertaining presenter the entire audience was hanging on every word and we all erupted in applause at the end of the talk.  His passion for his work was evident and this translated into a surprisingly interesting talk on a low level-testing tool.</p>
<p><strong><a href="http://shinetechblog.files.wordpress.com/2011/12/yow2011squarebanner.png"><img class="alignleft size-full wp-image-1574" title="YOW2011SquareBanner" src="http://shinetechblog.files.wordpress.com/2011/12/yow2011squarebanner.png?w=640" alt=""   /></a>Keynote &#8211; <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3586">Escape from the Ivory Tower</a> – Simon Peyton-Jones</strong></p>
<p>You could be forgiven for calling Simon Peyton-Jones  “Monty” and John Hughes&#8217; “Python”.</p>
<p>Both went to university together at Cambridge and have the same passion, humour and comic delivery which makes for an excellent presentation. This was a wonderful follow on from the John Hughes talk.</p>
<p>This talk covered the history of Haskell, a functional programming language which has largely been academic until recently.</p>
<p>With the rise of parallel programming Haskell has attracted far more interest and suddenly Simon as a co-creator of Haskell is very much in demand as a speaker.</p>
<p>The speech centered around the history of Haskell and the differences between Haskell and other functional programming languages.  For non-functional programmers Simon recommended some exposure to Haskell to help them think about programming in a different way.</p>
<p>Again the speaker was very passionate about his topic and his presentation was so well put together that the audience was very much engaged.</p>
<p><strong>JavaScript Everywhere</strong></p>
<p>The next few talks that I attended painted a better picture for me on the rise and rise of JavaScript.</p>
<p><strong>Web As A Platform &#8211; <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3644">Dart, a new programming language for structured web programming</a>  – Kasper Lund</strong></p>
<p>This talk introduced Dart, a new programming language (almost) released by Google, still very much in its formative years.</p>
<p>Through coding up examples, the presenter highlighted a number of the language features mainly comparing them to JavaScript.   I took it that Dart was positioning itself to rival JavaScript. Dart can either run on it’s own VM or can be compiled down to JavaScript… which leads me into the next talk.</p>
<p><strong>Web As A Platform &#8211; <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3549">The Web Browser is a Transitional Technology</a> – Allen Wirfs-Brock</strong></p>
<p>This talk was based on the premise that we are moving into a new era of computing. We went from corporate computing to personal computing and now into what Mozilla’s Allen Wirfs-Brock labeled the Ambient Computing era.</p>
<p>Ambient is defined as “completely enveloping” so I take it he was trying to capture the fact the now people have multiple devices which they want and use all the time, therefore we are enveloped in the technology.  Bit of a stretch for me I’m afraid… I don’t think that phrase is going to stick.</p>
<p>In any case, he made good points that the new gadgets entering the market do not typically use a browser any more to interact with the web.  However a lot of them still use the same technology stack just without the browser chrome.  This web platform can sit directly on new hardware losing the PC and the browser.  To relate back to the title of the speech, the browser was a PC based, transitional technology to get us to this point.</p>
<p>The biggest point I believe Allen made was that JavaScript was directly built into this technology stack and was the only language present.  By this fact alone it foretells a bright future for JavaScript as it would be very difficult for an emerging technology (such as Dart) to proliferate to the point that all vendors across the Internet and gadget market will replace JavaScript in this platform.</p>
<p>I guess that’s why the Dart guys have ensured Dart can compile down to JavaScript….</p>
<p><strong>Web As A Platform &#8211; <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3563">NodeJS and the JavaScript-Everywhere Strategy</a> &#8211; Matthew Eernisse</strong></p>
<p>Yammer’s Matthew Eernisse talked about JavaScript on the server side and the rise of NodeJS.  In the talk Eernisse wrote a web server from scratch to show how quickly you can get off and running with NodeJS.  He discussed some of the tools available to help with NodeJS development and highlighted some of the trouble shooting lessons he had learned.  With so many callbacks and asynchronous code it can be difficult finding root causes of issues.  Eernisse showed how he changed his debug to help address those issues.</p>
<p>The majority of the Yammer upload apps are NodeJS applications and Shine Technologies has also done some major project work with a Melbourne client on various NodeJS apps.</p>
<p>This talk complemented the previous ones on highlighting the rise and rise of JavaScript to me.</p>
<p>The only other talk I should mention was the <a href="http://www.yowconference.com.au/YOW2011/general/workshopDetails.html?eventId=3496">Keynote</a> by Damien Conway on extending Perl to implement quantum physics. This was genius in PowerPoint but while I enjoyed it and followed it to a degree, I could not hope to summarise it due to its complexity.  Presentations like Conway’s go a long way to inspiring people in the field to take their profession far beyond what anyone thought was possible.  Sensational stuff!</p>
<p><strong>Summary</strong></p>
<p>There were some other interesting talks, which rounded out the conference plus a good chance to meet other developers and people in the industry as well as the speakers themselves who were very approachable.</p>
<p>This was a very well run conference and I will be lining up next year again for it.</p>
<p><em>Alistair Sutton is a Senior Consultant for Shine Technologies and has recently moved to Brisbane to open a Brisbane branch for Shine.</em></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1564/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1564/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1564/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1564/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1564/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1564/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1564/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1564/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1564&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/12/12/yow-developers-conference-brisbane/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/7167efd68f982e19a174e78d5b2c7c4a?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">alistairsuttonshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/12/photo-2.jpg?w=300" medium="image">
			<media:title type="html">photo-2</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/12/photo9-e1323658432449.jpg?w=225" medium="image">
			<media:title type="html">Action shot -  Yow! Brisbane 2011</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/12/yow2011squarebanner.png" medium="image">
			<media:title type="html">YOW2011SquareBanner</media:title>
		</media:content>
	</item>
		<item>
		<title>CouchDb on Android</title>
		<link>http://blog.shinetech.com/2011/11/14/couchdb-on-android/</link>
		<comments>http://blog.shinetech.com/2011/11/14/couchdb-on-android/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 06:13:41 +0000</pubDate>
		<dc:creator>Daniel Brain</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1479</guid>
		<description><![CDATA[Synchronising advanced data structures with a backend sucks. Especially when the sync is both ways; user updates to server, server updates to user. Couchbase for Mobile attempts to solve this issue by bringing CouchDb and it&#8217;s spiffy replication to Android. What? &#8230; <a href="http://blog.shinetech.com/2011/11/14/couchdb-on-android/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1479&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:center;"><img class="aligncenter size-medium wp-image-1501" title="Android on Couch" src="http://shinetechblog.files.wordpress.com/2011/11/android-on-couchdb.jpg?w=300&#038;h=170" alt="" width="300" height="170" /></p>
<p>Synchronising advanced data structures with a backend sucks. Especially when the sync is both ways; user updates to server, server updates to user. <a title="Couchbase for Mobile" href="http://www.couchbase.com/products-and-services/mobile-couchbase" target="_blank">Couchbase for Mobile</a> attempts to solve this issue by bringing <a title="CouchDb" href="http://couchdb.apache.org/" target="_blank">CouchDb</a> and it&#8217;s spiffy replication to Android.<span id="more-1479"></span></p>
<h2>What? Why?</h2>
<p><img class="alignright size-full wp-image-1506" title="Doctor What Is This" src="http://shinetechblog.files.wordpress.com/2011/11/doctor-whatisthis.jpeg?w=640" alt=""   />Why would you ever want CouchDb on your phone, you ask. Well, along with giving you some fancy pants replication, which I&#8217;ll rant about soon, some of the benefits over Android&#8217;s built in <a title="SQLite" href="http://sqlite.org/" target="_blank">SQLite</a> support are:</p>
<ul>
<li>Unstructured data storage in JSON documents</li>
<li>Map/reduce for querying</li>
<li>Versioning of documents</li>
<li>And more..</li>
</ul>
<p>In a bit more detail ..</p>
<h3>JSON documents with whatever you want in them</h3>
<p>The data in CouchDb is document oriented, in that it stores and returns your content in JSON documents. These documents can have whatever fields and whatever JSON acceptable values you wish without any table changes. This gives you the power to support dynamically added fields. If you wanted to create a form that accepts additional user defined fields, CouchDb or something like it is what you want.</p>
<p>A CouchDb document, requested with a GET to /database/boo, is read and written something like</p>
<p><pre class="brush: jscript;">
{
  &quot;_id&quot;: &quot;booboo&quot;,
  &quot;_rev&quot;: &quot;gibberish&quot;,
  &quot;favouriteFoods&quot;: [ &quot;Bangers&quot;, &quot;Mash&quot; ],
  &quot;bodyWeight&quot;: 300
}
</pre></p>
<p>While a horribly non standard representation of a SQL table structure, that allows dynamically added fields, would be something like</p>
<pre>Form#1()
FormValue#1(
  formId: 1,
  fieldName: "favouriteFoods",
  fieldValue: "Bangers",
  fieldType: "String"
)
FormValue#2(
  formId: 1,
  fieldName: "favouriteFoods",
  fieldValue: "Mash",
  fieldType: "String"
)
FormValue#3(
  formId: 1,
  fieldName: "bodyWeight",
  fieldValue: "300",
  fieldType: "Number"
)</pre>
<p>Retrieved with queries like</p>
<p><pre class="brush: sql;">
SELECT * FROM Form
SELECT * FROM FormValue WHERE formId = 1
</pre></p>
<p>As you can see the CouchDb approach is much nicer, and in SQLite&#8217;s case the structure of Form and FormValue need to be defined when the table is created. Meaning updates to the structure of these tables involve fancy scripts or complicated <a title="SQLiteOpenHelper.onUpgrade" href="http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)" target="_blank">SQLiteOpenHelper.onUpgrade</a> functions.</p>
<h3>Map/reduce functions</h3>
<p><img class="alignleft size-thumbnail wp-image-1507" title="MapReduce" src="http://shinetechblog.files.wordpress.com/2011/11/mapreduce.jpg?w=150&#038;h=115" alt="" width="150" height="115" />CouchDb has a different method of querying the data compared to normal SQL databases, depending on your usage this could be a deal maker or a deal breaker.</p>
<p>In CouchDB you create views of your data, written in Javascript, emitting a key and a value. You then look up the data you want using the key you specified. You can also reduce the values for summing or other fun things. For example:</p>
<p><pre class="brush: jscript;">
&quot;byName&quot;: {
  &quot;map&quot;: function (doc) {
    if (doc.name) {
      emit(doc.name, 1);
    }
  },
  &quot;reduce&quot;: function (key, values, rereduce) {
    return sum(values);
  }
}
</pre></p>
<p>When this has been indexed you will have an index like:</p>
<pre>"Jim", 1
"Jim", 1
"Jack", 1</pre>
<p>Calling it with reduce will give you:</p>
<pre>"Jim", 2
"Jack", 1</pre>
<h3>Versioning of documents</h3>
<p>CouchDb versions documents. Every time you update a document the previous revision will still exist and be accessible (until compaction which I&#8217;ll ignore), which may be useful for basic undo or rollback functionality.</p>
<h3>Everything CouchDb gives you</h3>
<p><img class="aligncenter size-medium wp-image-1509" title="Obese Cat" src="http://shinetechblog.files.wordpress.com/2011/11/obesecat.jpg?w=300&#038;h=155" alt="" width="300" height="155" /><br />
And all of the other things CouchDb provides, like hugs, kittens and obese indexes (don&#8217;t quote me).</p>
<h2>Replication</h2>
<p><img class="aligncenter size-full wp-image-1504" title="Replicators" src="http://shinetechblog.files.wordpress.com/2011/11/10-points-for-reference.jpg?w=640" alt="10 points if you get the reference"   /><br />
The main benefit you&#8217;ll see with using CouchDb for your application (presumably) is data synchronisation via replication.</p>
<p>CouchDb supports really easy start and stop replication, with it&#8217;s own conflict resolution. You could have multiple databases that haven&#8217;t seen each other in months, tell them about each other and each of them will eventually catch up with the other as far as documents go. This is awesome for &#8220;when I want&#8221; syncing, and offline editing of data that syncs when a connection is established again. Some use cases:</p>
<h3>Taking notes</h3>
<p>This would be great for a note taking application that supports mobile as well as web edits. The user could add notes on both sides and sync to make both sides consistent when they want / when a wireless connection is available.</p>
<h3>Real time when available</h3>
<p>You could have replication going any time the application is in the foreground. This would allow for applications that work in real time but don&#8217;t explode when the network is lost.</p>
<p>And I&#8217;m sure other more exciting things my boring brain chose to shield me from.</p>
<h2>I&#8217;m sold. How do I make the magic happen?</h2>
<p><img class="alignleft size-medium wp-image-1505" title="Magic Happening" src="http://shinetechblog.files.wordpress.com/2011/11/magic-happening.jpg?w=256&#038;h=300" alt="" width="256" height="300" />First up, make an Android 2.x project in your favourite Java IDE (Eclipse), which you have obviously already set up for Android development.</p>
<p>Next you need to get the latest version of CouchDb for Android (still in Developer preview), <a title="here" href="http://www.couchbase.org/get/couchbase-mobile-for-android/current" target="_blank">here</a>. This website also covers the instructions for getting your project CouchDb friendly, basically it&#8217;s &#8220;run an Ant script and hope it&#8217;s not doing anything too horrible&#8221;. Without going too into it, it&#8217;s configuring your project for CouchDb, Erlang (which CouchDb uses behind the scenes) and some funky native libraries.</p>
<p>You can also add <a title="Ektorp" href="http://ektorp.org" target="_blank">Ektorp</a>, a Java API for CouchDb with Android support. This wraps the CouchDb calls so you don&#8217;t have to generate your own HTTP requests. That&#8217;s really up to you, but the code examples below use this, and Couchbase recommends it as far as Android CouchDb libraries go.</p>
<h2>I&#8217;m listening..</h2>
<p>If you&#8217;re anything like me, you&#8217;ve probably skipped to this section or closed the page when you didn&#8217;t instantly see code, but here goes.</p>
<p><img class="aligncenter size-full wp-image-1503" title="Super Duper Programmer" src="http://shinetechblog.files.wordpress.com/2011/11/super-duper-programmer.jpg?w=640" alt=""   /></p>
<h3>Starting CouchDb</h3>
<p>First we&#8217;ll set up a CouchbaseDelegate in our main Activity. You use this to capture startup errors and kick off initialisation steps / replication when the database has started.</p>
<p><pre class="brush: java;">
ICouchbaseDelegate couchDelegate = new ICouchbaseDelegate() {
  @Override
  public void exit(String error) {
    // Show the error to the user
  }

  @Override
  public void couchbaseStarted(String host, int port) {
    // CouchDb has started, set up your connector
    // in our case initialise Ektorp
    startEktorp(host, port);
  }
};
</pre></p>
<p>Now we&#8217;ll actually request for CouchDb to be started, referencing the delegate we created above. In my case I&#8217;m calling this when the activity starts.</p>
<p><pre class="brush: java;">
private void startCouch() {
  CouchbaseMobile couch = new CouchbaseMobile(
    getBaseContext(), couchDelegate
  );
  couchConnection = couch.startCouchbase();
}
</pre></p>
<p>CouchbaseMobile will do its magic and eventually call your delegate.</p>
<h3>Connecting to the database</h3>
<p>Now that CouchDb has started, we&#8217;ll connect using the host and port the delegate gave us.</p>
<p><pre class="brush: java;">
clientBuilder = new AndroidHttpClient.Builder();
httpClient = (AndroidHttpClient)clientBuilder
  .host(host)
  .port(port)
  .build();
dbInstance = new StdCouchDbInstance(httpClient);
// The last parameter true will create the database
// if it doesn't exist.
dbConnector = dbInstance.createConnector(DATABASE_NAME, true);
</pre></p>
<p>The dbConnector is now ready for normal database use. Let the CRUD begin.</p>
<h3>Creating the initial design documents</h3>
<p>CouchDb is pretty useless without a view over your data (unless you know ids or want to just work with all documents). So after CouchDb has started you should create (or update) the design documents specifying your views.</p>
<p><pre class="brush: java;">
designDocId = &quot;_design/slyncy&quot;;
byNameView = &quot;byName&quot;;
byNameMap = &quot;function(doc) {if (doc.name) emit(doc.name, doc);}&quot;;
DesignDocument dDoc = new DesignDocument(designDocId);
dDoc.addView(byNameView, new DesignDocument.View(
  byNameMap
));
dbConnector.create(dDoc);
</pre></p>
<h3>Putting a list adapter on top of the view</h3>
<p>Assuming you&#8217;re displaying the data in a list, you&#8217;d want to wrap a view in a custom CouchbaseViewListAdapter. There&#8217;s a horrible implementation in the example code showing basic view mapping.</p>
<p><pre class="brush: java;">
ViewQuery query = new ViewQuery()
  .designDocId(designDocId)
  .viewName(byNameViewName)
  .descending(true);

// The third parameter specifies that you should listen to
// the _changes feed from CouchDb enabling this means the
// list will automatically update for you when data changes
adapter = new CouchbaseViewListAdapterImpl(
  dbConnector, query, true
);
</pre></p>
<p>The final parameter (_changes: true) is pretty powerful. It works like Android content provider data change notifications, allowing the list to update when the data changes. Delete a document and it will be removed from the list.</p>
<p>Something Ektorp is missing with their base CouchbaseViewListAdapter class is support for include_docs when querying the view. This means your document will have to be emitted as an indexed value, which could lead to obese indexes if your data set is big enough.</p>
<h3>Starting replication</h3>
<p>Starting replication is pretty simple. You build a ReplicationCommand, specifying the source, target and continuous (once until complete (false), or continually run until shut down (true)).</p>
<p><pre class="brush: java;">
pushReplicationCommand = new ReplicationCommand.Builder()
  .source(DATABASE_NAME)
  .target(syncUrl)
  .continuous(true)
  .build();

EktorpAsyncTask pushReplication = new EktorpAsyncTask() {
  @Override
  protected void doInBackground() {
    dbInstance.replicate(pushReplicationCommand);
  }
};
pushReplication.execute();
</pre></p>
<p>Switch the source and target around for pull replication. Depending on how your system is you would probably want both (user updates -&gt; server, server updates -&gt; user).</p>
<h3>CRUD</h3>
<p>After the connection is set up, CRUD is simple. You just call create/update on a document (where document is a Map in my case), or delete with a given id and revision.</p>
<p><pre class="brush: java;">
dbConnector.create(document);
dbConnector.get(Map.class, id);
dbConnector.update(document);
dbConnector.delete(id, revision);
</pre></p>
<h3>Summing up</h3>
<p><img class="alignleft size-full wp-image-1516" title="Easy Peasy" src="http://shinetechblog.files.wordpress.com/2011/11/easypeasy.jpg?w=640" alt=""   />So, as you can see, connecting to CouchDb on Android is fairly simple, if a little verbose, but that&#8217;s the Java way.</p>
<p>You can find a working (you know, sometimes) example application <a title="here" href="https://github.com/dbrain/slyncy" target="_blank">here</a>, based on <a title="AndroidGrocerySync" href="https://github.com/couchbaselabs/AndroidGrocerySync" target="_blank">AndroidGrocerySync</a>.</p>
<h2>Concerns</h2>
<h3><img class="alignleft size-full wp-image-1510" title="Scared Orangutan" src="http://shinetechblog.files.wordpress.com/2011/11/scared-orangutan.jpg?w=640" alt=""   />Data Security</h3>
<p>Sure, replication sounds dandy, but how do I stop the user replicating changes of documents they don&#8217;t own?</p>
<p>CouchDb has a method for this called <a title="Validation Functions" href="http://guide.couchdb.org/draft/validation.html" target="_blank">Validation Functions</a>. Basically you can define a Javascript function that will look at an update and allow you to reject the change. The last parameter of these functions is a user context. So using this you can work out who&#8217;s writing and if their write is valid. For example:</p>
<p><pre class="brush: jscript;">
function (newDoc, savedDoc, userCtx) {
  if (savedDoc) {
    // This is an update, make sure the user
    // isn't watching the world burn.
    if (newDoc.userName !== userCtx.name) {
      throw({ unauthorised: 'You shall not pass ' + userCtx.name });
    }
  }
}
</pre></p>
<h3>Internal phone security</h3>
<p>A completely uninformed concern (I&#8217;m sure Couchbase has thought of it) is security from other applications running on the phone. What if you have private data you don&#8217;t want Mr Naughty&#8217;s application to push to his cloud of deceit?</p>
<p>Completely based on a Stack Overflow thread <a title="here" href="http://stackoverflow.com/questions/5670131/couchdb-security-for-android-devices-and-ios" target="_blank">here</a>, it seems that connecting to Couch and access the database itself is secure enough, but the data is written to external storage, which isn&#8217;t secure at all.</p>
<h2>Conclusion</h2>
<p>I&#8217;ll sum it up in pros and cons form.</p>
<h3><img class="size-thumbnail wp-image-1517 alignleft" title="Good News Everyone" src="http://shinetechblog.files.wordpress.com/2011/11/good-news-everyone.png?w=150&#038;h=120" alt="" width="150" height="120" />Pros:</h3>
<ul>
<li>CouchDb on Android makes replication easy. It&#8217;s basically allout of the box, just point and say go</li>
<li>The JSON strucure of CouchDb documents gives your application a lot of flexibility and a nice way to store data.</li>
<li>The actual code behind it isn&#8217;t too painful or that far away from &#8216;typical Android&#8217; code.</li>
</ul>
<h3><img class="alignleft size-thumbnail wp-image-1518" title="Bender" src="http://shinetechblog.files.wordpress.com/2011/11/cons.jpg?w=150&#038;h=150" alt="" width="150" height="150" />Cons:</h3>
<ul>
<li>Starting up CouchDb is slow, from what I&#8217;ve heard mostly due to loading an Erlang interpeter. You&#8217;ll see the lag between starting the application and initialising CouchDb if you run the example application</li>
<li>Map/Reduce while providing some friendliness also removes the possibility of on the fly SQL style queries</li>
<li>Packaging CouchDb with your application adds about 10mb of bloat to your installation.</li>
</ul>
<p>All up I&#8217;ll give it 3.33 out of 5 overly intelligent mice, ready to take over the world.<br />
<img class="aligncenter size-full wp-image-1512" title="3.33 Out Of 5" src="http://shinetechblog.files.wordpress.com/2011/11/3-33outof5.gif?w=640" alt=""   /></p>
<h3>Links / More interesting reads:</h3>
<ul>
<li>Example Github project: <a title="https://github.com/dbrain/slyncy" href="https://github.com/dbrain/slyncy" target="_blank">https://github.com/dbrain/slyncy</a></li>
<li>A nice setup guide <a title="here" href="http://www.couchbase.org/wiki/display/membase/Getting+Started+with+Android+and+CouchDB" target="_blank">here</a></li>
</ul>
<p><strong>Note</strong>: Images randomly pilfered from Google Image Search.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1479/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1479/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1479/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1479/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1479/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1479/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1479/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1479/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1479&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/11/14/couchdb-on-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/aa2b7b475f8b31201696bfbe160dca86?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">danielbrainshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/android-on-couchdb.jpg?w=300" medium="image">
			<media:title type="html">Android on Couch</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/doctor-whatisthis.jpeg" medium="image">
			<media:title type="html">Doctor What Is This</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/mapreduce.jpg?w=150" medium="image">
			<media:title type="html">MapReduce</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/obesecat.jpg?w=300" medium="image">
			<media:title type="html">Obese Cat</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/10-points-for-reference.jpg" medium="image">
			<media:title type="html">Replicators</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/magic-happening.jpg?w=256" medium="image">
			<media:title type="html">Magic Happening</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/super-duper-programmer.jpg" medium="image">
			<media:title type="html">Super Duper Programmer</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/easypeasy.jpg" medium="image">
			<media:title type="html">Easy Peasy</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/scared-orangutan.jpg" medium="image">
			<media:title type="html">Scared Orangutan</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/good-news-everyone.png?w=150" medium="image">
			<media:title type="html">Good News Everyone</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/cons.jpg?w=150" medium="image">
			<media:title type="html">Bender</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/11/3-33outof5.gif" medium="image">
			<media:title type="html">3.33 Out Of 5</media:title>
		</media:content>
	</item>
		<item>
		<title>A Good Look at Android Location Data</title>
		<link>http://blog.shinetech.com/2011/10/14/a-good-look-at-android-location-data/</link>
		<comments>http://blog.shinetech.com/2011/10/14/a-good-look-at-android-location-data/#comments</comments>
		<pubDate>Fri, 14 Oct 2011 00:28:38 +0000</pubDate>
		<dc:creator>Marc Fasel</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[Location Data]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1439</guid>
		<description><![CDATA[Getting started with the development of location-based services on Android is relatively easy thanks to the well documented location API. However, getting more serious shows there is still much uncharted territory. One such area concerns the accuracy of real-life location data, which &#8230; <a href="http://blog.shinetech.com/2011/10/14/a-good-look-at-android-location-data/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1439&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img class="alignleft size-full wp-image-1457" title="android_logo" src="http://shinetechblog.files.wordpress.com/2011/10/android_logo.png?w=640" alt=""   /></div>
<p dir="ltr">Getting started with the development of location-based services on Android is relatively easy thanks to the <a href="http://developer.android.com/guide/topics/location/obtaining-user-location.html" target="_blank">well</a> <a href="http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html" target="_blank">documented</a> <a href="http://www.vogella.de/articles/AndroidLocationAPI/article.html" target="_blank">location API</a>. However, getting more serious shows there is still much uncharted territory. One such area concerns the accuracy of real-life location data, which I have recently taken a close look at. In short, location data can be far more accurate than Google&#8217;s conservative estimates &#8211; at least with the phone that I used.</p>
<p dir="ltr"><span id="more-1439"></span>The Android developer documentation gives estimates on expected accuracy of the location data. This estimate varies according to the location provider used. Android distinguishes two location provider types with the following accuracy:</p>
<ul>
<li>Fine-grained location provider like the GPS provider with an accuracy of less than 100 m.</li>
<li>Coarse-grained location provider like the network location provider with an accuracy of 100 &#8211; 500 m</li>
</ul>
<p dir="ltr">One look at the Google Maps application makes it clear that the estimates for the accuracy are very conservative: in many cases the user location is shown on Google Maps with an accuracy of a few meters, much better than the estimates stated above.</p>
<p dir="ltr">My interest is in the individual accuracy of real-world data rather than an average accuracy estimate. Each time a location provider sends a location update, the accuracy of this individual location is given as well. In this article I look at this accuracy as reported by the location provider, and  compare the location accuracy of the two main location providers to actual locations.</p>
<h2 id="internal-source-marker_0.012480390258133411">Location Providers</h2>
<p dir="ltr">Location providers are the sources of location data in Android. Even though the Android API specifies location providers in a very generic way, in practice there are two main location providers: The GPS location provider and the network location provider. Because they use different ways to obtain location data they differ in accuracy, minimum notification interval, time to first fix (TTFF), and battery consumption.</p>
<p dir="ltr">The way you receive location information in Android is to register a Location Listener with the Location Manager. At registration the location provider, notification interval and notification distance have to be specified:</p>
<p><code>locationManager.requestLocationUpdates(provider, notificationInterval, notificationDistance, locationListener);</code></p>
<p dir="ltr">The Location Manager  will call the <code>onLocationChanged()</code> method of the listener if the distance since the last location update for the registered location provider is greater then the <code>notificationDistance</code>, or the time since last location update is greater than the <code>notificationInterval</code>.</p>
<div>
<h2 id="internal-source-marker_0.012480390258133411">GPS Location Provider</h2>
<p dir="ltr">The most obvious location provider is the GPS. GPS provides data with high accuracy: Less than 100 m is the official number, but real accuracy is often around 2 m &#8211; 20 m. Once it is connected to satellites it can provide location updates in intervals as short as a few seconds.</p>
<p dir="ltr">Sounds like an ideal location provider, but the GPS also has its draw-backs. For one, the initial connection to the satellites &#8211; Time to First Fix (TTFF) &#8211; can be quite slow. GPS traditionally needs to connect to at least three satellites for a 2D location, and initial transmission of so-called Ephemeris data takes a minimum of 30 seconds for a satellite. Once the Ephemeris data has been transmitted and connection to the satellite is made, location updates are very fast.</p>
<p dir="ltr">To speed up the TTFF, manufacturers have come up with a new way to deliver the initial Ephemeris data to the GPS: They use an Internet connection to deliver the data much faster than the transmission from the satellite. Android uses this so-called Assisted GPS (A-GPS) to speed up TTFF to 5-15 seconds, but only if you have an Internet connection.</p>
<p dir="ltr">Another draw-back of the GPS provider is that the battery consumption is quite high, and continued use of the the GPS will drain the battery. Even though GPS location updates can be received every few seconds, the Android developers guide recommends update intervals for the GPS of greater than 10 minutes. This limits the type of applications that can benefit from using the GPS.</p>
<p dir="ltr">Last but not least: Since GPS uses a radio signal, solid objects &#8211; especially those made from metal &#8211; will obstruct the signal. In practice, this means the GPS will not work in most buildings (GPS is not affected by clouds, rain, or snow, though).</p>
<p dir="ltr"><span class="Apple-style-span" style="color:#000000;font-size:17px;line-height:25px;">Accuracy</span></p>
<div>
<div>
<p dir="ltr">Each location update from a location provider comes with the accuracy of the data in meters. This accuracy is given for each location update. To visualise the location data and the accuracy for each location I wrote an Android application that records the location data in a database. Drawing the recorded data on a Google Map helps visualise the data. The following map shows the data recorded for the GPS provider during a walk through Melbourne.</p>
<div id="attachment_1444" class="wp-caption aligncenter" style="width: 650px"><a href="http://shinetechblog.files.wordpress.com/2011/10/walkaboutgps.png"><img class="size-full wp-image-1444" title="GPS Location Data" src="http://shinetechblog.files.wordpress.com/2011/10/walkaboutgps.png?w=640&#038;h=541" alt="" width="640" height="541" /></a><p class="wp-caption-text">GPS provider data compared to actual location</p></div>
<div>
<p id="internal-source-marker_0.5163292873185128" dir="ltr">The black line is the actual path I took during the walk. The white dots are the locations recorded by the GPS provider, while the red circles around the dots indicate the accuracy per location as reported by the GPS provider.</p>
<p dir="ltr">As expected the accuracy of the GPS provider is quite good: Most of the time the accuracy is within 30 m, some times as good as 2 m. That is much better than the conservative estimate of less than 100 m stated in the documentation.</p>
<p dir="ltr">An interesting observation is that sometimes the actual location is not within the circle of accuracy given by the GPS provider. The location marked with 1 on the map is about 25 m off the actual location, with an accuracy radius of about 5 m. Even with the radius of accuracy the result is still 20 m off the actual location.</p>
<p dir="ltr">Another observation that shows the draw-back of the GPS: if we are indoors or have otherwise bad reception there may not be a GPS signal, which means the location is completely lost. Marker 2 shows a section of the walk without any GPS signal. First I walked through a building from the Flight Centre to the cafe “The Journal”. Even after I passed though this building and walked down down the narrow Flinders Lane the GPS reception didn’t improve, so there are no readings at all during this time.</p>
<div>
<h2 id="internal-source-marker_0.5163292873185128">Network Location Provider</h2>
<p dir="ltr">The network location provider uses both WiFi hotspots and cell towers known to the Android device to approximate a location of a user. When the location provider is polled, the IDs of the WiFi hotspots and cell towers in the area are sent via Internet to the Google Location Server, a database with location information on WiFi hotspots and cell towers. Google Location Server returns an approximate location of the user.</p>
<p dir="ltr">The data comes from a combination of cell and WiFi hotspot information, and can only be obtained when the device can access the Internet to query the Google Location Server. Accuracy of the data is specified somewhere between 100 m &#8211; 1000 m depending on the information available. WiFi hotspots allow an accuracy of 100 m &#8211; 500 m, while cell towers only allow for an accuracy greater 500 m. This means the network provider will be very inaccurate in areas without WiFi hotspots. Conversely, the more hotspots and cell towers are in the area the greater the accuracy.</p>
<p dir="ltr">The network provider can give first location results within seconds. This is much faster than the GPS location provider, which even using A-GPS may take up to a minute to give back first results.</p>
<div>
<h3>Accuracy</h3>
<p dir="ltr">The following map visualises data recorded for the network provider when walking through Melbourne.</p>
<div id="attachment_1447" class="wp-caption aligncenter" style="width: 650px"><a href="http://shinetechblog.files.wordpress.com/2011/10/walkaboutnetwork.png"><img class="size-full wp-image-1447" title="Network Provider Data" src="http://shinetechblog.files.wordpress.com/2011/10/walkaboutnetwork.png?w=640&#038;h=521" alt="" width="640" height="521" /></a><p class="wp-caption-text">Network provider data compared to actual location</p></div>
<div>
<p dir="ltr">The black line again is the actual path taken, while the white dots are the locations recorded by the network provider. The turquoise circles indicate the accuracy reported by the network provider. The walk took about 30 minutes, during that time 16 points where within a reasonable accuracy (I discarded those points with an accuracy of greater than 100 m as too inaccurate, just to make the map clearer).</p>
<p dir="ltr">The map shows that at least in an urban area the network provider gives enough data with an accuracy of less than 100 m. Most of them were actually in the area of 50 m. This is not as good as the GPS, but still quite impressive. The network provider also has number of advantages over the GPS: It works both indoors and outdoors, starts up quickly, and doesn’t drain the battery.</p>
<h3>WiFi Hotspot Location Data</h3>
<p dir="ltr">During recording of the data I stumbled across an interesting anomaly: The network location provider put me in a totally different location than where I actually was. Curiously this happened every time I connected to my WiFi hotspot at home.</p>
<div id="attachment_1448" class="wp-caption aligncenter" style="width: 397px"><a href="http://shinetechblog.files.wordpress.com/2011/10/wrongnetworklocation.png"><img class="size-full wp-image-1448" title="Wrong WiFi Hotspot Location" src="http://shinetechblog.files.wordpress.com/2011/10/wrongnetworklocation.png?w=640" alt=""   /></a><p class="wp-caption-text">Wrong WiFi Hotspot Location</p></div>
<div>
<p id="internal-source-marker_0.5163292873185128" dir="ltr">The location marked with 1 is near my home, while the location marked with 2 is the place where I used to live. Once I arrived home the network provider placed me in location 2 instead of near location 1. Apparently Google thought I was in my old home once I logged into my home network, because it had previously registered the location of my WiFi hotspot in location 2.</p>
<p dir="ltr">This made me think about how Google actually obtains the location of a WiFi hotspot. It used to be possible to register the location of your WiFi hotspot with Google by hand. This option apparently does not exist anymore. As this <a href="http://android.stackexchange.com/questions/4715/how-may-i-submit-a-wifi-hotspot-to-androids-database-for-a-better-triangulation" target="_blank">discussion</a> shows, the data for the <strong>network provider</strong> actually comes from data Android <strong>GPS providers</strong> sent to the Google Location Server at some other time:</p>
<blockquote>
<p dir="ltr">“[...] before the GPS acquires a &#8220;fix&#8221;, Android will send the Wifi&#8217;s MAC/SSID and Cell Tower base stations CID/LAC around you to Google&#8217;s server and Google&#8217;s server will send back your location information; after the GPS acquires a &#8220;fix&#8221;, your device will send the Wifi MAC/SSID, Cell Tower CID/LAC, and your GPS location to Google&#8217;s server and Google&#8217;s server will collect this information to refine their own Wifi database.”</p>
</blockquote>
<p dir="ltr">The discussion also shows an Email reply from a Google employee stating that updating location information on WiFi hotspots is done automatically when a GPS provider sends new location data, but “<em>may require a significant amount of data from you and other users before changes are made to Google&#8217;s location database</em>”.  That explains why my WiFi hotspot is still registered at my old home in the Google Location Server.</p>
<div>
<h2 id="internal-source-marker_0.5163292873185128">Conclusion</h2>
<p dir="ltr">Comparing the location data received from the location providers with the actual location data shows that both location providers are much better in accuracy than the conservative estimates of the documentation.</p>
<p dir="ltr">For the hightest accuracy the GPS provider needs to be used, but is not suitable for all situations. The limitation of GPS to outdoor use is quite constraining, as is the battery consumption and TTFF, especially when used without A-GPS.</p>
<p id="internal-source-marker_0.5163292873185128" dir="ltr">The results of network provider for me came as a surprise: It is quite accurate while doing without the draw-backs of GPS like power-consumption,  TTFF, and restriction to outdoor use. It does lead to large inaccuracies in areas without WiFi hotspots.</p>
<p dir="ltr">Clearly a combination of both provides will yield the best results. How they are mixed depends on the application. A foreground application with emphasis on accuracy would use the GPS provider as the primary provider, with the network provider as a backup, while a background application with emphasis on low power consumption would use the network provider as its primary location provider with the GPS as a backup. Varying the update intervals allows fine-tuning the providers to a specific application.</p>
<p dir="ltr"><span class="Apple-style-span" style="color:#000000;font-size:22px;line-height:32px;">Code</span></p>
<p>If you want to have a look at the location data on your Android device I have uploaded the code to <a href="https://github.com/marcfasel/LocationMapper" target="_blank">GitHub</a>. It consists of an Android application that records the data as well as an HTML page that displays the data on Google Maps.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1439/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1439/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1439/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1439/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1439/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1439/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1439/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1439/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1439&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/10/14/a-good-look-at-android-location-data/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/b6fce92508146cc8d095ed11ebacfbd7?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">marcfaselshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/10/android_logo.png" medium="image">
			<media:title type="html">android_logo</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/10/walkaboutgps.png" medium="image">
			<media:title type="html">GPS Location Data</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/10/walkaboutnetwork.png" medium="image">
			<media:title type="html">Network Provider Data</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/10/wrongnetworklocation.png" medium="image">
			<media:title type="html">Wrong WiFi Hotspot Location</media:title>
		</media:content>
	</item>
		<item>
		<title>Swipe Conference Highlights: Gamification</title>
		<link>http://blog.shinetech.com/2011/09/09/swipe-conference-highlights-gamification/</link>
		<comments>http://blog.shinetech.com/2011/09/09/swipe-conference-highlights-gamification/#comments</comments>
		<pubDate>Fri, 09 Sep 2011 07:07:10 +0000</pubDate>
		<dc:creator>Michael Gillies</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1384</guid>
		<description><![CDATA[Of the many excellent sessions at this week&#8217;s Swipe Conference, the one titled &#8220;Build Better Cocoa Apps Using Game Mechanics&#8221; by Paris Buttfield-Addison was unique in its topic. In it, Paris outlined how gamification is currently viewed as something that can be &#8230; <a href="http://blog.shinetech.com/2011/09/09/swipe-conference-highlights-gamification/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1384&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><img src="http://shinetechblog.files.wordpress.com/2011/09/swipe.png?w=640&amp;h=213" alt="Swipe Conference" /></p>
<p>Of the many excellent sessions at this week&#8217;s <a href="http://swipeconference.com.au/">Swipe Conference</a>, the one titled &#8220;Build Better Cocoa Apps Using Game Mechanics&#8221; by Paris Buttfield-Addison was unique in its topic. In it, Paris outlined how gamification is currently viewed as something that can be quickly slapped onto an existing product in order to increase its appeal, whereas in reality, successful gamification requires carefully thought-out integration, for when done correctly it should form a core part of your app&#8217;s user experience.<br />
<span id="more-1384"></span><br />
In case you&#8217;re new to the concept, <a href="http://en.wikipedia.org/wiki/Gamification">gamification</a> is the application of game-like mechanics to non-game products in an effort to increase engagement with the user, motivating them to spend more time or money on your product.</p>
<p>The current trend in gamification is rather worrying, with seemingly everyone adding it to the list of things their product needs &#8211; as though it were a requirement for being successful. The reality of the situation is that these &#8216;gamification grafts&#8217; do nothing to enhance the user experience at all, providing mainly virtual badges for completing rather menial tasks &#8211; for example, pushing a button. This lack of challenge contributes to a failure to keep a user engaged, for they quickly become bored and move on.</p>
<p>A better approach to gamification would be to find a way to enhance the core functionality through the use of game-like mechanics. An example of successful gamification is <a href="http://stackoverflow.com/">Stack Overflow</a>. The core functionality is to provide people with a place to both ask and answer questions. However, game play elements come into it by rewarding users with a reputation system; the more you participate on the site, the more your reputation increases. Your reputation is then an indication of how helpful you are in the community. With higher reputation comes privileges that extend to helping with moderation of the site. This reputation system sets itself up in a unique way so that it encourages people to actively take part in the community and rewards them in the process.</p>
<p>Perhaps the most important point that was made during Paris&#8217; session was that not all products are suited to gamification. An app that displays the weather has no use for leader boards or an elaborate point system &#8211; they bring nothing meaningful to the user experience. However something like Foursquare, whose core functionality is to provide you with a means of sharing your location with others, benefits greatly from the addition of game play elements, effectively turning an otherwise dull concept into an engaging experience that rewards and encourages exploration of your surroundings.</p>
<p>In conclusion, the concept of gamification is definitely here to stay, but as developers and designers, we need to be vigilant and not give in to the urge to simply slap on a half-baked implementation. Instead we need to take the extra time to evaluate if it will actually enhance the existing user experience.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1384/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1384/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1384/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1384/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1384/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1384/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1384/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1384/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1384&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/09/09/swipe-conference-highlights-gamification/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/088a5cf14ded31a969394544d7df1789?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">michaelgilliesshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/swipe.png?w=640&amp;h=213" medium="image">
			<media:title type="html">Swipe Conference</media:title>
		</media:content>
	</item>
		<item>
		<title>iOS Developers and Designers: Stickin’ together is what good waffles do!</title>
		<link>http://blog.shinetech.com/2011/09/09/expanding-team-member%e2%80%99s-responsibilities-for-high-quality-iphone-experiences/</link>
		<comments>http://blog.shinetech.com/2011/09/09/expanding-team-member%e2%80%99s-responsibilities-for-high-quality-iphone-experiences/#comments</comments>
		<pubDate>Fri, 09 Sep 2011 06:45:14 +0000</pubDate>
		<dc:creator>Chaise Hocking</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1396</guid>
		<description><![CDATA[We’ve all heard developers say it: “I’m a terrible drawer” or “I’ve got no design skills”. Perhaps we’re even guilty of saying it ourselves &#8211; I know I am. But after attending this year’s Swipe Conference I now subscribe to &#8230; <a href="http://blog.shinetech.com/2011/09/09/expanding-team-member%e2%80%99s-responsibilities-for-high-quality-iphone-experiences/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1396&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://shinetechblog.files.wordpress.com/2011/09/simp01.jpg"><img class="alignnone size-full wp-image-1432" title="simp01" src="http://shinetechblog.files.wordpress.com/2011/09/simp01.jpg?w=640" alt=""   /></a></p>
<p>We’ve all heard developers say it: “I’m a terrible drawer” or “I’ve got no design skills”. Perhaps we’re even guilty of saying it ourselves &#8211; I know I am. But after attending this year’s <a href="http://swipeconference.com.au/">Swipe Conference</a> I now subscribe to the opinion that this is no longer acceptable. We are all responsible for the design of the app we are building; developer, designer, tester, or producer: every member of the team is accountable for helping shape the app’s design and interactions.<span id="more-1396"></span></p>
<div id="attachment_1411" class="wp-caption alignnone" style="width: 609px"><a href="http://shinetechblog.files.wordpress.com/2011/09/oldcollab.png"><img class="size-full wp-image-1411" title="The usual way of collaborating" src="http://shinetechblog.files.wordpress.com/2011/09/oldcollab.png?w=640" alt=""   /></a><p class="wp-caption-text">For far too long this has represented how teams have collaborated.</p></div>
<p><strong>Why must we all be accountable?</strong></p>
<p>We &#8211; as developers &#8211; are iPhone experts. We know what can and can’t be done technically. We have toyed with and tried building (with both successes and failures) many ideas before. But before that, we are users; in fact, not just users but experienced <em>super</em> users. Sure we know how to code, but this is really just a small part of creating an app with an amazing user experience.</p>
<p><strong>But I can&#8217;t draw</strong></p>
<p>During the Swipe Conference we had a 30-minute session that addressed this exact problem. But the fact is, that it’s not a problem at all. When talking about working together to help build an intuitive interactive app, I’m not talking about creating the entire visual representation of your app. I’m talking about presenting ideas, and thinking through them as a team.</p>
<p>This 30-minute session taught us such a simple lesson, how to use a pen, how to draw a basic shape, a square, a circle, and how to colour them in. This is all you need to do, in order to present your ideas to the team. Sketch some simple shapes that represent the objects in your app, shade the background to bring the elements to the front, and colour them in. It’s simpler than a picture you would have drawn in kindergarten. “I can’t draw” is not an excuse!</p>
<p><strong>So I’ve drawn my picture, now what?</strong></p>
<p>At the end of this session, we were all encouraged to hand in the sketches of the iPhone interfaces that we had created. The organisers then took these sketches and stuck them up on the wall. And guess what, with just a black pen, a grey texta, and an orange texta (the swipe conference colour), we had hundreds of ideas that both conveyed an idea and were immediately understandable.</p>
<p>Just as we were able to do at Swipe Conference, everyone in an iPhone team can and must spend time doing the same thing. Pin your ideas on a wall, tear them down, change them, evolve them, give feedback, and work together to evolve from an infinite number of ideas from each team member into one highly refined and fantastic experience.</p>
<p><strong>Brilliant apps with intuitive interactions</strong></p>
<div id="attachment_1412" class="wp-caption alignnone" style="width: 436px"><a href="http://shinetechblog.files.wordpress.com/2011/09/newcollab.png"><img class="size-full wp-image-1412" title="The Required Way of Collaborating" src="http://shinetechblog.files.wordpress.com/2011/09/newcollab.png?w=640" alt=""   /></a><p class="wp-caption-text">This is how we need to think about working</p></div>
<p>By having a team where everyone can provide input, we help to create an experience that can only be beneficial. I know from some of the projects I’ve worked on, that it can be increasingly frustrating when you&#8217;re involved building the inner workings of the app, but cannot influence its overall direction. With such a great device to work on, and the potential it provides to user and developers alike, it would be a gross injustice to continue working in a counter productive way.</p>
<p>Let the designers turn your ideas into beautiful pixel-perfect designs, and let the developers transform these designs into interactive working interfaces &#8211; but also work together with everyone to allow your app to become a masterful interactive experience.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1396/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1396/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1396/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1396&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/09/09/expanding-team-member%e2%80%99s-responsibilities-for-high-quality-iphone-experiences/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/b5c1dc68b3374b9754e81f4414340112?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">chaisehockingshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/simp01.jpg" medium="image">
			<media:title type="html">simp01</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/oldcollab.png" medium="image">
			<media:title type="html">The usual way of collaborating</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/newcollab.png" medium="image">
			<media:title type="html">The Required Way of Collaborating</media:title>
		</media:content>
	</item>
		<item>
		<title>Swipe Conference Highlights: Using gestures as shortcuts within iOS apps</title>
		<link>http://blog.shinetech.com/2011/09/07/swipe-conference-highlights-using-gestures-as-shortcuts-within-ios-apps/</link>
		<comments>http://blog.shinetech.com/2011/09/07/swipe-conference-highlights-using-gestures-as-shortcuts-within-ios-apps/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 00:48:20 +0000</pubDate>
		<dc:creator>Shaun Ervine</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[swipeconference]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1362</guid>
		<description><![CDATA[Yesterday was the last day of Swipe Conference so I thought I would take this time to reiterate one of the points I took from the first presentation by Josh Clark.  Josh covered quite a few topics and if you &#8230; <a href="http://blog.shinetech.com/2011/09/07/swipe-conference-highlights-using-gestures-as-shortcuts-within-ios-apps/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1362&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://shinetechblog.files.wordpress.com/2011/09/swipe.png"><img src="http://shinetechblog.files.wordpress.com/2011/09/swipe.png?w=640&#038;h=213" alt="" title="swipe" width="640" height="213" class="alignnone size-full wp-image-1379" /></a></p>
<p>Yesterday was the last day of <a href="http://swipeconference.com.au/">Swipe Conference</a> so I thought I would take this time to reiterate one of the points I took from the first presentation by Josh Clark.  Josh covered quite a few topics and if you haven&#8217;t already you should check out his book <a href="http://oreilly.com/catalog/0636920001133">Tapworthy: Designing Great iPhone Apps</a>. </p>
<p>In short:</p>
<ul>
<li>Gestures can be brilliant … if the context they are used in feels natural</li>
<li>If you&#8217;re using gestures make sure your users will find them</li>
<li>If you don&#8217;t think your users will figure out your gestures easily, don&#8217;t overload your users with lots of help hints all at once; instead, let them &#8220;unlock&#8221; them over time, like a reward for using your app</li>
<li>Downside though is that there is no consensus on what a 3 finger swipe gesture might do. Every iOS app that uses this gestures decides it for themselves.</li>
</ul>
<p>It was obvious from the way Josh presents that he has so much passion for touch / gesture based devices. What I personally took away from his presentation was that gestures can be awesome shortcuts within your app. In a lot of cases gestures are a natural progression with how we interact with real world items.<span id="more-1362"></span></p>
<p>So let&#8217;s drill in a little more to some of these points.</p>
<p><strong>Gestures are brilliant&#8230; if used in the correct context</strong></p>
<p>How cool are gestures?! As a developer I have the freedom to implement any gesture I want, to perform any actions I desire. But it&#8217;s not really that simple &#8211; you need to consider if the gesture you&#8217;re using makes sense for the functionally you&#8217;re tying it to. For example, do you believe your users will associate a cool 4 finger pinch gesture in your app with bringing up a feedback email form?</p>
<p>Bad example, I know &#8211; because of course you would say: thats just stupid; why would you do that?! But these are exactly the kind of questions we need to ask ourselves &#8211; not only as developers, but as UX designers.</p>
<p><strong>How will users learn your gestures?</strong></p>
<p>If you want to add a gesture to your app because it&#8217;s a cool shortcut, how are you going to let your users know those gestures exist within your app?</p>
<p>Take a look at Apple for example. Their iBook app allows a user to turn a page by swiping from right to left; and yet in Contacts app, performing this action will most likely prompt you to delete one of your contacts. This is just confusing to a user.</p>
<p>I highly recommend that you watch <a href="http://cathyshive.com/">Cathy Shive</a>&#8216;s presentation (when the Swipe Conference presentations are released &#8211; I will update this post when it happens). Cathy highlighted a lot of great reasons why it&#8217;s so important to get your metaphors right. If it looks like a book and doesn&#8217;t function at all like a book, then why are you making your app look like a book?</p>
<p>If the gesture you&#8217;re adding into your app is not something a user will instinctively know to try out, then you need to give them some hints to be able to find this shortcut.</p>
<p>There are a number ways you can do this:</p>
<ul>
<li>Possibly draw attention to the part of the app that has this gesture &#8211; maybe it could pulse for the first time to signify it is interactive</li>
<li>Perform an animation that hints to the type of gesture that may be used to replay something</li>
<li>If your app has quite a few shortcuts maybe only provide one hint each time the user starts up your app</li>
</ul>
<p>Don&#8217;t forget to give your users a chance to explore your app. Users love to explore. They may stumble upon your gestures themselves.</p>
<p><strong>Don&#8217;t overload your new users with &#8220;helpful&#8221; hint messages</strong></p>
<p>I really liked the example Josh highlighted, which was if you were to be given an in-depth explanation before you were to read a book, you would instantly feel like using a book was quite complicated. For example: you turn the page from left to right, you read from left to right (depending on culture) and when you reach the end of a line you jump down to the next line and continue; to bookmark you can fold over a page and return to it in the future; when done, simply close the book (there&#8217;s a funny explanatory diagram along similar lines that you can find <a href="http://www.subtraction.com/2011/03/28/an-illustration-for-stack-america">here</a>).</p>
<p>The same goes for an iOS app. Feel free to explore gestures; make use of them as shortcuts within your app, but if you need to explain to a user how to use your app, then don&#8217;t just throw up a big old welcome message that tells a user every gesture they can perform &#8211; I guarantee you they will glaze over it. If it looks and feels complicated, then you&#8217;re just putting off your users.</p>
<p>In short, ease your users into finding these hidden gems within your app.</p>
<p><strong>I hope swipeconf runs again next year!</strong></p>
<p>Swipe Conference was great! I had a great time and all the presenters were excellent. It was cool to see so many iOS developers / UX designers out there who are really trying to build the best iOS apps they can.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1362/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1362&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/09/07/swipe-conference-highlights-using-gestures-as-shortcuts-within-ios-apps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/c6bc2b8da920b22451e0c8c7a28f901b?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">shaunervineshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/swipe.png" medium="image">
			<media:title type="html">swipe</media:title>
		</media:content>
	</item>
		<item>
		<title>Me Want Cookie: Session Handling with NetBiscuits Mobile Web Apps</title>
		<link>http://blog.shinetech.com/2011/09/06/me-want-cookie-session-handling-with-netbiscuits-mobile-web-apps/</link>
		<comments>http://blog.shinetech.com/2011/09/06/me-want-cookie-session-handling-with-netbiscuits-mobile-web-apps/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 06:55:26 +0000</pubDate>
		<dc:creator>Edward Calderon</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[netbiscuits]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1163</guid>
		<description><![CDATA[Shine was recently involved with helping a client bring an outsourced mobile web site in-house. The site was essentially a guide for browsing business and event information for cinemas, restaurants and bars in your area. Bringing this web site in-house &#8230; <a href="http://blog.shinetech.com/2011/09/06/me-want-cookie-session-handling-with-netbiscuits-mobile-web-apps/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1163&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://shinetechblog.files.wordpress.com/2011/09/cookie-monster.jpg"><img src="http://shinetechblog.files.wordpress.com/2011/09/cookie-monster.jpg?w=640" alt="" title="cookie-monster"   class="alignnone size-full wp-image-1357" /></a></p>
<p>Shine was recently involved with helping a client bring an outsourced mobile web site in-house. The site was essentially a guide for browsing business and event information for cinemas, restaurants and bars in your area. Bringing this web site in-house was mainly an exercise in re-writing the outsourced instance as a component to the client’s own internally developed <a title="http://nodejs.org" href="http://nodejs.org" target="_blank">NodeJS</a>/<a title="http://expressjs.com/" href="http://expressjs.com/" target="_blank">Express</a> app server (currently used to serve their main &#8211; non-mobile &#8211; web site). </p>
<p>The <a title="http://www.netbiscuits.com" href="http://www.netbiscuits.com" target="_blank">NetBiscuits</a> platform was used to handle all the device specific porting which allowed the development effort to focus almost entirely on business logic and backend data processing. The combined learning curve of NetBiscuit’s own markup language with Shine’s <a title="https://github.com/shinetech/jazz" href="https://github.com/shinetech/jazz" target="_blank">Jazz</a> template system was simple enough to make the presentation layer development a breeze. This blog will talk about the process involved in developing for NetBiscuits and some of the problems and solutions encountered on the way.<br />
<span id="more-1163"></span><br />
<strong>So what is NetBiscuits?</strong><br />
NetBiscuits is a hosted platform technology that enables web apps to reach mobile devices. It’s essentially a knowledge base that maps mobile devices and their browsers to a presentation profile, translating your mobile site into the format expected by whatever mobile client that is making the request.</p>
<p>It’s worth noting that the concept of porting web content to mobile devices and their browsers is big. Seriously. The impact of standardized mobile web development is perhaps lost on those of us who’ve never worked in it before. Where common web development concerns itself with compliance across 4 or 5 main browsers, mobile web development must cater to <a title="http://www.tera-wurfl.com/explore/" href="http://www.tera-wurfl.com/explore/" target="_blank">hundreds</a>. Even in the days when Nokia ruled the world the support and maintenance of mobile web apps for an ever-growing device list was not just for the final phase of a project but an ongoing full time job. </p>
<p>Maximizing your audience still means supporting the lowest denominator, but these days you can expect your low-end browsers to run javascript. This old school WAP and J2ME developer acknowledges that times have moved on but pays due credit to the people behind NetBiscuits and their mobile platform.</p>
<p><strong>Working with NetBiscuits</strong><br />
You develop your mobile web app in mostly the same way as any other web app with the difference that instead of dynamically generating HTML you’re generating <a title="http://www.netbiscuits.com/biscuitml-reference" href="http://www.netbiscuits.com/biscuitml-reference" target="_blank">BiscuitML</a>. Your production URL will point to your NetBiscuits account (hosted on their cloud) which in turn points to your app server.</p>
<div class="mceTemp mceIEcenter" style="text-align:center;">
<dl class="wp-caption aligncenter">
<dt class="wp-caption-dt"><a href="http://shinetechblog.files.wordpress.com/2011/09/simple_nb_flow.png"><img class="size-full wp-image-1165" title="simple_nb_flow" src="http://shinetechblog.files.wordpress.com/2011/09/simple_nb_flow.png?w=640&#038;h=175" alt="simple_nb_flow" width="640" height="175" /></a></dt>
<dd class="wp-caption-dd">Simple Control Flow</dd>
</dl>
</div>
<p>For as long as your app server talks to the NetBiscuits platform in BML, NetBiscuits will talk fluently to all devices that hit your mobile site. This means your development efforts can focus purely on the business logic without the concern of tailoring content to multiple screen sizes and browser types.</p>
<div class="mceTemp mceIEcenter" style="text-align:center;">
<dl class="wp-caption aligncenter">
<dt class="wp-caption-dt"><a href="http://shinetechblog.files.wordpress.com/2011/09/detailed_nb_flow.png"><img class="size-full wp-image-1164" title="detailed_nb_flow" src="http://shinetechblog.files.wordpress.com/2011/09/detailed_nb_flow.png?w=640&#038;h=192" alt="Detailed NetBiscuits Control Flow" width="640" height="192" /></a></dt>
<dd class="wp-caption-dd">Detailed Control Flow</dd>
</dl>
</div>
<p>So what can you do with BML? Pretty much everything you can do with HTML. For most of the devices hitting your mobile site NetBiscuits will convert your BML to HTML. Writing markup in BML is done with Biscuit tags that comprise of familiar page elements such as; list, table, form, image etc. More specialised tags are available to handle ad-banners, analytics, maps and media. A script tag exists to provide various levels of javascript support ranging from handling browser events completely within the markup to simply relying on an external js file.</p>
<p><strong>Challenges with Session Handling</strong><br />
Environmental constraints meant that client side session management was the only option available. This in turn meant that support for cookies and javascript was a requirement for any browser hitting the site. Cookies would store the user’s state code (see below) and the preferred list of cinema venues for returning movie times.</p>
<p><pre class="brush: xml;">
&lt;TEXT&gt;
    &lt;richtext&gt;
        Select your state:[br]
    &lt;/richtext&gt;
    ...
    &lt;richtext&gt;
        &lt;event type=&quot;onclick&quot;&gt;
            &lt;!-- Custom set cookie function --&gt;
            &lt;action eval=&quot;setStateCodeCookie('VIC');&quot; /&gt;
            &lt;action eval=&quot;return true;&quot; /&gt;
        &lt;/event&gt;
        [url=&quot;path/to/main/page/?{URLParams}&quot;]VIC[/url]
    &lt;/richtext&gt;
    ...
&lt;/TEXT&gt;

</pre></p>
<p>Maintaining sessions within cookies is certainly made easier in the Tomcat/JSP model where the HTTPSession interface provides easy access to user data. In such a scenario, session data are largely managed by the server and a user is identified by a cookie-stored session id. In our instance we ended up pulling session data directly from cookies after discovering some limitations with BML.</p>
<p>Amidst the wealth of documentation for BML and its rich internet features there were examples of how to get/set/delete cookies from script tags. This led us to the false belief that a cookie could be interrogated and manipulated fully from within the markup. Wrong. BML’s <code>getCookie</code> function exists only to test the presence of a cookie, not to read/extract its data. Cookie handling was therefore relegated to an external js file which also meant taking control away from the markup for certain browser events. Specifically, the <code>onclick</code> event had to be hijacked from certain anchor tags to implement redirects for re-written URLs.</p>
<p><pre class="brush: xml;">
&lt;TEXT&gt;
    &lt;richtext&gt;
        Find Movies:[br]
    &lt;/richtext&gt;
    ...
    &lt;richtext&gt;
        &lt;event type=&quot;onclick&quot;&gt;
            &lt;!-- Override default behaviour and use
                 an externally defined custom handler
                 to perform redirect --&gt;
            &lt;action eval=&quot;getPreferredCinemasForMovieSearch('{URLParams}');&quot; /&gt;
            &lt;action eval=&quot;return false;&quot; /&gt;
        &lt;/event&gt;
        [url=&quot;#&quot;]Browse by Cinemas[/url]
    &lt;/richtext&gt;
    ...
&lt;/TEXT&gt;
</pre></p>
<p><strong>Hijacking the Onclick Event</strong><br />
Retrieving a user’s cinema preferences (above) is one example of URL re-writing trickery. Retrieving their state code is another. A state code would populate all URLs presented to the user. New users would have their state code persisted in URL parameters for the duration of their session. Returning users would need their session initialised by extracting their state code from the cookie.</p>
<p>Since cookie data wasn’t available at BML generation time, extraction would have to happen at URL click time. So this meant triggering a javascript function on the browser using the anchor tag’s <code>onclick</code> event.</p>
<div class="mceTemp mceIEcenter" style="text-align:center;">
<dl class="wp-caption aligncenter">
<dt class="wp-caption-dt"><a href="http://shinetechblog.files.wordpress.com/2011/09/event_blackhole.png"><img class="size-full wp-image-1200" title="Cookie handling at onclick" src="http://shinetechblog.files.wordpress.com/2011/09/event_blackhole.png?w=640&#038;h=181" alt="Cookie handling at onclick" width="640" height="181" /></a></dt>
<dd class="wp-caption-dd">Cookie handling at onclick</dd>
</dl>
</div>
<p>Performing cookie data extraction at ‘click time’ effectively turns the handler function into an event-swallowing black hole, since it must also perform the page redirect leaving no control to pass back to the browser and it’s anchor tags. A consequence is that any URL parameters normally processed within the markup must now be passed to the javascript function for re-writing to the URL.</p>
<p><strong>Ideals, Alternatives and Trade Offs</strong><br />
Relying on the BML to handle all things cookie/session related would have been the most ideal solution. URLs could have been re-written at BML generation time using cookie data without any javascript intervention. With the benefit of hindsight, the next best alternative would have been to utilize the <code>onload</code> event instead of hijacking the <code>onclick</code> event. This is because the <code>onload</code> event allows for the markup to retain control of its anchors – since re-writing happens well before URL click time.</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/09/session_handling1.png"><img class="aligncenter size-full wp-image-1193" title="session_handling" src="http://shinetechblog.files.wordpress.com/2011/09/session_handling1.png?w=640&#038;h=402" alt="" width="640" height="402" /></a>This works fine for initialising a returning user’s state code since ALL URLs are modified with this data in the same way. However in situations where we needed to be more selective (extracting a user’s cinema preferences for only certain URLs), additional effort is required to identify/isolate the subset of URLs to operate on. Not all URLs need specific preference data appended to them. So the trade off is down to the assembly and redirect of URLs for a pre-determined anchor using the <code>onclick</code> method versus isolating a target set of anchors and appending data to an existing URL using the <code>onload</code> method.</p>
<p><pre class="brush: xml;">
&lt;page&gt;
    &lt;script&gt;
        &lt;event type=”onload”&gt;
            &lt;!-- Append cookie data to a
                 target set of anchor tags --&gt;
            &lt;action eval=&quot;appendCookieDataToTargetURLs('{cookieName}',
                                                       '{targetId}',
                                                       '{URLParams}');&quot; /&gt;
        &lt;/event&gt;
    &lt;/script&gt;
...
&lt;/page&gt;
</pre></p>
<p><strong>Conclusion</strong><br />
On the one hand it makes sense that BML can only provide superficial support for cookies given that its markup is never processed directly by the browser. On the other hand, if the NetBiscuits platform is communicating with client browsers and processing the BML on our behalf, could it not set its own session cookie and expose it through a set of functions within the markup? Where is NetBiscuit’s HTTPSession?! Perhaps the logistics of supporting potentially thousands of such sessions makes this concept infeasible.</p>
<p>To summarise, there may be further options available for enabling a mobile website that warrant a comparison but our experience with NetBiscuits was a happy and successful one. Cookie handling aside, the presentation layer development for our mobile app was super smooth. We also made use of a couple of the specialised tags for analytics and maps with relative ease.</p>
<p>The absence of full cookie support just means a little extra work. Perhaps we’ll see this built out in a future implementation of BML? In the meantime, its just old-school javascript know-how to enable cookie based sessions for your web apps. Of course, all this needs to be put in perspective with the main advantage provided by NetBiscuits: standardised mobile web development! Easy to overlook this significance when granted in such an accessible and ready-to-use format.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1163/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1163&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/09/06/me-want-cookie-session-handling-with-netbiscuits-mobile-web-apps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e5c4cf41c760c1697460856b91db6a72?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">edwardcalderonshinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/cookie-monster.jpg" medium="image">
			<media:title type="html">cookie-monster</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/simple_nb_flow.png" medium="image">
			<media:title type="html">simple_nb_flow</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/detailed_nb_flow.png" medium="image">
			<media:title type="html">detailed_nb_flow</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/event_blackhole.png" medium="image">
			<media:title type="html">Cookie handling at onclick</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/09/session_handling1.png" medium="image">
			<media:title type="html">session_handling</media:title>
		</media:content>
	</item>
		<item>
		<title>JavaScript from Nose to Tail</title>
		<link>http://blog.shinetech.com/2011/09/06/javascript-from-nose-to-tail/</link>
		<comments>http://blog.shinetech.com/2011/09/06/javascript-from-nose-to-tail/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 00:42:30 +0000</pubDate>
		<dc:creator>Marc Fasel</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1195</guid>
		<description><![CDATA[Cliffano Subagio from Shine Technologies presented together with Carl Husselbee from Sensis &#8220;JavaScript from Nose to Tail&#8221; at the August MelbJS Meetup. The slides and the video of the presentation are now online.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1195&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div></div>
<p>Cliffano Subagio from Shine Technologies presented together with Carl Husselbee from Sensis &#8220;JavaScript from Nose to Tail&#8221; at the August <a title="MelbJS" href="http://melbjs.com/" target="_blank">MelbJS</a> Meetup. The <a title="slides" href="http://www.slideshare.net/cliffano/javascript-everywhere-from-nose-to-tail" target="_blank">slides</a> and the <a title="video" href="http://vimeo.com/28531395" target="_blank">video</a> of the presentation are now online.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1195/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1195/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1195/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1195/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1195/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1195/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1195/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1195/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1195&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/09/06/javascript-from-nose-to-tail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/b6fce92508146cc8d095ed11ebacfbd7?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">marcfaselshinetech</media:title>
		</media:content>
	</item>
		<item>
		<title>Automatic Data Migration Testing: Empowering Testers with Hudson</title>
		<link>http://blog.shinetech.com/2011/08/31/hudson-for-better-automatic-data-migration-testing/</link>
		<comments>http://blog.shinetech.com/2011/08/31/hudson-for-better-automatic-data-migration-testing/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 06:27:31 +0000</pubDate>
		<dc:creator>Meng Xu</dc:creator>
				<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[hudson]]></category>
		<category><![CDATA[jenkins]]></category>

		<guid isPermaLink="false">http://blog.shinetech.com/?p=1043</guid>
		<description><![CDATA[Introduction There have been many good examples of using Hudson for cross-platform builds and automatic execution of tests, but Hudson also provides a great environment for empowering non-developers to execute particular tests whenever they want. We have found this to &#8230; <a href="http://blog.shinetech.com/2011/08/31/hudson-for-better-automatic-data-migration-testing/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1043&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>Introduction</strong></p>
<p>There have been many good examples of using <a href="http://hudson-ci.org/">Hudson</a> for cross-platform builds and automatic execution of  tests, but Hudson also provides a great environment for empowering non-developers to execute particular tests whenever they want. We have found this to be particularly the case when automating data migration tests.</p>
<p>This article will discuss the what automatic data migration testing is, and how Hudson can make it easier. Whilst it refers to Hudson, the same techniques could also be used with <a href="http://jenkins-ci.org/">Jenkins</a>.<br />
<span id="more-1043"></span><br />
<strong>About automated data migration testing</strong></p>
<p>Data migration testing is usually quite complicated and time-consuming. This is because you need to make sure all the migrated records are checked for accuracy from the source database to the destination database. It not only require testers to identify how the migrated records are mapped from the source to the destination, but also to perform checking on the values of the records.</p>
<p>The complexity of data migration testing increases when the testing needs to be done on huge amount of data and the mapping from the source to the the destination is quite complicated.</p>
<p>In order to reduce the complexity of data migration testing and achieve better testing performance, it becomes necessary to apply automatic verification. In some cases manual testing can be completely superseded by automatic testing.</p>
<p><strong>A simple example</strong></p>
<p>The following diagram illustrates a simple method for automating data migration testing that we have taken in the past:</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/08/automatic_testing_program3.png"><img class="alignnone size-large wp-image-1155" title="automatic_testing_program" src="http://shinetechblog.files.wordpress.com/2011/08/automatic_testing_program3.png?w=1024&#038;h=536" alt="" width="1024" height="536" /></a></p>
<p>We see that testers only need to provide test inputs, each of which specifies:</p>
<ul>
<li>the table(s) that the data is being sourced from</li>
<li>the table(s) that the data is being sent to</li>
<li>how the migrated data is mapped from the source to the destination</li>
</ul>
<p>Inputs can be things like custom JMeter Test Scripts or Excel Spreadsheets.</p>
<p>Once the test inputs have been prepared, an automatic data migration testing program can load them and perform checking on the data from the source database to the target database.</p>
<p>After the testing is completed, the program will generate the test reports which can be either XML or HTML format.</p>
<p><strong>Limitations of a stand-alone approach</strong></p>
<p>Whilst it provides a good baseline to work from, the aforementioned approach is not particular user-friendly:</p>
<ol>
<li>Test programs are usually executed from the command-line, meaning each test execution needs to be triggered on a separate terminal. Therefore, multiple terminals will be required to execute a number of different tests if test output for each test execution needs to be monitored and kept.</li>
<li>Testers need to tell the program which test is to be executed, and the environment that the test is to be executed against. The execution can become quite complex when there are a lot potential tests to choose from, or a number of different environments.</li>
<li>During the process of data migration, there can be frequent changes to data mapping rules, which requires testers to frequently edit their existing test inputs accordingly, or to add new test inputs</li>
</ol>
<p>Fortunately, there is a tool that helps with some of these problems: the Hudson continuous integration server.</p>
<p><strong>How Hudson helps</strong></p>
<p>By using Hudson to run tests, users get an out-of-the-box interface to trigger tests, monitor test progress, and track test results. Specifically:</p>
<ol>
<li>Testers do not have to execute tests from the command-line</li>
<li>Testers can specify parameters and easily pass them to test programs; for example: the test input to be executed and the environment that the test is to be executed against</li>
<li>Multiple test executions can be triggered simultaneously</li>
<li>Test reports and console output are well maintained</li>
<li>Test inputs can be managed and fetched from a central repository</li>
<li>Specific descriptions can be generated for each test execution, which provides better maintenance and tracking</li>
<li>Each tester may log onto Hudson with a specific user name and password, which helps identify who ran each test</li>
</ol>
<p><strong>Setting it up</strong></p>
<p>So how does one go about setting up such a project? Firstly, a Hudson project needs to be created. The project can be created by simply clicking on &#8220;New Job&#8221; on the Hudson homepage, and provide the project name and project type:</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/08/new_project.png"><img class="alignnone size-large wp-image-1119" title="new_project" src="http://shinetechblog.files.wordpress.com/2011/08/new_project.png?w=1024&#038;h=445" alt="" width="1024" height="445" /></a></p>
<p>Click &#8220;OK&#8221; button to save the project, and the project will be shown on the Hudson homepage:</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/08/project_created1.png"><img class="alignnone size-large wp-image-1132" title="project_created" src="http://shinetechblog.files.wordpress.com/2011/08/project_created1.png?w=1024&#038;h=193" alt="" width="1024" height="193" /></a></p>
<p>We can then click through to the project, and click the &#8216;Configure&#8217; link. In order to allow testers to specify the test to be run and the database environment the test is to be run against, the project needs to have two input parameters defined for it:</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/08/build_parameters.png"><img class="alignnone size-large wp-image-1118" title="build_parameters" src="http://shinetechblog.files.wordpress.com/2011/08/build_parameters.png?w=1024&#038;h=760" alt="" width="1024" height="760" /></a></p>
<p>Now let&#8217;s specify what the build actually executes. Normally, this would be a complex Ant script. For the purposes of simplicity, we&#8217;ll just specify a dummy shell script:</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/08/build_step3.png"><img class="alignnone size-full wp-image-1129" title="build_step" src="http://shinetechblog.files.wordpress.com/2011/08/build_step3.png?w=640&#038;h=410" alt="" width="640" height="410" /></a></p>
<p>In this case, the script will:</p>
<ol>
<li>Check if the specified input test file exists. If the input test file does not exist, then it will exit the current build job gracefully; otherwise it will proceed the build job.</li>
<li>Check if the test reports have been generated successfully for the current build job.</li>
<li>At the end of each build job, a custom build description will be set which will clearly tell which test was executed on which test environment &#8211; for example &#8220;Execution of test_input1.xlsx on Source Database 2&#8243;.</li>
</ol>
<p>Finally, as test reports need to be kept for for tracking purposes, we define them as build artifacts:</p>
<p><a href="http://shinetechblog.files.wordpress.com/2011/08/artifacts.png"><img class="alignnone size-large wp-image-1123" title="artifacts" src="http://shinetechblog.files.wordpress.com/2011/08/artifacts.png?w=1024&#038;h=235" alt="" width="1024" height="235" /></a></p>
<p><strong>Taking it for a spin</strong></p>
<p>To run this build:</p>
<ol>
<li>Click &#8216;Build Now&#8217; for the &#8216;Automatic Data Migration Testing&#8217; project</li>
<li>Select a specific test input to run:<a href="http://shinetechblog.files.wordpress.com/2011/08/select_test.png"><img class="alignnone size-large wp-image-1134" title="select_test" src="http://shinetechblog.files.wordpress.com/2011/08/select_test.png?w=1024&#038;h=330" alt="" width="1024" height="330" /></a></li>
<li>Select the test environment to execute the test input against:<a href="http://shinetechblog.files.wordpress.com/2011/08/select_env.png"><img class="alignnone size-large wp-image-1135" title="select_env" src="http://shinetechblog.files.wordpress.com/2011/08/select_env.png?w=1024&#038;h=334" alt="" width="1024" height="334" /></a></li>
<li>Click &#8216;Build&#8217; to trigger the build to start executing the test input.</li>
<li>Track test execution progress by accessing the build console output:<a href="http://shinetechblog.files.wordpress.com/2011/08/console_output2.png"><img class="alignnone size-large wp-image-1137" title="console_output" src="http://shinetechblog.files.wordpress.com/2011/08/console_output2.png?w=1024&#038;h=360" alt="" width="1024" height="360" /></a></li>
</ol>
<p>Once the build job is completed, testers can:</p>
<ul>
<li>Check the test reports by accessing the build artifacts:<a href="http://shinetechblog.files.wordpress.com/2011/08/build_artifacts2.png"><img class="alignnone size-full wp-image-1136" title="build_artifacts" src="http://shinetechblog.files.wordpress.com/2011/08/build_artifacts2.png?w=640&#038;h=411" alt="" width="640" height="411" /></a></li>
<li>Use the custom build description to keep track of what this build did:<a href="http://shinetechblog.files.wordpress.com/2011/08/custom_description.png"><img class="alignnone size-large wp-image-1139" title="custom_description" src="http://shinetechblog.files.wordpress.com/2011/08/custom_description.png?w=1024&#038;h=498" alt="" width="1024" height="498" /></a><br />
In this case, the test input file is &#8220;test_input1.xlsx&#8221; and the test environment is &#8220;Source Database 3&#8243;; therefore the build description will be set as &#8220;Execution of test_input1.xlsx on Source Database 3&#8243;.</li>
<li>Review the build console output</li>
</ul>
<p><strong>Conclusion</strong></p>
<p>We&#8217;ve seen how Hudson is a great environment for empowering testers to run their own data migration tests. It does this by:</p>
<ul>
<li>Managing test inputs and environments</li>
<li>Executing single or multiple tests</li>
<li>Tracking test executions</li>
<li>Storing test reports</li>
</ul>
<p>It&#8217;s a tribute to the original Hudson developers that it can be used in new and interesting ways.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/shinetechblog.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/shinetechblog.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/shinetechblog.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/shinetechblog.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/shinetechblog.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/shinetechblog.wordpress.com/1043/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/shinetechblog.wordpress.com/1043/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/shinetechblog.wordpress.com/1043/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.shinetech.com&amp;blog=25494966&amp;post=1043&amp;subd=shinetechblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.shinetech.com/2011/08/31/hudson-for-better-automatic-data-migration-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e1cfbf96c3ec195241b36cbbf57821f2?s=96&amp;d=identicon&amp;r=G" medium="image">
			<media:title type="html">mengxushinetech</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/automatic_testing_program3.png?w=1024" medium="image">
			<media:title type="html">automatic_testing_program</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/new_project.png?w=1024" medium="image">
			<media:title type="html">new_project</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/project_created1.png?w=1024" medium="image">
			<media:title type="html">project_created</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/build_parameters.png?w=1024" medium="image">
			<media:title type="html">build_parameters</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/build_step3.png" medium="image">
			<media:title type="html">build_step</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/artifacts.png?w=1024" medium="image">
			<media:title type="html">artifacts</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/select_test.png?w=1024" medium="image">
			<media:title type="html">select_test</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/select_env.png?w=1024" medium="image">
			<media:title type="html">select_env</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/console_output2.png?w=1024" medium="image">
			<media:title type="html">console_output</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/build_artifacts2.png" medium="image">
			<media:title type="html">build_artifacts</media:title>
		</media:content>

		<media:content url="http://shinetechblog.files.wordpress.com/2011/08/custom_description.png?w=1024" medium="image">
			<media:title type="html">custom_description</media:title>
		</media:content>
	</item>
	</channel>
</rss>

