c o d i n g f r o g s

croaking about programming, programming languages, software engineering, and the business of software

8Apr/110

Partial Baskets Are Still Worth 0 Points

In the 2010-2011 NCAA basketball season, Butler University built atop an improbably successful basketball season the previous year by repeating their run to the NCAA title game.  There was a lot of hype leading into the game.  Could mid-sized Butler really topple a mighty basketball powerhouse like UConn and win a national championship?

Butler came into the game full of quiet confidence, but for whatever reason they were never able to find a shooting rhythm like they'd had in previous games.  In the biggest game of the year they managed to make only a pitiful 18.75% of their shots from the field.  They fought hard, executed their offense and played excellent defense, but were not able to overcome such woeful shooting numbers.  UConn won the title, and Butler got to head home, in the words of Jerry Seinfeld, as "the best loser."

It's not my intent to pick on Butler — I often cheer for the underdog so I was hoping they would win.  My heart broke for them as they continued to try in vain.  The point is to drive home the title of this post:  Partial baskets are still worth 0 points.  Butler had so many partial baskets, shots that nearly went in, that they may have won the game if those counted for something.  Unfortunately, a partial basket is worth the same as a turnover:  Nothing.

It's funny how obvious this is in sports, but when it comes to business we pretend like it doesn't apply.

Let's suppose you are working on a software product, and you have exactly one primary competitor.  You both ship your next release at the same time.  Your competitor's product has 10 key features that customers want.  Your product has 8 of those same features.  You also know you were working on the other two features, plus five others, but those seven features did not get into the product.

Imagine your sales rep going into one of your big customer accounts:

Sales Rep:  "Check out the new version of our product.  It has 8 new features that are important to you!"

Customer:  "Yes, but your competitor's product has those features plus two others.  Why should I choose your product instead of theirs?"

Sales Rep:  "That may be true, but we almost completed those two features, plus five others!  We have seven other features almost in the product!"

Of course, the customer doesn't care about those other partially completed features.  Partial baskets are still worth 0 points.  So if the customer doesn't care about partially completed features, why do you?

Why do you track and report a "percentage complete" metric for your tasks?  Why do you go into a status meeting and report that your project is 50% done?  You cannot sell a feature, or a project, or a task that is less than 100% complete, so why do you measure for it?

One of my most prized learnings from Peter Drucker's "Management" book was this basic principle:  Performance measurement should be focused on measuring things that matter to the customer.  That's why I try to stay away from recognizing partial completion, and why you should too.

Organizations that can focus around this line of thinking will find that they become more in tune with their customers because they are continually thinking about their offering from the customer's point of view.  Thinking about a feature as 80% complete is thinking about it from the individual contributor's point of view.  On a 10-week project, the individual contributor has done 8 weeks of work so they are 80% complete.  They want those 8 weeks to matter; of course they do.  But those 8 weeks don't matter to your customer unless the other two weeks of work are also complete and the project is actually finished and shipped.  Customers don't care about partial completion; they think in binary, even if they don't understand it.  Complete.  Not complete.  Those are the only two states that matter to a customer.

Those are the only two states that should matter to you, too.

21Oct/100

How To Ruin Your Own Vacation

You know the feeling.  The feeling you get as you are heading home from work on the last day before your vacation.  That feeling of the weight and stress and pressure of delivering excellent software on time just floating away off your shoulders.  Nothing to look forward to for the next two weeks but fun and relaxation.

Right?

Or are you worried you are going to get a call?

It's the nature of the beast.  We plan to escape, but sometimes that call just can't be avoided.

Sometimes it can, though.  Sometimes you get called because you did something boneheaded, something you could have avoided that would have made your vacation more like, uh, a real vacation.

Some time ago I was working through a bug that was assigned to me at work.  After a bit of digging, I realized the bug was being caused because two methods in a related class had recently been deleted.  Putting those methods back in the class would fix my bug, but was that the right thing to do?

I assumed not.  I work with smart people, so I assumed that there was a good reason for removing those methods.  So I dug into the source code control system to determine which checkin had removed those methods, who had performed the checkin, and why.

I found the commit in question, noticed who had done it, and looked into the commit notes.  Here's essentially what I saw:

Description of problem:  Code was broken.  Description of fix:  Solved problem.

Meat Loaf says "two out of three ain't bad," but that doesn't apply in this case.  Note that our checkin system automatically adds the "Description of problem" and "Description of fix" tags so the commit notes weren't nearly so verbose as it appears.

Obviously this was of no help to me in determining why the change was made, and without a reference to a bug database record I couldn't look up the bug to find out about it either.  So even though the developer in question was on vacation that day, I had to call him:  I couldn't wait for him to get back for the answer.

So, there you have it:  One way to ruin your own vacation is to avoid taking any time at all to provide useful commit notes.

Notice that even typing the notes that were put into this commit was an utter waste of time.  I don't know about you, but I don't make a habit of checking in fixes to code that isn't broken.  So the statement "Code was broken" is a statement of the obvious.  Of course the code is broken; why else would you be checking in a fix?  Saying the code was broken is redundant and unnecessary.  Likewise for "Solved problem"; why would you be checking in if you didn't solve the problem?

The single most effective change that could be made here would be to simply reference the bug database record.  Even if the problem description were simply changed to say "Bug #3165150" that would be enough.  Annoying, but enough.  With that I could at least look up the bug in the bug database and maybe figure out why the change was required.  But seriously, how long does it really take to add a few notes about what changed and, more importantly, why?

I've also seen commit notes like this:

- removed GetLastWidgetStatus() method

- modified signature for UpdateWidget()

- added null check to SyncWidget()

Gosh, really?  You needed to tell me that?  I thought that's what diff tools were for.

Here's my suggestion for creating Awesome and Useful commit notes:

  • Include a description of the problem.  Use the title from the bug record as a guideline.  You might want to be a little more verbose, but often it isn't necessary, as long as you...
  • Include a reference to the bug record.  A clickable link is best, if possible; if not, at least a record ID so the bug can easily be found.
    • At this point some of you may be saying, "What if there is no associated bug record?"  In that case, the answer is, "WHY ON EARTH ARE YOU DOING WORK WITHOUT AN ASSOCIATED BUG RECORD?!?"
      • I mean, seriously.  If for no other reason, you need a record so your boss knows what you are doing!
    • Horrible Example:  "Code was broken."
    • Bad Example:  "WidgetManager class not working."
    • Good Example"  "WidgetManager not correctly updating widgets on DisplayChanged event; see bug #5150316."
  • Include a description of why you made the changes you made, not just THAT you made changes or a simple enumeration of the changes.
    • Horrible Example:  "Fixed code."
    • Bad Example:  "removed GetLastWidgetStatus(), modified signature for UpdateWidget(), added null check to SyncWidget()"
    • Good Example:  "The UpdateWidget() method had no knowledge of the event causing the call so it wasn't handling the DisplayChanged event properly; I added a parameter to UpdateWidget() to provide this information which allows us to handle the event correctly.  Also added a null check to SyncWidget() which would have caught the bug.  Removed GetLastWidgetStatus(); nobody is calling it anymore."

See?  That's not so bad.  Just a few minutes out of your life to show your love and caring to your team members when you are gone.  Just a few minutes out of your life so you can really enjoy that vacation without worrying whether the phone is going to ring.

13Feb/100

Trusting Teams

We all know how it feels to be trusted.  That's a big part of our profession as software engineers.  Our job is not just to solve a problem, but to do it in a way that is highly performant, easily maintained, efficient, extensible, secure, resilient, and correct.  We have to understand what customers need, not what they say they need.  And before we even solve the problem, we have to estimate how long it will take us to solve it, and make and keep commitments for when we will deliver.

It is a tough job, but we're pretty good at it.  Like Michael Jordan in the NBA Finals, we know we can step up and perform.  We enjoy that feeling of coming through and delivering.

Because we are good at what we do, we like feeling like our employers trust us.  We don't want to work for employers that don't.  It bugs us when our boss tries to tell us how to do our job or doesn't believe us when we declare that we will be done on time.  The satisfaction that comes from keeping your word is diminished if someone is breathing down your neck every step of the way.

This is what true delegation is about, and I'm a big fan.  I'm a Covey disciple and not afraid to admit it.  In fact, when I once interviewed for a job, I was pushed on the concept of delegation, and I declared, "Why do they work for you if you don't believe they will do what they say they will do?"  There's a great amount of job satisfaction that comes from filling a stewardship that is truly yours.

The problem is, it isn't quite like that in teams — at least, not good ones.

We had a rather interesting team status meeting this past week at UDC.  I won't go into details, but as I thought about it over the rest of the week, I could see a clear issue near the heart:  People not feeling trusted in their stewardships.

After thinking about this a lot, discussing it with team members, and re-reading "The Five Dysfunctions of a Team" by Patrick Lencioni, I hit upon a bit of an epiphony for myself that helped me understand the issue better.

The most basic team dysfunction he identifies is an absence of trust.  Toward the end of Lencioni's book, he explains this further:

In the context of building a team, trust is the confidence among team members that their peers' intentions are good, and that there is no reason to be protective or careful around the group.  In essence, teammates must get comfortable being vulnerable with one another.  This description stands in contrast to a more standard definition of trust, one that centers around the ability to predict a person's behavior based on past experience.... As desirable as this may be, it is not enough to represent the kind of trust that is characteristic of a great team.  It requires team members to make themselves vulnerable to one another, and be confident that their respective vulnerabilities will not be used against them.

Upon reading this, I realized instantly how this related to our team.

Suppose you are the lead of a team of six engineers.  Your team is working in a one-month milestone, and you've got about six person-months of work to be done in that milestone.  How do you go about getting it done?

Well, you could try running the whole show by yourself.  After all, you are the lead.  So you could go among the team members all day long, telling them what to do.  You could tell them what class hierarchy to use, what data structure to use, what design pattern to use.  You could critique their naming conventions or even tell them what character to type when.

You might make your milestone, if those engineers are still working with you at the end of a month.  But even if they stay, you've lost the opportunity to get them to buy in.

Of course, we all know that strategy is flawed, so you try delegating instead.  You trust your team.  If they say they will do it, they will.  So you give them each assignments, or you let them choose their assignments.  They each have their own area of stewardship, and they each commit to be done at the end of the milestone.  So, I guess you can just go golfing for the rest of the month, right?  Then come back at the end of the month and everything should be done.

They said they would be done, so they'll be done, right?  That's what it means to trust.  Unless something came up, of course.  But even if they all did make it, they missed out on a great opportunity:  The opportunity to be a team.

See, teams do trust each other.  They rely on each other and believe in each other.  But they work together anyway.  They meet together.  They hold each other accountable.  They win and lose together.

In the previous scenario, if five of your six engineers had completed their work, does that mean success or failure?  Does that mean you were 83% successful?  Do you just round up and say you were generally on target?

Great teams don't do that.  They succeed and fail together.  In a great team, five out of six people being successful is a failure on two fronts.  First, they failed because they didn't accomplish the team goal.  Second, they failed to pull together as a team.

So let's go back a month.  How does that team pull together?

The team has to care about each member.  It has to hold itself accountable for a common goal, and commit to win together or not at all.  Because of this, the team must ask each other hard questions.

When this happens to you, as a member of that team, you might feel like you aren't being trusted.  This is when you have to do what Lencioni suggests:  You have to trust your team enough that they can ask.  You have to trust them enough that you believe they have the right intentions at heart.  You have to trust that when they dig on you and question you, they won't hold it against you if they find a flaw in you.  You have to trust that when you question them, they won't take it personally either.

The questioning is part of the deal if you want people who are passionate and care and want to win.  What do you do when someone you care about comes home?  You ask them questions.  You ask about their day, who they saw, how things went, what they learned, how did their presentation go, etc.

You don't ask these questions because you don't trust them (er, usually, anyway).  You ask because you care.  Asking questions is how we express interest, concern, and buy-in.

When you work for a company that cares, questions are part of the deal.  Microsoft cares.  We are passionate about technology.  We want to win.  We want our teams to win.  We want to create great products and delight customers.  Everyone in my management chain has this passion.  So, I can expect this kind of questioning from everyone in my management chain.

I've worked for other companies that don't have this passion.  It shows because nobody asks, about anything.

The same holds true for teams.  Teams ask each other.  They are honest with each other.  They are open with each other.  They rely and depend upon each other.  And they win and lose together.

I've been on teams like this.  They are AWESOME.  As great as it feels individually to fulfill a stewardship, it feels even better to be a part of a team that works together and helps each other and wins.  The cost of entry?  Humility.  Vulnerability.  You have to be willing to let your team ask you about your approach and technique and decisions, and be willing to let them dig and dig.  They do this because, like you, they want to win.  They want to win WITH you, not OVER you.  And they depend on you to question them so you can win with them also.

When your team does this, when you really trust each other and open up to each other, you'll find weaknesses, problems, and concerns.  Each time you do this, it is an opportunity to pull together as a team and win together.  Your strengths compensate for my weaknesses.  Instead of six people individually trying to deliver six distinct units of work of about one person-month of effort each, you have six people working together to deliver six person-months of work.  My weakness may have been my downfall when I worked alone, but now that we work together your strength can compensate for my weakness, and mine can compensate for yours.  We can do more together.

Kum-ba-yah.  Even though I believe this, I think I'm going to be sick with all this syrupy feel-goodness if I don't stop soon.  But that doesn't mean it isn't real.  Be passionate enough about success as a team that you are willing to learn from each other and challenge each other to grow together.  Care enough about your team to respectfully question your teammates, and trust that they care about the team when they question you.  If you do this, you'll find that working on that kind of a team is an experience you'll remember your whole career.

5Jan/100

Fudging Complete

Are you guilty of this?

If you have kids, I bet they do it.  You tell one of your kids to mow the lawn or do the dishes.  After a while you see them playing XBox or watching TV.  You ask, "Did you mow the lawn/finish the dishes?"  "Yeah, I'm done," they claim.  Then you go to check out the handiwork, only to find that there's a good 100 square feet of lawn that simply got skipped, or that all the dirty pots are still sitting on the countertop.

Don't get so high and mighty:  You probably did it when you were a kid, too.

Apparently, as we grow up, we change.  Some people don't, I guess.  Some people continue to knowingly lie about this stuff even as adults (e.g., presidents of the USA).  But most of us change a bit.  Perhaps we don't like getting caught.  Or we don't like the idea that we failed to do something we said we'd do.

The problem is, even though most of us change, it doesn't mean we are all delivering what we committed to.

If you've been given a task, completing the task means completing the work pertaining to that task.  All of it.  Not "the bulk" of it, or "the majority" of it, or "everything except a few odds and ends."  It means the whole thing.

That's what Fudging Complete is.  It's when, either because you are afraid of the consequences of not finishing, or because you don't like to admit failure, or because you don't want to lie, you try to convey a sense of "complete" when you aren't really complete.  You redefine "done" to mean "mostly done".  Or you change the definition of the task so that it matches the work that has been done, even though now the task doesn't match its intended purpose.

It's when you knowingly check in code that hasn't been fully tested in order to meet your feature complete date.  You know the feature isn't actually done, because you haven't completely tested it.  Or maybe you've done some preliminary testing on it, but you haven't written your unit tests.  You know if you do what you should, you will miss the date, and that looks bad.  So instead you can make your date by checking in today.  You are knowingly incurring test debt, but at least you made your date.  But you aren't really complete.

It's when you are at the end of a sprint and you take a look at the committed items, and notice that all but one of the committed items are done, and report your sprint status as having met your commitments anyway.  In the footnotes you make note of the fact that the sprint is complete, except for one or two small tasks that didn't get finished, but other than that the sprint is complete.  But you aren't really complete.

If you do this, you are Fudging Complete.  You are like the movie rated PG-13 for "partial nudity."  What does it mean to be partially nude?  You are either nude or you aren't!  A movie either has nudity in it or it doesn't.

Of course, "partial nudity" technically makes sense and is in fact quite common.  I am partially nude as I type this post:  My forearms are fully exposed.  But the term doesn't really mean what it implies.  Saying a movie contains "partial nudity" is simply one person's way of trying to deceive you about what is really in the movie.  It doesn't have nudity!  It only has partial nudity!

Fudging Complete has the same effect.  Telling your manager that your project is complete, except for one or two loose ends, conveys the wrong sense to your manager.  It is technically possible to be partially complete, but saying it doesn't convey the right message.  It tries to convince your manager that you are complete, and you aren't.

When we do our work, we need to approach it the way a basketball player approaches shooting a basket.  When you're playing basketball, whether you will take the shot depends on a number of things:  Whether you actually have the ball, whether you are near enough to your basket that you think you can make the shot, whether anyone on your team is open closer to the basket, whether you are open to take the shot, etc.  However, you know as you shoot the shot that there's a chance you will miss.  Missing the shot is no big deal; every basketball player misses shots.  If you miss, it is not that big of a deal.  You quickly regroup and get ready for your next opportunity to shoot.

Working on software projects needs to be like this.  It is okay to miss.  Everyone misses.  Sometimes software engineers are afraid to fail, so I don't call it "failing" — I call it "missing."  If you miss, learn from your mistake and do better next time.

What you shouldn't do, however, is be dishonest about missing.  Everyone misses.  You are not perfect.  Good teams and companies and managers know you will miss and will appreciate you being frank with them about what happened, instead of trying to redefine what completion means to make yourself look good.  Don't do that.  Don't fudge complete.