in

 

Jimmy Bogard

Assistant to the assistant to the regional manager

February 2008 - Posts

  • Setting the default browser inside Visual Studio

    My default browser is Firefox, and has been for many, many years.  But that's not everyone's favorite browser, nor is the one they have to use all day long.  When developing web applications for clients, it's important to know what their browser requirements are.  Often, for LOB apps or intranet apps, it's some version of IE.  In this case, I need to develop my web app using IE.

    This caused conflicts for me recently as my default browser is Firefox.  Whenever I would start the app (Ctrl + F5), a new tab would pop up in my Firefox browser.  I didn't want that, I wanted IE to pop up.

    One way to make IE pop up is to change the Web Application Project's Web settings:

    Here I can type in the path to IE with appropriate command-line arguments.  But that's annoying and brittle, as not everyone has IE in the same location.  This option doesn't work very well.

    Instead, we can set the default Visual Studio default browser, which doesn't conflict with the machine-wide default browser.  To get this set up, we'll need to open an ASPX file in our solution.

    If you don't have one, just create one temporarily.  For some reason, this option only shows up when you have an ASPX file open.  The option we're looking for isn't anywhere in "Tools->Options", or at least I couldn't find it anywhere.

    Finally, go to "File->Browse With...":

    This will bring the "Browse With" dialog up:

    Select whatever browser you want (IE for me) to be your default, and click "Set as Default".  Now whenever I start the application from Visual Studio, the correct browser pops up.  This is a Visual Studio-wide setting, so you'll need to use this property judiciously.

    Posted Feb 29 2008, 09:01 AM by bogardj with 5 comment(s)
    Filed under:
  • The Gmail rainbow

    I love Gmail, and I really love its labels, but I really really love its filters.  I had a hard time following all of the groups I wanted until Joe showed me how to drink from the firehose.  Now I get greeted with a nice rainbow in Gmail:

    With this, twitter, and Google Reader, sometime I feel like I need to quit my day job to keep up with the conversations.  So now I have two problems: I'm running out of colors and running out of hours in the day.  Anyone else have a worse rainbow than mine?

    Posted Feb 27 2008, 09:35 PM by bogardj with 2 comment(s)
    Filed under:
  • TestDriven.NET keyboard shortcut

    Continuing with the Palermo brain dump theme, Jeffrey introduced me to a keyboard shortcut for running TestDriven.NET tests from a keyboard shortcut.  I had been right-clicking and going from the context menu:

    While the context menu is nice, it has me reaching for the mouse (like a chump).   Instead, I can set a keyboard shortcut to perform the same context-sensitive testing.

    To set the keyboard shortcut, first go to "Tools->Options..." to bring up the Visual Studio Options dialog, then select the "Environment->Keyboard" screen:

    In the "Show commands containing:" text box, enter "TestDriven" to get the the TestDriven.NET command quickly.  Select the "TestDriven.NET.RunTests" command and click the "Press shortcut keys:" text box.  Now enter the keyboard shortcut you like (I use 'Ctrl-T') and click the Assign button.  The shortcut key is not assigned until you click the "Assign" button.

    Once you assign the shortcut, I additionally set the "Use new shortcut in:" to "Text Editor".  For some reason, setting "Global" wasn't enough, I had to set the "Text Editor" command also.

    With this keyboard shortcut in place, you don't need to lift your hand to the mouse after writing your test.  The shortcut also works everywhere the TestDriven.NET menu works, so I can select a file, project, or solution in the Solution Explorer and run all of the tests with a quick keystroke.  Since the context menu gets pretty unruly, I save some time I normally spend searching through a menu that now stretches my entire screen.

    Posted Feb 27 2008, 08:42 PM by bogardj with 5 comment(s)
    Filed under:
  • Moving past stored procedures

    On Chad's recent SQL-assembly comparison post, a few interesting comments caught my eye proclaiming the glory of stored procedures.  From tom (no link):

    [Stored procedures] are not only useful for speed but also for ACID and to keep business logic in a central place. (Business logic in clients is an idea as good as storing logic in js on webpages IMHO).

    And Lars Pohlmann:

    @tom: full ACK to your thoughts about stored-procedures.

    That goes especially for environments, where you have different clients and architectures accessing data from and writing data to the database. You'll need the logic at a central point to avoid code-duplication, and stored-procedures are the best way to do that, even if they are not that beautiful.

    I thought that the world had moved past putting domain logic in stored procedures.  At least I had hoped so, as systems with domain behavior in the infrastructure (data) tier can be the worst systems to maintain.

    Years ago, stored procedures were the de facto standard for data access tiers.  I remember most examples of data access coming out of Redmond using stored procedures.  Conventional wisdom has bucked this trend, but why?  Stored procedures seemed like a great way to encapsulate data access, so why are so many folks, both inside and outside of Redmond, putting so much energy in to ORM technologies?  Weren't stored procedures supposed to solve this problem?

    Way back when

    I can't speak of all developers, but my love of stored procedures started back in ASP 3.0 and SQL 7.0/2000 days.  Since VBScript was not an OO language, all domain behavior was expressed procedurally.  I would use the transaction script pattern for all of my application needs, with everything to perform an operation like AddUser or SubmitOrder in one long method.

    Developing in VBScript can be quite a pain, so why not put all of my logic in a stored procedure?  It made sense from the application side, as it was very difficult to maintain ASP files with a bunch of VBScript everywhere.  VBScript just wasn't expressive enough for the model we had.

    With all of the domain logic in the stored procedure, we could work much closer to what we thought represented our system: database tables.  Since we were in an ecosystem whose primary language (VBScript) was not capable of the models in our system, like Customers, Orders, OrderItems, etc., it made perfect sense to put our logic in the system that did capture our models, the database.  We thought of an Order as a row in a table, the OrderTotal as the sum of the OrderItems, and the Customer as the foreign key on the Order table.

    When you're in a database-centric mindset, stored procedures make all the sense in the world.

    A new modeling paradigm

    With the introduction of .NET came the ability to create fully OO systems in the Microsoft world (I'm not counting C++, those guys are just plain nuts).  No longer would applications need to be driven by large amounts of procedural code, we could now have models expressed in software.  Clients of a system could now interact directly with our model, which provided a much greater expressiveness than SQL ever could.  The problems of stored procedures were stacking up:

    • Difficult to test, therefore hard to maintain
    • Procedural, not OO
    • Impedance mismatch between data model and conceptual model

    The last part was key for me moving away from stored procedures.  Conversations with customers did not include a database diagram.  If it ever did, the conversation went very poorly, as customers do not think of Orders and Customers as database tables.  They think of them as entities with rules and behavior.  SQL is not nearly expressive enough to describe the behavior of these entities that would in any way satisfy the customer, or even make sense to them.

    Domain behavior (or business logic) could now be kept in a central location, but this location is now the software model, not the data model.  Behavior related to an Order is actually on the Order.  If I want to know the behavior of the system, I just need to look at the unit tests.

    Since I can use the full gamut of design patterns and modeling techniques in modern OO software, why not use that system?  Duplication is the scourge of maintainability, so why not use a system that can both model the customer's domain and effectively eliminate duplication?

    Your application is not your data

    As Tom and Lars pointed out above, the database can be a point to centrally keep domain logic.  But they are very, very poor at expressing behavior or removing duplication.  An application goes well beyond data, it includes behavior as well.  Since TSQL can't handle the rigors of OO modeling, where do we keep this logic?  If we have many different clients wanting to interact with our system (not just data), how do we allow this?  I'll pick one of two ways:

    • Through objects
    • Through services

    Both these options allow me to make changes to the data model without affecting clients.  If clients want complex aggregate reporting, reporting databases are perfect for that.  But no one is touching my data model except for systems that include the behavior behind that data.  Since databases are so poor at expressing such behavior, I'll pick something far more expressive and maintainable.

  • NHibernate and xmlpoke

    Some time ago I wrote about targeting multiple environments through NAnt.  The basic concept is to use the xmlpoke task in NAnt to modify any XML configuration files your application might use.  One setting that changes in each deployment we have is the "connection.connection_string" setting in the NHibernate hibernate.cfg.xml file.  This setting controls the connection string NHibernate uses to connect to the database.

    Unfortunately, I ran into some annoying problems that caused me a lot of frustration.  When I tried to use the xmlpoke task:

    <xmlpoke file="${dir.website}\hibernate.cfg.xml"
     xpath="//*/property[@name='connection.connection_string']"
     value="Data Source=${database.server};Initial Catalog=${database.name};Integrated Security=true">
    </xmlpoke>
    

    I kept getting this from NAnt:

    [xmlpoke] No matching nodes were found with XPath expression '//*/property[@name='connection.connection_string']'.

    I double, triple, and eleventy-tuple-checked the XPath and tried many other XPath combinations.  But the problem wasn't with the XPath, it was with the hibernate.cfg.xml file.  Looking at the top at the NHibernate configuration file, I saw that the root element had an XML namespace applied to it:

    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.0">

    I've used XML namespaces in the past to add prefixes to element names.  The xmlpoke documentation mentions namespaces, and this post confirmed it: I have to specify a namespace in the xmlpoke task for the XPath query to work correctly.

    Armed with this, I was able to get my xmlpoke task working correctly:

    <xmlpoke file="${dir.website}\hibernate.cfg.xml"
             xpath="//*/hbm:property[@name='connection.connection_string']"
         value="Data Source=${database.server};Initial Catalog=${database.name};Integrated Security=true">
      <namespaces>
        <namespace prefix="hbm" uri="urn:nhibernate-configuration-2.2" />
      </namespaces>
    </xmlpoke>
    

    I had to do few things to get it to work:

    • Add the namespace element with the correct uri attribute
    • Give it a prefix, "foo" if you want, it doesn't matter
    • Changed the XPath to use the prefix specified earlier on each element in the query

    Now the XPath works and my property is changed correctly.  Even though I don't specify a prefix in the namespace in the configuration file, I still have to declare the prefix in the xmlpoke task.  I'm sure there's some smarty-pants XML guru that could tell me the details, but all I care is that my build is deploying the correct connection strings.

    One less future headache for me.

  • Last XML serializer I'll ever write

    I've made this class probably a half dozen times, and I'm getting pretty tired of writing it.  It seems like every application I write has to serialize and deserialize back and forth between XML strings and objects.  For future reference, here it is:

    public static class XmlSerializationHelper
    {
        public static string Serialize<T>(T value)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
            StringWriter writer = new StringWriter();
            xmlSerializer.Serialize(writer, value);
    
            return writer.ToString();
        }
    
        public static T Deserialize<T>(string rawValue)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
            StringReader reader = new StringReader(rawValue);
    
            T value = (T)xmlSerializer.Deserialize(reader);
            return value;
        }
    }
    

    I like this implementation as it's generic so it removes some casting from the user.  Yeah, I know this code is probably in a hundred other blogs.  But at least now I know exactly where to find it.

    Posted Feb 19 2008, 10:35 PM by bogardj with 6 comment(s)
    Filed under:
  • Unit testing MonoRail controllers - Redirects

    When developing with MonoRail, one of the common operations is to redirect to other controllers and actions.  Originally, I looked at the BaseControllerTester to help test, but it required a little too much knowledge of the inner workings of MonoRail for my taste.  Instead, I'll use a common Legacy Code technique to achieve the same effect.

    The first attempt

    The easiest way to see if a method is testable is just to try it out.  Right now I don't have much of an idea of what to test.  I do know that the method I want to call in the Controller base class is "Redirect".  I don't really know what that does underneath the covers, but I don't much care.  What I'd like to do is create a PartialMock for the AccountController, and just make sure that the "Redirect" method is called with the correct parameters.

    A side note, PartialMock is great for mocking classes (as opposed to interfaces).  I can selectively remove behavior for specific methods while leaving the other methods and behavior in place.

    Here's my first attempt at a test with AccountController getting mocked out:

    [TestFixture]
    public class When_authenticating_with_valid_credentials
    {
        private MockRepository _mocks;
        private IUserRepository _userRepo;
        private AccountController _acctCtlr;
    
        [SetUp]
        public void Before_each_spec()
        {
            _mocks = new MockRepository();
    
            _userRepo = _mocks.CreateMock<IUserRepository>();
            _acctCtlr = _mocks.PartialMock<AccountController>(_userRepo);
    
            User user = new User();
            user.Username = "tester";
            user.Password = "password";
    
            Expect.Call(_userRepo.GetUserByUsername("tester")).Return(user);
            Expect.Call(() => _acctCtlr.Redirect("main", "index")).Repeat.AtLeastOnce();
    
            _mocks.ReplayAll();
        }
    
        [Test]
        public void Should_redirect_to_landing_page()
        {
            _acctCtlr.Login("tester", "password");
    
            _mocks.VerifyAll();
        }
    }
    

    In the Before_each_spec method, I set up the appropriate mocks and use the PartialMock method to try and mock out the AccountController.  Additionally, I set up expectations for the IUserRepository and additionally for the AccountController.

    Unfortunately, the test fails, but not for the reasons I like.  I get all sorts of exceptions from deep inside the MonoRail caves.  The mocking should have worked, so what went wrong?

    A little workaround

    Digging deeper into the MonoRail API, I find the culprit.  Although I told Rhino Mocks to intercept the Redirect call, it will only work for virtual and abstract methods.  The Redirect method is neither.

    Pulling an old trick out of the hat, I wrote quite a while ago about subclassing and overriding non-virtual methods.  This trick will work just great here.  I'll create a seam between the AccountController and MonoRail's SmartDispatcherController:

    public class BaseController : SmartDispatcherController
    {
        public virtual new void Redirect(string controller, string action)
        {
            base.Redirect(controller, action);
        }
    }
    

    Additionally, I change the AccountController to inherit from this new seam class.  Since I just wrap and delegate to the base class, production code won't be affected in the slightest.  Since my test mocks AccountController, which has a virtual "Redirect" method, the test now fails correctly.  And now that it fails correctly, I can fill out the implementation:

    public class AccountController : BaseController
    {
        private readonly IUserRepository _repo;
    
        public AccountController(IUserRepository repo)
        {
            _repo = repo;
        }
    
        public void Login(string username, string password)
        {
            User user = _repo.GetUserByUsername(username);
    
            if (user != null)
            {
                // check password
                Redirect("main", "index");
            }
        }
    }
    

    Although the BaseControllerTester provides a lot of out-of-the-box testing functionality, sometimes the implementation details can leak into my tests, which is what I don't want to happen.  I like to keep my tests coupled to frameworks as little as possible, and there's nothing really specific to MonoRail in my tests.  The method might change, but the MVC frameworks I've looked at all have some kind of "redirect to some other controller and action" method.

    The subclass-and-override technique provides a quick way to introduce a seam into classes that don't offer out-of-the-box testability in the places you want.  Since this pattern doesn't affect production code, I can feel confident testing my Controllers (or anything else similar) in this manner.

  • Eliminating obscure tests

    One of the purported benefits of unit tests and TDD in general is unit tests doubling as living documentation.  Unit tests are documentation in the form of executable client code demonstrating small units of behavior.  The idea is that if you wanted to understand how a class worked, you simply needed to look at the unit tests.

    But documentation, whether in the form of user manuals or unit tests, is only as valuable as the clarity of its content.  Obscure, vague tests can confuse developers trying understand behavior.  For example, can anyone follow the ambiguity of the following test?

    [Test]
    public void Should_compare_based_on_last_name_then_company()
    {
        Contact contact1 = new Contact() 
            { FirstName = "a", LastName = "a", CompanyName = "a" };
        Contact contact2 = new Contact() 
            { FirstName = "a", LastName = "a", CompanyName = "a" };
    
        Assert.AreEqual(0, contact1.CompareTo(contact2));
        contact2.LastName = "b";
        Assert.AreEqual(-1, contact1.CompareTo(contact2));
        contact1.LastName = "c";
        Assert.AreEqual(1, contact1.CompareTo(contact2));
        contact2.LastName = "c";
        contact2.CompanyName = "b";
        Assert.AreEqual(-1, contact1.CompareTo(contact2));
        contact1.CompanyName = "c";
        Assert.AreEqual(1, contact1.CompareTo(contact2));
        contact2.CompanyName = "c";
        contact2.FirstName = "b";
        Assert.AreEqual(-1, contact1.CompareTo(contact2));
        contact1.FirstName = "c";
        Assert.AreEqual(1, contact1.CompareTo(contact2));
    }
    

    The name of the test is reasonable enough, it's describing comparison behavior for a Contact object:

    public class Contact : IComparable<Contact>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string CompanyName { get; set; }
    
        public int CompareTo(Contact other)
        {
            int compareResult = LastName.CompareTo(other.LastName);
            if (compareResult == 0)
                compareResult = CompanyName.CompareTo(other.CompanyName);
            if (compareResult == 0)
                compareResult = FirstName.CompareTo(other.FirstName);
            return compareResult;
        }
    }
    

    Unfortunately, the name of the test is about the only good thing about it.  There are about a half-dozen asserts, sprinkled between changes to each objects state.  To understand what each assert is actually testing, you have to trace back the history of the changes to see what the state of each object truly is.

    This test is suffering from the Obscure Test smell, the cause being Eager Test.  It's testing far too much at once, and in doing so, misses quite a few scenarios.  If I change around the order of the comparisons in the Contact class, the test still passes!  That's a good sign of a bad test, if you can change the underlying behavior and the tests supposedly verifying behavior still passes.

    Test one thing

    So let's start over.  We have a request from the business that they want their contacts sorted by CompanyName first, then LastName.  Usually I keep my sorting concerns outside of the classes being sorted, but for posterity sake, let's keep the behavior in the Contact class.

    The main problem with the original test is that it tried to test a bunch of different scenarios at once.  Unit test convention tells us to test one thing per test.  It can be hard to define "one thing", but I like to think of it as "one context, one behavior".  A single piece of code might behave differently in different scenarios, so tackling it from the context/behavior side tends to get you more branch coverage.

    Now it's time to think of one context, and describe the desired behavior given that context.

    When comparing Contacts with different last name and different company names, it should sort based on the company names

    We could write several more scenarios, but one will suffice for now.  Using a BDD-style specification, this would result in the following specification:

    [TestFixture]
    public class When_comparing_Contacts_with_different_last_names_and_different_company_names
    {
        private Contact contact1;
        private Contact contact2;
    
        [SetUp]
        public void Before_each_spec()
        {
            contact1 = new Contact() 
                { FirstName = "a", LastName = "b", CompanyName = "a" };
            contact2 = new Contact() 
                { FirstName = "a", LastName = "a", CompanyName = "b" };
        }
    
        [Test]
        public void Should_sort_based_on_company_names()
        {
            contact1.CompareTo(contact2).ShouldEqual(-1);
        }
    }
    

    Now my test specification is not satisfied (i.e. failing), so I need to change the behavior of the Contact class to satisfy the new specification.  A couple things to note:

    • All setup information is put in the SetUp method
    • The specification part only contains assertions

    Now that I've explicitly partitioned the context (SetUp) from the specification (Test), it's far easier to make the connection between desired behavior and the observed behavior.

    Punished by laziness

    When I get lazy and try to test too much in a single unit test, I always pay more in the end.  Obscure tests are a subtle form of technical debt, as I'm fooling myself into thinking I have a good design because I have unit tests with coverage.  But if I can't look at a test and understand what it's testing, it probably put me in a worst spot than having no tests.  Instead of having to decipher just the underlying class, I have to decipher the test as well.

    Sticking to one context/specification of behavior helps me ensure that I can truly understand the underlying behavior of the system simply by reading the tests.

  • Getting over the TDD hump

    Chad mentioned that the first 2 hours of TDD are the hardest.  Without a good pair by your side, the pain can stretch well beyond a couple of hours.  Maybe I had a rare experience, but my first experience with TDD was successful and had very few bumps.  Looking back, I don't know what exactly we did right, but maybe the whole story might put things in focus.

    Step 1: Gettin' my learn on

    I hear a lot of questions about how to do TDD, what exactly TDD means and how it works.  Well, there's a whole book on it.  If you're done with that one and you have more questions, well there's this one that fills in the gaps.

    I had read a lot on blogs about TDD, but let's be honest.  Blogs are great about focusing on a single topic, or a short introduction, but they don't pull everything together in a single physical medium.  There are very few writers quite as clear and concise as Kent Beck, the author of the original book.  So if you hear any arguments about what TDD is, check out the original source.  It's very clearly defined.  Without reading Kent Beck's book, we were merely guessing on what TDD actually looked like.

    Step 2: Team buy-in

    Many of us in the team looked at XP and liked its values, principles and practices.  Another Kent Beck book laid out in clear terms what some good values are, and the value of agreeing on values.  Teams have values, implicit, de facto, or explicit.  Our team agreed to have some explicit values (feedback, communication, courage, etc.) and take time on regular occasions to reflect on whether we adhered to our values.

    We were pretty lucky that everyone on our team had an open mind, but then again, that's who we tried to hire.  We valued passion and open-mindedness to years of experience.  And in that case, we were successful.  Everyone agreed to try TDD, but no one mandated it.  We all agreed that people had success with it and we were capable of success, so there was really nothing stopping each of us from trying except for fear.  That's where our "courage" value kicked in.

    Step 3: A gentle introduction

    We would have seriously crashed and burned if we tried to introduce ourselves to TDD against our existing legacy codebase.  Nothing in our existing product was testable by any stretch of the imagination, and it seemed like that if we wanted to sneeze we needed the database up.  In Kent Beck's book, he introduces TDD in a pairing session tackling a simple problem, a bowling game.

    Our team agreed to do something similar, and practice TDD on a simple problem.  We decided the board game, "Connect Four" had simple enough rules for us to complete the game in a day.  There were no rules for our practice except:

    • We must program in pairs
    • Code must be written test-first

    We had no constraints on the interface of the game.  My pair decided to use arrays and console output for the game, while other pairs went for a visual, WinForms experience.

    At the end of the day, we got back together for a retrospective and compared code and tests.  We also talked about what went well and didn't go well, and what we could have done better.  Finally, we all agreed we had a lot of fun doing it and wanted to have that much fun developing against our real-life codebase.

    And they're off

    The bell sounded and the horses were out of the gates.  From that point forward, the bulk of our work was done test-first style.  We weren't great at first, but that wasn't the point.  We had committed as a team to give TDD a fair shot, and our codebase thanked us for it.  When we started, we had zero unit tests and we ended a year later with well over a thousand.  At first we would have little "woo hoos" when we hit milestones at the hundreds.  As our velocity increased, we only celebrated hitting 1000.

    Along the way, we had many questions answered simply through practice.  We tried different styles, stumbled through many smells.  Through our dedication to constant feedback and communication, we drove through any barriers we had.  If there was a wrong way to do things, we found it.

    But since we committed as a team to work together to improve ourselves (and deliver more value more often), the journey was far easier than it would have been flying solo.

    Posted Feb 13 2008, 08:31 PM by bogardj with 4 comment(s)
    Filed under:
  • Team System and open source

    A note to all open source developers in .NET:

    DO NOT use any exclusive Team System features in your open source projects!

    Team System and the Team Edition flavors do not mix with open source projects.  I opened up the SDC Tasks Library on CodePlex and was greeted by this fun message:

    Since I am using Visual Studio 2005 Professional, I can't open the "Test" project containing all of the tests.  This is unacceptable and borderline insulting.  No one except users of Team System can even open the project.  Only some of the Team Edition installations can open this project type.  There's not even anything interesting about this project, it just contains unit tests!

    In VS 2008, Test Projects are included with the Professional edition.  That means that Express edition users will be out of luck too.

    If you're developing open source libraries, all assembly dependencies should be included in your source repository.  If the license for the dependent assembly doesn't allow for redistribution, don't depend on it.  Pick something else.

    Posted Feb 07 2008, 08:30 AM by bogardj with 2 comment(s)
    Filed under:
  • Stories, requirements, and language

    The negotiation between client and team on what gets delivered is the toughest aspect of software development that I've encountered.  Something that's eased this aspect for me is adopting User Stories and abandoning "Function Requirements" and "Feature Requests".  I'm reading through Mike Cohn's User Stories Applied to gain a better understanding of the concept.  In the book, Mike Cohn shares a quote from a customer of his:

    You built exactly what I asked for but it's not what I want.

    I just love this quote, as it's what I've run into dozens of times when I used requirements and feature requests to define customer needs.  Mike has a great article on the advantages of user stories as requirements.

    For me, the difference between the three is the underlying meanings of the words will have with the clients.  It's amazing how much subtle variations in the language we use impacts assumptions, understandings and relationships.

    Negotiation and conflict

    I've used three types of artifacts in my career so far to deal with customer needs:

    • Feature requests
    • Function requirements
    • User stories

    Ignoring the semantic definition of all three, suppose each of these pointed to the same artifact: a story card.  This story card has something similar to this on the front:

    A job seeker can edit their resume

    Now all three definitions are on the same playing field and point to the exact same project artifact.  Do the definitions still all hold the same value?  Unfortunately not, as language and meaning significantly shape a person's interpretation of a concept.

    Asking and denying

    Take the words "Feature Requests".  What kind of contract does this imply between the customer and the team?  What kinds of interactions will this lead to?  Requests are questions, or "asks".  I am requesting that a job seeker can edit the resume.  How does the team respond?  Are they now in control of what gets developed or not?

    When you label something a "Request", it implies the customer is asking for a feature.  The team accepts or denies this request.  Now the contract between the customer and the team is a contentious and strained.

    Whether or not this is what happens in reality is irrelevant; the words attributed to the artifact enforce a certain kind of negative contract between customer and team.  Trying to fight the underlying meaning of the words will be like swimming against the current.  It's possible, but exhausting and expensive.

    Asking for features puts the customer in a bit of a jam.  It's now their responsibility to convince the team to accept their feature requests, even though the customer has the best knowledge of what has the highest priority.  Developing software is hard enough, we shouldn't make it more difficult by enforcing a subservient relationship between client and team through our language.

    Requirements and fear

    Swinging the pendulum the other direction are "Functional Requirements".  Now take the word "requirements" by itself and its meaning.  Requirements imply something needs to be done.  If you don't do what is required of you, you have failed.

    In the context of software development, "Functional Requirements" puts quite a bit of strain on the team.  If they deliver 99% of the requirements but miss one, they've failed as they haven't done everything that the customer said was required.

    Teams may deal with this by assigning priorities to requirements, but that's putting lipstick on a pig.  Something that is less required than something else doesn't mean it isn't required.  Not doing the lower priority requirement still means you missed a requirement.

    Putting requirements in contracts is also hazardous, as customers tend to focus on what was missed.  Even if the software moved in a different direction, the customer looks at the original requirements and sees items missing.  Just calling them "requirements" implies that they are absolutely necessary for success.  Because the team called a customer need a "Requirement", the customer believes success is dependent on that need being fulfilled.

    In the end, an acrimonious relationship between customer and team will result.  The team will fight as much as possible to limit the number of requirements in the contract for fear of not delivering them.  The customer can't berate you for missing a requirement that wasn't in the contract, but they'll resent you for not letting them put it in the contract in the first place.

    The fear and resentment between the two parties can absolutely kill productivity, and success will likely be accidental.

    Getting the language right

    Even if all three "customer need" definitions pointed to the same concept, the words attributed to the concept will shape the underlying contract and relationship between customer and team.  With User Stories, the team (which now includes the customer) is free to generate as many stories as they like.  The main negotiation that takes place are the priorities for the stories before each iteration.

    That's where the "Customer collaboration over contract negotiation" piece comes into play.  The team has one goal: customer success.  Anything that gets in the way of that success, including language, should be scrutinized, debated, and acted upon.  Since language and definitions shape understanding and meaning, it's critical to get the language right, even if the underlying concepts are the same.

    Posted Feb 06 2008, 09:24 AM by bogardj with 7 comment(s)
    Filed under:
  • Flexibility and control

    At our recent Headspring .NET Boot Camp, Jeffrey and I had an interesting conversation with a couple of attendees whose company was considering an all-out VSTS love fest.

    Already using TFS source control, the company was looking at using the Work Item and Team Build features, specifically to get integration between the two.  Most build systems (including CCNET) note what recent check-ins are included with each build.  The Work Item integration goes one step further, linking persisted Work Items (which could be User Stories, Product Backlog Items, Sprint Backlog Items, etc.) to individual builds and check-ins.

    Nearly simultaneously, Jeffrey and I asked: And how are you going to USE that information?  Neither developer could answer, and they had to IM their manager to get an answer.  The reply back was something about compliance, which was definitely not what this VSTS feature was designed to help with.  What was more likely was that this feature was intended to be used to exhort more restrictive control over development, through command-and-control management

    Check-ins would need to be associated with features, and builds would be checked to see what tasks were worked on and delivered.  Needless to say, the developers weren't too pleased with the extra burden of keeping up with all this extra information.

    The manager had likely fallen under the illusion of rigid control leading to more predictable success.

    Two kinds of control

    Think of the difference between an arrow and a guided missile.  The arrow is aimed once and released, and accuracy is pretty high for short distances.  Over longer distances, wind pushes the arrow astray, and the original trajectory, no matter how precise initially, becomes irrelevant.

    With a guided missile, small or large corrections can be made during flight to ensure the missile hits its target.  The initial aiming doesn't have to be precise by any means, as long as it's not pointing at the ground.

    In the first example, control is achieved through rigidity, leading to long term inaccuracy.  Taking five minutes to aim an arrow at a target a mile away isn't going to help me hit the target any easier.

    In the second example, control is achieved through flexibility, leading to long term accuracy.  It doesn't matter how much I aim the missile initially, as I'm likely wasting time.  Instead, through regular feedback and correction, I can change and correct the course to achieve previously unheard of accuracy.

    Feedback and accountability

    Instead of trying to manage daily tasks, the manager in the example above could have fostered feedback and accountability.  The goal isn't to have a list of features checked off at the end of six months, it's to deliver value and achieve the customer's business goals.

    Through regular feedback, the team's course can be shifted and corrected to aim at the customer's often moving target.  Through accountability, the team becomes responsible for acting on that feedback and ensuring the missile's rudders aren't stuck.

    Jeffrey and I suggested the team use the lightest tools possible, story cards, until the need can be proven for more heavy-weight tools.  The team needs to question their process and ceremony, always ensuring that their actions always work towards their stated goals.  Applying rigidity and inflexibility to this system will most surely lead to wild and disappointing misses.

    Posted Feb 04 2008, 09:02 PM by bogardj with 7 comment(s)
    Filed under:
  • Stuck in proprietary-land

    Many years ago, I made the fateful decision to standardize my home music collection on WMA.  The bundled software in Windows XP, Windows Media Player, ripped my CDs to the WMA format, for free.

    At the time, MP3 ripping utilities cost money, or came with a boatload of spyware or malware attached.  Windows Media Player also had a nice service where it automatically found media info from a central database and tagged your music files accordingly.  This was nice as it can be a huge pain to manually edit each MP3 file's ID3 information.

    Looking back, I chose wrong.  Why am I wrong?  The number one portable music player on the planet, the iPod, doesn't play WMA files.  When I first started creating my music library back in 2001, the iPod wasn't supported on Windows.

    To date, WMA players have been pretty lame.  I haven't seen one yet that approaches the usability of an iPod, and buying WMA files from official channels has been a lesson in bad DRM policies.

    So I'm now stuck converting my WMA files to some other format, which I'm still trying to decide what to go with.  Although MP3 is a licensed technology, it's so ubiquitous it seems like a good bet.

    I absolutely refuse to purchase music with DRM, as recent debacles (Google Video and PlaysForSure) have shown DRM is a losing proposition, for both content providers and content purchasers.

    I'll be very, very careful in the future when deciding how to persist media I care about.  If a music format can disappear at the whim of its creator, I don't want to be stuck with useless bits and bytes.

    Posted Feb 04 2008, 08:43 AM by bogardj with 8 comment(s)
    Filed under:
Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems