tag:blogger.com,1999:blog-91946779423087420512024-03-14T06:33:51.355-04:00Mike Dellanoce's BlogAnonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.comBlogger25125tag:blogger.com,1999:blog-9194677942308742051.post-30686354660263987992013-04-19T13:58:00.000-04:002013-04-19T14:14:59.661-04:00CoffeeScript Tip: Modular CakefileRecently I have been working in <a href="http://coffeescript.org/" target="_blank">CoffeeScript</a> a bit. One of the many nice parts of CoffeeScript is <a href="http://coffeescript.org/#cake" target="_blank">Cake</a>, a lightweight build system that ships with CoffeeScript. If your Cakefile starts to get a bit long, it is a piece of cake (no pun intended) to split it up into more manageable... uh... slices? (Okay, sorry, no more bad cake jokes)<br />
<br />
<script src="https://gist.github.com/mdellanoce/5421923.js"></script><br />
Now anytime you want to define a new task you can put it in its own file in the tasks folder rather than fattening up your Cakefile. If you feel like being extra fancy, check out <a href="https://github.com/ryanmcgrath/wrench-js" target="_blank">wrench</a> which will let you load tasks recursively.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-31765058973741220382012-09-14T15:48:00.001-04:002012-12-06T19:08:35.357-05:00How we sidestepped an App Store catastrophe<b>UPDATE: </b>The app has been approved since I originally wrote this post. The app review delay had nothing to do with technology choices, and Apple has been fairly quick to approve updates since.<br />
<br />
I submitted <a href="http://www.outboxmail.com/" target="_blank">Outbox's</a> iPad app for review on July 10. It went into "In Review" status on July 24, where it has remained ever since. Actually, it was rejected once on August 22 because the demo account credentials I gave didn't work, despite server logs showing 2 logins on the demo account from Cupertino. I resubmitted, saw 4 logins the following day, and have heard nothing since. My expedited review request was denied. The request status update feature in iTunes Connect is a joke because it takes a week to get a response that the app is still in review, which of course I can see in iTunes Connect. Apple Developer Relations can't help because they can only contact the review team through the same channels I can. One of Outbox's founders even contacted a handful of friendly VPs at Apple for help, and still nothing.<br />
<br />
So here we are 2 months later (and counting), still in review.<br />
<br />
For a while we continued to plan our launch for "after we get approval" thinking that the app was bound to be approved soon since it had already been so much longer than the <a href="http://reviewtimes.shinydevelopment.com/" target="_blank">average review time</a>, but the weeks kept slipping by and we were forced to delay our launch week after week. Finally, we came to terms with the fact that Apple will get around to approving (or rejecting) the app whenever they damn well feel like it. It could be tomorrow or it could be a year from now. The important lesson I learned is <i><b>if your product lives in the iOS App Store you are forfeiting control over your release schedule</b></i>. Have a backup plan.<br />
<br />
Fortunately the Outbox iPad app is built with Javascript, HTML, and CSS. The app calls into native extensions for functionality like contacts and notifications as needed through <a href="http://phonegap.com/" target="_blank">PhoneGap</a>, and makes heavy use of <a href="http://www.mikedellanoce.com/2012/09/10-tips-for-getting-that-native-ios.html" target="_blank">hardware accelerated transforms to get a native look and feel</a>. So after a short discussion, we decided to launch a web app with support for iPad only (we haven't optimized for different aspect ratios or mouse interaction yet). This required almost zero additional effort because this is how we test the app most of the time anyway. The native bits that the app depends on degrade gracefully in a browser when they are not available. The only thing that needed to change was the email confirmation at the end of the signup process which now says "go to this URL on your iPad" instead of "download the app from the App Store". Our designer whipped up a screen with some instructions for the user to pin the app to the home screen when they follow the link from the confirmation email:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY-EMd3At9eZiCXxi5-Zmcrr_7HLDtgno9wKU3TdGZ3dae-V3_8xqi6OwFGuOdgAjo_bwWOV7cMQrfPDobAVF6FSS6v4BBc4OXWw1oYZYJCtNdCIi3kIDhPz0DPJLXGXQdiA2J4302D8x4/s1600/obx_web_app.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY-EMd3At9eZiCXxi5-Zmcrr_7HLDtgno9wKU3TdGZ3dae-V3_8xqi6OwFGuOdgAjo_bwWOV7cMQrfPDobAVF6FSS6v4BBc4OXWw1oYZYJCtNdCIi3kIDhPz0DPJLXGXQdiA2J4302D8x4/s400/obx_web_app.jpg" width="400" /></a></div>
<br />
In some ways the web app experience is actually better than the app store version of the app. <a href="http://daringfireball.net/2011/03/nitro_ios_43" target="_blank">Nitro</a> is available in chromeless web apps, but not in UIWebView, so Javascript execution gets about a 5X speed boost. At any rate, launching the web app beats the hell out of sitting around waiting when we could be making money and iterating on the product. Had we built a fully native application to begin with, turning around to build a web app would likely have taken weeks, if not longer. And if nothing else, <b><i>i</i></b><i><b>t feels good to own our release schedule again</b></i>.<br />
<br />
We just launched in Austin, so if you live in Austin, <a href="http://outboxmail.com/#invite" target="_blank">try us out</a>!Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com2tag:blogger.com,1999:blog-9194677942308742051.post-13763502598334573282012-09-03T13:35:00.001-04:002012-09-03T13:35:33.501-04:00My first "Hacker News Effect" experienceI recently ended a long quiet period on my blog. It had been 9 months since my last post, which incidentally, is about how old my daughter is... I'm sure there's correlation there somewhere. Anyway, as I sat around feeling like a bad citizen of the internet, I decided to dust off a post about <a href="http://www.mikedellanoce.com/2012/09/10-tips-for-getting-that-native-ios.html" target="_blank">mobile web performance</a> I had been working on for a while and finally publish it. I also figured I might as well try submitting the post to <a href="http://news.ycombinator.com/" target="_blank">Hacker News</a>. I checked the <a href="http://hnpickup.appspot.com/" target="_blank">pickup rate</a> and saw that it was a "good time" to submit, so I did, fully expecting to get just a handful of extra views before the submission quickly and quietly dropped off the newest submissions list.<br />
<br />
About 10 minutes later I checked my traffic statistics and saw I had almost 200 views. I checked Hacker News and saw my submission was in the #5 spot on the front page. My wife and I spent the next 2 hours watching the submission rise to the top spot while racking up a little over 3,000 views. I actually had trouble sleeping that night! But not the bad, anxious kind of sleeplessness, it was lack of sleep due to excitement!<br />
<br />
By the time my submission dropped off the front page my post had received about 15,000 views. I never promoted my own writing before so my blog received a steady trickle of organic search traffic. Hacker News made my previous traffic graph look like a flat line.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9glMGaNU4EdiwmeNOHa3jSaBg9B2ikWT0WJLYk77Y09W4BCx1OWiY-BpfIw_ntK2pi5l_Lq-dHBC5yuQerNBC8x_QME86E937FHxx2G_K9a0nIGHJLNflJtL9u6Lqo_LS1FlA7bgqFDp_/s1600/hn_traffic.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9glMGaNU4EdiwmeNOHa3jSaBg9B2ikWT0WJLYk77Y09W4BCx1OWiY-BpfIw_ntK2pi5l_Lq-dHBC5yuQerNBC8x_QME86E937FHxx2G_K9a0nIGHJLNflJtL9u6Lqo_LS1FlA7bgqFDp_/s640/hn_traffic.png" width="640" /></a></div>
<br />
The initial spike has long since ended, but the post is still getting around 100 views per hour, which is head and shoulders above what my blog used to get!<br />
<br />
My biggest surprise throughout the whole experience was how <b>overwhelmingly positive</b> the feedback was in both the discussion on Hacker News and in the comments on the post. Here was my favorite:<br />
<blockquote class="tr_bq">
<span style="background-color: #f6f6ef; font-family: Verdana; font-size: 12px;">I already feel like you saved me 2 weeks in testing.</span></blockquote>
Thank you Hacker News, and thank you to everyone who stopped by to read!Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-22974936918898886712012-09-01T21:52:00.001-04:002013-05-08T20:54:12.650-04:0010 tips for getting that native iOS feel with PhoneGapAt <a href="http://www.outboxmail.com/" target="_blank">Outbox</a> we have been hard at work building our iPad application with <a href="http://phonegap.com/" target="_blank">PhoneGap</a>. I wanted to share some of the lessons my team has learned so far. All of the following tips have been tested on iOS 4, 5, and 6 with PhoneGap 1.8. Also note that these tips apply just as well to web applications running on mobile Safari.<br />
<br />
Want more information about developing high quality PhoneGap applications, with in-depth explanations and working code examples? Check out <a target="_blank" href="http://phonegap-tips.com"><b>phonegap-tips.com</b></a>.<br />
<br />
<b id="tip1">Tip #1 - Test on old hardware</b><br />
<br />
Your app looks and feels great on that shiny new iPad 3 or iPhone 4S, right? Unfortunately, not everyone runs out to drop $500 whenever Apple releases a new toy. Get your hands on a first generation iPad or third generation iPhone. Always test on them first. If your app performs acceptably on on old hardware it is going to be <b>blazing fast </b>on the newer hardware.<br />
<br />
<b id="tip2">Tip #2 - Use pre-emptive 3D transforms</b><br />
<br />
If an element is going to be transformed in response to user interaction put an identity 3D transform on the element before any user interaction happens, for example:<br />
<pre>-webkit-transform: translate3d(0px,0px,0px);</pre>When the user first interacts with the element the initial movement will be much smoother.<br />
<br />
<b id="tip3">Tip #3 - Show or hide elements with 3D transforms when possible</b><br />
<br />
Invariably you will have some elements that need to be shown or hidden based on user interaction. For example, a modal dialog or menu of some sort. The easiest way to do this is usually <span style="font-family: Courier New, Courier, monospace;">display:none</span> or <span style="font-family: Courier New, Courier, monospace;">visibility:hidden</span>, however, you can achieve a significant speed increase by using a 3D transform to position the element offscreen. In my experience, using this technique to show or hide menus resulted in a 3-5X speed increase over <span style="font-family: Courier New, Courier, monospace;">display:none</span>.<br />
<br />
<b id="tip4">Tip #4 - Preload images</b><br />
<br />
Even though your images are already stored on the iOS device there will still be a noticeable "pop-in" when the images are first displayed. I found <a href="http://www.ajaxera.com/image-preloading-through-css3-caching/" target="_blank">CSS3 caching</a> to be the best method for dealing with this issue. If you are not keen on enumerating and maintaining a list of every background image you use in your app, here is a <a href="https://gist.github.com/3581792" target="_blank">jQuery plugin</a> that will preload any background image referenced in your CSS.<br />
<br />
<b id="tip5">Tip #5 - Phark image replacement does not play nice with 3D transforms</b><br />
<br />
Image replacement by setting a large, negative text-indent is great for accessibility since screen readers will find the text and browsers will only display the image. However, the text-indent will make for unbearably choppy 3D transitions in mobile Safari (this is actually related to tip #7). Fortunately, there are <a href="http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/" target="_blank">alternatives</a> to Phark that perform much better.<br />
<br />
<b id="tip6">Tip #6 - Velocity scrolling!</b><br />
<br />
Velocity scrolling is a super easy way to get a native feel in the scrollable portions of your app. It is simple to enable it on any scrollable area with a CSS rule:<br />
<pre>-webkit-overflow-scrolling: touch;</pre>That's it! However, be warned, Apple's current implementation <a href="http://stackoverflow.com/questions/7808110/css3-property-webkit-overflow-scrollingtouch-error" target="_blank">is a</a> <a href="https://groups.google.com/forum/?fromgroups=#!topic/phonegap/n2k-OvqCDcE" target="_blank">little</a> <a href="http://remysharp.com/2012/05/24/issues-with-position-fixed-scrolling-on-ios/" target="_blank">bit</a> <a href="https://github.com/scottjehl/Device-Bugs/issues/14" target="_blank">buggy</a>.<br />
<br />
<b id="tip7">Tip #7 - Respect maximum texture sizes</b><br />
<br />
Each iOS device has a <a href="http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/OpenGLESPlatforms/OpenGLESPlatforms.html" target="_blank">maximum texture size</a>. If you try to smoothly transform an element larger than the maximum texture size, the element will be broken into smaller tiles before the transform is applied, and this a very slow and ugly process.<br />
<br />
<b id="tip8">Tip #8 - Hide large, off-screen images</b><br />
<br />
If your app displays many large images, hide the images that are off-screen. Otherwise, it doesn't take many large images to unceremoniously crash your app. Both <span style="font-family: Courier New, Courier, monospace;">display:none</span> and <span style="font-family: Courier New, Courier, monospace;">visibility:hidden</span> work just fine, but tip #3 will not cut it here.<br />
<br />
<b id="tip9">Tip #9 - Eliminate tap event delays</b><br />
<br />
It takes mobile Safari about a third of a second (300 milliseconds) to decide that a touch start event followed by a touch end event should be synthesized into a click event. Plenty of frameworks, such as <a href="http://jquerymobile.com/" target="_blank">jQuery Mobile</a>, have "tap" handling code that can eliminate this delay for you.<br />
<br class="Apple-interchange-newline" /> <b id="tip10">Tip #10 - Disable tap highlighting</b><br />
<div><br />
</div><div>Have you ever noticed that translucent gray highlight mobile Safari puts on links and buttons when they are clicked? It is a dead giveaway that your app is not native, but you can get rid of it by making the highlight color completely transparent:</div><pre>-webkit-tap-highlight-color:rgba(0,0,0,0);</pre>Overall we're loving PhoneGap at Outbox. Hopefully these tips will help make a few more happy PhoneGappers!<br />
<br />
<b>Update</b><br />
<div>This post got picked up by Hacker News. <a href="http://news.ycombinator.com/item?id=4465878">See the discussion here</a>.</div>Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com34tag:blogger.com,1999:blog-9194677942308742051.post-9305360257516004952011-12-10T15:45:00.000-05:002013-09-18T14:33:28.034-04:00Zero-friction Javascript Minification with RequireJS and ExpressMost software development efforts involve multiple source code files, and Javascript-heavy web applications are no exception. However, if you want your application to <a href="http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309">load fast</a>, then you need to combine and minify all those Javascript files somehow. <a href="http://requirejs.org/">RequireJS</a> is a library that can help with this process by allowing you to define javascript modules and the dependencies between them. In "development mode", RequireJS will download modules individually as they are needed. When all of your scripts are shiny and bug-free you can run the optimization tool which will analyze the module dependencies and create a single, minified Javascript file.<br />
<br />
The optimization tool is usually run as part of a build process before deploying the application, but if your application runs on <a href="http://nodejs.org">Node.js</a> you can eliminate this extra step. Since the optimization tool is itself a Node.js script, it can be invoked directly from the application's start-up code. Here is what this might look like with the fantastic <a href="http://expressjs.com">Express web framework</a>:<br />
<br />
<script src="https://gist.github.com/1453578.js"></script><br />
<br />
In development mode, the application will serve the non-optimized Javascript files from the <i>public</i> folder. In production mode, the RequireJS optimizer will combine and minify the Javascript files and serve the optimized files from the <i>public_build</i> folder. Any other files in the <i>public</i> folder (such as images and stylesheets) will also be copied to the <i>public_build</i> folder, so you don't need to clutter your source code repository with generated files.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com2tag:blogger.com,1999:blog-9194677942308742051.post-53484021255496782692011-12-04T08:48:00.000-05:002011-12-04T19:26:43.545-05:00Commit early, commit oftenHidden deep inside <a href="http://tortoisesvn.net/">TortoiseSVN</a> is a reporting tool that can give you <a href="http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-showlog.html#tsvn-dug-showlog-5">statistics about commits to your repository</a>. I ran this report at my <a href="http://www.rackspace.com/">day job</a> several times over the years and the output has always been a quiet source of pride for me. I decided to publish the report here since I'm moving on to a new project. If nothing else, it serves as a reminder to myself of what I spent in the last four years doing:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPBha6gBEoARQQ9ktyoiZqxaTtFc1AAsb3fdH39h8mwLPX8uzVDpwnuCbCHZ-dU5X1NBKsQ9kPOKuvGJaLrf9Cey___eIRTm8suOnqaPnpCYUJVwV1_Gg9Rali-8gTmlRLX9JsgC8AJbNu/s1600/most_active_all_time.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="293" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPBha6gBEoARQQ9ktyoiZqxaTtFc1AAsb3fdH39h8mwLPX8uzVDpwnuCbCHZ-dU5X1NBKsQ9kPOKuvGJaLrf9Cey___eIRTm8suOnqaPnpCYUJVwV1_Gg9Rali-8gTmlRLX9JsgC8AJbNu/s400/most_active_all_time.png" /></a></div><br />
This is the commit history for the entire four years of the project up to the date when this post was published (names have been removed to protect the innocent). I account for about <b>18% of the total commits</b> to the repository. One of my teammates (who incidentally owns the third highest bar in the graph) claimed that I average <b>7.5 commits per hour</b> assuming a 40 hour work week (ha). I think his math might be a little off since I calculated a significantly less impressive 5 commits per day when I ran the numbers... although maybe his numbers are a little closer if you exclude the year I served in management.<br />
<br />
Hold on a second...<br />
<br />
This can't be fair, can it? I've been on the team longer than anyone else at this point, so of course I've amassed more commits. Well, let's look at the commit history for one month during which the team membership was relatively stable:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhanJ2M5EdDA0Fr6MT770ZBrOVV3Z5hCuIXrt2CSnImBBWXvZMHL3ikKWPf91iLtPQWc-wnh8b-D2Sc93DVW8c4z7zblwRagjmjaD6qKFzOA7_29GDnm5eH8WeJXZpiBtYpIKKZjZ4jTNsS/s1600/most_active_february_2011.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="293" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhanJ2M5EdDA0Fr6MT770ZBrOVV3Z5hCuIXrt2CSnImBBWXvZMHL3ikKWPf91iLtPQWc-wnh8b-D2Sc93DVW8c4z7zblwRagjmjaD6qKFzOA7_29GDnm5eH8WeJXZpiBtYpIKKZjZ4jTNsS/s400/most_active_february_2011.png" /></a></div><br />
Me again, and by a wider margin, too.<br />
<br />
A lot of my teammates were shocked as these graphs made their way around the team, but there are benefits to working at this pace:<br />
<ul><li>You are less likely to break something with a lot of small commits than you are with a few huge ones,</li>
<li>Your teammates see your code sooner, so you get feedback sooner and reduce the risk of merge conflicts,</li>
<li>Customers get features and bug fixes sooner (as long as other organizational factors don't stand in the way),</li>
<li><a href="http://www.codinghorror.com/blog/2008/08/check-in-early-check-in-often.html">And plenty of other reasons</a> smarter people have already enumerated.</li>
</ul><br />
For me, writing software is all about momentum. I am more stressed out at the end of the day if I <b>don't</b> commit a whole bunch of code.<br />
<br />
Happy committing!Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-43559616899548104612011-11-15T06:54:00.001-05:002011-11-19T14:42:03.417-05:00Octophile: Social media widgets for GitHubLast week I put one of those <a href="http://twitter.com/about/resources/followbutton">Twitter follow buttons</a> on my blog. It was cool, but it looked a little lonely all by itself. It occurred to me that other developers can follow me on <a href="https://github.com">GitHub</a> too, so I started looking for a similar button for GitHub. Much to my surprise, I was not able to find one. Luckily, GitHub has <a href="http://developer.github.com/">a pretty awesome API</a>, so I decided to try to make a follow button for GitHub myself. I cobbled together a small <a href="http://www.sinatrarb.com/">sinatra</a> application, pushed it to <a href="http://www.heroku.com">heroku</a>, and <a href="http://octophile.com">octophile.com</a> was born!<br />
<br />
You can see the GitHub follow button in action off to the right (if you are reading this on my website and not a RSS reader). If you find this button useful, or would like to see some other widgets like this, I'd love to hear your feedback.<br />
<br />
Happy coding!<br />
<br />
<b>Update 11/19/2011:</b><br />
I have since found that something like this <i>does</i> already exist: <a href="http://githubanywhere.com/">github anywhere</a>.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-68656869630252704332011-10-13T21:37:00.000-04:002011-11-10T09:31:32.099-05:00Easy vagrant setup on windows with chocolateySetting up <a href="http://vagrantup.com/">vagrant</a> on windows is <a href="http://vagrantup.com/docs/getting-started/setup/windows.html">well-documented</a> and, overall, pretty easy. However, it is a little more complicated than just:<br />
<pre>gem install vagrant
</pre>
Luckily, us Windows developers recently got <a href="http://chocolatey.org/">chocolatey</a>. I just put together a few packages that makes vagrant setup on Windows a snap. To try it out just follow the <a href="http://chocolatey.org/">chocolatey installation instructions</a>. Then open a command prompt and run:<br />
<pre>cinst vagrant
</pre>
This command will download and install <a href="http://jruby.org/">JRuby</a>, <a href="https://www.virtualbox.org/">VirtualBox</a>, <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">PuTTY</a>, and the vagrant gem. It will also automatically set the registry keys for putty so that once you set up a box with vagrant you can SSH into it with:<br />
<pre>putty -load vagrant
</pre>
At this point the package comes with the old "works on my machine" stamp.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1D11WtaOvkaXuzMoGMIC5Ded_xQwEOYQxuDa2o7uVpU2561QPdfAJ1g_PPxqszSJIn3OgwL3QbR0Wn30MbmC4okneA090kvDO9Z74-mACtX81Euxktf0i0jytKWauXR97RMAN8XGFKoCG/s1600/works-on-my-machine.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1D11WtaOvkaXuzMoGMIC5Ded_xQwEOYQxuDa2o7uVpU2561QPdfAJ1g_PPxqszSJIn3OgwL3QbR0Wn30MbmC4okneA090kvDO9Z74-mACtX81Euxktf0i0jytKWauXR97RMAN8XGFKoCG/s320/works-on-my-machine.png" width="200" /></a></div>
<br />
Check out the code on <a href="https://github.com/mdellanoce/chocolateypackages">github</a> or <a href="https://github.com/mdellanoce/chocolateypackages/issues">report an issue</a>.
<br /><br />
<b>Update 11/10/2011:</b>
<br />
More recent versions of the package will not modify the putty registry with the vagrant profile. Instead I recommend installing <a href="https://github.com/mdellanoce/vagrant-putty">vagrant-putty</a>.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com2tag:blogger.com,1999:blog-9194677942308742051.post-20673134656488207812011-09-22T09:56:00.000-04:002011-09-22T09:56:43.464-04:00Enabling Pound proxy support for the HTTP methods PUT and DELETEI'm not sure how many people out there are using <a href="http://www.apsis.ch/pound/">Pound</a> as a reverse proxy, but if you have it sitting in front of a ReSTful web service you may run into some issues with HTTP methods other than GET, POST, and HEAD. By default Pound only supports GET, POST, and HEAD. Pound will return an HTTP status code of 501 (not implemented) if it encounters a different method, such as PUT or DELETE.<br />
<br />
Resolving this issue is easy. Each ListenHTTP or ListenHTTPS section in your pound configuration may contain the xHTTP setting. The default value for this setting is 0 (GET, POST, and HEAD). Setting the value to 1 adds support for PUT and DELETE. So putting it all together:<br />
<br />
<pre>ListenHTTP
# ... some settings
xHTTP 1 #Support GET, POST, HEAD, PUT, and DELETE
# ... some more settings
End
</pre><br />
Happy proxying!Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com2tag:blogger.com,1999:blog-9194677942308742051.post-26817092721496567362011-08-29T07:19:00.000-04:002011-08-29T07:19:09.595-04:00HTML Basics: Labels and inputsI stumbled across some code the other day that made me smile. Here is essentially what was going on:<br />
<br />
<pre class="csharpcode"><span class="kwrd"><</span><span class="html">input</span> <span class="attr">id</span><span class="kwrd">="checkbox"</span> <span class="attr">type</span><span class="kwrd">="checkbox"</span> <span class="kwrd">/></span>
<span class="kwrd"><</span><span class="html">label</span> <span class="attr">id</span><span class="kwrd">="label"</span> <span class="attr">for</span><span class="kwrd">="checkbox"</span><span class="kwrd">></span>My Label<span class="kwrd"></</span><span class="html">label</span><span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">="text/javascript"</span><span class="kwrd">></span>
$(<span class="str">'#label'</span>).click(<span class="kwrd">function</span>() {
<span class="kwrd">var</span> checkbox = $(<span class="str">'#checkbox'</span>);
checkbox.attr(<span class="str">'checked'</span>, !checkbox.<span class="kwrd">is</span>(<span class="str">':checked'</span>));
});
<span class="kwrd"></</span><span class="html">script</span><span class="kwrd">></span></pre><br />
Naturally, this bit of javascript will toggle the checkbox's checked state whenever the label is clicked. There is nothing functionally wrong with this approach, except that it is wasted effort. Every browser I have ever worked with will do this automatically without any javascript. Simply associate a label with a checkbox (or radio button) and clicking the label will toggle the checkbox's checked state:<br />
<br />
<!-- code formatted by http://manoli.net/csharpformat/ --><br />
<pre class="csharpcode"><span class="kwrd"><</span><span class="html">input</span> <span class="attr">id</span><span class="kwrd">="checkbox"</span> <span class="attr">type</span><span class="kwrd">="checkbox"</span> <span class="kwrd">/></span>
<span class="kwrd"><</span><span class="html">label</span> <span class="attr">id</span><span class="kwrd">="label"</span> <span class="attr">for</span><span class="kwrd">="checkbox"</span><span class="kwrd">></span>My Label<span class="kwrd"></</span><span class="html">label</span><span class="kwrd">></span></pre><br />
<input id="checkbox" type="checkbox" /><label for="checkbox">Go ahead, click me</label>Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-82840564909657723112011-03-27T09:35:00.000-04:002011-03-27T09:35:07.567-04:00Testing MySQL queries with NUnitEven the most adamant unit-testing purist will admit that database queries need to be tested. If possible, these tests should run against the same database engine that will be used in production.<br />
<br />
With a SQL Server database, testing queries is fairly easy, since most Visual Studio installations will include SQL Server Express. Just create the database in a <a href="http://www.nunit.org/index.php?p=setupFixture&r=2.5.9">SetupFixture</a>, connect with Windows Authentication, and you're all set. MySQL presents a few more challenges, however. First, it needs to be installed. Second, the tests need the correct credentials to connect to the installed MySQL instance.<br />
<br />
One simple way to handle this is to set up a central MySQL instance for testing only. However, this means team members must be on the network to run the tests. There is also the issue of multiple team members running the tests at the same time causing unexpected failures in each other's test runs, or worse, causing unexpected failures in an automated build.<br />
<br />
A better alternative is to keep the MySQL binaries in version control with a known configuration that can be used in test runs. The binary distribution of MySQL is fairly large; however, with the right command line arguments, we only need two files: <i>bin\mysqld-nt.exe</i> and <i>share\english\errmsg.sys</i> (or whichever language you want to use). Include both of these as content files in a test project and set the build action to "Copy If Newer". In a SetupFixture, start MySQL with some code like this in the setup method:<br />
<br />
<pre class="csharpcode">var process = <span class="kwrd">new</span> Process();
var arguments = <span class="kwrd">new</span>[]
{
<span class="str">"--standalone"</span>,
<span class="str">"--console"</span>,
<span class="str">"--basedir=."</span>,
<span class="str">"--language=."</span>,
<span class="str">"--datadir=."</span>,
<span class="str">"--skip-grant-tables"</span>,
<span class="str">"--skip-networking"</span>,
<span class="str">"--enable-named-pipe"</span>
};
process.StartInfo.FileName = <span class="str">"mysqld-nt.exe"</span>;
process.StartInfo.Arguments = <span class="kwrd">string</span>.Join(<span class="str">" "</span>, arguments);
process.StartInfo.UseShellExecute = <span class="kwrd">false</span>;
process.StartInfo.CreateNoWindow = <span class="kwrd">true</span>;
process.Start();</pre><br />
The first two arguments (<i>--standalone</i> and <i>--console</i>) tell MySQL to run as a standalone instance and to keep the console window open (i.e. do not run as a service). The next three arguments (<i>--basedir=.</i>, <i>--language=.</i> and <i>--datadir=.</i>) tell MySQL to run from the current directory, load language files (errmsg.sys) from the current directory, and write data files to the current directory. The <i>--skip-grant-tables</i> argument disables security so that the tests do not need to worry about providing credentials when connecting. The final two arguments (<i>--skip-networking</i> and <i>--enable-named-pipe</i>) tell MySQL not to listen for TCP connections and instead allow named pipe connections. This prevents our standalone MySQL instance from interfering with any other MySQL installations on the machine.<br />
<br />
Once the instance has started, we can connect with a connection string like this: <i>Data Source=localhost;Protocol=pipe;</i>. Finally, kill the MySQL process in the SetupFixture teardown method.<br />
<br />
On my team, we have rolled this functionality (and a few other goodies) into a NUnit addin, but that's a story for another blog post.<br />
<br />
Happy testing!Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com4tag:blogger.com,1999:blog-9194677942308742051.post-31524279469961134152011-02-10T08:56:00.000-05:002011-02-10T08:56:45.835-05:00NServiceBus assembly scanning: avoiding unintended consequencesThe default startup behavior for a NServiceBus endpoint is to scan all assemblies in the deployment directory for any types it might be interested in, for example, message modules and message handlers. This is really handy, but occasionally it can lead to unintended consequences. Fortunately, the With method has a few overloads and one of them takes a list of assemblies to scan. If you want to prevent loading types from any stray assembly that might make it into your deployment directory, change your initialization code to look like this:<br />
<div><br />
<pre class="csharpcode">var assemblies = GetType().Assembly
.GetReferencedAssemblies()
.Select(n => Assembly.Load(n))
.ToList();
assemblies.Add(GetType().Assembly);
NServiceBus.Configure.With(assemblies);</pre><br />
</div><div>This restricts the assembly scanning process to only the assemblies that your endpoint explicitly references. We can extract this code to an extension method so we can use it in other endpoints:</div><br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> IEnumerable<Assembly> ReferencedAssemblies(<span class="kwrd">this</span> Type type)
{
var assemblies = type.Assembly
.GetReferencedAssemblies()
.Select(n => Assembly.Load(n))
.ToList();
assemblies.Add(GetType().Assembly);
<span class="kwrd">return</span> assemblies;
}</pre><br />
Now our endpoint initialization looks like this:<br />
<br />
<pre class="csharpcode">NServiceBus.Configure.With(GetType()
.ReferencedAssemblies());</pre>Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com1tag:blogger.com,1999:blog-9194677942308742051.post-83611192407427489872010-12-21T06:54:00.001-05:002010-12-21T06:55:51.144-05:00Assert.DoesNotThrow... why does it exist?Take a look at this test:<br />
<br />
<pre class="csharpcode">[Test]
<span class="kwrd">public</span> <span class="kwrd">void</span> TestSomething()
{
Assert.DoesNotThrow(MethodUnderTest);
}</pre><br />
It seems to me that it is functionally equivalent to this test:<br />
<br />
<pre class="csharpcode">[Test]
<span class="kwrd">public</span> <span class="kwrd">void</span> TestSomething()
{
MethodUnderTest();
}</pre><br />
In other words, Assert.DoesNotThrow is the same as writing a test with no assertion. Is it really enough that the code runs without throwing an exception? Presumably the method under test is doing <i>something</i>, so shouldn't you verify those results with a stronger assertion?Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com3tag:blogger.com,1999:blog-9194677942308742051.post-27930521619179506252010-12-07T07:00:00.000-05:002011-12-15T10:35:43.363-05:00AsyncController and custom action invokersIf you are trying to get <a href="http://msdn.microsoft.com/en-us/library/ee728598.aspx">AsyncControllers</a> to work, you might run into this gem when you try to test your controller:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6ZpfVWUW4j4e79yqR9Sb-tneKZWUxEtE_g-953XEyB0Hy1UPMX2AxPqyle0q4nM5jx25VcgAuKlN5ZKnnSx49V9w8mWN6U76Eoazzt9gBywK6ajm56r8ckombLVw2VYnK_hYkCSYkMvJs/s1600/the_resource_cannot_be_found.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="The resource cannot be found" border="0" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6ZpfVWUW4j4e79yqR9Sb-tneKZWUxEtE_g-953XEyB0Hy1UPMX2AxPqyle0q4nM5jx25VcgAuKlN5ZKnnSx49V9w8mWN6U76Eoazzt9gBywK6ajm56r8ckombLVw2VYnK_hYkCSYkMvJs/s320/the_resource_cannot_be_found.png" width="320" /></a></div><br />
If this happens to you, a <a href="http://stackoverflow.com/questions/3286340/resource-not-found-in-asp-net-mvc-asynccontroller">custom action invoker</a> is likely to be the culprit. In my case, I was using <a href="http://www.castleproject.org/container/">Castle Windsor</a>, and I had extended <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.controlleractioninvoker(v=VS.90).aspx">ControllerActionInvoker</a> to provide dependency injection to my <a href="http://www.asp.net/mvc/tutorials/understanding-action-filters-cs">action filters</a>. My action invoker looked something like this:<br />
<br />
<script src="https://gist.github.com/1481509.js?file=CastleActionInvoker.cs"></script><br />
<br />
And this is how I had registered the action invoker with Windsor (this assumes you are using a controller factory that is aware of Windsor):<br />
<br />
<br />
<script src="https://gist.github.com/1481509.js?file=Global.asax.cs"></script><br />
<br />
All I had to change to fix the problem was to make my custom action invoker inherit <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.async.asynccontrolleractioninvoker(VS.98).aspx">AsyncControllerActionInvoker</a> instead:<br />
<br />
<script src="https://gist.github.com/1481509.js?file=AsyncCastleActionInvoker.cs"></script><br />
<br />
AsyncControllerActionInvoker implements <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.async.iasyncactioninvoker(VS.98).aspx">IAsyncActionInvoker</a> and adds a few new methods. Depending on what you are trying to accomplish with your custom invoker, you may need to override a few of these new methods as well.<br />
<br />
Interestingly enough, I did not have to change how the invoker was registered with Windsor.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com2tag:blogger.com,1999:blog-9194677942308742051.post-4160386267806495962010-12-06T07:18:00.000-05:002010-12-06T07:18:18.913-05:00Using AsyncController with NServiceBusWith <a href="http://www.nservicebus.com/">NServiceBus</a> sometimes you do not want to allow a web request to complete until you have received some response from your message handler. For example, suppose you have defined the following message handler that returns a response code on success:<br />
<br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> TestMessageHandler :
IHandleMessages<TestMessage>
{
<span class="kwrd">public</span> IBus Bus { get; set; }
<span class="kwrd">public</span> <span class="kwrd">void</span> Handle(TestMessage message)
{
<span class="rem">//Do something interesting...</span>
Bus.Return(0);
}
}</pre><br />
This is a perfect scenario for using the asynchronous page API. It allows you to execute a potentially long-running operation on a separate thread outside of the IIS thread pool. While this thread is executing, the original request thread is returned to the thread pool. As a result, the asynchronous page API is great for I/O bound operations, since you keep threads in the thread pool ready to service requests and the new thread spends most of its time blocked on I/O. NServiceBus supports the asynchronous page API out of the box:<br />
<br />
<pre class="csharpcode">Bus.Send(<span class="kwrd">new</span> TestMessage()).RegisterWebCallback(callback, state);</pre><br />
Unfortunately, RegisterWebCallback does not work with ASP.NET MVC. If you are using ASP.NET MVC, you can use <a href="http://msdn.microsoft.com/en-us/library/ee728598.aspx">AsyncController</a>, which was introduced in ASP.NET MVC 2. The following code illustrates how you might use AsyncController to wait for a response the message handler:<br />
<br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> TestController : AsyncController
{
<span class="kwrd">private</span> IBus bus;
<span class="kwrd">public</span> TestController(IBus bus)
{
<span class="kwrd">this</span>.bus = bus;
}
<span class="kwrd">public</span> <span class="kwrd">void</span> IndexAsync()
{
AsyncManager.OutstandingOperations.Increment();
bus.Send(<span class="kwrd">new</span> TestMessage()).Register(Callback);
}
<span class="kwrd">public</span> ActionResult IndexCompleted()
{
<span class="kwrd">return</span> View();
}
<span class="kwrd">private</span> <span class="kwrd">void</span> Callback(<span class="kwrd">int</span> responseCode)
{
AsyncManager.OutstandingOperations.Decrement();
}
}</pre><br />
As you can see, the AsyncController API is a little awkward (though it is an improvement over the asynchronous page API, in my opinion), but it is a small price to pay for scalability.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com5tag:blogger.com,1999:blog-9194677942308742051.post-71747446570917806202010-08-14T15:07:00.002-04:002010-08-14T21:11:25.451-04:00Ctrl-C and the NServiceBus generic hostTen posts and almost a whole year later, my <a href="http://mikedellanoce.blogspot.com/2009/11/configuring-nservicebus-in-web.html">very first post about NServiceBus</a> is still by far my most popular. So here is some more <a href="http://www.nservicebus.com/">NServiceBus</a>-y goodness.<br />
<br />
Last week a coworker came to me asking for help with a <a href="http://www.nservicebus.com/SelfHosting.aspx">self-hosted NServiceBus</a> application. He had a small console application set up to test NServiceBus and it worked beautifully in all but one case. When he killed the application with Ctrl-C, the message being processed was always lost. At first I thought maybe the application was not using a <a href="http://www.nservicebus.com/Transactions.aspx">transactional endpoint</a>, but it was configured to do so. I did not see the same behavior with the <a href="http://www.nservicebus.com/GenericHost.aspx">generic host</a> running in console mode, so I figured the generic host was handling Ctrl-C somehow. A quick search turned up the <a href="http://stackoverflow.com/questions/177856/how-do-i-trap-ctrl-c-in-a-c-console-app">CancelKeyPress event</a>. I opened up the generic host in <a href="http://www.red-gate.com/products/reflector/">reflector</a>, and, on a hunch, navigated to the TopShelf.Internal.Hosts namespace (the generic host <a href="http://www.udidahan.com/2010/08/01/cautiously-merging-il/">internalizes</a> another excellent open source project called <a href="http://code.google.com/p/topshelf/">TopShelf</a>). Sure enough, the TopShelf console host handles the CancelKeyPress event, and ultimately allows all of the worker threads in NServiceBus to finish handling messages before shutting down.<br />
<br />
One question this brought up is what happens if someone pulls the plug on my machine after a message has been received, but before it has been processed? My impression was that a transactional endpoint would take care of this, but now I'm not so sure.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com1tag:blogger.com,1999:blog-9194677942308742051.post-23397284285739098862010-07-27T20:32:00.001-04:002010-07-27T20:32:41.373-04:00Over-testing: the data-driven editionLearning to test at the right level of abstraction is tough. A common mistake involves the abuse of data-driven testing tools. Data-driven testing tools, like <a href="http://www.nunit.org/index.php?p=testCase&r=2.5.6">TestCase</a> in NUnit, are convenient and powerful. You can write a lot of tests really fast, but if you're not careful, you can end up repeating yourself.<br />
<br />
For example, suppose we define the following (woefully oversimplified) utility function to test if a string is a valid email address:<br />
<br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> IsValidEmail(<span class="kwrd">string</span> email)
{
<span class="kwrd">return</span> Regex.IsMatch(email, <span class="str">@"\w+@\w+\.com"</span>);
}</pre><br />
The test suite for this function should be complete. A data-driven approach works really well here:<br />
<br />
<pre class="csharpcode">[TestCase(<span class="str">"a@test.com"</span>)]
[TestCase(<span class="str">"1@test.com"</span>)]
<span class="rem">//... lots more</span>
<span class="kwrd">public</span> <span class="kwrd">void</span> TestValidEmail(<span class="kwrd">string</span> email)
{
Assert.That(IsValidEmail(email));
}
[TestCase(<span class="kwrd">null</span>)]
[TestCase(<span class="str">"not an email address"</span>)]
<span class="rem">//... and so on</span>
<span class="kwrd">public</span> <span class="kwrd">void</span> TestInvalidEmail(<span class="kwrd">string</span> email)
{
Assert.That(IsValidEmail(email), Is.False);
}</pre><br />
Now, suppose we use this method in some application logic:<br />
<br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> SendConfirmation(<span class="kwrd">string</span> message, <span class="kwrd">string</span> email)
{
<span class="kwrd">if</span> (!IsValidEmail(email))
{
<span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">"email"</span>);
}
SendEmail(message, email);
}</pre><br />
Awesome, let's test this bad boy... er, I mean here's the test we wrote before writing the method:<br />
<br />
<pre class="csharpcode">[TestCase(<span class="str">"a@test.com"</span>)]
[TestCase(<span class="str">"1@test.com"</span>)]
<span class="rem">//... lots more</span>
<span class="kwrd">public</span> <span class="kwrd">void</span> TestSendEmailIfValid(<span class="kwrd">string</span> email)
{
SendConfirmation(<span class="str">"test"</span>, email);
<span class="rem">//Assert sends email...</span>
}
[TestCase(<span class="kwrd">null</span>)]
[TestCase(<span class="str">"not an email address"</span>)]
<span class="rem">//... and so on</span>
<span class="kwrd">public</span> <span class="kwrd">void</span> TestSendEmailThrowsIfInvalid(<span class="kwrd">string</span> email)
{
SendConfirmation(<span class="str">"test"</span>, email);
<span class="rem">//Assert throws exception...</span>
}</pre><br />
Okay, stop... do we really need to re-test every single valid and invalid email address? Data-driven tests make this easy, but that doesn't make it right. In this function, there are really only two paths that matter: an invalid email address throws an exception, and sending an email successfully. Let's try again:<br />
<br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> TestSendEmailIfValid(<span class="kwrd">string</span> email)
{
SendConfirmation(<span class="str">"test"</span>, <span class="str">"validemail@test.com"</span>);
<span class="rem">//Assert sends email...</span>
}
<span class="kwrd">public</span> <span class="kwrd">void</span> TestSendEmailThrowsIfInvalid()
{
SendConfirmation(<span class="str">"test"</span>, <span class="str">"not an email address"</span>);
<span class="rem">//Assert throws exception...</span>
}</pre><br />
Mockists might even take this so far as to stub out the IsValidEmail function for the purposes of testing this function, but for this simple case, it might be overkill since IsValidEmail has no external dependencies to begin with.<br />
<br />
In the real world, this kind of mistake is harder to spot. Generally, if you have an explosion of TestCase attributes covering all kinds of permutations, consider revisiting the code under test. There may be some opportunities to simplify both your code and your test suite.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-84196513177714802402010-07-17T11:33:00.001-04:002010-07-17T11:35:44.523-04:00JavaScript - apply invocation pattern part 2In my <a href="http://mikedellanoce.blogspot.com/2010/07/things-your-parents-never-told-you.html">last post</a> I promised a real-world example of the apply invocation pattern. The truth is it was getting late, and I didn't feel like writing anymore. However, one of my coworkers called me out, most likely because he's a JavaScript ninja and wants to put me in my place. In an effort to deny him the satisfaction, I'll steal an example from people who are smarter than I.<br />
<br />
If you use <a href="http://jquery.com/">jQuery</a>, you've probably used the <a href="http://api.jquery.com/jQuery.each/">each function</a> at some point. The each function works something like this (what follows is a <b>vast </b>oversimplification, see <a href="http://github.com/jquery/jquery/blob/master/src/core.js">here</a> for the actual implementation):<br />
<br />
<pre>jQuery.extend({
each: function(array, callback) {
for (var i = 0; i < array.length; i++) {
var value = array[i];
//Apply callback with "this" as the current value
callback.apply(value, [i, value]);
}
}
});
</pre><br />
Now we can use the each function like this:<br />
<br />
<pre>var sentence = '';
var words = ['hello', ' ', 'world', '!'];
jQuery.each(words, function() {
sentence += this;
});
//sentence == 'hello world!'
</pre>Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-40908990425059748082010-07-13T22:10:00.002-04:002010-07-17T11:34:01.192-04:00Things your parents never told you about JavaScript - Apply invocation patternSo, yeah, it's been a while... okay, it's been more than a while. I'm sure my 8 followers missed me. Anyway, I recently had the opportunity to learn a whole mess of new stuff, and I wanted to start writing some of it down. I had a 3 week fling with Ruby, followed by a longer affair with JavaScript. I was a static language guy for the last 3 years, so all this dynamic nonsense had my head spinning... and you know what?<br />
<br />
I <i>liked</i> it.<br />
<br />
I always thought of JavaScript development as painful; a sort of necessary evil. Turns out there's an <i>obscenely</i> powerful language there, if you go looking for it (incidentally, start by looking <a href="http://www.amazon.com/gp/product/B0026OR2ZY">here</a>). Among those powerful features are <a href="http://en.wikipedia.org/wiki/First-class_function">first-class functions</a>. For example, suppose I run the following code:<br />
<br />
<pre>var greeter = {
name: 'Mike',
greet: function() {
return 'hello ' + this.name;
}
};
greeter.greet(); // -> 'hello Mike'
</pre><br />
Nothing shocking there, right? Well, I can actually reach into the greeter object and <i>steal</i> the greet function:<br />
<br />
<pre>var greet = greeter.greet;
greet(); // -> 'hello '
</pre><br />
Okay, kind of cool, but not quite the expected result. Where did my name go? When you grab a function that references <i>this</i> and invoke it, you need to tell JavaScript what context you want to execute it in. The built-in JavaScript Function object has a method called apply which lets you set the value of <i>this</i> (it also lets you pass an argument array if you want to):<br />
<br />
<pre>var bob = {
name: 'Bob'
};
greet.apply(bob); // -> 'hello Bob'
</pre><br />
This is called the <i>apply invocation pattern</i>. What can you do with it? That'll have to wait for <a href="http://mikedellanoce.blogspot.com/2010/07/javascript-apply-invocation-pattern.html">another post</a>...Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-49960720004742420252010-03-11T06:58:00.000-05:002010-03-11T06:58:34.413-05:00Re-throwing exceptions in C#<span class="Apple-style-span" style="font-family: Arial; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"></span></span><br />
<br />
What is the difference between the following two blocks of code?<br />
<br />
<pre class="csharpcode"><span class="rem">// #1</span>
<span class="kwrd">void</span> HandleException()
{
<span class="kwrd">try</span>
{
<span class="rem">//Do something...</span>
}
<span class="kwrd">catch</span> (Exception e)
{
<span class="kwrd">throw</span> e;
}
}
<span class="rem">// #2</span>
<span class="kwrd">void</span> HandleException()
{
<span class="kwrd">try</span>
{
<span class="rem">//Do something...</span>
}
<span class="kwrd">catch</span> (Exception e)
{
<span class="kwrd">throw</span>;
}
}</pre><br />
Both blocks catch and re-throw an exception. The first block re-throws the caught exception, the second block does not specify anything to throw. The main difference between these blocks becomes apparent when the exception is logged higher up in the call stack. The stack trace for the first code block will be missing anything that came before the throw. The second code block will contain the full stack trace. This can be the difference between life and death when trying to diagnose an issue in production.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com1tag:blogger.com,1999:blog-9194677942308742051.post-76767086815743359712010-01-06T06:50:00.001-05:002010-01-06T06:52:04.686-05:00Castle Windsor: Order MattersI've been learning a lot about <a href="http://www.castleproject.org/container/index.html">Castle Windsor</a> lately. I ran into something that surprised me yesterday. Suppose you have the following class hierarchy:<br />
<pre class="csharpcode"><span class="kwrd">interface</span> Service
{
}
<span class="kwrd">class</span> ServiceA : Service
{
}
<span class="kwrd">class</span> ServiceB : Service
{
}</pre>What do you think the output from this code will be?<br />
<pre class="csharpcode">var container = <span class="kwrd">new</span> WindsorContainer();
container.Register(Component
.For<Service>()
.ImplementedBy<ServiceA>());
container.Register(Component
.For<Service>()
.ImplementedBy<ServiceB>()
.Named(<span class="str">"serviceb"</span>));
var service = container.Resolve<Service>();
Console.WriteLine(service.GetType().Name);</pre>If you said <i>ServiceA</i>, then you were right! Now, what about the output from this code?<br />
<pre class="csharpcode">var container = <span class="kwrd">new</span> WindsorContainer();
container.Register(Component
.For<Service>()
.ImplementedBy<ServiceB>()
.Named(<span class="str">"serviceb"</span>));
container.Register(Component
.For<Service>()
.ImplementedBy<ServiceA>());
var service = container.Resolve<Service>();
Console.WriteLine(service.GetType().Name);</pre>If you said <i>ServiceB</i>, then maybe the title of this post gave the answer away. I expected the named service to be a special case. In other words, I thought asking for a <i>Service</i> implementation would always give me <i>ServiceA</i>, unless I specifically asked for <i>ServiceB</i> by name.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com3tag:blogger.com,1999:blog-9194677942308742051.post-29783742096198045662009-12-14T06:59:00.006-05:002011-12-14T20:10:41.528-05:00ASP.NET MVC XML Model Binder<b>Update 12/14/2011</b><br />
This is one of my most highly viewed posts. Unfortunately, this post applies to version 1 of ASP.NET MVC (it might also work with version 2 with some small modifications). If that is what you are looking for, then please read on! Otherwise, for more relevant coverage of this topic I recommend <a href="http://lostechies.com/jimmybogard/2011/06/24/model-binding-xml-in-asp-net-mvc-3/">Jimmy Bogard's post</a><br />
<br />
I needed a way to receive raw XML in my action methods, rather than form-encoded values. Model binding makes it a piece of cake:<br />
<br />
<script src="https://gist.github.com/1479347.js?file=XmlModelBinder1.cs"></script><br />
<br />
In my action method all I have to do is apply the model binder attribute:<br />
<br />
<script src="https://gist.github.com/1479347.js?file=Controller1.cs"></script><br />
<br />
Now the edit action receives an XML string. Even better, I can get a strongly typed object if it is serializable:<br />
<br />
<script src="https://gist.github.com/1479347.js?file=XmlModelBinder2.cs"></script><br />
<br />
Now my action method looks like this:<br />
<br />
<script src="https://gist.github.com/1479347.js?file=Controller2.cs"></script><br />
<br />
The model binder attribute is a little too verbose for my taste, so I wrote a custom model binder attribute:<br />
<br />
<script src="https://gist.github.com/1479347.js?file=BindXmlAttribute.cs"></script><br />
<br />
Finally my action method is nice and readable:<br />
<br />
<script src="https://gist.github.com/1479347.js?file=Controller3.cs"></script><br />Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-38467833274043676452009-12-08T07:00:00.000-05:002009-12-08T07:00:20.585-05:00"Good Enough" Test AutomationIf you are practicing Agile and you want to stay releasable at the end of every iteration, <a href="http://every2weeks.wordpress.com/2008/03/22/agile-axiom-2-without-automation-it-is-mathematically-impossible-to-stay-releasable-at-the-end-of-every-iteration/">you must automate your tests</a>. If you do not automate, one of two things will happen:<br />
<ol><li>Your velocity will decrease each sprint as you need to reserve more and more time for regression testing.</li>
<li>You will not run (or will forget to run) regression tests, and you run the risk of breaking something unintentionally. Best-case, your testers will catch any problems before release. Worst-case, your customers will find problems after release.</li>
</ol><div>Now, here's the fun part: you have 2-3 weeks to build and test something potentially releasable. How can you possibly squeeze test automation into that time frame? The same way you attack that next killer feature: start small and iterate.<br />
<br />
A few days ago I was testing some changes to a multi-step online signup process. The current code base is, shall we say, less than testable at the unit level. As a result, all testing for this feature has been manual in the past. After a few manual test runs, introducing some automated tests at the browser level seemed like a good idea. I immediately thought about continuous integration, but quickly realized dealing with all the necessary data setup and tear-down was going to take several days to get right. All I needed at that moment was a script to fill out the forms and click through the whole process. I coded a short <a href="http://watir.com/">Watir</a> script, ran it a few times, and visually verified the process still worked end-to-end.<br />
</div><div><br />
</div><div>If all you need is a script to do the boring, repetitive parts of testing for you, write the script. If the script is useful, you'll keep coming back to it, and eventually get it running under continuous integration. Just take the first step, choose a tool, and start automating.<br />
</div>Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-73035831460060230372009-12-02T08:23:00.000-05:002009-12-02T08:25:51.985-05:00Missing reports in CruiseControl.NETMy team experienced a spell of build failures last week due to broken unit tests. It wasn't a big deal, broken tests happen from time to time, the breaker simply fixes them and life goes on. However, something strange happened when we looked at the build report to see what failed.<br />
<br />
<div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd6wU3HVRxH22zBUX3gxqXmypkKMdLpDK66M7l0kUO88VYPJFSw2jzjorLzaoQVZ19PHGHbLmafYR6uY76fsjT4Gfsun9WvRjKENEScsCP3ZQ1bV5b1C2Y02O9HmM4dpzv2dXyHgPsc0QP/s1600-h/invisible_tests.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd6wU3HVRxH22zBUX3gxqXmypkKMdLpDK66M7l0kUO88VYPJFSw2jzjorLzaoQVZ19PHGHbLmafYR6uY76fsjT4Gfsun9WvRjKENEScsCP3ZQ1bV5b1C2Y02O9HmM4dpzv2dXyHgPsc0QP/s320/invisible_tests.png" /></a><br />
</div><br />
The report showed that the <a href="http://www.nunit.org/">NUnit</a> process had exited with an error code, but the unit test summary claimed that no tests had been run.<br />
<br />
I logged in to the build server and checked out the build log. The unit test results were there, and I was able to search the log to find which ones failed, but obviously nobody wants to log in to the build server and search through a text file whenever a unit test breaks. On closer inspection, I realized that <i>all</i> of the XML data for the test results were wrapped in a CDATA section. One developer pointed out that this was likely caused by strange characters in the test results, and the documentation for the <a href="http://confluence.public.thoughtworks.org/display/CCNET/File+Merge+Task">file merge task</a> confirmed the possibility. However, my team has amassed about 2,500 unit tests, so finding the offending character in approximately 10,000 lines of test results would have been difficult to say the least.<br />
<br />
After some digging, I found out that <a href="http://ccnet.thoughtworks.com/">CruiseControl.NET</a> logs a debug message when a file cannot be merged because it contains invalid XML. I opened up the log (ccnet.log by default) and a quick search for <i>output is not valid XML</i> revealed the exact line number in the test results that caused the file merge task to fail. Now we are happily integrating continuously once again.Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com0tag:blogger.com,1999:blog-9194677942308742051.post-21937662963161303902009-11-25T08:22:00.000-05:002009-11-25T08:22:14.659-05:00Configuring NServiceBus In Web ApplicationsMy team recently started using <a href="http://www.nservicebus.com/">NServiceBus</a> for a new project. It has gone extremely well for the most part. Messaging can be tricky, and a tool like NServiceBus can lower the barrier to entry and gently guides developers towards messaging best practices.<br />
<br />
Like any tool, NServiceBus has a learning curve, and there were a few problems along the way. The biggest was an issue with configuring web applications as endpoints. Each web application used the fluent configuration API in the Application_Start event handler like so:<br />
<br />
<br />
<pre>NServiceBus.Configure.With()...</pre><br />
<br />
It worked fine in almost all cases. However, when one application was deployed to IIS, the configuration code was throwing <a href="http://msdn.microsoft.com/en-us/library/system.typeloadexception.aspx">inexplicable errors</a>. My team lost about a week trying to figure out what was going on, and eventually started investigating workarounds in order to meet the deadline. Workarounds usually result in their own <a href="http://programmer.97things.oreilly.com/wiki/index.php/The_Longevity_of_Interim_Solutions">unique set of problems</a>, which I desperately wanted to avoid. Finally, a long session with <a href="http://www.red-gate.com/products/reflector/">reflector</a> revealed the problem:<br />
<br />
<br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><pre>NServiceBus.Configure.WithWeb()...</pre><br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">The difference between the two methods is subtle. The former tells NServiceBus to scan <a href="http://msdn.microsoft.com/en-us/library/system.appdomain.basedirectory.aspx">AppDomain.BaseDirectory</a> for assemblies, while the latter tells NServiceBus to scan <a href="http://msdn.microsoft.com/en-us/library/system.appdomain.dynamicdirectory.aspx">AppDomain.DynamicDirectory</a>. The reason this affected one application in particular was because of how that application is deployed. Different versions of the application are deployed in virtual directories under the same web application in IIS, so there was a mismatch between some assembly versions.<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">The NServiceBus samples demonstrate the use of the WithWeb method. Had we paid more attention to the samples, we might have completely avoided this headache.<br />
</div>Anonymoushttp://www.blogger.com/profile/12073145930607775983noreply@blogger.com2