Take the 2-minute tour ×

I find myself pondering over this question from time to time, again and again. I want to do things the right way: to write clean, understandable and correct code that is easy to maintain. However, what I end up doing is writing patch upon a patch; just because there is no time, clients are waiting, a bug should be fixed overnight, the company is losing money on this problem, a manager is pressing hard etc., etc.

I know perfectly well that in the long term I am wasting more time on these patches, but as this time spans months of work, nobody cares. Also, as one of my managers used to say: "we don't know if there will be a long term if we don't fix it now."

I am sure I am not the only one entrapped in these endless real/ideal choice cycles. So how do you, my fellow programmers, cope with this?

UPDATE: Thank you all for this interesting discussion. It is sad that so many people have to choose daily between a quantity and a quality of their code. Still, surprisingly many, people think it is possible to win this battle, so I am going into the trenches too.

share|improve this question
Simple: do it right and do it fast –  ren Dec 5 '12 at 17:10
@ren: Well, I suppose you aren't a programmer, you are a manager :-) –  Flot2011 Dec 5 '12 at 17:23
Obligatory. xkcd.com/844 –  mikeTheLiar Dec 5 '12 at 21:30
Do it ASAP. Then if you still have time, do it right. –  Laurent Couvidou Dec 6 '12 at 10:59
As Uncle bob says: The slow way is the fast way. Take the time it takes to write those unit tests, and write your code well. This might cause it to take some more time for the feature to be implemented, but will save time in the long run as it will be easier for others to modify and fix bugs in. –  martiert Dec 15 '12 at 16:53
show 6 more comments

14 Answers

up vote 82 down vote accepted

Actually, this is a very difficult question because there is no absolutely right answer. In our organization we have been putting better processes in place to produce better code. We updated our coding standards to reflect how we, as a group, write code, and we have instituted a very strong test/refactor/design/code loop. We deliver continually or at least try to. At the very least, we have something to show the stakeholders every two weeks. We feel that we are software craftsmen and morale is high. But, despite all these checks and balances, we suffer from the same problem you do.

At the end of the day, we are delivering a product to a paying customer. This customer has needs and expectations, realistic or not. Often the sales team gets us into trouble just to get a commission. Sometimes the customer has go-live expectations that are unrealistic or demand change even though we have a contract in place. Timelines happen. PTO and lost days during a sprint can happen. All sorts of little things can culminate in a situation where we are forced into the conundrum of "do it right" or "do it ASAP." Almost always, we are forced to "do it ASAP."

As software craftsmen, developers, programmers, people who code for a job -- it is our natural inclination to "do it right." "Do it ASAP" is what happens when we work to survive, as most of us do. The balance is hard.

I always start by approaching executive management (I am Director of Software Development and an active developer in that group) to defend the schedule, team and work being done. Usually at that point I'm told the customer has to have it now and it has to work. When I know there is no room for negotiation or give, I go back and work with the team to see what corners can be cut. I won't sacrifice quality in the feature that is driving the customer's need to get it ASAP, but something will go and it will get pushed into another sprint. This is almost always OK.

When you are unable to deliver because there are so many bugs, code quality is bad and getting worse, and timelines are getting shorter, then you are in a different situation than what I describe. In that case, current or past mismanagement, bad development practices that led to poor code quality, or other factors may be taking you on a death march.

My opinion here is to do your best to defend good code and best practices to start pulling your company out of the trenches. If there isn't a single colleague willing to listen or go to bat for the group against management, then it might be time to start looking for a new job.

In the end, real life trumps all. If you are working for a company that needs to sell what you are developing, then you will encounter this trade-off daily. Only by striving to achieve good development principles early on have I been successful at staying ahead of the code quality curve.

The push and pull between developers and salesmen reminds me of a joke. "What's the difference between a used car salesman and a software salesman? At least the used car salesman knows he is lying." Keep your chin up and try to "do the right thing" as you go.

share|improve this answer
"Often the sales team gets us into trouble just to get a commission" - At what point would you consider that sales should be held responsible for selling something that the business can't deliver - assuming there is one? Do you have examples where they've crossed the line between aggressive marketing and overselling? –  Tom W Dec 5 '12 at 14:40
@TomW I have several in house examples, specifics which I could not post here but when it happens it almost always happens when we need a reference account or near the end of the quarter. We have some very good salesmen and some not so good ones. Recently there has been a big shift in cleaning house once it was determined that Development was not the issue and the entire sales structure changed for the better. Things have been going wonderfully since. I would love to be more specific but I cannot. –  Akira71 Dec 5 '12 at 14:57
+1 - "I won't sacrifice quality in the feature that is driving the customers need to get it ASAP, but something will go"...that was fantastic. –  Joel B Dec 5 '12 at 17:26
@TomW - I always like to point out that the Titanic's chief naval architect who warned against cost cutting (Thomas Andrews) went down with the ship while the top sale/marketing guy who urged cost cutting and getting things done ASAP (Bruce Ismay) escaped in a lifeboat. –  jfrankcarr Dec 5 '12 at 18:56
I'd have loved to have the time type an answer like this, but I have a client whinging to my boss on the phone. "Often the sales team gets us into trouble just to get a commission." Same here...but somehow they still get those bonuses! –  Kenzo Dec 5 '12 at 20:03
show 1 more comment

One thing I've realized in my career is that there is always time to do it right. Yeah, your manager might be pushing. The client might be pissed. But they don't know how long things take to do. If you (your dev team) don't do it, it's not getting done; you hold all of the leverage.

Because you know what caused your manager to be pushing you or your client to be pissed off? Poor Quality.

share|improve this answer
While there's usually time to do a good job, there's usually not time to do it perfectly. There's a world of difference between the two. –  Donal Fellows Dec 5 '12 at 13:13
@DonalFellows of course. 'Right' is always "following best practices, using our best understanding of the problem at this point, to the best of our ability". People make mistakes. Requirements change. Best practices change. Don't cut corners and refactor when stuff happens. –  Telastyn Dec 5 '12 at 14:17
@DonalFellows - "The enemy of excellence is perfection". A program written in a maintainable fashion, that meets the clients' requirements and does so with acceptable performance, is a program that is "done". Nothing ivory tower about it. –  KeithS Dec 5 '12 at 15:58
@DonalFellows Nobody used the word perfect, a perfect solution is a wrong solution, Telastyn is speaking of a Right solution. The right solution is the one that meets requirements and is unlikely to cause problems in the future while being easy to handle in the event it does. Absolutes are always wrong. –  Jimmy Hoffa Dec 5 '12 at 16:31
+1 - For Telastyn, While all customers want their stuff done now. FAR MORE customers want their stuff to work more so than getting it done now. It seems everyone who disagrees with Telastyn claims that they will lose a customer if it doesn't get done quickly. That is by far the exception and not the rule. What is the rule, that most people who are disagreeing, is that they are ignoring that they will lose far more customers by delivering shoddy products. The claim that the customer wants it now is the usual excuse by people who don't care about quality. So I'm skeptical of the claimed risk. –  Dunk Dec 6 '12 at 23:48
show 7 more comments

There is only one solution. Reserve around 10-20% of project/work time for refactoring. If it's difficult to convince the management that it is a justifiable task give them the only real argument: without refactoring the cost of code maintenance will grow exponentially over time. It's good to have a few metrics/articles/research results to back up this thesis during the meeting with the manager :)

Edit: there are a few good resources on "refactoring vs rising costs of maintenance" mentioned in this whitepaper: http://www.omnext.net/downloads/Whitepaper_Omnext.pdf

share|improve this answer
There is a better option: make refactoring part of you regular coding habit. Dayly. Hourly. Whenever you add or change a function. So you don't have to reserve extra time for it, or "convince management". –  Doc Brown Dec 5 '12 at 13:02
It's only valid when you don't have to deal with code that is already written. It's a common task to add new value to the old/legacy/inherited source code. But when you look at that code you don't know where to begin and you feel it's easier to write that code all over again than to learn how it works. Try to justify these estimates: two days to add new value, six days to refactor the old code to make it maintainable. It's often to hear "don't refactor, just add the new value, we'll figure out later what to do with that old code". –  Andrzej Bobak Dec 5 '12 at 13:09
@Flot2011 Then you have only one solution. Let "day-to-day" refactoring be your routine task. For example every tuesday focus only on improving quality of the code. Make sure it is respected by the management and make sure they know refactoring is not a waste of time. Without these two conditions met sooner or later they'll abandon the idea of improving "something that's already here and it's working". –  Andrzej Bobak Dec 5 '12 at 13:34
@DocBrown It works when you talk to management. If you talk to senior developer and tell him you'll be adding two fields to the form and it will take you 3 days ... Well good luck :). –  Andrzej Bobak Dec 5 '12 at 14:16
Having to inflate your estimates to get maintenance time is problematic for a number of reasons. Sometimes technical debt is in fact worth incurring. What happens when biz suddenly notices that in an emergency situation it took 15 minutes to slap two new fields in when last time it took 8 days. IMO, biz needs to be conscious of tech debt and the long-term impact it has. The problem needs to be understood as either you pay now or you pay 5 times as much later when all is said in done. –  Erik Reppen Dec 5 '12 at 20:00
show 7 more comments

Whenever you have time for doing something right, use it - write the best code you can, and improve it steadily. Don't make your job harder by beeing sloppy and introducing technical debt when there is no need to.

Emergency calls for fixing a severe bug are no things you can control by yourself, when they occur, you have to react ASAP, that's life. Of course, if you are under the impression that your whole job consists of emergency calls, and you have never enough time for doing things right, then you are on a road to burn-out and should talk to your boss.

If that does not help, there is still "Scotty's strategy" to get enough time for doing things right: multiply all your estimates by a factor of 4:


share|improve this answer
Scotty's strategy works. Just don't let your boss know you're doing this. Often times the time it takes in reality is double. It's always better to finish early than late. –  Luke Dec 5 '12 at 17:19
add comment

This boils down to what I've started thinking of as "The Eternal Conflict" (between business and engineering). I don't have the solution as it's a problem that never goes away but you can do stuff to help mitigate.

  • Communicate Value

What people often don't realize is that as engineers we're just assuming the problem of "successful business" is always a given. We want our code to be nice and neat and maintainable so that we can add new features and tweak existing ones rapidly and with a minimum of customers doing QA for us by discovering bizarre fringe cases that would have been thwarted by better code. Keeping customers and maintaining a competitive edge with features and finesse nobody else can produce fast enough are both business wins that good code directly contributes to and inform much of the reason we want better code in the first place.

So spell it out. "We want to do X in our codebase because if we don't it will impact business negatively due to Y" or " ...because it will enhance our ability to stay competitive by improving our ability to turn new improvements and features around faster."

And do your best to try and get tangible evidence that improvements are working. If improving some subset of an app resulted in faster feature/improvement, check whatever backlog tool you might be using for evidence thereof and point it out at appropriate meetings.

  • Get the Team on the Same Damn Page

Egos are often a problem. One thing engineering teams need very badly is to establish the value of having some kind of agreed upon consistent approach to solving certain types of problems over everybody doing their own cup of Kool Aid d'jour because they know better. It's okay to believe the other guy's preference is worse than yours but value consistency over being more right if his approach is workable and it's an argument you can't win. Compromise for the sake of consistency is key. When things are consistent it's harder to do them wrong since the consistent established way will usually also be the fastest way.

  • Pick the Right Tools

There are two schools of frameworks/toolsets/libraries/whatever. "Set 99% of it up for me so I have to know/do very little" vs. "stay out of my way when I don't want you there, but help me DIY very rapidly and consistently with stuff that I actually want to use on the carrot rather than stick principle." Favor the second one. Flexibility and granular control should never be sacrificed at the altar of rapid turnaround because to biz, "we can't do this because our own tools won't let us" is never an acceptable answer and the question will always come up for non-trivial/disposable product engineering. In my experience, inflexible tools almost always get busted wide open or worked around inelegantly and make a big giant unmaintainable mess. More often than not, the flexible/easier to modify solutions are just as or very nearly as fast in the short term, regardless. Fast, flexible, and maintainable are possible with the right tools.

  • FFS, If Engineers Don't Decide, at Least Get Engineer Input on Picking the Tools

I get the sense this is a developer-perspective question but I've been in far too many situations where technology decisions were made with zero engineer input. What the Hell is that? Yes, somebody ultimately has to make the final call, but get some qualified opinions if you're a non-technical manager, not what some sales guy or demo site says about its own products. Anything promising to save you money because people don't need to be as smart or because it protects developers from themselves is a filthy, dirty lie. Hire talent you can trust. Spell out to them what you want from a stack or other tech solution and take their input seriously before deciding what tech bandwagon to jump on.

  • Focus on Design Over Implementation

Tools are for implementation and as such they can help you, but first priority has to be the architecture regardless of whatever set of toys you have for building that architecture. At the end of the day KISS and DRY and all excellent philosophies that extend from those matter more than whether it's in .NET or Java or perhaps something that's both free AND doesn't suck.

  • Log Your Concerns

When the biz-side insists you do it the bad way, save that e-mail, especially the part where you said why it would cost you. When all of your predictions come true and serious business-damaging problems result, that's when you've got a big pile of arguments for taking engineer concerns more seriously. But time things carefully. In the middle of the blazing inferno is a bad time for an "I-told-you-so" on following fire code. Put the fire out, and bring your list of previously ignored concerns to a retrospective meeting/conversation, and try to keep the focus on engineering concerns expressed and ignored and the reasoning you understood why they were being ignored, not the names of the actual people making the decision to ignore. You're an engineer. Stay on the problems, not the people. "We expressed concern over X because we were afraid it would lead to Y problems. We were told Z and to put off dealing with it."

share|improve this answer
Very nice and in-depth answer. May I add, that i've already experienced a bad case of pick the right tools, that produced a major waste of time. We could ship the product one month later, after the decision was made that we abandon this product and use something that doesn't lock us out. –  mri Jan 21 '13 at 20:05
add comment

This won't work in every case, but I have had some luck using this strategy if the problem is a broken production problem that must be urgently fixed. Estimate the time to do a quick fix to get production running and the time to do the quality fix for the future. Present the estimates to your boss/client and get the time approved for both. Then you do the quick fix to get production runnning and a long term fix immediately therafter when the urgent time pressure is off. I find that if I present it as I need this time to get the job done right, but I can put a temporary fix in place until I can do that, that my clients seem to like that approach. It gets prod running again and it gets the long term need taken care of.

share|improve this answer
add comment

I see my job as providing the best quality software that is possible within the time constraints allowed for the project. If I am concerned that the level of quality will be low, then I will engage the project owner. I describe my concerns and discuss the potential risks of deploying the software in that state. One of 3 things will happen at this point:

  1. The project owner will not want to accept the risks and will move the schedule back to allow us to spend more time on software quality.

  2. The project owner will not want to accept the risks but cannot move the schedule back. If this happens, then we need to negotiate on what features/functionality to remove from project scope in order to spend more time on software quality for the main parts of the application.

  3. The project owner will accept the risks and the low quality software will go out on schedule. Sometimes the business risk of deploying nothing (or deploying late) is much greater than the business risk of deploying low quality software, and only the project owner can make that decision.

Writing software is a lot like painting a portrait. It is impossible to say that a portrait is done "right" or "perfect". Perfect is the enemy of done. You could literally spend 1 month working on a single method and it still not be considered "perfect" by some. My job is to paint a portrait that the customer is happy with.

share|improve this answer
add comment

The optimal balance may be to spend as much extra time doing it right as you would waste fixing the bugs you eliminate by doing it right. Avoid gold-plating the solution. In most cases the Volkswagen solution done right is as good as the Cadillac solution. You can usually upgrade later when it is proven you need the Cadillac.

Fixing code that hasn't followed best practices often take much longer. Trying to find where the null is coming from when the call looks like a.b.c.d.e(), can take a long time.

Applying DRY and reusing existing code is usually much faster than coding and testing yet another solution. It also makes it easier to apply changes when they do occur. You only need to change and test one set of code, not two, three, or twenty.

Aim for solid basic code. A lot of time can be wasted trying to make it perfect. There are best practices that lead to code which is fast, but not necessarily the fastest it could be. Beyond that, trying to anticipate bottlenecks and optimize the code as it is built can be wasted time. Even worse, the optimization may slow the code down.

Whenever possible, provide the minimal working solution. I have seen weeks wasted gold plating solutions. Be extremely careful about scope.

I spent some time working on project that should have taken six months. When I joined it had been in progress for a year-and-a-half. The project lead had asked the project manager one question at the start: "Do you want me to do it right or be responsive?" In one week, a feature was implemented Monday, Wednesday, and Friday; Tuesday and Thursday the feature was removed.

EDIT: When the code is done to a satisfactory level, leave it. Don't go back to fix it if you come up with a better way to do it. If you must make yourself a note. If changes are required, review your idea and implement it then if it still makes sense.

If there are places where you would implement extensions for upcoming features, don't implement the extensions. You could leave a marker comment to remind you where to make the changes.

share|improve this answer
Unless DRY means confusing, illegible, implementation of massive cascading inheritance schemes. Don't do that. Sorry, I say that a lot, but I really hate that. Also, +1 for minimal working solution in most cases. Sometimes some forward-looking architectural features can be helpful as long as you don't overdo it though. –  Erik Reppen Dec 6 '12 at 1:42
@ErikReppen Code which is confusing, illegible, and an implementation of massive cascading inheritance schemes would fail my definition of DRY. If you need to figure the code out each time you use it, the design clearly fails DRY even if the implementation passes. –  BillThor Dec 6 '12 at 2:01
It can involve a lot of code reuse though. The annoying part is climbing a tree of 18 classes or prototypes to find the actual definition of a method that's doing something really annoying especially if there's overrides. –  Erik Reppen Dec 6 '12 at 2:12
add comment

Make it work then make it perfect

I may draw some slack for this - but if time is of the essence, then your main priority should be to get it working, simple as that. Comment extensively about the shortcomings in your code and make a note of what you've done in any project/time management software you're using.

Hopefully this will give you more time to return to these issues and make them perfect.

Obviously there is no absolute correct answer to this, but it's an answer I try and stick to. You may not find it suited to your current work style though. Which leads me on to the alternative...

Just find a method that works for you; and then stick with it. Everyone has their own way of dealing with projects and there's no "one size fits all" approach. Find an approach, and make it yours.

share|improve this answer
When management knows, that it works. They take it as done and don't want you to spend any other efforts on refactoring, etc. –  Adronius Dec 16 '12 at 13:45
add comment

When in emergency create the patching solution. Create a new bug in bug tracking mentioning this. Make it right, whenever you have apt time.

share|improve this answer
The problem is, there almost never is apt time, that's exactly the problem, and bugs of this kind will always get the lowest priority. –  Flot2011 Dec 5 '12 at 11:57
I'd say this is true only if by "emergency" you mean "something that happens no more than once every six months" and by "when you have time" you mean "within a week or so". Otherwise your follow up question becomes "help, the client needs something ASAP, but the code I have to change is a confusing mess and it will take me weeks to sort out!" –  Nathan Long Dec 5 '12 at 14:13
add comment

"Doing it right" means making the right tradeoffs for a particular situation. Some of them are:

  1. Development time and cost
  2. Ease of reading, debugging, and updating the code later (everything from variable names to architecture)
  3. Thoroughness of the solution (edge cases)
  4. Speed of execution

Obviously, if you're never going to maintain a piece of code, #2 can be sacrificed for any of the others.

If you're going to keep using and updating some code, taking shortcuts now just means slowing yourself down later.

If you are currently delivering buggy code (weak on #4) and taking a long time to do it (weak on #1), and it's because you're trying to update code that was weak on #2, well, you've got a solid, pragmatic argument for changing your practices.

share|improve this answer
add comment

I think I do what everybody who is stuck working in this industry does. I get it done as fast as I can and if I have to leave out some of the nice things that would help prevent problems in the future, or make problem-solving easier in the future, I do. It is not an optimal situation but when you are stuck with deadlines based on estimates based on estimates, based on a lot of unknown variables, it is pretty much the best you can do.

share|improve this answer
add comment

Here's a good plan:

  1. Make your do-it-right plan take exactly same amount of time than do-it-asap.
  2. Optimize your time to do it until your environment is happy; keep the quality
  3. ???
  4. Success
share|improve this answer
add comment

If it's a bug, do it ASAP, if it's a new feature, take your time.

And if you work for a company that does not respect developer work, you may have not choice but to do it fast and sacrifice on quality.

I've worked for a number of companies that would just go from project to project, and do everything fast. Ultimately, they had little success in every project because the implementation (not just the programming) was rushed through.

The best companies out there understand that good software takes time and craftsmanship.

share|improve this answer
add comment

protected by maple_shaft Dec 13 '12 at 13:03

