<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
    <title>justmonkey.biz</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/" />
    
   <id>tag:justmonkey.biz,2007://2</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2" title="justmonkey.biz" />
    <updated>2007-05-01T23:43:53Z</updated>
    <subtitle>A whole bunch of monkey business...</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Justmonkeybiz" /><feedburner:info uri="justmonkeybiz" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><entry>
    <title>Good Developer Habit #3: Leverage Standard Documentation Conventions</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2007/05/good_developer_habit_3_leverag.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=137" title="Good Developer Habit #3: Leverage Standard Documentation Conventions" />
    <id>tag:justmonkey.biz,2007://2.137</id>
    
    <published>2007-05-01T21:31:34Z</published>
    <updated>2007-05-01T23:43:53Z</updated>
    
    <summary>Make sure you learn the simple formats in your language of choice for documenting (Javadoc, Doxygen for C++, Perldoc). Why? Besides generating HTML, PDF, etc. documentation users can read without loading source files, many modern IDEs (Eclipse, etc) parse documentation...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Coding" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>Make sure you learn the simple formats in your language of choice for documenting (Javadoc, Doxygen for C++, Perldoc).  Why?  Besides generating HTML, PDF, etc. documentation users can read without loading source files, many modern IDEs (Eclipse, etc) parse documentation and can present it as you mouse over on code statements. </p>

<p><b>Java/C++</b></p>

<p>At the very least you should have Javadoc and Doxygen have very similar styles, the examples below comply in both system.   the following docs for any source file:</p>

<pre>
  /**
   * @class MyClass
   *
   * Describe what the heck your class does, threading expectations,
   * how it should be used, etc.
   *
   * @version $Id: $
   */
  public class MyClass {
</pre>

<p>And for all public methods that you expect others to consume:</p>

<pre>
  /**
   * @return a Collection of Mojo, or empty Collection if has no Mojo
   */
  Collection<Mojo> getMyMojo();
</pre>

<p>Bonus points for including threading and concurrency expectations, exception behavior, performance hints.<br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>Good Developer Habit #2: Be a Better Logger than Paul Bunyan</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2007/04/good_developer_habit_2_be_a_be.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=136" title="Good Developer Habit #2: Be a Better Logger than Paul Bunyan" />
    <id>tag:justmonkey.biz,2007://2.136</id>
    
    <published>2007-05-01T02:20:58Z</published>
    <updated>2007-05-02T05:09:58Z</updated>
    
    <summary>Like many things logging is an art, not a science. Many rules of thumb apply for effective logging, starting with use a logger (e.g. log4j, rlog, etc) rather than cerr or System.out.println. Never emit a log statement w/o at least...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Coding" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>Like many things logging is an art, not a science.  Many rules of thumb apply for effective logging, starting with use a logger (e.g. log4j, rlog, etc) rather than cerr or System.out.println.</p>

<p><b>Never emit a log statement w/o at least one argument!</b></p>

<p>Logging is expensive.  It likely requires argument processing, disk writes, and storage.  <b>Make every log event really count by providing as much relevant context as possible</b> for someone who views the log messages 5 minutes (or 5 days) later to understand what might have occurred.  The more '''relevant''' context provided in the message the higher the probability someone can interpret and deduce the root cause.</p>

<p>Bad:</p>

<pre>
  log.warn("Missing item");
</pre>

<p>Good:</p>

<pre>
  log.warn("Missing item in order " + orderID + " for customer "
                 + customerID);
</pre>

<p>It only took 2 seconds longer to type a much more useful error message.  Don't be lazy!  Its extremely frustrating when you are under pressure to debug a production system and realize someone forgot to log critical information that would help understand root cause.</p>

<p><b>Use appropriate logging levels</b></p>

<p>In production applications you should expect to drive log files to <b>zero fatals and errors</b>.  You should also consider driving warnings towards 0 as having unnecessary entries in your logs makes surfacing real problems more difficult.</p>

<p><b>Think about the computation</b></p>

<p>Reminder: '''even if the logging level is disabled all arguments passed into the logger get evaluated'''.  The following is a good example using log4j where CPU cost is undefined:</p>

<pre>
  log.debug("Event " + event + " occurred for customer " + customerID);
</pre>

<p>While this looks innocuous, if <code>event</code>'s toString() method actually does much computation this can eat up valuable CPU.  For instance, event.toString() couldb e doing a database lookup to get event meta-data.  A better approach is to add a conditional check:</p>

<pre>
  if( log.isDebugEnabled() )
    log.debug("Event " + event + " occurred for customer " + customerID);
</pre>

<p>For fatal/error/warning messages this is unnecessary since it is generally expected all log messages of those levels should be emitted into logs.  However, for any more verbose levels (inform/debug/notify/verbose) you should wrap w/ a conditional check.  '''If you are in a tight loop or critical core function, be extra careful!'''</p>

<p>Another rule of thumb: <b>'DON'T MODIFY STATE OR ADD BUSINESS LOGIC IN LOG STATEMENTS</b>.  This is considered a BIG NO NO:</p>

<pre>
  log.warning("Request count=" + (++requestCount));
</pre>

<p>If someone changes the logging level there is a possibility that those statements never execute (depending on whether the logging library has conditional check macros/byte code insertion)!  In fact, even though it works one day there are no guarantees that deploying a new version of your logging library won't change the behavior.</p>

<p><b>Java</b></p>

<p>Perhaps one day Java's log4j or commons logging will finally add byte code injection to insert these statements automatically.  However until that day, follow the conditional check pattern. </p>

<p>And if using Java's log4j for logging exceptions, then leverage it's native ability for including Exceptions w/ configurable backtraces:</p>

<pre>
  log.debug("Unexpected exception for accountID=" + accountID, e);
</pre>]]>
        
    </content>
</entry>
<entry>
    <title>Good Developer Habit #1: Embed RCS ID into EVERY file</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2007/04/good_developer_habit_1_embed_r.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=134" title="Good Developer Habit #1: Embed RCS ID into EVERY file" />
    <id>tag:justmonkey.biz,2007://2.134</id>
    
    <published>2007-04-29T21:34:20Z</published>
    <updated>2007-05-02T05:33:31Z</updated>
    
    <summary>Ever run across a file and wondered where the heck it came from? I hated being paged at 3am, only to find a script or class file for something I didn't write having a bug and not being able to...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Coding" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>Ever run across a file and wondered where the heck it came from?  I hated being paged at 3am, only to find a script or class file for something I didn't write having a bug and not being able to track down what branch to make a patch from.  <b>IMO, no file should ever be checked into a source repository without an RCS ID tag!</b></p>

<p>Almost every source control system supports the <code>$Id: $</code> tag, I know for a fact that <a href="http://www.perforce.com/">Perforce</a>, <a href="http://subversion.tigris.org/">Subversion</a>, and CVS all support this tag.  Use it or lose it (the file's origin that is)!</p>

<p><b>Scripting Languages</b></p>

<p>Embedding RCS ID is particularly important for Perl, Ruby, and other scripts as they often get copied around such that no tools can be used to find their origin.  Just add a simple comment at the top:</p>

<pre>
  #!/usr/bin/ruby
  # $Id: $
</pre>

<p><b>Config</b></p>

<p>Again, embedding RCS ID tags enables someone to quickly find exactly where to change the config file in it's permanent repository.  There is nothing worse than wasting 5 minutes of time trying to track down exactly how the file got deployed to a box, where it was imported from, and what branch it was released on.  Save everyone time by adding tags where.  Simple:</p>

<pre>
  # $Id: $
  
  *.*.SelfImplode = F;
</pre>

<p>This includes Java properties files, Spring, XML config, JSON, or whatever you might be using to "configure" any software component. </p>

<p><b>Java</b></p>

<p>An interesting pattern I've seen lately is to emit software versions into the application log based on log level:</p>

<pre>
  public class YourObject {
    private static final Logger log = Logger.getLogger(YourObject.class);
    static { log.debug("$Id: $"); }
</pre>

<p>Note, depending on how many classes your application uses this could increase JVM/application startup time.  I suspect in 99.9% of the cases these few extra microseconds won't matter.</p>

<p>For a long time I've wanted a mechanism where, via [[JMX]], I could connect remotely to a running process and inspect which versions of software were loaded.</p>

<p><b>C++</b></p>

<p>Embedding RCS ID as a string variable into binaries/shared objects enables executing:</p>

<pre>
  % strings my-app-binary-file | grep "\$Id"
</pre>

<p>to find exactly what versions of code are linked in.  Extremely useful for reducing MTTR, we've seen it in practice.  This simple trick enables an oncall to quickly track back and patch.</p>

<p>It's easy to roll your own based off that macro, just make sure the compiler doesn't optimize out the strings.  Create a simple #define macro for embedding these quickly.</p>

<p><b>Documentation (Javadoc/Doxygen/etc)</b></p>

<p>All of this applies equally to  documentation.  Ever read a Javadoc provided by another team and wanted to know where to update it to be clearer?  Simply adding <code>@version $Id: $</code> makes this trivial.</p>

<p>The following example ensures [[Javadoc]] generated docs include exactly what file is being referenced and where to change it!</p>

<pre>
  /**
   * @class Kryptonite
   *
   * Rock solid implementation, use sparingly.
   *
   * @version $Id: $
   */
  public class Kryptonite {
</pre>

<p>There are numerous other cases where embedded RCSID make sense, it's just another good habit to leverage them where possible.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Simple Developer Habits and Rules of Thumb</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2007/04/simple_developer_habits_and_ru.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=135" title="Simple Developer Habits and Rules of Thumb" />
    <id>tag:justmonkey.biz,2007://2.135</id>
    
    <published>2007-04-29T21:04:24Z</published>
    <updated>2007-05-01T21:57:03Z</updated>
    
    <summary>I've been doing more code reviews lately and realized many common rules of thumb weren't percolating through the general developer community. There are tons of great books out there on design patterns, dependency injection, test driven development, ORM, etc. but...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Coding" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>I've been doing more code reviews lately and realized many common rules of thumb weren't percolating through the general developer community.  There are tons of great books out there on design patterns, dependency injection, test driven development, ORM, etc. but few that cover simple basics and tricks useful for writing and maintaining production software.</p>

<p>I'll be posting a series of simple suggestions on how to improve the code you write.  These rules of thumb are based on reviewing millions of lines of code mixed with dealing w/ the less often discussed aspect of software development: code maintenance lifecycle.  Many are extremely basic and you likely already put them to practice.  However some seemingly trivial changes can pay off over the long haul, particularly as software evolves across multiple developers.  YMMV.<br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>Blue Dot!</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2006/11/blue_dot.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=130" title="Blue Dot!" />
    <id>tag:justmonkey.biz,2006://2.130</id>
    
    <published>2006-11-05T23:02:46Z</published>
    <updated>2006-11-05T23:11:44Z</updated>
    
    <summary>I've used del.icio.us for quite a time to organize the bookmarks I share between the many computers I tend to use. However, last month Hemant encouraged me to check out Blue Dot again. I'd checked out the site almost a...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Gadgets" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p><img src="http://bluedot.us/images/banner_logo.png" align="right">I've used <a href="http://del.icio.us/">del.icio.us</a> for quite a time to organize the bookmarks I share between the many computers I tend to use.  However, last month <A href="http://bhanoo.blogspot.com/">Hemant</a> encouraged me to check out <a href="http://bluedot.us/">Blue Dot</a> again.  I'd checked out the site almost a year ago since learning an old team-mate of mine, Eric F., had joined the company but at the time it was still coming together.   </p>

<p>Blue Dot is so incredibly better that del.icio.us that I've since imported my entire del.icio.us bookmarks.  The UI is much better, simple permissions structure, the ability to add comments to links (essentially in a blog style) w/ auto-image tagging, improved community collaboration, RSS feeds for just about any view into the data.  </p>

<p>The guys at Blue Dot really seem to get it and is already an extremely useful tool I use almost daily.  Kudos.<br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>Carbonado</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2006/10/carbonado.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=129" title="Carbonado" />
    <id>tag:justmonkey.biz,2006://2.129</id>
    
    <published>2006-10-27T07:16:23Z</published>
    <updated>2006-10-27T07:39:32Z</updated>
    
    <summary>As Werner Vogels mentioned, congrats to Brian and his fellow engineers responsible for building and releasing Carbonado!...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Engineering" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>As <a href="http://www.allthingsdistributed.com/2006/10/carbonado.html">Werner Vogels mentioned</a>, congrats to Brian and his fellow engineers responsible for building and releasing <a href="http://carbonado.sourceforge.net/">Carbonado</a>!</p>]]>
        
    </content>
</entry>
<entry>
    <title>CellarTracker!</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2006/09/cellartracker.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=128" title="CellarTracker!" />
    <id>tag:justmonkey.biz,2006://2.128</id>
    
    <published>2006-09-01T19:02:49Z</published>
    <updated>2006-11-05T23:22:52Z</updated>
    
    <summary> As most folks who start enjoying wine learn, storing bottles for a year or more often greatly improves how well the drink. Once you go beyond a dozen bottles of wine it becomes hard to remember where you got...</summary>
    <author>
        <name>ryans</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p><a href="http://www.cellartracker.com/"><img src="http://www.justmonkey.biz/img/ct.jpg" align="center" border=0></a><br clear></p>

<p>As most folks who start enjoying wine learn, storing bottles for a year or more often greatly improves how well the drink.  Once you go beyond a dozen bottles of wine it becomes hard to remember where you got a given bottle of wine, how much you paid, and how previous tastings were.  I had been using Windows based <a href="http://www.cellarwinesoftware.com/">Cellar!</a> for the last 2 years, however after Paul recently moved his entire wine collection to his new house and re-inventoried his entire collection he really touted CellarTracker!. </p>

<p>I decided to give it a whirl.  Import was relatively painless, I exported all my data from Cellar! into CSV and <a href="http://www.cellartracker.com/list.asp?iUserOverride=18935">uploaded to CellarTracker!</a>.  It took a few days, but eventually it got added into their Bulk Import system.  I suspect this is largely still a manual process for Eric LeVine, the site owner.  The bulk import too managed to automatically match ~40% of my wines, the rest I had to manually match entries w/ wines in their system.  I only found and had to add 2 wines that they didn't have already listed!  Regardless, converting was quicker than I expected.  </p>

<p>The site is "free", which really rocks w/r/t playing around and seeing it the tool is for you.  After realizing CellarTracker was much better than what I was using I sent in the requested donation.  The site has some minimal community features, most useful is data/peer-reviews/tasting notes and label images uploaded by others.  It's also nice to see what <a href="http://www.cellartracker.com/list.asp?iUserOverride=21027">>friends</a> enjoy drinking.  The biggest downside is the UI, however that can easily be improved, they are really focusing on building up their already solid data base of wines, tasting notes, pricing, drinking windows, etc. which IMO is much more important than the UI at this stage.</p>

<p>Image courtesy of <a href="http://erich.typepad.com/erichian/2006/08/cellartracker.html">Erich Ian's review</a>, also worth reading.<br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>Geoff Arnold joines Amazon.com DSE</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2006/08/welcome_to_dse.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=126" title="Geoff Arnold joines Amazon.com DSE" />
    <id>tag:justmonkey.biz,2006://2.126</id>
    
    <published>2006-08-14T22:58:58Z</published>
    <updated>2006-08-18T05:35:42Z</updated>
    
    <summary>I'd like to welcome Geoff Arnold as the newest Principal Software Engineer to join Amazon.com's Distributed Systems Engineering team. Geoff spent the last 20 years working on all sorts of interesting distributed computing problems as one of very few Distinguished...</summary>
    <author>
        <name>ryans</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>I'd like to welcome <a href="http://www.geoffarnold.com/">Geoff Arnold</a> as the newest Principal Software Engineer to join <a href="http://ds.amazon.com/">Amazon.com's Distributed Systems Engineering</a> team.  Geoff spent the last 20 years working on all sorts of interesting distributed computing problems as one of very few Distinguished Engineers at Sun Microsystems.  Personally I'm looking forward to working with Geoff and seeing how he spreads his technical influence across Amazon.com.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Amazon S3</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2006/03/post_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=121" title="Amazon S3" />
    <id>tag:justmonkey.biz,2006://2.121</id>
    
    <published>2006-03-16T03:49:56Z</published>
    <updated>2006-08-17T22:58:30Z</updated>
    
    <summary>Amazon.com just launched S3 (Simple Storage Service), a serious game changer. Should be extremely interesting to follow what innovators integrate S3 into over the coming months. Definately see interesting backup solutions and potentially digital content/software distribution via their BitTorrent interface....</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Engineering" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p><img src="http://g-images.amazon.com/images/G/01/00/10/00/14/19/27/100014192753.gif" align="right"><a href="http://www.amazon.com/">Amazon.com</a> just launched <a href="http://aws.amazon.com/s3">S3</A> (Simple Storage Service), a serious game changer.  Should be extremely interesting to follow what innovators integrate S3 into over the coming months.</p>

<p>Definately see interesting backup solutions and potentially digital content/software distribution via their <a href="http://www.bittorrent.com/">BitTorrent</a> interface.  Very nice touch!  Naysays may balk at the cost per-GB but I think they are really missing the boat here.  To have your data securely stored across multiple physical locations (to avoid complete loss in fire, etc) is quite costly as a home user, particularly when you only need to store a small amount (e.g. 10GB) of data.  Think about it.  If you bought the smallest drive to fit that data (30GB) it costs you ~$25 (per pricewatch w/ S&H).  Now buy 2 for local RAID, then a 2 more for storing offsite.  You are already up to $100.  And that assumes the offsite disks are manually moved locally to transfer data, and then manually (e.g. walk with sneakers) to the offsite location.  Want online access?  Buck up for a CPU, case, motherboard, network connection, etc.  Easily another $100+.</p>

<p>S3 in comparison you can back up 10GB costs only $1.55/month + $2 transfer cost.  The peace of mind knowing all my digital photos are safely archived offsite (and I can access from anywhere) is worth MUCH more than $1.50/month!</p>

<p>Also interesting is the Amazon Web Services team published the principles of distributed system design used to meet their requirements for S3. </p>

<ul>
<li><b>Decentralization</b>: Use fully decentralized techniques to remove scaling bottlenecks and single points of failure.
<li><b>Asynchrony</b>: The system makes progress under all circumstances.
<li><b>Autonomy</b>: The system is designed such that individual components can make decisions based on local information.
<li><b>Local responsibility</b>: Each individual component is responsible for achieving its consistency; this is never the burden of its peers.
<li><b>Controlled concurrency</b>: Operations are designed such that no or limited concurrency control is required.
<li><b>Failure tolerant</b>: The system considers the failure of components to be a normal mode of operation, and continues operation with no or minimal interruption.
<li><b>Controlled parallelism</b>: Abstractions used in the system are of such granularity that parallelism can be used to improve performance and robustness of recovery or the introduction of new nodes.
<li><b>Decomposed components</b>: Do not try to provide a single service that does everything for everyone, but instead build small components that can be used as building blocks for other services.
<li><b>Symmetry</b>: Nodes in the system are identical in terms of functionality, and require no or minimal node-specific configuration to function.
<li><b>Simplicity</b>: The system should be made as simple as possible (– but no simpler). 
</ul>
]]>
        
    </content>
</entry>
<entry>
    <title>Music collection archived (finally)</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2005/09/music_collection_archived_fina.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=106" title="Music collection archived (finally)" />
    <id>tag:www.none-of-yo.biz,2005:/test/blog//2.106</id>
    
    <published>2005-09-01T08:55:45Z</published>
    <updated>2005-11-04T08:56:57Z</updated>
    
    <summary>I finally ripped the majority of my CD collection!!! Truthfully, I can't believe how many CDs Mary and I have bought over the years (it doesn't help to work at a retail company). Accessing SlimServer states "Your music library contains...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="AV" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>I finally ripped the majority of my CD collection!!!  Truthfully, I can't believe how many CDs Mary and I have bought over the years (it doesn't help to work at a retail company). </p>

<p>Accessing SlimServer states "Your music library contains 400 albums with 5319 songs by 744 artists."  Wow!!  Plus there are still a few CDs that I'm missing or haven't ripped.  Total disk space for the collection is 127GB for FLAC originals.  Compare that to the 30GB required for re-encoded @ 256kbps MP3, which fits perfectly on my iPod.</p>

<p><img src="http://www.mikewren.com/flac/flac_full.gif" align="right" width="150">I ripped to lossless FLAC format and have a crontab that periodically runs and re-encoded them to 256kbps VBR MP3 for my iPod.  Averaging 5 CDs per day the process took almost 3 months.  Every time I walked by my PC I slipped in another disc.  To rip the discs I used <a href="http://www.exactaudiocopy.de/">EAC</a> (Exact Audio Copy) with <a href="http://www.accuraterip.com/">AccurateRip</a> configured for my drive.  Several of my CDs were damaged and a few tracks couldn't be ripped.  Luckily I have detailed logs for each CD so I can go back and see if enabling a higher level of error correction help.  Or perhaps I can find someone to lend me an undamaged version.</p>

<p>DeSantis pointed my towards the Open Source <a href="http://www.slimdevices.com/su_downloads.html">Slim Devices SlimServer</a> software for managing your music collection via a web interface.  SlimServer provides a decent UI, search capabilities, and the ability to stream your music remotely.  Though I decided not to buy one, the <a href="http://www.slimdevices.com">Squeezebox2</a> device provides an easy way to play music through your stereo.</p>

<p>Almost all my albums have cover art associated with them, courtesy of <br /><br />
the <a href="http://louhi.kempele.fi/~skyostil/projects/albumart/">Album Cover Art Downloader</a> (Windows) which integrates with Amazon.com to smoothly download cover art for your entire collection.  My automated encoding scripts also update ID3v2 APIC tags to embed the cover art into convert MP3s.  Unfortunately iTunes has a semi-known bug where it incorrectly handles APIC embedded art (in fact iTunes embeds art itself under the incorrect index).  I spent about an hour trying to debug this before deciding to just wait until future iTunes releases when this actually works.</p>

<p><a href="http://www.sleevetown.com/plastic-cd-sleeves.shtml"><img src="http://www.sleevetown.com/images/simple-poly.jpg" border=0 align="left" width="150"></a>Also, after being recommended highly by my good buddy Jon, I ordered hundreds of <a href="http://www.sleevetown.com/">Sleevecity</a>'s 3.5 mil 100% virgin polyethylene CD sleeves to replace all the hard plastic cases.  My entire collection of CDs fits into two shoeboxes now.  Cost $3.99 / 100 sleeves.  As long as you don't mind getting rid of all the plastic cases (I kept any unique cases) this is a compact and cheap way of storing your originals.</p>

<p>I feel much better this time around than the last 2 attempts at ripping my collection.  The first time around in late 2000 I ripped to one of the first <a href="http://request.com/us/">AudioReQuest Music Servers</a> (an awesome product at the time, I haven't used a more recent version) and unfortunately used way to low quality MP3 @ 192kpbs.  The muffled sound was clearly noticable on higher end headphones or when played on my stereo system.  I attempted again several years later but didn't complete ripping since I didn't feel like I had a good long term strategy that was flexible.  FLAC and all my custom, automated scripts make me feel much better about having a long term solution.</p>

<p>Next up?  Figuring out a better way to play music on my stereo than hooking up my iPod or using my old, seldom working HTPC.  Perhaps exploring (or re-exploring in some cases) <a href="http://www.meedio.com">Meedio</a>, <a href="http://www.mythtv.org/">MythTV</a>, <a href="http://www.microsoft.com/windowsxp/mediacenter/default.mspx">MCE 2005</a>, <a href="http://www.rokulabs.com/">Roku</a>, <a href="http://sonos.com/">Sonos</a>, or other (preferably cheap) solution.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Pham Quoc Hung</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2005/08/pham_quoc_hung_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=107" title="Pham Quoc Hung" />
    <id>tag:www.none-of-yo.biz,2005:/test/blog//2.107</id>
    
    <published>2005-08-29T08:59:56Z</published>
    <updated>2005-11-04T09:00:24Z</updated>
    
    <summary>One of my favorite Pacific Northwest artists, Pham Quoc Hung, finally has his website up and running. Over the next few months Hung plans to post more of his portfolio and will start keeping his show schedule online for those...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Life" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p><a href="http://www.phamquochung.com/rsblog"><img src="http://www.phamquochung.com/portfolio/artist/Artist_at_Work.thumb.jpg" align="right" border="0"></a>One of my favorite Pacific Northwest artists, <a href="http://www.phamquochung.com/rsblog">Pham Quoc Hung</a>, finally has his website up and running.  Over the next few months Hung plans to post more of his portfolio and will start keeping his show schedule online for those who track his work.</p>

<p>Mary and I will likely visit with Hung after work next Thursday at the Pioneer Square first Thursday art walk.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Sony Qualia 70"</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2005/07/sony_qualia_70.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=108" title="Sony Qualia 70&quot;" />
    <id>tag:www.none-of-yo.biz,2005:/test/blog//2.108</id>
    
    <published>2005-07-27T09:00:47Z</published>
    <updated>2005-11-04T09:01:42Z</updated>
    
    <summary>I was touring a house last weekend which had this massive RPTV w/ a really nice picture which ended up being the new Sony Qualia. I didn't know how cool the Qualia was at the time until another friend of...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="AV" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p><img src="http://www.elegantaudiovideo.com/images/006-2.jpg" align="right">I was touring a house last weekend which had this massive RPTV w/ a really nice picture which ended up being the new <a href="http://www.ultimateavmag.com/directviewandptvtelevisions/705sony/">Sony Qualia</a>.  I didn't know how cool the Qualia was at the time until another friend of mine brought up that he was thinking of buying a new TV and the Qualia was at the top of his list.  Had I known how impressive this set was I would have definately checked it out more!  Even in the minute or so I got to view the Qualia it was obvious the set needed some serious picture control tweaking before it looked phenomenal.</p>

<p>I've had great luck w/ Sony TVs.  My nearly 6 year old Sony 53" 4:3 53XBR300 RPTV has really lasted the test of time ($4000 at the time); it is still excellent.  The picture display looks better than most HDTV RPTV sets sold in stores (other than really high end).  This is mostly due to the fact that I had it ISF hand tuned a few years back and then also added an external <a href="http://www.dvdo.com">iScan HD scaler</a> (~$1000) last year to replace Sony's original DRC (Digital Reality Creation) internal scalar. </p>

<p>My Sony supports several HDTV resolutions up 1040i; I run all 16:9 video at 540p via the iScan which looks amazing and 4:3 at 480p full screen.  The best picture comes from the HDTV channels via my Comcast digital box (also upscaled by the iScan) and the results are stunning.</p>

<p>My luck w/ Sony video products has been great.  Fortunately I don't need a new TV or I'd probably be crazy enough to buy the Qualia.<br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>JavaOne Notes: Java on Linux</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2005/06/javaone_notes_java_on_linux.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=109" title="JavaOne Notes: Java on Linux" />
    <id>tag:www.none-of-yo.biz,2005:/test/blog//2.109</id>
    
    <published>2005-06-28T09:02:06Z</published>
    <updated>2005-11-04T09:02:47Z</updated>
    
    <summary>I was hoping there would be a bit more about Linux tuning, problems, etc. in this presentation; though it had some useful tips that might come in handy given I've never actually deployed production scale Java app under Linux (soon!)....</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Engineering" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>I was hoping there would be a bit more about Linux tuning, problems, etc. in this presentation; though it had some useful tips that might come in handy given I've never actually deployed production scale Java app under Linux (soon!).</p>

<p>Lots of Threads<br />
� Old systems have thread limit of 1024<br />
� Don�t set LD_ASSUME_KERNEL<br />
� Use small stack sizes (e.g. �Xss48k<br />
� Use ulimit �s to change stack size for native threads<br />
� Pay attention to /proc/sys/kernal/threads-max (automatically set by kernel based on memory available; different kernel versions compute differently)</p>

<p>cat /proc/self/maps<br />
� determine max heap size on a given system</p>

<p>2.4 -> 2.6 kernel changes<br />
� Overall transition is smooth<br />
� Some caveats:<br />
o HZ changed from 100 to 1000<br />
� Thread.sleep(1) will wake up after 1ms vs 10ms!<br />
� Max cause excessive context switches if in a loop<br />
o Thread.yield() is more expensive<br />
� �XX:+DontYieldALot</p>

<p><br />
To run java inside gdb and valgrind</p>

<p>setenv LD_LIBRARY_PATH `java PrintLibraryPath`</p>

<p>public class PrintLibraryPath {<br />
  public static void main(String[] args) {<br />
    System.out.println(System.getProperty(�java.library.path�));<br />
  }<br />
}</p>

<p>JDK Tools<br />
� jstack: print stack trace<br />
� jmap: print heap uisage, object histogram<br />
� jjinfo: show command line flags & system properties<br />
� jstat: performance stats about various JVM properties</p>]]>
        
    </content>
</entry>
<entry>
    <title>JavaOne Notes: 1.5 Features Tips and Techniques</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2005/06/javaone_notes_15_features_tips.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=114" title="JavaOne Notes: 1.5 Features Tips and Techniques" />
    <id>tag:www.none-of-yo.biz,2005:/test/blog//2.114</id>
    
    <published>2005-06-28T08:35:45Z</published>
    <updated>2005-11-04T09:06:17Z</updated>
    
    <summary>After a less than thrilling session on Jini attended an excellent quick overview presentation of Java 1.5 features by BEA engineers. Foreach � avoids needing to cache collection size pre-loop (scopes size var appropriately) � no access to index or...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Engineering" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>After a less than thrilling session on Jini attended an excellent quick overview presentation of Java 1.5 features by BEA engineers.</p>

<p>Foreach<br />
� avoids needing to cache collection size pre-loop (scopes size var appropriately)<br />
� no access to index or iterator (e.g. remove current element)</p>

<p>Annotations<br />
� @SuppressWarnings�.suppresses compiler warning for a specific block (e.g. @SupperWarnings(�deprecation�) )<br />
� 1.5 currently ignores SuppressWarnings (supported in Eclipse 3.1 and JDK 1.6)<br />
� SuppressWarnings (all, deprecation, unchecked, fallthrough, etc)<br />
� @Deprecated: can�t indicate why, not a javadoc�if you use also put in javadoc tag to give more info to callers<br />
� @Override: indicates that a method should be overriding a superclass, if superclass method doesn�t exist (i.e. it changed) an error is emitted<br />
� Annotations are usefull in frameworks<br />
� Not a pre-processor�you can�t modify the code that is generated; by design from Sun<br />
� Not a silver bullet; don�t use for things they aren�t intended for (e.g. @Property to create get/set methods�this becomes essentially a macro�makes hard to synchronized since you can�t edit the code)</p>

<p>Enumerations<br />
� Type-safe (much better than public static final int!!! failures occur pre-runtime now)<br />
� Should be able to drop in 1.5 enums wherever ints are used today<br />
� EnumMap and EnumSet are optimized specifically for when you are using enums in maps and sets�<br />
� Can statically import enums (useful in the case where you are using a private enums�you can import inner class statically to avoid having to prepend inner class name)<br />
� Hidden static methods not in java.lang.Enum: values() returns all enum values (finally!); valueOf(String) to convert string rep<br />
� Enums can have methods! Very useful�</p>

<p>Varargs<br />
� Use sparingly!<br />
� Cleans up code where you have multiple methods that take varing numbers of methods�<br />
� NOTE: Backward compatibility issues for callers that import your binary jar; changing FORCES you to recompile all clients!!!<br />
� There is a backward compatibility map from array[] argument methods to var arg methods</p>

<p>Covariant Returns<br />
� Design pattern<br />
� Hide implementation details from API users<br />
� Avoids bad behaviors like downcasts to internal types<br />
� Impl can return specific type (rather than interface) and clients can avoid casts</p>

<p>Generics<br />
� Type inferencing on invocation<br />
� Generics w/ no parameters are determined by compiler by looking at where invoked (if value is returned and assigned, type == assigned type)<br />
� Type inferencing is not possible where no type info is available from context of being called<br />
� Can�t determine inference where called as a return from a method w/o assignment under certain situations (e.g. return x ? genericObj.foo() : null )<br />
� Can�t determine inference by being casted (e.g. <Integer> genericObj.foo() )<br />
� Type CAN be passed explicitly in this case: return genericObj.<Integer>foo()</p>

<p>Generics: Beyond collections<br />
� Class<T><br />
public T newInstance()<br />
� Comparable<T><br />
public int compareTo(T o)<br />
� Enum<E extends Enum<E>><br />
public Class<E> getDeclaringClass() // return class that impls enum</p>

<p>Using lower bound wildcards<br />
� Array typing is too lose; generic typing is too strict<br />
� List<Number> : list whose element type is known precisely�and that is Number<br />
� List<? extends Number> : exact element type isn�t known, but you do know it is a *subtype* of number<br />
� Why use <? extends �> : great for hiding implementation details<br />
� private Set<? extends Customer> getCustomers(); // hides the fact that the class returns an internal CustomerImpl class<br />
� Very important for interfaces to avoid exposing impl details; e.g. void removeNegatives(List <? extends Number> list)</p>

<p>Upper bound wildcards<br />
� List<? super Number><br />
� NOTE: type safety can make code obscenely bloated</p>

<p>Unbounded wildcard<br />
� List<?> : have no idea what the heck is passed in, other than it�s an object; equivalent to List<? extends Object></p>

<p>If read-only access is needed, use Collections.unmodifiiableCollection() for immutable collections (wrapper from java.util.collections)</p>

<p>Constructing Generics<br />
� Example: Pair<A,B> to enable returning multiple objects from a method<br />
� Before 1.5 Generics you had to explicitly create wrapper classes (e.g. return new FileInfo(name, size))<br />
� Under 1.5: Return new Pair<File, Integer>(file, size)<br />
� Can be used for additional compile time type safety</p>

<p>Generic Methods<br />
� �Necessary� when parameterizing the return (e.g. <T> List<T> reverse(List<T> list) )<br />
� Type info for generics is lost at compile time (erasure)<br />
� Type Tokens:</p>

<p>public class ArrayExample<T> {<br />
  // T must have a no arg constructor!!!  No way to enforce, failures<br />
  // will occur at runtime if someone<br />
  private Class<T> clazz;</p>

<p><br />
public ArrayExample(Class<T> clazz) {<br />
this.clazz = class;<br />
}</p>

<p><br />
public T[] getArray(int size) {<br />
return (T[])Array.newInstance(clazz, size);<br />
}<br />
}</p>

<p>Migration 1.4 -> 1.5<br />
� Safe to add generics gradually (binary compatible�but can�t compile on pre-1.5; even safe for subclasses to NOT be recoded to use generics)<br />
� Raw collections should be avoided as of 1.5<br />
� Temporary use of Collection�s checked wrappers can help (e.g. checkedCollection() )</p>]]>
        
    </content>
</entry>
<entry>
    <title>JavaOne Notes: Grizzly HTTP Listener via NIO</title>
    <link rel="alternate" type="text/html" href="http://justmonkey.biz/2005/06/javaone_notes_grizzly_http_lis.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.none-of-yo.biz/MovableType/mt-atom.cgi/weblog/blog_id=2/entry_id=110" title="JavaOne Notes: Grizzly HTTP Listener via NIO" />
    <id>tag:www.none-of-yo.biz,2005:/test/blog//2.110</id>
    
    <published>2005-06-28T08:02:56Z</published>
    <updated>2005-11-04T09:03:17Z</updated>
    
    <summary>Intro to NIO � Selector � basic abstraction to enable multiplexed I/O o Register one or more �selectable� channels o Relationship between channel and selector represented by a selection key o Selection key remembers the events you are interested in...</summary>
    <author>
        <name>ryans</name>
        
    </author>
            <category term="Engineering" />
    
    <content type="html" xml:lang="en" xml:base="http://justmonkey.biz/">
        <![CDATA[<p>Intro to NIO<br />
� Selector � basic abstraction to enable multiplexed I/O<br />
o Register one or more �selectable� channels<br />
o Relationship between channel and selector represented by a selection key<br />
o Selection key remembers the events you are interested in<br />
o Selector�s select() method updates the keys which are �ready�<br />
o Service each channel by iterating over they keys that are �ready�</p>

<p>Block/Non-Blocking<br />
� Traditional java.net.Sockets are blocking<br />
� Channels can be blocking or non-blocking<br />
o Non-blocking channels<br />
Never puts the invoking thread to sleep<br />
� Operation completes right away and returns a result indicating what (if anything) was done<br />
� Non-blocking makes it esy to manage many channels simultaneously<br />
� But, you have to tell the channel to be blocking or non-blocking<br />
� Additional book keeping required, you may get partial results back</p>

<p>Buffer and ByteBuffer<br />
� Containers for handling data<br />
� Worker very well together with Channels<br />
o High performing if done right!</p>

<p>� To use Buffers you must understand<br />
o Capacity � max num of elements<br />
o Limit � count of �live� elements, don�t read/write beyond<br />
o Position � index of next element to read./write<br />
o Mark � a remembered position<br />
o 0 <= mark <= position <= limit <= capacity</p>

<p>� ByteBuffers � two flavors<br />
o HeapByteBuffer<br />
� Underlying storage maintained in a Java language byte[]<br />
o DirectByteBuffer<br />
� Underlying storage maintained in native code, not in the Java language heap<br />
�<br />
� Tradeoffs with both of these approaches</p>

<p>� What�s true and what�s not true?<br />
o Using NIO SocketChannels and ByteBuffers is easy == true<br />
o Building a high performing and highly scalable app with NIO is easy == false<br />
o Non-blocking is fort server-side apps only == false</p>

<p>Grizzly is part of App Server 9.0 (Glass fish); Open Sourced</p>

<p>Grizzly integrates w/ current Apache Tomcat HTTP Connector architecture (Coyote)</p>

<p>Problems w/ NIO Non-Blocking<br />
� No guarantee that data is processed<br />
count = socketChannel.read(byteBuffer)<br />
� May not read the entire stream contents, requiring an extra read<br />
o Occurs frequently when reading HTTP requests<br />
� Same issue exists with writing data</p>

<p>A Task-based architecture has been used, each task representing an operation when manipulating the byte steam<br />
� AcceptTask for managing OP_ACCEPT<br />
� ReadTask for managing OP_READ<br />
� ProcessorTask for parsing</p>

<p>Tasks can execute on their own thread, on a shared thread or using the Selector thread</p>

<p>� Better off reading and processing in same thread<br />
� Single thread pool for read/process<br />
� Thread doing accepts, pool doing reads</p>

<p>Non-Blocking NIO is very similar to libc select()/poll()</p>

<p>The Grizzle GW supports 2 strategies:<br />
� Mode Blocking:<br />
� Mode Non-Blocking: w/ algorithm to predict byte stream completion<br />
� These are the modes that have produced best perfomance</p>

<p>Lessons Learned implementing Grizzly<br />
� Buffer management is crucial<br />
� DirectByteBuffer (DBB) is a big win<br />
� DBB expensive to allocate<br />
� Bext Practices<br />
o Use DBB w/ SocketChannels to avoid unnecessary copying of date<br />
o Avoid copy data out of DBB<br />
o Create view buffers to minimize DBB allocation costs<br />
� What�s a view buffer?<br />
o A buffer that manages data in another buffer</p>

<p>� Why useful?<br />
o Allocate one very large DBB and create smaller �views� or view buffers<br />
o Reduce number of costly DBB allocactions<br />
o Can re-use views</p>

<p>Gotchas<br />
� Register �key� in same thread doing the select<br />
o Unpredictable behavior in 1.4.x JVMs<br />
� Enable/disable a key�s operation of interest in same thread as select<br />
� Selector.select() and Selector.wakeup() are expensive<br />
� Buffers � too many leads to GC issues<br />
� Keep-Alive connections are well suited to using NIO (connection create/teardowns aren�t any more efficient under NIO)</p>]]>
        
    </content>
</entry>

</feed>

