<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CUcMRXw6eip7ImA9WhRaFE8.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821</id><updated>2012-02-16T21:11:24.212+01:00</updated><title>Mendelt Siebenga</title><subtitle type="html">Converting caffeine to code</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.mendeltsiebenga.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/MendeltSiebenga" /><feedburner:info uri="mendeltsiebenga" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DU8CRHwyeyp7ImA9WhdXGU0.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-8802016695244168202</id><published>2011-09-01T22:11:00.000+02:00</published><updated>2011-09-01T22:11:05.293+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-01T22:11:05.293+02:00</app:edited><title>Acer Iconia A500 review</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/U_9c-lFKA8bbWmNDe2jsoWcSSNk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/U_9c-lFKA8bbWmNDe2jsoWcSSNk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/U_9c-lFKA8bbWmNDe2jsoWcSSNk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/U_9c-lFKA8bbWmNDe2jsoWcSSNk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;A couple of weeks ago I bought an Android tablet, the Acer Iconia A500. Today I received an email from Acer asking to fill in a short survey to tell them what I like and don't like about my new tablet. I might as well share my thoughts on this tablet in a short review on my blog.&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;p&gt;The Acer Iconia is one of the first generation Android Honeycomb Tablets. The specs are pretty much&amp;nbsp;interchangeable. Dual core 1 GHz Tegra 2, 10 inch 1280 x 800 screen etc. Just like the Asus Eee Tab and the Samsung Galaxy Tab 10.1 and many other tablets that will probably follow. Instead lets look at what makes the Acer different from all these similar tablets. The tablet is available in a 16 and 32 Gb version and you can choose if you want it 3G enabled or if you just want to use Wifi. I went for the cheapest version with 16 Gig and no mobile internet.&lt;/p&gt;
&lt;p&gt;First lets look at the positives&lt;br /&gt;
The reason I went for the Acer is connectivity. Besides the standard connectors this tablet has a mini-HDMI connector and two USB ports, one for connecting to a computer and another one that can act as a USB host so you can connect a keyboard, a mouse or even external harddrives.&lt;br /&gt;
I'm not a big fan of proprietary skins on Android devices. I rooted my HTC Desire phone to get rid of Sense so another reason to choose the Acer is the version of Android installed on it. Apart from adding a couple of its own apps Acer hasn't changed a lot about the standard Honeycomb experience. This is the closest you can get to vanilla Honeycomb without rooting your tablet.&lt;br /&gt;
And last but not least I just like the way this tablet looks. The two dark metal strips along the longer sides make it stand out from other tablets. It looks and feels well made.
&lt;/p&gt;
&lt;p&gt;
Of course there are also a couple of minor issues with this tablet.&lt;br /&gt;
First of all there is Android itself. I got the tablet with Android 3.0 installed and even though the OS itself feels stable and responsive many of the applications that were preinstalled felt flaky. Especially the Android Market and the browser crashed a lot. With the update to 3.1 many of these problems were solved but the Android Browser is still very slow on pages with some javascript. I expected better from the company that made Chrome.&lt;br /&gt;
Another thing that irritates me is the power adapter. It has a very short chord so when you're charging you have to sit within 1 meter from a power outlet if you want to use your tablet. And instead of connecting to the mini USB connector like most phones the tablet has a separate power connector so you can't charge the tablet from a computer.
&lt;/p&gt;
&lt;p&gt;
All in all this is a really good tablet. The extra USB connector is something that is very usefull in every day use. I often just connect the keyboard from my computer when typing email and you can easilly plug in a USB stick to watch a movie. Compared to the iPad the screen dimensions are better for media consumption. You can watch widescreen movies at 720p.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-8802016695244168202?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/PO1rUnDJaQs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/8802016695244168202/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/09/acer-iconia-a500-review.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/8802016695244168202?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/8802016695244168202?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/PO1rUnDJaQs/acer-iconia-a500-review.html" title="Acer Iconia A500 review" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/09/acer-iconia-a500-review.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MDQXk7fip7ImA9WhdRE0o.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-7595030728139749289</id><published>2011-08-03T14:44:00.000+02:00</published><updated>2011-08-03T14:44:30.706+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-03T14:44:30.706+02:00</app:edited><title>Building Android projects with Jenkins, Ant and Mercurial</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yqNriK1whUin_7RW9PH1OD5r_Yc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yqNriK1whUin_7RW9PH1OD5r_Yc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yqNriK1whUin_7RW9PH1OD5r_Yc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yqNriK1whUin_7RW9PH1OD5r_Yc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I have recently set up a Jenkins build server for my Android projects hosted on Bitbucket. It’s not difficult but there are a couple pitfalls and the information on how to do this isn’t available from one single place so I decided to document the process and put up the information over here. Maybe other people will benefit from having a step-by-step guide too.&lt;br /&gt;
&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;I'm using Bitbucket to store my projects so I'm going to use Mercurial for source control. I want to use SSH for authentication. It's a bit more of a hassle to set up but I don't like to store my Bitbucket credentials in Jenkins.&lt;br /&gt;
&lt;br /&gt;
Right now I'm using the generated ant build scripts. I might switch to Gradle or Maven in the future so stay tuned for updates.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;These are the versions I used for this guide:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Ubuntu Server 11.04 Natty Narwhal (I love typing these names)&lt;br /&gt;
&lt;li&gt;Mercurial 1.7.5&lt;br /&gt;
&lt;li&gt;Jenkins 1.423&lt;br /&gt;
&lt;li&gt;Java OpenJDK version 1.6.0_22&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;h2&gt;Preparation&lt;/h2&gt;&lt;p&gt;I’m assuming you already have a fully functional machine with a Debian flavored OS like Ubuntu. If you want to use another Unix need to replace all the apt-stuff with the package manager of your choice.&lt;/p&gt;&lt;p&gt;First let’s get our system up to date and install a couple of prerequisites.&lt;/p&gt;&lt;pre class="brush:shell"&gt;apt-get update
apt-get upgrade
apt-get install openjdk-6-jdk ant mercurial
&lt;/pre&gt;&lt;p&gt;If you’re running on a 64-bit system you will also want to install ia32-libs to enable the Android SDK to run in 32-bit mode.&lt;/p&gt;&lt;pre class="brush:shell"&gt;apt-get install ia32-libs
&lt;/pre&gt;&lt;h2&gt;The Android SDK&lt;/h2&gt;&lt;p&gt;Now we've got that over with lets get started for real. First we need to decide where we want to put the Android SDK files. I chose /opt/ But you can put it anywhere you want. Lets download and extract the files we're going to need there &lt;/p&gt;&lt;pre class="brush:shell"&gt;cd /opt
wget http://dl.google.com/android/android-sdk_r12-linux_x86.tgz
tar xvfz android-sdk_r12-linux_x86.tgz
&lt;/pre&gt;&lt;p&gt;This will download and extract all the files to /opt/android-sdk-linux-x86.&lt;/p&gt;&lt;p&gt;The last thing we need to do is to update the sdk. This will make it download all the files it needs to actually build stuff. It's easy to get confused here because normally you'd do this with the GUI the nice people at Google built for us. But when you're logged in to your build server through a terminal like me this won't work. Luckilly it's easy to update the SDK from the command line. &lt;/p&gt;&lt;pre class="brush:shell"&gt;/opt/android-sdk/tools/android update sdk -u -f
&lt;/pre&gt;&lt;p&gt;This will just download all the available packages. The -u switch keeps the SDK from trying to show any UI. -f forces it to overwrite any previously downloaded stuff if there is a newer version available. Remember to do this whenever there are new versions of Android available. &lt;/p&gt;&lt;p&gt;Now go make some tea. This will take a while. &lt;/p&gt;&lt;h2&gt;Setting up Jenkins&lt;/h2&gt;&lt;p&gt;The next step is to set up Jenkins. This is a bit easier because Jenkins is available as a .deb package. You can add the Jenkins repository to your sources and then install it. &lt;/p&gt;&lt;pre class="brush:shell"&gt;echo deb http://pkg.jenkins-ci.org/debian binary/ &gt; /etc/apt/sources.list.d/jenkins.list
apt-get update
apt-get install jenkins
&lt;/pre&gt;&lt;p&gt;You now have Jenkins running on port 8080 on your server. Unfortunately Jenkins is wide open after you install it. Let's set up some password security first. &lt;/p&gt;&lt;p&gt;Go to http://&lt;your server&gt;:8080 with your favorite browser and select &lt;strong&gt;Manage Jenkins/Configure System&lt;/strong&gt; Select &lt;strong&gt;Enable Security&lt;/strong&gt; Go to &lt;strong&gt;Select Security Realm&lt;/strong&gt; and select &lt;strong&gt;Jenkins's own user database&lt;/strong&gt; Now click &lt;strong&gt;Save&lt;/strong&gt; at the bottom of the screen. &lt;/p&gt;&lt;p&gt;Now you can add some users who have access to Jenkins. Select &lt;strong&gt;Manage Jenkins&lt;/strong&gt; again, now go to &lt;strong&gt;Manage Users&lt;/strong&gt; to do this. The link to add a user is hidden on the left side of the screen. &lt;/p&gt;&lt;p&gt;After you've finished adding users you have to go back to the &lt;strong&gt;Configure System&lt;/strong&gt; screen and select how you want to authorize users. For Authorization select one of the last three choices depending on how much control you want over what users can do.  &lt;/p&gt;&lt;h2&gt;Source control&lt;/h2&gt;&lt;p&gt;Now lets see if we can get Jenkins to get our project from Bitbucket. First we need to install the Mercurial plugin. Go to &lt;strong&gt;Manage Jenkins / Manage Plugins&lt;/strong&gt; and install the Mercurial Plugin on the &lt;strong&gt;Available&lt;/strong&gt; tab. If this tab is empty refresh the plugins on the &lt;strong&gt;Advanced&lt;/strong&gt; tab. &lt;/p&gt;&lt;p&gt;Now we're going to set up ssh authentication. Jenkins has set up it's own account on the server so we're going to create a keypair for that account and add it to Bitbucket with the right authorizations. That way Jenkins can login to Bitbucket and clone our repository. You're probably still logged in to the command line of your buildserver. Create the keypair like this: &lt;/p&gt;&lt;pre class='brush:shell'&gt;sudo su - jenkins
cd
ssh-keygen -t
less ~/.ssh/id_rsa.pub
&lt;/pre&gt;&lt;p&gt;Just use the default path for the keys and press enter when you're asked for a passphrase. The last command lists the public key Jenkins will use to access your repository. Copy this key go to the account settings on your bitbucket webpage, look up the box with &lt;strong&gt;SSH keys&lt;/strong&gt; in the title, paste in your key and click &lt;strong&gt;Add key&lt;/strong&gt;. That's all there is to it. &lt;/p&gt;&lt;p&gt;Now we should be able to clone our repository. Make sure you're still logged in as the Jenkins account in your terminal and type: &lt;/p&gt;&lt;pre class="brush:shell"&gt;hg clone ssh://hg@bitbucket.org/&lt;your username&gt;/&lt;your repository&gt;
&lt;/pre&gt;&lt;p&gt;You'll probably be asked if you want to add the bitbucket key to the list of known hosts. Type yes and go on, Mercurial should now get your complete project for you.&lt;/p&gt;&lt;h2&gt;Configuring the build&lt;/h2&gt;&lt;p&gt;Point your browser to your Jenkins page again. Log in and select &lt;strong&gt;New Job&lt;/strong&gt;. Type the job name for your build and select &lt;strong&gt;Build a free-style software project&lt;/strong&gt;. And press &lt;strong&gt;Ok&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;Select &lt;strong&gt;Mercurial&lt;/strong&gt; for source code management and type
&lt;pre&gt;ssh://hg@bitbucket.org/&lt;your username&gt;/&lt;your repository&gt;&lt;/pre&gt;for your repository URL. Set the branch to default and you're good to go. No need to enter passwords because we set up SSH earier. Click Save and test out if Jenkins is able to clone your repository.&lt;/p&gt;&lt;p&gt;Now all we have left to do is to tell Jenkins how to build our project and we're done. We do this by adding a build step on the build configuration page. Just click &lt;strong&gt;Add build step&lt;/strong&gt;and choose &lt;strong&gt;Invoke Ant&lt;/strong&gt;
&lt;/p&gt;&lt;p&gt;You can now add build targets for Ant. For this example you can use &lt;strong&gt;clean&lt;/strong&gt; and &lt;strong&gt;release&lt;/strong&gt; to make a release build. If your build.xml file isn't right at the root of your project you need to click &lt;strong&gt;Advanced&lt;/strong&gt; and tell Jenkins where to find it relative to your project root.
&lt;/p&gt;&lt;p&gt;All we need to do now is tell Ant where it can find the Android SDK. We do this by adding an environment variable in the properties field.&lt;pre&gt;sdk.dir=/opt/android-sdk&lt;/pre&gt;and we're done.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-7595030728139749289?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/FmO92OrpS3w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/7595030728139749289/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/08/building-android-projects-with-jenkins.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7595030728139749289?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7595030728139749289?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/FmO92OrpS3w/building-android-projects-with-jenkins.html" title="Building Android projects with Jenkins, Ant and Mercurial" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/08/building-android-projects-with-jenkins.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEHSHw5eSp7ImA9WhdRGEw.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-8873782948459372311</id><published>2011-05-15T15:34:00.025+02:00</published><updated>2011-08-08T16:43:59.221+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-08T16:43:59.221+02:00</app:edited><title>Android development resource links</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eVncm2I1JDZ5YYQ7kM3gba3Se_M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eVncm2I1JDZ5YYQ7kM3gba3Se_M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eVncm2I1JDZ5YYQ7kM3gba3Se_M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eVncm2I1JDZ5YYQ7kM3gba3Se_M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I've been playing with the Android SDK and I have a growing list of bookmarks to Android dev resources for my own use. I thought the best place to keep them would be here on my blog. That way other people can benefit too. I'll keep updating this list so feel free to add suggestions in the comments.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;&lt;h2&gt;Official stuff&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.android.com/" target="_blank"&gt;The Android website&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://developer.android.com/sdk/installing.html" target="_blank"&gt;Downloading and Installing the Android SDK&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://developer.android.com/guide/index.html" target="_blank"&gt;SDK Documentation&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://developer.android.com/reference/packages.html" target="_blank"&gt;SDK Reference&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://tools.android.com/" target="_blank"&gt;Android tools&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://developer.android.com/guide/practices/ui_guidelines/index.html" target="_blank"&gt;UI design guidelines&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://android-developers.blogspot.com/" target="_blank"&gt;Android developers blog&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;Android is open source, here is the &lt;a href="http://source.android.com/" target="_blank"&gt;source&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;Tools and libraries&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;IDE’s: &lt;a href="http://www.eclipse.org/downloads/" target="_blank"&gt;Eclipse&lt;/a&gt;, &lt;a href="http://netbeans.org/downloads/index.html" target="_blank"&gt;Netbeans&lt;/a&gt;, &lt;a href="http://www.jetbrains.com/idea/download/" target="_blank"&gt;IntelliJ IDEA&lt;/a&gt; or &lt;a href="http://developer.motorola.com/docstools/motodevstudio/" target="_blank"&gt;Motodev Studio&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/android-ui-utils/" target="_blank"&gt;Android UI utils&lt;/a&gt; – Create icons and other assets for your app&lt;br /&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/roboguice/" target="_blank"&gt;RoboGuice&lt;/a&gt; - Android IoC framework.&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;Android developers with blogs&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://commonsguy.wordpress.com/" target="_blank"&gt;A Commons Blog&lt;/a&gt; - Mark L. Murphy from &lt;a href="http://commonsware.com/" target="_blank"&gt;Commonsware&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://androidaudiohacks.com/home/" target="_blank"&gt;AndroidAudioHacks.com&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://androidblogger.blogspot.com/" target="_blank"&gt;AndroidBlogger&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://android-er.blogspot.com/" target="_blank"&gt;Android-er&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.badlogicgames.com/wordpress/" target="_blank"&gt;Badlogic Games&lt;/a&gt; – Mario Zechner&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.androidengineer.com" target="_blank"&gt;Android Engineer&lt;/a&gt; – Matt Quigley&lt;br /&gt;
&lt;li&gt;&lt;a href="http://w2davids.wordpress.com/" target="_blank"&gt;Wagied Davids&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://zerocredibility.wordpress.com/" target="_blank"&gt;Zero Credibility&lt;/a&gt; - Jeffrey Blattman&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;Android books&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;The busy coder's guide to &lt;a href="http://commonsware.com/Android/Android-2_9-CC.pdf"&gt;Android Development&lt;/a&gt; and &lt;a href="http://commonsware.com/Android/Android-2_9-CC.pdf"&gt;Advanced Android Development&lt;/a&gt; are free books from &lt;a href="http://commonsware.com/" target="_blank"&gt;Commonsware&lt;/a&gt;. Their paid subscription will get you more up to date ebooks on Android development.&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1617290505/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=mendelsiebent-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399349&amp;amp;creativeASIN=1617290505"&gt;Android in Action&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1430232978/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=mendelsiebent-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399349&amp;amp;creativeASIN=1430232978"&gt;Beginning Android 3&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1430232226/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=mendelsiebent-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399349&amp;amp;creativeASIN=1430232226"&gt;Pro Android 3&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;Android community&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://stackoverflow.com/"&gt;stackoverflow.com&lt;/a&gt; - Developer Q/A site with an active android dev community.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://androidforums.com/"&gt;androidforums.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://forum.xda-developers.com/forumdisplay.php?f=564"&gt;xda developers&lt;/a&gt; - lots of info on rooting phones, some on development&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.anddev.org/"&gt;anddev.org&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;&lt;a href="http://www.google.com/events/io/2011/sessions.html"&gt;Google IO 2011 session videos&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/3d-graphics-on-android-lessons-learned-from-google-body.html"&gt;3D Graphics on Android: Lessons learned from Google Body&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/accelerated-android-rendering.html"&gt;Accelerated Android Rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/android-app-engine-a-developer-s-dream-combination.html"&gt;Android + App Engine: A Developer's Dream Combination&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/android-development-tools.html"&gt;Android Development Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/android-market-for-developers.html"&gt;Android Market for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html"&gt;Android Protips: Advanced Topics for Expert Android App Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/bringing-c-and-c-games-to-android.html"&gt;Bringing C and C++ Games to Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/building-aggressively-compatible-android-games.html"&gt;Building Aggressively Compatible Android Games&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/best-practices-for-accessing-google-apis-on-android.html"&gt;Best Practices for Accessing Google APIs on Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/building-android-apps-for-google-tv.html"&gt;Building Android Apps for Google TV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/designing-and-implementing-android-uis-for-phones-and-tablets.html"&gt;Designing and Implementing Android UIs for Phones and Tablets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/dont-just-build-a-mobile-app-build-a-business.html"&gt;Don’t just build a mobile app. Build a business&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/evading-pirates-and-stopping-vampires-using-license-verification-library-in-app-billing-and-app-engine.html"&gt;Evading Pirates and Stopping Vampires using License Verification Library, In-App Billing, and App Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/fireside-chat-with-the-android-team.html"&gt;Fireside Chat with the Android Team&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/honeycomb-highlights.html"&gt;Honeycomb Highlights&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/how-to-nfc.html"&gt;How to NFC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/html5-versus-android-apps-or-web-for-mobile-development.html"&gt;HTML5 versus Android: Apps or Web for Mobile Development?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/memory-management-for-android-apps.html"&gt;Memory management for Android Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/optimizing-android-apps-with-google-analytics.html"&gt;Optimizing Android Apps with Google Analytics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/taking-android-to-work.html"&gt;Taking Android to Work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2011/sessions/android-open-accessory-api-and-development-kit-adk.html"&gt;Android Open Accessory API and Development Kit (ADK)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;&lt;a href="http://www.google.com/events/io/2010/sessions.html#Android"&gt;Google IO 2010 sessions&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/beginners-guide-android.html"&gt;A beginner's guide to Android&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/writing-real-time-games-android.html"&gt;Writing real-time games for Android redux&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/world-of-listview-android.html"&gt;The world of ListView&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/casting-wide-net-android-devices.html"&gt;Casting a wide net: how to target all Android devices&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/android-ui-design-patterns.html"&gt;Android UI design patterns&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html"&gt;Developing Android REST client applications&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/jit-compiler-androids-dalvik-vm.html"&gt;A JIT Compiler for Android's Dalvik VM&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/writing-zippy-android-apps.html"&gt;Writing zippy Android apps&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/android-audio-techniques.html"&gt;Advanced Android audio techniques&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/push-applications-android.html"&gt;Building push applications for Android&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2010/sessions/analyzing-monetizing-mobile-apps.html"&gt;Analyzing and monetizing your Android &amp;amp; iPhone apps&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;&lt;a href="http://www.google.com/events/io/2009/sessions.html#mobile"&gt;Google IO 2009 session videos&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/CodingLifeBatteryLife.html"&gt;Coding for Life - Battery Life, That Is&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/DebuggingArtsNinjaMasters.html"&gt;Debugging Arts of the Ninja Masters&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/HowToCodeThee.html"&gt;How Do I Code Thee? Let Me Count the Ways&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/LookingBeyondScreenTextSpeechAndroid.html"&gt;Looking Beyond the Screen: Text-To-Speech and Eyes-Free Interaction on Android&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/MasteringAndroidMediaFramework.html"&gt;Mastering the Android Media Framework&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/PixelPerfectCodeInteractionDesignAndroid.html"&gt;Pixel Perfect Code: How to Marry Interaction and Visual Design the Android Way&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/SupportingMultipleDevicesBinary.html"&gt;Supporting Multiple Devices with One Binary&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/TurboChargeUiAndroidFast.html"&gt;Turbo-charge your UI: How to Make your Android UI Fast and Efficient&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://www.google.com/events/io/2009/sessions/WritingRealTimeGamesAndroid.html"&gt;Writing Real-Time Games for Android&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;p&gt;&lt;h2&gt;&lt;a href="http://sites.google.com/site/io/"&gt;Google IO 2008 session videos&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://sites.google.com/site/io/an-introduction-to-android"&gt;An Introduction to Android&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://sites.google.com/site/io/inside-the-android-application-framework"&gt;Inside the Android Application Framework&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://sites.google.com/site/io/dalvik-vm-internals"&gt;Dalvik VM Internals&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://sites.google.com/site/io/building-an-android-application"&gt;Building an Android Application 101&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="http://sites.google.com/site/io/anatomy--physiology-of-an-android"&gt;Anatomy &amp;amp; Physiology of an Android&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-8873782948459372311?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/xOnUsY7e9X8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/8873782948459372311/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/05/android-development-resource-links.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/8873782948459372311?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/8873782948459372311?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/xOnUsY7e9X8/android-development-resource-links.html" title="Android development resource links" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/05/android-development-resource-links.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMDSHg6eip7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-3316769450466197042</id><published>2011-03-15T14:57:00.001+01:00</published><updated>2011-03-15T14:57:59.612+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T14:57:59.612+01:00</app:edited><title>The big move</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oTemadohXI4nBz5rU6u2XSd0-Bk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oTemadohXI4nBz5rU6u2XSd0-Bk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oTemadohXI4nBz5rU6u2XSd0-Bk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oTemadohXI4nBz5rU6u2XSd0-Bk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;People who visit here more often probably noticed that my blog has been down a couple of times the last few months. The problem was that after giving up on hosting it on an (expensive!) windows server I tried unsuccessfully to host my blogengine.net blog on Ubuntu with Mono. I could probably get this to work but it takes too much time and effort. So I decided to move to a hosted blog on Blogger. This way I can spend more time blogging and less time on blog administration.&lt;/p&gt; &lt;p&gt;If you’re on a stylish white blogger page right now you’re already on the new blog. Have fun and expect most of my old content to appear there over time. If you’re on my old coffee themed blog you’ll probably need to move to mendeltsiebenga.nl. Or you can wait. As soon as I have all my content moved over I’ll point mendeltsiebenga.com to the new blog too.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-3316769450466197042?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/sHRp42gvt9Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/3316769450466197042/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/03/big-move.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/3316769450466197042?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/3316769450466197042?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/sHRp42gvt9Y/big-move.html" title="The big move" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/03/big-move.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UFSHY-cSp7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-866630864198922968</id><published>2011-02-14T12:00:00.000+01:00</published><updated>2011-03-15T14:20:19.859+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T14:20:19.859+01:00</app:edited><title>Abusing using</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WalK4ws5LtEUCMOnRW-ayAlUbVA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WalK4ws5LtEUCMOnRW-ayAlUbVA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WalK4ws5LtEUCMOnRW-ayAlUbVA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WalK4ws5LtEUCMOnRW-ayAlUbVA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;When we went from unmanaged to managed languages we got rid of the headache of having to do manual memory management. Unfortunately that meant we also lost destructors and with them the ability to do some nice tricks. Luckily we can still do some of these tricks with the using keyword. Lets take a look&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;One of the nice things you could do with destructors in c++ was to tie the execution of a piece of code to the scope of a variable. You did this by putting the piece of code in a destructor of some object, every time you instantiated that object on the stack you were assured your code would be run when that object left scope.&lt;/p&gt; &lt;p&gt;But wait, we still can do this with using and IDisposable.&lt;/p&gt; &lt;p&gt;Oh boy! Silly example time!&lt;/p&gt; &lt;p&gt;Lets say you’ve got a bunch of freeloading friends. You kept score on how many rounds of beer you bought last night in a dictionary and now you want to confront them with the ugly truth by putting the contents of that dictionary online in an html table.&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;var rounds = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;,&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&amp;gt; {{&lt;span style="color: #006080"&gt;"Me"&lt;/span&gt;, 6}, {&lt;span style="color: #006080"&gt;"Bill"&lt;/span&gt;, 3}, {&lt;span style="color: #006080"&gt;"Pete"&lt;/span&gt;, 1}};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Formatting html tables can be a lot of busywork. You need to keep track of all elements. Every &amp;lt;td&amp;gt; needs a &amp;lt;/td&amp;gt;. This can get messy fast!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;First we create a helper class that will print and keep track of elements:&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; HtmlElement : IDisposable&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Element;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; HtmlElement(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; element)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         Element = element;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         Console.WriteLine(&lt;span style="color: #006080"&gt;"&amp;lt;{0}&amp;gt;"&lt;/span&gt;, Element);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         Console.WriteLine(&lt;span style="color: #006080"&gt;"&amp;lt;/{0}&amp;gt;"&lt;/span&gt;, Element);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Now printing tables (or any kind of simple html) is easy.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HtmlElement(&lt;span style="color: #006080"&gt;"table"&lt;/span&gt;))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var row &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; rounds)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HtmlElement(&lt;span style="color: #006080"&gt;"tr"&lt;/span&gt;))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HtmlElement(&lt;span style="color: #006080"&gt;"td"&lt;/span&gt;)) Console.WriteLine(row.Key);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HtmlElement(&lt;span style="color: #006080"&gt;"td"&lt;/span&gt;)) Console.WriteLine(row.Value);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Every html element we print is tied to the scope of the using block it’s in. When we get to the end of the block the closing element is automatically added. Simple and pretty readable.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I’ve seen this trick used in all kinds of places where you want a piece of code guaranteed to run after some other operation. Transactions in nHibernate use the same mechanism for example. Keeps you from typing catch/finally blocks around every transaction.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-866630864198922968?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/cRSUf7xrXDY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/866630864198922968/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/03/abusing-using.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/866630864198922968?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/866630864198922968?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/cRSUf7xrXDY/abusing-using.html" title="Abusing using" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/03/abusing-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QGQnszcSp7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2797031263656796036</id><published>2010-10-06T13:00:00.000+02:00</published><updated>2011-03-15T14:22:03.589+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T14:22:03.589+01:00</app:edited><title>Running a Git repository on Ubuntu using Gitosis</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2uqd8FfjiTcGZCMnWApTNjBKOfc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2uqd8FfjiTcGZCMnWApTNjBKOfc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2uqd8FfjiTcGZCMnWApTNjBKOfc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2uqd8FfjiTcGZCMnWApTNjBKOfc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;20I’ve been using Git for a couple of small projects that I’ve been hosting on github.com but version control for my bigger ‘secret’ projects still runs on a windows machine with visual svn server.&lt;/p&gt; &lt;p&gt;Now that I’m starting to use Mono for a couple of projects so I’m playing with linux more. Last week I decided to try to try out gitosis on an ubuntu server. I found out it’s pretty easy to use when you know your way around git but for a noob like me some things weren’t immediately clear. Eventually I solved most problems I ran into, so I decided to write up the steps I took to install gitosis on ubuntu 10.04&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;I got most of my information from this a blogpost by &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way" target="_blank"&gt;Gary Dolley&lt;/a&gt;, I’ll probably point to this it a few times but this post is from 2007. Things have become a bit easier by now.&lt;/p&gt; &lt;p&gt;If you’re not used to git and gitosis there are two things that might be a bit unclear when you start. So we’ll tackle them first.&lt;/p&gt; &lt;p&gt;First of all there’s authentication. If you’ve used github you should be familliar using public/private key-pairs for authentication but for those who havn’t here’s the short version;&lt;/p&gt; &lt;p&gt;Instead of using passwords gitosis wants you to store a key-pair in the home directory of every computer you use git on. You can then tell gitosis the public key and it uses public/private key magic to authenticate you whenever you push or pull changes. It sounds complicated but its easier to use than the traditional username/password hassle and it’s more secure too.&lt;/p&gt; &lt;p&gt;The other weird thing gitosis does that’s actually very practical when you get the hang of it is that it uses a git repository to store all configuration. This makes management very easy. Want to add a repository? Just pull from gitosis admin on your local workstation, change some config files, commit your changes and push them back. Easy as that.&lt;/p&gt; &lt;p&gt;Enough talking, lets get started.&lt;/p&gt; &lt;h1&gt;Installing Gitosis&lt;/h1&gt; &lt;p&gt;First we need to get git onto your ubuntu server machine (if you’re using a different flavour of linux things might be different for you. I’ll try to point out possible differences). In the original description you had to pull it from a repository somewhere and then install everything yourself but as there’s a gitosis package available we’ll just use that&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;sudo apt-get install gitosis&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This will install gitosis and create a gitosis user. Next we need to create the admin repository where gitosis&amp;nbsp; stores it’s configuration. To do this we also need to have a public key for the first user we want to give access to the repository. I like to be able to administrate my gitosis server from the command line of the server itself so unlike Gary’s post who uses a keypair from a client machine I’ll just create a key-pair for the user on the machine gitosis runs on. I’ll show how to add more users on different machines later.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;ssh-keygen -t rsa&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;this should do the trick. It will create a private/public key pair in the .ssh directory of your home dir. It will also ask you for a key phrase to encrypt your keys. You can keep this blank but it’s a good idea to enter something here.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Now we can run&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;sudo -H -u gitosis gitosis-init &amp;lt; ~/ssh/id_rsa.pub&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;to create the admin repository. Note that the aptitude package has added the ‘gitosis’ user we’re using here. Many descriptions on how to use gitosis run gitosis as ‘git’ so some of the commands look different.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;git clone gitosis@{your-servername}:gitosis-admin.git&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;will clone the admin repository to your home dir where you can edit things.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Adding a (remote) user&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;You can take a deep breath now, after all this hard work we can move on to the fun (and useful) stuff. Adding users and repositories. Lets get started by adding a user on a remote workstation with rights to the admin repo.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;First we need a public/private key pair for the user on your workstation. If you’ve been using github for version control you probably already have a key-pair set up. If not you can create a keypair with&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;ssk-keygen -t rsa&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;If you’re using windows you can run this command from the git-bash shell. Be sure to enter a passphrase.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;After this you can copy your public key to your server.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;scp ~/.ssh/id_rsa.pub {server-admin-user}@{your-servername}:~/&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Copy it to the keyfile directory in the gitosis admin repo and rename it to {username}.pub where username is the name you want to use for this user in your gitosis.conf file.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Next edit your gitosis.conf file it should look a bit like&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;p&gt;[gitosis]&lt;br&gt;&lt;br&gt;[group gitosis-admin]&lt;br&gt;writable = gitosis-admin&lt;br&gt;members = &lt;a href="mailto:{your-user-name@your-server"&gt;{your-user-name@your-server&lt;/a&gt;}&lt;/p&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;You can add the user you just added to members, just use a space to separate user names.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;members = {your-user-name@your-server} {your-workstation-user-name}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;You update gitosis by pushing these changes back to the repo, git add, git commit and git push work just like you’re used to. Now you should be able to clone the admin repo on your workstation too.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;git clone gitosis@{your-server-name}:gitosis-admin.git&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Git should ask you for your passphrase. If it asks you for your password instead you did something wrong adding the public key. A common mistake is forgetting the .pub at the end of your key file. If it asks for a passphrase but then still won’t let you in you probably mistyped something in your gitosis.conf file.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Next we’ll get gitosis to do some real work by storing something more than just the admin repository.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;h1&gt;Adding a repository&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Adding a repository is easy now. First we add a group to your gitosis.conf file. If you followed all the steps until now you can do this from your workstation.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;[group {project-name}]&lt;br&gt;writable = {project-name}&lt;br&gt;members = {member1} {member2} ...&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Push these changes back to the remote repository and gitosis will update.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now you can create a project directory somewhere on your workstation. Git init, add files, git add and git commit. You can let git know about the remote repository like this&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0px; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;git remote add origin gitosis@{servername}:{repositoryname}.git&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;and then you can just push and pull from your new repository.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;That’s all for now. I hope this will help you. Please let me know if I made any mistakes so I can fix them for the next reader.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2797031263656796036?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/EK3m0M8lgSM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2797031263656796036/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/03/running-git-repository-on-ubuntu-using.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2797031263656796036?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2797031263656796036?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/EK3m0M8lgSM/running-git-repository-on-ubuntu-using.html" title="Running a Git repository on Ubuntu using Gitosis" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/03/running-git-repository-on-ubuntu-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IHQXg9eCp7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-6020657373360650074</id><published>2010-04-07T13:00:00.000+02:00</published><updated>2011-03-17T11:58:50.660+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:58:50.660+01:00</app:edited><title>JavaScript Tetris update</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/p2NF6UNfZxjrOExVwyHO5a3ideQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/p2NF6UNfZxjrOExVwyHO5a3ideQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/p2NF6UNfZxjrOExVwyHO5a3ideQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/p2NF6UNfZxjrOExVwyHO5a3ideQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Here’s the last post in my JavaScript Tetris series. Time to show the final version of the Tetris implementation I built. It’s not completely finished but I did come pretty far. I only put in a few hours in total. I’m going to race through the final implementation in this post. After this I’ll go back to writing about C#. I promise :-)&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;There’s a couple of stories I want to implement in this post;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Rotating blocks  &lt;li&gt;Bounds checking. We want to make sure blocks don’t move outside the playing field.  &lt;li&gt;When a block reaches the bottom of the playing field it has to stack up in a wall.&lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Rotation&lt;/h3&gt; &lt;p&gt;The first big change I made was to implement rotation. It’s actually pretty easy to rotate a block 90 degrees. Just swap the x and y coordinates of all the squares that make up the block and make one negative. Negative x means rotate left and negative y means rotate right. To make it possible to rotate around other points than 0,0 I just move the block before and after the rotation. Blocks now have a center of rotation property too.&lt;/p&gt; &lt;h3&gt;Bounds checking&lt;/h3&gt; &lt;p&gt;In order to implement this easily I had to shift around some object responsibilities. Blocks didn’t know about their position, so in order to know if a block was outside of the playing fields I had combine information from the game object (block position) with information from the block (block shape). It would be more logical to have blocks maintain their own position. After I made this change it was pretty easy to check if a block moved outside of it’s bounds.&lt;/p&gt; &lt;p&gt;&lt;a href="/file.axd?file=2010%2f4%2ftetris0.04.rar"&gt;tetris0.04.rar (15.32 kb)&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;Wall&lt;/h3&gt; &lt;p&gt;This seems like a pretty big feature but most of the functionality for it was already there. All the wall has to do was maintain an array of blocks and do some collision detection. I had this implemented in a couple of minutes. Hooking it into the presenter and the game object was easy too. I actually spent some time moving the bounds checking logic into the wall object too.&lt;/p&gt; &lt;h3&gt;Thoughts&lt;/h3&gt; &lt;p&gt;There’s still some stuff missing. You can’t start/stop the game. The game doesn’t detect when you lose. And most importantly it doesn’t keep score. These are all pretty easy to implement but my goal isn’t to build a complete implementation of Tetris. It’s to learn more about JavaScript.&lt;/p&gt; &lt;p&gt;So how do I feel about JavaScript now? To be honest I’ve got mixed feelings. It’s a pretty interesting language. Lots of functional elements. I like that. And I’d like to get a bit more into the prototypical nature of JavaScript objects. But there’s a lot not to like about JavaScript too. I had some issues where different browsers worked differently. For example I wrote some tests checking the type of returned objects that broke in Internet Explorer. On other occasions Chrome and Firefox were too lenient with functions that were passed incorrect parameters and failed in a completely unrelated place.&lt;/p&gt; &lt;p&gt;Oh, and there’s no parameter overloading for functions.&lt;/p&gt; &lt;p&gt;I might be spoiled with my programming languages but JavaScript seems a bit like version 0.9b of a language that’s going to blow everyone away in version 2.0. (and yes, I know I’m going to be flamed for this)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-6020657373360650074?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/qqkEEbcELmk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/6020657373360650074/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/03/javascript-tetris-update.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/6020657373360650074?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/6020657373360650074?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/qqkEEbcELmk/javascript-tetris-update.html" title="JavaScript Tetris update" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/03/javascript-tetris-update.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08GRHg_fyp7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-5075325330753534170</id><published>2010-03-28T13:00:00.000+02:00</published><updated>2011-03-17T12:03:45.647+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T12:03:45.647+01:00</app:edited><title>JavaScript Tetris part III</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tMEX-ifTqw7jGvXNJcGuAJ4IS2w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tMEX-ifTqw7jGvXNJcGuAJ4IS2w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tMEX-ifTqw7jGvXNJcGuAJ4IS2w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tMEX-ifTqw7jGvXNJcGuAJ4IS2w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Here’s just a short update on the Tetris project (if you can call it a project). I had a pretty busy week but I did find some time to play around some more with JavaScript, try out some GOF creational patterns, and build a nice domain model to make working with squares and blocks a bit easier.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;This time I wanted to make the falling blocks look like real Tetris blocks. Right now the whole game state is pretty much an x and y position of the falling block, but in order to draw more complex blocks my domain model needs to get a bit bigger too.&lt;/p&gt; &lt;p&gt;The first thing I did was encapsulate x,y value pairs in a Vector object. I built a Square object with an x, y and a color and I built a Block object to hold several square objects to form one of the well known Tetris blocks.&lt;/p&gt; &lt;p&gt;The Vector, Square and Block classes only expose their properties through methods, that way they can’t be changed after creation. Actions on these objects will just return a new object, for example moving a square will leave the old square unchanged. This is something I’m used to in C#, and it looks pretty clean in JavaScript too. Not sure if this is common practice.&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; Vector(x, y) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.x = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; x; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.y = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; y; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.moveLeft = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Vector(&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;             x - 1, y);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This is a small snippet of the Vector class to illustrate my point. The x and y are implemented as functions instead of properties. The Game object stores the current position in a Vector and just calls moveLeft when the user presses the left button to get a new vector one step to the left. This means I go around creating and throwing away more objects. But I have less side effects, which seems more elegant to me especially in a functional-ish language like JavaScript.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In order to make it easy to build the seven types of blocks from code I tried implementing some of the creational patterns. Eventually I things weren’t so complex that I needed a factory object or a builder so I went with a simple factory method ‘buildBlock’.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; Block.buildBlock = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(color, coordinates) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; squares = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Array();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;( &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; i &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; coordinates) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         squares.push( &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Square( coordinates[i][0], coordinates[i][1], color ) );&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Block( squares );&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Instead of creating this method in the constructor method of Block like I normally do I tacked this method on to the Block constructor. This way you can call it without having an instance of Block, a bit like a static method in C#.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now I can define the different types of blocks like this.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; Block.blocks = &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     [&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         Block.buildBlock(&lt;span style="color: #006080"&gt;'maroon'&lt;/span&gt;, [[-1,0], [0,0], [1,0], [2,0]]),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         Block.buildBlock(&lt;span style="color: #006080"&gt;'lightgrey'&lt;/span&gt;, [[-1,0], [0,0], [1,0], [1,-1]]),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         Block.buildBlock(&lt;span style="color: #006080"&gt;'magenta'&lt;/span&gt;, [[-1,-1], [-1,0], [0,0], [1,0]]),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         Block.buildBlock(&lt;span style="color: #006080"&gt;'darkblue'&lt;/span&gt;, [[0,0], [1,0], [1,1], [0,1]]),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         Block.buildBlock(&lt;span style="color: #006080"&gt;'green'&lt;/span&gt;, [[-1,0], [0,0], [0,1],[1,1]]),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         Block.buildBlock(&lt;span style="color: #006080"&gt;'brown'&lt;/span&gt;, [[0,0], [-1,0], [1,0], [0,1]]),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         Block.buildBlock( &lt;span style="color: #006080"&gt;'cyan'&lt;/span&gt;, [[-1,1], [0,1], [0,0], [1,0]])&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     ];&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Pretty clean if I say so myself.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As usual you can download the code and play around with it yourself.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="/file.axd?file=2010%2f3%2ftetris0.03.rar"&gt;tetris0.03.rar (13.79 kb)&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Next up, rotating blocks.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-5075325330753534170?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/Zgpah0OiVzQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/5075325330753534170/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2010/03/javascript-tetris-part-iii-update.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5075325330753534170?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5075325330753534170?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/Zgpah0OiVzQ/javascript-tetris-part-iii-update.html" title="JavaScript Tetris part III" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2010/03/javascript-tetris-part-iii-update.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EASX49fip7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-7642287961120732289</id><published>2010-03-21T12:00:00.000+01:00</published><updated>2011-03-17T12:00:48.066+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T12:00:48.066+01:00</app:edited><title>JavaScript Tetris part II – some tests</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pUkNEoxvN8yIkP7cKULgIbJdmGs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pUkNEoxvN8yIkP7cKULgIbJdmGs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pUkNEoxvN8yIkP7cKULgIbJdmGs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pUkNEoxvN8yIkP7cKULgIbJdmGs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Here’s a little update on the JavaScript front. I’ve been busy working on Tetris this weekend. Lots of new stuff to learn and lots to do. First of all I got a list of issues from &lt;a href="http://www.cultiv.nl/"&gt;Sebastiaan Janssen&lt;/a&gt; that needed fixing (thanks, that was exactly the kind of feedback I was hoping for). I’ve been playing around with unit testing JavaScript with &lt;a href="http://docs.jquery.com/QUnit"&gt;QUnit&lt;/a&gt;. Of course my existing code wasn’t really testable so I had to refactor things a bit too. And I tried to test-drive a couple of small stories.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;I’m not going to list all the code I wrote in my posts anymore. It makes for pretty dull reading and you can download the code and read it at your own leisure. I’m sure the code is a lot more readable in your editor than on my blog anyway. I’ll just list a couple of interesting pieces and try to work out more of the concepts in my blog posts.&lt;/p&gt; &lt;p&gt;First of all here are the issues Sebastiaan wanted me to fix:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;I’m using the JavaScript const keyword but IE doesn’t support this.  &lt;li&gt;Setting css styles can be done a bit cleaner.  &lt;li&gt;JavaScript in the .html file  &lt;li&gt;You can’t use arrow keys to move blocks. This is a problem on laptop keyboards without a numeric keypad. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The first three were easy to fix, I added a user story for the fourth issue. As this was the only user story that came from a potential user I put it right at the top of my backlog.&lt;/p&gt; &lt;h3&gt;Refactoring&lt;/h3&gt; &lt;p&gt;I want to start test-driving things, QUnit is a nice new toy that I want to start using. But unfortunately my code is a bit of a ball of mud. Luckily it’s not big so we can’t call it an &lt;a href="http://www.laputan.org/mud/mud.html#BigBallOfMud"&gt;antipattern&lt;/a&gt; yet. But it’s a good time to start separating some concerns.&lt;/p&gt; &lt;p&gt;I want to pull out pieces of functionality and put them in their own objects. Something like a model view presenter architecture would be nice with a TetrisView object to encapsulate drawing and reacting to user input, a TetrisGame object to handle game state and a TetrisPresenter to tie the two together.&lt;/p&gt; &lt;p&gt;This is what the tests look like,&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; module('tetrisGame');&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; test('when initializing', function() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; game = new TetrisGame();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     equals(18, game&lt;span style="color: #cc6633"&gt;.yPos&lt;/span&gt;, 'block starts on the &lt;span style="color: #0000ff"&gt;right&lt;/span&gt; y &lt;span style="color: #0000ff"&gt;position&lt;/span&gt;.');&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     equals(5, game&lt;span style="color: #cc6633"&gt;.xPos&lt;/span&gt;, 'block starts on the &lt;span style="color: #0000ff"&gt;right&lt;/span&gt; x &lt;span style="color: #0000ff"&gt;position&lt;/span&gt;.');&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt; test('when running the game loop', function() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; game = new TetrisGame();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     game&lt;span style="color: #cc6633"&gt;.gameLoop&lt;/span&gt;();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;     equals(17, game&lt;span style="color: #cc6633"&gt;.yPos&lt;/span&gt;, 'block moves down.');&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;     equals(5, game&lt;span style="color: #cc6633"&gt;.xPos&lt;/span&gt;, 'block stays in the same horizontal &lt;span style="color: #0000ff"&gt;position&lt;/span&gt;.')&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt; });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt; test('when moving &lt;span style="color: #0000ff"&gt;left&lt;/span&gt;', function() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; game = new TetrisGame();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;     game&lt;span style="color: #cc6633"&gt;.moveLeft&lt;/span&gt;();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;     equals(4, game&lt;span style="color: #cc6633"&gt;.xPos&lt;/span&gt;, 'block moves &lt;span style="color: #0000ff"&gt;left&lt;/span&gt;');&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;     equals(18, game&lt;span style="color: #cc6633"&gt;.yPos&lt;/span&gt;, 'block stays at the same &lt;span style="color: #0000ff"&gt;height&lt;/span&gt;');&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt; });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt; &lt;span style="color: #008000"&gt;// etc...&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;I’m not yet 100% happy with them. I like how QUnit pushes you to a context-specification-ish test style. But it’s easy to assert too much in one test which is a bit of a test-smell to me.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I like how easy it is to build stub and mock objects in a dynamic language. I played a bit with these in tetrispresentertests.js if you want to have a look.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Tell me a story&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;The iteration backlog for this iteration (today) looks like this.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The user can steer blocks with the arrow keys. &lt;br /&gt;&lt;li&gt;Blocks can’t move outside of the playing field. &lt;br /&gt;&lt;li&gt;When a block reaches the bottom of the playing field a new block should appear at the top &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Now that I’ve got game logic, presentation logic and the view separated out nicely it’s easy to add some tests for these stories and implement them. I’ll just let the code speak for itself.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="/file.axd?file=2010%2f3%2ftetris0.02.rar"&gt;tetris0.02.rar (12.36 kb)&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-7642287961120732289?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/UBI0YHS32eQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/7642287961120732289/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2010/03/javascript-tetris-part-ii-some-tests.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7642287961120732289?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7642287961120732289?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/UBI0YHS32eQ/javascript-tetris-part-ii-some-tests.html" title="JavaScript Tetris part II – some tests" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2010/03/javascript-tetris-part-ii-some-tests.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MHRn84fip7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-5956573458281953185</id><published>2010-03-16T12:00:00.000+01:00</published><updated>2011-03-17T11:57:17.136+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:57:17.136+01:00</app:edited><title>Diving into JavaScript with Tetris</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/X6Nd20bgy88H9tfYU37HNbSgscY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/X6Nd20bgy88H9tfYU37HNbSgscY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/X6Nd20bgy88H9tfYU37HNbSgscY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/X6Nd20bgy88H9tfYU37HNbSgscY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;To prepare for the &lt;a href="http://devnology.nl/"&gt;Devnology&lt;/a&gt; &lt;a href="http://devnology.nl/nl/bijeenkomsten/details/20-codefest-tetris"&gt;meeting&lt;/a&gt; next month I have to write a version of Tetris in a language of my choosing. I had already fired up Visual Studio to build a kick-ass C# XNA version with explosions and 3D visuals when I realized it would be much more fun and educational to pick a language I’m less familiar with. I’m pretty sure there will be Ruby, Python, Java and Haskell implementations by some people who are pretty good at programming in those languages so I decided not to pick any of those obvious languages. But I’d still like to invest my time learning something I’m actually going to use, so Cobol wasn't an option.&lt;/p&gt; &lt;p&gt;I picked JavaScript.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;The next couple of posts I’m going to be building Tetris using JavaScript and &lt;a href="http://jquery.org"&gt;jQuery&lt;/a&gt;. I’ll pick a couple of stories every few days to implement and if I’m lucky I’ll have something resembling Tetris in a couple of weeks to show off. I actually hope I’ll get some feedback when I do things wrong. Most of my JavaScript experience has been adding simple onclick handlers to html files and pulling my hair out because of DOM incompatibilities. The new JavaScript frameworks hide all the DOM ugliness so it’s a good time to dive into JavaScript again.&lt;/p&gt; &lt;p&gt;In this first post we’ll get started implementing a couple of easy stories. I chose the following three.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;As a user I can see a playing field that is 10 units wide and 18 units high.  &lt;li&gt;Blocks fall one unit every second.  &lt;li&gt;As a user I can steer blocks left and right with the arrows on the numeric keypad. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Lets get started.&lt;/p&gt; &lt;h3&gt;As a user I can see a playing field that is 10 units wide and 18 units high&lt;/h3&gt; &lt;p&gt;The first story is too easy. The display is just going to be a div. So we create a tetris.html file like this:&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;!&lt;/span&gt;&lt;span style="color: #800000"&gt;DOCTYPE&lt;/span&gt; &lt;span style="color: #ff0000"&gt;HTML&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;html&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;head&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;link&lt;/span&gt; &lt;span style="color: #ff0000"&gt;rel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="stylesheet"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;href&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="tetris.css"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;head&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;body&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="field"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;body&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;html&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;and the stylesheet:&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; #field&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;position&lt;/span&gt;: &lt;span style="color: #006080"&gt;relative;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;top&lt;/span&gt;: &lt;span style="color: #006080"&gt;40px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;left&lt;/span&gt;: &lt;span style="color: #006080"&gt;50%;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;margin&lt;/span&gt;-&lt;span style="color: #0000ff"&gt;left&lt;/span&gt;: &lt;span style="color: #006080"&gt;-100px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;width&lt;/span&gt;: &lt;span style="color: #006080"&gt;200px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;height&lt;/span&gt;: &lt;span style="color: #006080"&gt;360px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;border&lt;/span&gt;: &lt;span style="color: #006080"&gt;solid grey 2px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;I decided on a block size of 20 pixels so the field is 200 by 360 pixels.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Blocks fall one unit every second&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;For this story to work we first need to be able to draw blocks. &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; makes this pretty easy. Especially since blocks are just going to be small div’s with a big border in this first version, so our first pieces of JavaScript look like this:&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; drawBlock(x, y) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; block = $(&lt;span style="color: #006080"&gt;"&amp;lt;div class='block'&amp;gt;&amp;lt;/div&amp;gt;"&lt;/span&gt;).css(&lt;span style="color: #006080"&gt;'top'&lt;/span&gt;, (17 - x) * 20).css(&lt;span style="color: #006080"&gt;'left'&lt;/span&gt;, y * 20);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     $(&lt;span style="color: #006080"&gt;'#field'&lt;/span&gt;).append(block);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; clearBlocks() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     $(&lt;span style="color: #006080"&gt;'.block'&lt;/span&gt;).remove();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In order to draw a block every second we need some sort of gameloop that is called every second. So I put something like this in the jQuery document ready handler :&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; $(document).ready(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     setInterval( &lt;span style="color: #006080"&gt;"gameLoop()"&lt;/span&gt;, 1000);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;and the gameloop:&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; verticalPosition = 18;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; horizontalPosition = 5;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; gameLoop() {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     verticalPosition--;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     clearBlocks();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     drawBlock(verticalPosition, horizontalPosition);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;some css for the blocks:&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;div&lt;/span&gt;&lt;span style="color: #cc6633"&gt;.block&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;position&lt;/span&gt;: &lt;span style="color: #006080"&gt;absolute;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;width&lt;/span&gt;: &lt;span style="color: #006080"&gt;12px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;height&lt;/span&gt;: &lt;span style="color: #006080"&gt;12px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;border&lt;/span&gt;: &lt;span style="color: #006080"&gt;solid black 4px;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;And voila, we’ve got movement on our screen. Pretty easy actually.&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;As a user I can steer blocks left and right with the arrows on the numeric keypad.&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;We still can’t call this a game though. Movement is nice but without interactivity we might as well be looking at dancing hamsters. We want to be able to steer our block around.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;jQuery makes registering a keyboard handler pretty easy. We can just add:&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; $(document).keydown(keyHandler);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;and the handler:&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;const&lt;/span&gt; keyCodeMoveLeft = 100;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;const&lt;/span&gt; keyCodeMoveRight = 102;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;const&lt;/span&gt; keyCodeMoveDown = 98;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; keyHandler(keyEvent) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(keyEvent.keyCode === keyCodeMoveLeft) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         horizontalPosition--;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(keyEvent.keyCode === keyCodeMoveRight) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         horizontalPosition++;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(keyEvent.keyCode === keyCodeMoveDown) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;         verticalPosition--;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;     &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;     clearBlocks();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;     drawBlock(verticalPosition, horizontalPosition);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New',courier,monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Next time we’re going to look at tooling to make testing and debugging all this a bit easier and we’re going to get a bit more OO.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You can download the code in this post here:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="/file.axd?file=2010%2f3%2ftetris0.01.rar"&gt;tetris0.01.rar (1.02 kb)&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-5956573458281953185?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/r43Q4WxudJY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/5956573458281953185/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2010/03/diving-into-javascript-with-tetris.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5956573458281953185?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5956573458281953185?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/r43Q4WxudJY/diving-into-javascript-with-tetris.html" title="Diving into JavaScript with Tetris" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2010/03/diving-into-javascript-with-tetris.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IBSHcyfyp7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-578317749866665058</id><published>2010-01-19T12:00:00.000+01:00</published><updated>2011-03-15T14:25:59.997+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T14:25:59.997+01:00</app:edited><title>Using xUnit.Net with .Net 4.0</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/RZf4x0w34Gab70Xn7p2ERdjG53I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/RZf4x0w34Gab70Xn7p2ERdjG53I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/RZf4x0w34Gab70Xn7p2ERdjG53I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/RZf4x0w34Gab70Xn7p2ERdjG53I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I’ve been using xUnit.Net for a while now. It’s just a tiny bit cleaner and slightly less abrasive than other .Net unit testing frameworks. Leaving out unnecessary stuff like [TestFixture] and shortening Assert.AreEqual to the equally clear but shorter Assert.Equal don’t seem like big improvements but when you type them several times a day tiny improvements start to add up. I also like the use of the [Fact] attribute instead of [Test]. It shifts the focus from testing to defining behavior. So how do we get all this goodness working with the Visual Studio 2010 beta?&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;Creating tests is as easy as it normally is, you can just reference xunit.dll it in your 4.0 test-projects. Running your 4.0 tests can be a problem, the testrunners included in the xUnit.net package are compiled against the 2.0 framework so they won’t load 4.0 test-assemblies.&lt;/p&gt; &lt;p&gt;The obvious solution is to just download the source and compile it yourself. (+1 for open source!) Make sure you select the .Net Framework 4 and not the .Net Framework 4 Client profile in the project properties for the console runner because it uses some logging functionality that’s not available in the client profile. Everything will just run after this.&lt;/p&gt; &lt;p&gt;I found an easier solution on &lt;a href="http://www.markhneedham.com/blog/"&gt;Mark Needhams blog&lt;/a&gt; In his article &lt;a href="http://www.markhneedham.com/blog/2009/05/30/xunitnet-running-tests-written-in-visual-studio-2010/"&gt;xUnit.NET: Running tests written in Visual Studio 2010&lt;/a&gt; he explains how you can run the 2.0 console runner with the 4.0 clr by adding a section to the .config file instead of recompiling the whole thing. Adding the following lines to the xunit.console.exe.config should do the trick;&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; ...&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;startup&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;requiredRuntime&lt;/span&gt; &lt;span style="color: #ff0000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="v4.0.20506"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;safemode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="true"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;startup&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; ...&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;I found the same trick works with the gui runner too. Unlike the console runner it doesn’t come with a config file so you need to create one yourself, add the &amp;lt;startup&amp;gt; section and it will load 4.0 test-assemblies.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;When you want better VS.Net integration there are some other testrunners you can use. The easiest here is good old &lt;a href="http://testdriven.net/"&gt;TestDriven.Net&lt;/a&gt;. You can download the version 3 beta for Visual Studio 2010 integration and run your 4.0 tests with it.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Another testrunner that works is the one included with &lt;a href="http://www.jetbrains.com/resharper/"&gt;Resharper&lt;/a&gt;. Normally it isn’t free but &lt;a href="http://www.jetbrains.com/"&gt;Jetbrains&lt;/a&gt; has released a &lt;a href="http://www.jetbrains.com/resharper/beta/beta.html"&gt;public beta&lt;/a&gt; for version 5 that works with Visual Studio 2010. To get xUnit.Net working with Resharper you need the &lt;a href="http://xunitcontrib.codeplex.com/"&gt;xUnit.Net contrib&lt;/a&gt; project. The maintainers have done a great job keeping it up to date with Resharper 5.0 alpha and beta builds so they’ve got a &lt;a href="http://xunitcontrib.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=35006"&gt;version for the latest beta&lt;/a&gt; available.&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-578317749866665058?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/Ln5Bsc2pxxA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/578317749866665058/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2010/01/using-xunitnet-with-net-40.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/578317749866665058?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/578317749866665058?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/Ln5Bsc2pxxA/using-xunitnet-with-net-40.html" title="Using xUnit.Net with .Net 4.0" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2010/01/using-xunitnet-with-net-40.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0ENRXw_fSp7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2393621959886595358</id><published>2009-07-15T13:00:00.000+02:00</published><updated>2011-03-15T15:34:54.245+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T15:34:54.245+01:00</app:edited><title>Agile architecture part II, SOLID or YAGNI?</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/siFdnxByLWawp8X8F0UbWcfrHAs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/siFdnxByLWawp8X8F0UbWcfrHAs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/siFdnxByLWawp8X8F0UbWcfrHAs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/siFdnxByLWawp8X8F0UbWcfrHAs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In a previous post about agile architecture I reasoned why big design up front isn’t a good solution to the problem of handling complexity in software. The best solution is architecting your application to avoid complexity as much as possible. At the end of the post I suggested reducing complexity by not implementing anything you don’t need right now. This principle is well known as YAGNI, short for You Aint Gonna Need It. Don’t implement anything you don’t need now. This will keep complexity down making it simpler to extend when you do need it. There’s another solutions to handling complexity though. You can reduce complexity by modularization. In software engineering we’ve got the SOLID principles for this. Unfortunately the SOLID principles seem to go against what YAGNI tells us. They tell us to add interfaces, separate out our dependencies and add all kinds of structures to our code that we don’t need just yet. So what’s it going to be SOLID or YAGNI?&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;The idea is actually quite simple. Lets look at a purely theoretical piece of software consisting of one component that can have ten states. Now we want to implement a new feature that will cause our piece of software to double in size. You’d think it would double in complexity too but you’d be wrong. When we add a similar component with ten states the total amount of states isn’t 10 + 10 = 20 but 10 * 10 = 100. So instead of doubling the complexity we’ve squared it. This is why spaghetti software will get unmaintainable really fast when size increases.&lt;/p&gt; &lt;p&gt;What we can do to contain this complexity is by separating our software into components or modules. If we construct our software so that we can reason about it’s parts instead of the whole thing we can still fit it in our heads. We don’t need to look at all the 100 states in the previous example when we can the software as separate modules or components. Then we only need to reason about the separate parts and the thin interfaces where they touch each other.&lt;/p&gt; &lt;p&gt;This is where SOLID comes in. I won’t get into the details of the SOLID principles here. Just &lt;a href="http://www.bing.com/search?q=Solid+principles&amp;amp;go=&amp;amp;form=QBLH&amp;amp;filt=all"&gt;bing&lt;/a&gt; them and you’ll find enough hits to explain them. But they give us guidelines on how to partition our software, hiding complexity behind well-defined interfaces and separating components so we can handle them by themselves giving us the ability to handle each part of our code as if it was alone in the world.&lt;/p&gt; &lt;p&gt;So I think we can use them both YAGNI does not tell us to refrain from adding lines of code we’re not going to need. YAGNI tells us not to add complexity we don’t need. SOLID is about removing complexity by separating out components.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2393621959886595358?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/dtLcJgVlcok" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2393621959886595358/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/07/agile-architecture-part-ii-solid-or.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2393621959886595358?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2393621959886595358?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/dtLcJgVlcok/agile-architecture-part-ii-solid-or.html" title="Agile architecture part II, SOLID or YAGNI?" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/07/agile-architecture-part-ii-solid-or.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IMSX0zeyp7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-7891216390182125017</id><published>2009-06-27T16:32:00.000+02:00</published><updated>2011-03-15T15:33:08.383+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T15:33:08.383+01:00</app:edited><title>Agile architecture, embrace change by reducing complexity</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oCZThgbOYVExAUwcTWnQn1TbLwY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oCZThgbOYVExAUwcTWnQn1TbLwY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oCZThgbOYVExAUwcTWnQn1TbLwY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oCZThgbOYVExAUwcTWnQn1TbLwY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Software development can sometimes be very counterintuitive. For example, when people started building larger software systems halfway through the last century one of the things they discovered was that changing existing software is often far more difficult and error prone than building new software. Most developers rediscover this somewhere in their first year of being a professional developer. They start out with a new project and as time goes by changes start taking more and more time, this can be very hard to explain to a client and usually we don’t until we get completely stuck and tell the client we need to start from scratch. I think this practice has been responsible for most of the bad reputation software development has.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;So if changing software is such a hard thing to do we just have to do things right from the beginning. Analyze all requirements the client could ever have, make a design that incorporates all those requirements and then build that, this way we should never have to change anything. Sounds like a great plan but there are three things that make this quite impossible. Clients, stupid programmers and the rest of the world.&lt;/p&gt; &lt;p&gt;First of all clients don’t know what they want. It seems like I’m just trying to shift blame away from developers like me but I’m not. This is just a fact we have to deal with in our profession. Clients are not omniscient. They learn during a project and learning makes them change their mind. Of course there are ways to make sure clients don’t do silly things like this. You can spend more time doing requirements studies so they have a chance to change their mind before we start building or we can write everything down in big contracts so clients aren't allowed to change their mind anymore.&lt;/p&gt; &lt;p&gt;But then we encounter our next hurdle, stupid programmers. See, now I’m laying blame directly at our own feet. Programmers aren’t omniscient either. When you ask them to design a system they will make mistakes. The bigger the system the more mistakes. And most of these mistakes will only show up once you’ve built the system, meaning you have to change the system and we didn’t want to do that. Of course there’s an easy solution for this. You don’t let developers design the system anymore. You’ve got architects for that, they’re easy to find, they live in ivory towers.&lt;/p&gt; &lt;p&gt;So now you’ve spent a year creating the best requirements. Your architects have created a bulletproof design, you can now safely build your system right? Well no. Now you’ve got the real world to contend with. And it changes too.&lt;/p&gt; &lt;p&gt;I think we can safely conclude that resisting change isn’t a solution for our problems. Agile methodologies acknowledge that fact. Agile tells us to embrace change. But how do we make sure our software doesn’t make us regret this? We need to architect our software to embrace change too. Instead of going to around the problem like we used to do we need to get to the bottom of it and eliminate it from our software.&lt;/p&gt; &lt;p&gt;But how do you architect software to be changeable? Well this is another counterintuitive aspect of software engineering. In other engineering practices we have to contend with natural laws that constrain what we do. In structural engineering gravity is a big constraint. When you want to be flexible you build bigger foundations. In electrical engineering Ohm’s law is a constraint, so when you want to be flexible there you build in bigger cooling fins and more powerful power supplies. Software engineering is different in this aspect. Our main concern is complexity so preparing for change by over dimensioning your foundations will only work against you, you’re only making your software more complex, that will not help you fight complexity.&lt;/p&gt; &lt;p&gt;An agile architect will always go for simplicity. Do the simplest thing that will actually work, don't build things you’re not sure you’ll need. Keep responsibilities separated and abstract away everything.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-7891216390182125017?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/DaQ15ca1Dgw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/7891216390182125017/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/06/agile-architecture-embrace-change-by.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7891216390182125017?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7891216390182125017?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/DaQ15ca1Dgw/agile-architecture-embrace-change-by.html" title="Agile architecture, embrace change by reducing complexity" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/06/agile-architecture-embrace-change-by.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cMQng_cCp7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2939171761271411127</id><published>2009-06-17T13:00:00.000+02:00</published><updated>2011-03-17T11:51:23.648+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:51:23.648+01:00</app:edited><title>Using a nested Master Page with ASP.Net</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YNXZI10lzNugyUezES5q81SW6Co/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YNXZI10lzNugyUezES5q81SW6Co/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YNXZI10lzNugyUezES5q81SW6Co/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YNXZI10lzNugyUezES5q81SW6Co/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The first thing I actually missed from Webforms are nested masterpages. Fortunately they’re not missing at all, they just figured out those MVC guys (and galls) like code so much, they don’t need no stinkin’ templates for something as trivial as this. And of course we don’t. Here’s how to roll your own.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;Masterpages are a great way to keep your webpages DRY. Repeating layout/markup/header stuff goes into the masterpage. This is great until you create a bigger site with more than one masterpage. Suddenly you’re repeating code between masterpages. So we go up one more level. We make a masterpage for the masterpages. Yes it’s tortoises all the way down.&lt;/p&gt; &lt;p&gt;We start with two normal masterpages. Master.Master and Child.Master. I’ve always been good in coming up with original names. They’ll both look a bit like this:&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="background-color: #ffff00"&gt;&amp;lt;%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;!&lt;/span&gt;&lt;span style="color: #800000"&gt;DOCTYPE&lt;/span&gt; &lt;span style="color: #ff0000"&gt;html&lt;/span&gt; &lt;span style="color: #ff0000"&gt;PUBLIC&lt;/span&gt; &lt;span style="color: #0000ff"&gt;"-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;html&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://www.w3.org/1999/xhtml"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;head&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;title&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:ContentPlaceHolder&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="TitleContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;title&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;head&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;body&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:ContentPlaceHolder&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="MainContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;body&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;html&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Now we want Master.Master to look exactly like this. And we want Child.Master to look exactly like this but add “Child – “ before the title and we want the content of the child in VERY BIG LETTERS, so we’ll put a &amp;lt;h1&amp;gt; &amp;lt;/h1&amp;gt; tag pair around the ‘MainContent’ contentplaceholder. I wanted to use &amp;lt;blink&amp;gt;, my favorite tag but it’s not supported anymore.&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Of course we can just add all this to Child.Master and be done with it but we want to re-use the Master.Master code. So lets use Master.Master as a masterpage. This works just the way you’d expect. You just add a ‘MasterPageFile’ attribute to the Master tag and use ‘asp:Content’ tags to fill in the contentplaceholders. The big difference with content-pages is that you nest asp:ContentPlaceHolder tags inside the content. These can be filled in later by your pages. This is how your Child.Master will look.&lt;/p&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="background-color: #ffff00"&gt;&amp;lt;%@ Master MasterPageFile="~/Views/Shared/Master.Master" Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:Content&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="TitleContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="MainContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     Child - &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:ContentPlaceHolder&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ContentPlaceHolder1"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:content&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:Content&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="MainContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="MainContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;h1&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:ContentPlaceHolder&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="MainContent"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;h1&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:content&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Have fun!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2939171761271411127?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/bczrZQS56YU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2939171761271411127/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/06/using-nested-master-page-with-aspnet.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2939171761271411127?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2939171761271411127?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/bczrZQS56YU/using-nested-master-page-with-aspnet.html" title="Using a nested Master Page with ASP.Net" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/06/using-nested-master-page-with-aspnet.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8HRHYzcCp7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2879068835618442078</id><published>2009-06-15T13:00:00.000+02:00</published><updated>2011-03-17T11:47:15.888+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:47:15.888+01:00</app:edited><title>ASP.Net MVC … Wow!</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5k2rPHSa9u3wtQGiKbWBsnjXUsk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5k2rPHSa9u3wtQGiKbWBsnjXUsk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5k2rPHSa9u3wtQGiKbWBsnjXUsk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5k2rPHSa9u3wtQGiKbWBsnjXUsk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I’ve been very happy on the windows programming side. I used to do web-programming but frankly ASP.Net web forms ruined that for me. Agreed… it’s very good for quickly setting up administrative websites that run inside the firewall. It has all the right abstractions allowing you to quickly piece together simple grid-based CRUD webapps without worrying about state, postbacks, javascript or even HTML. But when you want to build fun websites that look good and are designed to run on the big bad web these abstractions start to work against you.&lt;/p&gt; &lt;p&gt;Lately I’ve been getting a bit restless though. I need to learn some new stuff. Frankly my job is boring, right now I’m responsible for maintenance and support for a legacy C++ MFC system *yawn* so time to get back into web programming. Enter MVC!&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;Agreed, this is nothing new. Every other platform has had it’s web MVC framework for ages, even .Net has had monorail. But for me it’s new. And completely cool!&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The architecture&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I’ve been working with all kinds of UI patterns on the windows side. MVP, MVC, MVVM and so on hold no secrets for me but the web variant of MVC is a bit different for me. The whole routing thing took some getting used to, the controllers/view interaction is very simple compared to the windows world and I had to do some reading to get an IoC container working. But other than that the programming model is beautiful. No complicated page lifecycles but still every bit as extendable as we’re used to.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Testability&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;In web forms I had a whole bag of tricks to make things testable. Eventually I got some sort of MVP model working where I abstracted away all the page logic to a presenter object that was running behind the page. But the way pages behaved with controls throwing events all over the place this wasn’t as easy as it should have been. You had to be very keen on testing to go this route. In MVC things are the other way around. You have to try very hard to put logic in your views, although I have seen people manage this. Controllers are testable by default and everything is mockable. Great stuff for a TDD junkie like me.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Control&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;In web forms I had all but given up on java script. The controls you put on the page had their own idea about what javascript should run and you had to fight with these to ajaxify your pages. In MVC you have much more control over how your pages look in HTML. This also makes it very easy to add javascript. I’ve even ordered my first jQuery book.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;What am I building?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Wouldn’t you like to know? Right now the project I’m working on is still in the proof of concept phase. I’m trying to get some basic functionality working. If I’m more sure about the possibilities I’ll put a first version online. But that probably won’t be until the end of this year. But you can expect a lot of MVC posts from me in the future.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2879068835618442078?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/LPLyaoY3MXs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2879068835618442078/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/06/aspnet-mvc-wow.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2879068835618442078?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2879068835618442078?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/LPLyaoY3MXs/aspnet-mvc-wow.html" title="ASP.Net MVC … Wow!" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/06/aspnet-mvc-wow.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMNRnY5fip7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2775068273447280042</id><published>2009-06-14T13:00:00.000+02:00</published><updated>2011-03-17T11:41:37.826+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:41:37.826+01:00</app:edited><title>Looking back at Open Space</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/XZMnhAlGMhOoEZkTtyPbkqI7Dms/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XZMnhAlGMhOoEZkTtyPbkqI7Dms/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/XZMnhAlGMhOoEZkTtyPbkqI7Dms/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/XZMnhAlGMhOoEZkTtyPbkqI7Dms/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Last weekend I helped organize the Dutch Open Space Code Day. This wasn’t the first open space event I’ve been to but it was the first one where I was involved in the organization. Kees Dijk and me got the idea from the &lt;a href="http://openspacecode.com"&gt;UK Open Space Code&lt;/a&gt; days that are organized by Alan Dean. And with some help from &lt;a href="http://www.imtech.eu/nl/ict"&gt;Imtech ICT&lt;/a&gt;, who kindly provided space, coffee and lunch, we got going.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;So what did we do all day?&lt;/p&gt; &lt;p&gt;After a short introduction we started the planning phase. This is typical of open space, there are no scheduled speakers, all the scheduling is done at the start of the first day. Attendees propose sessions themselves, &lt;a href="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHlXlCw9yI/AAAAAAAAVRM/ZNhBSOq-9LE/s1600-h/IMG_1761%5B7%5D.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 4px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top: 0px; border-right: 0px; padding-top: 0px" title="IMG_1761" border="0" alt="IMG_1761" align="right" src="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHlYBfO8BI/AAAAAAAAVRQ/cmr3JVOW0PU/IMG_1761_thumb%5B5%5D.jpg?imgmax=800" width="240" height="161"&gt;&lt;/a&gt;everyone votes to see what sessions are most popular. Then sessions are shuffled around to fit the available time and space. The schedule stays fluid for the rest of the event but most of the planning is done right at the start.&lt;/p&gt; &lt;p&gt;I can imagine this is a nervous moment for most open space organizers. What if no-one wants to propose a session? We had nothing to worry about in this respect. Many of the attendees were accomplished speakers on other conferences and I was confident they would also step up here. I wasn’t disappointed. On the right is what the schedule looked like after a couple of minutes proposing sessions.&lt;/p&gt; &lt;p&gt;After the sessions were voted on, combined and thinned out a bit we got going. Subjects ranged from Silverlight to DDD and design by contract, all interesting stuff. The first round of sessions started a bit late. So after only an hour it was already lunch time.&lt;/p&gt; &lt;p&gt;Most people just ate lunch while continuing the morning sessions. We had plenty of time planned for lunch so after about an hour people started coming back to the main room to get some coffee and get ready for another round of sessions. The afternoon round of sessions went by just as fast as the morning sessions.&lt;/p&gt; &lt;p&gt;On the whole I can say the day was a success. I had some worries that there were too many high-profile speakers attending and that this would kill the interactive nature of open-space but this just didn’t seem to be a problem. A couple of things could go better. People didn’t really seem inclined to move from session to session. Normally this is a mechanism in open space that ensures attendees get the most out of the sessions and sessions that are less interesting die out. In this case the quality of content in all the sessions was very high so there wasn’t much need for people to move between sessions.&lt;/p&gt; &lt;p&gt;The focus of Open Space Code is supposed to be on coding. This never got off the ground. Most people had laptops and some code examples were shown but at the end of the day no code was checked in to the Google Code repository that was provided for this day. This probably had to do with the fact that people had to specifically ask to get access to the repository. Next time we’ll try to streamline this process by providing access to a version control system beforehand. This way people can prepare code samples before the event.&lt;/p&gt; &lt;p&gt;I also got some suggestions to make the sessions a bit shorter next year. This time we had two sessions of two hours each to give people enough time to actually do some coding. Next time we’ll probably do three 1,5 sessions instead. This might fit in better with lunch too.&lt;/p&gt; &lt;p&gt;All in all the day was a big success. I’m really looking forward to my next open space event.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2775068273447280042?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/2dIuIDYfoPA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2775068273447280042/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/06/looking-back-at-open-space.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2775068273447280042?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2775068273447280042?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/2dIuIDYfoPA/looking-back-at-open-space.html" title="Looking back at Open Space" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHlYBfO8BI/AAAAAAAAVRQ/cmr3JVOW0PU/s72-c/IMG_1761_thumb%5B5%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/06/looking-back-at-open-space.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUGSXs4eyp7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-7860715394783961269</id><published>2009-05-30T13:00:00.000+02:00</published><updated>2011-03-17T11:37:08.533+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:37:08.533+01:00</app:edited><title>Pomodoro</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LCmyMByoFN1xrntqyGH1X3snaNM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LCmyMByoFN1xrntqyGH1X3snaNM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LCmyMByoFN1xrntqyGH1X3snaNM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LCmyMByoFN1xrntqyGH1X3snaNM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I finally gave up and went with the hype. I admit it, I bought my first piece of Apple hardware. It wasn’t even as expensive as I thought it would be and its shiny. I always had a soft spot for brushed stainless steel. &lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;Here it is, my first Apple product. &lt;a href="http://lh3.ggpht.com/_SJSJB2KxXsg/TYHkUgPHlyI/AAAAAAAAVRE/B9v0sBqb_T8/s1600-h/IMG_1746%5B3%5D.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top: 0px; border-right: 0px; padding-top: 0px" title="IMG_1746" border="0" alt="IMG_1746" align="right" src="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHkU-l_HyI/AAAAAAAAVRI/WKs2sMbp4o0/IMG_1746_thumb%5B1%5D.jpg?imgmax=800" width="200" height="217"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;So why am I blogging about a kitchen utensil you might ask? Well, actually this fruity piece of stainless steel is a productivity enhancer. Let me explain. &lt;/p&gt; &lt;p&gt;Focusing your work is often hard. And many tasks, like programming, need focus. Lots has been written about how interruptions from telephones, coworkers or managers will ruin productivity. But there’s a dirty little secret here. Even when you leave them alone most programmers are perfectly capable of interrupting their own work. They read blogs, have a chat at the coffee machine or read email. Having some time to wind down between work is of course good but but only when you’re able to do focused work in between those distractions. &lt;/p&gt; &lt;p&gt;Part of the problem is that our expectations about ourselves are too high. We expect ourselves to be able to do hours and hours of work. In exceptional circumstances this is possible, when you get into the mythical state of ‘flow’ time just flies by and todo-lists shrink at an alarming rate. But in most circumstances you need short periods to rest your mind in between work. The trick is to keep those rest-periods short and to really focus during work. &lt;/p&gt; &lt;p&gt;Enter the pomodoro. Or in my case a stainless steel apple-timer. &lt;/p&gt; &lt;p&gt;The idea comes from &lt;a href="http://cirillosscrapbook.wordpress.com/"&gt;Francesco Cirillo&lt;/a&gt; who had the same problem us programmers have when studying. Days of study would fly by but when he looked back at what he accomplished during those study he was usually underwhelmed. In order to improve matters he used a tomato shaped kitchen-timer to keep an eye on time. He lives in Italy where a tomato is called a pomodoro and so the pomodoro technique was born. &lt;/p&gt; &lt;p&gt;Francesco realized he needed to do things to be able to focus, time his work-periods and rest-periods and write them down to be able to see if he improved. The technique is actually really simple, just simple enough to work. &lt;/p&gt; &lt;p&gt;The first thing is to achieve focus. You can do this by splitting up your time into periods of focused work with rest-periods in between. The pomodoro technique uses 25 minute work-periods with 5 minute rest-stops in between. After 4 of these you get a longer rest-period. &lt;/p&gt; &lt;p&gt;To make sure you know what you need to do in these periods you need to keep a couple of simple lists. First you need to make a to-do list of the tasks you plan to do during the day. Just write down several tasks on a piece of paper. Set your timer to 25 minutes and start working. When the timer rings you mark a successful pomodoro and take a 5 minute break, you can talk to a colleague go to the bathroom. &lt;/p&gt; &lt;p&gt;The real trick is dealing with interruptions. Normally this is the hard part. Most interruptions can’t be delayed indefinitely. But because your pomodoro is only 25 minutes long you &lt;em&gt;can&lt;/em&gt; often delay interruptions till the next break. Write it down, mark an interruption and continue the pomodoro. &lt;/p&gt; &lt;p&gt;If you want to know more about this check out these resources &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://cirillosscrapbook.wordpress.com/"&gt;Francesco Cirillo’s site&lt;/a&gt;  &lt;li&gt;&lt;a href="http://www.pomodorotechnique.com/"&gt;His book about the technique&lt;/a&gt;  &lt;li&gt;&lt;a href="http://blog.staffannoteberg.com/"&gt;Staffan Noteberg’s blog&lt;/a&gt;  &lt;li&gt;&lt;a href="http://www.pomodoro-book.com/"&gt;Staffan Noteberg’s book&lt;/a&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/1049570704178378821-7860715394783961269?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/ZgEFBQNZUWg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/7860715394783961269/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/05/pomodoro.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7860715394783961269?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/7860715394783961269?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/ZgEFBQNZUWg/pomodoro.html" title="Pomodoro" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHkU-l_HyI/AAAAAAAAVRI/WKs2sMbp4o0/s72-c/IMG_1746_thumb%5B1%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/05/pomodoro.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEDQHszeip7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-3246659590028971390</id><published>2009-03-23T12:00:00.000+01:00</published><updated>2011-03-17T11:27:51.582+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:27:51.582+01:00</app:edited><title>Agile maturity</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6MQE8R5Hk5JBnKdrq4lrdkPbNjY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6MQE8R5Hk5JBnKdrq4lrdkPbNjY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6MQE8R5Hk5JBnKdrq4lrdkPbNjY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6MQE8R5Hk5JBnKdrq4lrdkPbNjY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In the ten years I’ve been programming I’ve learned two pretty important things. &lt;/p&gt; &lt;ol&gt; &lt;li&gt;Project success is about people and teams. No matter your process, good teams will succeed (usually in spite of your process) and bad teams will fail.  &lt;li&gt;Every time you make a rule about something, people will stop thinking about that thing and blindly apply the rule. &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;This sounds pretty bland, even Chinese fortune cookies usually have more interesting things to say, until you think about one of the consequences. You need good people for project success but if you give them too much rules they will stop thinking and become as smart, or as stupid as the rules. Most Methodologies seem to think that more rules is better. If a rule doesn’t benefit you it surely won’t hurt too much, just implement as much as you can and things will surely get better.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;This is one of the reasons I’ve never been fond of things like CMMI, the heavier your process, the more rules you implement, the more mature you are. All in the name of repeatability. You don’t want successful projects to be a fluke you want them to be repeatable. This sounds really good but I think you throw out the baby with the bathwater. You can’t repeat success by copying and pasting because the most important factor is people and you can’t copy and paste people.&lt;/p&gt; &lt;p&gt;This is why I have some trouble with Scott Ambler’s ideas of an &lt;a href="http://www.ibm.com/developerworks/blogs/page/ambler?entry=apmm_overview" target="_blank"&gt;Agile Project Maturity Model&lt;/a&gt;. Don’t get me wrong. I like the idea of having some scale to rate agile implementations but I don't think the scale Scott proposes has much value. It takes all the faulty assumptions from CMMI and applies them to agile. It just doesn’t fit! Agile is not about repeatability, it’s about adaptability. This is why I’d like to propose a different scale, one based on the &lt;a href="http://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition" target="_blank"&gt;Dreyfus model&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;I think maturity is about learning. And, coincidentally so is the &lt;a href="http://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition" target="_blank"&gt;Dreyfus model&lt;/a&gt;. It has five levels&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Novice - rigid adherence to rules  &lt;li&gt;Advanced beginner – limited situational perception  &lt;li&gt;Competent - deliberate planning  &lt;li&gt;Proficient - holistic view of situation, rather than in terms of aspects  &lt;li&gt;Expert - no longer reliance on rules, guidelines, maxims &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;I think organizations learn just like individuals. These levels can be applied to teams and organizations. You see this in Ken Schwaber’s books on Scrum for example. Organizations starting with Scrum should first start applying all the rules very rigidly, but after some time this is counterproductive. The rules can be adapted in project retrospectives, the organization is learning. &lt;/p&gt; &lt;p&gt;A mature organization should apply the right rules to the right projects leaving their professionals with enough room to react to changing requirements in every situation. A mature organizations should also recognize that less mature teams within that organization will need a different set of rules than more mature teams.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-3246659590028971390?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/cYZspVYo2HE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/3246659590028971390/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/03/agile-maturity.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/3246659590028971390?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/3246659590028971390?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/cYZspVYo2HE/agile-maturity.html" title="Agile maturity" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/03/agile-maturity.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4MQHc9fCp7ImA9WhZTE0g.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-6467230168201492181</id><published>2009-03-08T12:00:00.001+01:00</published><updated>2011-03-17T11:33:01.964+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-17T11:33:01.964+01:00</app:edited><title>Not all quality is free. But it’s cheaper than you think</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1S7fziHGSnIJk5w71EH8HKc6KyQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1S7fziHGSnIJk5w71EH8HKc6KyQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1S7fziHGSnIJk5w71EH8HKc6KyQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1S7fziHGSnIJk5w71EH8HKc6KyQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I started writing a reply to &lt;a href="http://softwaredevelopmenttoday.blogspot.com/2009/03/perfection-in-software-is-cheaper-not.html" target="_blank"&gt;this post&lt;/a&gt; but it got kind of long, by the time I started thinking about adding pictures it dawned on me that it’s probably a good idea to write my own post on the subject. &lt;/p&gt; &lt;p&gt;The discussion here is based on an idea from lean development. Traditionally people thought that quality had a price. Removing defects has a cost so more quality means higher cost. Lean production tells us this is not true. If you remove the defects sooner you can remove them cheaper. By removing the cause of the defects you can prevent them from being added. This will not only improve the quality but actually remove the cost of fixing the defects. Agile methodologies like XP show us that this works for software too. Up to a point.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;There are a couple of ways you can prevent defects from appearing in your software. The two most effective things you can do are TDD or test first development and pair programming. Both give you early feedback about defects and prevent you from introducing them. Both have their own types of defects they will prevent. Test first programming seems suited for removing defects related to low level behavior of components in your software. Pair programming has a more wide range of defects it will prevent, having two pairs of eyes and two brains look at the same piece of code. I’ve found that most errors it prevents are maintenance related. High level interaction problems are usually too complex to find this way.&lt;/p&gt; &lt;p&gt;The biggest improvement in quality you will get from these methods is not so obvious though. I’ve found both methods force you to think about low level specifications before implementing them. Writing a test forces you to think about how the code you’re testing is going to behave. You’ll have to specify this behavior in your test before implementing it. Writing down executable specifications like this is very powerful. I’ve found the dynamics of TDD don’t feel like testing at all. It focuses the development effort but TDD &lt;em&gt;will not replace testing.&lt;/em&gt; Simply because you won’t find all classes of errors.&lt;/p&gt; &lt;p&gt;I’ve found two places where developer testing breaks down.&lt;/p&gt; &lt;p&gt;The most obvious place is in testing your requirements. Requirements are notoriously imprecise. Problems in writing down the requirements or in interpreting the requirements will often only be found in an additional inspection phase. Software might be working correctly but is it actually doing the right thing. Usability issues also fall in this category.&lt;/p&gt; &lt;p&gt;Integration of components is also a source of defects that won’t be found with TDD or pair programming. In simple cases where components just call each other integration issues are often found by the compiler. But in more complex cases, for example when components should work together in a multithreaded application defects are almost inevitable.&lt;/p&gt; &lt;p&gt;I don’t think you can eliminate inspection. Software is just too complex. I don’t think zero defects is achievable either. But when looking at common development practices today I think there is a lot of low hanging fruit. Most development organizations can indeed save on inspection and defect-removal by increasing quality using these practices. But even then they’ll be a long way from zero defects.&lt;/p&gt; &lt;p&gt;The original fallacy was to think the cost of removing defects was a straight line that went up. But assuming the cost per defect is a straight line with a downward slope is too simplistic too. Here’s the picture I promised:&lt;a href="http://lh3.ggpht.com/_SJSJB2KxXsg/TYHhUXLQH_I/AAAAAAAAVQ4/NCL2PxksDFk/s1600-h/quality_2%5B6%5D.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="quality_2" border="0" alt="quality_2" src="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHhUlmoNJI/AAAAAAAAVQ8/n6-TATu7jqQ/quality_2_thumb%5B4%5D.jpg?imgmax=800" width="556" height="174"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Quality will eventually cost you money when all the easy bugs are gone. But until then we should invest in it as much as we can.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-6467230168201492181?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/NT-bZLBy-zc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/6467230168201492181/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/03/not-all-quality-is-free-but-its-cheaper_08.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/6467230168201492181?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/6467230168201492181?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/NT-bZLBy-zc/not-all-quality-is-free-but-its-cheaper_08.html" title="Not all quality is free. But it’s cheaper than you think" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_SJSJB2KxXsg/TYHhUlmoNJI/AAAAAAAAVQ8/n6-TATu7jqQ/s72-c/quality_2_thumb%5B4%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/03/not-all-quality-is-free-but-its-cheaper_08.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYEQnk7cCp7ImA9WhZTEko.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-4555594920246167141</id><published>2009-02-22T12:00:00.000+01:00</published><updated>2011-03-16T13:05:03.708+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-16T13:05:03.708+01:00</app:edited><title>Chaos in WPF</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yDhsVXivRmvdeA2dBLGEgp6-z3Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yDhsVXivRmvdeA2dBLGEgp6-z3Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yDhsVXivRmvdeA2dBLGEgp6-z3Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yDhsVXivRmvdeA2dBLGEgp6-z3Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_SJSJB2KxXsg/TYCnbCljAlI/AAAAAAAAVQo/4MT_CNj79KQ/s1600-h/feigenbaum_2%5B3%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="feigenbaum_2" border="0" alt="feigenbaum_2" align="left" src="http://lh4.ggpht.com/_SJSJB2KxXsg/TYCnbmpZUpI/AAAAAAAAVQs/BQ8DjiQYECE/feigenbaum_2_thumb%5B1%5D.png?imgmax=800" width="240" height="140"&gt;&lt;/a&gt;I’ve been reading up on math lately. Mostly chaos theory and nonlinear dynamics. I still don’t get why they don’t teach stuff like this in school, I might have even found math fun if they had done so, part of the fun of these areas of mathematics are the cool graphics they produce. Everyone knows the Mandelbrot set, but in this post I want to focus more on chaos theory. And to make it interesting for my usual readers lets draw some pictures with WPF&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;But first some math to scare off all the wanna-be geeks out there. We’re going to have a look at the logistic map. &lt;/p&gt; &lt;p&gt;x&lt;span style="vertical-align: sub" class="Apple-style-span"&gt;n+1&lt;/span&gt; = x&lt;span style="vertical-align: sub" class="Apple-style-span"&gt;n&lt;/span&gt;r(1 – x&lt;span style="vertical-align: sub" class="Apple-style-span"&gt;n&lt;/span&gt;) &lt;/p&gt; &lt;p&gt;This function was thought up by the mathematician Pierre François Verhulst to model population growth. The function models two things, bigger populations grow faster until they get too big, then growth will be limited by competition for resources. When you look at the function you will see that it’s a non-linear difference equation. &lt;/p&gt; &lt;p&gt;The fun starts when you start playing with r. For small values of r the x will quickly go to zero and stay there. Things get more interesting for r &amp;gt; 1, first x will stabilize on some value. The stable value for x gets bigger as r gets bigger, but for values of r bigger than 3 x will actually start to oscillate, first between 2 values, then between 4 values, then 8 and then the behaviour of x will become chaotic. You can plot this out and you will get a nice fractal-image. If you zoom in on part of the image you will see the same image repeated. &lt;/p&gt; &lt;p&gt;I wanted to see if I could plot this. My previous toy project was done with WinForms but I found drawing pixels a bit cumbersome. This time I wanted to try out WPF. I found that drawing single pixels in WPF is not trivial either but with a little help from the WriteableBitmap component I could access single pixels in a bitmap. I’d like to have a simple panel component that I can reuse for simple toy projects like this so I quickly built a nice BitmapPanel. Here’s the interface definition. The source code for it is included in the project files if you want to see how it works. &lt;/p&gt; &lt;div&gt; &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IBitmapPanel&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; PixelWidth { get; }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; PixelHeight { get; }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; Action Redraw;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetPixel(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; y, &lt;span style="color: #0000ff"&gt;byte&lt;/span&gt; color);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;byte&lt;/span&gt; GetPixel(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; y);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;You get redraw events every time the panel changes shape. You can retrieve the size of the panel and you can get and set pixels. Simple enough but usable. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;I now could put the bitmap panel on a window and build a presenter object around it. The presenter is where all the interesting stuff happens, it looks like this: &lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ChaosPresenter&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IBitmapPanel View { get; set;}&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Initialize()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         View.Redraw += RedrawHandler;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; RedrawHandler()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;         var width = View.PixelWidth;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (var i = 0; i &amp;lt; width; i++)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;             var factor = i*3f/width + 1;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;             Iterate(i, factor);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetPixelScaleY(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;float&lt;/span&gt; y)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;         var ycoordinate = (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;)((1.0f - y) * View.PixelHeight);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;         var index = x + ycoordinate * View.PixelWidth;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;         View.SetPixel(x, ycoordinate, (&lt;span style="color: #0000ff"&gt;byte&lt;/span&gt;)((View.GetPixel(x, ycoordinate) + 0xFF) / 2));&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Iterate(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;float&lt;/span&gt; factor)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;         var number = .2f;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(var i = 0; i &amp;lt; 100; i++)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  33:&lt;/span&gt;         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  34:&lt;/span&gt;             number = GetNextIteration(factor, number);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  35:&lt;/span&gt;         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  36:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  37:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(var i = 0; i &amp;lt; 1000; i++)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  38:&lt;/span&gt;         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  39:&lt;/span&gt;             SetPixelScaleY(x, number);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  40:&lt;/span&gt;             number = GetNextIteration(factor, number);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  41:&lt;/span&gt;         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  42:&lt;/span&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  43:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  44:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;float&lt;/span&gt; GetNextIteration(&lt;span style="color: #0000ff"&gt;float&lt;/span&gt; factor, &lt;span style="color: #0000ff"&gt;float&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  45:&lt;/span&gt;     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  46:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; factor*&lt;span style="color: #0000ff"&gt;value&lt;/span&gt;*(1f -&lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  47:&lt;/span&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  48:&lt;/span&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;It wraps the IBitmapPanel and redraws the complete diagram every time it resizes. The RedrawHandler is where stuff happens. It maps different values for r between 1 and 4 on the x axis of the bitmap panel and calls Iterate for all those values of r. Iterate starts at x = 0.2 and throws away the first 100 iterations. This allows x to stabilize into the typical behavior for that value of r. Then it iterates through the next 1000 values and plots them.&amp;nbsp; GetNextIteration is my implementation of the logistic function. You can play with the values in Iterate if you like. By changing the number of iterations on line 32 you can see how quicly x settles in it’s typical behaviour for different values of r for example. I got the image at the start of this post by iterating 10 times before starting to plot. You can see that x settles pretty quick for most values of r, but near r = 1 and r = 3 it takes more iterations for x to settle down. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The executable can be downloaded here: &lt;a href="/file.axd?file=2009%2f2%2fChaosExecutable.zip"&gt;ChaosExecutable.zip (5.43 kb)&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;And code is available here: &lt;a href="/file.axd?file=2009%2f2%2fChaos.zip"&gt;Chaos.zip (10.36 kb)&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-4555594920246167141?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/5NZBToDXsR4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/4555594920246167141/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/02/chaos-in-wpf.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/4555594920246167141?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/4555594920246167141?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/5NZBToDXsR4/chaos-in-wpf.html" title="Chaos in WPF" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_SJSJB2KxXsg/TYCnbmpZUpI/AAAAAAAAVQs/BQ8DjiQYECE/s72-c/feigenbaum_2_thumb%5B1%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/02/chaos-in-wpf.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQHSX0_fSp7ImA9WhZTEks.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-5050201392216985350</id><published>2009-02-12T12:00:00.000+01:00</published><updated>2011-03-16T10:38:58.345+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-16T10:38:58.345+01:00</app:edited><title>I can’t go to bed right now</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9EakDsM01rEkwBR0-QaMMQmDpoY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9EakDsM01rEkwBR0-QaMMQmDpoY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9EakDsM01rEkwBR0-QaMMQmDpoY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9EakDsM01rEkwBR0-QaMMQmDpoY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://xkcd.com/386/" target="_blank"&gt;&lt;img style="display: inline; margin-left: 0px; margin-right: 0px" align="right" src="http://imgs.xkcd.com/comics/duty_calls.png" width="148" height="144"&gt;&lt;/a&gt;&lt;a href="http://www.codinghorror.com/blog/" target="_blank"&gt;Someone&lt;/a&gt; is wrong on the internet.&lt;/p&gt; &lt;p&gt;In the past few episodes of the &lt;a href="http://blog.stackoverflow.com/" target="_blank"&gt;stackoverflow podcast&lt;/a&gt; Joel Spolsky and Jeff Atwood already talked about SOLID principles and TDD saying they don’t really care for it, they both seem to have been successful without it. They also admitted neither of them had any real experience with this style of programming. This is why I find it really surprising Jeff even took the trouble of writing &lt;a href="http://www.codinghorror.com/blog/archives/001225.html" target="_blank"&gt;another blog post&lt;/a&gt; about this voicing his opinions about a set of principles he clearly has never practiced.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;First of all I find this post very unprofessional. In the short ten years I’ve been programming I’ve seen lots of practices, rules, patterns, principles, styles and methodologies. Some of them are successful, some of them aren’t. Some of them work in some situations and some of them never work and I never get tired of hearing people talk about what worked for them, what didn’t work for them and why. This post isn’t about that. Jeff admitted to not having much experience trying these principles, he does seem to have a couple of issues with rules though.&lt;/p&gt; &lt;p&gt;Jeff also seems to completely miss the point on what principles actually are. He goes on a rant of why rules are bad but &lt;strong&gt;principles aren't rules. &lt;/strong&gt;In fact I think they are almost the opposite of rules. Rules are what made the 2Life Crew change the lyrics of their hit song &lt;a href="http://www.youtube.com/watch?v=IN3P_ttCffk" target="_blank"&gt;Me so horny&lt;/a&gt; without changing its meaning. Principles are what drives you to not let your little sister listen to it. Rules tell you what to do in any situations. Principles describe where you want to go leaving you to decide what the next step will be to get you just a little closer.&lt;/p&gt; &lt;p&gt;The case for or against SOLID and TDD seems familiar. It’s an old discussion of efficiency vs. effectiveness. Not doing TDD and not doing things SOLID lets me write loads of code really fast, its really efficient. But programming is not about writing code. This may surprise some people. Programming is design. It’s about thinking. It will surprise you how &lt;a href="http://answers.yahoo.com/question/index?qid=20080325193536AAl5OKQ" target="_blank"&gt;few lines of code&lt;/a&gt; an average programmer writes, so typing is not a bottleneck. There are other bottlenecks. Maintenance and readability. SOLID and TDD address these bottlenecks leading to well partitioned readable code. The dynamics of writing code change from frantic sprints and evenings of bug-hunting to a sustainable pace.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-5050201392216985350?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/BgrfLuHyb2g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/5050201392216985350/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/02/i-cant-go-to-bed-right-now.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5050201392216985350?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5050201392216985350?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/BgrfLuHyb2g/i-cant-go-to-bed-right-now.html" title="I can’t go to bed right now" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/02/i-cant-go-to-bed-right-now.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcFRnY_eCp7ImA9WhZTEk0.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-8606056726428192608</id><published>2009-02-01T12:00:00.000+01:00</published><updated>2011-03-15T17:20:17.840+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T17:20:17.840+01:00</app:edited><title>More about dependency injection</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/JsmaRFTL62DF1yCj6xHmBMUreUY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JsmaRFTL62DF1yCj6xHmBMUreUY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/JsmaRFTL62DF1yCj6xHmBMUreUY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JsmaRFTL62DF1yCj6xHmBMUreUY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In a &lt;a href="/post/Using-Singletons-Safely.aspx" target="_blank"&gt;previous post&lt;/a&gt; I talked about problems caused by singletons and how to solve them using dependency injection. I mainly talked about constructor injection. In a reaction to that post &lt;a href="http://roytang.net/" target="_blank"&gt;Roy Tang&lt;/a&gt; voiced his concerns about scaling contructor injection. In real life applications you often have a lot of dependencies, passing them through constructors can become a problem in real life solutions where you’ve got objects with lots of dependencies. Usually when manual IoC does not scale anymore I use an IoC container. But this might not always be an option. In this post I want to talk about a few ways to get around this problem.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;&lt;span style="font-size: 13px; font-weight: bold" class="Apple-style-span"&gt;Are you solving the right problem?&lt;/span&gt;&lt;/p&gt; &lt;p&gt;Often problems like these are indicators of other problems. The first thing to look for when you’ve got classes that have too many dependencies is the single responsibility principle. Classes often have too many dependencies because they do too much. You might want to split up that class in a few more granular classes.&lt;/p&gt; &lt;p&gt;One solution to avoid is reusing dependencies between classes. For example it might be tempting to rewrite this;&lt;/p&gt; &lt;div&gt; &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassA {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ClassA(ILogger logger, ClassB objectB) {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// ...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassB {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ClassB(ILogger logger) {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// ...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;to this:&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassA {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ClassA(ClassB objectB) {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// ...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassB {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ILogger Logger {get; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; set;}&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ClassB(ILogger logger) {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;       Logger = logger;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Eliminating ClassA’s dependency on the logger, it can just reuse ClassB’s logger, right? Well no, this breaks the single responsibility principle. The logger reference has become part of the public interface of ClassB effectively giving ClassB an extra responsibility as a LoggerProvider.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Alternatives to constructor injection.&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Constructor injection is not always the right way to do things, so you might want to inject your dependencies somewhere else. Property or method injection might be good alternatives.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Property injection exposes dependencies as properties. Property injection is a bit more flexible than constructor injection but also a bit more dangerous. It allows you to set dependencies one at a time, this can be good when you’re testing something that doesn’t need the full set of dependencies reducing the size of your tests. But it can also cause objects to be only partially initialized causing problems. Property injection is very powerful but it gives you a lot of rope to hang yourself with too, be careful using it outside of an IoC container.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If a class only uses a dependency in one method you might want to pass that dependency as a parameter to that method instead of having it passed into the constructor, this is called method injection. For example the following class:&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Shape {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Shape(Canvas canvas) {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// ...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;    &lt;span style="color: #008000"&gt;// ...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Draw() {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// draw to the canvas&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;might be better implemented as:&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Shape {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;    &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;    &lt;span style="color: #008000"&gt;// ...   &lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Draw(Canvas canvas) {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;       &lt;span style="color: #008000"&gt;// draw to the canvas&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;    }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size: 13px; font-weight: bold" class="Apple-style-span"&gt;Using Defaults&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In addition to using different forms of dependency injection when needed you can reduce the amount of code by providing default dependencies. I wouldn’t do this in large projects because adds some coupling but it can be a good way to reduce the amount of “wiring” code and still maintain some testability.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For the ClassA class from the first example would look like this:&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassA {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ClassA() &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;       : &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LoggerImplementation(), &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ClassB())&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;    { }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ClassA(ILogger logger, ClassB objectB)&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Providing you with a two options. You can then use the default constructor in your code and the DI constructor in your tests.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For large applications using an IoC container still gives you the most flexibility with the least trouble. I hope I’ve given a good overview of the options you’ve got for maintaining dependencies when you don’t have access to one of those.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-8606056726428192608?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/YiPv1JiaNHc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/8606056726428192608/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/02/more-about-dependency-injection.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/8606056726428192608?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/8606056726428192608?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/YiPv1JiaNHc/more-about-dependency-injection.html" title="More about dependency injection" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/02/more-about-dependency-injection.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cGQ30zcSp7ImA9WhZTEk0.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2998947313370169703</id><published>2009-01-08T12:00:00.000+01:00</published><updated>2011-03-15T17:03:42.389+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T17:03:42.389+01:00</app:edited><title>Fun with planets</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pzwAa-M7IVufpBs3a_X6F_B0EyE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pzwAa-M7IVufpBs3a_X6F_B0EyE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pzwAa-M7IVufpBs3a_X6F_B0EyE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pzwAa-M7IVufpBs3a_X6F_B0EyE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_SJSJB2KxXsg/TX-N22vHs-I/AAAAAAAAVQU/x-oapRAUuxw/s1600-h/screenshot%5B5%5D.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 8px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="screenshot" border="0" alt="screenshot" align="right" src="http://lh3.ggpht.com/_SJSJB2KxXsg/TX-N3X-WFpI/AAAAAAAAVQY/gZuG80e2R5c/screenshot_thumb%5B3%5D.jpg?imgmax=800" width="155" height="155"&gt;&lt;/a&gt; Over the holidays I finally got around to doing some recreational coding again. The results even surprised me so I thought I’d share it with my blog-readers. So here it is, your very own planitarium. Planets flying around with real gravity just like Newton taught us (who needs all that fancy new-fangled relativity anyway), and if you feel like it you can even play God and slingshot planets into outer space. Just try clicking anywhere in or around the window.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;I also included the source code although I’m not particularly proud of it. I’ve spent more time playing with the program than actually writing nice code. It’s been a long time since I’ve actually written code without tests. The code itself is quite simple. There’s a galaxy object that contains and handles all the planet interaction. There’s a body object that comes in two flavours, a normal one and a mousebody that represents the mouse position. They both implement IBody so the Galaxy doesn’t care what bodies there are. The normal body objects fly around. The MouseBody always has the position of the mousepointer and only has mass when you push a mousebutton.&lt;/p&gt; &lt;p&gt;That’s about it. There’s a planetariumview and a presenter object that handle painting the whole planet stuff. There’s a Time object that wraps a timer for the heartbeat and there is a program that wires it all together.&lt;/p&gt; &lt;p&gt;Enjoy! and let me know if you do anything fun with it.&lt;/p&gt; &lt;p&gt;Code: &lt;/p&gt; &lt;p&gt;&lt;a href="/file.axd?file=2009%2f1%2fPlanetarium.rar"&gt;Planetarium.rar (13.85 kb)&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Binary:&lt;/p&gt; &lt;p&gt;&lt;a href="/file.axd?file=2009%2f1%2fPlanetarium.exe"&gt;Planetarium.exe (16.00 kb)&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2998947313370169703?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/idDiXQ17HZ8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2998947313370169703/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2009/01/fun-with-planets.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2998947313370169703?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2998947313370169703?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/idDiXQ17HZ8/fun-with-planets.html" title="Fun with planets" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_SJSJB2KxXsg/TX-N3X-WFpI/AAAAAAAAVQY/gZuG80e2R5c/s72-c/screenshot_thumb%5B3%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2009/01/fun-with-planets.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04BRHk9cSp7ImA9WhZTEUQ.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-2317388365077116940</id><published>2008-12-14T12:00:00.000+01:00</published><updated>2011-03-15T15:39:15.769+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T15:39:15.769+01:00</app:edited><title>Why software engineering is NOT like structural engineering</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PbVZu55It0cdk0WQ_bjvogDPGLI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PbVZu55It0cdk0WQ_bjvogDPGLI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PbVZu55It0cdk0WQ_bjvogDPGLI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PbVZu55It0cdk0WQ_bjvogDPGLI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_SJSJB2KxXsg/TX953tYdxAI/AAAAAAAAVQI/bwTcXdmg7F8/s1600-h/121_2%5B3%5D.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="121_2" border="0" alt="121_2" align="right" src="http://lh4.ggpht.com/_SJSJB2KxXsg/TX954MgM4CI/AAAAAAAAVQM/Sny2oyZ6fD0/121_2_thumb%5B1%5D.jpg?imgmax=800" width="160" height="240"&gt;&lt;/a&gt;While cycling home from work today I was listening to the &lt;a href="http://deepfriedbytes.com/" target="_blank"&gt;Deep Fried Bytes&lt;/a&gt; episode with &lt;a href="http://blogs.msdn.com/ricom/" target="_blank"&gt;Rico Mariani&lt;/a&gt;. I should have been warned by his introduction; “He has an analogy for everything”. But since he seems to be a smart person the good old “Software engineering is just like structural engineering” caught me by surprise. I thought we ditched that one together with the waterfall process.&lt;/p&gt; &lt;p&gt;Usually this analogy is used to get people to do big up front design. “You wouldn’t start pouring concrete for the foundations when you don’t know how many stories your building should have” In structural engineering you need to finish a design before you start building.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;But in software engineering all we do is design. Sure, in waterfall you have a design and implementation phase. But if you look more closely implementation has nothing to do with building anything. It’s design on a more detailed level, code is design too just like UML. The only thing we do that looks the slightest bit like building is deploying our software. Luckilly I’ve never seen anyone deploy software that they havent designed yet.&lt;/p&gt; &lt;p&gt;The forces in software design are also completely different from structural engineering. Any good software design is highly decoupled. This means that you don’t have a foundation that should change whenever another part of the “building” changes. In structural engineering you don’t have that luxury. We don’t have the technology to decouple gravity yet so every time you add to your building you’re going to need a bigger foundation.&lt;/p&gt; &lt;p&gt;Another reason we’re so big on decoupling is that software engineering is hard for completely different reasons than structural engineering. Complexity is a much bigger factor in software. Requirements change a lot more too. I’m not trying to say software engineering is harder in any way or that structural engineers don’t have problems with complexity or customers who change their minds. But in software engineering these things play a much bigger role. Luckilly we can handle these problems by decoupling the different parts of our design so we only have to handle the complexity of the individual components and can change around pieces if the customer needs something new.&lt;/p&gt; &lt;p&gt;So if software engineering is all about complex and flexible designs how should we go about creating them? Waterfall tells us to finish our high level design first and then fill in the details. The problem with this is changing requirements and no feedback on the quality of the design. Should we do bottom up design then? Start small and add more pieces later like agile tells us to do? I think we should do both. Work bottom up but be shure you have a rough sketch of what you’re trying to design. Don’t spend too much time on it because you’re probably going to throw it a way at least a couple of times before your building is finished.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-2317388365077116940?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/h77_4lFDXXY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/2317388365077116940/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2011/03/why-software-engineering-is-not-like.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2317388365077116940?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/2317388365077116940?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/h77_4lFDXXY/why-software-engineering-is-not-like.html" title="Why software engineering is NOT like structural engineering" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_SJSJB2KxXsg/TX954MgM4CI/AAAAAAAAVQM/Sny2oyZ6fD0/s72-c/121_2_thumb%5B1%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2011/03/why-software-engineering-is-not-like.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UNRXoyfSp7ImA9WhZTEk0.&quot;"><id>tag:blogger.com,1999:blog-1049570704178378821.post-5698671024168599492</id><published>2008-12-09T12:00:00.001+01:00</published><updated>2011-03-15T17:08:14.495+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-15T17:08:14.495+01:00</app:edited><title>Using Singletons Safely</title><content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SN2tJgxRu4eGh5gmrWW0YArXZqg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SN2tJgxRu4eGh5gmrWW0YArXZqg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SN2tJgxRu4eGh5gmrWW0YArXZqg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SN2tJgxRu4eGh5gmrWW0YArXZqg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank"&gt;singleton&lt;/a&gt; is probably the best known of the &lt;a href="http://en.wikipedia.org/wiki/Gang_of_Four_(software)" target="_blank"&gt;GoF Design Patterns&lt;/a&gt;, it’s also the most controversial. I try avoid using singletons in my code when I can but since the singleton is a very simple but powerful pattern I sometimes sin against the decoupling gods and use one or two of them. Lots of stuff has been written about &lt;em&gt;creating&lt;/em&gt; singletons. In this post I want to show you how properly &lt;em&gt;use&lt;/em&gt; a singleton and contain most of the damage singletons do.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;This post was inspired by a Twitter discussion I had with &lt;a href="http://twitter.com/LaTtEX" target="_blank"&gt;@LaTtEX&lt;/a&gt; who blogs &lt;a href="http://dotnet.kapenilattex.com/" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt; &lt;p&gt;First lets talk about all the reasons &lt;em&gt;not&lt;/em&gt; to use a singleton. The objection I hear most against singletons is thread safety. The problem here is that if two threads access the the singleton simultaneously when the singleton isn’t created yet the singleton might accidentally create two instances of itself. The naive implementation has this problem and even some solutions that have been suggested like &lt;a href="http://www.ibm.com/developerworks/java/library/j-dcl.html" target="_blank"&gt;double checked locking&lt;/a&gt; aren’t completely thread safe. This isn’t why I dislike singletons though. I think the biggest problem with singletons is coupling.&lt;/p&gt; &lt;p&gt;Singletons are accessed through &lt;a href="/post/When-to-use-static-methods.aspx" target="_blank"&gt;static methods&lt;/a&gt;. Calling a static method couples your code to the implementation of that method so every call to the Instance property or method of a singleton makes your code harder to test and harder to maintain. A call to a singleton by definition has side effects. Usually these are very large, singletons are usually used for resource intensive objects that you only want to create once. You don’t want to be coupled to code with severe side effects.&lt;/p&gt; &lt;p&gt;My strategy for defusing singletons is actually quite simple. Reduce the number of MySingleton.Instance calls. Lets say we have a singleton for logging that we want to use in a repository class, something like this.&lt;/p&gt; &lt;div&gt; &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Repository&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;MyClass&amp;gt; ReadObjects()&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;         Logger.Instance.LogMessage(&lt;span style="color: #006080"&gt;"ReadObjects started"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         &lt;span style="color: #008000"&gt;// ..code..&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;         Logger.Instance.LogMessage(&lt;span style="color: #006080"&gt;"ReadObjects finished"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; StoreObject(MyClass anObject)&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         Logger.Instance.LogMessage(String.Format(&lt;span style="color: #006080"&gt;"StoreObject {0} started"&lt;/span&gt;, anObject.Id));&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;         &lt;span style="color: #008000"&gt;// ..code..&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;         &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;         Logger.Instance.LogMessage(&lt;span style="color: #006080"&gt;"StoreObject finished"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Coupling-wise things can’t get much worse than this. Every time something is logged Logger.Instance gets called making our Repository object depend not only on the Logger class but also on it’s implementation as a singleton. This is not something we want our repository to be aware of. We can easilly make this a bit better by creating the instance once and reusing it.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Repository&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Logger logger = Logger.Instance;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;MyClass&amp;gt; ReadObjects()&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         logger.LogMessage(&lt;span style="color: #006080"&gt;"ReadObjects started"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;         &lt;span style="color: #008000"&gt;// ..etc..&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;The code is a little bit better because I’m not repeating my mistake over and over but I’m still not satisfied. Let’s see how I can improve this even further.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Repository&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; { &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Logger logger;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Repository(Logger logger)&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.logger = logger;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;MyClass&amp;gt; ReadObjects()   &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     {   &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;         logger.LogMessage(&lt;span style="color: #006080"&gt;"ReadObjects started"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         &lt;span style="color: #008000"&gt;// ..etc..&lt;/span&gt;&lt;/pre&gt;&lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Here I used the constructor to inject the logger instance into my class. This is a simple concept but it has a big impact on the flexibility of your code. Your classes aren’t aware of how objects need to be instantiated anymore. This makes code more testable and maintainable. You can inject a class that derives from Logger, as long as it works the same as its base class this will just work. Usually I even hide classes that provide a common service like logging or caching behind an interface to decouple usage of instances even more from their implementation.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If you really paid attention you probably noticed that by having the Logger injected into the Repository in its constructor you have made the instantiation of the singleton a bit less lazy. You might never even call ReadObjects and never need the Logger. If you really need instantiation to be that lazy you could inject the Logger as a parameter into the ReadObjects method, I found that usually injecting in the constructor is fine.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You might say that by pushing the call to Instance out of my repository into the code that creates the repository I have only moved the problem somewhere else, and you would be right. But this problem can actually be solved by moving it. As long as you move it in the right direction. I’ve put the code that creates the repository and the code that gets an instance of the Logger together. If you do this for more of your code you’ll end up with creation and usage of your classes nicely separated with all the code that’s responsible for wiring up your application nicely centralized.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1049570704178378821-5698671024168599492?l=www.mendeltsiebenga.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MendeltSiebenga/~4/PK6MPGFOCkU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.mendeltsiebenga.com/feeds/5698671024168599492/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.mendeltsiebenga.com/2008/12/using-singletons-safely_09.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5698671024168599492?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1049570704178378821/posts/default/5698671024168599492?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MendeltSiebenga/~3/PK6MPGFOCkU/using-singletons-safely_09.html" title="Using Singletons Safely" /><author><name>Mendelt Siebenga</name><uri>http://www.blogger.com/profile/16167357910199702130</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.mendeltsiebenga.com/2008/12/using-singletons-safely_09.html</feedburner:origLink></entry></feed>

