<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0"><channel><title>digitalBush</title> <link>http://digitalbush.com</link> <description>Tales of a Tormented Software Developer</description> <lastBuildDate>Wed, 21 Jul 2010 04:21:05 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.0</generator> <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/digitalbush" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="digitalbush" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">digitalbush</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><item><title>The Importance of Liquidity</title><link>http://digitalbush.com/2010/07/20/the-importance-of-liquidity/</link> <comments>http://digitalbush.com/2010/07/20/the-importance-of-liquidity/#comments</comments> <pubDate>Wed, 21 Jul 2010 04:21:05 +0000</pubDate> <dc:creator>josh</dc:creator> <category><![CDATA[personal]]></category> <category><![CDATA[saving money]]></category> <category><![CDATA[liquidity]]></category> <category><![CDATA[saving]]></category> <category><![CDATA[unemployment]]></category><guid isPermaLink="false">http://digitalbush.com/?p=811</guid> <description><![CDATA[Not too long ago I blogged about how I found a job in an unconventional manner. The dev team I ended up working with was top notch. I was able to work with them for two months and I learned so much in such a short amount of time. Unfortunately the company that was supporting [...]]]></description> <content:encoded><![CDATA[<p>Not too long ago I blogged about how I <a
href="http://digitalbush.com/2010/06/16/will-tweet-for-food/">found a job in an unconventional manner</a>.  The dev team I ended up working with was top notch.  I was able to work with them for two months and I learned so much in such a short amount of time.  Unfortunately the company that was supporting said dev team was a <a
href="http://www.tennessean.com/article/20100707/NEWS01/7070361/2066/news03">little less than stable</a>. I'm happy to say that I've moved on and have found employment elsewhere, but that's not what I want to talk about tonight.</p><p>Getting booted on my ass revealed how well our family had prepared for tough times.  My wife and I have made it a point to live within our means and save money for a rainy day.  While people around us have been buying fancy new cars and big homes filled with a lot of toys, we lived in our small house and drove older vehicles to save money. When our son, Hudson, came into the world, we decided to upgrade homes, but still managed to be reasonable with our home purchase.</p><p>We bought a new home and decision time came.  Do I put a big fat down payment on the new home to keep the monthly payments low or just take advantage of the super low interest rates our shitty economy has bestowed upon us?  The problem with the big fat down payment is that I would have to give up a large chunk of our savings.  In the end I compromised and met somewhere in the middle.  I felt confident that I had enough remaining for my family to survive a while should bad things happen.</p><p><strong>Bad things happened.<br
/> <span
style="font-weight: normal;">About a month prior to my previous employer's implosion, we decided that my wife should stay home with our child.  This was huge for both of us.  My wife has worked since she was 16 and staying at home was a huge lifestyle change for her.  For me, it meant some added pressure to provide for my family. We were up for it and took the plunge. Naturally now that we're solely</span> </strong>dependent on my income is when I would get laid off.  That's just the way my world works.</p><p><strong>Is my World Ending?<br
/> <span
style="font-weight: normal;">As it turns out, losing my job wasn't the end of the world.  We had at least 6 months of funds to float us until I could find more work.  Granted, that's not 6 months of eating steaks every night, but it's still 6 months of mortgage, utilities,  health insurance, groceries, etc.  With that under my belt, I was able to go out an look for jobs confident that I didn't have to take the first thing that came my way.  I was able to pick where I wanted to go so that I could do what's best for my family.</span></strong></p><p>This whole experience has just validated my theories about how our family's finances should be managed. I feel good about how things have turned out. Let my situation serve as an example for you. I would say that you need at least 3 months of money available "just in case." You just never know when the FBI and IRS will pay your company a visit.</p><p><strong><span
style="font-weight: normal;"><br
/> </span></strong></p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/digitalbush?a=8BJ6mnylVv0:6CsCruE6NJo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/digitalbush?i=8BJ6mnylVv0:6CsCruE6NJo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/digitalbush?a=8BJ6mnylVv0:6CsCruE6NJo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/digitalbush?d=yIl2AUoC8zA" border="0"></img></a>
</div>]]></content:encoded> <wfw:commentRss>http://digitalbush.com/2010/07/20/the-importance-of-liquidity/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>CouchDB Bulk Load Performance</title><link>http://digitalbush.com/2010/07/01/couchdb-bulk-load-performance/</link> <comments>http://digitalbush.com/2010/07/01/couchdb-bulk-load-performance/#comments</comments> <pubDate>Thu, 01 Jul 2010 20:05:21 +0000</pubDate> <dc:creator>josh</dc:creator> <category><![CDATA[development]]></category> <category><![CDATA[asynchronous]]></category> <category><![CDATA[couchdb]]></category> <category><![CDATA[parallel]]></category><guid isPermaLink="false">http://digitalbush.com/?p=798</guid> <description><![CDATA[Yesterday I wrote a very long (sorry!) post about my technique for bulk loading data into CouchDB. I didn't want to make that post any longer, so today I'm going to talk about how well the bulk loading performs. All of these numbers come from my machine which is a Core2 Quad Q9000 @ 2Ghz [...]]]></description> <content:encoded><![CDATA[<p>Yesterday I wrote a very long (sorry!) post about <a
href="http://digitalbush.com/2010/06/30/throttling-asynchronous-tasks/">my technique for bulk loading data into CouchDB</a>.  I didn't want to make that post any longer, so today I'm going to talk about how well the bulk loading performs. All of these numbers come from my machine which is a Core2 Quad Q9000 @ 2Ghz with 8GB RAM and a single 7200 RPM drive.</p><p>As you may recall, the main problem I had was getting too much stuff in memory and having everything blow out with an out of memory exception. The solution I posted yesterday keeps memory under control and seems to keep all four processors busy. Here's a screenshot of task manager while it is running.</p><p><a
href="http://digitalbush.com/wp-content/uploads/2010/07/wiki-import-system-load.png"><img
class="aligncenter size-full wp-image-799" title="wiki-import-system-load" src="http://digitalbush.com/wp-content/uploads/2010/07/wiki-import-system-load.png" alt="" width="675" height="459" /></a></p><p>Armed with a stopwatch and the CouchDB web interface, I did some crude timings.  I may go back at some point and wrap my loader with some timing code so that I can generate some minute-by-minute graphs, but this will do for now.</p><table><tr><th>Elapsed Time (minutes)</th><th>Database Size (gigabytes)</th><th>Document Count</th></tr><tr><td>1</td><td>.33</td><td>19,000</td></tr><tr><td>2</td><td>.7</td><td>49,000</td></tr><tr><td>3</td><td>1.0</td><td>89,000</td></tr><tr><td>4</td><td>1.4</td><td>134,000</td></tr><tr><td>5</td><td>1.8</td><td>181,000</td></tr><tr><td>10</td><td>3.6</td><td>503,000</td></tr><tr><td>15</td><td>5.1</td><td>843,000</td></tr><tr><td>20</td><td>6.7</td><td>1,201,000</td></tr><tr><td>25</td><td>7.9</td><td>1,473,000</td></tr><tr><td>30</td><td>9.1</td><td>1,759,000</td></tr></table><p>I was really impressed with the numbers!  After 30 minutes, I was averaging 977 documents/second and and 5.2 megabytes/second. Keep in mind this is all running local on my machine, but the numbers sure are encouraging.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/digitalbush?a=GrCQBOWGcgw:Kd4Qri3nbfM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/digitalbush?i=GrCQBOWGcgw:Kd4Qri3nbfM:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/digitalbush?a=GrCQBOWGcgw:Kd4Qri3nbfM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/digitalbush?d=yIl2AUoC8zA" border="0"></img></a>
</div>]]></content:encoded> <wfw:commentRss>http://digitalbush.com/2010/07/01/couchdb-bulk-load-performance/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Throttling Asynchronous Tasks</title><link>http://digitalbush.com/2010/06/30/throttling-asynchronous-tasks/</link> <comments>http://digitalbush.com/2010/06/30/throttling-asynchronous-tasks/#comments</comments> <pubDate>Thu, 01 Jul 2010 03:13:01 +0000</pubDate> <dc:creator>josh</dc:creator> <category><![CDATA[development]]></category> <category><![CDATA[asynchronous]]></category> <category><![CDATA[bulk data]]></category> <category><![CDATA[couchdb]]></category> <category><![CDATA[parallel]]></category> <category><![CDATA[xml]]></category><guid isPermaLink="false">http://digitalbush.com/?p=771</guid> <description><![CDATA[I was recently tasked with load testing CouchDB. We have been using the document store very heavily for several new projects and we really needed to understand what it was capable of. More importantly, we needed to try and identify where it starts to fall apart. Knowing the performance characteristics of the software you are [...]]]></description> <content:encoded><![CDATA[<p>I was recently tasked with load testing <a
href="http://couchdb.apache.org/">CouchDB</a>. We have been using the document store very heavily for several new projects and we really needed to understand what it was capable of. More importantly, we needed to try and identify where it starts to fall apart. Knowing the performance characteristics of the software you are using is vital when making decisions about scaling.</p><p>The first step was to identify a large data set. I started to go grab the stack overflow data when a friend of mine pointed me to <a
href="http://en.wikipedia.org/wiki/Wikipedia_database">wikipedia</a>. Now this is a set of data to toy with.  It's an xml file which contains the more than 9.5 million pages which make up wikipedia. Let that soak in for a minute. Unzipped it weighs in at 25.4GB and I'm sure that it has grown since I downloaded last.</p><p><strong>Time to play!</strong><br
/> The general structure of the data looks like this:</p><pre>    public class Page
        [JsonProperty("_id")]
        public string Id { get; set; }
        public string Title { get; set; }
        public string Redirect { get; set; }
        public Revision Revision {get;set;}
    }

    public class Revision {
        public string Id { get; set; }
        public DateTime Timestamp { get; set; }
        public Contributor Contributor {get;set;}
        public string Minor {get;set;}
        public string Comment { get; set; }
        public string Text {get;set;}
    }

    public class Contributor {
        public string Username { get; set; }
        public string Id { get; set; }
        public string Ip { get; set; }
    }</pre><p>After identifying the structure, my next step was to actually parse the xml file. After a few minutes of banging my head against the wall, I ended up at this. I use an XmlReader to scan forward through the file and use the LINQ to XML bits to break off the page elements.</p><pre>    public class WikiFileParser {
        string fileName;

        public WikiFileParser(string fileName){
            this.fileName = fileName;
        }

        public IEnumerable&lt;XElement&gt; GetPages() {
            var file = new StreamReader(fileName);
            var reader = XmlReader.Create(file);
            reader.MoveToContent();

            while (reader.Read()) {
                if (reader.NodeType == XmlNodeType.Element &amp;&amp; reader.Name == "page"){
                    XElement x = XNode.ReadFrom(reader) as XElement;
                    if (x != null)
                        yield return x;
                }
            }
        }
    }</pre><p>The reason I chose this method is that I needed to keep a minimal amount of data in memory and I wanted to use the convenience of the LINQ to XML api to populate my objects.</p><p>Before I get to the meat, I need to share a few extension methods:</p><pre>    public static XElement Named(this XElement elm, string name){
        var newElm = elm.Element("{http://www.mediawiki.org/xml/export-0.4/}" + name);
        if (newElm == null)
            newElm = new XElement("dummy");
        return newElm;
    }</pre><p>This one is to get around some weird namespace issues that I encountered. If someone knows how I can avoid this, please let me know!</p><pre>    public static IEnumerable&lt;IEnumerable&lt;T&gt;&gt; Chunk&lt;T&gt;(this IEnumerable&lt;T&gt; pages, int count){
        List&lt;T&gt; chunk = new List&lt;T&gt;();
        foreach (var page in pages){
            chunk.Add(page);

            if (chunk.Count == count){
                yield return chunk.ToList();
                chunk.Clear();
            }
        }
        yield return chunk.ToList();
    }</pre><p>This one is kind of interesting. I'm using this to batch up single entities into clumps so that I can perform bulk operations.</p><p><strong>Finally, on to the meat!</strong><br
/> I'll start by posting the code and the I'll explain each method in detail.</p><pre>    public class BulkLoader{
        string uri;
        public BulkLoader(string uri) { this.uri = uri; }

        public void Load(string filename){
            Action&lt;IEnumerable&lt;XElement&gt;&gt; saveAction = Save;
            var file = new WikiFileParser(filename);

            var workers = file
                .GetPages()
                .Chunk(1000)
                .Select(x =&gt; saveAction.BeginInvoke(x, null, null))
                .Aggregate(new Queue(),
                           (queue, item) =&gt;{
                               queue.Enqueue(item);
                               if (queue.Count &gt; 5)
                                   queue.Dequeue().AsyncWaitHandle.WaitOne();
                               return queue;
                           });

            //Wait for the last bit to finish
            workers.All(x =&gt; x.AsyncWaitHandle.WaitOne());
        }

        void Save(IEnumerable&lt;XElement&gt; elms){
            var json = new { docs = elms.Select(x =&gt; MakePage(x)) }.ToJson(false);
            var request = WebRequest.Create(uri);
            request.Method = "POST";
            request.Timeout = 90000;

            var bytes = UTF8Encoding.UTF8.GetBytes(json);
            request.ContentType = "application/json; charset=utf-8";
            request.ContentLength = bytes.Length;

            using (var writer = request.GetRequestStream()){
                writer.Write(bytes, 0, bytes.Length);
                request.GetResponse().Close();
            }
        }

        Page MakePage(XElement x){
            var rev = x.Named("revision");
            var who = rev.Named("contributor");
            return new Page(){
                Title = x.Named("title").Value,
                Redirect = x.Named("redirect").Value,
                Id = x.Named("title").Value,
                Revision = new Revision(){
                    Id = rev.Named("id").Value,
                    Timestamp = Convert.ToDateTime(rev.Named("timestamp").Value),
                    Contributor = new Contributor(){
                        Id = who.Named("id").Value,
                        Username = who.Named("username").Value,
                        Ip = who.Named("ip").Value
                    },
                    Minor = rev.Named("minor").Value,
                    Comment = rev.Named("comment").Value,
                    Text = rev.Named("text").Value,
                }
            };
        }
    }</pre><p><code>MakePage</code> is responsible for turning the xml into a plain object. Here is where I needed that funky extension method to keep from typing the namespace over and over. There's not much to see here.</p><p><code>Save</code> is responsible for persisting the object to CouchDB. <a
href="http://sharplearningcurve.com/blog/">Alex Robson</a> will roll his eyes when he sees that part.  He has written a tremendously awesome .NET CouchDB API called Relax which you can <a
href="http://github.com/arobson/Relax">find on github</a>. The reason I decided not to use his api is because I was trying to eek out every bit of speed increase that I could find.</p><p><code>Load</code> is where the magic happens. This is the part that tripped me up for quite a while. At first I was using <code>Parallel.ForEach</code> and I kept running into out of memory exceptions.  It wasn't until Alex put up <a
href="http://sharplearningcurve.com/blog/post/2010/06/15/ETL-To-CouchDB-With-Symbiote-Relax-and-Reactive-Extensions.aspx">this blog post</a> that I saw where I went wrong. I used a similar approach, but with plain old IEnumerable instead of IObservable /  Reactive Extensions.</p><p>Then, Alex <a
href="http://sharplearningcurve.com/blog/post/2010/06/29/Using-Reactive-Extensions-To-Throttle-Asynchronous-Tasks.aspx">decided to one up me</a> the other night before I even finished writing this post. You see, the problem with the original solution is that it would collect 5 asynchronous tasks and then wait for them all to finish before starting 5 more. My implementation suffered the same problem.</p><p>Sing with me; "Anything Rx can do, IEnumerable can do with more coooooode." I'm sorry that I just put you through that; my musical skills are definitely lacking. I really should get back to explaining code now. So, you see I start by looking at the stream of pages. I collect 1000 and then I fire off an asynchronous invoke of the batch save I describe above. The result of that is a handle to the asynchronous task which I can then use to track the status of it. I then aggregate that into a queue where will collect up to 5 tasks and then start dequeuing the oldest task and then waiting until it's finished.</p><p>The result?  I can keep 5 tasks running constantly always pumping data. Since the data set is rather large and I'm using fairly good sized batches, this produces quite a bit of memory pressure. If you want to try this at home with not so much memory, then back down the batch size.</p><p>This was a fun task to do. Since I've already lost most readers somewhere about 15 paragraphs back, I'll save the performance for another post.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/digitalbush?a=yeASRKK8zvM:1U2ae5ZTceo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/digitalbush?i=yeASRKK8zvM:1U2ae5ZTceo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/digitalbush?a=yeASRKK8zvM:1U2ae5ZTceo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/digitalbush?d=yIl2AUoC8zA" border="0"></img></a>
</div>]]></content:encoded> <wfw:commentRss>http://digitalbush.com/2010/06/30/throttling-asynchronous-tasks/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Will Tweet for Food</title><link>http://digitalbush.com/2010/06/16/will-tweet-for-food/</link> <comments>http://digitalbush.com/2010/06/16/will-tweet-for-food/#comments</comments> <pubDate>Thu, 17 Jun 2010 03:09:17 +0000</pubDate> <dc:creator>josh</dc:creator> <category><![CDATA[personal]]></category> <category><![CDATA[job]]></category> <category><![CDATA[twitter]]></category><guid isPermaLink="false">http://digitalbush.com/?p=722</guid> <description><![CDATA[Some of you may know that I've recently switched jobs. For several months I tried to find just the right job using traditional job search mechanisms and was failing miserably. I got a few interviews, but nothing really clicked.  I didn't want to get stuck in some soul sucking corporate dev job wasting away in [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://www.flickr.com/photos/86624586@N00/12032239/"><img
class="alignright" src="http://farm1.static.flickr.com/9/12032239_5ab7036e9a.jpg" alt="" width="316" height="203" /></a>Some of you may know that I've recently switched jobs. For several months I tried to find just the right job using traditional job search mechanisms and was failing miserably. I got a few interviews, but nothing really clicked.  I didn't want to get stuck in some soul sucking corporate dev job wasting away in a cube while writing COBOL.  Unfortunately that's what I kept finding.</p><p><strong>If you want something different, sometimes you have to look in different places.</strong> That's what I was thinking when I started seeking out local devs on twitter in the Nashville area. I started this quest about a year ago and I thought it would be entertaining to share with you how twitter found me a job.</p><p>The first step was to find some Nashville developers. This wasn't as easy as it sounds. You see, you don't just go out and do a search and come up with 20 or 30 people by location. Twitter doesn't quite work that well.  It really started with <a
href="http://twitter.com/elijahmanor">Elijah Manor</a>.  I stumbled upon him one day from a retweeted tech tweet of his. I saw that he was from Nashville and thought that was neat, so I followed him and started looking over the people he followed. From there I found a few more local developers.</p><p>The next step is to wait and watch. This is really just a continuation of step one. The only way to find people to follow is to see how people interact with one another. Some of the Nashville tweeple I had found were duds while others were awesome.  Some of them interacted with other local devs. Jackpot! Over the course of a few months I picked up a few more local people who I thought were interesting.</p><p>The third step is to interact.  Twitter doesn't work unless you are producing output. Twitter will let you virtually stalk someone, but I doubt that would land you a job. "Hello sir, you don't know me, but I've been following you for a few months..." That just won't help any. No, you just need to put yourself out there.  Talk to other devs about interesting stuff.  Build relationships.  Try not to be stupid or controversial.  It's that easy.</p><p>The fourth step is to wait (again).  At this point you aren't looking for a job, you are waiting for opportunities.  While you are having fun interacting and learning from others just keep an eye open for goodies.  When you see something, go after it and see where it takes you.</p><p>Where it took me was two different opportunities. I can't believe it, but not only did twitter get me in the door with two companies, but it got me two, count them, <strong>two </strong>job offers.  Both of those opportunities I thought were very good and would have suited me well.  Traditional job searches got me in the door, but it was with the wrong companies for my needs. The interviews I got via twitter were very laid back and natural.  They were more of a friendly chat than anything else.</p><p>After a couple of brief discussions with <a
href="http://sharplearningcurve.com/blog/">Alex Robson</a> and <a
href="http://www.davepurdon.com/">Dave Purdon</a> about how I got hired and why they chose me I've come to a few conclusions. Alex told me that he felt that using social mediums allowed them to find like minded people.  I share the same feelings towards my employer. Being able to interact with potential co-workers well in advance of my hiring showed me which employers treat their employees well. Dave said that they felt comfortable with me because they saw that I loved what I did and used my own time to research and explore software development. From my point of view, I felt that a company that allowed (or even better, encouraged!) their devs to use twitter would be a good fit. It showed me that they promote openness and are current with trends.</p><p>I just want to let everyone know that you have options when it comes to finding a job.  There is certainly more than one way to do it.  The most important thing is to always be looking for opportunities.  Sometimes they might appear in places you aren't expecting.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/digitalbush?a=4mJZbMaFHhg:LaWVYJWogtA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/digitalbush?i=4mJZbMaFHhg:LaWVYJWogtA:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/digitalbush?a=4mJZbMaFHhg:LaWVYJWogtA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/digitalbush?d=yIl2AUoC8zA" border="0"></img></a>
</div>]]></content:encoded> <wfw:commentRss>http://digitalbush.com/2010/06/16/will-tweet-for-food/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Slight Adjustments</title><link>http://digitalbush.com/2010/06/10/slight-adjustments/</link> <comments>http://digitalbush.com/2010/06/10/slight-adjustments/#comments</comments> <pubDate>Fri, 11 Jun 2010 03:07:10 +0000</pubDate> <dc:creator>josh</dc:creator> <category><![CDATA[personal]]></category> <category><![CDATA[adjustment]]></category> <category><![CDATA[fix]]></category> <category><![CDATA[life]]></category> <category><![CDATA[plumbing]]></category><guid isPermaLink="false">http://digitalbush.com/?p=725</guid> <description><![CDATA[Tonight I set out to fix a drain in the front bathroom.  This was one of the things on my todo list since we moved into our new home over a month ago.  This tub is where we've been giving Hudson his baths and the lever style drain stopper wasn't completely plugging the drain.  Hudson [...]]]></description> <content:encoded><![CDATA[<p>Tonight I set out to fix a drain in the front bathroom.  This was one of the things on my todo list since we moved into our new home over a month ago.  This tub is where we've been giving Hudson his baths and the lever style drain stopper wasn't completely plugging the drain.  Hudson likes his time in the tub, so naturally the water draining out slowly was a problem.</p><p><img
class="alignright" src="http://farm4.static.flickr.com/3207/2682157559_7e47ae178c_m.jpg" alt="" width="240" height="161" />With me being the person that I am, I went to the hardware store and bought one of those push style drains to replace it.  I installed one on the old house, so I knew this wouldn't be an issue.  I never even investigated why the old one leaked, I just knew I was going to tear the old one out and put in a shiny new one.  I removed the two screws holding the overflow plate (the plate with the lever in the middle) and pulled out the linkage and stopper.</p><p>I'm about to start removing the drain plate when it hit me: there is a threaded rod on that linkage I just threw in the garbage. That would let me move the stopper up and down and adjust how deep it goes into the pipe.  So, for shits and grins I turned the threaded rod out a few turns and stuck it back in. Amazingly it worked. No more leaky drain.</p><p>I could have punched myself. I moved the rod maybe an eighth of an inch to fix the problem. That's it, 1/8 of one inch. I had spent $20 on the replacement. I drove a few miles to the hardware store and burned a little gas. I wasted half an hour going to pick up the parts.  I did all of that to solve a problem that was only an eighth of an inch long.</p><p>So many times my solution is to find the biggest hammer and beat until the problem goes away. Tonight I was reminded that sometimes I just need to take a moment to see what I have in front of me. The best solution isn't always to rip something out and replace it. Sometimes a little tweak is all that is needed. </p><p>While tonight I am talking about plumbing, this really applies to life in general.  How much of your life have you tried to replace when all you needed to do was make a slight adjustment?  Even worse, how much of your life has made you unhappy and you've just let it happen without a second thought? Maybe a small tweak is all you need to restore a little bit of your sanity.  Think about it.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/digitalbush?a=zXSoOr7XI7g:wT1-oP4dRso:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/digitalbush?i=zXSoOr7XI7g:wT1-oP4dRso:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/digitalbush?a=zXSoOr7XI7g:wT1-oP4dRso:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/digitalbush?d=yIl2AUoC8zA" border="0"></img></a>
</div>]]></content:encoded> <wfw:commentRss>http://digitalbush.com/2010/06/10/slight-adjustments/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss><!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced)
Database Caching 6/9 queries in 0.002 seconds using apc

Served from: _ @ 2010-07-29 07:20:35 -->
