Monday, October 17, 2011

Story Points vs Hours

In the Agile methods many suggest using something called Story Points instead of time when estimating the time a task would require for implementation. Rather than saying that it will take two days they would say it takes, for example, four Story Points. They then track what is called Velocity to see how many Story Points the team can complete in a week and suggest that about that many Points, let's say 20, is what the team can implement in a week.

I find this very awkward. Is it just a technique to hide the hours? Because, after all, most of us are still payed by the hour, and we also want to have an idea about the dates we might expect things to be finished. Story Points take this away. What would you say to the carpenter who you pay by the hour if he said he will have your bathroom done in 80 Story Points? He expects to burn about 20 Story Points per week, he adds. I would think he was a freak!

The only reasonable reason I find to use Story Points instead of Hours (or Days) is the notion that different coders may need different amounts of time to solve a task. With Story Points two coders may estimate a task to, for instance, four, while using days one might need two days and the other three days. That would implicitly say that coders are linear to each other in skill difference, since for the equation to sum up you'd need them to agree that the next task, estimated to two Story Points, would take the former one day and the later one and a half. Something I strongly disbelieve.

The more unreasonable reason is that as estimates are hard to do, you put a metric on them that is hard to understand to get away with them easier. If you say that something will take three days it's easy to see if you were right, while estimating it will take three Story Points will keep you safe. Who are to say how long a Story Point is? Hardcore agilists laughs at such a silly question.

I guess I'm missing something, but I have a hard time seeing the Point of Story Points. Feel free to enlighten me using the comment field!

p.s. I've never tried Story Points, so I might be totally wrong. It may be Gods gift to software developers. d.s.

Friday, October 14, 2011

EPiServer 6.0 compare bug

I've spent most of today, and a couple of hours yesterday, to figure out a weird problem with the function that allow you to compare two versions of a page in the EPiServer 6.0 edit mode. As soon as I clicked the compare button I got the YSOD telling me that a NullReferenceException was thrown from the method ComputeVaryCacheKey deep down in the ASP.NET rendering.

I hooked up the debugger and found that everything seemed to be in order. Altho, we had a few customized renderings in the chain so I started by disabling them one by one to find the cause. Once they were all removed I still had the problem tho, so I started on another track. Next thing I did was to look at the output caching used. Starting with simplifying the GetVaryByCustomString method in Global.asax so it should be almost impossible to have a problem there didn't help. Next thing was removing the OutputCache directives on my controls one by one and in the end - bingo! When the last OutputCache directive was removed I got some other error instead from the compare button.

So it comes down to that adding an OutputCache directive with VaryByCustom would make that ComputeVaryCacheKey crash when trying to compare two pages... I really need my output caching, but for the sake of coming to the bottom of this I left them out looking at the new error message. Maybe it could be the root course and if that was solved I could add the caching again?

The new error said "']]>' is not allowed within '<!CDATA[' blocks" or something like that. Well, fair enough. I looked at the source of the page being compared and there were a couple of CDATA blocks in the scripts generated by ASP.NET but none of them seemed to be malformed. At this point I decided to fire up another EPiServer site and see if the CDATA blocks looked the same, and if they would like being compared on that site. The CDATA blocks looked the same and they did like being compared in that context... Odd. Here I decided to add the OutputCache directive to a control on this site and see if it would work here - And it DID! There was a difference tho - this site was build on EPiServer 6 R2.

At this point I contacted the EPiServer support that within an hour reported back to me that this was a known bug in EPiServer 6.0 that had been solved in R2. The general advise was to upgrade to R2, but in case I couldn't do that I also was send a custom "CompareProvider" written by the support guy that should work with 6.0. So I put that in the bin directory, configured the site as he instructed me for activating this new provider and gave it a go. I still got that "']]>' is not allowed within '<!CDATA[' blocks"... but the good part was that I could add my OutputCache directives again and still getting that error!

Well, now at least I had my own custom code running closer to the problem. I reflected the provider that the support guy sent me and it was only one class. I copied the code to a class in my own project allowing me to set a breakpoint in there. When I had the code it was also obvious that the CDATA issue was addressed in it, but apparently it didn't address the problem well enough. I started by just removing the CDATA start and end block from the input to the compare function and then it worked! Or well, kind of. It didn't seem to have support for css being added with @import so I got a comparison of the page without styling... still, it was the best yet!

Hacking away even more I hardcoded an addition of the primary css to the source, and now it looked good too! A bit too hacky tho, for my taste, it struck me that I could reflect the source from the EPiServer 6 R2 binaries to see how they solved it there. The first line in that version was the Obsolete attribute - use "HtmlDiffProvider" instead it said. Wonder if that works with 6.0 I pondered, and reflected that source and added it to my project next to the code from the support guy. Then executed... and boom! That first NullReferenceException from the caching again! Dang. But, with the code from these two providers I managed to create a one provider that worked fine with EPiServer 6.0!

During this entire episode I did of course do a lot of searching on the web for guidance... getting none! Hence I decided to write this post to help the next person that enters this moat. It's not your fault! It's a bug in the platform! Stop wasting your time looking for problems in your project, and instead add your own CompareProvider.

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!