“We” is a Good Way to Get Nothing Done

IMG_3800I've noticed through the years that lots of people shoot themselves in the foot over and over again, and they never realize that they're doing it. It's the simplest thing in the world, yet it seems to constantly evade even seasoned managers. Paradoxically, it even seems to be a great way to reach out to people, empowering them to do great things, yet, it'll kill you every time.

So, what's the problem? Simple. If you make more than one person responsible for something, it's only by the greatest miracle that it'll get done at all. Doesn't seem to make sense, does it? After all, adding people to a task should make it move more quickly. Adding brains to a problem should boost creativity. Why does this break down? In short, if more than one person is responsible for a task, then nobody is responsible.

Here's what I'm talking about. If you've ever been in a meeting -- a hallway meeting or a board meeting -- and heard someone say, "I thought you were doing that!", then you've seen this phenomenon in action. As soon as there's any ambiguity about whose head is going to roll if there's a problem, you invite more problems. This isn't necessarily because people aren't trying hard, though this does provide a convenient avenue for scapegoating. No, it's really a problem of communicating and personal integrity, and thus, it scales up exponentially as the number of "responsible" parties grows.

Let's walk through an example. Let's say you're chairing a committee of peers, and you ask them collectively to achieve some objectives, you're very likely to see one or more of the following scenarios play out:

  • The committee members sit down and rationally divide the work, then each goes off and completes the work as intended. Riiiigghhttt..... While this does sometimes happen just like that, it's only when all three of the people are responsible, reliable, and free from political motivation. It can happen, but you can't rely on it in the average organization.
  • One member steps up and takes responsibility for the group. He monitors the division of work, and he checks to make sure that things get done. This is essentially a project manager role for that group of tasks. Note that since this is an informal organization, you still need the cooperation of the other members. Any one of them can intentionally or unintentionally torpedo his individual task, putting the whole project at risk
  • Political infighting erupts over division of work, credit for success, blame for failure, and so on. This might seem very likely, but I've rarely seen it, since this sort of bickering draws negative attention in a hurry.
  • Nothing gets done. Variations on this theme would be very little gets done, or something gets done very, very late, or something gets done that has no significant resemblance to the intended objective. This scenario is quite common, because it's the easiest, and the responsibility structure allows any of the users to "opt out" of the work, and then re-surface to point fingers when questions arise.

All of this sounds pretty pessimistic, as if I expect everybody in any given business environment to be lazy, politically-motivated, ruthless back-stabbers. This isn't the case, though I've certainly seen it to be true from time to time. No, in most cases, these are dedicated, honest, hard-working co-workers who are simply trying to do their jobs to the best of their abilities. The best and most successful of these people will, by nature, be the busiest. No good deed goes unpunished, after all. These busy people probably won't have time for anything else. In fact, if you ask them directly to do something for you, there's a good chance they'll tell you that they're too busy.

If you ask them as part of a group to collectively do something together, however, there's a good chance they won't tell you that they're too busy because they assume that someone else is going to pick up that task. And therein lies the rub. Asking a group of people to do something allows the no-goods to squirm out of responsibility on purpose, and it allows the go-getters to wrongly believe that someone else is going to step up to the plate and do the right thing. Either way, there's a good chance that they ball is going to get dropped.

So be direct. It's not rude or imposing - it's the only way to get something done. Make sure that when a task is given, it's given to one responsible person (even if other people are asked to "help"). Make sure that person realizes that an assignment happened. And then follow up to make sure it's done.

It sounds simple, but you'll be amazed how infrequently it happens when you start looking for it.

Bug Tracking 101: Where TFS Blows It

As a developer, I love Microsoft Team Foundation Server. As a manager, I hate it.

Why? Bug tracking.

"But TFS does bug tracking," you say. Sure it does. So let me try to explain why Microsoft's brand of bug tracking just isn't going to get the job done. I'll start with my personal opinions about bug tracking.

Bug tracking is one of the basic life-support functions in software development. I'd rank it second after Source Code Control as far as critical support functions. To put it bluntly, there's just no reason not to have a bug tracking system these days. There are hundreds of very good systems out there, and you can get most of them free in a box of breakfast cereal.

It's pretty common, in my experience, for people to argue against logging bugs. There's a perception that logging a bug is a big, hairy deal, or maybe they want to keep the count low in their "real" bug database so their numbers look good. Bull-pucky, I say. Log everything. If a bug occurs and it doesn't get recorded, it never happened.

Sure, you're going to get some bad bugs. You're going to get some duplicates. You're going to get some bugs you can't reproduce.

So what?

If you log a bug and have to close it because it's a bad bug, you spend some time doing so. Bug if you don't log a bug, you can never reverse that decision. In fairness, you'll usually want to have *something* in a report that's actionable, but I really prefer to set the bar low so I sweep more bugs into the net. I can far more easily wipe out the bad than I can make up for lack of data if there's something going on that I'm not seeing.

You may have inferred by this point that I prefer to let most, if not all users and testers enter bugs. Right on. Again, this is to help gather information as close to the source as possible. And yes, again, this increases the chance for junk data. And yes, yet again, the alternative is no data. If you make it easy for lots of people to give you feedback, some of them will give you feedback. If you make it difficult, damned few will give you any at all. You're in the dark -- probably with a false sense of confidence about the state of your system. "Look - no bugs logged in the last week! We're perfect!" Sure, you are.

Ok, so that's how I feel about bugs. Feel free to argue amongst yourself, or even with me. 😉

Back to TFS. Like I said, they have a bug tracker, so what's the problem? Not a thing, if you happen to be a developer with TFS already running as part of your IDE. If you're not a developer, here's what you've got to do to use TFS:

  • Buy a license. Yes, if you want to log a bug, you need a full TFS client license. Just to log a bug. JUST TO LOG A BUG.
  • Since you have to buy a license, you're probably going to need to justify that license to somebody (not that I've run into that brick wall recently, or anything....). Quick review: you're going to be asked to make a business case for purchasing a client license for someone so they can LOG A BUG!! Let me know how that goes for you, ok?
  • Now you need to get Team Explorer installed on the workstation of the person who's supposed to log the bug. Oh, no -- you can't just browse to a web page to do this (despite the fact that TFS makes heavy use of SharePoint). Is any of this making sense to you? Astute readers will observe at this point that there are add-on software components available to web-enable TFS. I'll observe right back at you that the very fact that this is an add-on tells you something about whether Microsoft gets how this software should be used.
  • Now, your user is ready to log a bug. After they open Team Explorer. On the machine where it's installed. Oh, they're at a different machine now? Maybe they're testing on a Mac? Nuts. Well, write everything down and log it when you get back to your desk. Poof! Your bug just disappeared, because 99 out of 100 users are just going to say, "why bother?" And they'd be right, of course.

Come on, Microsoft -- think this through and get it fixed. Now. Please.

In the mean time, use this.

Translators are a pain! Use Reflection to make them easier.

I'm working with a SOA architecture that's forcing me to bend, fold, spindle, and mutilate objects as they move across tiers. This is awkward, but it's a common side-effect of splitting applications across tiers. One of the implications of this design is that objects have to be translated, or copied value by value across tiers.

This work is pretty straightforward, but it's tedious, and worse, it doesn't add any value to the software -- it's just plumbing. Boy, I thought, wouldn't it be nice to be able to hook two equivalent objects up and move values from one to the other automatically.

Enter reflection. Now, before I show the goodies, you'll want to be careful where you use this. Reflection isn't as efficient as writing early-bound code, but when used sparingly, it can haul a lot of groceries with very little code. If nothing else, use this as a quick primer on reflection. It's not as hard as many people think, and it's a great technique to have in your toolbox.

Here's the code. If I were to enhance it, I might have it raise an event when it comes across a property it can't match, so a consumer could handle custom maps in-line. I think it would also be great to use this as the basis for a Visual Studio addin to manufacture early-bound code for translation - sort of like the translator wizard in the Web Services Factory, but a little more automatic. Have fun with it...

public class Translator
    {
        /// <summary>
        /// Use reflection to copy as many properties from the "from" object
        /// to the "to" object as possible, matching properties by name.
        /// </summary>
        /// <param name="objFrom">Copy from object</param>
        /// <param name="objTo">Copy to object</param>
        public static void Translate(object objFrom, object objTo)
        {
            Type tFrom = objFrom.GetType();
            Type tTo = objTo.GetType();

            //Get the properties of our type
            PropertyInfo[] fromProps = tFrom.GetProperties();

            foreach (PropertyInfo pInfo in fromProps)
            {
                try
                {
                    object[] fromValue = new object[1];
                    fromValue[0] = tFrom.InvokeMember(pInfo.Name, BindingFlags.GetProperty, null, objFrom, null);
                    tTo.InvokeMember(pInfo.Name, BindingFlags.SetProperty, null, objTo, fromValue);
                }
                catch (Exception ex) { }
            }
        }
    }

Mouse Balls

My current client is insistent that my team use their equipment while we're working on their software. I can't say I really agree with this, but I can understand the spirit of the request. More difficult to understand, however, is why they'd persist in this direction despite the fact that the hardware isn't up to the job. Processor speed is fair, but there's not enough RAM, and I think we'd have to have a personal memo from the governor to get a second monitor.

But the thing that's driving me absolutely batty is my mouse. Yes, it's an old-style mechanical mouse, complete with the rubber marble that turns the little rollers inside. The moving parts pick up junk and start to fail, and no amount of cleaning makes it quite right again. Every day, I end up taking the thing apart a couple times, to very little effect, and every day, I silently boil every time I move my mouse and the cursor just sits where it was, blinking in silent mockery of me and my defective hardware.

Yes, I've tried to obtain a new mouse. Paperwork has been obtained, filled out, and signed. As of my last trip up that mountain, I hadn't yet achieved enough signatures to move this $12 transaction forward. Yes, the time I've spent on paperwork and signatures exceeds (easily) the cost of a new mouse. Yes, I could probably go out and buy a damned mouse myself and bring it in. I very well may end up doing that the next time I order from Newegg or Amazon.

In the mean time, I have to marvel at this brilliant example of process gone astray...while I clean my mouse.

A Special Kind of Crazy

The franken-systems we often find ourselves immersed in are a product of a hundred bad decisions, compounded like interest until they yield a wealth of dysfunction. Such is the case in this example.

First, some background. I'm working on a system to do some event scheduling. At the beginning of the project, my team learned that we'd also be implementing a web service for a name and address system, since we needed some of that data, and the client kind of wanted a web service for that other system anyway. We could take as much time to build it as we needed, up to two weeks. A couple other guys on the team built this web service under the direction of a designer. This train of thought contains several bad decisions, for those keeping score at home.

Fast-forward to today. I'm working on updating address information in the scheduling system. What should have been a pretty simple effort had proven ridiculously difficult. The root of the current set of problems is the design of the aforementioned web service. Specifically, I'm beating my head on the wall over the state and county components of the address.

These are not, in fact, textual representations of the state and county, respectively. They're objects. Now, don't get me wrong - I'm a big fan of objects, and I can appreciate the elegance of a wide and deep hierarchy. It's a great way to explore a problem domain you may not be familiar with. Invoices have headers and detail lines, and a detail line has an item and a quantity and a description, right?

But is that really what you need for a state?

Let me run through some of the places where the choice of an object for the state has caused problems.

  • ASP.Net DataGrid data binding. It turns out that the DataGrid doesn't handle complex objects well, so it just couldn't cope with State as a whole object within an Address. There are multiple workarounds for this, of course, including replacing the grid, I'd expect. The direction I went on this was to craft a UIAddress object that flattened an Address the way I needed it. This resulted in extra code - not just to define the object, but to translate to and from the new, different address forms, but it worked for the UI.
  • Updates. It turns out that when you update the state value for an address, not only do you need to reach down in to the object (address.State.StateAbbreviation) -- no, that's not quite enough. Try to update that, and you'll get an error -- a key violation error -- because you haven't set the StateID to a valid value. That's right. You can't set an address to a different state unless you happen to know the database key of that state. Upon further examination, this made a bit more sense to me. After all, if we happen to grant statehood to Puerto Rico or maybe annex Canada or something, and we choose to abbreviate Puerto Rico as
    "TX" or "AB", well, then, we'd just have a mess on our hands, wouldn't we? So you can't just send in the state abbreviation -- that won't work at all. Sigh.
  • New objects. You can't just create a new Address() now. If you do that, you won't have initialized the corresponding State and County objects. Again, not the end of the world, but it's just a little bit more code you have to write whenever you use these objects.

The moral of this story is clear - consider the users of your APIs before they show up at the gates with pitchforks and torches.

When Tools let us Down

This afternoon, I was building a new class. I had a handful of data items I knew I needed, so I made fields for them, and then began constructing properties to encapsulate the fields. This is a well-known best practice, of course, because it lets you protect your internal representation of this data, and to therefore insulate consumers of your class from any changes in this underlying data.

Needless to say, setting up a property get...set block is slightly more time-consuming than just creating a field and being done with it. Along comes the Visual Studio C# refactoring tools to help encourage the proper behavior. Just right-click on your field, choose "Refactor...." --> "Encapsulate Field", and you can create the getter and setter in one swift action.

Except that this dialog takes longer to load (at least on this client's system) than it would take to type out the damned block to begin with. Thanks for the gesture, though.

In this case, the problem seems to be that the tool is solving a larger problem than I've got right now. It's able to seek out existing code that's already referencing this field and repair the effects of any name changes you make.

Ok, that's cool. But I don't need that right now. This is a brand-new class -- there are no references to these fields yet. But someone might need this, and I concede the fact that if I found myself needing functionality like this, I'd scream just as loudly if it was taken away from me.

So is there a better solution? I think so -- two, in fact, in this case, or maybe even three.

The first improvement I'd consider is to not spend time hooking up the "search all references" stuff unless I said I needed it.

In my case, though, there's an even better solution. The fields I was trying to encapsulate were already marked "private", which means that they can't be referenced outside the current class. That should simplify matters considerably.

Oh, and the third improvement, for extra credit, would be to multi-thread this dialog so I can run the simple functionality even if the advanced stuff is still loading.

Usability is everywhere.

George S. Patton on Refactoring

"The time to take counsel of your fears is before you make an important battle decision. That's the time to listen to every fear you can imagine! When you have collected all the facts and fears and made your decision, turn off all your fears and go ahead."

-- George Patton

I know, I know -- what in the world did Patton know about refactoring?

Nothing. But he knew a hell of a lot about getting things done. He knew that there is a time for planning and a time for acting, and he knew that if you prepared when it was time to prepare, you should feel confident in your actions because you've done your homework ahead of time. Had he lived to witness Agile development, he would have had the following advice about refactoring:

Preparation

Patton knew that no battle was ever won without proper preparation. For him, that meant training, discipline, and strategic planning. We could learn a few things from him.

  • Training. It's important to know the technology you're working with. This shouldn't be a news flash, but you won't be effective unless you are fluent in the development language and architecture in use. Please also be comfortable with development best practices such as those from McConnell.
  • Version Control. This had better be another no-brainer. In fact, if you don't have your code in an SCC system, give up now and go into sales. You're not going to make it in software development.
  • Unit tests. Make sure you have them, and make sure they're really exercising the system. It's sometimes difficult to hit 100% code coverage, but if you're not at 80% or better, you're not trying very hard, and you're badly exposed to regression bugs. You'll deserve whatever sad fate awaits you.
  • Objective. Patton knew the value of planning. In this case, you need to clearly understand what you're trying to accomplish with your refactoring. Maybe there's a pattern that isn't being followed consistently. Maybe there's functionality that should be extracted into an object or component. Whatever - just make sure you know exactly what you're trying to get done. When you start to work, you'll find it easy to be distracted - there's always something else to fix or improve. While Patton also understood the value of tactical flexibility, losing sight of your objective is the best way to ensure that you'll fail.

Refactoring

Now you're ready to work, so crank up the chain saw. Now is not the time to be timid - you've planned for this, so make it happen. While you're in there,

  • Don't leave dead code -- commented dead code is useless. It's available in SCC if you need it. You don't buy a book and expect to see all the edits. Outtakes can be funny, but not in the middle of the movie. You want your live code to be living -- not a monument to your past sins. You already decided that your old code needed to be refactored, so don't chicken out now. An agile methodology thrives on having frequent builds that are as near to production-ready as possible. You wouldn't want to ship with dead code in your project, so get rid of it.
  • Don't half-refactor. You're probably going to want to try to reach some interim stable points where you can build and run some unit tests, but beyond that, try not to stop until you're done. When you are refactoring, this is your chance to apply a consistent thought process, design, and coding style across the project. Future developers will thank you if you manage not to leave a Frankenstein-style mishmash of source code.
  • Keep notes. If you find additional areas that need work, make a note somewhere where you'll follow up.
  • Test. You need to see clean unit tests before you're done. Remember, commenting the test out doesn't count. If you can, run through some UI-level or System testing, too.

As always, scale the process to match the task - small refactoring jobs move through planning and refactoring in seconds, but large efforts can take considerable time. Remember, though, that source code control is never optional, and if you skip unit tests, you're really asking for trouble.

What other refactoring tips do you have?

BT builds Etch-a-Sketch UMPC for Dilbert’s boss

Just about everyone has seen the famous Dilbert strip where Dilbert reminds his boss to turn his laptop over and shake it to reboot. As the PHB is walking away, Dilbert asks his co-workers if they think he'll ever figure out that they gave him an etch-a-sketch.

Well, I just about fell out of my chair when I saw this one, but Engadget is reporting that BT has finally built the famous etch-a-sketch computer. I have no idea how they could resist the urge to release the first picture without a Adams' famous strip on the screen!

Bugs should not be logged?

Here's a fun one. I came across an article explaining why bugs should not be tracked via a post on Joel on Software. As I read the article, I oscillated between outrage and amusement. Could this guy really be serious?

I considered the possibility that Mr. Thorup just wasn't experienced in software development, and then I thought that perhaps he was being intentionally outlandish in order to make a point. I'm leaning toward the latter.

No matter. Let's take his idea at face value and examine it.

To summarize the article, Lars suggests that the ability to log a bug breeds a casual attitude toward these bugs. Log it and forget it. Out of sight, out of mind. Better to deal with the little beastie right now, or if now isn't doable, then at least keep the bug somewhere close-at-hand. A post-it on your monitor. A bug report in a database, says Lars, adds no value to your software. It's unnecessary overhead, and it not only can be eliminated, it should be eliminated.

Fair enough, and all things considered, a pretty healthy attitude towards software development. After all, I've long been a proponent of using only as much process as is needed for the task at hand. So why am I not beaming with excitement at the prospect of ditching my bug database?

Simple. Two reasons: workflow and usability.

Workflow should be pretty easy to understand. It's really difficult for one guy with a fist-full of post-it notes to scale a bug tracking process up to deal with more than a small workgroup. Throw in a remote tester / user / developer / manager, and you're cooked. Simply put, the larger your project, the more people are going to be involved in the process. There are guaranteed to be cases where the person who's reporting the bug isn't the person who needs to fix it. In fact, the person who's reporting the bug may not even know who's supposed to fix it. This implies workflow, and that isn't satisfied well with post-its.

Of course, the post-it that falls off the wall of shame and behind the desk will kill you, too.

But what does usability have to do with tracking bugs? Besides the really clever segue from my last post, the way you handle bug reports has a very real usability factor for your users and testers, and your developers, too. Again, for small shops and small projects, I can see the value of hollering, "got another one!", and then slapping another yellow square on the wall.

Lars suggests that the optimum approach is to fix the bug as soon as it's seen. Great -- as long as the bug I see is my own, and and long as the fix can happen quickly without tearing me off of whatever I was working on when I found the bug. If I find a bug in an area of the code I'm not familiar with, or if the fix for the bug is going to turn into a non-trivial refactoring effort, I really have to question whether you want your developers dropping everything to play exterminator.

How about when users or testers find bugs? Every developer fights a constant battle to get "into the zone" -- it takes time to get your head into a design or coding task, and interruptions cause a loss of productivity entirely out of proportion to the time apparently taken by the interruption. This is the premise behind point #8 in Joel Spolsky's 12 Steps to Better Code -- be sure that developers have quiet working conditions. If you have testers and users running up to developers every time they think they've found a bug, the developers quite literally won't get anything done.

Say "yes" to frequent interaction, but say "no" to real-time interruptions.

This, by the way, is the same reason that computer architectures make use of asynchronous channels like message queues. It is far more scalable and efficient to let multiple subsystems operate with a little buffer between them, lest all of the component parts get hung up waiting on one another.

A bug database can also be more user-friendly to someone reporting a bug. Consider what would happen if you made every tester and user run a gauntlet before you accepted a bug report. Is this bug already logged? Is it reproducible? On our system, too? Is this bug *really* important enough to work right now? Don't you think we should walk around to see the other stakeholders to see if they agree that we should make this change right now?

Never mind.

Your goal when tracking bugs is not to collect the smallest number of bugs. In fact, if your bug reporting mechanism is working well, you'll probably get a ton of feature requests and product suggestions via bug reports. Don't flog these users for improper use of the bug system. Thank them for their feedback. It's far easier to categorize bug reports into feature requests than it is to guess what your users are thinking.

Make bug reporting as easy as possible for testers and users. The closer the testers are to your team, the more you want to work with them to educate them on what makes a good bug report, because that will save everyone a ton of time, but for the beta testers, non-technical testers, or users, just take whatever they'll give you. The alternative, in many cases, is to just not learn about their experiences, and you can't recover that lost data.

To log or not to log? No contest -- you won't catch me without a bug database any more than you'll catch me without source code control. It's just not going to happen.

You call this usability? ‘Cause I don’t!

So, how useless is this?? If you’ve got an email without any formatting in it, you don't need print preview very badly, do you? I mean, how hard is it, exactly, to figure out what it’s going to look like when it’s printed? When your email is formatted, on the other hand, you're up a creek. Nice.

I'm pretty sure that Lewis Black would be able to come up with something far more colorful to say about the bozo's who punted on this feature, but it might not be printable for polite company. Still, this is a pretty lame cop out.

This is a classic case of a user interface usability problem. This is what most people think of when they refer to usability. Interface design and implementation is the most easily-seen, and often the most vividly-felt form of usability we encounter in software development. Plenty of books have been written about this sort of usability. Cooper's About Face is one of my favorites.

The inspiration for this post was a classic UI usability foible, but this isn't the only kind of usability you should be aware of. As software developers, we encounter usability in a number of areas beyond the traditional "pretty picture" stuff (apologies to Cooper).

Consider the dynamics of that Outlook dialog, and ask yourself why it's so immediately identifiable as a usability problem. It's a disruption. It was supposed to work, and then suddenly, it didn't. I got angry at Outlook. That's how I know it's a usability problem.

I'm going to explore some other aspects of usability in software development in some coming articles, and I think this well-timed error message is a great leaping-off point.

Where do you find usability in unconventional places -- in development or otherwise?