• Imagine the scene.  You are starting a new project.  At the kickoff meeting the stakeholder introduces the mission of the project, the business analyst hands out the requirements document, the project manager hands out the project plan, and the development manager gives his best “Do it for the Gipper” speech.  You look through the project plan and see that it specifies a release date (several months in the future), the resources that will be involved, major milestones to be met, and everyone’s assignments.

    The team looks over the stack of paper in front of them, and roll their eyes. “Here we go again” is on everyone’s mind, but think better about voicing it out loud.  Out come the smart phones to see what family events and vacations will have to be cancelled due to slipped release dates and last minute death marches. 

    Why does this happen?  And seem to happen often enough that everyone who’s been a developer for more than a few years all have a similar story. 

    The Iron Triangle of Project Management

    IronTriangleThere are three factors of software development that must be considered.  What will go into the release, how much the project will cost (largely a factor of the number of resources involved), and how long it will take to develop.  This triangle is traditionally represented a number of ways, but I prefer the figure to the right.  It shows the balance between these three factors.  If any one of them is changed, it will offset the triangle, and the other factors will have to be adjusted accordingly.

    Increasing the scope (for example) will extend the right side of the triangle, and schedule and cost must be extended to keep everything in balance.

    This is not news to anyone in project management.  In fact, it’s a well known fact for all types of projects, software, construction, and manufacturing.  In theory, it makes perfect sense.  If I need to build a house, I take the blue prints and can calculate with a high degree of certainty how many people I will need (and for how long), what the cost of the materials will be, and how long it will take to build that house.

    The Fundamental Flaw

    This theory holds up as long as everything on the project is roses and unicorns.  But what if there is a significant rainfall that floods the build site and construction is delayed for a week?  What if there is a hurricane on the coast, and this creates a shortage of drywall?  What if the construction company has never built a straw-bale house before? Now instead of repeating the same job that they have done hundreds or thousands of times before, they can only guess how long it will take.

    And this is the fundamental flaw with the iron triangle.  Scope can never be absolutely predicted.  It can be accurately predicted for tasks that you have done many times before.  Do you drive to work?  How long does it take? Your answer is probably something like “About X minutes”.  It’s about because of the variables that occur in life.  Maybe the traffic lights are against you one day, but you catch them all green the next.  What if there’s an accident?  Could you predict that it would take you 90 minutes to get to work when yesterday it only took 30?  Certainly the scope of the work was the same.  Driving from home to work.  But the schedule (and one might say the cost due to increased fuel consumption) changed significantly.

    Estimates are not Exactimates

    How do you estimate the amount of time a task will take?  Is it something that you have done before?  Or is it just like something you’ve done before.  Or maybe you have never done anything like it.  How do you tell decide how much time do you need in the schedule?  Most developers who are honest with themselves will usually admit that it’s all a guess.  Sometimes it’s a SWAG – Scientific Wild A$$ Guess.  But usually it’s just a WAG – dropping the science.

    How many times have you given your estimates to you development lead and he/she doubles them. “Developers are always too optimistic”.  Then these numbers are handed into the project management office, and they add another factor on top. “Last project ran late, so we will build in some slack to make sure we deliver on time”.

    Then these numbers are carefully factored into the project plan, and the promise of is handed out to all parties – stakeholders, management, and any other interested parties.  “We will deliver this amount of work on this date and it will cost this much” is the triumphant announcement.

    And once again the cycle commences…

    The Death March

    As the project is commencing, and everyone is carefully reporting their hours and status, the problems start to hit.  Maybe not big ones at first, but they begin to add up.  That 8 hour task took 16.  Bob got sick and missed a week of work. Susie’s baby came early, and is on maternity leave.  The chance of delivering the promised scope at the promised time with the approved budget becomes slimmer as time marches on.

    Concessions have to be made, but the iron triangle is, well, iron.  One can’t just pull one side longer and keep the same shape.  The date has been promised to external organizations.  Perhaps there’s a marketing campaign that is set to launch at the same time as the new software.  Maybe customer contracts are in place.  Regardless of the obligation, the date is usually the last thing that can move. So the only chance is to throw hours at the project.  Overtime gets approved, and all are expected to work extra.  Just a few hours at first, but then more as the triangle gets more unbalanced. 

    IronTriangle2More often than not, the overtime progresses into a death march.  Developers are eating dinner at their desks, working through lunch, make life sacrifices for the sake of the project.  Quality starts to degrade due to exhaustion and less careful programming.

    There an old saying that nine women in a month can’t make a baby.  However, this principle often gets applied in these situations when management approves bringing in extra headcount to try and save the project. 

    Maybe the extra head count and overtime work does save the project.  But did you notice what happened?  The cost/resources side of the triangle got extended to account for the change in scope.  Despite the best efforts (and intentions) of all parties involved, the reality of the situation couldn’t be avoided.

     

    Making The Right Choice

    Reality is clear.  You can’t fix all three sides of the triangle.  As an organization, you have to decide what is most important to you.  Is it release date?  Then fix the date, and make the concession that the software will have as much scope as was able to be completed in a quality manner in that time frame.  The advantage of fixing schedule is that it produces the side effect of fixing the cost.  If you have X team members, they will be working Y hours per week until release.  Cost then is fixed at X*Y*Z where Z is the number of weeks until release (of course in reality you have things like vacations, sick leaves, etc. that must be factored in).

    The opposite is true as well.  If you have a fixed budget, you can extrapolate a release date by doing the above calculation solving for Z instead of the right hand side of the equation.

    Fixing scope isn’t as clear cut of a story.  Since scope relies on inaccurate estimates, that side of the triangle will keep moving, adjusting schedule and cost along with the changes from estimates to actuals.

    So decide what matters.  Put a stake in the ground for your release date.  Or your budget.  Than realize that the rest will be what it will be.  But at least you can keep your promise the stakeholders, the customers, and most importantly, to the team.

    Happy Coding!

  • Technorati Tags: ,

    I hit this error today while working with an MVC3 application.  It appeared out of the blue – but don’t they always?  Fortunately, I make a habit of committing my work into SVN every time my tests pass, so I could have just reverted back to my last Revision, but I wanted to know what I did to cause this.

    Much to my demise, the optimistic fixes didn’t work:

    • Restart the debugger several times, because surely that will fix it :-)
    • Close Visual Studio and reopen it.

    Just kidding.  But we do tend to try those don’t we?

    Back on topic, I looked at the changes between my current work space and the last working revision.  Turns out somehow the web.config in the Views directory was deleted.  Once I restored the file from SVN, all worked wonders again.

    Wonderfully descriptive error message, isn’t it?

    Happy Coding!

  • After many years in Nashville, TN, the Devlink conference moved to Chattanooga, TN. John Kellar, the founder and lead organizer, moved to Chattanooga, and as someone who runs conferences in different cities, I can appreciate John wanting to have DevLink follow him. image

    In the days leading up to the event, it was interesting to hear some folks say they weren’t going to go “because it’s not in Nashville”.  Well, I can say first hand, they screwed up!  John and crew once again put on an awesome show!  Over 120 sessions, and open spaces track, and plenty of off-hours activities made this one of the best DevLink conferences ever.

    Telerik was well represented, not only continuing the trend of supporting the community through sponsoring events and user groups, but also sending a great crew of speakers!

    The Telerik Lineup of Speakers:

    My sessions:

    • Lessons Learned: Being Agile in a Waterfall Sandbox
    • SOLID Development Patterns for Mere Mortals

    Todd Anglin (Chief Evangelist for Telerik)

    • Building RESTful Applications with Open Data Protocol
    • The Rich Standard: Getting Familiar with HTML5
    • HTML5 and CSS3 Techniques You Can Use Today
    • Doing More With LESS for CSS

    Lee Brandt (Telerik Insider)

    • NHibernate, FluentNHibernate and the Repository Pattern in 75 Minutes or Less

    David Giard (Telerik Insider)

    • Effective Data Visualization: The Ideas of Edward Tufte

    We were so busy with all of the awesome content and activities that we didn’t miss Nashville on bit.  See you next year!

    Happy Coding!

  • [Cross posted from http://www.skimedic.com/blog]

    IMGP1261The 4th annual St. Louis Day(s) of .NET built on the previous years successes and once again delivered an amazing show.  Held at the beautiful Ameristar Casino and Resort in St. Charles, Missouri.  This year, the conference maxed out the capacity of the conference center (over 800 people attended the show!)

    Hats off to Jeff Fattic, Scott Spradlin, and Kevin Grossnicklaus and the scores (yes I mean scores) of other volunteers that made this event possible. I also have to give props to their spouses, children, friends, and co-workers, since the time commitment to run such a large event is extremely significant.

    Telerik was proud to be one of the Gold Sponsors of the event, always willing to support the community.  Telerik was also very well represented among the speakers, with myself (Patterns and Practices Evangelist) and two Telerik Insiders (Lee Brandt and Steve Bohlen). Between the three of us we gave 9 talks! 

    I gave:

    • Deliver Cleaner Code with LINQ to Objects
    • Lessons Learned: Being Agile in a Waterfall Sandbox
    • Implementing M-V-VM (Model-View-ViewModel) for WPF
    • Enhancing LightSwitch Applications with Telerik/Third Party Controls

    Steve Bohlen:

    • Refactoring to a S.O.L.I.D. Foundation
    • Unit Testing Patterns and Anti-Patterns
    • Taming Dependency Chaos with Inversion of Control Containers

    Lee Brandt:

    • NHibernate, Fluent NHibernate and the Repository Pattern in 1 Hour or Less
    • Behavior-Driven Development from the Trenches

    Once again, an amazing job.  Great content, great speakers, great venue, great attendees.  Well worth the trip to come to the show, no matter where you live!

    Happy Coding!

  • My employer, Telerik, is once again competing for a bevy awards in the DevProConnections competition.  We are competing in 20 (yes, I mean twenty) categories, so there’s many places where you can show your love!

    To find out more about the competition you can read this great post on Telerik Blogs.

    I was a consumer of Telerik tooling long before I became an employee, and am still amazed by the level of responsiveness that the product teams have to feedback that I illicit from the community (both in person and online).

    Happy Coding!

  • While we still have a couple of speakers that we are trying to work into the line-up (but we only have so many slots, so decisions are very tough), the lineup for the Philadelphia Day of Agile is gearing up to be an awesome event!

    We have international speakers, agile thought leaders, and experts in the field coming from all over the country to share their knowledge with you!  And the best part?  Admission is only $50!  This is less than half of what it costs to run this event, the rest is paid for by our generous sponsors.

    I also want to give a shout out to Agile Philly and the Philly PMI – Delaware Chapter who are co-chairs of the event.

    For all of the information, please check out the website at www.dayofagile.org and the registration site at www.phillydayofagile.eventbrite.com.

    Here is the agenda for the day.  As you can see, it’s a virtual fire hose of information!

    Track 1

    Welcome Phil Japikse
    What is Agile and Why Should I Care? Steve Bohlen
    The Testing Pyramid Nancy Chacko
    Intro to Kanban Jon Mills
    Selling Agile Into Your Organization John Petersen
    Closing Keynote: Enterprise Agility Philip Japikse

    Track 2

    Welcome Phil Japikse
    Agile Teams - From Good To Great David Bulkin
    Making Distributed Teams Work (Effectively, Even) Jim Holmes
    Help! There's a waterfall in my Sprint Jim Schiel
    5 Dysfunctions of Agile Teams Bob Hartman
    Closing Keynote: Enterprise Agility Philip Japikse

    Track 3

    Welcome Phil Japikse
    Agile Project Owners - What Ails Them Anupam Kundu
    Risk Adjusted Release Planning Bob Hartman
    Introduction to Test Driven Development James Bender
    Beyond Metrics Andre Dhondt
    Closing Keynote: Enterprise Agility Philip Japikse
  • Technorati Tags: ,,

    Agile is becoming more and more popular.  All of your friends are doing it, and they always make it to happy hour!  So why aren’t you becoming agile?  What’s holding you back?  How do you overcome the blocking obstacles to transition over to a more agile development environment?

    Come join myself along with a panel of other industry experts – Joel Semeniuk and Steve Porter for an interactive discussion to answer your questions with real world experience.  You will also have a chance to win a 10-User license for TeamPulse.

    To register for the panel, go to the webpage to register.

    Happy Coding!

  • For those of you that attended the What’s New for Desktop Developers in Q2 2011 Release Webinar, thank you for attending!  For those that didn’t get to attend (or for those of you that want to go back through it since it was jam packed with information), the recording worked perfectly, and I will be posting it to Telerik TV in the next 48 hours! 

    Several people attending the webinar asked for the source code for my project that I created to demo the features as well as the powerpoint slides, and you can get them both here (slide deck, code samples and database backup). I would be remiss if I didn’t mention that the RADControls for Windows Forms ships with an extremely robust sample application that shows off all of the controls, complete with source code!  There is also a separate sample application that demonstrates the RADRichTextEditor, and I encourage you to look into those samples for much more robust usages of the controls.

    For more information on the RADControls for Windows Forms and all of our other great controls and tools (did you know we make more than just components?), please start your journey at http://www.telerik.com.

    Happy Coding!

  • [Cross posted from http://www.skimedic.com]

    Technorati Tags: ,

    Yesterday, after my session on LINQ at MADExpo, a gentleman asked me how I would solve a certain problem that he is facing at work with LINQ.  Here is my solution (turns out I was a little brain dead after giving three sessions at the conference, so while he was sitting with me, I just couldn’t see it).

    The Problem

    The problem consists of a list of salespeople that have sales.  Here are the classes involved:

    public class SalesPerson
    
    {
    
     public string Name { get; set; }
    
     
     public IList<Sales> Sales { get; set; }
    
    }
    
     
    public class Sales
    
    {
    
     public string Day { get; set; }
    
     
     public decimal Amount { get; set; }
    
    }
    
     

    The gentleman wanted to know (by day) the top sales people.  If the relationship was bi-directional (there was a link to SalesPerson from the Sales class), this would have been an extremely simple solution.  But since the relationship is only one way, there was a little more thinking involved.

    Creating the Test

    To setup the test, we had to create some data and some asserts to validate that the LINQ statement pulled back the correct SalesPeople.  Here is the test:

    [Test]
    
    public void ShouldGetAverageDailySales()
    
    {
    
        SalesPerson bob = new SalesPerson() {
    
            Name = "Bob",
    
            Sales = new List<Sales>() {
    
                CreateSales("Mon", 50),
    
                CreateSales("Tue", 50),
    
                CreateSales("Wed", 500),
    
                CreateSales("Thu", 50),
    
                CreateSales("Fri", 50) } };
    
        SalesPerson sue = new SalesPerson() {
    
            Name = "Sue",
    
            Sales = new List<Sales>() {
    
                CreateSales("Mon", 100),
    
                CreateSales("Tue", 400),
    
                CreateSales("Wed", 100),
    
                CreateSales("Thu", 300),
    
                CreateSales("Fri", 100) } };
    
        SalesPerson tom = new SalesPerson() {
    
            Name = "Tom",
    
            Sales = new List<Sales>() {
    
                CreateSales("Mon", 195),
    
                CreateSales("Tue", 200),
    
                CreateSales("Wed", 200),
    
                CreateSales("Thu", 200),
    
                CreateSales("Fri", 2000) } };
    
        IList<SalesPerson> people = new List<SalesPerson>() {
    
            bob,
    
            sue,
    
            tom };
    
     //Create LINQ Statement Here 
        Assert.AreEqual("Tom", sales[0].Name);
    
        Assert.AreEqual(195, sales[0].Amount);
    
        Assert.AreEqual("Mon", sales[0].Day);
    
     
        Assert.AreEqual("Sue", sales[1].Name);
    
        Assert.AreEqual(400, sales[1].Amount);
    
        Assert.AreEqual("Tue", sales[1].Day);
    
     
        Assert.AreEqual("Bob", sales[2].Name);
    
        Assert.AreEqual(500, sales[2].Amount);
    
        Assert.AreEqual("Wed", sales[2].Day);
    
     
        Assert.AreEqual("Sue", sales[3].Name);
    
        Assert.AreEqual(300, sales[3].Amount);
    
        Assert.AreEqual("Thu", sales[3].Day);
    
     
        Assert.AreEqual("Tom", sales[4].Name);
    
        Assert.AreEqual(2000, sales[4].Amount);
    
        Assert.AreEqual("Fri", sales[4].Day);
    
    }
    
     

    We have one helper method for the test, shown here:

    private Sales CreateSales(string day, decimal amount)
    
    {
    
     return new Sales() {
    
            Day = day,
    
            Amount = amount };
    
    }
    
     

    Breaking It Down

    The approach that I took (and if readers have a more elegant solution, please post a comment) was to first determine the maximum sales by day (note my solution does not take into account ties).

    The first step was to get the Sales classes into their own collection.  To do this we use “SelectMany”.  The following LINQ statement will return an IEnumerable<Sales>. If we just used “Select”, we would get IEnumerable<IEnumerable<Sales>>, which doesn’t help in the least.  Remember when you are pulling a child collection out of your source collection, you are typically going to use SelectMany (but your problem will really dictate what to use).

    var p1 = people.SelectMany(p => p.Sales);

    The next step is to group all of the sales data by day.  We do this with a groupby, selecting the Key value and the data to place in the group.  The following code illustrates this.

    var p2 = p1.GroupBy(p => p.Day, p => p.Amount);

    This creates a dictionary where the Day (from the Sales class) is the key, and all of the matching sales amounts become the data associated with the key. To access the data, we can inspect the created entity in the Immediate window.  Each item in the created IEnumerable has a Key property, and the Value of the data is an IList<decimal>, that we can enumerate over with a simple ToList() call.

    ? p2.ToList()[0].Key
    
    "Mon"
    
    ? p2.ToList()[0].ToList()
    
    Count = 3
    
        [0]: 50
    
        [1]: 100
    
        [2]: 195
    
     

    This still isn’t what we want, since we need the Max sales per day.  Fortunately, from here, this is a simple step by using a Projection.  Projections are where we create a new object from an existing object(s). In the following code snippet, we are creating a new Sales object for each key.  The unique key (Day from the original collection) is assigned the Day property in the new object, and the Amount is the maximum value of that Day’s records in the dictionary.

    var p3 = p2.Select(r => 
    
     new Sales {Day = r.Key,Amount = r.Max() });

    Putting it all together into one line, it looks like this:

    var sales = people.SelectMany(p => p.Sales)
    
       .GroupBy(p => p.Day, p => p.Amount)
    
       .Select(r => new Sales {
    
            Day = r.Key,
    
            Amount = r.Max() });

    This gives as a new IList of Sales objects, one for each Day in the source data, with the Max sales amount for that day. Examining the resulting IEnumerable in the Immediate window gives us this glimpse into the data:

    ? p3.ToList()
    
    Count = 5
    
        [0]: {LinqSamples.A_BaseOperators.Sales}
    
        [1]: {LinqSamples.A_BaseOperators.Sales}
    
        [2]: {LinqSamples.A_BaseOperators.Sales}
    
        [3]: {LinqSamples.A_BaseOperators.Sales}
    
        [4]: {LinqSamples.A_BaseOperators.Sales}
    
    ? p3.ToList()[0]
    
    {LinqSamples.A_BaseOperators.Sales}
    
        Amount: 195
    
        Day: "Mon"

    Now that we have the top sales by day from the original collection, we need to go back and find the SalesPerson that had the top sales.

    At first, it is tempting to write the following code into our LINQ expression, where “z” represents the top sales object from the previous LINQ statement above:

    people.Where(p => p.Sales.Contains(z))

    There are a couple of issues with this.  The first is that we create new Sales objects, and Contains is a reference operation. So it is trying to compare based on the actual references in memory, not the values of the Sales object.  Secondly, this statement gives us another list, and we need to get a single Value.  To fix the second problem, we call “FirstOrDefault”.  This will give us the first object returned, or null (since SalesPerson is a class) if there isn’t anything matching the predicate.

    To solve the first problem, we need to create a custom comparer so that our code is comparing values instead of references.

    public class SalesComparer : IEqualityComparer<Sales>
    
    {
    
     public bool Equals(Sales x, Sales y)
    
        {
    
     return (x.Day.Equals(y.Day) && x.Amount.Equals(y.Amount));
    
        }
    
     
     public int GetHashCode(Sales obj)
    
        {
    
     return obj.GetHashCode();
    
        }
    
    }
    
     
     

    Now that we have resolved both of those issues, our final partial LINQ statement looks like this:

    var p4 = p3.Select(z => 
    
     new { 
    
          Day = z.Day, 
    
          Name = people
    
             .Where(p => p
    
                 .Sales
    
                 .Contains(z, new SalesComparer()))
    
             .FirstOrDefault().Name, 
    
          Amount = z.Amount })

    This creates a list of new objects that contain three properties, Day, Name, and Amount.

    Putting it all together into one statement yields this:

    var sales = people
    
       .SelectMany(p => p.Sales)
    
       .GroupBy(p => p.Day, p => p.Amount)
    
       .Select(r => new Sales {
    
                    Day = r.Key,
    
                    Amount = r.Max()
    
                })
    
       .Select(z => new { 
    
           Day = z.Day, 
    
           Name = people
    
              .Where(p => p.Sales
    
                 .Contains(z, new SalesComparer()))
    
              .FirstOrDefault()
    
              .Name, 
    
           Amount = z.Amount });
    
     

    So, there you have it.

    Happy Coding!

  • [Cross Posted from skimedic.com]

    I was invited to speak in Colorado and Arizona for three user groups, and it was a great time!

    image

    I kicked off the trip in Colorado Springs at the South Colorado .NET Users Group ran by Ben Hoelting, a fellow MVP and a friend of mine that also speaks at VSLive.  We had a great chat with an overview of Uncle Bob Martin’s SOLID Principles, and then spent the majority of the time discussion software patterns and where they would make sense in the real world.

    Next up saw North Colorado .NET Users Group, headed up by Jeff Certain, also a fellow MVP. For this group I gave a new talk that I had been working on called “Introducing Agile into the Workplace”. I culled the content from several other agile talks that I give, and bundled it up into one.  What was great about this group is the level of involvement we had in the discussion.  Maybe it was the wine and the really good Colorado beer, but it was one of the best conversational meetings I’ve been to in a long time.  Special thanks also to Kathleen Dollard for adding her wisdom and experience into the discussion.

    imageFrom the Denver, Colorado area I headed South and West to Tucson, Arizona for the Tucson .NET Users Group, led by Mike Collins. We discussed Windows Presentation Foundation for Developers, but we also discussed a lot of the anxiety about the way Microsoft is (imho) mishandling Windows 8 announcements and the fear, uncertainty, and doubt (FUD) surrounding the future (or feared lack thereof) of .NET development on the new Windows platform.  Whereas I don’t have any more knowledge or information than anyone else (outside of Microsoft), we can all admit two things:

    • 1) Microsoft is doing a terrible job with communication. and
    • 2) I can’t see (again, merely my opinion), MS turning their back on all of the developers in the .NET ecosystem.

    I had a little bit of an issue getting home (my original flight out of Tucson was cancelled, and I had to drive to Phoenix to catch a flight to Las Angeles to get back to Cincinnati), but the trip was still really cool.  After all, it’s not the travel that makes this job exciting, it’s meeting all the new, smart, interesting people along the way.

     

    Again, thank you to Telerik for providing the travel, sponsoring the meetings, and allowing me to speak to the community as a core part of my job.  It just reinforces their dedication to meeting with the developers of the .NET ecosystem and supporting all of the community initiatives that make us stronger as a community.

    Happy coding!

  1. 1
  2. 2
  3. 3
  4. 4
  5. »