Being able to reduce complex problems into smaller units is a crucial skill every programmer should have under his/her belt/skirt. Reducing won’t always solve your problem, but it certainly does help you to narrow down the problem and solve logical issues, bugs and all sorts of things relating to programming. So what exactly is Reductionism?
Reductionism (Quote: Wikipedia): Can either mean (a) an approach to understanding the nature of complex things by reducing them to the interactions of their parts.
So really folks when we talk about Reductionism as it relates to programming, what we are really talking about is a scientific method of fault-finding. Often used in debugging or to pinpoint the root cause of an issue.
Before I go any further I would like to say, it is likely you’re already a reductionist, you might not have put a label on yourself, but very few developers get far without being able to break down a problem into smaller units. If you are in the habit of doing this, you might still pick up some tips here and there by reading this article.
How many times has someone come to you and say “It doesn’t work”. You might reply “have you tried this” or “have you tried that”. You might make these recommendations without thinking. But lets take a closer look.
Let’s step out the programming box for a minute and think in general computing terms. Why is it that some people can’t install software / updates / an operating system? You would think anyone would be able to insert a DVD and click next a few times, but a great deal of people won’t even try.
Lesson 1: Confidence
If you’re ever going to solve a complex problem you need to have confidence you’re the right person to solve the problem. You might base this on your general programming experience, and a lot of the time confidence might not even be an issue. Yet there are times when even an experienced developer hits a brick wall. Often this happens on unfamiliar systems or frameworks, or languages and technologies. When you’re outside of your typical development comfort zone. You need to exert more confidence to overcome the problem.
Lesson 2: Time
Time. It is crucial to acknowledge that Reductionism as a science takes time! The more complex the problem, the less familiar you are with the environment, the more variables and systems in place, and the more unknown leads to potentially more time being taken to find the root cause of an issue. Do not be intimidated by the time it could take you to find causes for particularly stubborn issues!
If reducing could take a physical form, it would definitely be a tree. A tree with branches and children. Just like the ones you’re used to programming against. You might start by mentally mapping out the possible causes in your mind, and explore each avenue (or branch). You do this to form constants and establish grounded assumptions. You might start off trying to solve the problem with an idea of how long you think it will take. Be prepared to invest MORE time than you initially had in mind.
Lesson 3: Cover ALL ground
This is one for the more experienced developers. Here your experience works against you. You see a junior might not make the same assumptions you’re making because the junior thinks to himself “I know very little about everything relating to this problem, so I’ll try explore everything”. The seasoned developer might say “It couldn’t possibly be that!” or “I’m 99.9% certain it’s not this”. And as a result might not explore those avenues (branches), even if they were easy to explore.
Sometimes it is good to check everything just in case, but I’ve found recently that in fact those just in case branches of exploration were infact where the problem was. I would have sworn before a judge I was 100% sure the problem could not exist in “this input” or “that function”. Yet after exploring everything else, having gone back to assumptions not based on “scientific reduction” but on “my assumptions”, I found the issue right there! I would say “when in doubt”, but instead I’ll rather say “Check it anyways”, take off your experience cap, and treat every branch of exploration in its own merits as it relates to the particular problem you are facing.
Lesson 4: What is an assumption?
An assumption is an ESTABLISHED FACT! Every established fact needs to be verified. For example you might be working on a problem where you have a data type mismatch. If you’re expecting an integer, and you’re sure your function returns an integer then you have an assumption. You can’t mentally assume anything, scientifically you have to verify it to be 100% sure. How do you do this? You’ll test it! If you don’t test it you could end up with weak assumptions.
Lesson 5: What are weak assumptions?
Weak assumptions are assumptions that have not been tested at all or not tested conclusively. Sometimes it just isn’t possible to test every single scenario, so at times it is valid to fault find based on weak assumptions. For example, you might have 3 functions and you don’t know which one is causing a problem, but without testing anything, you suspect one function over the rest as the cause. You base this on the error message and what the role of the function is. The problem might exist elsewhere, but to test in a pure procedural way would (in your opinion) waste time. You could be right, or wrong. This is how it goes when dealing with weak assumptions. They are not evil, but just be honest with yourself about any assumptions you make. If it is weak, and you’re going ahead anyway, remember to return to these weak or weaker assumptions as you progress and still not able to solve the problem.
Lesson 6: Never give up on a problem with easy to verify weak assumptions in place
Depending on your problem you might not be able to verify every weak assumption. But those that you can – DO IT! Before you completely give up on the problem and start looking for a workaround, or completely leave it unsolved. It might take you a few extra hours to work through these, make a list of them, and assert them all.
Lesson 7: Reduce with some intelligence
Plan a bit upfront. Use some paper if you have to. Make notes! If the situation calls for it, write down the environmental details at the time. It could be that you’ll end up taking 10 or 100 or 1000 steps to eventually solve your problem. Try to improve your technique as time goes by, and there is one good way you can do this and this is to think of any problem as a tree with branches and sub branches. Sometimes the more you drill down the more complex things get. Sometimes you want to explore more obvious branches first, depending on the knowledge you have on any given system. Sometimes you’ll try explore just about anything to get more clues. As you progress on a problem, learn to re-evaluate on the fly.
Don’t give up too easily. Make sure you have a clear head when reducing. Get excited about solving the problem, and celebrate considerably when you so finally solve it.
Using the internet: forums, Q&A sites is NOT CHEATING. Your ultimate goal is to (a) solve the problem (b) gain knowledge of the problem and systems involved (c) refine your method of reducing.
This is a good holistic view, each and every problem you face is experience that will help you solve the next. Just remember to avoid in the box thinking, and good luck.