Suddenly a clever idea strikes you. Hmmm... it just might work. You realize deep down it's not the right way to do it. Maybe it means adding some temporal/implicit dependencies. ("as long as no one starts calling foo() before initBar(), everything should keep working.")
Maybe it means throwing in a magic string that will only work until January 3 next year. ("No problem, I'll just come back to this code after the deadline. We shouldn't be too busy then.")
Maybe it means breaking the design and making the code untestable. ("Well, it would be nice to have automated tests around this, but it seems to be working. Hopefully no one makes any changes to this code before the deadline.")
Maybe it means living with intermittent bugs. ("Hmmm. The system only times out 8% of the time. We need to figure out why before we go into production, but that should be good enough for testing.")
Maybe it means removing one bug and introducing another one. ("Well, at least we can submit the page now. Hopefully none of the users double-clicks the submit button until I've had a chance to revisit the code after the deadline. I'll fix it later.")
That's the magic word. Later. It makes a great warning signal that you may be heading down a dangerous path. When you catch yourself thinking "I'll fix it later", stop for a minute. You're feeling that little twang of guilt for a reason (even if it's masked by the little ego boost you get from coming up with such a clever workaround). Think about the real consequences of this decision. Will you really get back to it later? What will happen if you don't? What are the risks you're introducing? Ask another developer for an opinion. Ask the customer for an opinion (if you can phrase it in customer language). Think a little longer about other solutions.
There are several popular variants of "I'll fix it later":
- I'll fix that bug later.
- I'll verify with the customer that I've built what they actually need later.
- I'll write unit tests later.
- I'll remove the fragility from the unit tests later.
- I'll make the unit tests readable later.
- I'll make the unit tests fast later.
- I'll integration test later.
- I'll usability test later.
- I'll remove that copy/paste duplication later.
- I'll bounce my idea/design/code off another developer later.
- I'll remove that workaround/hot fix/complete hack later.
- I'll make the code readable/maintainable later.
- I'll worry about performance/reliability later.
"Later equals Never."
Why is this? There are a few reasons that I've noticed:
- When you cut corners in order to deliver on time, you're giving management and your customer a false sense of how fast you can reliably deliver. Agile teams use the term 'velocity' to describe the estimated amount of customer value they can deliver per iteration. If there is still work left to be done, you are effectively lying to your customer about how fast you can deliver value. Since your customer thinks you can deliver more than you really can, you will be overloaded with work again next time. You will start accumulating technical debt. There is no easy cure for technical debt (the most common cure being a complete re-write), so prevention is the best medicine. The best way to prevent technical debt from accumulating is to establish realistic expectations about how fast you can effectively work.
- When you skimp on automated tests, and even when you write tests but don't ensure they are readable, atomic, and easily-maintained unit tests, you limit your ability to effectively refactor. When you can't easily refactor, it begins to get hard to write readable, atomic, and easily-maintained unit tests. Not only that -- because it's harder to evolve your design, you will face a stronger temptation to fix bugs with workarounds and hacks that will come back to bite you later. You will spend more time debugging and bug fixing, leaving you less time to write tests and refactor. It's a downward spiral that results in reduced velocity.
- unit tested
- verified by customer & customer tests
- usability tested
- integrated
- integration tested
- documented
- performance tested
- peer reviewed (via pair programming or some other mechanism)
- refactored, readable, duplication-free
- bug-free
Do you have any other "I'll fix it later" variants to add to my list? Stories about how planning on fixing something later came back to haunt you, or how adhering to a definition of done saved a lot of potential pain? When is it ok to "fix it later"? Where's the fine line between LeBlanc's Law and YAGNI? Please share your thoughts in the comments section!


16 comments:
Good article Ryan. Very true. I think Dave should check for "prior art" on Leblanc's Law though.
Sweet article dude :) Thanks for attributing me btw. I'm actually using this in a discussion about the merits of refactoring. This article is really well thought out, and helps make the point for continual refactoring quite nicely.
I think the whole "later == never" thing started as an admission of my own tendency to procrastinate - but it does seem to have an amazingly broad applicability. A practice I now try is to have a list of "must do" items right under my monitor, and I don't consider the task done until they're all checked off. Things like "fix that kludge you put in BlahClass, ensure code coverage is high, test on Linux, etc".
Oh and "later equals never" comes up with 3 google hits, one of which actually talks about this exact form of procrastination. But I think I started quoting it first :)
Agile Guru R.P. Cooper hits the nail on the head once again.
Where I am, later == never because there is zero time or business justification to fix a problem that is visible only to developers. Once a hack is in it's done until something breaks "later". No matter that it will take ten times as long to correct it then. The project schedule will never and could never contain line items for "fixing the code". No one (except the developers (well only one, me) cares. So at the time it's broke, it's "now or never" not "now or later".
Great post! I posted some comments on my blog at Pure Danger Tech.
It depends upon your goals. If you want to remain a programmer, then follow this advice. If you want to make money then you _should_ give your employer a dishonest exaggeration of the speed at which you can get things done. Then he'll give you a raise, assign you new development, and turn your buggy monstrosities over to the "slower" programmers for maintenance. Then, before it all catches up with you, move into management. Tell people, "I got the code out the door while the window of opportunity was still open."
Please create a printer stylesheet or an easy way to print. I use firefox and can't print your article.
Thanks for the suggestion, Stucco. I'm running into some kinks trying to create a print stylesheet that works with my blogger template, but I'll put more time into it later this evening.
Horror stories that come back to bite?
How about three that collide?
Mine: writing C code for the first time, needed a library up ASAP, didn't know which flag to set on file create, so passed a "-1" to it and set all flags.
Including global write and setuid.
Bad, but not yet a disaster.
Second person: has lots of permission problems with a system, so he says "the app needs to run as root".
Worse, but not yet a disaster.
Third person: we need to be able to access this from anywhere on the internet, so lets NFS export world mount world write.
Now we have: NFS world mount world write, process creating files as root, with other write and setuid set. Result: owned box. All three were a Temporary fix, we'll come back to fix this before it goes into production.
The attitude that "we will fix it later" is why I no longer work for someone else as a developer.
After retiring from 20 years of service in the military, I searched for a job where "doing it right the first time was a priority." Everyone said that it was, but I found that it was never the case.
Deadlines would loom, and my part of the project was done correctly and Unit tested and worked, so I would be assigned to help other younger programmers meet their deadlines. Their solutions were usually a "quick fix to get it out the door."
When the deadline was met, the younger programmers usually went on to other projects, while I was again assigned to fix the parts of the project that didn't work.
I got tired of fixing other people's code, so I now develop my own software, for my own purposes. It is speced out, tests are written before the code, the code is Unit Tested and when implemented, it works first time every time. In the military, I also learned the concept that it should be fully documented, so if something happens to me, someone else can take up the torch and run with it.
And did I say that I don't have to fix someone elses code :)
Thanks, all, for sharing your comments and stories!
P.S. Stucco (and anyone else wondering): I've managed to wrestle my blogger template into a print style. You should now be able to print articles from On Agile pretty cleanly.
Cheers!
But Ryan, you just made yourself a liar...
You said you'd fix the stylesheet "later"... and then you did!
:)
Great article, BTW.
Thanks Travis!
I guess the important thing is I designated a specific later ("later this evening"), not just the nebulous catch-all "later".
Very pertinent advice, thank you! I think it extends to everything and not only development! We run a fairly complex IP PBX, which I reconfigure to cater for various connection options, such as softphones. I test from my side and ask the user to test from their side as soon as they are set up. Frequently, they don't, I don't hear from them until weeks later and then they find it doesn't work! In one laughable case, the user phoned me, by an alternate means, to say his softphone wasn't working, so I made a connection and he answered with the silence of surprise, which all goes to show ....! (I have a saying too: The client is not usually right; but he or she has rights! And one of those is to be kept accurately informed of progress, problems and limitations.)
Have you tried using a reminder service like backpackit to help with this? I haven't yet, but I imagine it'd be a little harder to ignore those e-mails than the stack of "we should really do this" cards on the wall.
Well, what can I say... there are 1,129 "todo" items in the 5500 classes of the project I am currently working on, and there are probably even more things left for "later"
Post a Comment