in

 

Jimmy Bogard

Chief disinformation radiator

January 2008 - Posts

  • Some C# obscurities

    I'm sure everyone's tired of hearing about C# 3.0 features like lambda expressions, extension methods, anonymous types and so on.  Before you fall in love with the new features, there are a few oldies-but-goodies that revolve around the "?" character.  I use a couple of these to stump interviewees who proclaim themselves to be C# experts.  These question marks can provide a much cleaner, terser syntax for some fairly common C# usage patterns.

    Conditional operator

    This one can be easy to abuse, but it provides a nice terseness to code that has conditional assignments:

    if (hoursTraveled > 0)
        speed = distanceInMiles / hoursTraveled;
    else
        speed = 0;
    

    I'm trying to calculate speed, but clearly I don't want to get DivideByZeroException.  Sometimes these types of assignments can add up, so I like to condense them down with the C# conditional operator:

    speed = hoursTraveled > 0 ? distanceInMiles / hoursTraveled : 0;
    

    Now the conditional assignment can be written on a single line.

    I don't see this feature used very often, so there is a tradeoff in familiarity.  If the conditional or assignment statements grow too large, it can start to hurt readability, so just use your best judgement on this one.

    Nullable types

    The release of the .NET Framework 2.0 brought along a little struct type that solved a whole heap of problems.  Value types (structs) can be used to represent types that don't care about referential identity.  For example, if I have the number 2, and you have the number 2, they're the same number no matter how many times we create it.

    Value types have another interesting aspect, they can never have a null value.  The details behind this are exciting if you like things Jeffrey Richter style, full of heap and stack knowledge, but in the end you just need to know that C# structs can never be null.  This line does not compile:

    int i = null;

    But not every system in the world that deals with "int" recognizes this rule.  Databases and XML schemas are two examples where "int" values can be null.  To handle the impedance mismatch of real-world nulls and CLR-land value types, the Nullable<T> generic value type was introduced.  By declaring a variable to be Nullable<int>, I can now do this:

    Nullable<int> i;
    i = null;
    
    Assert.That(i.HasValue, Is.False);
    
    i = 3;
    
    Assert.That(i.HasValue, Is.True);
    Assert.That(i.Value, Is.EqualTo(3));
    Assert.That(i, Is.EqualTo(3));
    

    Note that I have no problems assigning int values to the Nullable<int> type, as the appropriate cast operators have been defined.  Declaring a nullable type is fairly ugly using the full generic notation, so C# has a nice shortcut:

    int? i;
    i = null;
    

    There's our friend the question mark.  It's telling us "I think this variable is an int, but I'm not sure?".  This is just another compiler trick C# uses, just like extension methods.  At compile time, "int?" is replaced with "Nullable<int>", so it's really just a shorthand way of expressing nullable types.

    Before nullable types, I had to use a bunch of dirty tricks to represent nulls in my entities, usually with magic numbers and values like "Double.NaN" or "DateTime.MinValue".  Nullable types let me bridge the gap between the nullable and non-nullable worlds.

    Null coalescing operator

    This is the one I love to stump the self-proclaimed experts with.  I draw this on the whiteboard:

    ??

    And ask them, "what does this operator do in C#?"  Usually I get the crickets, but the special few can tell me about the null coalescing operator.  The null coalescing operator is very similar to the conditional operator, but with the conditional built-in.  I find myself doing this quite a lot with nulls:

    if (category.Description == null)
        output = "<Empty>";
    else
        output = category.Description;
    

    I have a value that could potentially be null, in this case the description of a category, but I need to output that value to a friendly format.  Unfortunately, nulls aren't always too friendly to end-users.  Let's try the conditional operator to see how that cleans things up:

    output = category.Description != null ? category.Description : "<Empty>";
    

    But these conditionals can get ugly, so I can use the "??" operator to provide an even terser syntax:

    output = category.Description ?? "<Empty>";
    

    All of these representations are equivalent, but I like the short and sweet syntax the "??" operator provides.  Someone not familiar with this operator might not have any clue what the code does, so there is some level of risk involved.

    But I generally don't like to let a lack of knowledge with a built-in language feature deter me from using it, especially if it can provide a much cleaner syntax.

    And as always...

    If the syntax and usage these little question marks provide don't provide better readability (solubility?), then don't put them in.  These features are there to help, not to satisfy technical fetishes.  As always, keep in mind that your end goal is better readability and better maintainability, not a checklist of features used.

    Posted Jan 30 2008, 09:40 PM by bogardj with 6 comment(s)
    Filed under:
  • Best tool for the job

    I'm not sure if this is a trap, but I find myself doing this more and more.  Let's say you have a short (less than 2 weeks) project to work on, and maybe it's for a church website or something similar.  Non-business critical, but the customer wants it to look nice, wants it simple, and doesn't want to pay much (or anything) for it.

    You have two choices for the application architecture.  One is the Evans' style, the "new default architecture" that has a nice layered approach to it.  The other is to use lots of WYSIWYG designer tools, such as LINQ to SQL, that can get you up and running quickly.

    What I tend to do is opt for the more complex architecture first, even though the customer explicitly doesn't need it.  YAGNI tells me that I should opt for the cheaper architecture, and add complexity when required.  Pragmatism tells me that it's difficult to switch the entire architecture of an application.  It's difficult to switch from designer-based infrastructure to something more robust like NHibernate.

    To make it easy to move away from LINQ to SQL, I'd need to abstract away my interactions with that library so I can switch it out for something else.  The problem is that it's just as much work to implement a layered approach as it is to try an abstract away LINQ to SQL.

    And this is my dilemma: By locking myself in to a less flexible technology, I've limited the future complexity my solution can handle.  Even though LINQ to SQL is great for forms-over-data, I can't predict what my church website might need in the future.  Since customer's needs always change, how can I guess about future complexity?

    I don't really know if my customer will need more complexity in the future, but I assume they will.  If the customer needs more complexity, and the architecture can't handle it, I'm stuck re-writing significant portions of the application to use NHibernate instead.

    Even though NHibernate isn't always the simplest thing that could possibly work, I find myself opting to use it first as I know it can handle future complexity much better than the alternatives.

    Posted Jan 28 2008, 08:18 AM by bogardj with 19 comment(s)
    Filed under: ,
  • WatiN and INamingContainer adventures

    I decided to add a simple WatiN acceptance test today to validate our login page.  When a user enters invalid credentials, the page should show an error message.

    To test this, I need to set the text of the username and password, and click the Login button.  Since I didn't want just any textbox, but specifically the username and the password, I like to use the element ID's to find them.

    We're using the ASP.NET Login control to provide the login interface, which has the textboxes, the button, and the error message in one package.  When I want to get the ID, this is what it winds up being:

    ctl00_ctl00_ContentPlaceHolderMain_CenterContent_ctl00_ctlLogin_UserName

    Well that's no fun.  The INamingContainer interface puts out some crazy HTML element IDs to guarantee uniqueness.  Luckily I can use regular expressions to search for elements ending in "UserName", and that works for the button, too.

    However, the error message does not have an ID around it, so I have to dig into the login control manually to fish it out:

    Table loginControl = browser.Table(new Regex("._ctlLogin$"));
    TableCell errorCell =
        loginControl.TableBodies[0].TableRows[0].TableCells[0].
            Tables[0].TableBodies[0].TableRows[3].TableCells[0];
    

    Since I don't have access to the innards of the HTML in the Login control, this is what I have to resort to.

    I'm really looking forward to MVC framework, where I can take back control over the HTML generated.  At least WatiN will be easier.

  • Some essential Visual Studio tools

    Visual Studio for me personally is tough to use without some essential tools and add-ins installed.  Having recently set up a dev machine, I became keenly aware of the pain of using a clean installation of Visual Studio.  So I don't forget next time, here are the add-ins I like to use:

    There are plenty of other non-VS tools I use, but these are just to get me started inside Visual Studio.

    ReSharper

    ReSharper can be described as "crack for .NET developers".  Once you try it for a week, it's nearly impossible to code without it.  It affects productivity drastically, to the point that without it you might as well be coding with both hands tied behind your back.

    I think Jeremy mentioned it somewhere that, he doesn't take a .NET presenter seriously if they aren't using some refactoring add-on to Visual Studio.  Whenever I interact with a new team, it's one of the first things I get everyone to install, it's that important.

    TestDriven.NET

    TestDriven.NET is an add-on that makes TDD in Visual Studio a breeze.  All I have to do is right-click and select "Run Test":

    The menu is context-sensitive, so I can run one test, an entire fixture, or tests in the entire solution.  Wherever I click, that's the scope to search for tests to run.

    CoolCommands

    Many times I'd try to do some operation in Visual Studio only to realize there wasn't a menu command to do it.  CoolCommands adds those much needed commands, like:

    • Collapse all projects
    • Command prompt here
    • Locate in solution explorer

    And several others.  I use ReSharper's "Go to type by name" feature quite a bit, but many times I need to locate the file in the Solution Explorer.  CoolCommands lets me do just that:

     

    The installer is set up to target VS 2005, but this post contains instructions for installation on VS 2008 by making a small change to the setup batch script.

    VsCmdShell

    I'm a big fan of command-line builds, but sometimes it can get annoying dealing with an extra command prompt window.  VsCmdShell puts the Visual Studio Command Shell right inside the IDE:

    Now I can run my command-line builds directly inside the IDE, making them that much easier to use.

    Scott Bellware's TDD code snippets and VS macro

    ReSharper lets me create code from tests very easily, but what about the tests and specs themselves?  Scott (no link anymore) created some VS code snippets and a VS macro to create new tests and name them well.  Instead of posting screenshots, it's easier if you head over to JP's blog and check out the video he created of these add-ins in action.  The code snippets and macro have made TDD and BDD about as smooth as it can get in Visual Studio.

    Not an exhaustive list

    Since my old dev machine is now kaput, I'm sure there are a few others that I'm missing.  This set of add-ins does get me to a level where I feel that there is very little in the IDE working against me, which is always a good thing.

    Posted Jan 22 2008, 08:54 AM by bogardj with 5 comment(s)
    Filed under:
  • Notes from the Austin DDD Book Club

    We had our first meeting of the Austin DDD (Domain-Driven Design) Book Club today, and I thought it went well for a first meeting.  The book club was created because a few of us noticed at the Austin altnetconf that a discussion on DDD brought many widely different views on the subject.  To gain a deeper insight on DDD, some Austinites decided to get together every other week to read and discuss topics in Eric Evans' Domain-Driven Design book.

    This week, our group tackled:

    • Part I Intro
    • Chapter 1: Crunching Knowledge
    • Chapter 2: Communication and the Use of Language

    Here's a nice photo of a discussion in progress:

    As you can see, we had about 10 folks join us (Kevin is out of frame on the right).  No chairs were thrown either, which was good for all parties involved (including the chairs).

    The discussions tended to meander from the book some, which is fine, but it usually means you don't get to finish all of the material, which we didn't.  We did have some good discussions on:

    • Definition of "Model"
    • Whole team
    • Importance of communication
    • Ubiquitous Language
    • Modeling strategies
    • Many war stories of not doing whole team, or having bad communication, or having excessive translation between technical and business folks

    I'm sure there are some other topics I'm forgetting.  Since some conversations went way off-topic of DDD and into XP, I think I might try harder next meeting to keep it focused on the material, as it's the only way we'll get through it.  I noticed a couple of times people thumbing forward, which indicates they're ready for the conversation to either move on or get back on topic of the book.

    In any case, it was a nice meeting, and hopefully there was enough interesting discussion for everyone to come back next meeting.

  • Customer-facing identifiers

    I'm still installing miscellaneous drivers for my work laptop (Dell Inspiron 1501).  I just downloaded an additional printer driver for an office printer, but can anyone tell me in less than 5 seconds, without Googling, which file is the printer driver?

    Unless you have Internet access, you'll have a tough time guessing which is which.  That doesn't really help me when one of the drivers I'm installing is the network driver, and therefore have no Internet access yet.

    I think this is a prime example of technical data making its way to the customer's eyes, when it shouldn't.  Nothing on these files gives any indication what the driver is for.  I understand needing to have some identifying values on the file name for support purposes, but can I at least get a category in the file name? At least twice I've clicked and guessed wrong this week.

    I was on a product team once that used GUIDs for all entity identifiers.  Unfortunately, we also forced the users to use the GUIDs to load any entity from our API, but provided no way to easily extract them from any user interface.  End users had to manually type in all 32 hexadecimal characters from going back and forth from the screen to the code.  The irate emails cascaded down, and we didn't make that mistake again.

    Customers care about identity, they want to know that they're retrieving the right customer, and that the customer they're retrieving isn't duplicated.  Developers sometimes make the mistake that customers always care about how the identity is maintained, through a GUID or otherwise.  Under most circumstances, they don't, so we shouldn't force our special internal technical solutions for identities on customers and end users.  It's one of the quickest ways to confuse them.

  • Advanced CI: integrating web applications

    So you've already got an automated build with unit tests and deployment packaging.  But if you have a Web Application project as part of your solution, there is still the potential for some compilation errors to get past your builds.  So if your builds compile your solution, how can we run into compilation problems?  Let's look at a simple scenario.

    It happens every day

    Suppose I'm creating a simple ASP.NET MVC application, and I put some code in the template (ASPX) page:

    <h2>I HAZ A BUKKET</h2>
    
    <% Html.ActionLink<HomeController>(action => action.Index(), "Home"); %>
    

    Nothing fancy, I'm just creating a link to the home url.  But what happens when I mess something up here?

    <h2>NOOO!!!! THEY BE STEALIN MY BUKKET</h2>
    
    <% Html.ActionLink<HomeController>(action => action.IndexWHOOPS(), "Home"); %>
    

    The "Index" method exists on the HomeController class, but the "IndexWHOOPS" method definitely does not.  This should result in a compilation error.  However, when I build the solution, I don't have any errors:

    ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

    Succeeded, hooray!  My build is green, let's deploy!  If I happen to navigate to the lolrus page above, I get an error:

    Well that's no good, my build says "green" but in reality I have compilation errors.  My confidence in my automated build process is shot now, as I can't catch all compilation errors.  Someone could type in gibberish, and my build wouldn't catch it.  There are ways to catch these problems, however.

    Precompilation is the key

    When ASP.NET 2.0 was released, an additional command-line tool, aspnet_compiler, was shipped with it to allow developers to pre-compile web pages, ensuring a snappy response.  Without precompilation, each page and user control's ASPX and ASCX file are dynamically compiled when first requested, which caused a noticeable delay on the client side.

    But I don't want to wait for users to catch compilation errors in my templates, I want them caught during my build.  Since the tool to do so is already available via the command line, integrating it with NAnt or MSBuild is very straightforward.  In fact, there's already an AspNetCompiler task built-in to MSBuild, so you'll be able to use that.

    Before we integrate precompilation into our NAnt build, our compile task looks like this:

      <target name="compile">
        <exec program="${environment::get-folder-path('System')}\..\Microsoft.NET\Framework\v3.5\msbuild.exe"
              commandline="mvcapp.sln" />
      </target>
    

    We just need to add an additional compile step right after the solution compile that will perform our additional ASP.NET compilation:

      <target name="compile">
        <exec program="${environment::get-folder-path('System')}\..\Microsoft.NET\Framework\v3.5\msbuild.exe"
              commandline="mvctest.sln" />
    
        <exec program="${environment::get-folder-path('System')}\..\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe"
            commandline="-v mvctest -p mvctest\MvcApplication" />
      </target>
    

    Right after the solution compile, I compile the web application.  Depending on your deployment scenarios, you may want to tweak the command-line options passed in.  The options I used simply compile the web application in-place, but if I wanted to I could supply an output directory to place the compiled files.

    I'm just interested in receiving compiler errors, so what does our build tell us now?

         [exec] c:\dev\mvctest\mvctest\MvcApplication\Views\Home\Index.aspx(8): erro
    r CS1061: 'MvcApplication.Controllers.HomeController' does not contain a definit
    ion for 'IndexWHOOPS' and no extension method 'IndexWHOOPS' accepting a first ar
    gument of type 'MvcApplication.Controllers.HomeController' could be found (are y
    ou missing a using directive or an assembly reference?)
    
    BUILD FAILED

    Now I get detailed errors when I have compilation errors in my ASPX, ASCX, and all other files that get dynamically compiled by ASP.NET.  I can again put code in the designer files with confidence that my backup partner (continuous integration) will catch problems that I miss.

    Compile your designers

    Designers provide a nice declarative syntax for UI elements.  Many .NET technologies include designers, including ASP.NET and WPF (XAML).  But if your designers aren't compiled along with the rest of your build process, you have a hole in your build strategy as some bugs won't be noticed until they're seen by someone trying to view the UI.  This problem can be exacerbated if you have actual code in your designer files.

    By compiling your designers in the rest of your CI process, you can again have the confidence that 100% of your application is free of compilation errors.  But since you already have automated UI tests, you caught the errors already, right?

  • Abusing using statements

    I've always thought that the using statement was one of the most useful features included in C#.  It's easy to use:

    public string GetFileTextForParsing(string path)
    {
        string contents = null;
    
        using(StreamReader reader = File.OpenText(path))
        {
            contents = reader.ReadToEnd();
        }
    
        return contents;
    }
    

    The using statement allows me to create scope for a variable, ensuring any expensive resources are cleaned up at the end of the using block.  To be able to take advantage of the using statement, the variable created inside the "using (<object instantiated>)" must implement the IDisposable interface.

    At a recent presentation of the new ASP.NET MVC framework, I saw a rather strange use of the using statement that bordered on abuse.  It's from the MVC Toolkit, which Rob Conery introduced a while back.  The UI helpers are very nice, but it introduced a rather interesting way of creating HTML form elements:

    <% using (Html.Form<HomeController>(action=>action.Index())) { %>
    
    <input type="text" id="search" />
    
    <input type="button" value="Submit" />
    
    <% } %>
    

    When this code executes, it creates the proper HTML form tags.  The using statement is used because it can create both the beginning form tag at the beginning of the using block and the end form tag at the end of the using block.

    I'm seen some pretty creative uses of the using statement (that's actually my very first blog post, ever), but this one rubbed me the wrong way.  The traditional usage of the using statement is simply to provide an easy syntax to properly use IDisposable instances.  IDisposable has a rather specialized description in MSDN documentation:

    Defines a method to release allocated unmanaged resources.

    I don't think the Form method above has unmanaged resources.  That isn't to say that IDisposable should only be used to for objects with unmanaged resources, like database connections, file handles, etc, as the using statement makes it such a palatable feature.  Some common uses for IDisposable include:

    • Cleaning up resources (database connections)
    • Creating scope for an operation (RhinoMocks record and playback)
    • Creating a context for a certain state (security impersonation)

    The problem with the proliferation of IDisposable is we've reached the point where the IDisposable interface has no meaning in and of itself.  It's morphed into a convenient way to allow use of the using statement.  What's made the using statement so popular is that it provides a convenient syntax to encapsulate

    1. Code to be executed at the beginning of a block (the constructor)
    2. Code to be executed at the end of a block (the Dispose method)

    Figuring out if I can use the using statement with a given object or method call is a deductive process.  Unless the class or method is named in a manner that makes it obvious that I'm creating a scope block, like "CreateContext", I have to rely on documentation, examples, or Reflector to know that I'm supposed to use IDisposable.

    Additionally, there's nothing stopping me from not using the using statement.  For example, in the ASP.NET example above, let's try removing the using statement:

    <% Html.Form<HomeController>(action=>action.Index()); %>
    
    <input type="text" id="search" />
    
    <input type="button" value="Submit" />
    

    This results in the end form tag never getting generated.  This means that we're absolutely relying on developers to either call the Dispose method or use the using statement.

    A new interface?

    It used to be easy to know which objects needed to be disposed of properly, as these objects used unmanaged resources or had the explicit purpose of creating a context.  Since the using statement is such a convenient language feature, the IDisposable interface is used in a much wider variety of scenarios.  All these extra scenarios have made the existence of the IDisposable interface little more than a mechanism to take advantage of the IDisposable interface.

    The name doesn't make much sense anymore, as a fraction of the implementations of IDisposable are actually to clean up unmanaged resources.  A more appropriate name for IDisposable might be "IScopeable" or "IContext", anything that better describes what its use has become.

    Changing the name isn't feasible, but what I'd really like to see are compiler warnings or Resharper code analysis warnings telling me when I'm using an IDisposable instance without calling the Dispose method or including it with the using statement.  It's just too much work to check every single type I run into to see if it implements IDisposable.

    So as fun as the using statement might be, I'd like to see it either more obvious to discover that I need to use the using statement, or a little more restraint on slapping IDisposable on anything with two legs.

    Posted Jan 15 2008, 11:04 PM by bogardj with 7 comment(s)
    Filed under: , ,
  • Making the permanent move

    I'm getting pretty tired of cross-posting, so I'm making the permanent move over to Los Techies.  After all, if I get a free t-shirt:

    Then the least I can do is stop dipping my toe in the pool and just jump in.  Cross-posting is for chumps anyway.

    You don't need to update your feeds, except the feed now links to Los Techies.  This will be my last post on the blogspot site (sniff, sniff), and while you treated me well blogspot, your name doesn't rhyme with a tasty, tasty beer.

    Posted Jan 14 2008, 10:22 PM by bogardj with no comments
    Filed under:
  • Starting a new gig

    A few months ago, Jeffrey Palermo approached me at an AgileATX meeting to join him at Headspring Systems.  After much cajoling and intimidation (Jeff's a big guy), I accepted the offer, and today I started my new job.  Headspring Systems offered me a great opportunity to help customers succeed, where success might not mean just developing whatever requirement the customer throws at me.

    Headspring is a .NET shop that uses ALT.NET/Agile principles to deliver solutions.  That means this blog is going to start seeing a lot more NHibernate, StructureMap, Domain-Driven Design, Behavior-Driven Design, design patterns, ASP.NET MVC, and a whole lot less on legacy code.  I love the Michael Feathers, but legacy code is a challenge I like to tackle where there is a commitment to pay down the technical debt.  We're also committed not create more legacy code, which is also a refreshing philosophy.

    Also, it's my first consulting experience, so any advice is welcome :) (e.g. customer is always wrong, etc.).

    Posted Jan 14 2008, 10:17 PM by bogardj with 12 comment(s)
    Filed under:
  • Converting tests to specs is a bad idea

    When I first started experimenting with BDD, all the talk about the shift in language led me to believe that to "do BDD" all I needed to do was to change my "Asserts" to some "Shoulds".  At the root, it looked like all I was really doing was changing the order of my "expected" and "actual".

    In my admittedly short experiences so far, I've found that BDD is much more than naming conventions, language, and some macros.  For me, unit testing was about verifying implementations while specifications were about specifying behavior.  Although I'm not supposed to test implementations with unit testing, conventions led me down this path.  It's easy to fall into the trap of testing implementations, given constraints we put on ourselves when writing unit tests.

    Starting with tests

    Typically, my unit tests looked something like this:

    [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void Transfer_WithValidAccounts_TransfersMoneyBetweenAccounts()
        {
            Account source = new Account();
            source.Balance = 100;
    
            Account destination = new Account();
            destination.Balance = 200;
    
            AccountService service = new AccountService();
    
            service.Transfer(source, destination, 50);
            
            Assert.AreEqual(50, source.Balance);
            Assert.AreEqual(250, destination.Balance);
        }
    }
    

    When I wrote the implementation test-first, I first got a requirement or specification from the business.  It sounded something like "We want to be able to transfer money between two accounts".

    Before I started writing my tests, I had to figure a few things out.  Our naming conventions forced us into a path that made us choose where the behavior was supposed to reside, as we named our test fixtures "<ClassUnderTest>Tests".  In the example above, we're testing the "AccountService" class.  Additionally, our individual tests were named "<MethodName>_<StateUnderTest>_<ExpectedBehavior>".  We took these naming conventions because it organized the class behavior quite nicely according to members.

    Converting to BDD syntax

    I wanted to try BDD, so the quickest way I saw to do it was to change the names of our tests and switch around our assertions:

    [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void Transfer_WithValidAccounts_ShouldTransfersMoneyBetweenAccounts()
        {
            Account source = new Account();
            source.Balance = 100;
    
            Account destination = new Account();
            destination.Balance = 200;
    
            AccountService service = new AccountService();
    
            service.Transfer(source, destination, 50);
    
            source.Balance.ShouldEqual(50);
            destination.Balance.ShouldEqual(250);
        }
    }
    

    Now that I see the word "Should" everywhere, that means I'm doing BDD, right?

    Just leave it alone

    BDD is much more than naming conventions and the word "should", it's more about starting with a context, then defining behavior outside of any hint of an implementation.  When creating my Transfer test initially, before I could start writing ANY code, because of our naming conventions I had to decide two things:

    • What class does the behavior belong
    • What method name should be assigned to the behavior

    But when writing true BDD-style specs, I don't care about the underlying class or method names.  All I care about is the context and specifications, and that's it!  If I was writing the Transfer behavior BDD-first, I might end up with this:

    [TestFixture]
    public class When_transfering_money_between_two_accounts_with_appropriate_funds
    {
        [Test]
        public void Should_reflect_balances_appropriately()
        {
            Account source = new Account();
            source.Balance = 100;
    
            Account destination = new Account();
            destination.Balance = 200;
    
            source.TransferTo(destination, 50);
    
            source.Balance.ShouldEqual(50);
            destination.Balance.ShouldEqual(250);
        }
    }
    

    The key difference here is nowhere in the fixture nor the test method name will you find any mention of types, member names, or anything that hints at an implementation.  I'm driven purely by behavior, which led me to a completely different design than my test-first design.  In the future, if I decide to change the underlying implementation, I don't need to do anything with my BDD specs.  When I've decoupled my implementation of behavior completely from the specification of behavior, I can make much more dramatic design changes, as I won't be bound by my tests.

    I've also found I don't modify specifications nearly as much as I used to modify tests.  If behavior is changed, I delete the original spec and add a new one.

    So don't trick yourself into thinking that you need to modify your tests to become BDD-like.  Just leave those tests alone, they're doing exactly what they're designed to do.  A single context is likely split across many, many test fixtures, so it's just not an exercise worth undertaking.  Start your BDD specs fresh, unencumbered from existing test code, and the transition will be much, much easier.

  • Stop the Flash insanity

    More and more it seems high-profile websites are using Flash as a mechanism to deliver essential content.  In extreme cases, such as mycokerewards, the entire site is built on Flash.  Ads in websites, which you used to be able to ignore, now use Flash to replace the entire screen contents, screaming at you to "GO SEE CLOVERFIELD!!!".

    My dev machine is a fairly hefty beast, but it still has a hard time processing Flash-only sites:

    I'm not even doing anything in the Flash-only site except that I'm looking at it.  It's doing some ridiculous, pointless animation of bubbles floating around, and that requires 40% of my dual-core machine's resources.  When I look at this site on a single-core machine, I pretty much can't use FireFox any more, as it's completely consumed with those floating bubbles.

    Sites that used to be relatively easy to get around are now just annoying, like ESPN.com, which are starting to rely heavily on Flash to deliver actual content.  Please don't start playing some highlights video if I'm just going to your homepage, I really don't like Stuart Scott screaming "BOOYAH" to me through my speakers.

    If anything, Flash should be use to complement content, but not be the actual content.  To deal with normal annoyances, I go back and forth between these two FireFox add-ons:

    • Adblock Plus (blocks ad content, but not other Flash content)
    • Flashblock (blocks ALL Flash content, letting you opt-in to anything you want to see)

    Flash for delivering ad content is perfectly fine, as long as it's non-intrusive and non-resource intensive.  Flash for delivering site content is just plain heinous, and I hope Santa delivers coal in those perpetrators' stockings next year.

    Posted Jan 10 2008, 10:38 AM by bogardj with 1 comment(s)
    Filed under:
  • More on Scrummerfall

    A couple of comments have led me to think that I didn't explain what it is.  Let's review waterfall phases:

    • Requirements specifications
    • Design
    • Implementation
    • Integration
    • Testing
    • Deployment

    Each of these has a gated exit, such that to exit one phase, you need to meet certain criteria.  For example, to leave "Design" phase, you have to have your detailed design with estimates signed off by developers, analysts, and the customer.  You cannot enter Implementation until you have finished design.

    Scrummerfall still uses a phase-based methodology, but uses iterations for the "Design" and "Implementation" phases.  Testing is done as unit tests during development, but QA is not involved until the actual Testing phase later.

    Scrummerfall is easier to introduce in companies heavily invested in waterfall, as it's only one group (developers) that are actually changing how they work.

    Scrummerfall also makes two assumptions that become more invalid and costly the larger the projects are:

    • Requirements don't change after Design
    • Integration, Testing, and Deployment are best done at the end

    Now just because Agile doesn't have gated phases for these activities doesn't mean they don't happen.  Design and requirements gathering still happen, as do release planning, testing, deployment, etc.  The difference is that all of these activities happen each iteration.

    This is very tough in fixed-bid projects, which assume that requirements, cost, and deadline don't change.  There are alternatives to fixed-bid projects, which I won't cover here, that provide the best of both fixed-bid and time-and-materials projects.

    With Agile, you don't do a "Testing" iteration and a "Design" iteration.  That's lipstick on a pig, you're still doing waterfall. 

    So how do you avoid Scrummerfall if you're trying to introduce Agile into your organization?  The trick is to sell the right ideas to all of the folks involved.  If it's only developers leading Agile adoption, chances are you won't get too far past TDD, continuous integration, pair programming, and the rest of the engineering-specific XP practices.

    Get buy-in from an analyst, a PM, a tester, your customer, and your developers.  You won't have to convert all of the analysts and PMs, just the ones working on your project.  Remember, each person needs to see tangible business value from the changes you are proposing.  I tend to target management for Scrum and developers on XP, because although it's easy to get everyone to agree on values and principles, the concrete practices vary widely between the different roles.

    Posted Jan 09 2008, 04:05 PM by bogardj with no comments
    Filed under:
  • For the record

    This is not Scrum:

    • Planning
      • Release planning
      • Backlog creation
      • Architecture and high-level design
    • Development sprints
      • Design
      • Code
      • Test
    • Conclusion
      • System integration
      • System test
      • Release

    This is Scrummerfall, where we still do a phase-based waterfall model, but do iterations during the "development" phase.  I hear the word "hybrid" thrown around a lot in the above model.

    This isn't the cool kind of hybrid, like a Prius or a Liger (pretty much my favorite animal).  It's more of the Frankenstein hybrid, where it looks good on paper, but in the end you need the village mob with pitchforks and torches to drive it away.  Afterwards, the villagers have a bad taste in their mouth regarding science, so they banish it instead of booting out the mad scientist.

    One of the key benefits of agility is the ability to respond to change through feedback.  If the backlog is set in stone before my "development sprints" start, how do I change the backlog once business requirements and priorities change, which they inevitably will?  There is no mechanism to respond to change in Scrummerfall, dooming your project to quick failure, but now you get to blame Scrum.

    Another disaster waiting to happen is waiting until the end to do system integration.  I think everyone learned that "it works on my computer" doesn't fly very far once you start collecting a paycheck.  Customers demand the software works on their machine, not yours.  So why wait until the very end to do the riskiest aspect of development, when cost of failure is at its highest?  It pretty much guarantees failure and some exciting blamestorming meetings.

    I think these models come about from those who think Agile and Scrum are just another process, a cog to switch out.  Agile isn't a process, it's a culture, a mindset, a belief system, a set of values, principles, and practices.  Treating it like just another process gives rise to tweaking and leads to hideous hybrid Frankenstein monsters, roaming the countryside and spreading failure.

    Posted Jan 08 2008, 04:38 PM by bogardj with 1 comment(s)
    Filed under:
  • SVN and proxy servers

    So I wanted to check out Jeffrey's sample code he demonstrates in the latest dnrTV episode.  I get a fun message back from SVN, which is completely meaningless to me:

    It turns out that although SVN works through port 80, the proxy server I'm behind filters HTTP headers, one of which is PROPFIND.  Google tells me that I can configure SVN to use a proxy server, which is what I need to do with several applications (including Live Writer).  Although I have to hard-code my password into the configuration file, it fixes the problem:

    I have to change the configuration file every few months when my password expires, but otherwise I'm good.

    Posted Jan 07 2008, 02:53 PM by bogardj with 3 comment(s)
    Filed under:
More Posts Next page »
Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems