Archive for December, 2008

Are you sure you want to exit?

Tuesday, December 30th, 2008

Why is it necessary to make me confirm every action I take?? Every time I see a dialog asking me to confirm something, I inevitably just hit return or click through the dialog without thinking, so what is the point?? On top of that, I am now trained to click through dialogs, so on the rare occasion where the dialog is useful (the Unsaved Changes dialog is always useful, even if it can be annoying sometimes), Often I’ll click through without paying attention.

This is bad.

Software should be written so I don’t have to confirm things.? If I screw up, I won’t realize it until after I’ve confirmed the operation anyway, so why not just provide me a way to undo my change so I can get back to my previous state.

Save the confirmation dialogs for things that are irreversible, like closing a document that has unsaved changes.? If you assume your users are idiots, I guarantee you will have idiots for users.? Treat them like they know what they are doing, but provide a safety net for when they make a mistake, and your users will be empowered to learn things for themselves.

Appearing Gracious

Tuesday, December 23rd, 2008

No one likes rejection.? Most of us, when faced with it, would rather blame someone else for the failure, instead of looking at what we did to contribute to it.? Seth Godin posits that the responses fall into one of two categories (paraphrased for simplicity):

  1. Throw a fit.
  2. Thank everyone for their time and seek to improve.

I highly recommend you read and think about what he is saying, because it is excellent advice that isn't followed often enough.? But, as with all things, there is a catch.? It is far more difficult than it can seem.? It is not enough to simply go through the motions and appear to be gracious.? You have to actually believe it.? Otherwise, the loss of trust could be so great as to be far more destructive than simply throwing a fit in the first place (at least everyone will know where you stand and what you think).

Fortunately, you can learn to respond graciously, but it take practice, effort, and a sincere desire to do so.? You also need an organization in place around you that allows for graciousness – failure happens, especially in the software world, and if you are not in a place where you can deal constructively with that failure and apply it to your future work, then you will find it very difficult to be successful.

New Theme!

Thursday, December 18th, 2008

?So you may have noticed the site looks a bit different today…? I've always planned on doing a redesign of the site – its been a while since I've done any website work, and I'd like to get back up to speed, so I thought a website redesign would be the way to go.

For the moment, I kept it pretty simple.? If you would like to use it for your site please visit the download page to get the latest version.? Be aware that it is still under development, so keep your eyes out for new versions – I will post them here whenever I deploy them.

CodeInReview Theme.zip (6.37 kb)

Design and Implementation of Large Projects

Tuesday, December 16th, 2008

OK, so this isn’t really about the design and implementation of large projects.? Rather it is about the perception of the design and implementation of large projects.? Just to put numbers to things, lets assume that in this context I am referring to a 10 developer project that has been under development for 3+ years.

Now imagine for a moment that you are a new developer assigned to this project.? You come in and open the project for the first time and all you see is a mess of code.? Huge methods with interlocking dependencies.? Even the simplest task seems to involve multiple areas of the code.? Changes you make seem to cascade into unrelated areas of code.? The project seems headed for disaster.

When faced with this problem, there are generally 2 responses.?

The first approach is to assume that you are basically an idiot.? I rarely see developers take this approach, and I can’t really blame them.? We all want to be the super-star.? We all want to be the guy/gal with the answers.? That is why the next approach is so seductive – you can become the one with the answers by default.

The other response is to immediately begin a campaign of improvement.? You talk to management.? You promote aggressively refactoring and rewriting the entire code base.? You suggest simplification.? You point out unnecessary code.? You demand unit tests so that the suggested rewrite won’t break anything.? You tirelessly work to point out all the flaws in the design and how they can be fixed.

You attempt to enlist others in your campaign, but can’t seem to find any supporters, except for maybe that other new guy who joined last month.? When you approach the more experienced folk they just shrug their shoulders and claim that “it works”.? Frustrated by the experience, you transfer over to a smaller team where they do things *right*.

This happens so often it has almost become a cliche.? Large projects are littered with awful code and design, while small projects excel at being lean and simple.? Of course, I happen to think that is absurdly false.? Small projects have just as many inconsistencies as large projects do, its just the scale of the project reduces the total number.?

If you were to take the first approach suggested, and assume that there is a historical context to the project, you would then be able to put the design and development into that context.? Suddenly, you might understand why the GUI layer talks directly to the database during a save instead of via the business layer (because when you moved to version 1.3, you found that the overhead of the new business object translation caused an unacceptable degradation in performance).

Suddenly, you might notice that the more experienced members of the team are able to make changes in a reasonable amount of time with little or no side-effects.? You might notice that they are able to add new features without introducing defects or regressions.? Over time, you might even notice that you are able to make changes more efficiently.?

You might even come to understand and respect the stability and well-understood nature of the mature code base.

The idea that you can come into a large project and suggest meaningful large-scale design improvements within a month or two of joining is laughable.? In just the hypothetical project I mentioned there is over 30 years of development-hours embedded in the code.? To suggest that you can understand that well enough to embark on a redesign and/or a rewrite of the code in such a short period of time is to suggest that you don’t even understand the context of the problem, much less what is needed to fix it.

So when confronted by a large project that seems to be a complete disaster, give it time.? Learn the code.? Watch the more experienced developers and learn how they view the code.? Once you think you understand the code base, keep learning.? Wait an equivalent amount of time and re-evaluate where improvements could be made.? If after all this, you still feel the code is in need of a major overhaul, then go ahead and embark on your campaign to improve it.?

Now you are operating from a position of experience and understanding.? You are not simply making suggestions you don’t fully understand.? The rest of the team will be able to see that and will no longer simply dismiss your ideas as naive.?

Of course, you may find you have become one of those old developers who shrug their shoulders at the new guy who keeps spouting off about this and that.

Commit Wars

Monday, December 15th, 2008

Quick show of hands…? How many of you have gotten into a commit war?? I think we all know what I'm talking about – some projects even have rules that exist solely to prevent commit wars from occurring (they generally take the form of limiting the frequency of commits for a given file).? These things generally start out innocently.? Some well-intentioned developer opens up a file and decides that a couple of variable names aren't as clear as they should be.? So he renames them.? Since he is already in there, he reformats a couple of lines of code to meet his personal preferences and commits the file.

The original developer is then informed of a defect in her code.? Nothing serious – a simple mistake in the index being used.? She opens the file and is confused by the naming scheme – it seems the new names conflicted with the index name, and resulted in the defect.? In addition, the code was reformatted in an odd manner.? A firm believer in “the one true brace style”, and already on edge for taking the blame for a defect introduced by someone else, she reverts back to the original check-in and reformats the entire file to fit her preference.

The first developer notes the change in the file and the loss of all his insightful and very carefully chosen variables names.? Now furious, he undoes the commit and sends a nasty note to the original developer instructing her to leave his changes alone.

Not one to take something like this lying down, the original developer begins to nit all of his code in reviews.? When he doesn't fix her complaints, she comes in afterwards and changes it anyway.

Preventing Escalation

In hind sight, commit wars are remarkably simple to prevent.? Simply by mandating a standard code format you can avoid the majority of commit wars.? In addition, it is critical to ensure that your reviews focus on real problems and not on simply stylistic or implementation preferences by the reviewer.?

Of course, the most crucial element to preventing a commit war is to create an environment and team where there is enough respect that the developers do not feel the need to look over each other's shoulders.? If no one can trust the rest of the team to do things right, then every little change is subject to enhanced scrutiny, and possible retaliation.

Finally, if every change requires a peer review, most of these problems will never make it past the review.? Too often, teams believe that only the major changes should be reviewed.? But by putting a lightweight review process in place to review every code change, you can avoid the sorts of unnecessary changes that create commit wars.? Of course, if you actually expect to get things one, you had better make sure that your reviews are quick and painless…

Software Quality Improvement Tools

Thursday, December 11th, 2008

As a software developer, I understand and respect the effort that is required to put out a quality piece of software.? It is a hard, thankless task, requiring weeks and months of effort.? It requires a constant re-evaluation of the state of the tool and a careful balance of the needs of the customer with the goals of the business.

That being said, if you wish to sell me a tool designed to improve the quality of my software project, I will judge you based on the quality of your tool.? If you claim that the goal of your process is to “ensure the production of high-quality software that meets the needs of its end-users, within a predictable schedule and budget”, and yet your own software tools are littered with bugs and inconsistencies, I will judge you harshly.?

If your very name has the word “quality” in it, I will expect it to meet my minimum standards of quality.? I have a hard time believing in the benefits of your software if you cannot use it to improve your own.

If you take pride in your customer service, I expect that your customer service is not hidden behind a broken support form.

Mistakes happen and I can understand that.? But when your business if built upon the notion that you can provide a silver bullet to improve my software, you had better be sure that your software is better than mine.? Otherwise, I will have no patience for you or your tools.

Unfortunately, most of the tools that I encounter that claim to enhance software quality appear to be so fragile as to frighten me off without even attempting a proper evaluation.? Tools with that many errors I do not want anywhere near my own software, lest the poor practices in which it was created will seep into my own work.

Solutions are not Requirements

Thursday, December 11th, 2008

Yesterday, I described a particularly prolonged form of Project Suicide.? In my description, I touched on a point that I feel should be expanded upon.? Essentially the type of project suicide that I described revolves around the difference between how a client views a requirement and how most software engineers view requirements.

Clients inevitably frame requirements in terms of a problem:?

I need to be able to add 2 numbers.

Engineers inevitably frame requirements in terms of the solution:

We will provide 2 text entry dialogs.? In each dialog, the user will be able to enter a single number.? We will provide a single button called 'Add', which when pressed will add the 2 numbers in each dialog and display the result in a third text dialog.? The third text dialog will not be editable.

These are 2 very different beasts.? Most engineers will look at the first statement and immediately begin complaining about the lack of specifics.?

  • How do you add the numbers??
  • Where do you enter them??
  • Where do you display the result?

Eventually they will derive out the second example, and set it down as the official requirement, completely losing the fact that all the customer wanted was a way to add 2 numbers.? Everything else is just implementation details of a particular solution.

The problem with treating solutions as requirements is that you remove your ability to address the core problem.? You cannot anticipate future problems, because you are essentially reading from a script that tells you exactly what to implement.? That is not to say that you shouldn't explicitly detail your solution.? It simply means that your solution is not the requirement, it is simply a mechanism to satisfy the requirement.?

Solutions are not requirements.

Don't even bother phrasing a solution as a requirement.? Understand the solution and why it was suggested.? Document the underlying problem that is solved by the solution.? That is your requirement.?

Detail the solution in a design document for the requirement.? That way, no one will be tempted to treat it as gospel.? Designs are changed, modified, even thrown out, and people do not bat an eyelid.? But attempt to change a requirement, and everyone gets upset.

The other advantage of avoiding the temptation to treat solutions as requirements and treating them as designs instead is that on quality development teams most designs will go through some sort of vetting process.? This could be a formal sit down review, or a quick peer collaboration to make sure that nothing is missed.? Requirements rarely achieve even that level of scrutiny simply because by their nature there is little to debate.? They are coming in from the customer.? If the customer wants his spreadsheet software to also control his coffee pot, then at the end of the day the spreadsheet software will control his coffee pot.? This will happen one way or another, so there is little point in reviewing it internally.

Dealing with these vague requirements with multiple possible solutions will initially be a little bit overwhelming if you are used to the tightly constrained world of solutions as requirements.? But with time and effort I think you will find that the flexibility it offers you to address the core problem, not simply implement an attempted solution, will result in a much more satisfying, successful development cycle, and a happier client base to boot.

Project Suicide

Wednesday, December 10th, 2008

Have you ever had an argument with a client where you resorted to telling them they got exactly what they asked for?? Out of all the forms of project suicide I have seen, it astounds me that not only is this still common, but it is believed to be a legitimate response to customer's complaints.

The problem seems to stem from this mindset of software engineers to think in terms of solutions – not in terms of problems.? Customers and clients tend to think in terms of problems – they may suggest solutions, but they are limited by the current behavior and appearance of their toolset.? We as engineers like to take these suggested solutions and set them in stone.? We want to write them down and examine their every detail.? We try to force the customer to commit to design decisions so that we can move forward with our implementation.? The customer, who doesn't think in terms of solutions, simply goes with the flow, gratified that his or her suggestion was so useful.

This is why, after spending weeks ironing out the exact layout and specification of the entire feature and then an additional month implementing it, followed by weeks of testing, when the customer finally gets their hands on the release with the shiny new solution, she hates it.? So she comes yelling and screaming to the team demanding you correct your mistake, but of course, the team is protected.? Every step of the way, you've gotten the customer's signature that says this is what she wants.? It is part of the process we are all taught and follow blindly – when in doubt, ask.?

So when she comes yelling and screaming, you pull out all of those approvals and proceed to explain how you did exactly what she wanted.? As a matter of fact, you prove to her that you gave her more than she wanted.? When you are finished, all she can do is tell you to fix it and wait for the next release to see if you have a solution to her real problem.

That is project suicide.

From this moment on, the working environment is changed.? Everything must be documented, approvals must be given, and all decisions must be effectively supported.? Once this line has been crossed, you are no longer working with your clients as a team, you are working as an obstacle that must be dealt with.? The trust has been broken.? The client hired you to solve a problem, not satisfy a process.? Once you are in the business of satisfying a process, your margin for error has disappeared, because the process specifies exactly what is expected, and no allowances can be made.

It always seemed much better to accept the short term consequences of an honest mistake than the long term consequences of a refusal to accept it.

I am the Dumbest Person in the World

Tuesday, December 2nd, 2008

I’ve worked in this industry long enough to accept this fact.? I sit through meetings where someone will spout off something about “leveraging the core architectural paradigm” and everyone will ooh and aah in understanding and all I can do is look around in confusion, and then ask questions.

Lots of questions.

Mind numbingly stupid questions.

Questions like

  • What exactly is our architectural paradigm and what does that have to do with adding a menu item to print from the context menu?
  • Shouldn’t we just add the menu item right here in the constructor?
  • Why are we having a meeting to discuss this?
  • Why are we talking about the Command Pattern??
  • Why can’t we just handle the code right here in the OnPrint method?? This nice method that’s already written and fully tested?

and so forth…?

I’ve been known to question topics until the other folks give up and retreat in the face of my stupidity.? I can’t help it.? Sometimes I simply do not understand, and I want to understand.

Desperately.

There is nothing worse than having to sit through a two hour meeting where all you come away with is the fact that Billy from QA laughs like a hiena when he’s nervous.? Meanwhile, all your other fellow developers all seemed invigorated by the exchange of ideas that has taken place.

Of course, I’ve also found that this realization has somehow helped me to become a much better developer.? Now, whenever I approach a new piece of code, I don’t automatically assume that I am smarter and could write a better method than the person who’s code I am reviewing.? Instead, I think to myself:

“You know, I’m pretty dumb, and the person who wrote this probably isn’t, so maybe I should find out why they wrote it before I go mucking around in here”.

Just the act of acknowledging my own stupidity keeps me from making errors that I might otherwise be tempted to create.? Errors that might lead me to simplify some algorithm only to discover that I had forgotten to handle the special case where the variable was 0, resulting in a divide-by-zero exception instead of the expected answer of -1.? I don’t know why -1 would be the expected answer, but as I mentioned, I am the dumbest person in the world.

So I just keep asking questions until I’m satisfied.? Until, little by little, I understand what the code was intended to do.? Until, slowly, I realize that the code doesn’t actually do what the original author intended.? Until, slowly, I realize that -1 was intended to indicate an error state, not a number.? Until slowly I realize that the problem is that -1 is also an actual valid result.? Until, finally, I understand that the reason the software keeps crashing is because it was treating -1 as a valid result, instead of an indication of a divide-by-zero, and I can finally take action to correct the code.

Because now I understand, and I am no longer the dumbest person in the world…? At least until the next piece of code comes along, and I have to start the questions all over.