<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-2292736096229539017</id><updated>2010-02-16T15:35:48.284-06:00</updated><title type='text'>perrys_head.select{ |thought| thought.tidbit }</title><subtitle type='html'>A technology agnostic blog focusing on object-oriented development using agile practices.</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.hertler.org/atom.xml'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-3004428419340798896</id><published>2010-02-16T15:35:00.002-06:00</published><updated>2010-02-16T15:35:48.292-06:00</updated><title type='text'>mort_calc gem</title><content type='html'>I recently published the &lt;a href="http://gemcutter.org/gems/mortgage_calc"&gt;mort_calc gem&lt;/a&gt; at &lt;a href="http://gemcutter.org"&gt;gemcutter.org&lt;/a&gt;. The code can be found at &lt;a href="http://github.com/perry3819/mort_calc/"&gt;http://github.com/perry3819/mort_calc/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The gem calculates the &lt;a href="http://en.wikipedia.org/wiki/Annual_percentage_rate"&gt;APR&lt;/a&gt; and monthly payment for a mortgage in the United States.&lt;br /&gt;&lt;br /&gt;Calculating the monthly payment is straight forward.&lt;br /&gt;&lt;br /&gt;&lt;img class="alignnone size-full wp-image-4831" title="monthly_payment" src="http://www.pathf.com/blogs/wp-content/uploads/2010/02/monthly_payment.png" alt="monthly_payment" width="161" height="66" /&gt;&lt;br /&gt;&lt;br /&gt;C = Loan amount&lt;br /&gt;&lt;br /&gt;E = Extra costs&lt;br /&gt;&lt;br /&gt;r = monthly interest rate = interest rate / 1200&lt;br /&gt;&lt;br /&gt;N = amortization term in months&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;An iterative approach is needed to find the APR. The equation for the APR follows.&lt;br /&gt;&lt;br /&gt;&lt;img class="alignnone size-full wp-image-4830" title="apr" src="http://www.pathf.com/blogs/wp-content/uploads/2010/02/apr.png" alt="apr" width="163" height="75" /&gt;&lt;br /&gt;&lt;br /&gt;a = APR/1200&lt;br /&gt;&lt;br /&gt;N = amortization term in months&lt;br /&gt;&lt;br /&gt;P = Monthly payment (including all fees paid by borrower)&lt;br /&gt;&lt;br /&gt;C = Loan amount&lt;br /&gt;&lt;br /&gt;The following graph shows the APR calculation plotted for N = 360, P = 2500, and C = 400,000. The APR is where the line crosses the &lt;strong&gt;A&lt;/strong&gt; axis.&lt;br /&gt;&lt;br /&gt;&lt;img class="alignnone size-full wp-image-4835" title="apr_plot" src="http://www.pathf.com/blogs/wp-content/uploads/2010/02/apr_plot.png" alt="apr_plot" width="499" height="325" /&gt;&lt;br /&gt;&lt;br /&gt;I chose the&lt;a href="http://en.wikipedia.org/wiki/Newton's_method"&gt; Newton-Raphson method&lt;/a&gt; to quickly find a precise solution.&lt;br /&gt;&lt;br /&gt;&lt;img class="alignnone size-full wp-image-4834" title="Screen shot 2010-02-16 at 1.51.57 PM" src="http://www.pathf.com/blogs/wp-content/uploads/2010/02/Screen-shot-2010-02-16-at-1.51.57-PM.png" alt="Screen shot 2010-02-16 at 1.51.57 PM" width="140" height="46" /&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://github.com/perry3819/mort_calc/blob/master/lib/mortgage_calc/mortgage_util.rb"&gt;MortgageUtil&lt;/a&gt;.calculate_apr method provides a starting value of the interest rate, which makes the Newton-Raphson converge on a accurate solution between 1 and 3 passes.&lt;br /&gt;&lt;script src="http://gist.github.com/305850.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;% sudo gem install gemcutter&lt;br /&gt;&lt;br /&gt;% gem tumble&lt;br /&gt;&lt;br /&gt;% sudo gem install mortgage_calc&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/305874.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-3004428419340798896?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/3004428419340798896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=3004428419340798896' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3004428419340798896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3004428419340798896'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2010/02/mortcalc-gem.html' title='mort_calc gem'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-9152500216786820942</id><published>2009-11-12T21:35:00.003-06:00</published><updated>2009-11-26T08:46:17.200-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>MySecrets</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://blog.hertler.org/uploaded_images/Screen-shot-2009-11-12-at-4.49.39-PM-707144-738927.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="320" src="http://blog.hertler.org/uploaded_images/Screen-shot-2009-11-12-at-4.49.39-PM-707144-738923.png" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;I developed &lt;a href="https://github.com/perry3819/mysecrets"&gt;MySecrets&lt;/a&gt; to manages my personal secrets/passwords. I had a lot of fun doing &lt;a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development"&gt;BDD&lt;/a&gt; with &lt;a href="http://cukes.info/"&gt;cucumber&lt;/a&gt;. Pickle works very nicely with Machinist to reduce &lt;a href="http://wiki.github.com/aslakhellesoy/cucumber/step-definitions"&gt;step definition code&lt;/a&gt;. I used &lt;a href="http://github.com/binarylogic/authlogic"&gt;authlogic&lt;/a&gt; for authentication and &lt;a href="http://github.com/justinfrench/formtastic/"&gt;formtastic&lt;/a&gt; to reduce the boiler plate code in my views.&lt;br /&gt;&lt;br /&gt;I had some trouble integrating cucumber, pickle, machinist, and authlogic. A &lt;b&gt;user &lt;/b&gt;has 0 to many &lt;b&gt;secrets&lt;/b&gt; and &lt;b&gt;secrets&lt;/b&gt; are protected by authlogic. So cucumber features that needed to add secrets and validate them were a little tricky.&lt;br /&gt;&lt;br /&gt;This scenario creates a user, login in, creates a secret, shows the secret, and finally validates the secret.&lt;br /&gt;&lt;script src="http://gist.github.com/233367.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The show pages are handled with a &lt;a href="http://api.rubyonrails.org/classes/ActionController/PolymorphicRoutes.html#M000487"&gt;polymorphic_path&lt;/a&gt;.&lt;br /&gt;&lt;script src="http://gist.github.com/233372.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The actual user creation and login steps are handled here. &lt;br /&gt;&lt;script src="http://gist.github.com/233375.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The secret is validated with:&lt;br /&gt;&lt;script src="http://gist.github.com/233370.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;All of the coded can be found at &lt;a href="http://github.com/perry3819/mysecrets"&gt;http://github.com/perry3819/mysecrets&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-9152500216786820942?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/9152500216786820942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=9152500216786820942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/9152500216786820942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/9152500216786820942'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/11/mysecrets-cucumber-pickle-rspec.html' title='MySecrets'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-2944182372418181016</id><published>2009-11-12T18:46:00.004-06:00</published><updated>2009-11-26T08:46:45.498-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Gem'/><title type='text'>pwfoo - Ruby Gem</title><content type='html'>&lt;a href="http://github.com/perry3819/pwfoo"&gt;pwfoo&lt;/a&gt; is a gemcutter.org hosted gem that I developed to generate random passwords, score the strength of passwords, and generate random seeds.&lt;br /&gt;&lt;br /&gt;Generate password&lt;br /&gt;&lt;script src="http://gist.github.com/233456.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Determine password strength&lt;br /&gt;&lt;script src="http://gist.github.com/233460.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://github.com/perry3819/pwfoo/blob/master/lib/pwfoo/srand_seed_generator.rb"&gt;SrandSeedGenerator&lt;/a&gt; is interesting because it uses the current time and currently running processes to generate random seeds.&lt;br /&gt;&lt;script src="http://gist.github.com/233465.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/perry3819/pwfoo"&gt;pwfoo&lt;/a&gt; can be installed from gemcutter.org.&lt;br /&gt;&lt;script src="http://gist.github.com/233466.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-2944182372418181016?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/2944182372418181016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=2944182372418181016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2944182372418181016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2944182372418181016'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/11/pwfoo-ruby-gem.html' title='pwfoo - Ruby Gem'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-8796628997503963755</id><published>2009-10-28T21:38:00.005-05:00</published><updated>2009-11-26T08:47:14.276-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>NHibernate Optimization - Part 2 - Data Access Object (DAO)</title><content type='html'>In the first post on NHibernate Optimization, mapping file configuration was discussed. This post will focus on code optimization in data access objects (DAOs).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Load objects by ID.&lt;/b&gt;&lt;br /&gt;Object should be loaded by ID whenever possible to benefit from first-level cache (session cache)&lt;b&gt;. &lt;/b&gt;Whenever an object is saved or loaded it is added to NHibernate's first-level cache with the ID as the key. As a reminder when NHibernate loads an object, it first looks in the first-level cache, then query cache, followed by second-level cache and finally SQL is executed. Therefore, loading an object by ID will be very quick if it is already in first-level cache.&lt;br /&gt;&lt;br /&gt;Sometimes the UI layer needs to request an object with a business key rather than a &lt;a href="http://en.wikipedia.org/wiki/Surrogate_key"&gt;surrogate key&lt;/a&gt;. In this case, a thread-safe Dictionary with key=&lt;b&gt;business key&lt;/b&gt; and value=&lt;b&gt;surrogate key&lt;/b&gt; should be considered. The UI layer requests the object by business key from the service layer. The service layer finds the surrogate key in the Dictionary and uses it to query the DAO. This is a little extra work, but&amp;nbsp; can reap appreciable performance benefits.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Use HQL, DTOs, and/or hand-coded ADO.NET in bottlenecks.&lt;/b&gt; &lt;br /&gt;Oftentimes the UI layer presents a screen that summarizes the state of many different objects, which can force many separate and expensive database calls that return much more data that is actually necessary. A good way to optimize this is to use HQL or hand-coded ADO.NET to SELECT only the required data, using aggregate functions if necessary, and return the data in a non-hibernate mapped data transfer object (DTO).&lt;br /&gt;&lt;br /&gt;This post scratched the surface of code optimizations in the data access layer. Please stand by for upcoming code optimization recommendations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-8796628997503963755?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/8796628997503963755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=8796628997503963755' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/8796628997503963755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/8796628997503963755'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/10/nhibernate-optimization-part-2-data.html' title='NHibernate Optimization - Part 2 - Data Access Object (DAO)'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-3599938527014234458</id><published>2009-10-26T13:41:00.017-05:00</published><updated>2009-11-26T08:47:43.960-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Interval Rails Caching</title><content type='html'>&lt;a href="http://feedpoint.hertler.org/"&gt;Feedpoint&lt;/a&gt; (&lt;a href="http://github.com/perry3819/feedpoint"&gt;source&lt;/a&gt;) is a blog aggregator written with Ruby on Rails deployed on a linux server. It retrieves RSS content from blogs and displays them sorted by date at &lt;a href="http://feedpoint.hertler.org/"&gt;http://feedpoint.hertler.org&lt;/a&gt;. Retrieving the RSS content is an expensive step and caching is needed to speed up HTTP requests. Google searching for a way to expire page caching on a timed interval did not yield promising results so I developed a very easy custom strategy through the use of Linux &lt;a href="http://www.linuxhelp.net/guides/cron/"&gt;cron&lt;/a&gt; jobs.&lt;br /&gt;&lt;br /&gt;The Rails code for the page caching is in &lt;a href="http://github.com/perry3819/feedpoint/blob/master/app/controllers/home_controller.rb"&gt;home_controller.rb&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/233309.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;caches_page &lt;/b&gt;and &lt;b&gt;expire_page&amp;nbsp; &lt;/b&gt;are  &lt;a href="http://api.rubyonrails.org/classes/ActionController/Caching/Pages/ClassMethods.html"&gt;ActionController&lt;/a&gt; methods. &lt;b&gt;caches_page &lt;/b&gt;caches the  the &lt;b&gt;:index &lt;/b&gt;and &lt;b&gt;:planet_redpoint&lt;/b&gt; actions and &lt;b&gt;expire_page &lt;/b&gt;expires them.&lt;br /&gt;&lt;br /&gt;With this setup, http://feedpoint.hertler.org/home/&lt;b&gt; &lt;/b&gt;will load the &lt;b&gt;:index &lt;/b&gt;into page cache and http://feedpoint.hertler.org/home/expire_cache will expire the cache. At this point, monkeys could be &lt;a href="http://www.ehow.com/how_2056641_train-pet-monkey.html"&gt;trained&lt;/a&gt; to navigate to the &lt;b&gt;expire_cache&lt;/b&gt; URL every ten minutes or a cron job could be set up. This post will focus on setting up the cron job.&lt;br /&gt;&lt;br /&gt;The cron job was configured by entering  &lt;b&gt;crontab -e&lt;/b&gt; from a terminal and then adding the following line:&lt;br /&gt;&lt;script src="http://gist.github.com/233316.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;This job uses &lt;a href="http://curl.haxx.se/"&gt;cURL&lt;/a&gt; to call the &lt;b&gt;expire_page &lt;/b&gt;action every ten minutes. &lt;a href="http://www.google.com/search?hl=en&amp;amp;client=firefox-a&amp;amp;rls=org.mozilla%3Aen-US%3Aofficial&amp;amp;hs=DtU&amp;amp;q=cron+tutorial&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi="&gt;Good cron tutorials&lt;/a&gt; are all over the web and beyond the scope of this post.&lt;br /&gt;&lt;br /&gt;One added benefit of this approach is that if a blogger is anxious for a recently posted blog to show up on the world famous http://feedpoint.hertler.org site, it can manually be refreshed right away!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-3599938527014234458?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/3599938527014234458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=3599938527014234458' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3599938527014234458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3599938527014234458'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/10/interval-rails-caching.html' title='Interval Rails Caching'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-2527893837111104024</id><published>2009-10-26T09:31:00.003-05:00</published><updated>2009-11-26T08:48:19.896-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>NHibernate Optimization - Part 1 - Mapping Files</title><content type='html'>NHibernate is a powerful object/relational persistence and query service that has deep market penetration in the Java space and is rapidly gaining acceptance in the .Net community. NHibernate is particular beneficial to domain-driven projects as developers can focus on good OO&amp;nbsp;design and have the database automatically generated from the domain model. Since developers are focused on classes and not tables, performance can suffer because little thought is given to how SQL is generated and executed.&amp;nbsp;This is the first post in a series that will focus on strategies to monitor performance, best practices, and optimizing N/Hibernate code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Problem&lt;/b&gt;&lt;br /&gt;Improper data access code and/or hibernate mapping files can cause NHibernate to execute inefficient queries, execute the same queries over and over, and/or retrieve much more data than needed. The three main areas of concern when dealing with Nhibernate performance are the mapping files, data access objects (DAOs), and monitoring/profiling tools.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Mapping file optimization&lt;/b&gt;&lt;br /&gt;Improper fetch strategies are the most common mistakes in Nhibernate mapping files. Many times developers simply copy and paste an existing mapping file and just change the table and column names without giving any thought to fetching strategies used. &lt;i&gt;&lt;span style="text-decoration: none;"&gt;As a general rule, &lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="text-decoration: none;"&gt;&lt;b&gt;lazy &lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="text-decoration: none;"&gt;&lt;span style="font-weight: normal;"&gt;associations should be used by default because no matter what fetching strategy is used, non-lazy relationships will be fully loaded into memory executing SQL queries if necessary.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="font-style: normal;"&gt;&lt;span style="text-decoration: none;"&gt;&lt;span style="font-weight: normal;"&gt;The Nhibernate developer should read and understand the &lt;a href="http://www.blogger.com/%20https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/#performance-fetching-custom"&gt;fetching strategy section&lt;/a&gt; of the reference documentation. &lt;a href="https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/#performance-fetching-batch"&gt;Batch fetching&lt;/a&gt; and &lt;a href="https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/#performance-fetching-subselect"&gt;subselect fetching&lt;/a&gt; can significantly reduce the number of SQL queries executed.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="text-decoration: none;"&gt;&lt;span style="font-weight: normal;"&gt;Another mapping element that can speed up the NHibernate application is &lt;a href="https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/#performance-cache"&gt;second-level caching&lt;/a&gt;. A good idea for all applications is to enable &lt;b&gt;read-only &lt;/b&gt;cache on "look-up" data that never changes. &lt;b&gt;Nonstrict-read-write&lt;/b&gt; works well for objects that are mostly read and seldom written. More on caching will follow in upcoming posts.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="text-decoration: none;"&gt;&lt;span style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="text-decoration: none;"&gt;&lt;span style="font-weight: normal;"&gt;In summary, use lazy associations by default, choose the write fetching strategy, and include second-level caching when appropriate.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-2527893837111104024?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/2527893837111104024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=2527893837111104024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2527893837111104024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2527893837111104024'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/10/nhibernate-optimization-part-1-mapping.html' title='NHibernate Optimization - Part 1 - Mapping Files'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-921056272426445128</id><published>2009-10-23T10:39:00.003-05:00</published><updated>2009-10-23T15:42:18.365-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>chroot sftp for blogger.com Tutorial</title><content type='html'>I use blogger.com to author and publish this blog. After clicking the&lt;b&gt; PUBLISH POST &lt;/b&gt;button, blogger.com moves the post to hertler.org, which means that I need to give blogger.com access to my server.&lt;br /&gt;&lt;br /&gt;To do this securely, I only allow blogger.com access to hertler.org through &lt;a href="http://en.wikipedia.org/wiki/SFTP"&gt;SFTP&lt;/a&gt; and I &lt;a href="http://en.wikipedia.org/wiki/Chroot"&gt;chroot&lt;/a&gt; the blogger.com user to /home/blogger so that only blog files are permitted to be updated. I set this up on my &lt;a href="http://www.ubuntu.com/"&gt;ubuntu&lt;/a&gt; virtual machine through &lt;a href="http://hostingrails.com/"&gt;hostingrails.com&lt;/a&gt;, which by the way is a fantastic hosting provider. &lt;br /&gt;&lt;br /&gt;Here are the steps to chroot blogger.com:&lt;br /&gt;1) Verify that you have an OpenSSH &amp;gt;= 4.9. Update OpenSSH if needed.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;root@web1:/# ssh -V&lt;br /&gt;OpenSSH_5.1p1 Debian-3ubuntu1, OpenSSL 0.9.8g 19 Oct 2007&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;2) Create the blogger.com user and change the owner and group of its home directory to &lt;b&gt;root&lt;/b&gt;.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;root@web1:/# /usr/sbin/useradd blogger&lt;br /&gt;root@web1:/# passwd blogger   &lt;br /&gt;root@web1:/# chown -R root.root /home/blogger&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;3) Edit &lt;b&gt;/etc/ssh/sshd_config&lt;/b&gt; to set up the chroot.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Subsystem sftp internal-sftp&lt;br /&gt;Match user blogger&lt;br /&gt;      ChrootDirectory /home/blogger&lt;br /&gt;      AllowTcpForwarding no&lt;br /&gt;      ForceCommand internal-sftp&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Be sure to &lt;b&gt;delete&lt;/b&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Subsystem sftp /usr/lib/openssh/sftp-server. &lt;/span&gt;More information on &lt;br /&gt;&lt;br /&gt;4) Restart ssh.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;/etc/init.d/ssh restart&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;5) Verify that you can sftp in with the blogger user and that the root directory for the user is &lt;b&gt;/home/blogger&lt;/b&gt;.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;perry-hertlers-mac-pro:~ perry$ sftp blogger@hertler.org&lt;br /&gt;Connecting to hertler.org...&lt;br /&gt;blogger@hertler.org's password: &lt;br /&gt;sftp&amp;gt; pwd&lt;br /&gt;Remote working directory: /&lt;br /&gt;sftp&amp;gt; ls&lt;br /&gt;testfileinbloggerhomedir.txt           &lt;br /&gt;sftp&amp;gt; &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;OK, now we have the chrooted sftp access for blogger set up, but we still need to server those files on the web site. We can simply set up a symbolic link to &lt;b&gt;/home/blogger&lt;/b&gt; from our virtual host directory. &lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;root@web1:/# ln -s /home/blogger /var/www/blog.hertler.org/current&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Now we are securely giving blogger.com sftp access to our web server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-921056272426445128?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/921056272426445128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=921056272426445128' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/921056272426445128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/921056272426445128'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/10/chroot-sftp-for-bloggercom-tutorial.html' title='chroot sftp for blogger.com Tutorial'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-1368324522681223416</id><published>2009-08-14T12:43:00.004-05:00</published><updated>2009-10-15T20:11:09.440-05:00</updated><title type='text'>britetab.com</title><content type='html'>I started working on a new project last week for britetab.com. which allows one to create and share resumes using custom images, photos, and videos.&lt;br /&gt;&lt;br /&gt;My &lt;a href="http://www.britetab.com/ilab/resume/view?token=W3SYv4FCjBOCVBk4vvyoG7WT2Z0%3D"&gt;britetab resume&lt;/a&gt;, shows just a few of the available features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-1368324522681223416?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/1368324522681223416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=1368324522681223416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/1368324522681223416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/1368324522681223416'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/08/britetabcom.html' title='britetab.com'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-9067377218325974283</id><published>2009-08-10T12:38:00.003-05:00</published><updated>2009-08-10T13:22:02.935-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Install mysql gem on OS X 10.5</title><content type='html'>I had a little trouble installing the mysql gem on OS X 10.5 this morning so I thought I would post the solution.&lt;br /&gt;&lt;br /&gt;1) Download the mysql binaries from apple http://support.apple.com/kb/TA25017?viewlocale=en_US&lt;br /&gt;2) Unpack the binaries.&lt;br /&gt;3) &lt;span style="font-weight:bold;"&gt;sudo gem install mysql -- --with-mysql-config=&lt;unpack-dir&gt;/usr/bin/mysql_config (be sure to give an absolute path to the config file)&lt;/span&gt;&lt;br /&gt;4) done&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-9067377218325974283?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/9067377218325974283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=9067377218325974283' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/9067377218325974283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/9067377218325974283'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/08/install-mysql-gem-on-os-x-105.html' title='Install mysql gem on OS X 10.5'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-6362645234858078145</id><published>2009-08-10T11:28:00.014-05:00</published><updated>2009-11-06T11:03:14.453-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Feedpoint - Rails Blog Aggregator</title><content type='html'>I finished up the 0.1 release of &lt;a href="http://github.com/perry3819/feedpoint"&gt;feedpoint&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Feedpoint is a blog aggregator. Companies may find it useful for showcasing blogs of its employees.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So far, the whole application is written with &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;. Additional front-end frameworks are planned including &lt;a href="http://javafx.com/"&gt;JavaFX&lt;/a&gt; and &lt;a href="http://silverlight.net/"&gt;Silverlight&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Privileged users may add new feeds through a web interface. &lt;/div&gt;&lt;br /&gt;&lt;img src='http://hertler.org/images/newfeed.png'/&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The &lt;a href='http://redpointtech.com/Redpoint/blogs/'&gt;main&lt;/a&gt; screen displays all of the posts sorted by date.&lt;/div&gt;&lt;br /&gt;&lt;a href='http://hertler.org/images/feedpoint.png'&gt;&lt;br /&gt;&lt;img width=600 src='http://hertler.org/images/feedpoint.png'/&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-6362645234858078145?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/6362645234858078145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=6362645234858078145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/6362645234858078145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/6362645234858078145'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/08/feedpoint-rails-blog-aggregator.html' title='Feedpoint - Rails Blog Aggregator'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-8153054503560120536</id><published>2009-07-24T13:43:00.005-05:00</published><updated>2009-07-24T14:08:00.489-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TFS'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>TFS - Stop and Start Server</title><content type='html'>After some failed attempts at stopping and starting servers through third party tasks, I had quick success using the exec command in the &lt;b&gt;TFSBuild.proj&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:js"&gt;&lt;br /&gt;&amp;lt;PropertyGroup&gt;&lt;br /&gt;    &amp;lt;web-site-id&gt;1&amp;lt;/web-site-id&gt;&lt;br /&gt;    &amp;lt;server-cmd-prefix&gt;C:\Windows\system32\cscript.exe c:\Inetpub\AdminScripts\adsutil.vbs&amp;lt;/server-cmd-prefix&gt;&lt;br /&gt;    &amp;lt;stop-server-cmd-line&gt;$(server-cmd-prefix) STOP_SERVER W3SVC/$(web-site-id)&amp;lt;/stop-server-cmd-line&gt;&lt;br /&gt;    &amp;lt;start-server-cmd-line&gt;$(server-cmd-prefix) START_SERVER W3SVC/$(web-site-id)&amp;lt;/start-server-cmd-line&gt;&lt;br /&gt; &amp;lt;/PropertyGroup&gt;&lt;br /&gt;  &lt;br /&gt; &amp;lt;Target Name="StopSite"&gt;&lt;br /&gt;    &amp;lt;Message Text="stopping site..."/&gt;&lt;br /&gt;    &amp;lt;Exec Command="$(stop-server-cmd-line)"/&gt;&lt;br /&gt; &amp;lt;/Target&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;Target Name="StartSite"&gt;&lt;br /&gt;    &amp;lt;Message Text="starting site..."/&gt;&lt;br /&gt;    &amp;lt;Exec Command="$(start-server-cmd-line)"/&gt;&lt;br /&gt; &amp;lt;/Target&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;To find the &lt;b&gt;web-site-id, &lt;/b&gt;refer to &lt;a href="http://weblogs.asp.net/owscott/archive/2005/07/29/how-to-find-the-siteid-in-iis5-and-iis6.aspx"&gt;Scott Forsyth's Blog&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-8153054503560120536?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/8153054503560120536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=8153054503560120536' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/8153054503560120536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/8153054503560120536'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/07/tfs-stop-and-start-server.html' title='TFS - Stop and Start Server'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-5428811969066897691</id><published>2009-07-20T11:24:00.017-05:00</published><updated>2009-11-06T11:24:52.280-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='openssl'/><title type='text'>AES Encryption Wrapper for Ruby</title><content type='html'>I thought I would share my &lt;a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard"&gt;AES encryption&lt;/a&gt; wrapper for Ruby. The attached code utilizes &lt;a href="http://www.openssl.org/"&gt;openssl&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;openssl&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;AESCrypt&lt;/span&gt;&lt;br /&gt;  &lt;span class="constant"&gt;DEFAULT_CIPHER_TYPE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;aes-256-cbc&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;  &lt;span class="constant"&gt;CRYPT_STRUCT&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Struct&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:encrypted_data&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:iv&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;AESCrypt.encrypt&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;plain_text&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;opts&lt;/span&gt;&lt;span class="punct"&gt;={})&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;OpenSSL&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Cipher&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;DEFAULT_CIPHER_TYPE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;encrypt&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;opts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;reverse_merge!&lt;/span&gt; &lt;span class="symbol"&gt;:key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;random_key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:iv&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;random_iv&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;random_key&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;opts&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:key&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iv&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;random_iv&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;opts&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:iv&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;encrypted_data&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;update&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;plain_text&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;encrypted_data&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;final&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;CRYPT_STRUCT&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;encrypted_data&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;random_key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;random_iv&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;AESCrypt.decrypt&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;crypt_struct&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;OpenSSL&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Cipher&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;DEFAULT_CIPHER_TYPE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;decrypt&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;crypt_struct&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iv&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;crypt_struct&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iv&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;update&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;crypt_struct&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;encrypted_data&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;cipher&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;final&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  white-space: normal; font-family:Georgia, fantasy;font-size:16px;"&gt;This code is pretty straightforward. One thing of interest is that we are using a random AES key and initialization vector on lines &lt;strong&gt;10&lt;/strong&gt; and &lt;strong&gt;11&lt;/strong&gt; respectively. This results in consumers of this API needing to store the key and initialization vector in order to &lt;strong&gt;decrypt&lt;/strong&gt;, which is why a &lt;strong&gt;CRYPT_STRUCT&lt;/strong&gt; is returned on line &lt;strong&gt;14&lt;/strong&gt;. &lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  white-space: normal; font-family:Georgia, fantasy;font-size:16px;"&gt;The &lt;a href="http://github.com/perry3819/my_password_manager/blob/master/lib/aes_crypt.rb"&gt;source&lt;/a&gt; and &lt;a href="http://github.com/perry3819/my_password_manager/blob/master/test/unit/lib/aes_crypt_test.rb"&gt;test&lt;/a&gt; files are available at the &lt;a href='http://github.com/perry3819/my_password_manager'&gt;my_password_manager&lt;/a&gt; github site.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-5428811969066897691?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/5428811969066897691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=5428811969066897691' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/5428811969066897691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/5428811969066897691'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/07/aes-encryption-wrapper-for-ruby.html' title='AES Encryption Wrapper for Ruby'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-3512618732046794589</id><published>2009-07-13T16:17:00.010-05:00</published><updated>2009-12-01T16:07:33.471-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>When is "last"?</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;One of the &lt;a href="http://en.wikipedia.org/wiki/Extreme_Programming"&gt;extreme programming&lt;/a&gt; rules is &lt;a href="http://www.extremeprogramming.org/rules/optimize.html"&gt;Optimize Last&lt;/a&gt;. The rule is stated as&lt;br /&gt;&lt;div&gt;&lt;span style="font-family: Times; font-size: medium;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family: Times; font-size: medium;"&gt;Do not optimize until the end. Never try to guess what the system's bottle neck will be. Measure it!&lt;br /&gt;Make it work, make it right, then make it fast. &lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;When is "last"? Is it one week before the application goes into production, at the end of an iteration, at the end of the story, or at the end of a pairing session?&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another question: what and how much should be optimized?&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Though the answers to these questions may very a little from project to project, in my experience "last" should mean both at the end of the stories and end of iteration and just the &lt;b&gt;bottlenecks&lt;/b&gt; should be optimized with the aid of a profiling tool.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Optimization strategy:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Obtain non-functional performance requirements for the system very early in the project.&lt;/b&gt; If there is know target, are we not wasting our time optimizing? By the way, "as fast as possible" is &lt;i&gt;not&lt;/i&gt; a sufficient requirement.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Set up automated performance tests.&lt;/b&gt; You may even want to go as far a having it run as part of your continuous integration build and having the build fail if certain performance thresholds are not met. &lt;/li&gt;&lt;li&gt;&lt;b&gt;Near the end of story completion, profile the new code.&lt;/b&gt; I use ANTS Profiler for C# and JProfiler for Java. Obvious bottlenecks with minimal code changes for optimization should be implemented without hesitation. Continue to fix bottlenecks until the application is meeting its performance requirements.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Near the end of the iteration, profile the whole application. &lt;/b&gt;Consider having team members rotate through application-wide optimization responsibilities every iteration.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-3512618732046794589?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/3512618732046794589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=3512618732046794589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3512618732046794589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3512618732046794589'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/07/when-is-last.html' title='When is &quot;last&quot;?'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-3259940037749479447</id><published>2009-07-07T11:23:00.005-05:00</published><updated>2009-07-07T11:43:28.519-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><title type='text'>Selling Agile Development Practices to Your Manager</title><content type='html'>There have been some comments that some of you developers are very interested in adopting agile development practices, but your manager isn't seeing the benefit.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are two important points to make to your manager.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Incremental development practices prevent defects and catch them early&lt;/li&gt;&lt;li&gt;The cost of a defect drastically goes up the further along it is in the project life cycle&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Incremental development practices are geared around preventing defects and catching them early with comprehensive tests, frequent integration, and knowledge sharing. Take a look at my &lt;a href="http://hertler.org/docs/IncrementalDevelopmentPractices.ppt"&gt;Incremental Development Presentation&lt;/a&gt; for more information.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A simple &lt;a href="http://www.google.com/search?hl=en&amp;amp;client=opera&amp;amp;rls=en&amp;amp;q=cost+software+defects&amp;amp;btnG=Search"&gt;google search&lt;/a&gt; yields a lot of evidence to support the high cost of defects. The cost of defects relative to project life-cycle looks a lot like the image below.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;img src="http://hertler.org/docs/defect-cost.jpg"  height="400" width="600"/&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-3259940037749479447?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/3259940037749479447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=3259940037749479447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3259940037749479447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3259940037749479447'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/07/selling-agile-development-practices-to.html' title='Selling Agile Development Practices to Your Manager'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-1529315478791594099</id><published>2009-07-06T15:29:00.003-05:00</published><updated>2009-07-06T15:43:34.130-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance'/><title type='text'>The Multi-core Problem</title><content type='html'>If you don't have any experience with functional programming languages, do yourself a favor and take the time to watch this &lt;a href="http://www.infoq.com/presentations/joe-armstrong-erlang-qcon08"&gt;presentation&lt;/a&gt; by Joe Armstrong who is the &lt;a href="http://erlang.org/"&gt;Erlang&lt;/a&gt; programming language creator.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One of the main points that Mr. Armstrong makes is that as time goes on&lt;b&gt; sequential programs will get slower&lt;/b&gt; because they do not utilize more than one &lt;a href="http://en.wikipedia.org/wiki/Multi-core"&gt;core&lt;/a&gt; and current trends are to have &lt;b&gt;more and slower cores &lt;/b&gt;to reduce power consumption&lt;b&gt;.&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Functional programming languages like &lt;a href="http://erlang.org/"&gt;Erlang&lt;/a&gt; can utilize as many cores as necessary because there is no mutable state, there is no shared memory, and actors are completely isolated.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-1529315478791594099?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/1529315478791594099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=1529315478791594099' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/1529315478791594099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/1529315478791594099'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/07/multi-core-problem.html' title='The Multi-core Problem'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-8729046955983686021</id><published>2009-07-06T14:51:00.003-05:00</published><updated>2009-07-06T15:01:37.793-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>FirstMem - a tool for verbatim text memorization</title><content type='html'>I have recently spent some time learning &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; and &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt;. When I learn a new language I typically write an easy application so that the focus is not on solving a particularly difficult problem, but on learning the new technology.  To learn &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;, I wrote &lt;a href="http://firstmem.hertler.org"&gt;http://firstmem.hertler.org&lt;/a&gt;. The code is hosted at &lt;a href="http://code.google.com/p/firstmem/"&gt;http://code.google.com/p/firstmem/&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://code.google.com/p/firstmem/"&gt;&lt;/a&gt;As I was writing the code I was constantly shocked at how little code it took to perform complex tasks and how easy the Rails framework is to learn. It almost felt like cheating!&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-8729046955983686021?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/8729046955983686021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=8729046955983686021' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/8729046955983686021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/8729046955983686021'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/07/firstmem-tool-for-verbatim-text.html' title='FirstMem - a tool for verbatim text memorization'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-287804318211942584</id><published>2009-06-12T13:50:00.003-05:00</published><updated>2009-06-12T13:59:03.080-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><title type='text'>Hudson Client for iPhone</title><content type='html'>I was planning on using &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; for CI anyway on my next project, but now &lt;a href="http://greensopinion.blogspot.com/2009/05/hudson-helper-hudson-on-your-iphone.html"&gt;Hudson Helper&lt;/a&gt; is making me really impatient!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-287804318211942584?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/287804318211942584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=287804318211942584' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/287804318211942584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/287804318211942584'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/06/hudson-on-iphone.html' title='Hudson Client for iPhone'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-5766389283965582579</id><published>2009-06-12T08:29:00.004-05:00</published><updated>2009-06-12T08:46:25.556-05:00</updated><title type='text'>Sweet Spot</title><content type='html'>Bud Caddell constructed an interesting venn diagram and &lt;a href="http://whatconsumesme.com/2009/what-im-writing/how-to-be-happy-in-business-venn-diagram/"&gt;posted&lt;/a&gt; it on his &lt;a href="http://whatconsumesme.com/"&gt;blog&lt;/a&gt;. This motivated me to think about where I am right now in my career. I am probably in the region where &lt;b&gt;What we do well&lt;/b&gt; and &lt;b&gt;What we can be paid to do&lt;/b&gt; intersect, but probably not entirely in &lt;b&gt;What we want to do&lt;/b&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is normal for me. Throughout my career, I have constantly sought to learn new technologies and paradigms  in my spare time and then utilize those skills professionally. This whole cycle occurs for me usually in less than a year. Right now, I am rapidly coming up to speed in functional programming languages because of not only their elegance, but the multi-core utilization problem they solve (more on this to follow).  Functional programming is &lt;b&gt;What I want to do&lt;/b&gt; and is probably &lt;b&gt;What I can be paid to do&lt;/b&gt;,  but is not yet something &lt;b&gt;I can do well&lt;/b&gt; so I need to &lt;b&gt;Learn more&lt;/b&gt;. I'm working on it....&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://blog.hertler.org/uploaded_images/budcaddell-780650.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://blog.hertler.org/uploaded_images/budcaddell-780647.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-5766389283965582579?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/5766389283965582579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=5766389283965582579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/5766389283965582579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/5766389283965582579'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/06/sweet-spot.html' title='Sweet Spot'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-2449085146415524094</id><published>2009-05-30T09:13:00.006-05:00</published><updated>2009-06-01T16:00:00.537-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TDD in the Real World Slides</title><content type='html'>&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); text-decoration: underline;"&gt;&lt;a href="http://hertler.org/docs/tddRealWorld.ppt"&gt;Here&lt;/a&gt;&lt;/span&gt;&lt;a href="http://hertler.org/docs/tddRealWorld.ppt"&gt; &lt;/a&gt;are the TDD in the Real World slides for the &lt;a href="http://www.chicagocodecamp.com/"&gt;Chicago Code Camp&lt;/a&gt; presentation that I gave on May 30th.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-2449085146415524094?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/2449085146415524094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=2449085146415524094' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2449085146415524094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2449085146415524094'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/05/tdd-in-real-world-slides.html' title='TDD in the Real World Slides'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-5115708064603165449</id><published>2009-05-19T16:14:00.003-05:00</published><updated>2009-05-19T16:18:57.052-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Conference'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Chicago Code Camp</title><content type='html'>Be sure to attend &lt;a href="http://www.chicagocodecamp.com/"&gt;Chicago Code Camp&lt;/a&gt; on May 30th at the &lt;b&gt;&lt;a href="http://www.clcillinois.edu/"&gt;College of Lake County (CLC)&lt;/a&gt;&lt;/b&gt;, in Grayslake, IL.&lt;br /&gt;&lt;br /&gt;I will be doing a presentation entitled &lt;a href="http://www.chicagocodecamp.com/Sessions.html"&gt;TDD in the Real World&lt;/a&gt;. There will be a lot of real-time coding! It should be fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-5115708064603165449?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/5115708064603165449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=5115708064603165449' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/5115708064603165449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/5115708064603165449'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/05/chicago-code-camp.html' title='Chicago Code Camp'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-7082537801619056441</id><published>2009-02-23T09:26:00.009-06:00</published><updated>2009-03-20T14:09:15.807-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><title type='text'>Do The Simplest Thing That Could Possibly Work (DTSTTCPW)</title><content type='html'>&lt;p&gt;&lt;a href="http://c2.com/xp/YouArentGonnaNeedIt.html"&gt;DTSTTCPW&lt;/a&gt; means not writing code to "future requirements" and not implementing the current requirements in a fancy-overly-complicated-cool-sure-to-impress-peers manner. I am convinced that many designs are driven by how cool they would look in a power point presentation rather than pragmatism!&lt;/p&gt;&lt;p&gt;Some examples of DTSTTCPW violation include writing unnecessary reusable code, writing unneeded highly decoupled code, writing code that goes above and beyond requirements, and introducing a design pattern into the code with no immediate benefit (e.g. strategy pattern with only one strategy). The remainder of this blog entry will focus on writing unnecessary reusable code as this is the most common mistake.&lt;/p&gt;&lt;p&gt;On a recent project, we were losing a lot of time trying to integrate with an unsupported web service. Up to seven people were involved from different sides of the planet. I started asking questions like 1) what does the web service do? 2) where does it get its data? 3) what business logic does it perform? It turns out that the web service was just executing a stored procedure and performing no business logic. Even worse, the stored procedure what local to our application's database!&lt;/p&gt;&lt;p&gt;Apparently the motivation was that at some point in the future other applications would potentially reuse this web service. Many readers of this might think that this is smart because someone was planning for the future. Most people have been in meetings or peer reviews where a developer is congratulated on his forward thinking for implementing a highly reusable design. Only a few years ago, I would have been impressed, too. Now, ......not so much. The reasons:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Reusablity comes at a high cost&lt;/strong&gt; -  Implementing requirements in a way that takes into account other  uses requires a lot of brainstorming and iterations to get right.&lt;/li&gt;&lt;li&gt;&lt;a href="http://c2.com/xp/YouArentGonnaNeedIt.html"&gt;You are not going to need&lt;/a&gt; the reusability anyway. Writing from  experience, these sure to happen future requirements seldom happen.  In lean terms, reusability provides no value to the customer. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;Added complexity&lt;/strong&gt; - necessarily, a  reusable design requires more complexity and probably more lines of  code. This results in not only higher up front costs, but higher&lt;br /&gt; maintenance costs.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Common objections:&lt;/p&gt;&lt;p&gt;&lt;em&gt;Yeah, but I once wrote this  reusable code that was used by many other developers on a wide variety of applications!&lt;/em&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How many times did you write reusable code that wasn't reused?&lt;/li&gt;&lt;li&gt;How much did the reusable code cost the customer?&lt;/li&gt;&lt;li&gt;Did the customer benefit from the reusable code or just people within your organization, team, or department?&lt;/li&gt;&lt;li&gt;Were other teams forced to use your code even though it didn't really meet their requirements?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;Sometimes DTSTTCPW results in poor performance or non-functional requirements not being satisfied.&lt;/em&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Then you did not DTSTTCPW. Instead you DTSTT. Non-functional requirements need to be taken into account when deciding on the simplest thing that could possibly work.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-7082537801619056441?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/7082537801619056441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=7082537801619056441' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/7082537801619056441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/7082537801619056441'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2009/02/do-simplest-thing-that-could-possibly.html' title='Do The Simplest Thing That Could Possibly Work (DTSTTCPW)'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-6690353462820841384</id><published>2008-11-26T12:04:00.013-06:00</published><updated>2008-11-27T06:48:43.423-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='OO'/><title type='text'>Favor Composition Over Inheritance</title><content type='html'>Put another way, favor "has-a" over "is-a" relationships.&lt;br /&gt;&lt;br /&gt;What's so bad about inheritance?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Subclasses are tightly coupled to their base classes.  Many times subclasses make assumptions about the context in which a method it overrides is getting called, which means that small implementation changes in the base class can produce unexpected behavior.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Dependencies of the subclass are hard-wired making unit testing difficult. One cannot mock a base class of a subclass.&lt;/li&gt;&lt;/ul&gt;It is definitely fine to inherit from interfaces; it's the concrete implementations that cause all of the problems.&lt;br /&gt;&lt;br /&gt;An added benefit of composition relationships is that behavior can be changed at run-time (&lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;Strategy Pattern&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-6690353462820841384?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/6690353462820841384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=6690353462820841384' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/6690353462820841384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/6690353462820841384'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2008/11/favor-composition-over-inheritance.html' title='Favor Composition Over Inheritance'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-4270790712417342850</id><published>2008-11-11T15:06:00.011-06:00</published><updated>2008-11-14T15:20:40.390-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Pair-Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><title type='text'>A(nother) Case for Pair-Programming</title><content type='html'>The benefits of pair-programming include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Faster&lt;br /&gt;&lt;li&gt;Fewer bugs&lt;br /&gt;&lt;li&gt;Higher quality code (continuous peer review and brainstorming)&lt;br /&gt;&lt;li&gt;Shared understanding of code-base&lt;br /&gt;&lt;li&gt;Can learn from partner&lt;br /&gt;&lt;li&gt;Better design&lt;br /&gt;&lt;li&gt;Team building&lt;br /&gt;&lt;li&gt;Higher confidence in code&lt;br /&gt;&lt;li&gt;Higher satisfaction&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Scheduling problems (developer schedules are different)&lt;br /&gt;&lt;li&gt;Personality conflicts&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Most studies show that a pair is 40 to 80% faster than an individual, which means that two individuals are faster than a pair. However, the resultant code is higher quality in that it has a better design and fewer bugs. It has been extensively &lt;a href="http://www.google.com/search?hl=en&amp;client=opera&amp;rls=en&amp;q=cost+software+defects&amp;btnG=Search"&gt;documented&lt;/a&gt; that the cost and time it takes to fix bugs found by testers or customers is many times larger than the cost of the originally written code, which effectively means that over the whole project life-cycle pair-programming is &lt;i&gt;faster&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Scheduling problems can be solved, but personality conflicts can be a real problem. A good pair programmer leaves his/her ego at the door, is flexible, and most importantly communicates well. One mitigation strategy is to frequently rotate pairs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-4270790712417342850?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/4270790712417342850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=4270790712417342850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/4270790712417342850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/4270790712417342850'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2008/11/case-for-pair-programming.html' title='A(nother) Case for Pair-Programming'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-2773671480468684558</id><published>2008-11-03T09:44:00.003-06:00</published><updated>2008-11-11T15:39:59.424-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mock'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Testable Code</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;One of the best ways to ensure testable code is practice Test Driven Development. How can code not be testable if it is already tested?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Another good idea is to write code that is easy to test in isolation, which is mostly done by mocking its dependencies. "Mockable" classes are achieved with:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Injecting dependencies with an Inversion of Control framework such as &lt;a href='http://springframework.org'&gt;Spring&lt;/a&gt;&lt;br /&gt;    &lt;/li&gt;&lt;li&gt;Avoiding singleton and static methods&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Favoring composition over inheritance&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-2773671480468684558?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/2773671480468684558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=2773671480468684558' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2773671480468684558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/2773671480468684558'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2008/11/testable-code.html' title='Testable Code'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2292736096229539017.post-3256433117167040155</id><published>2008-10-24T15:50:00.002-05:00</published><updated>2008-11-11T15:40:25.185-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mock'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Mock Example</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Mock_Object"&gt;Mocking&lt;/a&gt; is a great way to test a class in isolation. Not only can determinisitic results of the mocked class be forced, but parameters to the mocked object's methods can be tested.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is a unit test that uses &lt;a href="http://code.google.com/p/mockito/"&gt;mockito&lt;/a&gt; as its mocking framework. It is organized in the increasingly  popular Arrange / Act / Assert format. This tests a yet to be written subclass of &lt;a href="http://www.springframework.org/"&gt;Spring's &lt;/a&gt;&lt;a href="http://static.springframework.org/spring-ws/docs/1.0-m2/api/org/springframework/ws/endpoint/AbstractJDomPayloadEndpoint.html"&gt;AbstractJDomPayloadEndpoint&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=" background-;color:Teal;"&gt;  1&lt;/span&gt; @Test&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  2&lt;/span&gt; &lt;span style=" ;color:Blue;"&gt;public&lt;/span&gt; &lt;span style=" ;color:Blue;"&gt;void&lt;/span&gt; validDepthOfField( ) &lt;span style=" ;color:Blue;"&gt;throws&lt;/span&gt; Exception {&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  3&lt;/span&gt;     stub( _depthOfFieldCalculator.calculateDepthOfField( _expectedDofParams ) ).toReturn( _depthOfField );&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  4&lt;/span&gt;&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  5&lt;/span&gt;     &lt;span style=" ;color:Blue;"&gt;final&lt;/span&gt; PhotoEndpoint photoEndpoint =&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  6&lt;/span&gt;         &lt;span style=" ;color:Blue;"&gt;new&lt;/span&gt; PhotoEndpoint( _depthOfFieldCalculator );&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  7&lt;/span&gt;     &lt;span style=" ;color:Blue;"&gt;final&lt;/span&gt; Element dofElem =&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  8&lt;/span&gt;         photoEndpoint.invokeInternal( _depthOfFieldRequest );&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt;  9&lt;/span&gt;       &lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 10&lt;/span&gt;     Assert.assertEquals( _depthOfField.getFarLimit(),&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 11&lt;/span&gt;             _parseDouble( dofElem, _farLimitExpression));&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 12&lt;/span&gt;     Assert.assertEquals( _depthOfField.getNearLimit(),&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 13&lt;/span&gt;             _parseDouble(dofElem, _nearLimitExpression));&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 14&lt;/span&gt;     Assert.assertEquals( _depthOfField.getHyperFocalDistance(),&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 15&lt;/span&gt;             _parseDouble(dofElem, _hyperFocusDistanceExpression));&lt;br /&gt;&lt;span style=" background-;color:Teal;"&gt; 16&lt;/span&gt; }&lt;/pre&gt;&lt;div&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;Line 3&lt;/span&gt;: &lt;/span&gt; &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;_depthOfFieldCalculator &lt;/span&gt;was mocked with mockito in JUnit's &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;@Before&lt;/span&gt;. If &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;calculateDepthOfField(...) &lt;/span&gt;is called with a object matching &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;_expectedDofParams&lt;/span&gt;(equals overridden), &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;_depthOfField &lt;/span&gt;will be returned. Important to note that if the  &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;calculateDepthOfField &lt;/span&gt;is called with the wrong parameter, the mock will return &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;null&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;Lines 5-6&lt;/span&gt;:&lt;/span&gt; Create a class that does not yet exist with our mock.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;Lines 7-8&lt;/span&gt;:&lt;/span&gt; Call the endpoint's invoke method that is under test.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;Lines 10-15&lt;/span&gt;:  &lt;span class="Apple-style-span" style="font-weight: normal; "&gt;Assert that the returned Element is valid.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2292736096229539017-3256433117167040155?l=blog.hertler.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/3256433117167040155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2292736096229539017&amp;postID=3256433117167040155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3256433117167040155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2292736096229539017/posts/default/3256433117167040155'/><link rel='alternate' type='text/html' href='http://blog.hertler.org/2008/10/mock-example.html' title='Mock Example'/><author><name>Perry Hertler</name><uri>http://www.blogger.com/profile/16787915862093216541</uri><email>perry@hertler.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='17408813592242887110'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>