Attention: We are retiring the ASP.NET Community Blogs. Learn more >

Fear and Loathing

Gonzo blogging from the Annie Leibovitz of the software development world.

  • Mike Cohn is blogging

    Or maybe I'm just slow on the uptake? I got word via Mountain Goat Software, Mike's company, that his blog Succeeding with Agile is now available. However there are posts there dating back to January. In any case, whether it's new or not, it's a blogger to read. Mike has always been there for me with little tidbits of extra info and sending me resources when I was swimming in Agile questions. He's an excellent speaker and I look foward to his blog entries, even if they're only going to be once a month (hey, he's a busy guy). Check it out and consider adding him to your blog roll as he's on of the key guys in Agile software today.

  • No iPhone for you Canada!

    I was informed by informed sources (and this is probably old news) that they'll be no iPhones for Canadians, unless you're willing to pay Cingular roaming charges. I was planning on getting an iPhone but found out that a) the plan is locked to Cingular b) Cingular only services the U.S. c) you cannot simply drop in a SIM card from any other provider as iPhones are locked to the Cingular provider.

    My personal opinion is that Apple should have unlocked the phone and let you use any carrier. Okay, so they wouldn't have got the big bucks they're obviously getting from Cingular but if you crunch the numbers (and I'm sure they did) I would think you would have more hardware sales than payola in the long run. Guess not, so until Steve Jobs calls me up and puts me in that position it's no iPhone for us Canucks.

    Update: I was doing a little blog sleuthing and came across various rumours about Rogers being a carrier for the iPhone. However a) it's about 6 months out at best b) there's no official word that I can find and c) more informed (non-official) sources tell me this is false. Gizmodo says it's "confirmed" but I have doubts. Every report though says "a customer service email" or "customer service representative". To me, that's not official in any capacity.

    Someone will obviously hack this and probably within 6 months (or sooner) you could use one up here, but otherwise the only way would be to get a Cingular plan then pay roaming fees all the time. I may have good consultating rates, but not that good.

    Anyways, now I'm looking at the HTCs as people are saying they're good. Looking for any suggestions from anyone on model. There was an article a few days ago Forbes on iPhone alternatives so they look pretty good. Let me know what you recommend?

  • Load Testing Smart Clients

    It's a question, not a blog post. Anyone got some good tips, tricks, techniques, and tools for load testing Smart Clients? There's a plethora of info out for load testing web applications but little to nothing on Smart Clients. Just looking for ideas from the code monkeys out there.

  • An attempt at working with eScrum

    Okay, first off this tool wins the "Most Horrible Name Marketing Could Come Up With" award. I mean seriously, eScrum? Well, I guess when Scrum for Team System is taken what else do you do?

    I took a look at eScrum but after an hour of configuration and various error messages I gave up. I'm the type that if I need to spend half a day to try something out, something that I kind-of already have, that's half a day wasted. I personally think most of the people out there that are saying this tool is "pretty nice" haven't actually installed it (or tried to install it).

    So take this blog entry with a grain of salt as I didn't complete it to get to the finish line.

    What is eScrum?
    Anyways, eScrum is a web-based, end-to-end project management tool for Scrum built on top of TFS. It allows multiple ways to interact with your Scrum project:

    • eScrum web-based UI
    • TFS Team Explorer
    • Excel
    • MS Project

    Like any Scrum tool, it offers a one-stop place for all Scrum artifacts like product backlogs, sprint backlogs, retrospectives, and those oh-so-cool burndown charts.

    Installation is pretty painless. That is until you realize that you need a bevy of Microsoft technologies and tools installed in order to run eScrum. eScrum uses a variety of web and back-end technologies and you need to install of of them before getting your eScrum site up and running, although you can install them before or after eScrum, your choice.

    You'll need to install:

    ScreenShot001

    Once everything is installed hang on a second kids, there's still configuration to be done! eScrum is a bit of a pain to configure. Configuring eScrum is like installing Linux, there are a lot of steps and at any point you can really screw things up.

    ASP.NET AJAX Control Toolkit Version Conflicts
    Since the release site of the AJAX Control Toolkit does not allow download of previous versions and eScrum is compiled with a specific version, you may need to update the web.config file to allow automatic usage of a newer version of the AJAX Control Toolkit.  eScrum has not been tested with newer versions, but may work well.

    Add following XML to the eScrum web.config file after the </configSections> close tag.  Afterward, update the newVersion attribute to the version of the control toolkit that you are using.

    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="AjaxControlToolkit"
                    publicKeyToken="28f01b0e84b6d53e"
                    culture=”neutral”/>
                <bindingRedirect oldVersion="1.0.10301.0" newVersion="1.0.CHANGEME.0"/>
            </dependentAssembly>
        </assemblyBinding>
    </runtime>

    Setting up SharePoint Templates
    Oh yeah, the fun still continues and we're still not finished. The eScrum TFS Template includes a team SharePoint portal template which gets installed when a new TFS Project is created with the eScrum template.  The SharePoint templates must be added to the server before creating a TFS Project with the eScrum Process Template.
    Deployment Steps. Follow these instructions to get this step done:

    1. Log on to the target server
    2. Open a command prompt and change directory to: <SystemDrive>\Program Files\Common Files\Microsoft Shared\web server extensions\60\BIN
    3. Add the new templates using
      1. stsadm -o addtemplate -filename <path>\eScrum.stp -title "eScrum"
      2. stsadm -o addtemplate -filename <path>\eScrumFeaturesIdeas.stp -title "eScrum Features & Ideas"
      3. stsadm -o addtemplate -filename <path>\eScrumRiskLog.stp -title "eScrum Risk Log"
      4. stsadm -o addtemplate -filename <path>\eScrumStrategy.stp -title "eScrum Strategy & Issues"
    4. Type IISRESET to reset IIS

    Setting up an eScrum TFS Project
    eScrum uses eScrum TFS Projects as a back end storage and management, so you won't be able to use it on existing projects. Once you have added the eScrum Process Template to your TFS server, you will need to create a new TFS Project using the eScrum Template.

    First you'll need to get the templates uploaded via Team Explorer (or inside Visual Studio). Make sure you don't have even the Word document open while you're uploading the template or it will fail when it tries to create the zip file.

    Once you've uploaded the templates and they're available, you need to create a project using the eScrum template:

    1. In Team Explorer, right click your server and select "New Team Project…"
    2. Name your project and use the eScrum template
    3. Add yourself and your team members are all added to the Project Contributors (or Project Administrators, depending on your preference) security group.
      1. Right-click on your new Project and select "Team Project Settings.Group Membership…"
      2. Double-click either the Administrators or Contributors group
      3. Change the "Add member" selection to "Windows User or Group"
      4. Add your members
      5. Click OK

    Finally!
    There are some other installs they want you to do and I suggest you follow the various installation and configuration guides but for my test this was good enough to get something up and running.

    Now browse to where you installed it and you'll see something like this:

    ScreenShot002

    Creating Projects
    eScrum is a little odd, but it seems to align to the Scrum process. Of course the thing with Scrum is that it's adaptable. There is no golden rule of how it works. There are guidelines and people generally follow them but for example in eScrum you must have a product. The eScrum project you create isn't good enough, it needs something actually called a "Product" (using the concept that multiple products form a project). I don't personally do Scrum that way so found it a little frustrating. The other frustrating thing when setting up a project (oh sorry, "product") was that I couldn't save it until I Product contributors were added (team members) and it wouldn't let me add team members until I created groups and that's where I stopped before my brain exploded.

    Enough Configuring, I give up!
    Yes, I gave up installing and configuring the beast as it was just too much. I mean, I'm all for tools and setting up websites but after an hour of screwing around (even though I knew what I was doing) I said enough was enough. Realistically, give yourself a half day (if you rush) or a full day with some testing to get this puppy up and running.

    In fact, even after I had the template setup and a test project created I had no idea (other than through the Web UI) how to create a product? (which I couldn't do because of the security issues) It didn't look like I could create one in Team Explorer as all it would let me create was a bug, product details (but it needs a product first), sprint details, sprint retrospective, or a sprint task. WTF?

    Yeah, the SharePoint Scrum Master was lost so either I'm an idiot (possible) or this tool isn't very intuitive, even for someone who thinks he knows what he's doing.

    I wasn't going to go through the rest of the steps and who knows what else was needed, thus I wasn't able to get screenshots with projects configured and sprint backlog items, etc. I'll leave that for another soul to give up his day for.

    I do however have some images for the various tabs so you can get a feel for what eScrum has to offer:

    Product Page

    ScreenShot003

    Sprint Page

    ScreenShot004

    Daily Scrum Page

    ScreenShot005

    Retrospective Page

    ScreenShot006

    Bottom Line
    Was it worth it? Was it worth all the installing and configuring and configuring and installing?

    IMHO, no.

    I'm very happy with Conchango's Scrum for Team System and hey, to install that I just had to upload a new process template from Team Explorer. No mess no fuss.

    Once you do get the configuration and installation out of the way, eScrum looks interesting. It's got a nice dashboard for tracking your sprint, lets you keep on top of the daily Scrum electronically, and offers a bevy of Scrum reports like burndowns, metrics, and a product summary (none of which I have seen because I didn't take it that far when setting it up).

    There are problems with the setup (even though I didn't finish). For example the SharePoint template contains entry into the Links list pointing to http://eScrum and http://eTools, none of which are correct so you have to fix this (and frankly, I don't even know what the eTools link is supposed to be). The SharePoint templates are just custom lists with a few extra fields, nothing special here. Even the logo for the site was broken in the template so it's obviously this is either rushed or nobody cares about the quality of presentation of the tool (and I wouldn't call this a 1.0 release).

    Other things that immediately are a problem I had with this, you had to modify an XML config file every time you needed to add a project (and it's called a "Group" inside of the config file). Maybe you can do it through the web UI, but it looked to me like you had to modify this for each project.

    I think for any kind of adoption, Microsoft needs to put together an installer for this as we don't all have a day to kill configuring a tool that should be seamless (after all, it's just a website and a TFS template remember). They also should have some documentation/guidance on this. From the looks of what I could get up and running there's very little actual "guidance" on using the tool and frankly, from the websites there's very little anything about this tool. Does MS think you install it (assuming you have the gumption to go through the entire process) and it'll just work and people will understand it? Even Scrum for Team System has nice documentation written on the process that goes along with the tool. Tools and technologies alone do not make for a good package.

    If you want to use Scrum with TFS, stick to Conchango's Scrum For Team System template. It has it's own share of flaws but installs in about 5 minutes.

  • Coalescing with ReSharper 3.0

    The ReSharper 3.0 beta is out and I'm really digging it. It's little things that make my day a better place.

    For example I had a piece of code that looked like this:

       14 public ErrorReportProxy(IWebProxy proxy, bool needProcessEvents)

       15 {

       16     _errorReport.Proxy = proxy;

       17     if (proxy.Credentials != null) _errorReport.Proxy.Credentials = proxy.Credentials;

       18     else _errorReport.Proxy.Credentials = CredentialCache.DefaultCredentials;

       19     _needProcessEvents = needProcessEvents;

       20 }

    "if" statements are so 1990s so you can rewrite it like this using the conditional operator "?"  

       14 public ErrorReportProxy(IWebProxy proxy, bool needProcessEvents)

       15 {

       16     _errorReport.Proxy = proxy;

       17     _errorReport.Proxy.Credentials = (proxy.Credentials != null)

       18                                         ? proxy.Credentials

       19                                         : CredentialCache.DefaultCredentials;

       20     _needProcessEvents = needProcessEvents;

       21 }

    However with nullable types in C# 2.0 you can use the language feature of using the "??" assignment (called the null coalesce operator). The ?? operator defines the default value to be returned when a nullable type is assigned to a non-nullable type. This shortens the code but makes it more readable (at least to me).

    ReShaper to the rescue as it showed me squiggly lines in my code where I had the "?" operator and said (in a nice ReSharper way not an evil Clippy way):

    '?:' expression could be re-written as '??' expression.

    So a quick ALT+ENTER and the code becomes this:

       14 public ErrorReportProxy(IWebProxy proxy, bool needProcessEvents)

       15 {

       16     _errorReport.Proxy = proxy;

       17     _errorReport.Proxy.Credentials = proxy.Credentials ?? CredentialCache.DefaultCredentials;

       18     _needProcessEvents = needProcessEvents;

       19 }

    Okay, so maybe I'm easily amused but it's the little things that make my day (and maybe yours) a little brighter. The coding assistance feature of ReSharper 3.0 is shaping up to be very useful indeed.

  • Refactoring Dumb, Dumber, Dumbest away

    In my previous crazy post I had shown some code that was butt ugly. It was a series of if statements to determine some value (an enum) then use that value to switch on a case statement that would assign some values and audit the steps as it went along. It was ugly and the challenge before me was to refactor it away. I chose the Strategy Pattern as it seemed to make sense in this case, even if it did introduce a few more classes. So here we go.

    First, lets look at the full code we're refactoring. Here's the silly enumerated value:

       15 enum DumbLevel

       16 {

       17     Dumb,

       18     Dumber,

       19     Dumbest,

       20     Not

       21 }

    And here's how it's used:

      695 for (int i = 0; i < _segments.Count; i++ )

      696 {

      697     ISegment segment = _segments[i];

      698 

      699     #region determine cable count & heat segment voltage

      700 

      701     int cableCount;

      702     decimal heatSegmentVoltage;

      703     DumbLevel dumbLevel;

      704 

      705     //determine the specific segment configuration

      706     if (_segments.Count > 1)

      707     {

      708         cableCount = segment.GetCableCount(); //use # of tracers to determine cable count

      709 

      710         if (cableCount == 1)

      711         {

      712             if (PassesCount > 1)

      713             {

      714                 if (i <= (_segments.Count - 2)) //for all but last

      715                     dumbLevel = DumbLevel.Dumbest;

      716                 else

      717                     dumbLevel = DumbLevel.Dumb; //last segment

      718             }

      719             else

      720                 dumbLevel = DumbLevel.Dumb;

      721         }

      722         else

      723             dumbLevel = DumbLevel.Dumber;

      724     }

      725     else

      726         dumbLevel = DumbLevel.Not;

      727 

      728 

      729     //calculate cable count and heat segment voltage based on the segment configuration

      730     switch (dumbLevel)

      731     {

      732         case DumbLevel.Dumb:

      733             cableCount = segment.GetCableCount(); //use # of tracers to determine cable count

      734             AuditStep("Cable Count: {0} (based on count of Tracers identified)", cableCount);

      735             AuditStep("");

      736 

      737             heatSegmentVoltage = SupplyVoltage * Project.VoltageDrop * segmentPercentage;

      738             AuditStep("Supply Voltage ({0}) * Voltage Drop ({1}) * Segment Percentage ({2})", SupplyVoltage, Project.VoltageDrop, segmentPercentage);

      739             break;

      740 

      741         case DumbLevel.Dumber:

      742             cableCount = segment.GetCableCount(); //use # of tracers to determine cable count

      743             AuditStep("Cable Count: {0} (based on count of Tracers identified)", cableCount);

      744             AuditStep("");

      745 

      746             heatSegmentVoltage = SupplyVoltage * Project.VoltageDrop * segmentPercentage / PassesCount;

      747             AuditStep("Supply Voltage ({0}) * Voltage Drop ({1}) * Segment Percentage ({2}) / Passes # ({3})", SupplyVoltage, Project.VoltageDrop, segmentPercentage, PassesCount);

      748             break;

      749 

      750         case DumbLevel.Dumbest:

      751             cableCount = _passesCount;

      752             AuditStep("Cable Count: {0} (based on Passes #)", _passesCount);

      753             AuditStep("");

      754 

      755             heatSegmentVoltage = SupplyVoltage * Project.VoltageDrop * segmentPercentage / PassesCount;

      756             AuditStep("Supply Voltage ({0}) * Voltage Drop ({1}) * Segment Percentage ({2}) / Passes # ({3})", SupplyVoltage, Project.VoltageDrop, segmentPercentage, PassesCount);

      757             break;

      758 

      759         case DumbLevel.Not:

      760             cableCount = 1;

      761             AuditStep("Cable Count: 1");

      762             AuditStep("");

      763 

      764             heatSegmentVoltage = SupplyVoltage * Project.VoltageDrop;

      765             AuditStep("Supply Voltage ({0}) * Voltage Drop ({1})", SupplyVoltage, Project.VoltageDrop);

      766             break;

      767 

      768         default:

      769             throw new ApplicationException("Could not determine a known segment configuration.");

      770     }

      771 }

    Basically it's going through a series of segments (parts of a cable on a line) and figuring out what the segment configuration should be. Once it figures that out (with our fabulous enum) it then goes through a case statement to update the number of cables in the segement and the voltage required to heat it. This is from an application where the domain is all about electrical heat on cables.

    Lets get started on the refactoring. Inside that tight loop of segments, we'll call out to get the context (our strategy container) with a method we extracted called DetermineCableCountAndHeatSegment. Here's the replacement of the Dumb/Dumber if statement:

      710 SegmentConfigurationContext context = DetermineCableCountAndHeatSegmentVoltage(i, segmentCount, segment, segmentPercentage);

      711 int cableCount = context.Configuration.CalculateCableCount();

      712 decimal heatSegmentVoltage = context.Configuration.CalculateVoltage();

    And here's the actual extracted method:

      765 private SegmentConfigurationContext DetermineCableCountAndHeatSegmentVoltage(int i, int segmentCount, ISegment segment, decimal segmentPercentage)

      766 {

      767     SegmentConfigurationContext context = new SegmentConfigurationContext();

      768 

      769     int cableSegmentCount = segment.GetCableCount();

      770 

      771     if(segmentCount > 1)

      772     {

      773         if (cableSegmentCount == 1)

      774         {

      775             if (PassesCount > 1 && (i <= (segmentCount - 2)))

      776             {

      777                 context.Configuration = new MultiPassConfiguration(PassesCount, SupplyVoltage, Project.VoltageDrop, segmentPercentage);

      778             }

      779             else

      780             {

      781                 context.Configuration = new SinglePassConfiguration(cableSegmentCount, SupplyVoltage, Project.VoltageDrop, segmentPercentage);

      782             }

      783         }

      784         else

      785         {

      786             context.Configuration = new MultipleCableCountConfiguration(cableSegmentCount, SupplyVoltage, Project.VoltageDrop, segmentPercentage, PassesCount);   

      787         }

      788     }

      789     else

      790     {

      791         context.Configuration = new DefaultSegmentConfiguration(1, SupplyVoltage, Project.VoltageDrop);                       

      792     }

      793 

      794     return context;

      795 }

    The if statement is still there, but now it's a little easier to read in a method and makes more sense overall. We can tell now, for example, if there's more than 1 cableSegmentCount we use the MultipleCableCountConfiguration strategy object. Okay, not as clean as I would like it but it's a step forward over a case statement.

    The configuration classes are the strategy implementation. First here's the interface, ISegmentConfiguration:

        3 public interface ISegmentConfiguration

        4 {

        5     int CalculateCableCount();

        6     decimal CalculateVoltage();

        7 }

    This just gives us two methods to return the count of the cables and the voltage for a given segment.

    Then we create concrete implementations for each strategy. Here's the Simplest one, the DefaultSegmentConfiguration:

        3 class DefaultSegmentConfiguration : SegmentConfiguration

        4 {

        5     public DefaultSegmentConfiguration(int cableCount, int supplyVoltage, decimal voltageDrop)

        6     {

        7         CableCount = cableCount;

        8         SupplyVoltage = supplyVoltage;

        9         VoltageDrop = voltageDrop;

       10     }

       11 

       12     public override int CalculateCableCount()

       13     {

       14         AuditStep("Cable Count: {0}", CableCount);

       15         AuditStep("");

       16         return CableCount;

       17     }

       18 

       19     public override decimal CalculateVoltage()

       20     {

       21         decimal heatSegmentVoltage = SupplyVoltage * VoltageDrop;

       22         AuditStep("Supply Voltage ({0}) * Voltage Drop ({1})", SupplyVoltage, VoltageDrop);

       23         return heatSegmentVoltage;

       24     }

       25 }

    Here it just implements those methods to return the values we want. DefaultSegmentConfiguration inherits from SegmentConfiguration which looks like this:

        5 internal abstract class SegmentConfiguration : DomainBase, ISegmentConfiguration

        6 {

        7     protected int CableCount;

        8     protected int SupplyVoltage;

        9     protected decimal VoltageDrop;

       10     protected decimal SegmentPercentage;

       11     protected int PassesCount;

       12     public abstract int CalculateCableCount();

       13     public abstract decimal CalculateVoltage();

       14 }

    This provides protected values for the sub-classes to use during the calculation and abstract methods to fulfil the ISegmentConfiguration contract. There's also a requirement to audit information in a log along the way so these classes derive from DomainBase where there's an AuditStep method (we're looking at using AOP to replace all the ugly "log the domain" code).

    Now we have multiple configuration classes that handle simple stuff. Calculate cable count and voltage. This lets us focus on the algorithm for each and return the value needed by the caller. Other implementations of ISegmentConfiguration will handle the CalculateVoltage method differently based on how many cables there are, voltage, etc.

    Like I said, it's a start and puts us in a better place to test each configuration now rather than that ugly case statement (that's practically untestable). Its also clearer for new people coming onto the project as they [should] be able to pick up on what the code is doing. Tests will help strengthen this and make the use of the classes much more succinct. More refactorings that could be done here:

    • Get rid of that original if statement, however this might be a bigger problem as it bubbles up to some of the parent classes. At the very least, it could be simplified and still meet the business problem.
    • Since all ISegmentConfiguration classes return the cable count, maybe this should just be a property as there's no real calculation involved here for the cable count.

    Feel free to suggest even more improvements if you see them!

  • Acropolis, CAB, WPF, and the future

    "Acropolis, the future of Smart Client"

    So sayeth Glenn Block, product lead for the Smart Client Software Factory and CAB. Glenn's a good friend and he's just doing his job, but I felt a little shafted when Acropolis popped up on the scene. I mean, after the last few weeks of CAB is complex and CAB is this and CAB is that, the last thing we need is a CAB replacement but here it comes and it's called Acropolis.

    There were many requests to ship a WPF version of SCSF/CAB and well, we're actually doing it now with the SCSFContrib project up on CodePlex. Is Acropolis a WPF version of CAB? We'll see but Glenn says "Acropolis takes the concepts of CAB to levels that folks in p&p might have never dreamed". From the initial reaction I'm seeing from people like Chris Holmes and Oren, Acropolis doesn't look all that impressive. Another wrapper on top of WPF, a little orchestration thrown in to "wire up components and dependencies" and the promise of building apps without writing or generating any code. I've heard this story before with CASE and like Oren, I see ugly XAML (or XML or XML-like) code being behind all this which doesn't give me a warm and fuzzy.

    I have yet to setup Acropolis and take it for a real test drive so I have to act like the movie reviewer who's never seen the movie but heard other reviews and has some initial reactions from the trailer. If CAB wasn't on the scene, this would be a great. It's hard enough to get deep into XAML as it is, so layering more complexity on top of that requires something that will help a developer, not hinder him. True, you can still (and will) rip open the XAML to figure out what's going on and make those adjustments but at least it's not that complex right now with POWPF (plain old WPF if there is such a thing). It's 2007 and we've evolved (almost) to the point where we can trust designers and editors. I still have to tweak the .designer generated files [sometimes] to get the right objects parenting in a WinForm app, but I consider that part of the territory. However when I look at what is behind the Acropolis XAML it makes me shudder. There was a quote from another blog that really disturbed me "Probably the best suggestion I can give to my customers, as I always do, is to take inspiration from all of these solutions and to build his own one". Wow. Last option I would ever say to someone especially if there's something out there to do the heavy lifting for you.

    What bothers me about this whole thing is the MS statement of "we currently have no further plans for SCSF releases". I bought into Software Factories and thought the implementation Microsoft chose (the GAT and GAX) was a good option. Building my own factories or modifying others isn't that difficult and I can express what I really intend in a factory quite easily. With no future releases it means not only CAB is stopped in its tracks, so is SCSF. We just launched the SCSFContrib project which was basically a way to extend the core without touching it, however that restriction now becomes a bit of a roadblock, and we haven't really even got rolling on the project yet.

    Maybe we need to go one step further and allow the core of CAB to be modified/rewritten/extended and let the community evolve it. Is that something that would be useful? I mean, after the debate that raged on and Jeremy Miller banging out his own "roll your own CAB framework" maybe we need to open the heart of the beast and give it an implant that will let it live past the Acropolis phase. Some of us have invested already in one framework and I don't think there's a cost benefit to shift to another one, although that seems like the path we're being pushed down. Maybe the SCSFContrib project needs to be modified to support core changes and really divorce CAB from it's over architected implementation. A CAB where the guts are abstractions might help support a more popular community driven adoption and get it past the dependency on using MS tools. How about a CAB where you can use log4net, or Windsor, or pico? If Oren can build his own Event Broker in hours and Jeremy can instruct people on building your own CAB over a dozen blog posts I don't see why this isn't possible given some help from the world around us.

  • The Robot is in the House

    Errr, make that the yard.

    Quick. What am I doing right now? I mean, right now, this very instant. Yes, I'm typing this blog entry but what else am I doing? I'm cutting my lawn. Really.

    Late last year we had a rather talented chap come in, brave the coldness of Alberta in September, and proceed to lay out 10,000 square feet of sod (no easy feat). That's the size of our backyard. Of course come the spring brings the weeds, and the grass, and the chore of cutting all this new grass. There I was faced with the decision. Should I buy a ride-on mower and be a weekend Andretti, chewing up the grass, and probably killing myself or at least one of the dogs in the process. Or is there a better option?

    Enter the RL1000 Robomow from Friendly Robotics. Yeah, I kid you not. I heard about it through the grapevine, did some research and lo and behold most people felt it was a good buy. It's the same cost as a ride-on mower so it was one or the other. The geek in me of course chose the robot. After all, how many people can claim to have a robot do their backyard lawn cutting for them?

    It arrived on Friday and I spent part of Saturday setting it up. I felt like Sam Neill in Bicentennial Man when their Robot (in the guise of Robin Williams) gets delivered to the house, although the Robomow doesn't talk, do dishes, or take care of kids it does a splendid job of cutting grass. It took me about an hour to lay out 500 feet of perimeter wire. This is a long piece of wire pegged into the ground that holds it down and surrounds your lawn. The Robomow, on it's first run, will travel around the perimeter following the wire and get a feel for how your backyard is layed out. Luckily ours, while huge, is pretty much square with a small section on either side of the house.

    After pegging everything in, I fired it up and had Sheila (RedvsBlue fans will know where this comes from) go around the figure stuff out. Once that worked (and it did on the first shot, I was impressed) I commanded her to do my bidding and mow that lawn. First it edges the lawn, cutting along where the perimeter is setup, then it criss-crosses over the middle part. It does this several times and as it hits each edge, it will make a small adjustment and go back the way it came (in a slightly altered direction from where it came). After 3 or 4 passes it's done. It takes about 2-3 hours to do the lawn but I just sit back and don't worry about it.

    Works like a charm, although a) I had to go and remove some of the larger weeds in the middle of the ground as Sheila got stuck on them and b) you still have to trim the edges but it only takes about 20 minutes for that (and less for a smaller lawn). All in all, a good investment. I have it programmed now to go every Tuesday, Thursday and Saturday night at 7pm. This leaves me the chore of watering the beast on Sundays which is fine for me and keeps everything short and sweet. There's no bagging, it just mulches things down to a fine cut and is actually better for the lawn overall.

    If you're looking for a new geek toy and have a big, flat, square(ish) lawn I highly recommend the Robomow. It really does work as advertised.

  • My own Private WTF

    I've always wanted to submit something to The Daily WTF (come to think of it, I think I did but that was a long time ago) but today it just made me cry as I experienced my own private WTF. We had a developer leaving today and as I was doing a code sweep (looking at what was there, how the domain was shaping up, etc.) I came across this gem:

        5         private enum DumbLevel
        6         {
        7             Dumb,
        8             Dumber,
        9             Dumbest,
       10             Not
       11         }
    Okay, I said to myself. It's his last day, he's having some fun. Back when I worked with wood burning computers I wrote code with silly variable names too.

    Then of course my curiosity was piqued and I just had to know how this enum was being used. This led me to this snippet:

       19             if (cableCount == 0)
       20             {
       21                 if (cableCount == 1)
       22                 {
       23                     if (PassesCount > 1)
       24                     {
       25                         if (i <= (_segments.Count - 2)) //for all but last
       26                             dumbLevel = DumbLevel.Dumbest;
       27                         else dumbLevel = DumbLevel.Dumb; //last segment
       28                     }
       29                     else dumbLevel = DumbLevel.Dumb;
       30                 }
       31                 else dumbLevel = DumbLevel.Dumber;
       32             }
       33             else
       34             {
       35                 dumbLevel = DumbLevel.Not;
       36             }
       37 
       38             //calculate cable count and heat segment voltage based on the segment configuration
       39             switch (dumbLevel)
       40             {
       41                 case DumbLevel.Dumb:
       42                     cableCount = segment.GetCableCount(); //use # of tracers to determine cable count 
       43                     AuditStep("Cable Count: {0} (based on count of Tracers identified)", cableCount);
       44                     AuditStep("");
       45                     heatSegmentVoltage = SupplyVoltage*Project.VoltageDrop*segmentPercentage;
       46                     AuditStep("Supply Voltage ({0}) * Voltage Drop ({1}) * Segment Percentage ({2})", SupplyVoltage,
       47                               Project.VoltageDrop, segmentPercentage);
       48                     break;
       49 
       50                 case DumbLevel.Dumber:
    	           // code omitted for sanity
       51                     break;
       52             }

    This was by far the ugliest code I've seen on this project. The if statements alone started my blood to boil, but then when I started to see the case statements my brain turned to mush and that was my day done.

    Sigh. Oh well, next week I'll introduce the team to the concept of inheritance so they can see how to make the case statements (and the craziest set of Enum values I've ever seen) go away. And Donald thinks he has it rough hiring new guys?

    NOTE: sorry about the formatting, my VS settings are just hosed today.

  • The Red "X" of Death

    You've heard of the Blue Screen of the Death (Windows). You've heard of the Yellow Screen of Death (ASP.NET). Now here's the Red "X" of Death. 

    Got this on one of our apps the other day by our QA folks. It's a Smart Client app using the DevExpress Ribbon, CAB, and a host of other UI goodness. Needless to say, the error wasn't too useful to anyone trying to fix it.

    There's *supposed* to be a grid in the middle there with all kinds of useful information and calculations. DevExpress just decided that it really didn't want to do all that work and gave us a nice big red "X" as if we're missing an image from a website.