CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

September 2007 - Posts

  • Just some little fundamental things to help you CodeBetter

    I'm a big believer in learning the fundamentals of coding and design.  To me, things like design patterns, design principles, and code smells are more important to learn than specific technologies.  To paraphrase a conversation I had yesterday, I think it's vastly more important for a newbie develeloper to understand OO principles before memorizing the inner workings of ADO.Net.  It can seem like a bunch of academic hotair, but over the last couple weeks my group has come across some cases where a knowledge or ignorance of these little fundamental things has had a real impact on our success that I thought I'd share.  Here you'll find one principle, one code smell, and a dash of ancient wisdom that we need to occasionally relearn.

    I think I'd be a ringer at a software design version of Trivial Pursuit, but rattling off the names for things like the Liskov Substitution Principle isn't as important as internalizing that principle to the point that it's just something you do.

     

    Liskov Substitution Principle

    As interpreted by me, the Liskov Substitution Principle states that if a method or class has a dependency on an abstract type it should be able to accept and work with any implementation of that abstraction without changing the original code.  The official wording is:

    Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.

    That doesn't do that much for me, so how about "downcasting from an abstraction is a code smell." 

    To explain this principle let's look at a violation from my current project that's just begging for a fix.  We use a third party grid control (not Telerik) in an unbound mode for maximum flexibility of display and rendering.  Before the grid is displayed, we create an "ICell" object for each cell in the grid that models the value and formatting of each cell.  When the grid starts to draw any cell for the first time it raises an event requesting information for the row and column coordinate.  One of the arguments to the event handler is an object that contains all of the attributes of the cell display like the following:

     

        public class CellFormatArgs : EventArgs
        {
            public string Contents;
            public Color BackgroundColor;
            public Color FontColor;
        }

    Our event handler simply has to find the correct ICell for the requested row and column, then set the properties on the CellFormatArgs object appropriately.  Fine and dandy, but the code that does that work looks like this:

     

        // The ICell implementations are just data holders in 
        // this first version
        public interface ICell
        {
     
        }
     
        public class CellDouble
        {
            public double Value;
        }
     
        public class CellRate : CellDouble
        {
        }
     
        public class CellPrice : CellDouble
        {
        }
     
     
        public void RenderCell(int rowIndex, int columnIndex, CellFormatArgs args)
        {
            ICell cell = fetchCell(rowIndex, columnIndex);
            if (cell is CellPrice)
            {
                // render the price cell
            }
            else if (cell is CellRate)
            {
                // render the rate cell
            }
            else if (cell is CellDouble)
            {
                // render the double Cell
            }
        }

    Pay particular attention to the RenderCell method.  It can't just accept any old version of an ICell and go with it.  The RenderCell method has to know exactly which type of ICell it is then act accordingly.  If you need to add a new type of ICell you'll have to also change the RenderCell, violating the Open/Closed Principle.  When we modify our code to comply with the Liskov Substitution Principle, we'll get this:

     

        public interface ICell
        {
            void Format(CellFormatArgs args);
        }
     
        public class CellDouble : ICell
        {
            public double Value;
     
            public void Format(CellFormatArgs args)
            {
                args.Contents = Value.ToString();
                if (Value < 0)
                {
                    args.FontColor = Color.Red;
                }
            }
        }
     
        public void RenderCell(int rowIndex, int columnIndex, CellFormatArgs args)
        {
            ICell cell = fetchCell(rowIndex, columnIndex);
            cell.Format(args);
        }
     

    We've made the ICell interface implementations responsible for knowing how to render and format themselves.  All RenderCell() has to do is find the right ICell and call the Format() method on it.  RenderCell() no longer has to have any knowledge whatsoever of what exactly each ICell is.  We can now add new ICell types without touching the RenderCell() method, putting us back into conformity with the Open/Closed Principle.  I'd also argue that RenderCell() is easier to understand, and the formatting rules for each ICell type is easier to understand because the logic is in the context of each ICell instead of being in the middle of a long method containing all of the formatting rules.  Our formatting rules also got easier to test here as well by pulling the formatting of the CellFormatArgs away from the third party grid's event handler.  We've improved coupling from RenderCell() to the ICell implementations.  We've improved the cohesion of our classes by putting the formatting responsibilities into the ICell implementations.  Now all of our rules and logic for formatting rates are completely contained inside the CellRate class instead of scattered over the code. 

    In general, I'd say that any downcasting from an abstract type to a subclass or specific implementation is a code smell.  There may be a perfectly justifiable reason to downcast in your code, but when you see it creeping in you should assume that it's "guilty until proven innocent."  As a general rule, you want the interfaces and contracts of your classes and services to be taked completely at face value.  Everything you need to use the class or service should be evident or visible through the contract.  If you need to take into account the internal workings behind the interface or contract, you've got a nasty form of tight coupling.

    Why is there a fancy name for this?  Isn't this just common sense engineering and polymorphism?  Well yes I guess it should be common sense, except that it's commonly violated to negative effect.  Besides, if you had a fundamental principle of software design named after yourself, wouldn't you want people to make over it just a bit instead of blowing it off?

     

    Shotgun Surgery

    Shotgun Surgery is one of the Code Smells from Martin Fowler's Refactoring book.  Have you ever found yourself in a situation where changing one piece of code always forces changes to one or more other pieces of code?  That's doing Shotgun Surgery.  What the smell tells you is that all of those pieces that have to change together should probably be unified into a single entity so that changes can be streamlined.  It's following the DRY Principle so you can make changes with fewer mechanical steps.

    My group hit something like this last week.  We have an enumeration that basically identifies every possible type of financial number in the system.  In another namespace altogether is a class that keeps a string description for each unique value of the enumeration for screen display.  Every time we add a new value to the enumeration we have to remember to go over to this other class and add a new string to the other string array or bad things will happen when the client runs.  Our eventual fix is to create a small new class to represent the enumeration values that will also contain the description.  New enumeration values will then be completely defined in one place.

     

    Optimize by Measurement

    So you know how for your entire career you've heard that the best way to optimize performance is to measure the performance first because the hotspots may not be where you think they are?  And you'll be better off in terms of effort spent to deal with the hotspots before anything else?  I lived that little exhortation the other day.  I have a screen that was far too slow a couple days ago and knew I was going to spend some time optimizing.  While I was stuck in a useless meeting I started jotting down ideas to eliminate some fat out of my calculation and aggregation code that would have required some significant changes.  Once I got back to my desk I ran the JetBrains profiler on the screen just to get some benchmarks.  Unsurprisingly to the experienced folks out there, the biggest performance problem was something completely unexpected.  The entire set of calculations and expensive grid rendering was performed twice inside the twisty event rippling of the screen.  Thirty minutes later I got the double screen rendering solved and the screen was much more responsive -- without so much as touching the calculation code.

    Lesson learned.  Pay attention to the older folks.

     

  • The difference between Jeffrey Palermo and I

    Just before we all get to ALT.NET, I'd thought I'd try to explain how you can tell the difference between the two of us since we're frequently mistaken for each other just like Fozzie and Kermit in the Great Muppet Caper.

    Fozzie is the one with the brown hat btw.

    Jeremy is a big guy who used to work with Jeffrey in Austin and writes about Agile and .Net related stuff

    Jeffrey is a bigger guy who used to work with Jeremy in Austin and writes about Agile and .Net related stuff

    Jeffrey is a proud Aggie.  Jeremy is a Rice grad who used to cringe when people asked him if he went to A&M when they saw Jeffrey's wall-spanning A&M banner in the office.

     

    There, easy enough right?

  • Fire your best people

    Points for using Office Space.  Fire your best people…reward the lazy ones.  via Reddit.

    There's a longstanding aggravation about the guy who goes first dashing out awful code, but being a hero to management and the business while the maintainers coming behind the hero are goats for being slower working with the bad code.  Life isn't fair -- unless you count the times you dropped off bad code on someone else.

  • I'm speaking at DevTeach Vancouver

    I thoroughly enjoyed DevTeach the first time around and hope Vancouver goes just as well.  I'm giving three talks over the first two days in the Agile track:

    • Creating a Maintainable Software Ecosystem -- All the build, test, and configuration management stuff you can do to make the last minute change request safe to do. 
    • Design Patterns for Maintainable WinForms -- The first 10 or so installments of "Build your own CAB."  Despite being in the Agile track, this talk is much more about patterns and design than process. 
    • How does design get done on an Agile project? -- This is the one I'm looking forward to.  I'm going to try to lay down the reasoning behind doing Continuous Design instead of traditional upfront design, how Continuous Design can increase the value delivered to the customer, and what you need to know to do it efficiently and under control.  I'm planning on throwing the session open for questions and discussion for the last half hour to make it more interactive.

    Hope to see you there.

     

     

     

  • Silly thing I want from Ruby in C#

    The trailing comma should be legal after the last array element like Ruby:  string[] names = new string[]{ "a",   };

    Trivial, but helpful here and there.

  • The occasional attraction of TypeMock & Duck Typing

    // virtual for self-mocking

    public virtual IMeasureCalculation CreateCalculation(string productType, IMeasurable measures)

     

    Look at the bolded part.  Noise in the code for no other reason than to let an opportunistic usage of self mocking slip through the blasted compiler.

  • ALT.NET in Austin and beyond

    In a couple weeks, myself and about a hundred some odd other folks are converging on Austin for the ALT.NET Open Spaces event.  Just to get myself ready, here are the things I'm thinking about before we all get there.

    The most important part of ALT.NET for me is simply being on the quest for better ways of building software.  For too long we've allowed our tool vendor to do far too much of our thinking for us.  We need to sit up and make our own value judgements about how we build software.  We should have the tools shaped to fit our values, not our values shaped around the tools. 

     

    What's Next?  Where are we going?  What are you interested in?

    We're using the Open Spaces event format, meaning that the conference agenda is decided upon by the attendees when we get there.  There's a list of possible topics on the conference's homepage.  You'll have to fill in your own topics, but I'll give you mine.  The topics that I want to talk about are:

    1. Language Oriented Programming.  Textual Domain Specific Languages.  Writing code in higher levels of abstraction to increase the signal to noise ratio.  Writing more expressive and elegant code that's easier to understand.  Packing more punch with each line of code.  Fluent interfaces in C#, DSL's in Boo, and the far out stuff happening in the Ruby space.  Getting things done in code in one place as opposed to scattering little breadcrumbs of meaning in Xml or Xaml files, attributes, and various modeling schemes.
    2. Executable Requirements.  I think this is one of the biggest unattained goals/dreams of Agile development.  Toolwise, either Fit (StoryTeller!) needs to improve or we get lined up behind the xBehave tools.  Process wise, we've got to figure out how to get the customers, analysts, testers, and developers on the same page to get this done.  I'm looking forward to meeting the Lostechies guys and see what they're up to in this regard.
    3. I wanna see if Scott Bellware can make a coherent case for BDD as something totally new, different, and better than simply doing TDD and acceptance testing well ;-)
    4. There is representation from both MbUnit and the new xUnit.Net tool there.  I've pretty well assumed that innovation in the xUnit space was basically dead with xSpec tooling coming on strong, but let's see if I need to sit up and pay more attention.
    5. And yes, I'm anxious to hear more experience reports from folks that are doing development work with Ruby on Rails or MonoRail.
    6. There's a rumor that we're going to see something tangible from ScottGu's garage project to build a true Rails-like MVC framework.

     

    LINQ isn't important

    LINQ is sexy.  LINQ is cool.  LINQ isn't particularly important in the greater scheme of things. 

    I could just have easily said WCF or WPF or WF in place of LINQ.  All of those things are improvements in tooling, but not a revelation.  We (the .Net development community) put far too much emphasis on knowing libraries, API's, and technology tricks.  In the end, what's more important to being successful?  Knowing obscure facts about ADO.Net or understanding how to create a solid separation of concerns between your business logic and your database? 

    What I think is lacking in .Net is a greater appreciation for core development skills like OOP and software engineering practices.  RAD tooling might enable us to write code quickly, but we know it doesn't lead to sustainable development efforts.  The first order factor in the productivity and quality equations is the capability of the folks designing, writing, and testing the code.  If there's anything I'd like to be a part of "ALT.NET" it's the importance of building a solid core[LINK to JP].

     

    The Elephant in the Room

    The very real and obvious problem for us in ALT.NET is the general lack of skill, knowledge, and experience with the techniques, practices, and patterns that we're espousing in the .Net community at large.  I've been interviewing people for .Net positions for my company and our parent company over the last couple months.  Here's the typical skillset I keep seeing:  calling stored procedures that someone else wrote, grabbing the DataSet coming back, and slapping the DataSet's into databound controls.  That's it.  They know how to use the most common tools in Visual Studio and .Net but don't have any real deep knowledge of OOP, software design concepts, and the Agile practices that I think are valuable.  They simply don't have the background and skillset to work the way that I feel is best. 

    For example, I think Model View Presenter (MVP) designs are the best way to create a maintainable WinForms application.  The harsh reality is that MVP really works best with a team of developers that understand the MVP pattern in specific and Object Oriented Programming in general, at least enough to understand the separation of concerns that we're trying to achieve and why we want to achieve that separation.  Unlocking the goodness of MVP requires a deep knowledge and understanding of coding and design.  The .Net developer community at large simply does not have the deep seated coding skill and experience with patterns that makes a code centric approach like MVP succeed.  MVP flies in the face of out of the box WinForms, and that makes it very difficult to find developers who can work in that way.  Going farther, using MVP with TDD, CI, and all the good stuff, may actually do more harm if the developers building the system and following me when I go on to my next consulting project don't have any clue about MVP. 

    The neverending questions are:

    1. Can we improve the situation?  Can we democratize the skills and patterns we already think are best?
    2. How do we improve the situation?  At least enough to be able to find other developers to make our development style sustainable and feasible?
    3. Do we just give up and jump to Ruby or Python instead where they seem to get it?  I don't think I'm capable of forcing my development style into the MSDN mold, so this eventual move has to figure into my future planning.  In a way, I'd rather be somewhere where I don't stick out like a sore thumb.  More on this below.

     

    Your developers can

    Far too often I hear the refrain "our developers just can't do that."  There's a clear assumption that visual programming and Rapid Application Development tooling is the only way that the average developer can produce code.  We've got to break this self-defeating attitude.  Much of the reason that the average .Net developer can only work with RAD tooling and data centric development is simply because that's the only thing that they're exposed to at work.  Learning the RAD tooling is often nontrivial, and there's not much in all of  mainstream development as complicated as the WebForms event pipeline.  So why can't the average .Net developer learn to do things in another way?  Given a chance and some guidance, I don't see why an average developer couldn't embrace the practices and patterns of development most associated with ALT.NET.

     

    Is .Net Middle Earth, Ruby the lands across the sea, and MonoRail the Gray Havens?

    More than one person has questioned whether or not the ALT.NET canon and crowd is inevitably destined for Ruby and Ruby on Rails.  There's some thought, and at this point observation, that the alpha geeks in .Net are starting to drift into Ruby development instead.  If you're willing to question the "MSDN way," you're much more likely to be exposed to RoR and open to giving it a try.

    I think Ruby and Ruby on Rails has already drained quite a bit of the thought leadership out of Java, and you'll definitely see some of that happening to .Net.  Yeah, it has some issues with scalability and I'd question the ActiveRecord approach for complex domain models and databases, but those issues can be or will be beaten (RBatis & Rubinius maybe).  The attraction of RoR and Ruby in general is how it completely embraces the Agile practices I want to use, and the coding and design values that I believe in.  On the other hand, the .Net framework and Visual Studio tooling out of the box does not reflect the way I want to work. 

    This mismatch of values and framework presents me with a dilemma.  Leave the nice, comfortable (staid) Microsoft development womb, or move on to this whole new Ruby world.  There's another alternative, and this is where I hope ALT.NET steps in.  Can we change enough of the .Net community and tooling to make .Net development be what we want it to be?  IronRuby is coming.  ScottGu and co are working on some sort of MVC web development framework and MonoRail is already in production.  C# 3 is coming with some more powerful language constructs (borrowed from other languages because there's nothing new under the sun).  F# is flying under the radar, but the F# team seems to be well on its way to productionalizing F# development (I'd really love to talk to someone doing real work with F#).  The community awareness and adoption of Agile practices are on an upswing.

    Is it too little too late though?  Is Ruby inevitable for us?  Would some folks be happy to see us leave .Net anyway?  Is Microsoft serious enough about IronRuby to make it be more than a new form of VBScript to wire up Silverlight?  Can we make the .Net community into something better?  I'm sure all of these topics will get bounced around.  I'll try to provide the play by play here the following week.

    Lastly, award yourself some serious geek points if you fully understood the title of this section.

     

    What about the "ALT.NET" name?

    There's been some consternation over the name lately.  I've decided that I just don't care.  Call it tangerine development if you want.  The little "ALT.NET" moniker should disappear into the sands of history within a short amount of time anyway.

     

    For those of you who didn't get to come to Austin

    The spots filled up fast, and there were quite a few folks who didn't get a spot.  All I can say is that one of two things is going to happen:

    1. It flops, in which case you didn't blow your weekend
    2. It works, in which case it'll only be the first of many ALT.NET events.  I won't speculate on when and where the next one will be, or in what format, but I can promise that there will be a next.

    There's an absurd amount of talented and thoughtful folks there, so I'm going to step back and let everyone else lead the sessions.  What I will do is blog as much as possible about the proceedings as possible and write a long retrospective afterwards.  I'm going to try to interact with as many people as possible and try to sample as many conversations as possible.

     

    Other Folks on ALT.NET

    • Jeffrey Palermo says we should enjoy our software development efforts.  Scroll down to find Frans Bouma's comment at the bottom too.  There's always better stuff coming up and our dearly held ideas about software construction have a nasty tendency to get overturned as our field progresses.
    • David Laribee, the Kent Beck of ALT.NET, says there isn't all that much new to ALT.NET.  I'd say there's two parts to this one.  The first part is simply encouraging the usage of the things we already consider to be better practices, even when that's in opposition to the .Net way inherently embedded in Microsoft tooling.  The second part is an exhortation to keep looking for better and better ways of building software and to look in more than one place for those better ways.
    • My old lunchtime basketball nemesis Joshua Flanagan weighs in with ALT.NET is freedom.

     

    Jeremy's Agenda at ALT.NET

    Conference wise, I'm going to try to observe as much as possible, interact with as many people as possible, and write as many blog posts as possible.  Otherwise, my agenda is to soak up as much Austin as I can before going back.  I plan on hitting a lineup of my favorite Tex-Mex places and picking up a "Keep Austin Weird" T-Shirt at Chuy's for my son.  After the conference on Saturday night I'm going to see Billie Joe Shaver play just outside of town at the Nutty Brown Cafe.  Anybody who wants to see the quintessential Texas singer/songwriter (Willie Nelson and Waylon Jennings more or less did a Shaver tribute cd is that tells you anything) in action from a 100 feet away is welcome to come. 

  • Wrestling with pure evil

    1.) Very long method

    +

    2.) Non descriptive variable names

    3.) Variables are reused for different things throughout the method

    4.) Lots of if/then exception cases

    +

    5.) Deeply nested Arrowhead code

    +

    6.) All data stored in Hashtable's -- and it's this data that's getting bamboozled somewhere

    +

    7.) Numbers that come out wrong

    =

    An unpleasant Friday afternoon. 

    I worked with a developer one time who took an inordinate amount of pride in his debugging prowess and ability to make bad code function.  I could have really admired his ability if I hadn't been so busy cursing him for the code I inherited from him.  I think I'm getting more tolerant of other people as I get older, but less tolerant of bad code and code friction.

    The next time I do greenfield development I promise to appreciate it.

  • Is there a good reason to switch to MSBuild?

    I have a new coworker (hey Sheraz!) the last couple weeks who's hellbent on becoming a development guru overnight.  He's keeping me on my toes with a bevy of questions.  Today's question was "why are we using NAnt instead of MSBuild?"  My answer:  mumbling, then "because I know how to make NAnt dance and it isn't broken."  I've got years of experience with NAnt and it holds no real mystery for me, so I don't see any real reason to trade one set of Xml markup for another.  In the circles I run around in I'd bet NAnt is still the most common tool. 

    Am I missing anything cool?  Anybody used both and found a strong technical reason to prefer one or the other?

    Rake is a different animal altogether.  That I can see as an advantage for more complex scripts.

  • Lesson Re-Learned

    Two lessons relearned/reinforced.  One in the positive and one in the negative.

    1.) When working in a strange codebase, make no assumptions about the way that it works internally.  I got burned a little bit yesterday because I had made a false assumption about the way the existing code performed the aggregation of financial numbers.  I should have done a little more research on the inner workings of the existing code.  No big deal because...

    2.) All two dozen places that I used aggregated data used the same 3-4 classes.  One 20 minute coding change later and all of the numbers on my report suddenly look much better.

  • Testers are pigs

    For the sake of this post, let's just assume that testers and developers are just one big happy family with the shared goal of shipping working software.  On rereading this post it's definitely preachy, but I've been burned in the past by not being inclusive of the testers and my current client definitely suffers a bit from a too developer-centric viewpoint.

    Testers are pigs in the "people who have a direct stake in the project's success" manner. Sometimes we fall into a trap of thinking that productivity and schedule constraints are strictly related to developer time, but the testers are just as important.  I've got a case at work where 2-3 days of developer time probably translates into a couple weeks of testing.  Asking me alone when we can deploy isn't that useful because the testing is the bottleneck.  The tester's time is paramount.  For that reason, we need to get the testers (the tester in reality) every chance to be forearmed with prior knowledge of the work being done.  Planning has to include the question "how long do you think you need to test this?"  Is it really fair to dump a feature on the testers that they've never heard of and say "test this by the end of day tomorrow?"  Do you like it when somebody drops a complex architecture with a design pattern you've never seen on your desk and says code this by next week? 

    Do unto testers as you'd have done unto you.

    Remember to involve the testers anytime you're launching a new project, scheduling a production rollout, changing requirements, or really doing anything that alters the course of the project.  A lot of the time we implicitly assume that the testing time is linearly dependent upon the development time, but that's not always true.  The testers really need to have a say in the project scheduling, both to ensure that they have adequate time to do their job, and also just to know what it is that they're going to be expected to test.  In an ideal Agile team the testers are fully involved with each user story in near lock step wth the developers, so it's easier to keep the testers into the normal flow of a project.  Ignore the testers in your planning, and you pay for it later.

  • The ugliest code ever

    Before I could stop my errant mouse clicking index finger this morning I stumbled into the generated code for a strongly typed DataSet this morning.  You know the orange bars that ReSharper puts into the vertical scroll bar to denote warnings in the code?  In the DataSet code it looked like a solid bar of orange sherbert. 

    I was at a .Net user group last month at a talk on Subsonic.  When the speaker said the generated code was probably pretty good because it was generated code I almost spit up my coke.  Nothing against Subsonic, but my experience says that generated code is usually of atrocious quality and lacking in readability.

    And now I'm going to have to go get gelato for lunch.  Bummer.

  • Godspeed Mr. Jordan (OT)

    It was a sad day for me.  Wheel of Time author Robert Jordan passed away today from a rare blood disease.  It sounds like he's left the manuscript for the last book in order for someone else to finish.  Let's hope it's a good send off for one of my favorite authors.

  • Having a Captain Ahab moment

    All developers are susceptible to the Captain Ahab moment.  That one little thing in your system you just can't seem to make work.  The ever elusive white whale circling the boat, taunting you with your impotence.  Productivity crashes and burns in obsessive hunts over the great white whale.  I'm putting down my harpoon for the moment to spend the rest of the day working on something useful.  The world just isn't going to stop turning because I can't make the 3rd party grid control bend to my will, but there'll be hell to pay for missing the deadline on everything else.

     

     

  • Illustrating the importance of teamwork by looking at dysfunctional projects

    Most of this post is a repeat from my original blog in the mists of time (2005).  I've written a lot about teamwork the last several months because it's something that I feel is both important and lacking at my current client.  Say you have a guru in the domain logic in one cube with minimal software development experience, and down the aisle is a pretty decent developer with little or no business domain expertise.  This is your entire team for a small, but vital analytical report.  Do you:

    A.)  Give them separate tasks.  Let the domain expert write functionally correct, but unmaintainable code while the decent technical developer writes beautiful code that does the wrong thing entirely

    B.)  Have them work together to combine their strengths and wash out their weaknesses

    Individual ownership of tasks may be an easy way to manage the team, but I think that's the tail wagging the dog.  A team that collaborates is better than a group of individuals.

    Onward to the horror story about a dysfunctional team. 

    Project "Team" Insanity

    I used Alistair Cockburn's chart below on the effectiveness of various communication channels in a presentation several years ago trying to convince my then management to move towards iterative and more collaborative processes.  Basically, Alistair Cockburn is trying to encourage more interactive and collaborative forms of communication as a better mechanism for transmitting information.  My organization at the time simply didn't consider the impact of communication and collaboration on project success.

     

    At the time the entire organization was in a "matrix" organization structured by functional group first, and project teams second. Cubicle assignment was strictly by discipline (development, architects, analysts, testers, etc.) because management was tired of reorganizing teams and paying moving costs to colocate teams. Everybody was working on multiple projects at a time.  This was done with the theory that all projects would have access to specialized knowledge and skillsets instead of these specialists being bottlenecks for the entire department by their limited availability. I had the distinctly unpleasant experience of simultaneously working on the rump end of a death march project as a developer (later cancelled), and trying to lead the development of a separate project with significant technical complexity.

    The first project was an early Web Services project using a custom in-house SOAP-like framework developed by the internal integration architecture team (if you ever hear a sentence like that, run away!). The lead developer/project manager was in his first lead role and had no prior team lead or architecture experience. There were five distinct methods for the service, and five developers, so naturally each developer was assigned a method and told to go off and code it. I failed in my attempt to escape the assignment and began to code my assignment.

    My first action was to throw out the technically unworkable design that was handed to me by an architect. Win32 API and COM calls from within XSLT transforms in a high volume system?  Write a separate XSLT transform for every permutation of shipper, location, and shipping option?  No thank you.  Of course the estimate for my part of the development project was already scheduled in a Microsoft Project file months before I even came on board.  Since that estimate was based on erroneous assumptions, I had to change that estimate upward immediately to the consternation of the team lead. 

    Early on, I asked the lead where the development database was located and was told each developer was just using their own box. Come to find out, every single developer had created or reused a different database schema structure to hold the same logical data. Two developers were using an existing Oracle schema structure, and the other three developers had made their own Sql Server databases.  The Oracle transactional database was overworked and we had an opportunity to move some load off by separating the rules data away from the transactional data tables.  In fact, that separation of schema was a secondary goal of the project from the beginning, but the entire team didn't get the message.  There wasn't a common vision for the team and the project. 

    Two of us had created fully functional, specialized rules engines that did roughly the same thing, but radically different in implementation.  I had no idea that my colleague was even doing anything related because I was in my silo and he was in his.  If we'd worked together at all, we could have written much less code. 

    My first action as a newly minted Systems Architect (make finger quotes for the full effect) was to blow the whistle on the technical weaknesses to my new boss.  The first effort was to try to resolve the competing database schema, but to no avail.  We ended up with the exact same set of data expressed in two different set of tables.  If the data was in one set of tables but not the other, the system wouldn't function correctly.

    The project was fortunately abandoned and replaced by a different effort (2+ years in MSF Planning at the time that this was written!).  For about the cost of 15-20 man years of effort, not one single line of code made it to production and the poorly performant existing system limped on. 

    I sincerely think the project could have succeeded if the developers had been working in a common location instead of in a complete vacuum.  It wasn't the most talented team I've ever been on, but we easily had the talent to pull it off.  Just accidentally overhearing conversations would have tipped us off that our code could be shared between service methods and certainly would have got us on a common database early.  Of course, the fact that every developer was actively plotting to get off the project didn't help.  Going through a massive reorganization at the same time didn't help either.  I escaped to another project and into a lead role, but it turned out nearly as badly in a way.

    The Second Project - Death March #2

    The second project was an extremely complex system with three other developers, all of whom sat in different wings of the floor, and were working on other projects at the same time. At no time during the course of the project was the requirements analyst present on the team at the same time I was. All communication was through a requirements document that was prepared when I was on the other project.  Unsurprisingly, that document turned out to be incomplete and/or flatout wrong. Come to find out late in the game, there was a second requirements specification with extra reporting requirements that no one in development knew about.  My review for the year was partially tarnished by my having missed the upfront estimate badly.  I was off to begin with, but the estimate was done with the requirements that I had in my hands at the time.  We pulled it off by working way too many hours, but I'll never do a project like that again. The saving grace was very good involvement from the business partners, otherwise it would have bombed. The system is undeniably successful in production (one of my friends won an award from the business for it after I left), but it was a long time before I enjoyed software development again. I'm pretty sure the CMM crowd would call this an unrepeatable process.

    Of course it didn't help that I was a technical dictator that over-engineered the application to a tremendous degree, but I'm making fun of other people here, dammit! I read somewhere that the worst designer is a fellow on his second project trying to use every idea he had from the first system (editor's note, it's from Fred Brooks in the "Mythical Man Month."  Thanks to Darrell for the head's up). Guilty as charged. I'd also just read the GoF book for the first time and got a little patterns happy. They should put a warning label on that thing.  If I were to do that system today I think I could do it with a small fraction of the code by keeping things simpler. 

    If I had collaborated much more early on with the other developers on design I think we would have knocked out a lot of the unnecessary complexity.  Unfortunately the roles were defined as "Jeremy designs and creates detailed instructions that everyone else just follows."  I created some unnecessary complexity that was followed to the tee by unthinking developers.  The team's understanding of the design was limited because the rest of the team didn't have much involvement in creating the design. Instead of telling the other developers what to do I should have given them the tools to understand what they needed to do and make decisions for themselves that supported the design, architecture, and goals of the project.

    My former employer has since quietly removed the worst of the organizational madness and is simultaneously working toward climbing the CMM ladder and tentatively introducing some basic best practices like automated builds and better unit testing. All I can say is good luck to you guys, and it'll be worth the effort (maybe not the CMM part, though).

    I think it's fun to laugh at the absurdity of past projects, as long as you don't repeat them. Bad examples can be more illustrative than good examples sometimes.

    So what did I learn?

    I obviously soured on that employer.  Less than a year after finishing the second project I got to jump straight from the pure insanity to a high caliber agile shop. An oranges to oranges comparison of effectiveness between the Microsoft Solutions Framework process at the first shop and Extreme Programming in the second is useless because too many other factors were different (stronger teams, more supportive organizations, less customer involvement), but the simple ideas below were an enormous improvement in my mind:

    1. Sitting near all of my teamates in an open room that facillitated collaboration
    2. Collaborative design
    3. Everybody focused on only the one project with a shared set of goals
    4. Developers, testers, and analysts on the project at the same time!

    The simple act of colocation and ramping up the interaction and collaboration between team members is a powerful tool for building software.  The absence of collaboration is a prelude to disastrous outcomes.  One of the responsibilities of the team leaders is to foster a common vision and understanding of the project throughout the whole team.  Creating a design and direction is one thing, but socializing that design and direction may be more important in the long run.

More Posts Next page »

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP