15

Following the Pareto rule, a programmer spends only 20% of his time for really useful things.

I spend 80% of my time debugging, fixing small things to get everything working.

Is there a way to spend less time debugging?

6
  • 9
    I am not sure that is how I would interpret the Pareto principle.
    – c_maker
    Oct 31, 2011 at 19:13
  • 6
    <meme>Have a look at TDD.</meme>
    – StuperUser
    Oct 31, 2011 at 19:14
  • 1
    What do you actually do when debugging?
    – user1249
    Oct 31, 2011 at 21:47
  • 3
    you need to spend more time on your attention to detail
    – user7519
    Oct 31, 2011 at 22:01
  • 1
    There is much to be gained from simply looking over your code now and then. Better yet, write comments as you feel the urge, so it will be easier to notice mistakes later.
    – Joey Adams
    Nov 1, 2011 at 4:42

16 Answers 16

5

Code in Agda or Coq. Once your code compiles, it will work. If it's too hardcore, choose a language with a weaker type system, e.g., Haskell or F#.

But still, in most cases you'll be much more productive spending 20% of your time on coding and 80% on testing and debugging. 100% of a week is much more than 20% of an hour. If debugging is what you need to get things done, than debugging is not a waste of time and you should not be bothered with "improving" this proportion.

17
  • 1
    JUst becasue something runs doesn't mean it doesn't have bugs. Bugs are often the result of the code doing the wrong thing.
    – HLGEM
    Nov 1, 2011 at 14:29
  • 3
    @HLGEM, before downvoting you should have read more on Agda and Coq. If your code compiles, it is guaranteed and proven to do exactly what its specification says. Of course there can be a bug in specification as well, but I would not call fixing this kind of issues a "debugging".
    – SK-logic
    Nov 1, 2011 at 15:02
  • 2
    @HLGEM, then your notion of "debugging" is quite creative and far from the mainstream. And anyway, with this approach a proportion between coding and "debugging" would be far from 20/80. So please, mind explaining your downvote.
    – SK-logic
    Nov 1, 2011 at 15:33
  • 1
    @HLGEM, it was not in a list of OP requirements. Nothing is known on how many developers are there, who's in charge, etc. The only question was "how to gauge the 20/80 ratio", and using a statically verified language is clearly the most obvious answer to it. But, as I said already, this answer is only applicable in very rare cases, and in general sticking to the 20/80 rule is a much better option.
    – SK-logic
    Nov 1, 2011 at 18:17
  • 1
    @uhbif19 Knuth meant to be humorous when saying that. You know what he really meant?
    – Phil
    Feb 13, 2012 at 0:34
44

Unit testing.

After I started applying unit testing I found that the code I wrote became better structured. It was then easier to avoid and spot bugs. I spent less time debugging, but more time with writing unit test.

I also think that the time invested in unit tests has a better return of investment then debugging. After a debugging session I just fixed the code. The same bug can appear weeks later and I have to debug again. If I write a unit test the bug is documented as a unit test and later acts as a regression test. If the bug appears again the unit tests reveals this to me.

4
  • I use Unit-Tests and completely agree with you. But, I can't test everything.
    – uhbif19
    Nov 1, 2011 at 7:47
  • 5
    Sure you can. Well not everything, but everything that matters. By using interfaces, dependency injection, faking and mocking classes/methods you will be able to write tests for pretty much all your code.
    – Fredrik
    Nov 1, 2011 at 8:56
  • 8
    @Fredrik, you can't properly unit test even the a + b piece of code (unless your test covers the whole range of your arithmetic data type).
    – SK-logic
    Nov 1, 2011 at 12:05
  • "After a debugging session I just fixed the code." -- Really? I think after a debugging session I just introduced more bugs - I just don't know where they are.
    – B Seven
    Nov 29, 2011 at 4:12
35
  • Unit testing, so that you know whether your code works in the first place.
  • At least some amount of upfront design, so that you know what you are coding.
  • Code reviews, because two heads are better than one, and four eyes are better than two. Not to mention that even trying to explain your code to someone else reveals many problems.
  • Version control, so that you can quickly isolate which changes may have caused the bug.
  • Refactoring, so that you code does not turn into a horrible incomprehensible mess.
  • Read "Clean Code" by Robert C. Martin, and do what he tells you. You will be amazed by the results.
9
  • 5
    Exactly - no single practice (e.g. unit testing) will give an order of magnitude improvement but a combination of practices can. In other words... there is no silver bullet.
    – Michael
    Oct 31, 2011 at 20:49
  • I would add TDD (where possible).
    – Tom
    Nov 1, 2011 at 3:57
  • 1
    I'd actually sort the clean code and refactoring first. Unit tests are good for finding and fixing bugs early, but they won't reduce the number of them (they will reduce the time a bit, because you will be fixing bugs when you have everything fresh in memory, but still). Writing clean code on the other hand reduces the actual number of bugs.
    – Jan Hudec
    Nov 1, 2011 at 8:10
  • 1
    @JanHudec Refactoring + clean code + tests = TDD
    – Tom
    Nov 1, 2011 at 11:46
  • 1
    @Tom: Yes, but the different parts of it have different effects. Learning to write clean code will help you cut down on debug time without any tests. Tests are there so you can test modules before their use is implemented and so you can verify you didn't modify behaviour when you refactor—which is needed to clean up old messy code.
    – Jan Hudec
    Nov 1, 2011 at 12:31
8

Unit testing will help as hopefully if you introduce bugs they will break before your production code - well written unit tests will also tell you exactly what broke.

That'll get you most of the way, but for 99.999% of projects you will still need to debug things from time time. The best thing to do here I find is to do 4 things:

  1. use immutable types wherever possible - if something has a wrong value you'll know exactly where to look immediately (where it's being constructed).
  2. enforce invariants in the code - if you know a value is definitely not allowed then check for it and throw an exception in the entry points to methods and constructors. If you combine this with immutable types then you can also begin making certain assumptions about what is valid or not.
  3. ensure you have adequate logging - get this in early and it'll give you a lot of important information about when things go wrong. AOP works really well here. Logging as an afterthought is usually a bit rubbish - get it in early as part of the project setup.
  4. if your code base is big/complex enough avoid using primitives - e.g. have a type called 'Age' rather than just using an int. It'll seem a bit pointless at first, but being able to track down all uses of something in an instant is a huge debugging win.
6

My 80% is debug. I am fixing simple bugs and trying to make all working.

Start by writing unit tests, and try to have as high coverage as possible. Someone mentioned TDD, but I would go with BDD.

At the end, you'll most likely spend 80% on debuging complex bugs.

6

How to spend less time debugging? Write less code.

Seriously, as long as you write code, you'll need to debug it. Unit tests etc help immensely, but don't think you'll ever remove the need for it altogether.

4

Understand the what and the why before you start writing code. Then use a methodology consistently. Which methodology you choose is not nearly as important as consistent repeated use of the methodology. If you want consistently good results, you need to do consistently good work and having a "method to your madness" is the first step to getting these results. As you identify issues you can adjust your methodology as needed and over time you will improve your development process, and hopefully fewer bugs and more new, meaningful development.

3

Give your code a careful read before you even compile it. A very careful read for syntax and functionality. It can be surprisingly informative, and is also a good indicator if a section of code is too complicated.

1
  • I totally agree. Reading your code immediately after you write it can very quickly reveal some evident bugs, like copy-and-paste typos (which can be difficult to find afterwards sometimes).
    – jirkamat
    Nov 3, 2011 at 17:21
3

Most answers seem focused on how to reduce the number of problems you have to debug and that is valuable. However, debugging will always be necessary so it is useful to look at ways of getting faster at debugging.

  • Know how to use your version control software.

    • Using branches will help you separate out areas of development and you'll be able to see which area of development has the bug and which don't.
    • Learn how to use bisection in your VCS, Git has this built in. If you use a different VCS that doesn't have bisection built in look for a tool that works like git bisect but for your VCS (I know this exists for SVN and shouldn't be too hard to create for other VCSs). This will help you narrow down to the code change that introduced the bug, which will help with knowing where to point your debugger. This bisection process will be faster if you have tests for the bug and knowing which commit contains the offending change will be more useful if you practice atomic commits.
  • Improve your understanding of the programming language you use.

    • Read books, blogs and code about the programming language.
    • Every time you fix a bug make sure you thoroughly understand why the code didn't work and why your fix works. Over time you will learn many gotchas in your language which will help you avoid their problems and spot the symptoms of them should they re-occur.
  • Be logical

    • Don't change more than one thing at once otherwise if the behaviour changes you won't know which change caused the change in behaviour.
    • Verify your assumptions.
2

Adding to the comments for Unit Testing but it is only really good if your code has been separated to support it (e.g. MVC). If you can't implement MVC (or similar) (legacy project), unit tests don't work at all for your UI. I would then add automated UI testing (Microsoft Coded UI Tests, WaitN) as this will reduce errors in that portion of your code.

I would also highly recommend running static analysis tools (e.g FxCop/Microsoft Code Analysis, Resharper, JustCode for the MS world). These can find all kinds of common coding problems which can reduce the silly debugging tasks and focus more on debugging business logic.

2

Make it work, then make it fast, then make it pretty. Most bugs come from early optimizations or re-factoring at lines of code that were totally fine. If you go with object orientation don't repeat yourself, keep it simple and always make sanity checks of value ranges especially if your methods will still work at constraints. It won't help you make less mistakes but it will likely help you to spot bugs faster and therefore debugging takes less time.

1
  • 1
    Your "Most bugs come from..." assertion sounds good, but do you have evidence to back that up? I think it would sound equally convincing if I said "most bugs come from poorly specified requirements or lack of a clear design." You should add a link or citation to research that supports your statement.
    – Caleb
    Nov 1, 2011 at 7:47
2

I've been given a lot of thought to this problem recently- the simple answer is go read Don Norman's The Design of Everyday Things; Write code like you would design a product.

To paraphrase, good design minimizes error. That means, a few things, most of which you already do (although you may not know exactly why).

-Name functions intuitively. This is formally known as affordance. That is, a button affords to be pressed, a lever affords to be switched, a handle to be pulled, etc.

-Make it hard to write bad code. Check for bad input and throw errors sooner rather than later, use apps hungarian when appropriate, etc. These are called lockout functions.

-Use abstraction where appropriate. Short-term memory is weak.

-Documentation is obviously important, but it is the least effective of making sure code is used properly. In short, well-designed products don't need any documentation. (The most obvious way to see this is looking at bad examples: namely, doors with handles that you're supposed to push.)

-Unit tests. These don't really prevent errors, so much as make it obvious where the bugs are, and provide sanity.

I'm sure I'm missing many more principles, but point is, read up on designing for error.

1

The best way to decrease debugging, IMO, is by concentrating and slowing down when coding. This forces you to see mistakes you may have made!

1

While I totally support the unit testing suggested above, TDD or BDD will be of great value as you need to first think about the problem and the solution.

But personally for me, taking a few minutes just to sit quietly and think about the problem and how to approach it and any pro's and cons with each approach, does wonders for my quality of code and helps clear my mind of clutter.

Sometimes a quick scribble on a piece of paper helps you see the larger connected pieces of the puzzle.

I write the worst code when I just dive in head first and pound the keyboard. A little bit of thought and contemplation makes a world of difference.

PS. I mean 5 maybe ten minutes, not hours writing a huge spec.

1

Some good answers already, just some more food for though in addtion to what others have said.

Learn from your mistakes. Don't keep making the same ones over and over again.

Make sure to cover edge cases when programming - those are places where there are frequently bugs.

Pay attention to the requirement. Even if it works but doesn't do what the requirement specified, that's a bug.

Exception logs can be a real help when something goes wrong six months from now. Be in the habit of recording exceptions.

0

My two top thoughts are 1) Write better code which will fail when you do something unexpected 2) Become better at debugging

My code is littered with

if(value!=null) throw new NotImplementedException();
if(obj.v>0) throw new Exception(); //sometimes i dont write NotImplementedException
if(value=="thing") throw ...;

Whenever i execute that piece of code the exception is thrown which causes the debugger to stop which lets me code in the new features or avoid the conditions rather then get confused about what is happening/have a bug

To become better at debugging mess around with the call stack, breakpoints (with conditions), the immediate window (also known as prompt or repl window), 'watch' variables and whatever else.

Not the answer you're looking for? Browse other questions tagged or ask your own question.