Thursday, February 24, 2011

If you can't reproduce it, you can't fix it

Every now and then you will be assigned a bug that seems impossible. You try to reproduce it, but you fail. You look at the code, and what happened seems impossible. It may now be tempting to add some if-statement to just make sure the object isn't null (for example) and close the bug. Don't Do That!

Doing that will cause a lot more trouble down the road. The problem will most likely come up again in some other part of your code, and then you'll be on yet one unplanned rescue mission. Maybe you'll be tempted once again to add a quick-fix and before you know your code will be full of them - all added with your best intention.

Then come the day when you find the real bug! Hooray! Finally your days of applying that dirty fix on different spots around your projects is over. But will you go back and revert your qd:s? No. Either there is no time, or you don't want to touch what works, or you just leave them there to take care about if this would happen again - but if you are like most people you will surely leave them there to rot. Don't Do That!

Leaving them mean more code to maintain, more things that can go wrong and more useless processor cycles. If there is an "if" in your fix (and it usually is) there will also be more forks in the code, which is very error prone.

So what should you do? You should put all your effort into being able to reproduce the bug. If you still fail, ask someone to help you reproduce the bug. If it seems to be a timing issue, write something that pushes your code so much that you cause the error within reasonable time before you try to solve it. Once again, how can you be sure you've solved the problem if you can't test if the problem disappeared when you're done?

Tuesday, December 21, 2010

Toedipping in ASP.NET MVC

Today I've finally had time to have a closer look at ASP.NET MVC, getting my hands dirty and actually doing something with it. I have vacation and the kids are at day care - so this was my chance!

I started up downloading the Visual Web Developer Express 2010 and created an ASP.NET MVC 2 template project. I executed it on the development web server, saw it worked, changed a couple of texts and reloaded to see my changes were applied. They were!

Then I googled to see if my web host, Binero, had support for ASP.NET MVC at all. I found that they had a blog entry with an instructional movie showing exactly how to make it work, so it shouldn't be a problem I figured.

I followed the instructions and uploaded my modified template site. It turned out the template site is using .NET 4.0 though, which Binero doesn't support, so it didn't work out of the box. Changing target version for the project to .NET 3.5 should do the trick I figured, so I did that and tried to run the project - and got some strange error. The page said Error CS1525 about a line in the View where the code was something about "Html.ActionLink". Google didn't quite help me, but pretty soon I noticed the obvious problem. It was marked "<%:" which is new in ASP.NET 4. Changing all "<%:" in the views to "<%=" made it work with the .NET 3.5 framework and I was back in game!

Playing around adding my own models, views and controllers was all pretty straight forward. Nowhere near as much magic as I had expected. I got a hold of it pretty fast and only had one thing stopping me so much I had to go googling again. Adding " - MySite" after the ContentPlaceHolder inside the title-element was not doing the trick for some reason.

<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /> - MySite</title>

All I got in the title was the content from the placeholder... I first thought it was some update problem and started recompiling, reloading, refreshing, re-everything, but no luck. Finally I went to google who could help me instantly. It has to do with the head-tag having runat="server" set. Full description and solution can be found here: TipJar: Title Tags and Master Pages

A couple of hours resulted in a very simple web site, but never the less a ASP.NET MVC web site.

My first!

Thursday, November 18, 2010

How to commit code

When you commit (check in) your code to the source control system there are some things you should do to ensure quality and trackability.

1) If your source control system supports change sets, that is commiting a set of files as a bundle, make sure you just include one issue in that bunch. You shouldn't fix a bunch of things in all ends of the project and then commit them all in the same change set. The change set may well span over multiple projects tho, because one change set should include all the changes done to resolve that particular issue. A change set should also be compilable upon commit and not rely on the next one to be able to work.

2) Before you commit your change set you should diff every file against the repository version and see that you only commit things that were intended to commit. It's pretty easy to commit code you commented out, temporary variable names or debugging code if you don't review your own commits. If your commit is in central parts of the application or very large it is good to have another team member sit next to you when reviewing the changes.

3) When you've limited your change set to include only one issue and reviewed all the changes done, you should write a short description of the content in your change set. This is written as the "commit comment" and will be visible when you look at the log for your repository. Since your change set only should deal with one issue it is easy to write a brief description of what you've done. It's also good to include an issue id if you have an issue tracking system.

I guess many readers might think that this takes a lot of time - but think of all the time you save due to the higher quality instead! I've done this with all commits for many years now and it is very uncommon that I add bad code to the repository. It's not at all uncommon that I notice bad code while doing my personal code review upon commit tho!

My biggest problem when converting to this more professional approach was to limit my changes to only one issue. Yet today there are times when I can't commit only one change as I've fixed two (or more) issues in parallell without commiting the first one - and when they touch the same file it isn't possible to have only one change in the change set. If one of the fixes are small I usually solve this by reverting the changes for that issue temporarily while commiting the first change and then redo the changes for the next commit - but once in a while I need to write a commit comment with the dreaded word "... and ...".

Thursday, November 11, 2010

I love deleting code

Yesterday I read a tweet saying "the next best thing after writing code is deletig code". My response was fast, saying "personally i like deleting code more. ;)". Let me elaborate on that!

Deleting code means that you either:
  • found a better way to do something
  • found unneeded abstractions
  • found unneeded functionality
So, deleting code (at least when it's done on purpose ;)) is always done because you don't need it. Taking away code that you don't need is great, because the less code you have, the less can go wrong, and after the code is removed there is less to test and less to maintain.

Therefore, always strive to have as little code as possible doing the job. As they say in Extreme Programming, "Pay as you go: Build just enough to meet today's requirements".

You could get sad when removing code because it means that you or someone else have done something that could be considered a waste. Well, sometimes it was a waste but it won't be less a waste because you keep it. Most times the code you're about to delete served a purpose though, leading you to find the better solution.

So summing it up; Don't be sad about deleting code, love it like I do!

Thursday, October 7, 2010

Odd way to fill your mailbox

On a site of mine I get an email every time an invalid url is requested. The purpose of that is mainly to find broken links. Sometimes a misconfigured crawler may spam me with a hundred mails, but they're pretty easy to delete and it doesn't happen frequently.

Tonight however, from 21.08 to 21.53, I received more than 3.500 such, all from the same ip. It would probably have been more if i didn't block that ip at 21.53, as I luckily was at the computer. The requested url:s were all directories and pages that exist on the site, but combined in odd ways, primarily stacking directories in long chains that doesn't exist.

As I don't have access to the firewalls of my hosting company I had to figure out a way to block the weirdo myself. My solution was to just terminate requests from that host in my asp.net page like this (but the real ip instead of the x:es):

protected void Page_Load(object sender, EventArgs e)
{
if (Request.UserHostAddress == "x.x.x.x") {
Response.End();
return;
}
...
}

Wednesday, March 17, 2010

The Anti-IF Campaign

When I first found Francesco Cirillo's Anti-IF Campaign I signed up almost instantly. Over the years I've learned that the if-statement is best used sparsely. Neither the campaign, nor I, strives to eliminate all if-statements but rather wants you to think twice before using them. Unfortunately I don't think the web site does a good job explaining why if is bad, so I'm going to make a try on my own.

Every if-statement creates another path through the code. That opens up for a lot of additional cases to test and hence harder to test. Harder to test means there will likely be more bugs. For example you need to add at least one Unit test for each if you add to your code. A nice technique for testing your code coverage is to comment out either the if or the content and see if any test fails. If it doesn’t the code is either unnecessary or not covered by your tests.

That being said code is a lot about different paths, and must be, so you can’t take away all if-statements. But consider your options!

There’s the redundant if:
if (flag) {
flag = false;
}
Just replace that with
flag = false;

There’s the horrible null check:
if (filter != null) {
filteredList = filter.Filter(list);
}
else {
filteredList = list;
}
Create a null object filter and always filter, like this.
  • If don’t have a interface for your filter already, create one.
interface IFilter {
Array Filter(Array list);
}
  • Make a implementation of that interface that just returns the argument.
class NullFilter : IFilter {
Array Filter(Array list) {
return list;
}
}
  • Where you used to decide not to set the filter field, create a NullFilter.
IFilter filter = new NullFilter();
  • Now remove the if and the else and just filter.
filteredList = filter.Filter(list);

Now lets round up with the case that Francesco lists on the Campaign site where you refactor your code to use strategy objects.

The Simplest Anti-IF Code (Anti-IF Campaign)

There's a lot of other cases, but I can't go through them all. I hope that you've learned that if should be avoided and that you will try to do so in the future.

I'll end this article with a Twitter quote from @garybernhardt.
Let's rename the "if" construct to "ponder" and impose a one-second busy wait per use. That'll teach those branchers! ;)