Friday, March 13, 2026

How painting a full picture helps with finding the correct solution

In my work, I often see developers implementing solutions without getting the full picture first. This is a problem because it often leads to patches instead of proper solutions. Patches make the code harder to maintain because instead of having a solid foundation, bits and pieces are held together with band-aids.

The analogy


Let’s use the analogy of bicycles on paths.

There are bicycles coming from three different paths, and they all pass the same check point before continuing on their routes.

The paths represent the code flow, and the bicycles represent the scenarios that could happen.

The task


Imagine that this is your existing project. You are tasked with ensuring that if a bicycle comes from Italy, they need to have an Italian flag on them before passing the check point.

The way an inexperienced developer would approach this task is to only focus on the path from Italy. Since bicycles on that path do not have an Italian flag on them, they slap on an Italian flag before the bicycles pass the check point, at point D. So this scenario is fixed, and they declare that their work is done.

Here some of you might say, who would do that? It’s obvious you need to add the flag at point C. If you were thinking that, congratulations, you are right! But remember that this is an analogy, and these paths are not so clearly visible when you are looking at code. 

 

How to paint a full picture


As mentioned earlier, an inexperienced developer would just study the path from Italy and look for a place to place their sticker. But what if this inexperienced developer were a little more careful, and asked themselves whether this is the correct place to place that sticker? How would they determine which is the correct place along that path from C to D?

This is where they could ask themselves a couple of questions:
1. Is there anyone else going through this point besides bicycles from Italy?
2. Are there any other ways bicycles could come from Italy, without going through this point?

The first question ensures that they do not mistakenly add stickers to bicycles coming from other places.
The second ensures that they do not miss out adding stickers to any bicycles coming from Italy.

By looking for the answers to these two questions, they will actually be able to draw out the paths (i.e. code flow) above to better visualize the scenario, and then this drawing would help them say, “It’s obvious the sticker should be added here!”

This is why getting a full picture of the existing system is a must when working on a task. This step is crucial to finding a correct solution.

What if…?


About the questions that a developer may ask themselves, there is also a third question that some more discerning engineers may think of:
3. Will all bicycles going through this point, eventually go through the check point where we need the sticker?

To know whether this question is relevant, there is another question that needs to be answered first: What if the sticker is added to bicycles from Italy that do not go through the check point? The sticker may not be necessary, but would the presence of the sticker be a problem? The answer may vary for each scenario. (Example 1: If we need to hold a valid passport to cross the border to exit the country, is it okay if we hold a valid passport but do not exit the country? Example 2: If we need to wear a heavy winter jacket when taking a flight to a cold country, is it okay if we wear the heavy winter jacket although our flight is cancelled and we are staying in Malaysia? You decide…)

What do you think?

Do you apply this technique as a developer? What other techniques do you use to ensure that you are implementing a proper solution?

If you haven't tried this method before, give it a try in your next task; it might help you more than you think. 

Thanks for reading! 

Sunday, November 23, 2025

When developers forget to be developers

Oftentimes, I would be discussing a task with a fellow developer, and when an interaction scenario is brought up, they would say, “Okay, I’ll make sure to test that.” Their implementation seems to be targeted at handling the new functionality that is requested, and they have no plans of handling anything else unless something is detected not to work.

But a developer’s task is to develop a solution that will cover interaction scenarios. While testing is necessary, developers should first develop. 

Some interactions can only be found from the code. This is because they arise from the way the code is implemented, rather than the way the product is used. This is commonly the case for race conditions. While testers can carry out tests where they execute two (or more) functionalities at the same time to see whether everything still works properly, if they do not hit a specific timing, the tests may still pass when there is a bug in the code.

However, a developer can easily detect a race condition from the code, if only they were to think of the interaction scenario in the first place. Then they can handle the scenario properly. 

(I stress the “if” above because it often happens that detecting interactions is overlooked. But that would be a separate discussion…)

To all developers, take note: If a scenario works when you test it, but you don’t know how it works, you did not develop that solution. So remember to do your job as a developer!

Wednesday, February 12, 2025

The fear of updating existing code

In my code reviews, I often see engineers adding on to existing code even when a simpler solution is to modify it.

For example, take a look at this code:

void update_door_position(position_type position)
{
    switch (position)
    {
        case OPEN:
            set_door_opening(100); // fully open (100%)
            break;
        case SLIGHTLY_OPEN:
            turn_on(30);
            break;
        case CLOSED:
            set_door_opening(0); // fully closed (0%)
            break;
        default:
            break;
    }
}

The function allows us to request three different positions for a door, and it adjusts the door opening accordingly.

But sometimes the initial implementation does not have so many positions. Sometimes the first version of the code is simply this:

void update_door_position(bool open)
{
    if (open)
    {
        set_door_opening(100); // fully open (100%)
    }
    else
    {
        set_door_opening(0); // fully closed (0%)
    }
}

Here the door starts off with only an open position and a closed position, and then comes an additional request: “Sometimes our users would like to open the door just a little bit to let some air through, instead of opening it wide to walk through.”

This is where I see many engineers end up modifying the code into this:

void update_door_position(bool open, bool slightly)
{
    if (open)
    {
        if (slightly)
        {
            set_door_opening(30);
        }
        else
        {
            set_door_opening(100); // fully open (100%)
        }
    }
    else
    {
        set_door_opening(0); // fully closed (0%)
    }
}

Even though this code does the exact same thing as the first chunk of code above, it is bulkier with more parameters to handle. Every time we want to call this function, we have to decide the value of two parameters instead of just one.

But what I find is, if the same engineers were asked to write the code from scratch for the three door positions, many would have written the first code above.

There seems to be a general reluctance to touch whatever has already been written (especially by someone else). Instead, flags are added here and there to achieve new functionality. However, this is not a good practice because it creates a code that is more difficult to read and to maintain. Imagine if more positions were added later for the door; how many flags would we use then?

When editing code, it is better to think about how the code should have been written if the new functionality had been there from the start. When we read code, we want to know what the code does right now, and not how many different phases had been used to add new functionality to the code. So we should write code that gives that kind of information, as simply as possible.

How painting a full picture helps with finding the correct solution

In my work, I often see developers implementing solutions without getting the full picture first. This is a problem because it often le...