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

<channel>
	<title>John P Wood &#187; Software</title>
	<atom:link href="http://johnpwood.net/category/software/feed/" rel="self" type="application/rss+xml" />
	<link>http://johnpwood.net</link>
	<description>collection of thoughts...</description>
	<lastBuildDate>Wed, 18 Jan 2012 20:56:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Introducing Proby &#8211; Task monitoring made simple!</title>
		<link>http://johnpwood.net/2011/09/19/introducing-proby-task-monitoring-made-simple/</link>
		<comments>http://johnpwood.net/2011/09/19/introducing-proby-task-monitoring-made-simple/#comments</comments>
		<pubDate>Mon, 19 Sep 2011 15:50:20 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[personal projects]]></category>
		<category><![CDATA[proby]]></category>
		<category><![CDATA[signal]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=1293</guid>
		<description><![CDATA[Note: This entry has been cross-posted from the Signal company blog. One Monday morning about a month ago, I was browsing through open issues in our bug tracker looking for [...]]]></description>
			<content:encoded><![CDATA[<p>Note: This entry has been cross-posted from the <a href="http://blog.signalhq.com/2011/09/19/introducing-proby-task-monitoring-simple/">Signal company blog</a>.</p>
<p><a href="http://probyapp.com"><br />
<img src="http://johnpwood.net/wp-content/uploads/2011/09/proby_logo.png" alt="" title="proby_logo" width="225" height="68" class="alignright size-full wp-image-1296" /><br />
</a></p>
<p>One Monday morning about a month ago, I was browsing through open issues in our bug tracker looking for something to work on.  It was my week on &#8220;technical support&#8221;.  At Signal, the engineer on technical support spends a week working on non customer facing issues with our infrastructure, process, etc, that are too large to simply knock out as you encounter them.</p>
<p>An issue entitled <em>&#8220;Add monitoring to detect jobs that do not start&#8221;</em> caught my attention.  We already had monitoring in place to alert us when a job fails.  However, we had nothing to alert us if that job never starts in the first place.  We have many scheduled jobs that run in the background, some pretty important, and have been bitten on more than one occasion by reoccurring jobs that had not run for quite some time.</p>
<p>I bounced some ideas off the team, and we all agreed that that it made sense to create a new application to monitor our scheduled tasks.  The app would know what is supposed to run, and when.  We would change all of our jobs to &#8220;ping&#8221; the app when they start and finish.  If the app detects that something did not run when it was supposed to, or did not finish when it was supposed to, it could alert the team.</p>
<p>And just like that, <a href="http://probyapp.com">Proby</a> was born.</p>
<p><em>“What&#8217;s with the name?”</em>, you ask?  I likened the application to a probation officer, keeping an eye on wayward tasks.</p>
<p>Since going live, Proby has caught several issues with our scheduled jobs that would have gone unnoticed&#8230;many more than I would have anticipated.  It has also evolved into a fairly complete application.  It is easy to setup new tasks.  It holds onto the execution history of each task, allowing you to see a trend of the run time for each task, and which runs resulted in an alarm.  It supports alarms via email or SMS, using Signal&#8217;s SMS messaging API.  It has several settings that allow you to tweak exactly when an alarm is sent, cutting down on the number of false alarms.  And, thanks to designer extraordinaire <a href="http://www.signalhq.com/about-us/team/drew-myler">Drew Myler</a>, it <a href="http://probyapp.com/screenshots">looks amazing</a>!</p>
<p>Shortly after creating Proby, we realized that there is no way we are the only ones who have had scheduled tasks go days without running, unnoticed.  So today, we are making Proby available to the general public.  It is currently in closed beta, and we are letting people in slowly to flush out any bugs or other issues.  <strong>Use of Proby is also FREE while it is in beta.</strong></p>
<p>Interested?  Head on over to <a href="http://probyapp.com/signup">http://probyapp.com/signup</a> and signup to participate in the closed beta!  And, <strong>don&#8217;t forget to <a href="http://twitter.com/#!/probyapp">follow @probyapp on Twitter</a></strong> for updates!</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2011/09/19/introducing-proby-task-monitoring-made-simple/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What I Learned by Attending a Code Retreat</title>
		<link>http://johnpwood.net/2011/07/29/what-i-learned-by-attending-a-code-retreat/</link>
		<comments>http://johnpwood.net/2011/07/29/what-i-learned-by-attending-a-code-retreat/#comments</comments>
		<pubDate>Fri, 29 Jul 2011 13:23:42 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[career development]]></category>
		<category><![CDATA[code retreat]]></category>
		<category><![CDATA[continued education]]></category>
		<category><![CDATA[practice]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=1258</guid>
		<description><![CDATA[On Tuesday, July 26th, I attended my first code retreat. The code retreat was led by Corey Haines and Tyler Jennings, sponsored by Obtiva, and held to coincide with Tech [...]]]></description>
			<content:encoded><![CDATA[<p>On Tuesday, July 26th, I attended my first code retreat.  The code retreat was led by <a href="https://twitter.com/#!/coreyhaines">Corey Haines</a> and <a href="http://twitter.com/#!/Tyler_Jennings">Tyler Jennings</a>, sponsored by <a href="http://obtiva.com/">Obtiva</a>, and held to coincide with <a href="http://techweek.com/">Tech Week</a>.  Simply put, it was invaluable experience, and I can&#8217;t wait for the chance to do it again.</p>
<h2>What the hell is a code retreat?</h2>
<p>For those who have never attended a <a href="http://coderetreat.com/">code retreat</a>, the format is simple.  The group is given a problem.  In our case the problem was <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life">Conway&#8217;s Game of Life</a>.  The code retreat is then broken up into several 45 minute sessions.  Each session you pair with somebody new, and you take a stab at solving some portion of the problem.  All code is written using <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a>.  At the end of each session you delete all of the code you created.  The problem, and the time limit on the sessions, are specifically chosen so that there is little to no chance that you will come up with a complete solution in the allowed time.  Solving the problem is not the point.  <strong>The point is to practice.</strong></p>
<p>We as software developers don&#8217;t give ourselves enough time to practice.  At work, or even with open source or side projects, we&#8217;re always trying to get something done.  Rarely, if at all, do we practice solely for the sake of practice.  This is what we focused on at the code retreat.  At the end of each 45 minute session, we deleted our code, and discussed what we learned.  We were encouraged to try new ideas, to really push ourselves outside of our comfort zone.  Knowing that the code would be deleted in a matter of minutes, there was no need to worry about screwing up the design, or creating something that would ultimately become unmaintainable.  We had a safety net, and were encouraged to use it.</p>
<p>Corey said that we never get the chance to write &#8220;perfect code&#8221;.  Perfect code doesn&#8217;t exist in the real world.  In the real world products need to ship.  It is simply not practical to spend the amount of time on a piece of code that is required to make it &#8220;perfect&#8221;.  There are always trade offs of one form or another.  However, code retreats give you the opportunity to practice writing perfect code.  There is nothing to ship, nothing to “get done”.  The code lives for 45 minutes, and then it disappears, giving you a unique opportunity to practice writing tiny pieces of perfect code.</p>
<h2>Structured chaos</h2>
<p>Sounds pretty hectic, right?  But, the sessions were far from unstructured.  Throughout the retreat, we were encouraged to keep in mind the four rules of simple design:</p>
<ul>
<li>Runs all the tests</li>
<li>No duplication</li>
<li>Proper naming (expresses ideas and reveals intent)</li>
<li>Small (small methods, small classes)</li>
</ul>
<p>The morning sessions were primarily focused on getting familiar with the problem.  As the day progressed, we were encouraged by Tyler and Corey to try out certain ideas, or to think about tackling old problems in new ways.  Can you solve the issue using polymorphism instead of if statements?  Can you do it by capping all of your methods to 3 lines?  What happens when you focus on proper naming of your tests and your methods?  These &#8220;challenges&#8221; were designed to push us out of our comfort zone.  It worked.</p>
<h2>Some thoughts</h2>
<p>I quickly realized that 45 minutes was not enough time to solve the problem.  However, it took me almost the entire day to finally get comfortable with the fact that even solving a significant portion of the problem was out of reach.  About half way through the day, I caught myself trying to solve a chunk of the problem that was way too large for the amount of time we were given.  This resulted in me rushing a solution in an attempt to get my way too large of scope test to pass.  At the end of the session, I was left confused with a pile of crappy code (unnecessary abstractions, no encapsulation, etc), at least half of which I wasn&#8217;t sure why we wrote.</p>
<p>I love that feeling you get when you create something, or solve a problem.  This is why I am a programmer.  Not being able to finish the problem, or even a significant portion of it, was incredibly frustrating.  It took me the entire day to finally let go of that.</p>
<p>It was also great to see the different ways people were approaching the problem.  At the start of the code retreat most pairs were pursuing a similar approach.  But by the end of the day, the variety of approaches was simply amazing.  With each session, everybody learned something new.  Since we were required to find a new partner for each session, the combined experience of each new team seemed to produce a new approach, slightly different from the approaches each of the partners had tried in previous sessions.  It was almost like looking at an old tree.  Each session resulted in the forking of each branch on the tree.  By then end of the day, there were a whole lot of branches.</p>
<h2>Practice, practice, practice&#8230;</h2>
<p>At the end of the code retreat, we all briefly shared with the group what we learned that day.  Everybody had something new to say.  The code retreat had a way of showing all of us what we needed to work on and what we needed to explore.</p>
<p>When writing this blog post, it suddenly hit me.</p>
<blockquote><p><strong>This is exactly what practice is designed to do!</strong></p></blockquote>
<p>When I practice something else (karate basics or kata for example), it has the same effect.  <strong>Serious practice makes it very clear what needs to be developed.</strong>  It makes no difference what it is that you&#8217;re practicing.  The key to getting better at something is to practice, and to continue developing the &#8220;problem areas&#8221; identified by your practice.  But it can&#8217;t be just any practice.  As Corey stated during the code retreat:</p>
<blockquote><p><strong>Practice doesn&#8217;t make perfect.  Perfect practice makes perfect.</strong></p></blockquote>
<p>Perhaps the single biggest thing I took away from the code retreat is that it showed me how to practice writing code.</p>
<h2>What I learned</h2>
<p>First off, I learned that I need to slow down&#8230;way down.  All too often I think I know the solution to a problem before my fingers even touch the keyboard.  And, perhaps worse, is that I am so focused on implementing <strong>that</strong> solution, that I will often ignore warning signs (code smells) that should be alerting me that my solution may perhaps not be the best solution.  This code retreat  made me realize that I need to do a much better job of listening to my tests, and listening to my code.  I need to do a better job of keeping my nose open at all times for code smells, and to stop when I smell something.  Something that doesn&#8217;t feel right in the tests is a sure sign that something is wrong with the design.  Stop, take a step back, think for a minute about what is causing the smell, and fix it.</p>
<p>There is nothing wrong with having a solution in mind before you start coding.  In fact, I think that most times you want to have a solution in mind before your fingers touch the keyboard.  However, you should keep an open mind as you start to build your solution.  Don&#8217;t assume your initial solution is the best solution.  In fact, it&#8217;s probably safer to assume that it is not, and allow your tests to guide you to a better one.</p>
<h2>Go to a code retreat!</h2>
<p>If you&#8217;re serious about getting better as a programmer, and have never been to a code retreat, your missing out on an incredible learning experience.  Make it a point to go to one.  Since code retreats are essentially group coding practice, you can attend them over and over and be sure to walk away with something new every time.  I&#8217;m already looking forward to the next one.</p>
<p>I have so much to learn.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2011/07/29/what-i-learned-by-attending-a-code-retreat/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Fast Queries on Large Datasets Using MongoDB and Summary Documents</title>
		<link>http://johnpwood.net/2011/05/31/fast-queries-on-large-datasets-using-mongodb-and-summary-documents/</link>
		<comments>http://johnpwood.net/2011/05/31/fast-queries-on-large-datasets-using-mongodb-and-summary-documents/#comments</comments>
		<pubDate>Tue, 31 May 2011 18:16:55 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[mongodb signal]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=1204</guid>
		<description><![CDATA[The past few months we at Signal have been spending a considerable amount of time and effort enhancing the performance of our application for some of our larger customers. It [...]]]></description>
			<content:encoded><![CDATA[<p>The past few months we at <a href="http://www.signalhq.com">Signal</a> have been spending a considerable amount of time and effort enhancing the performance of our application for some of our larger customers.  It wasn&#8217;t that long ago that our largest subscription list was only 80,000 subscribers.  We now have many customers with lists topping a million subscribers, with our largest currently sitting at 8.5 million.  That&#8217;s quite a jump in size, and not one that can generally be made without making a few tweaks to the application.  With this jump, certain areas of our application began to slow down considerably.  One such area was subscription list reporting.  Many of the reports were backed by SQL queries that were becoming increasingly expensive to run against the ever growing tables.</p>
<p>To address this issue, we decided to create daily summaries of the subscription list data, and report off of the summary data instead of the raw data.  The vast majority of our list reporting is already broken out by day, so this seemed logical.  And, we decided to use <a href="http://www.mongodb.org/">MongoDB</a> to store the summary data.</p>
<h2>Why MongoDB?</h2>
<p>We are already running MySQL and <a href="http://couchdb.apache.org/">CouchDB</a> in production.  Why not use one of those?  Why introduce a 3rd database product to the architecture?</p>
<p>The summary data is live data, not archived data (like the data we are storing in CouchDB).  As subscriptions are created/destroyed for the current day, we need to increment/decrement the appropriate metrics.  There are also some use cases where we need to alter summary documents for days in the past.  This means we need support for atomic operations in the underlying database, to prevent race conditions from skewing the stats.  CouchDB does not have the ability to atomically update a value in a document with a single call, so that took it out of the running.  Some of our more active lists see several new subscriptions a second.  Dealing with document update conflicts would have been a nightmare.</p>
<p>We decided to go with MongoDB over MySQL because of the structure of the summary data.  We had several metrics that we wanted to keep tabs on (opt ins per day, opt outs per day, etc).  Some of these metrics had a nested nature to them.  For example, in addition to keeping track of the number of opt-outs per day, we also want to keep track of the reasons those subscriptions were canceled.  Also, there are several ways that a user can opt-in to a subscription list.  For example, each list can have several different keywords for entry via SMS.  We needed a way of breaking all of these metrics out by method of entry.</p>
<p>Also, the main data structure containing the stats is repeated twice within the document.  Once for the current day&#8217;s stats, and once for the totals for that subscription list up until the date in the document.  This &#8220;to_date&#8221; data structure keeps us from having to evaluate <strong>ALL</strong> of a list&#8217;s documents in order to determine how many subscribers there are on a given date.  With the &#8220;to_date&#8221; data structure, the specific day&#8217;s document is all we need.</p>
<p>We decided that this data structure was better represented as a single JSON document instead of a series of tables in MySQL.  It seemed much cleaner to have a single document per list, per day that contained all of the information for that list&#8217;s daily activity than to have it scattered about in a series of relational tables.  Choosing MongoDB meant giving up on SQL&#8217;s aggregate functions (AVG(), MAX(), MIN(), SUM(), etc), but the benefits provided by the simplicity of the data structure seemed to make up for the loss of these functions.</p>
<h4>An example summary document</h4>
<pre>
{
  "campaign_id": 1,
  "subscription_campaign_id": 2,
  "account_id": 1,
  "date": ISODate("2010-10-13T00:00:00Z"),
  "stats": {
    "sms_101": {
      "confirmed_opt_ins": 100,
      "unconfirmed_opt_ins": 15,
      "unconfirmed_opt_outs": 10,
      "unconfirmed_opt_out_reasons": { "UI": 5, "CNF": 5 },
      "confirmed_opt_outs": 20,
      "confirmed_opt_out_reasons": { "UI": 10, "CNF": 10}
    }
    "sms_102": {
      "confirmed_opt_ins": 200,
      "unconfirmed_opt_ins": 30,
      "unconfirmed_opt_outs": 20,
      "unconfirmed_opt_out_reasons": { "UI": 5, "CNF": 15 },
      "confirmed_opt_outs": 35,
      "confirmed_opt_out_reasons": { "UI": 15, "CNF": 20 },
    }
    "email": {
      "confirmed_opt_ins": 300,
      "unconfirmed_opt_ins": 35,
      "unconfirmed_opt_outs": 25,
      "unconfirmed_opt_out_reasons": { "UI": 20, "BULK": 5 },
      "confirmed_opt_outs": 30,
      "confirmed_opt_out_reasons": { "UI": 20, "BULK": 10 }
    }
  }
  "to_date": {
    "sms_101": {
      "confirmed_opt_ins": 1100,
      "unconfirmed_opt_ins": 1000,
      "unconfirmed_opt_outs": 200,
      "unconfirmed_opt_out_reasons": { "UI": 100, "CNF": 100 },
      "confirmed_opt_outs": 400,
      "confirmed_opt_out_reasons": { "UI": 300, "CNF": 100 }
    }
    "sms_102": {
      "confirmed_opt_ins": 2200,
      "unconfirmed_opt_ins": 200,
      "unconfirmed_opt_outs": 150,
      "unconfirmed_opt_out_reasons": { "UI": 100, "CNF": 50 },
      "confirmed_opt_outs": 400,
      "confirmed_opt_out_reasons": { "UI": 250, "CNF": 150 }
    }
    "email": {
      "confirmed_opt_ins": 2050,
      "unconfirmed_opt_ins": 125,
      "unconfirmed_opt_outs": 75,
      "unconfirmed_opt_out_reasons": { "UI": 75 },
      "confirmed_opt_outs": 750,
      "confirmed_opt_out_reasons": { "UI": 600, "BULK": 150 }
    }
  }
}
</pre>
<h4>A possible relational database schema</h4>
<p><a href="http://johnpwood.net/wp-content/uploads/2011/05/list_summary_tables.png"><img src="http://johnpwood.net/wp-content/uploads/2011/05/list_summary_tables.png" alt="" title="list_summary_tables" width="521" height="347" class="alignleft size-full wp-image-1229" /></a></p>
<h2>MongoDB&#8217;s Atomic Operations</h2>
<p>As I mentioned above, MongoDB&#8217;s atomic operations were key to us choosing MongoDB for this task.</p>
<p>MongoDB does not support locking or transactions like you would find in a traditional relational database.  However, it does support a <a href="http://www.mongodb.org/display/DOCS/Atomic+Operations">number of operations that are guaranteed to be atomic on a single document</a>.  If your data is designed so that all related data (or at least data that would need to be updated at the same time) is contained within a single document, then the atomic operations supported by MongoDB should be more than enough to handle the majority of use cases.</p>
<p>For this project, we made heavy use of <a href="http://www.mongodb.org/display/DOCS/Updating#Updating-%24inc">the <code>$inc</code> operation</a>.  <code>$inc</code> will atomically increment or decrement a value anywhere in the document by the specified value.  If no property exists in the document with that name, <code>$inc</code> will create it, and set its initial value to the value you wanted to increment it by.  For this project, we simply initialized the data structure holding the metrics to an empty JSON hash when the summary document is created.  The first time <code>$inc</code> is used to increment or decrement some metric, it will insert the metric into the hash, along with the proper initial value.  Subsequent calls to update the document using the $inc operator will then update that value accordingly.</p>
<p>Using the <code>$inc</code> operation also meant we didn&#8217;t have to read the document to get the current value of the field in order to increment/decrement its value.  We were simply able to increment/decrement the value by making one call to the database, keeping things nice and simple.</p>
<h4>Atomically incrementing a document&#8217;s confirmed subscriptions count</h4>
<pre class="brush:ruby">
collection = db.collection('subscription_statistics')
today = Date.today.to_time
collection.update({'campaign_id' => 1, 'date' => today},
  {"$inc" => {"stats.sms_101.confirmed_opt_ins" => 1}},
  {:safe => true})
</pre>
<h2>MapReduce</h2>
<p>MongoDB also supports MapReduce, providing you the ability to evaluate your data in ways that simply can&#8217;t be done using their standard queries.  For this project, we needed to support summing the values of specific keys across several documents (to calculate the total opt-ins over a date range, for example).  Initially, this sounded like a good fit for MapReduce.  However, MapReduce will run the specified map function against each document in the database.  The more documents your database has, the longer it will take MapReduce to run.  I hoped that since we had built an index for the fields that MapReduce was using to determine if a document should be selected, that MongoDB would utilize that index to help find the eligible documents.  Unfortunately that was not the case.</p>
<p><strong>In our case, since we are only dealing with 365 documents for a year&#8217;s worth of statistics, it was considerably faster for us to find the documents using MongoDB&#8217;s standard queries and sum the data in ruby code, than to use MapReduce to do the same.</strong>  If we were evaluating ALL of the documents in the database, then MapReduce would have been a much better option.  I understand that 10gen is hard at work on making MapReduce faster for MongoDB 2.0.  Having a strong MapReduce framework can be a powerful tool for a statistics database.  Hopefully we&#8217;ll be able to utilize it in the future.</p>
<h2>The Results</h2>
<p>The results were staggering.  On our largest list, the overview chart we display showing the current number of subscriptions per day over the last 30 days <strong>went from taking 37726ms to load to just 502ms</strong>.  And the summary report for the list, which contains a wealth of statistics for the list including opt-ins / opt-outs per day, subscriber count by opt in keyword, and a series of summary statistics, <strong>went from taking 64836ms to load to just 322ms</strong>.</p>
<p>Dramatically reducing the size of the data being evaluated had an equally dramatic effect on the amount of time it took to evaluate that data.  And, MongoDBs atomic operations and dynamic queries made this project a blast to work on.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2011/05/31/fast-queries-on-large-datasets-using-mongodb-and-summary-documents/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Optional method parameters in Ruby</title>
		<link>http://johnpwood.net/2011/04/11/optional-method-parameters-in-ruby/</link>
		<comments>http://johnpwood.net/2011/04/11/optional-method-parameters-in-ruby/#comments</comments>
		<pubDate>Mon, 11 Apr 2011 15:13:55 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=1139</guid>
		<description><![CDATA[One of the things I love about Ruby is the flexibility it provides when it comes to method parameters. It&#8217;s dead simple to provide default values for one or more [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things I love about Ruby is the flexibility it provides when it comes to method parameters.  It&#8217;s dead simple to provide default values for one or more parameters, to handle variable length argument lists, and to pass blocks of code into a method.  But perhaps my favorite is the ability to tack hash key/value pairs onto the end of a method call, and have those options combined into a Hash on the other side.</p>
<pre class="brush:ruby">
def some_method(required_1, required_2, options={})
  # Do something awesome!
end

some_method("foo", "bar")
some_method("foo", "bar", :option_1 => false, :option_2 => true)
some_method("foo",
            "bar",
            :option_1 => false,
            :option_2 => true,
            :option_3 => "something",
            :option_4 => "something else")
</pre>
<p>This may not look like much.  However, this feature alone is capable of producing some very readable code, and is used extensively in APIs throughout the Ruby ecosystem.  Consider for a moment what these APIs would look like if Ruby did not have this capability, which isn&#8217;t hard to imagine for those of us with a background in a language like Java.  You would either be forced to require that each parameter be specified:</p>
<pre class="brush:ruby">
# What is this code doing?  What do the nil values,
# or even the true and false values map to?
some_method("foo", "bar", false, nil, true, nil)
</pre>
<p>or accept a hash or a request object that contains all of the necessary parameters:</p>
<pre class="brush:ruby">
# This is much more readable, but requires that the
# options hash be created on its own line.
options = {:option_1 => true, :option_2 => false}
some_method("foo", "bar", options)
</pre>
<p>Providing optional parameters via hash key/value paris at the end of a method call produces code that is incredibly readable.  <strong>You have the names of the attributes right next to their corresponding values!</strong>  There is no ambiguity whatsoever as to which values match up with which parameters.</p>
<p>It is also very flexible.  The order of the attributes in the hash does not matter, like it does for required attributes.  And, it is very easy to add new options, or delete old ones.  </p>
<p>This approach also makes it easy to specify default values for options that were not specified when calling the method:</p>
<pre class="brush:ruby">
def some_method(required_1, required_2, options={})
  defaults = {
    :option_1 => "option 1 default",
    :option_2 => "option 2 default",
    :option_3 => "option 3 default",
    :option_4 => "option 4 default"
  }
  options = defaults.merge(options)

  # Do something awesome!
end
</pre>
<p>There are however a few minor drawbacks to this approach.  The first is documentation.  Methods that take a hash of options as a parameter do not convey any information about the valid options in the method definition alone.  And, it is possible that the method in question simply forwards the options to another method, sending you on a wild goose chase to determine the set of valid options the code supports.</p>
<pre class="brush:ruby">
# Looking for a list of valid option keys...no help here.
def some_method(required_1, required_2, options={})
  do_something_awesome_with_the_options(options)
end
</pre>
<p><strong>This is why it is so important do document your public API if you are using this approach.</strong>  Take a look at the <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html">ActiveRecord::Associations::ClassMethods documentation</a>.  This page documents, in a very clear and easy to read mannor, all of the supported options for each method.</p>
<p>It is also worth pointing out that while this approach is great for optional parameters, it is ill suited for required parameters.  Required parameters should be specified outside of the options hash, making it clear that values for the required parameters must be provided.  While it&#8217;s true that stuffing all of your parameters inside a hash means you&#8217;ll never have to look at another <code>wrong number of arguments</code> error again, it will make your code difficult to understand, and easy to misuse.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2011/04/11/optional-method-parameters-in-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CouchDB Plugins for Scout</title>
		<link>http://johnpwood.net/2011/01/12/couchdb-plugins-for-scout/</link>
		<comments>http://johnpwood.net/2011/01/12/couchdb-plugins-for-scout/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 20:09:23 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[scout]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=1035</guid>
		<description><![CDATA[Back in December I whipped up a series of CouchDB plugins for the Scout monitoring service. The plugins allow you to track all sorts of metrics for CouchDB, including (but [...]]]></description>
			<content:encoded><![CDATA[<p>
Back in December I whipped up a series of <a href="http://couchdb.apache.org/">CouchDB</a> plugins for the <a href="https://scoutapp.com/">Scout</a> monitoring service.  The plugins allow you to track all sorts of metrics for CouchDB, including (but not limited to):</p>
<ul>
<li>Mean reads / second</li>
<li>Mean writes / second</li>
<li>Mean requests / second for DELETE, GET, HEAD, POST, and PUT requests</li>
<li>Mean view requests / second</li>
<li>Mean bulk HTTP requests / second</li>
<li>Counts for various HTTP response codes</li>
</ul>
<p>In addition, there is a plugin for individual CouchDB databases and individual couchdb-lucene indexes.  The database plugin will report:</p>
<ul>
<li>Database size</li>
<li>Number of documents</li>
<li>Number of deleted documents</li>
<li>Number of update operations</li>
</ul>
<p>The couchdb-lucene plugin will report:</p>
<ul>
<li>Size of the index</li>
<li>Number of documents indexed</li>
<li>Number of deleted documents</li>
</ul>
<p>The kind folks over at Scout have just released two new, official plugins based on the ones I created.  The <a href="https://scoutapp.com/plugin_urls/441-couchdb-overall">CouchDB Overall</a> plugin combines some of the more important CouchDB metrics into a single plugin, and the <a href="https://scoutapp.com/plugin_urls/451-couchdb-database">CouchDB Database</a> plugin reports the same set of the stats as the database plugin listed above.</p>
<p>The original plugins can be found at <a href="https://github.com/signal/scout-plugins/tree/master/couchdb">https://github.com/signal/scout-plugins/tree/master/couchdb</a>.  More information can be found <a href="https://github.com/signal/scout-plugins/blob/master/couchdb/README.md">here</a>.  I hope you find them useful.</p>
<p>Thanks to Doug Barth for some help on the plugins, and Derek over at Scout for putting together the official plugins.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2011/01/12/couchdb-plugins-for-scout/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introducing Tenacity &#8211; An ORM Independent Way to Manage Inter-database Relationships</title>
		<link>http://johnpwood.net/2011/01/05/introducing-tenacity-an-orm-independent-way-to-manage-inter-database-relationships/</link>
		<comments>http://johnpwood.net/2011/01/05/introducing-tenacity-an-orm-independent-way-to-manage-inter-database-relationships/#comments</comments>
		<pubDate>Wed, 05 Jan 2011 15:45:55 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[polyglot persistence]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tenacity]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=1003</guid>
		<description><![CDATA[I&#8217;m a big believer in polyglot persistence. There are so many (very different) production ready databases available today that&#8217;s it is becoming more and more common to find applications using [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a big believer in <a href="http://www.slideshare.net/jwoodslideshare/polyglot-persistence-two-great-tastes-that-taste-great-together-4625004">polyglot persistence</a>.  There are so many (very different) production ready databases available today that&#8217;s it is becoming more and more common to find <a href="2009/09/29/using-multiple-database-models-in-a-single-application/">applications using more than one database</a>, utilizing the strengths of each.  Using the right tool for the job gives me a warm, fuzzy feeling inside.</p>
<p>However, polyglot persistence comes with its own set of drawbacks.  One of those drawbacks is the loss of foreign keys, which are very important in maintaining data integrity.  Another drawback is that Object/Relational Mapping (ORM) libraries typically focus on a specific database, or type of database.  So, writing code that manages relationships between objects backed by different databases hasn&#8217;t been nearly as easy as writing code to manage relationships between objects in the same database.</p>
<p>Tenacity&#8217;s goal is to address some of these issues.  <a href="https://github.com/jwood/tenacity">Tenacity</a> is a ruby gem that provides an ORM independent way of managing relationships between models backed by different databases.</p>
<p>Tenacity works by <a href="https://github.com/jwood/tenacity/blob/master/EXTEND.rdoc">extending</a> popular Ruby ORM libraries to respond to a set of methods that the tenacity core uses to build and manage relationships between objects.  By extending the ORM libraries to implement this interface, tenacity is able work with the objects in a generic way, without having to know what database is backing the given objects.  This approach also allows you to continue using your favorite ORM libraries.  To use tenacity, you simply need to <code>include Tenacity</code> inside your model.</p>
<p>Tenacity is heavily based on <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html">ActiveRecordâ€™s associations</a>, and aims to behave in much the same way, supporting many of the same options.</p>
<p>This initial release of tenacity supports <code>belongs_to</code>, <code>has_one</code>, and <code>has_many</code> associations, and the <a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html">ActiveRecord</a>, <a href="https://github.com/couchrest/couchrest">CouchRest</a>, and <a href="https://github.com/jnunemaker/mongomapper">MongoMapper</a> ORMs.  However, there is still <a href="https://github.com/jwood/tenacity/issues">plenty of work to be done</a>.  Feedback, <a href="https://github.com/jwood/tenacity/issues">bug reports</a>, and code contributions are always welcome.</p>
<p>Tenacity is free and open source, and can be found on GitHub at <a href="https://github.com/jwood/tenacity">https://github.com/jwood/tenacity</a>.</p>
<h2>Example</h2>
<p><script src="http://gist.github.com/754326.js"></script></p>
<h2>Download</h2>
<p><code>gem install tenacity</code></p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2011/01/05/introducing-tenacity-an-orm-independent-way-to-manage-inter-database-relationships/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The (Eventual) Return of Mobile Applications to the Web</title>
		<link>http://johnpwood.net/2010/11/22/the-eventual-return-of-mobile-applications-to-the-web/</link>
		<comments>http://johnpwood.net/2010/11/22/the-eventual-return-of-mobile-applications-to-the-web/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 14:16:53 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[application development]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[mobile web]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=969</guid>
		<description><![CDATA[I don&#8217;t think that I&#8217;m overstating things by saying that the web has changed the world. There is no doubt about it in my mind. The past 20 years or [...]]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t think that I&#8217;m overstating things by saying that the web has changed the world.  There is no doubt about it in my mind.  The past 20 years or so have been a continuous stream of innovation.  We&#8217;ve seen the web transform from a simple platform used by government agencies to share information into something whose capabilities seem limitless.  Streaming media, e-commerce, full fledged office applications, real time news from more sources than you can imagine, and much more.  It truly is amazing what we&#8217;ve been able to accomplish with a platform whose original purpose was to share static documents.</p>
<h2>The Rise of the App</h2>
<p>However, the web does have limitations.  One such limitation has long been the ability to interact with the hardware you are using to browse the web.  Over the years technologies have been developed to help with this limitation (Java, Flash, etc), but I see those technologies as extensions the web, and not part of the web itself.  Those technologies have carried their own set of drawbacks as well, such as requiring the installation of client software, performance issues, and security vulnerabilities.</p>
<p>Nowhere is this limitation more obvious then in the mobile arena.  Today&#8217;s smartphones are amazing.  You have a camera, a GPS, a MP3 player, a web browser, oh&#8230;and a phone too, all wrapped up in one device.  It&#8217;s like walking around with a tiny computer in your pocket.  But currently, the web is only able to utilize a tiny fraction of this functionality.  Its document centric design, which has been stretched, twisted, and pulled in directions that its creators never could have imagined, appears to have finally reached its limit.  </p>
<p>In addition to hardware access limitations, may web applications were not designed to be viewed on a device with such a small screen and no mouse.  It can be very difficult to view a 900 pixel wide web page on a screen that is only a couple of inches wide.  And while you can zoom in over certain areas of the page, not being able to view and interact with the page in its entirety introduces some big usability issues.  Also, many web applications rely on mouse over events to interact with the user.  Drop down menus are a perfect example of this.  There is no mouse on today&#8217;s touch screen smartphones, making these sites very difficult to navigate when viewed on a mobile device.</p>
<p><a href="http://johnpwood.net/wp-content/uploads/2010/11/apple-app-store.jpg"><img src="http://johnpwood.net/wp-content/uploads/2010/11/apple-app-store.jpg" alt="" title="apple-app-store" width="200" height="200" class="alignleft size-full wp-image-972" /></a></p>
<p>These limitations have given rise to â€œthe appâ€.  The app, a native application that runs on the smartphone itself, it not a new idea.  Smartphones have been around for quite some time, and these phones have always had native applications.  But only recently did Apple change the game by providing independent application developers with a way to easily sell and distribute their applications.  As a result, there are now hundreds of thousands of applications out there for various platforms, many of which do incredible things with the hardware on the mobile device.  Things that simply could not be done via a web application.</p>
<p>The rise of the app came on so quick and so strong that many began to ask <a href="http://ideas.blogs.nytimes.com/2010/08/18/did-the-app-kill-the-web/">if the app killed the web</a>.  This is certainly a reasonable question to ask.  A native application has access to all that the device has to offer; the camera, the GPS, and yes, even the web.  Apps are also designed to run on a mobile device.  So, the text is easy to read, the controls are easy to use, and the user experience is generally much better than a web application.</p>
<h2>Problems with Native Applications</h2>
<p>While native applications have full access the the hardware and address many usability issues that web applications have on mobile devices, they introduce a new set of problems.</p>
<p>Some platforms charge program fees that must be paid to develop applications for the particular platform, even if you plan on creating a free app, or an app you never plan on releasing.  While generally inexpensive, it is a new cost that web application developers have never had to deal with.</p>
<p>Deployment is more complicated for native applications than it is for web applications.  Even though Apple&#8217;s App Store, Google&#8217;s Android Market, and other application marketplaces have made the distribution and installation of native applications much easier, it still does not compare to the ease of deployment of a web application.  On the web, you have complete control over what you deploy, when you deploy it, and to whom you deploy it to.  This is not the case with native applications, which can be subjected to drawn out, illogical review processes before being made available to the public.  If you have a critical bug that needs fixing, or you&#8217;re trying to beat your closest competitor to market with some killer new feature, this process can be agonizing.  And, even after publishing the latest version of your application to the marketplace, there is no way to force your users to upgrade.  This could leave you supporting older, buggy versions of your application, or maintaining old services still in use by those old versions of the application.</p>
<p><a href="http://johnpwood.net/wp-content/uploads/2010/11/xcode.png"><img src="http://johnpwood.net/wp-content/uploads/2010/11/xcode.png" alt="" title="xcode" width="500" height="436" class="alignnone size-full wp-image-975" /></a></p>
<p>If you charge for your application, distribution of that application is not free, or even cheap.  Apple&#8217;s App Store, Google&#8217;s Android Market, and Palm&#8217;s App Store all take a 30% cut of the sale price of your application.  Some may argue that this is a small price to pay for distribution to such a large audience.  However, the audience is larger on the web, and distribution is piratically free.</p>
<p>The development of native applications is largely platform dependent.  Programming languages and APIs vary significantly from platform to platform, making it practically impossible to develop a single application capable of running on multiple platforms.  Cross platform development tools, such as <a href="http://www.phonegap.com/">PhoneGap</a> and <a href="http://rhomobile.com/">Rhomobile</a>, address this issue by allowing you to develop native applications using HTML, Javascript, and CSS.  However, these tools don&#8217;t address the other issues mentioned in this section.  In addition, you also run the risk of some App stores outright banning applications not built using their tools (looking at you Apple).  Though Apple has recently softened their stance on this issue, I would not rule out future restrictions.</p>
<h2>A Mobile Web App in Native App&#8217;s Clothing</h2>
<p>The sad part is, <strong>the majority of today&#8217;s apps don&#8217;t need to be native applications</strong>.  They do nothing to utilize the features exclusive to native applications.  Most of these apps simply fetch data from a web service and display it nicely to the user.  Some take advantage of the GPS, or store data locally on the device.  However, these apps could just as easily be mobile optimized web applications.</p>
<p>â€œLook and feelâ€ is often cited as a reason to develop a native application instead of a mobile optimized web application.  Though this argument certainly has its merits, there are plenty of options out there to help make a web application look and feel great on a mobile device.  A bit of mobile optimized CSS (fluid layouts, properly sizing images, etc) can go a long way in terms of making a web application look awesome on a mobile device.  And, there are projects out there, such as <a href="http://www.jqtouch.com/">jQTouch</a>, <a href="http://jquerymobile.com/">jQuery Mobile</a>, and <a href="http://www.sencha.com/products/touch/">Sencha Touch</a> that can help your web application look and feel more like a native application if that&#8217;s what you are looking for.</p>
<p><a href="http://johnpwood.net/wp-content/uploads/2010/11/hilton.jpg"><img src="http://johnpwood.net/wp-content/uploads/2010/11/hilton.jpg" alt="" title="hilton" width="400" height="258" class="alignright size-full wp-image-973" /></a></p>
<p>Web applications also have access to a few features that, just a short time ago, were only available to native applications.  The device&#8217;s location is accessible via <a href="http://www.dinnermint.org/blog/javascript/javascript-geolocation-api/">Javascript&#8217;s Geolocation API</a>, eliminating the need to build a native application solely for access to the device&#8217;s GPS.  Web applications also have access to persistent local storage on the mobile device via the <a href="http://dev.w3.org/html5/webstorage/">HTML5 Web Storage API</a>.  While the Web Storage API falls short of a being a true database (it&#8217;s more like a hash, allowing you to store key/value pairs), it can go a long way in addressing the storage needs of most applications.</p>
<p>A good comparison between mobile apps and native apps can be found <a href="http://www.webmonkey.com/2010/08/how-do-native-apps-and-web-apps-compare/">here</a>.</p>
<h2>Making the Web a Friendlier Place for Mobile Web Apps</h2>
<p>The mobile web is growing by leaps and bounds, but much work is needed in order to make the web a friendlier place for mobile web applications.  The W3C realizes this, and have started a <a href="http://www.w3.org/2009/dap/">Device APIs and Policy Working Group</a> to create a specification that will allow web applications to access device hardware and services (contacts, calendar, camera, microphone, SMS, MMS, email, etc) in a standardized way.  The specification is far from complete, and it will likely be quite some time before these APIs have been implemented by the various web browsers.  But, the mere fact this is being worked on is a great sign for the future of mobile web applications.</p>
<p>There are non-technical hurdles preventing the web from being a more mobile friendly place as well.  </p>
<p><a href="http://johnpwood.net/wp-content/uploads/2010/11/mobileOK.jpg"><img src="http://johnpwood.net/wp-content/uploads/2010/11/mobileOK.jpg" alt="" title="Mobile OK" width="200" height="186" class="alignleft size-full wp-image-974" /></a></p>
<p>First, browsing the web on a mobile device isn&#8217;t a very pleasant experience right now.  Having â€œrealâ€ web browsers on mobile devices, such as WebKit, have gone a long way in fixing this.  However, many sites are not optimized for mobile devices, making them difficult to use.  I think this prevents the majority of people from browsing the web on their mobile device like they would on their desktop or laptop computer.</p>
<p>Second, we&#8217;ve been told for years that â€œThere&#8217;s an app for thatâ€.  Personally, when I&#8217;m looking for a mobile application take care of some task, the first place I hit is the Android Market.  Having one place, where apps are broken up into categories, and searchable, makes finding the right app for my needs incredibly easy.  There is no such place for web applications.  This used to be the case for desktop applications as well, but not anymore.  The Ubuntu App Center, and now the Apple Mac Store, aim to serve the same purpose as the App Store or the Android Market, but for desktop computers instead of mobile devices.  Perhaps it won&#8217;t be long before we see a categorized, searchable index for mobile web applications as well.</p>
<h2>Conclusion</h2>
<p>Opting to build a mobile optimized web application instead of a native application is <a href="http://scobleizer.com/2009/12/16/iphone-developers-abandoning-app-model-for-html5/">not a new idea</a>.  However, the idea has been slow to catch on, due to some of the reasons I&#8217;ve outlined above.</p>
<p>Obviously, even after the Device APIs being worked on by the W3C have been implemented, there will always be a need for native applications.  Games that need hardware accelerated graphics, or apps with complex user interaction will most likely stay native applications for the foreseeable future.  But I hope that the other applications, <strong>especially</strong> the applications that are simply a front to a web service, are re-born as web applications at some point in the near future.  For these apps, it&#8217;s time to come home.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/11/22/the-eventual-return-of-mobile-applications-to-the-web/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Script for Creating and Fetching Database Backups on Heroku</title>
		<link>http://johnpwood.net/2010/11/17/script-for-creating-and-fetching-database-backups-on-heroku/</link>
		<comments>http://johnpwood.net/2010/11/17/script-for-creating-and-fetching-database-backups-on-heroku/#comments</comments>
		<pubDate>Wed, 17 Nov 2010 14:47:53 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Scripts]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=955</guid>
		<description><![CDATA[Heroku recently announced a new database backup solution, PG Backups, to replace their previous one, bundles. The basic plan allows you to store two database backups on Heroku&#8217;s servers for [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://heroku.com">Heroku</a> recently announced a new database backup solution, <a href="http://blog.heroku.com/archives/2010/11/16/pgbackups/">PG Backups</a>, to replace their previous one, bundles.  The basic plan allows you to store two database backups on Heroku&#8217;s servers for free.  Since I already have a backup solution which allows me to store any number of backups, I decided to write a script to create database backups on Heroku, download them, and back them up using my existing solution.  PG Backups is incredibly easy to use, and does all of the heavy lifting.</p>
<p>Kudos to Heroku for continuing to find ways to make their platform easier to use.</p>
<p>The script is below.  Hope you find it useful.</p>
<p><script src="http://gist.github.com/703438.js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/11/17/script-for-creating-and-fetching-database-backups-on-heroku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Slides From My Intro To CouchDB Talk</title>
		<link>http://johnpwood.net/2010/08/18/slides-from-my-intro-to-couchdb-talk/</link>
		<comments>http://johnpwood.net/2010/08/18/slides-from-my-intro-to-couchdb-talk/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 13:40:08 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[chicagodb]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[talks]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=900</guid>
		<description><![CDATA[Thanks to everybody who showed up at Monday&#8217;s ChicagoDB meeting for the great discussion on MapReduce and my talk on CouchDB. Sides from my talk can be found on Slideshare, [...]]]></description>
			<content:encoded><![CDATA[<p>Thanks to everybody who showed up at Monday&#8217;s <a href="http://chicagodb.com/">ChicagoDB</a> meeting for the great discussion on <a href="http://nosqlsummer.org/paper/google-mapreduce">MapReduce</a> and my talk on <a href="http://couchdb.apache.org/">CouchDB</a>.  Sides from my talk can be found <a href="http://www.slideshare.net/jwoodslideshare/introduction-to-couchdb-4984849">on Slideshare</a>, and the files/commands that were used for the demo can be found on <a href="http://github.com/jwood/couchdb_demo">github</a>.  As usual, please don&#8217;t hesitate to <a href="mailto:john_p_wood@yahoo.com">email me</a> with any questions or comments.</p>
<p>See everybody next month!</p>
<div style="width:425px" id="__ss_4984849"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/jwoodslideshare/introduction-to-couchdb-4984849" title="Introduction to CouchDB">Introduction to CouchDB</a></strong><object id="__sse4984849" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=chidb-couchdb-100816161336-phpapp01&#038;stripped_title=introduction-to-couchdb-4984849" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4984849" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=chidb-couchdb-100816161336-phpapp01&#038;stripped_title=introduction-to-couchdb-4984849" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/jwoodslideshare">John Wood</a>.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/08/18/slides-from-my-intro-to-couchdb-talk/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Speaking About CouchDB at Upcoming ChicagoDB Meeting</title>
		<link>http://johnpwood.net/2010/07/22/speaking-about-couchdb-at-upcoming-chicagodb-meeting/</link>
		<comments>http://johnpwood.net/2010/07/22/speaking-about-couchdb-at-upcoming-chicagodb-meeting/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 15:33:11 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=892</guid>
		<description><![CDATA[I&#8217;m going to be speaking about CouchDB at the next ChicagoDB meeting, which will be held on August 16th, 2010. I&#8217;m currently putting together some slides that will (I hope) [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to be speaking about <a href="http://couchdb.apache.org/">CouchDB</a> at the next <a href="http://chicagodb.com/">ChicagoDB</a> meeting, which will be held on August 16th, 2010.  I&#8217;m currently putting together some slides that will (I hope) provide a good introduction to CouchDB and its features.  I also plan on doing a live demo at the end, so everybody can see CouchDB in action.</p>
<p>Information about the meeting can be found <a href="http://gathers.us/events/chicagodb-august-meeting/">here</a>.  I hope to see you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/07/22/speaking-about-couchdb-at-upcoming-chicagodb-meeting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Slides From My WindyCityDB Talk On Polyglot Persistence</title>
		<link>http://johnpwood.net/2010/06/29/slides-from-my-polyglot-persistence-talk-posted/</link>
		<comments>http://johnpwood.net/2010/06/29/slides-from-my-polyglot-persistence-talk-posted/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 12:39:45 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[polyglot persistence]]></category>
		<category><![CDATA[slides]]></category>
		<category><![CDATA[windycitydb]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=872</guid>
		<description><![CDATA[The slides from my WindyCityDB talk about Polyglot Persistence have been posted to Slideshare. You can see them here, or embedded in the post below. The case for Polyglot Persistence [...]]]></description>
			<content:encoded><![CDATA[<p>The slides from my <a href="http://windycitydb.org">WindyCityDB</a> talk about Polyglot Persistence have been posted to <a href="http://www.slideshare.net">Slideshare</a>.  You can see them <a href="http://www.slideshare.net/jwoodslideshare/polyglot-persistence-two-great-tastes-that-taste-great-together-4625004">here</a>, or embedded in the post below.</p>
<p>The case for Polyglot Persistence was made throughout the day by several of the speakers.  Most people seemed to acknowledge the fact that it is very likely one database may not have all of the tools you need to get your job done.  Instead of coercing a single database to try and do things it was never designed to do, it is becoming more common for applications to use multiple databases, utilizing each for their respective strengths.  But, of course, using multiple databases in a single application comes with its own set of issues, and you should make sure there is a real need for Polyglot Persistence before making that leap.</p>
<p>Thank you very much to the <a href="http://windycitydb.org">WindyCityDB</a> organizers for putting on such a great event.  I had a great time, learned a ton, met some interesting people, and participated in some great conversations.  What more can you ask for in a tech conference?</p>
<div style="width:425px" id="__ss_4625004"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/jwoodslideshare/polyglot-persistence-two-great-tastes-that-taste-great-together-4625004" title="Polyglot Persistence - Two Great Tastes That Taste Great Together">Polyglot Persistence &#8211; Two Great Tastes That Taste Great Together</a></strong><object id="__sse4625004" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=polyglotpersistence-100626195831-phpapp02&#038;stripped_title=polyglot-persistence-two-great-tastes-that-taste-great-together-4625004" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4625004" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=polyglotpersistence-100626195831-phpapp02&#038;stripped_title=polyglot-persistence-two-great-tastes-that-taste-great-together-4625004" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/jwoodslideshare">John Wood</a>.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/06/29/slides-from-my-polyglot-persistence-talk-posted/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8220;CouchDB: A Case Study&#8221; Posts Now Availalbe As A Whitepaper From Couchio</title>
		<link>http://johnpwood.net/2010/06/22/couchio-whitepaper/</link>
		<comments>http://johnpwood.net/2010/06/22/couchio-whitepaper/#comments</comments>
		<pubDate>Tue, 22 Jun 2010 17:12:39 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[couchdb case study]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=842</guid>
		<description><![CDATA[In the spring of 2009, we were starting to run into some performance issues with the Interactive Mediums application (formerly known as TextMe). At the advice of a contractor and [...]]]></description>
			<content:encoded><![CDATA[<p>In the spring of 2009, we were starting to run into some performance issues with the <a href="http://www.interactivemediums.com">Interactive Mediums</a> application (formerly known as TextMe).  At the advice of a contractor and friend, we began looking into <a href="http://couchdb.apache.org">CouchDB</a> as a potential solution to these problems.  As with most young projects, documentation was a bit scarce.  The official CouchDB website and the <a href="http://wiki.apache.org/couchdb/">CouchDB wiki</a> had some good information, but after reading what was available we still had many questions.  Should I create a new database for each type of document I have?  How many views should I store in a design document?  What are the advantages and disadvantages of views sharing a design document?  How do I even begin migrating my relational database backed application to CouchDB?</p>
<p>So I started taking notes, documenting everything I could regarding what we learned about CouchDB, the design decisions we made for our application (and their respective trade-offs), and the migration of our application code to use CouchDB.  I organized those notes, and posted them on this blog as <a href="/2009/06/15/couchdb-a-case-study/">a case study</a>, hoping it would help others looking into CouchDB.</p>
<p>I received a lot of positive feedback from the posts, making me feel like I had in fact filled that need, at least to some degree.  Even better, earlier this year I was contacted by <a href="http://www.couch.io/">Couchio</a> about combining the series of posts into a white paper that would be posted on their site.  This would put the case study in front of a larger audience, potentially helping even more people.  I was thrilled.</p>
<p>Today, that white paper was released as the &#8220;Epic Interactive Mediums Whitepaper&#8221; (love the <em>Epic</em> :)).  You can get it <a href="http://johnpwood.net/wp-content/uploads/2010/06/Migrating-to-CouchDB.pdf">here</a>.  Many thanks to the kind folks over at Couchio for putting this together.  I hope people will find it helpful.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/06/22/couchio-whitepaper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting &#8216;rake test&#8217; Running with Rails 3 and MongoDB</title>
		<link>http://johnpwood.net/2010/04/13/getting-rake-test-running-with-rails-3-and-mongodb/</link>
		<comments>http://johnpwood.net/2010/04/13/getting-rake-test-running-with-rails-3-and-mongodb/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 14:29:25 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[addressbook]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mongomapper]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rails3]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=792</guid>
		<description><![CDATA[I&#8217;ve recently started a re-write of my Addressbook application. Addressbook was my first Rails application, as well as my first full fledged Ruby application&#8230;and boy does it show! So, trust [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently started a re-write of my <a href="http://github.com/jwood/addressbook">Addressbook</a> application.  Addressbook was my first Rails application, as well as my first full fledged Ruby application&#8230;and boy does it show!  So, trust me, the re-write is justified :)</p>
<p>I saw the re-write as a good opportunity to get more familiar with Rails 3 and <a href="http://www.mongodb.org">MongoDB</a>.  After getting Rails 3 setup to use MongoDB via <a href="http://github.com/jnunemaker/mongomapper">MongoMapper</a> (<a href="http://gist.github.com/181842">Ben Scofield&#8217;s setup script</a> gets you most of the way there), I quickly realized that the tests would not run.</p>
<pre>
jwood-mbp:addressbook jwood$ rake test
(in /Users/jwood/dev/personal/addressbook)
Errors running test:units, test:functionals, test:integration!

jwood-mbp:addressbook jwood$ rake test:units
(in /Users/jwood/dev/personal/addressbook)
rake aborted!
Don't know how to build task 'db:test:prepare'
</pre>
<p><br/><br />
Some Googling revealed <a href="http://www.engineyard.com/blog/2010/rails-3-beta-is-out-a-retrospective/">this post</a> by Yehuda Katz, in which he says:</p>
<blockquote><p>
Additionally, users can completely remove the ActiveRecord gem, and be rid of the generators, rake tasks and other peripheral elements. An example: if DataMapper implements a db:test:prepare rake task, a Rails developer can replace ActiveRecord with DataMapper, and the test:units rake task will use DataMapper&#8217;s new tasks.
</p></blockquote>
<p>We&#8217;re not using DataMapper here, but the same thing applies to MongoMapper.  So, all that is needed is to implement a <code>db:test:prepare</code> task, which I did in <code>lib/tasks/mongo.rake</code></p>
<pre class="brush:ruby">
namespace :db do
  namespace :test do
    task :prepare do
      # Stub out for MongoDB
    end
  end
end
</pre>
<p>As of right now, the task does nothing.  I may end up adding some functionality to it as I work on the project.  We&#8217;ll see.</p>
<p>Running the tests again, I can see that was all that was needed to get going.</p>
<pre>
jwood-mbp:addressbook jwood$ rake test:units
(in /Users/jwood/dev/personal/addressbook)
Loaded suite /Users/jwood/.rvm/gems/ruby-1.9.1-p378@rails3/gems/
rake-0.8.7/lib/rake/rake_test_loader
Started
...
Finished in 0.062854 seconds.

3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
</pre>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/04/13/getting-rake-test-running-with-rails-3-and-mongodb/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Standup Timer 1.2 Released</title>
		<link>http://johnpwood.net/2010/03/10/standup-timer/</link>
		<comments>http://johnpwood.net/2010/03/10/standup-timer/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 14:30:32 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[Standup Timer]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=786</guid>
		<description><![CDATA[Standup Timer version 1.2 has just been released. Per popular demand (2 requests :)), I have added support for meetings of any length, with any number of participants. Prior to [...]]]></description>
			<content:encoded><![CDATA[<p>Standup Timer version 1.2 has just been released.  Per popular demand (2 requests :)), I have added support for meetings of any length, with any number of participants.  Prior to this release, Standup Timer restricted you to meetings 5, 10, 15 or 20 minutes long, and a maximum of 20 participants.  These restrictions are still enabled by default, but can be disabled via the application&#8217;s settings.</p>
<p>Standup Timer is free and open source. The source code can be found at <a href="http://github.com/jwood/standup-timer">http://github.com/jwood/standup-timer</a>. Standup Timer can be found in the Android Market.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/03/10/standup-timer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Thoughts on Android Development</title>
		<link>http://johnpwood.net/2010/02/23/thoughts-on-android-development/</link>
		<comments>http://johnpwood.net/2010/02/23/thoughts-on-android-development/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 14:25:15 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Standup Timer]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=700</guid>
		<description><![CDATA[Now that Standup Timer has a few releases under its belt, I thought it would be a good time to reflect on my experience with the Android SDK, and Android [...]]]></description>
			<content:encoded><![CDATA[<p>Now that <a href="/standup-timer">Standup Timer</a> has a few releases under its belt, I thought it would be a good time to reflect on my experience with the Android SDK, and Android development in general.  But before I begin, I should mention a few points about my background, to help you understand my perspective.</p>
<p>First, Standup Timer was my first mobile app.  Aside from a <strong>very</strong> small amount of time I&#8217;ve spent playing around with the Blackberry development kit (really too small to even mention), I have had no prior experience developing software for a mobile device.  My background is largely web development and distributed applications development.  Second, I have been doing Java development for quite some time, so I am very comfortable working in Java.  Third, if you&#8217;re not familiar with Standup Timer, it is a very simple application.  It only interacts with a few components of the Android platform, and only consists of a few screens.  No GPS, no web, no multi-touch, etc.  So, my tour of the Android SDK was far from complete.</p>
<h2>Dealing with multiple devices</h2>
<h3>Supporting multiple screen sizes</h3>
<p>The topic of supporting multiple screen sizes has been a popular one, especially when comparing Android development to iPhone development.  <strong>Supporting multiple screen sizes in your application does add a little complexity to the development process, but for my app (and I&#8217;d imagine most apps), it is very manageable.</strong></p>
<p><img src="http://johnpwood.net/wp-content/uploads/2010/02/screen_sizes-300x154.png" alt="" title="screen_sizes" width="300" height="154" style="float: left; margin: 0px 25px 25px 0px;" /> This issue did not take Google by surprise.  They knew that if Android was to be successful, it would need support devices with a wide range of physical characteristics, including screen size.  So, from the beginning, they made it possible for applications to support multiple screen sizes with little effort.  The Android platform contains many features to help with this, including the ability to pre-scale images for phones with different resolutions, allowing you to specify your screen component sizes in density independent pixels (dips), and allowing you to easily center and stretch your components to fill the screen.  These features, along with a set of best practices for supporting multiple screen sizes, are documented very well at <a href="http://developer.android.com/guide/practices/screens_support.html">http://developer.android.com/guide/practices/screens_support.html</a>.</p>
<p>For applications that do not use the standard Android view components, or do custom graphics, it may be a different story.  I have read blog posts from some Android game developers saying it is a larger issue, and some who say it is not.  So, I&#8217;m not sure.  However, for the vast majority of applications, the standard view components work just fine, making supporting multiple screen sizes a very manageable issue.</p>
<p>One thing that did bite me regarding multiple screen sizes is the fact that views will not scroll by default if they happen to flow off the screen.  You need to anticipate this, and wrap any views that may flow off the screen with a <code>ScrollView</code> to enable scrolling behavior.</p>
<h3>Supporting multiple devices</h3>
<p>To me, this issue is much larger than the multiple screen size issue.  Android is an open source project, which gives anybody the ability to modify the code however they wish.  Google prevents carriers and cell phone manufacturers from abusing this by holding back a few key applications from the open source release, including the Android Market application.  Without the Android Market application, phones would not have access to the 20,000 apps currently available for the Android platform.</p>
<p><strong>However, phone manufacturers do tweak the platform to work for their specific hardware.</strong>  Android 2.1 on one device is not necessarily the same as Android 2.1 on another device.  For an example of this, <a href="http://www.engadget.com/2010/02/08/motorola-droids-next-update-to-be-android-2-1-includes-multito/">compare 2.1 on the Motorola DROID with 2.1 on the Nexus One</a>.  <strong>These seemingly minor modifications can be very troublesome for application developers.</strong>  The web has been <a href="http://www.dailyfinance.com/story/too-many-androids-variety-of-phone-models-may-chase-app-makers/19265188/">flooded</a> <a href="http://www.switched.com/2009/11/20/android-explosion-poses-a-problem-for-developers/">with</a> <a href="http://www.wired.com/gadgetlab/2009/11/android-fragmentation/">reports</a> of developers growing frustrated with the complexity matrix of Android versions and the exploding number of phones running them, all potentially containing their own tweaks to the platform.  Browsing through the change logs of applications I have installed on my Motorola DROID, I can see that several apps have made changes to fix issues on specific devices.</p>
<p>This issue is forcing developers to not only test on every device they plan on supporting, but also to write device specific code to work around any known issues for a device.  As Android continues to grow, this level of support will be unsustainable.  Developing for a common platform should mean that your application will run fine on any device running that platform.  But, because of these device specific tweaks, this is quickly turning out not to be the case for Android.  I worry that if Google doesn&#8217;t find some way to control this, developers will continue to abandon the platform.</p>
<p>I have even run into what appear to be device related issues with Standup Timer, which is miniscule compared to the size and complexity some of the other apps available in the Android Market.  Standup Timer uses an Android API that prevents the user&#8217;s screen from blacking out while a timer is in progress, letting you always see how much time is remaining for a meeting.  Just the other day somebody left a comment in the Market indicating that this was not working on their device.  So far, all of the other reviews have been positive, leading me to believe that this could be an issue with that user&#8217;s particular device.  The commentator didn&#8217;t provide any information about the device they were using, or how they could be contacted.  So, I&#8217;m not sure if I&#8217;ll ever be able to track down this issue.  Even if I knew the device experiencing the issue, I&#8217;m not sure I would be able to help.  Unless you have access the device in question, reproducing these issues is practically impossible.  The Android simulator tool is great, but you cannot create a simulator for a specific Android device, running that device&#8217;s flavor of Android.  You can only create simulators running the â€œgenericâ€ version of an Android release.</p>
<h2>Development</h2>
<h3>Application life cycle</h3>
<p><img src="http://johnpwood.net/wp-content/uploads/2010/02/lifecycle-226x300.png" alt="" title="lifecycle" width="226" height="300" style="float:right; margin: 0px 0px 25px 25px;" />The Android platform primarily communicates with an application through a series of life cycle events.  The platform will let the application know when an activity (a screen) has been created, paused (lost focus), resumed (regained focus), etc.  <strong>The life cycle events are easy to understand, and are specific enough so that I never need to examine the state of my application or the platform within one of these callbacks.</strong>  The fact that a specific life cycle method was called tells you what state your application is in.</p>
<p>My largest complaint about how the platform manages an application is how it destroys and re-creates the activity (the object that backs the screen) when the phone rotates from portrait mode to landscape mode, or visa versa.  It seems to me that this would best be handled by making the appropriate life cycle callbacks to the same activity instance, giving it a chance to redraw the screen.  Instead, you are forced to save all of your activity&#8217;s state, and then reload it when the new activity instance takes over.  Forgetting to save the state of a particular variable means that value will be lost when the phone is rotated.  This was the source of several bugs when writing Standup Timer.</p>
<h3>Android APIs</h3>
<p><strong>I have no major issues with the Android APIs.  They seem complete (for what I needed), and most importantly, behaved as expected.</strong>  The database API seems a bit archaic, especially in today&#8217;s age of sophisticated O/R mapping tools.  But, at least I didn&#8217;t have to catch <code>SQLException</code> after each operation, like the JDBC API.</p>
<p>However, the lack of decent documentation for some of the APIs is a problem.  There were a few instances where I was forced into using trial and error to determine the purpose of a method parameter.  I feel this level of unclarity is unacceptable for a public API.</p>
<h3>UI Creation</h3>
<p>The Android SDK offers developers two methods for creating UI screens: programatically using Java code or declaratively using XML.  I did not attempt the programatic approach, as it brought back too many nightmares of building UIs for Java applets.  <strong>The XML approach to creating screen layouts, which is the recommended approach, is very straight forward.</strong>  Java developers, especially those working in the â€œenterpriseâ€, have grown to hate XML over the past few years, due to its verbosity and proliferation.  But, I think Android&#8217;s use of it is very tasteful.  At no point did I consider myself to be in XML-hell.  Looking back on the final XML that declares my user interface, it doesn&#8217;t seem overly verbose or complicated.</p>
<p>I did however struggle at times to figure out how to get the UI to look exactly the way I wanted it.  Again, this seems to be the result of poor documentation of the XML elements and their corresponding attributes.  Some more complex examples in the sample code included in the SDK would have also helped.</p>
<p>If you keep your screens simple, and don&#8217;t display too much information on any given screen, then you shouldn&#8217;t have much trouble dealing with how that screen looks in portrait or landscape mode.  Screens with a list of items, for example, will usually look just fine when viewed in either portrait or landscape mode.  When in landscape mode, the user will just see a little more blank space in the list.  For more complicated screens, the Android platform allows you to specify an alternate UI layout for landscape mode.  This allows you to completely restructure the elements on a screen to deal with the the wider, shorter screen size without affecting how the screen looks in portrait mode.  Given how I struggled to get the views to look exactly the way I wanted, I tried my best to avoid the need to specify an alternate layout file for landscape views.  Only two of the screens in Standup Timer actually needed a landscape specific layout file.</p>
<h3>adb</h3>
<p>The Android Debug Bridge (adb) is a nifty little tool that allows you to interact with an Android device or simulator from the command line.  You can install/uninstall applications, interact with files on the device, or run a shell on the device.  It also provides a series of commands that allow you to more easily create scripts to run on the device.  Not only is this tool useful by itself, but it also enables the creation of sophisticated tools for Android development.  <strong>Learning how to use adb is a wise investment of your time.</strong></p>
<h3>The Eclipse plugin</h3>
<p>The Eclipse plugin for Android development is great.  It provides tight integration between Eclipse and the Android SDK.  Code completion is available for the Android APIs as well as the different types of XML files used by the Android platform.  It has great support for Android resource files.  You can easily start your application on a simulator with the click of a button, and running your tests is a breeze.  <strong>I would not attempt to write an Android application without this plugin, or a similar plugin for a different IDE.</strong></p>
<p><img src="http://johnpwood.net/wp-content/uploads/2010/02/eclipse.png" alt="" title="eclipse" width="125" height="125" style="float:left; margin: 0px 25px 25px 0px;" />However, I did run into a few issues regarding how Eclipse interacts with the Android simulators.  On more than a few occasions, when starting the application or running the tests, the Eclipse plugin started a simulator running a version of the Android platform that did not match my project settings (although, I have not completely ruled out user error here :) ).  Also, the Eclipse plugin seems to have a few bugs around interacting with multiple simulators.  adb allows you to specify the target device or simulator when issuing a command, which is useful when you have more than one simulator running at a time (which is almost always the case given the current state of the Android platform).  However, the Eclipse plugin doesn&#8217;t always utilize this capability.  Sometimes it will detect multiple simulators running, and ask you which one you&#8217;d like to target.  Other times it will not.  In addition to the simulator interaction issues, there are a few areas that could benefit from a bit of polish.  The UI builders, for example, are difficult to work with.  It became obvious very quickly that I would be better hand coding the XML for the UI than attempting to use the builders.</p>
<h2>Testing</h2>
<h3>Simulators are awesome</h3>
<p><strong>The Android simulators are awesome.</strong>  Once you have the proper versions of the SDK installed, it is trivial to create simulators with different screen sizes, different amounts of available storage, running different versions of the Android platform.  And, as previously mentioned, adb is great for interacting with the simulators.  While not perfect (you should always test your app on a real device before publishing it), they are pretty darn close.</p>
<p>The only thing missing, and I&#8217;m not sure how feasible this is, is the ability to create a simulator for a specific device.  For example, if I know that my app is crashing on the Nexus One for some reason, I&#8217;d love to be able to create a Nexus One simulator, so I can find and fix the issue.  Currently, debugging and fixing device specific issues is not possible without access to the device in question.  I know some large mobile shops purchase the devices they plan on supporting, for testing purposes.  And, services like <a href="http://www.deviceanywhere.com/">Device Anywhere</a> allow you virtual access to a physical device, which would satisfy this need.  But these options, especially the first one, are expensive.  A developer trying to fix a device specific issue in their free, non ad subsidized application will not have the resources for either of these options.</p>
<h3>Automated (unit and functional) Testing</h3>
<p><strong>Automated testing on the Android platform is PAINFUL.</strong>  It&#8217;s hard to decide where to even begin.  First off, the tests provided with the sample applications in the SDK are very bare bones.  Most of them simply assert that an activity has been created, and that&#8217;s it.  If there was sufficient documentation describing how to write tests for you application, this wouldn&#8217;t be that big of a deal.  But, there isn&#8217;t.  Luckily, guys like <a href="http://dtmilano.blogspot.com/">Diego Torres Milano</a> are writing blog posts and giving presentations in an attempt to fill this gaping hole in documentation.  The <a href="http://www.slideshare.net/dtmilano/testing-on-android">slides from Diego&#8217;s presentation at Droidcon 2009</a> are a great place to start.  <strong>Standup Timer, which is <a href="http://github.com/jwood/standup-timer">open source</a>, also has a complete set of unit and functional tests for you to check out if you so desire.</strong></p>
<p>Another pain point regarding automated tests for Android applications is that <strong>the tests cannot be run inside a standard Java Virtual Machine.</strong>  The implementation of the APIs in the android.jar file provided with the SDK simply throw exceptions.  That jar file is only meant for building your application, not running it.  So, all tests must be run on the device (or in a simulator).  This dramatically slows down the execution of the tests.  One <a href="https://sites.google.com/site/androiddevtesting/">alternative</a> proposed by a non-Android group inside of Google is to mock out all of the Android components using a mocking library, enabling the execution of the tests in a standard virtual machine.  Although this would speed up the test execution, it comes with its own drawbacks.  Mainly, you end up having to mock out a <strong>TON</strong> of stuff.  I think that mocking out too many components significantly reduces the value of your tests.  If you mock out everything, what are you really testing?</p>
<p>The SDK contains a few base classes that you can extend for certain types of tests.  In particular, the SDK provides support for functional tests (the testing of a particular activity, or screen) and unit tests (the testing of some underlying support code).  Writing unit tests is pretty straight forward.  With a little bit of investigation and some trial and error, I was able to create a set of tests for my database layer, which will execute against a test version of the application&#8217;s database.</p>
<p><strong>Functional tests were much more problematic.  In addition to executing much slower than unit tests, they are also more difficult to write.</strong>  For functional tests, you write code to perform the operations a user would be performing on their phone (entering text, pressing buttons, etc).  The problem is that it is not very straight forward to perform these operations via code.  It took me quite some time to figure out how to simply enter some text in a text area and press a button via code.  Even when I thought I had functional testing figured out, there was still a use case I was unable to write a test for.  Most of the issues revolve around gaining access to the components you wish to interact with.  For a simple text box or button, it is very easy.  You can simply fetch the view by its id, the same way you do in your application.  However, once you start nesting components, it becomes much more complicated.  I tried several different ways to invoke the context menu (the long press menu) of a list item, inside of a list, which is inside of a tab.  None of them worked.</p>
<p><strong>Instead of writing functional tests for activities, I found it much easier to test activities using the <code>ActivityUnitTestCase</code> class with a mocked out instance of the activity.</strong>  Test classes that extend <code>ActivityUnitTestCase</code> don&#8217;t have as much as access to the platform as functional tests.  Several API methods will throw exceptions if called from within a <code>ActivityUnitTestCase</code>, and other API methods simply do nothing.  However, this can be addressed with some simple tools that should be in every developers toolbox: mocking and stubbing.  It is trivial to contain a method call that would throw an exception during testing within a method of its own.  This method can then be overridden by a mock implementation of the activity.  The mock can then optionally set a flag when the method is called, so the test can verify that some action was performed.  One place I do this is where the activity under test tries to start another activity.  Calling <code>startActivity</code> from within a <code>ActivityUnitTestCase</code> does nothing.  So, I placed the call to <code>startActivity</code> by itself in a protected method, overrode that method in the mock activity class, set a flag in the mock method implementation, and checked to see if that flag was set in the test case to verify that the activity was started.</p>
<h2>Deployment</h2>
<h3>Publishing to the Android Market</h3>
<p><strong>Publishing an application to the Android market could not be any easier.  The process is very well documented on the Android developers website, and the Eclipse plugin makes creating and signing an installation package a point and click operation.</strong></p>
<p><img src="http://johnpwood.net/wp-content/uploads/2010/02/android_market.jpg" alt="" title="android_market" width="125" height="127" style="float:right; margin: 0px 0px 25px 25px;" />A fee of $25 is required to create a Android Developers account.  This account gives you the ability to upload your application to the Android Market using the Android Developers website.  Once published, the application can immediately be found in the Android Market.  There is no approval process.  Updating your application is just as easy.  Simply upload the new version of your application, and it is available in the Android Market immediately. </p>
<p>It should be noted that there is no fee to install the application on your phone.</p>
<h2>Summary</h2>
<p>Android is a great platform.  It is feature rich, and developer friendly.  The devices that run it are powerful and easy to use.  I also love the fact that it is built on open source technology, and that Google, for the most part, has continued this tradition of openness.  </p>
<p>But, the platform is not without problems.  Most of my complaints here are minor, and are very addressable.  Android is still a young platform, so there is plenty of room to improve.  What worries me most about the future of the Android platform is the complexity matrix I talk about in the <strong>Supporting Multiple Devices</strong> section.  </p>
<p>Android was created to be a common platform for mobile application development.  A platform where application developers could write a single application capable of running on numerous devices.  However, this dream is at risk of becoming just that, a dream.  Unless Google can find a way to minimize the impact of device specific issues, it risks losing more and more Android developers.  Last year it was already known that 2010 was going to be a big year for Android.  With several new devices slated to hit the market, industry analysts are expecting its market share to jump considerably.  However, if each new device that hits the market brings with it its own set of device specific quirks, this could also cause the Android development community to quickly erode.  Applications are a very large part of the mobile experience today, and they will continue to be in the future.  But, without a development community, there will be no applications.</p>
<p>I really hope Google finds a way to address this very serious issue.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/02/23/thoughts-on-android-development/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Standup Timer 1.1 Released</title>
		<link>http://johnpwood.net/2010/02/08/standup-timer-1-1-released/</link>
		<comments>http://johnpwood.net/2010/02/08/standup-timer-1-1-released/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 14:47:10 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Standup Timer]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=686</guid>
		<description><![CDATA[Version 1.1 of Standup Timer has just been released. This new version stores statistics for your stand-up meetings on a per-team basis. Simply create one or more teams using the [...]]]></description>
			<content:encoded><![CDATA[<p>Version 1.1 of Standup Timer has just been released.  This new version stores statistics for your stand-up meetings on a per-team basis.  Simply create one or more teams using the new <strong>Teams</strong> menu option, then specify the team holding the meeting when starting the timer.  To view statistics for a given team, use the <strong>Teams</strong> menu option to pull up the list of teams, and select the team you would like to see statistics for.  The <strong>Stats</strong> tab will display the average statistics for that team across all of its meetings.  For a list of the meetings that team has held, click on the <strong>Meetings</strong> tab.  Finally, to see statistics for a specific meeting, simply select the meeting from the list of meetings.</p>
<p>Standup Timer is free and open source.  The source code can be found at <a href="http://github.com/jwood/standup-timer">http://github.com/jwood/standup-timer</a>.  Standup Timer can be found in the Android Market.</p>

<div class="ngg-galleryoverview" id="ngg-gallery-5-686">

	<!-- Slideshow link -->
	<div class="slideshowlink">
		<a class="slideshowlink" href="http://johnpwood.net/2010/02/08/standup-timer-1-1-released/?show=slide">
			[Show as slideshow]		</a>
	</div>

	<!-- Piclense link -->
	<div class="piclenselink">
		<a class="piclenselink" href="javascript:PicLensLite.start({feedUrl:'http://johnpwood.net/wp-content/plugins/nextgen-gallery/xml/media-rss.php?gid=5&amp;mode=gallery'});">
			[View with PicLens]		</a>
	</div>
	
	<!-- Thumbnails -->
		
	<div id="ngg-image-62" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/main.png" title=" " class="shutterset_set_5" >
								<img title="standup_timer_1.1_1" alt="standup_timer_1.1_1" src="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/thumbs/thumbs_main.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-60" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/menu.png" title=" " class="shutterset_set_5" >
								<img title="standup_timer_1.1_2" alt="standup_timer_1.1_2" src="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/thumbs/thumbs_menu.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-61" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/stats.png" title=" " class="shutterset_set_5" >
								<img title="standup_timer_1.1_3" alt="standup_timer_1.1_3" src="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/thumbs/thumbs_stats.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-59" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/meetings.png" title=" " class="shutterset_set_5" >
								<img title="standup_timer_1.1_4" alt="standup_timer_1.1_4" src="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/thumbs/thumbs_meetings.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-58" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/meeting_stats.png" title=" " class="shutterset_set_5" >
								<img title="standup_timer_1.1_5" alt="standup_timer_1.1_5" src="http://johnpwood.net/wp-content/gallery/standup-timer-1-1/thumbs/thumbs_meeting_stats.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 	 	
	<!-- Pagination -->
 	<div class='ngg-clear'></div>
 	
</div>


]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/02/08/standup-timer-1-1-released/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Know Thy Customer &#8211; Why Developers Should Do Customer Support</title>
		<link>http://johnpwood.net/2010/01/28/know-thy-customer-why-developers-should-do-customer-support/</link>
		<comments>http://johnpwood.net/2010/01/28/know-thy-customer-why-developers-should-do-customer-support/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 14:32:46 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[support]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=656</guid>
		<description><![CDATA[A couple of years ago I bought a new printer for the house; a nice 3-in-one printer/fax/copier. I always research the electronics I purchase, and this particular model had received [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of years ago I bought a new printer for the house; a nice 3-in-one printer/fax/copier.  I always research the electronics I purchase, and this particular model had received many very positive reviews.  So, you can bet I was surprised, and a little pissed off, when the printer started acting up just a few short months after I purchased it.  I tried like hell to figure out the issue, hoping my efforts would save me from a dreaded call to the manufacturer&#8217;s customer support hot line.  No such luck.  After a few hours of troubleshooting, I looked up the support number in the back of the users guide, dialed it, and prepared for the worst.</p>
<p><a href="http://johnpwood.net/wp-content/uploads/2010/01/support.gif"><img src="http://johnpwood.net/wp-content/uploads/2010/01/support-300x282.gif" alt="" title="support" width="300" height="282" class="alignright size-medium wp-image-678" /></a></p>
<p>We&#8217;ve all been there.  Unfamiliar with the product, we are often unable to explain in detail what is going on, especially over the phone.  And usually on the other end of the phone is an under paid customer support representative who simply reads from a script given to him by his manager.  Often these representatives know very little about the product they are supporting.  And, good luck if you happen to have a question that doesn&#8217;t appear on the script.</p>
<p>What happened next I will never forget.  On the other end of the line appeared this friendly, knowledgeable technician.  I described the problem I was having to him.  He listened patiently, and asked a couple of targeted questions to help narrow down the issue.  In no time at all, he knew exactly what was going on, and exactly how to fix it.  Step by step, he clearly instructed me on what needed to be done to get my printer back online.  Before you knew it, I was back in business. <strong> That technician, that single person, turned my experience around 180 degrees.  I was once again a satisfied customer.  Hell, I was more than satisfied.</strong></p>
<p><strong>You cannot underestimate the value of awesome customer support.</strong>  I will gladly pay more for a product or service if I know that it will come with great support, as I know it will save me from headaches and grief down the road.</p>
<p>Typically, developers don&#8217;t serve on the front lines of customer support.  However, not directly interacting with and supporting the users of your product means you are missing out on a great opportunity.  An opportunity to build customer loyalty, an opportunity to understand how a customer is using your product or service, or simply an opportunity to help somebody.</p>
<p><strong>I think developers should spend at least a few weeks a year directly supporting the users of their product.</strong>  There are several reasons why.</p>
<h3>You will learn how people use your product</h3>
<p>You think you know how people are using your product?  Think again.  You think that user interface you designed makes perfect sense?  Maybe it does to you and your co-workers, but odds are it is not as clear to your customers.  When on customer support, you&#8217;ll see first hand how customers are using your product.  <strong>If you find that your customers are fumbling around your product, thinking they are doing one thing but actually doing another, it&#8217;s a clear indication that your product isn&#8217;t as intuitive as it should be.</strong>  Don&#8217;t write off these issues as &#8220;user errors&#8221;.  Instead, get some feedback from your customer, and figure out how to make your product easier to use.</p>
<h3>It will become obvious what features are missing, what needs to be improved, or what needs to be taken out</h3>
<p><strong>Your sales team, marketing team, and product team may have some great ideas regarding what direction to take your product.  But, there is nothing quite like hearing it straight from the customer.</strong>  This doesn&#8217;t mean that you should run out and implement every feature, and make every change requested by a customer.  But, if you start to hear similar feedback while on support, it may be an indication of a legitimate need.  Take note of it!  Or, better yet, just do it!</p>
<h3>Developers can fix problems&#8230;fast</h3>
<p>Developers are in a great position to fix problems, fast.  They usually know the product more intimately than anybody else on the team, have easy access to the code, and sometimes have the ability to release a patch.  <strong>This gives developers the unique ability to provide amazing customer support.</strong>  There have been times where I&#8217;ve fixed an issue while still on the phone with a customer, or shortly thereafter.  Think about how you would feel if all of your problems were solved this quickly.</p>
<h3>Summary</h3>
<p><strong>Happy customers become loyal customers.  And, providing awesome customer support is one sure way to keep your customers happy.</strong>  Providing customer support can be very time consuming, sometimes consuming the majority of a developer&#8217;s time (which is why I think a few weeks a year is enough).  However, this should be thought of not as an expense, but an investment.  An investment in the customer <strong>and</strong> the developer.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2010/01/28/know-thy-customer-why-developers-should-do-customer-support/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>My First Android App &#8211; Standup Timer</title>
		<link>http://johnpwood.net/2009/12/04/my-first-android-app-standup-timer/</link>
		<comments>http://johnpwood.net/2009/12/04/my-first-android-app-standup-timer/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 14:32:42 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Standup Timer]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=629</guid>
		<description><![CDATA[Putting my brand new Motorola DROID to work, I just completed my first Android application, which I&#8217;m calling Standup Timer. Standup Timer is a very simple application that helps keep [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://johnpwood.net/wp-content/uploads/2009/11/icon-241x300.png" alt="icon" title="icon" width="241" height="300" style="float:left; margin:0px 25px 25px 0px;" />Putting my brand new Motorola DROID to work, I just completed my first Android application, which I&#8217;m calling Standup Timer.</p>
<p>Standup Timer is a very simple application that helps keep your <a href="http://en.wikipedia.org/wiki/Stand-up_meeting">stand-up meetings</a> focused, and on track.  I&#8217;ve been participating in stand-up meetings of one form or another for a few years now.  One thing that is constantly an issue with stand-up meetings is that they often run longer than they are supposed to.  Instead of simply stating their status and moving on, participants will often start to ramble, or engage in conversations with other members of the team.  Those who practice any form of the Agile software development methodology know that the value of stand-up meetings drops considerably if the meeting is constantly allowed to overflow its time constraints.</p>
<p>So, I created an app for that :)  Standup Timer helps to keep your stand-up meetings on track by allotting each participant an equal share of time, and letting participants know when they are about to exceed, or have exceeded their time.  The notification comes in the form of a bell ring for the warning, and an air horn when the time has run out.  If any time is left after all participants have presented their status, then Standup Timer will keep the clock ticking, so the remaining meeting time can be used for an open discussion.</p>
<p>Standup Timer is easy to use.  Simply provide the number of participants in the meeting, the length of the meeting, and press <strong>Start</strong> to start the timer.  On the timer screen, press <strong>Next</strong> when a participant is finished presenting their status to reset the timer for the next participant.  When the meeting is over, press <strong>Finished</strong>.  Standup Timer will remember the number of participants and meeting length from the last time you used it.  It also allows you to enable/disable sounds, and to specify when (how many seconds left in their share of time) to warn participants that they are about to exceed their share of time.</p>
<p><strong>Standup Timer is free and open source.</strong>  You can find the application in the Android Market, and the source code on GitHub at <a href="http://github.com/jwood/standup-timer">http://github.com/jwood/standup-timer</a>.</p>

<div class="ngg-galleryoverview" id="ngg-gallery-4-629">

	<!-- Slideshow link -->
	<div class="slideshowlink">
		<a class="slideshowlink" href="http://johnpwood.net/2009/12/04/my-first-android-app-standup-timer/?show=slide">
			[Show as slideshow]		</a>
	</div>

	<!-- Piclense link -->
	<div class="piclenselink">
		<a class="piclenselink" href="javascript:PicLensLite.start({feedUrl:'http://johnpwood.net/wp-content/plugins/nextgen-gallery/xml/media-rss.php?gid=4&amp;mode=gallery'});">
			[View with PicLens]		</a>
	</div>
	
	<!-- Thumbnails -->
		
	<div id="ngg-image-63" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/main.png" title=" " class="shutterset_set_4" >
								<img title="image_01" alt="image_01" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_main.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-56" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/timer.png" title=" " class="shutterset_set_4" >
								<img title="image_02" alt="image_02" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_timer.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-57" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/warning.png" title=" " class="shutterset_set_4" >
								<img title="image_03" alt="image_03" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_warning.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-52" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/individual_over.png" title=" " class="shutterset_set_4" >
								<img title="image_04" alt="image_04" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_individual_over.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-53" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/individuals_complete.png" title=" " class="shutterset_set_4" >
								<img title="image_05" alt="image_05" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_individuals_complete.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-54" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/meeting_length.png" title=" " class="shutterset_set_4" >
								<img title="image_06" alt="image_06" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_meeting_length.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-51" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/config.png" title=" " class="shutterset_set_4" >
								<img title="image_07" alt="image_07" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_config.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-66" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/menu.png" title=" " class="shutterset_set_4" >
								<img title="image_08" alt="image_08" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_menu.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-67" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/stats.png" title=" " class="shutterset_set_4" >
								<img title="image_09" alt="image_09" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_stats.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-65" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/meetings.png" title=" " class="shutterset_set_4" >
								<img title="image_10" alt="image_10" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_meetings.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 		
	<div id="ngg-image-64" class="ngg-gallery-thumbnail-box"  >
		<div class="ngg-gallery-thumbnail" >
			<a href="http://johnpwood.net/wp-content/gallery/standup-timer/meeting_stats.png" title=" " class="shutterset_set_4" >
								<img title="image_11" alt="image_11" src="http://johnpwood.net/wp-content/gallery/standup-timer/thumbs/thumbs_meeting_stats.png" width="100" height="75" />
							</a>
		</div>
	</div>
	
		
 	 	
	<!-- Pagination -->
 	<div class='ngg-clear'></div>
 	
</div>


]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2009/12/04/my-first-android-app-standup-timer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Multiple Database Models in a Single Application</title>
		<link>http://johnpwood.net/2009/09/29/using-multiple-database-models-in-a-single-application/</link>
		<comments>http://johnpwood.net/2009/09/29/using-multiple-database-models-in-a-single-application/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 12:55:35 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[polyglot persistence]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=569</guid>
		<description><![CDATA[The days of the relational database being a one-stop-shop for all of your persistence needs are over. A new class of application is beginning to emerge with requirements that exceed [...]]]></description>
			<content:encoded><![CDATA[<p>The days of the relational database being a one-stop-shop for all of your persistence needs are over.  A new class of application is beginning to emerge with requirements that exceed the capabilities of the relational database.  Some of these applications need unlimited scalability or bullet proof fault tolerance, while others may require blazing fast access or flexible data storage.  The relational database was simply not designed to meet the needs of this small but growing class.  Instead, a new breed of data stores are gaining momentum.  These data stores are looking at data persistence with a fresh set of eyes, diverging from the relational model considerably in order to meet these challenges.</p>
<h3>What&#8217;s wrong with the relational database?</h3>
<p>For 99% of the applications out there, absolutely nothing.  The relational database has been the industry standard for data storage over the past 30+ years for good reason.  It is an incredibly capable piece of software.  Although it may not be the <em>best</em> tool for everything it is used for, it certainly satisfies the needs of the vast majority of applications just fine.</p>
<p>However, while not new, the class of applications mentioned above are becoming more common.  These applications either handle enormous amounts of traffic, or deal with tremendous amounts of data.  The relational database falls short in a few areas when trying to meet the demands of an application like this.</p>
<p><span  class="alignleft"><br />
<a href="http://www.flickr.com/photos/45745303@N00/3677040009/" title="WordPress 2.7 Database" target="_blank"><img src="http://farm3.static.flickr.com/2631/3677040009_e1f7e1184b_m.jpg" alt="WordPress 2.7 Database" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-sa/2.0/" title="Attribution-NonCommercial-ShareAlike License" target="_blank"><img src="http://johnpwood.net/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit: <a href="http://www.flickr.com/photos/45745303@N00/3677040009/" title="bioxid" target="_blank">bioxid</a></small><br />
</span></p>
<p>A single database server is usually not enough to support these requirements.  Applications like this need a true database cluster, capable of adding storage space and processing power on the fly without the application even noticing.  However, relational databases weren&#8217;t designed to operate in a cluster where all machines are capable of reading and writing data.  This is largely due to the promises they make regarding data integrity.  In order to fulfill these promises, the database needs easy, quick access to all of the data at all times to verify that duplicates aren&#8217;t being inserted, constraints aren&#8217;t being violated, etc.  This quickly becomes a bottleneck when dealing with very large amounts of data.</p>
<p>There are techniques for scaling out relational databases, but they don&#8217;t address every concern.  One popular technique is to use one or more slave databases for read requests, while continuing to funnel all write requests through the master database.  The master database constantly synchronizes with the read only databases, so the data remains consistent between databases.  This technique works great for read heavy applications, but does not help applications that perform just as many creates, updates, and deletes.  Data sharding is another popular technique, which involves splitting the data up onto several different databases based on some criteria.  But this pushes an extraordinary amount of complexity onto the application, as it is now responsible for determining which database to use for specific data sets.  Master-master replication can be used to keep multiple master databases in sync, so any database server can perform read or write operations.  However, for some applications there comes a point where the replication can&#8217;t keep up with the traffic.</p>
<p>Relational databases are also (intentionally) very strict when it comes to the structure of the data being stored.  Data must be broken up into a series of rows and columns.  Good object/relation mapping tools hide much of this awkwardness from us, but some applications deal with data that doesn&#8217;t map well into rows and columns.  A simple key/value store is usually a better fit for applications like this.</p>
<h3>How does the new breed address these problems?</h3>
<p>The new breed of data stores, called <strong>NoSQL</strong> databases, make very few promises regarding data integrity.  In this new model, data integrity becomes the application&#8217;s concern.  By not having to enforce any complex data integrity rules, NoSQL databases can scale to levels way beyond that of a relational database.  Adding more processing power or storage capacity can be as simple as adding a new machine to the cluster.  The database can then store and process the data using any machine in the cluster.</p>
<p>In this model, the data being stored is <strong>self contained</strong>, and does not rely on any other data in the database.  Therefore there is no need for one machine to know anything about the other machines in the cluster.  This approach is quite different from the relational model, where data is broken up into multiple tables to eliminate duplicate data, and joined back together when being accessed.</p>
<p>Most of these databases subscribe to a theory called <strong>eventual consistency</strong>.  In situations where duplicate information is scattered across different servers in the cluster, it is not feasible for the database to find all instances of that data and update it as a part of the original operation.  Instead, the data will be replicated to the other database servers at a later time.  Until that replication takes place, the application will be in an inconsistent state, where simultaneous queries fetching the same data could return different results.  Although this sounds terrible, it turns out that in practice it is really not too big of a deal for most applications.  Do all customers of an online retailer need to see the exact same set of product reviews 100% of the time?  Probably not.</p>
<p>Also, because there are few promises regarding data integrity, NoSQL databases can offer data storage that is much more flexible.  The database no longer has to enforce the uniqueness of a column, or ensure that the id of some referenced piece of data actually exists in the database.  Some of these databases are true key/value data stores, where you can store just about anything.  Others require a certain document format to be used (such as JSON or XML), but still allow you to freely change the contents of that document as you wish.</p>
<h3>Still no one-stop-shop for persistence</h3>
<p>Although NoSQL databases address some issues that can&#8217;t be addressed by relational databases, the opposite is true as well.  The relational database offers an unparalleled feature set.  While some of these features prevent it from serving the needs of the class of applications described above, they are absolutely required by other classes of applications.  In some domains, data integrity is the number one concern.  You need to look no further than the classic â€œtry to withdraw money from the same account at the same timeâ€ example to justify the need for locks and transactions.</p>
<p>For the vast majority of applications out there, relational databases work great.  There are a boat load of tools and libraries that support them, and software developers are very familiar with how to use them.  It is safe to say that the relational database has secured its spot in IT departments and data centers around the world, and it isn&#8217;t going anywhere.  It is far from dead.</p>
<h3>Polyglot persistence</h3>
<p>An increasing amount of case studies are appearing that describe how real world applications are needing the data integrity offered by the relational database <strong>in addition</strong> to the benefits offered by NoSQL databases.  I believe this trend will continue, as companies are storing more data than ever, and processing that data in different ways than previously imagined.</p>
<p>To address these needs, some companies are beginning to run their relational database side-by-side with one or more of the NoSQL alternatives.  Extremely large data sets that require scalable storage space and processing power are moved to a NoSQL database, while everything else, especially data that needs its integrity kept in-check, remains in the relational database.  The term <strong><a href="http://www.infoq.com/news/2009/07/leberknight-polyglot-persistence">Polyglot Persistence</a></strong> has been used to describe the use of multiple databases within the same project.</p>
<h3>The benefits of polyglot persistence</h3>
<p>The benefits are somewhat obvious.  By running a relational database side-by-side with a NoSQL database, you get the best of both worlds.  Strict enforcement of data integrity from the relational database, and the scalability and flexibility provided by the NoSQL database.  This allows you to use the best tool for the job, depending on your use case.</p>
<p><span  class="alignright"><br />
<a href="http://www.flickr.com/photos/79538062@N00/3649334538/" title="172/365 - memory" target="_blank"><img src="http://farm4.static.flickr.com/3552/3649334538_b3c86ae2c7_m.jpg" alt="172/365 - memory" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-nd/2.0/" title="Attribution-NonCommercial-NoDerivs License" target="_blank"><img src="http://johnpwood.net/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit: <a href="http://www.flickr.com/photos/79538062@N00/3649334538/" title="jypsygen" target="_blank">jypsygen</a></small><br />
</span></p>
<p>There are a few scenarios where I&#8217;ve seen systems take advantage of polyglot persistence.  The first scenario involves the need to perform some set of complex calculations on an extremely large data set.  The data is either copied/moved from the relational database to the NoSQL database, or inserted directly into the NoSQL database by the application.  The application can then use a cluster of NoSQL database servers can then divide the work, process the data, and aggregate the results.  The more machines you have in your cluster, the less time the processing will take.  The resulting data can either remain in the NoSQL database or be inserted into the relational database, depending on what needs to be done with the results.</p>
<p>The other scenario takes advantage of the schema-less nature of some NoSQL databases.  While it is certainly possible to store a serialized data structure in a single column of a relational database, interacting with that data can be a bit more challenging than if that data were in a schema-less, document oriented database.  This use case, after all, is what the documented oriented databases were designed for.  These types of databases simply treat the data as a collection of key/value pairs, identified by a unique ID.  The NoSQL databases provide ways in which you can add structure back into the document so the data inside the document can be queried.  These databases are great for storing data that can be radically different from document to document, or data whose structure changes constantly.</p>
<h3>The challenges of polyglot persistence</h3>
<p>Polyglot persistence comes with its own set of challenges.  While potentially getting the best of both worlds as far as features go, you get the complexity and hassle of dealing with not only multiple databases, but multiple databases models.</p>
<h4>Determining which database to use to store certain data</h4>
<p>With more than one database, you now have to decide where to store the data.  It&#8217;s no longer a given.  If you make the wrong decision, you could be looking at a painful migration from one database model to another as a result.  To make this decision, you need to carefully examine how the data will be used.</p>
<h4>Increased application complexity</h4>
<p>Applications also face increased complexity as they now have to interface with two different (potentially <strong>very</strong> different) data stores.  If done correctly, you should be able to isolate this complexity to the persistence layer of your application, freeing the rest of the application from having to know what database specific data is coming from.  But, interfacing to multiple data stores could greatly increase the complexity of that data persistence layer.  Your application will now need to know:</p>
<ul>
<li>How to connect to each of the databases</li>
<li>What database to use for specific sets of data</li>
<li>How to handle the different types of errors from each database</li>
<li>How to map results from each database back to your application&#8217;s object model</li>
<li>How to handle queries for information across databases</li>
<li>How to mock out the different databases for testing</li>
<li>Potentially, how to move data from one database to another</li>
</ul>
<p>Addressing these concerns could result in a bunch of new application code, and with added code usually comes added complexity, and more bugs.</p>
<h4>Increased deployment complexity</h4>
<p>In addition to the increased application complexity, you will also face increased deployment complexity.</p>
<ul>
<li>Will you need to provision new hardware to host the new database?</li>
<li>How will you backup the data in the new database?</li>
<li>How will you manage and control changes to the configuration of the new database?</li>
</ul>
<h4>Training for developers and operational staff</h4>
<p>Given that this database will likely be radically different from the relational database that your developers and operational staff are comfortable with, how will you bring them up to speed on how to use and manage this new database?  And, given that the majority of the NoSQL databases are still very young, how will you keep your developers and operational staff up to speed with the latest developments on the project?</p>
<p>This is a big issue, especially in companies with large development and operations teams, and needs to be thought through carefully.</p>
<ul>
<li>Is there an expert you can hire to help you get up and running, and mentor your staff?</li>
<li>Is there any training available that you can give to your staff?</li>
<li>Who can you turn to for support when something goes wrong in production?</li>
</ul>
<h3>Summary</h3>
<p>I&#8217;ve always been a big advocate of using the right tool for the right job.  For the past 30 years, the relational database has been the de-facto standard for persistence.  Creative people have managed to  utilize and manipulate it to serve all sorts of different use cases, quite successfully.  But just because you can fit a square peg through a round hole if you hit it with a big enough hammer doesn&#8217;t necessarily mean that you should.</p>
<p>NoSQL databases can be great tools for addressing data persistence cases that the relational database struggles with.  In addition, each NoSQL database brings its own set of strengths and weaknesses to the table.  They are becoming very important tools to have around, and I believe that our industry will see a steady increase in the adoption of these tools going forward.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2009/09/29/using-multiple-database-models-in-a-single-application/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Disabling sessions in Rails 2.3.4</title>
		<link>http://johnpwood.net/2009/09/04/disabling-sessions-in-rails-2-3-4/</link>
		<comments>http://johnpwood.net/2009/09/04/disabling-sessions-in-rails-2-3-4/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 20:06:15 +0000</pubDate>
		<dc:creator>John Wood</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://johnpwood.net/?p=527</guid>
		<description><![CDATA[I got a nice surprise today when upgrading our message processing application from Rails 2.3.3 to Rails 2.3.4, to pull in some important security fixes. /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:445:in `initialize_database_middleware': You have a [...]]]></description>
			<content:encoded><![CDATA[<p>I got a nice surprise today when upgrading our message processing application from Rails 2.3.3 to Rails 2.3.4, to pull in some important <a href="http://weblog.rubyonrails.org/2009/9/4/ruby-on-rails-2-3-4">security fixes</a>.<br />
<code style="font-size: .75em;"><br />
/opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:445:in `initialize_database_middleware': You have a nil object when you didn't expect it! (NoMethodError)<br />
The error occurred while evaluating nil.name<br />
	from /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:182:in `process'<br />
	from /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:113:in `send'<br />
	from /opt/ruby-enterprise-1.8.6-20090113/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:113:in `run'<br />
        ....<br />
</code></p>
<p>Jumping into the Rails source, I found the offending line.</p>
<pre class="brush:ruby">
if configuration.frameworks.include?(:action_controller) &#038;&#038;
  ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
</pre>
<p>This code assumes that a session store is configured in your Rails app.  However, this particular application has no need for a session, so we were disabling it in the configuration by specifying the following:</p>
<pre class="brush:ruby">
config.action_controller.session_store = nil
</pre>
<p>I poked around on the web for a while, trying to find another way to disable the session.  No luck.  It appeared that the only other way to disable the session was to properly configure a session store in your <code>environment.rb</code> file, and then disable it in your <code>ApplicationController</code>.  That seemed lame.  Why should I have to configure something that I want to disable?</p>
<p>So, I coded up a simple class to act as the session store for the application that simply raises an error if anybody tries to access the session.</p>
<pre class="brush:ruby">
class NilSessionStore < ActionController::Session::AbstractStore
  def get_session(env, sid)
    raise NotImplementedError, "NilSessionStore: No session configured"
  end

  def set_session(env, sid, session_data)
    raise NotImplementedError, "NilSessionStore: No session configured"
  end
end
</pre>
<p>I then configured the application to use this class as the session store.</p>
<pre class="brush:ruby">
config.action_controller.session_store = :nil_session_store
</pre>
<p>Nice and simple, and it keeps me from having to configure something I never plan to use.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnpwood.net/2009/09/04/disabling-sessions-in-rails-2-3-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

