Solving Coding Problems

In all of my days as a programmer a lot of people approached me with the question "Why isn't my code working?" and it's usually because of one of the following reasons:
  • Syntax errors - missing semicolons/parenthesis, bad jQuery/css selectors.
  • Not enough knowledge about the problem domain or the technology.

A couple of days ago I was helping a good friend with a coding problem and he told me: "Don't solve it, tell me the strategy to solve it", this was the first time anyone told me that and it got me thinking... he was right, by solving every problem I'm not allowing the young programmers to learn and that gave me the idea to write this post.

I tried to think of the ways I deal with coding problems and I came up with several principles.

1. Always write syntactically-clean code

I often see people writing code with no coding standard (inconsistent indentation, spacing, etc...), and when I criticize them about it they say "I'm just testing something, it's not production code, bla bla bla...".

And when they ask me to help and I take a quick look at the code and tell them they're missing a semicolon or something like that they're amazed at how I do it.

Well... there's no magic to it, I'm just always writing my code as clean as possible (perfectly indented, consistent spacing between functions and parenthesis, etc... all according to a coding standard for the language I'm currently using).

Once you get used to always writing and looking at clean and consistent code, then whenever something is out of place, it just pops out.

2. Don't write large pieces of code without seeing if it works

(In a positive form: "Write code in small iterations of write-test-write-test...").

I'm constantly seeing people creating a new project and writing a lot of code without even compiling and running. The first time they try to actually run it they have no idea what's not working and have to go over a lot of code until they figure out what's wrong.

If you do have to figure out how to fix a large piece of code, the best way is to split the code to small chunks and check if they're working. Let's look at an example: People sometimes come to me with code like this (it happens a lot lately, I'm not sure why...):

  $('div.class1 a[href^=https://]')
    .doSomething()
    .doSomethingElse()...

To debug this you should use your browser's developer tools (FireBug, Chrome Developer Tools, ...). I personally prefer running test code directly in the JS console or adding console.log() calls as opposed to adding breakpoints (I don't yet trust JavaScript debuggers):

  • First, check the jQuery selector (in the browser's JS console), see if it returns the correct elements.
  • If it doesn't, you found your bug (or one of them :-))
  • if it does work, move on to "doSomething()", again, test it in the browser's JS console using the result of the selector
  • and so on...

The best habit for this is to use TDD/BDD which will force you to write smaller chunks of code in every iteration.

3. Solve the bug, not the symptom

I often see young programmers try to solve bugs by treating the specific symptoms described in a bug report instead of trying to understand why that bug is happening and what is causing it.

Make sure you understand the domain of the problem and the technologies used in the feature, because if you don't, you'll just cause more harm than good.

I hope you find this useful,
Until the next time,
David.

Comments

Itay Adler said…
Great post Dudi! keep them up :)
Boris said…
Hi,

I especially agree with 3. I often get a response of "just add a null check and return false" and I reply "But this method should never receive null as an argument in the current design". It is very important to understand the root cause of the problem before making a fix. My other motto is "if you don't know why it works it doesn't work". This is especially true when writing conditions. You write a condition, it doesn't work so you change AND to OR, add a NOT add another variable and it looks like it works but you don't know why. In these cases I simply delete the entire condition and write it all a new.

As for #2, I have a methodology that never failed me. BlitzCode but not in the sense of fast code. The German invented tactics stated that first you break through using a thin but strong line (like a needle) through the enemy lines and then expand from all directions. This is how I write code (especially if I have a big feature). First make a very small functionality work end to end, it can be a button that searches hard coded values in the database and then shows the result in a grid for example. This approach has 3 major benefits:
1) It reduces the frustration factor - You have something working you can show off very fast.
2) It allows you to make a better decision whether your design is good or not for the entire feature.
3) It allows you to reduce risk quite considerably early in the development stage (no nasty surprise when you discover that the grid expects the data in an entirely different way than the DAL retrieves it).

Sorry for the long comment.
Boris
David Elentok said…
Boris, I totally agree!
and thanks for the long comment :-)
nuit said…
i agree with #2: but,the length of the iteration should be proportional to your level of skill in this particular language and your time limit.
if you are fluent in a language you can write larger pieces of code without checking.
usually i have a console or another project file, to test small ideas and algorithms on it's own before i finaly implement them in a project. it's far more convenient than compiling and testing the whole software.

Problems i see with "blitzcode": you have to have in mind what you want to do. if you specialize on a particular feature without thinking about the rest, you will end up with a closed project and the rest will be fixing, patching and hacking. (hacking in terms of: trying to add something which was not planned)
such code looks always yucky and is never a good idea.
therefore: make a list, what you want to achieve and how.
catchword: test driven development

another long comment :-/
nuit
endrem said…
As for point 2, I think about it differently, rather like nuit said. It depends on your fluency in the given language, on the problem you are trying to solve and your understanding of that problem.

I do like to write big chunks of code when I implement new features and I have a clear picture in mind how I'm going to do it. I just write all that code, in certain cases even a day passes without compiling once. When I feel like the feature is ready for an initial test, I do compile and start testing. It is a great feeling when all that compiles on the first try and even better when it all works as expected. It doesn't make it much worse if you have to make a couple of adjustments here and there, but you manage to get it working quick. This alone makes it worth trying to wrap your mind around the problem at hand and implement it in one go. It helps improving your problem solving and coding abilities as well.

Another factor to this is how long it takes to get your project compiled and running. If it is long, like your project is too large, it forces you to think more thoroughly and compile less. You can consider writing a smaller test project, if it is a feature/problem that can be handled separately, but this is not always an option.

Long comment again, but I find them usually more useful than short ones :)
salty-horse said…
If you light a man a fire, he'll be warm for the night. If you light a man on fire, he'll be warm for the rest of his life.
danzat said…
I think you did not stress enough the problem of people not knowing how to use their tools and their platforms, this usually leads to reinventing the wheel and misusing tools in horrible ways.

And by tools I mean anything from the language you use, through the libraries and up to the editor and the OS.
Chris said…
With experience you get better at writing code that "just works" on the first run. And you get better at know which parts will "just work" and which parts should be write-test-write-test.
Anonymous said…
You sound so much like my boss/professor at grad school, I just had to say it.

Good post.
Anonymous said…
Copy and paste is a killer!!!
The amount of times I've seen people struggle because they missed one small change.

I also find it good to make the person talk me through each line of code, usually, about half way through the penny drops and they realise their mistake (usually related to copy and paste).

It has to be said though, sometimes it's hard to see the wood for the trees and a fresh pair of eyes can spot a problem in seconds that you've struggled with for hours.
Suyash Sumaroo said…
I specially agree with number 1. Many, and I insist, many people do not realise the importance of write clean and simple code. In my opinion, this could reduce the number of bugs by about 30-40%, or at least find them quickly.

Anyway, its a very good post - simple but very useful
Anonymous said…
Most of the "bugs" I have come across would be more accurately described as, "I forgot to tell you that it needed to do this." But you are right in that one needs to figure out the "bug" and then deal with it accordingly. One should never assume it is a missing requirement. Nor should one assume it isn't.
Anonymous said…
Great post but I nearly went blind trying to read it due to the color scheme - can you add some colors with more contrast?
TimSyg said…
Like endrem's "long comment" (which was very useful by the way), I too often find myself in need of writing a LOT of code before I can test (e.g. perhaps there are many interrelated methods that need to be written before I can test thoroughly). One trick I have learned is to have a second project set up to test smaller chunks of code where possible.
Anonymous said…
Boil the water in a large pot. Add a little sea salt, oil, and pasta freshly cut in long strips.
Always keep the water at an uninterrupted rolling boil, until done.
Test & test again, as you go along. When you think it is ready, throw a strand at the wall (or ceiling), and if it sticks & doesn't fall down, you are done (this is sometimes known as the tureen test, not to be confused with hanging).
You should just be able to get your teeth into it; not too hard or so soft that it falls apart when you try & pick it up. (If so, go back & start again.)
Add more oil - to keep it hot & stop it forming a solid mass - drain carefully, ensuring that none of it overflows the allotted colander, return it to the pan for a quick warm through.(If it's allowed to be really cool, it may congeal & take on an unpleasant new look.)
Plate up, add sauce & pass to the server. (Some may prefer to hang on to the sauce & pass it on later at a premium.)
Customers will demolish your efforts in no time.
Anonymous said…
I find that green dog urine helps when debugging
Solving coding problems will be handy because the code standards documents reveal the recommended methods that were tried and tested on the earlier projects. Thanks for sharing.

Web Design London UK
Fabio Araujo said…
TDD is really good, great way to test everything you do. Great post man!
I found lots of interesting information here. The post was professionally written and I feel like the author has extensive knowledge in the subject.

Popular posts from this blog

Restart the Windows File Sharing Service to fix weird problems

WPF, ImageSource and Embedded Resources

SharpDevelop dark color scheme