Published on

A Simple Bug Hunting Formula

Authors
A green bug camoflauged to symbolically reference the inevitable bugs written during the process of software development.

Photo by David Clode on Unsplash.

Assuming you have working software, as a developer, you hunt for bugs pretty much all the time.

A 40+ year developer himself, my father-in-law once told me that (paraphrased)

writing software is writing bugs.

So let's dive into a quick and simple algorithm to hunt for bugs successfully, which I just used this morning.

Fixing my buggy Asana task code

At Tincre we let people and businesses become digital ad agencies overnight. We abstract pretty much everything it takes, aside from setting up the LLC and making the initial client sale. It's pretty cool.

But ads are a minefield and many parts are still completely manual, human processes, when done correctly.

For these manual pieces, we leverage software to supercharge the manual process, making Tincre humans more efficient. Task management is a big part of that. In recently switching from Gitlab to Asana for task management, I wrote a small but annoying bug in how we generate content for ensuring ad campaigns are stopped. Let's dig in.

The bug

The code below creates a simple dictionary with two string parameters, title and content.

These populate our tasks over at Asana. In particular, our "stop" campaign tasks were missing an f-string, a string substitution feature within Python, in case you're unfamiliar.

Find below a simplified version of the buggy function.

def generate_asana_task_content(
    task_type: str,
    campaign: schemas.InternalCampaign,
):
    if task_type == "stop":
        return dict(
            title=":octagonal_sign: STOP {campaign.adTitle} - {campaign.pid}",
            content=generate_asana_task_html(campaign),
        )
    if task_type == "create":
        return dict(
            title=f":mega: CREATE {campaign.adTitle} - {campaign.pid}",
            content=generate_asana_task_html(campaign),
        )
    if task_type == "delete":
        return dict(
            title=f":fire: DELETE {campaign.adTitle} - {campaign.pid}",
            content=generate_asana_task_html(campaign),
        )

See the bug? The "stop" tree title parameter is missing an f-string, so our Campaign schema object doesn't substitute the campaign.adTitle or campaign.pid (Promo ID) information within the title string.

Tsk. Tsk. But at least we found the bug. Okay, so let's just add a little f right before the string, push changes and move along with our day.

Wrong!

Write a "bug" test

Instead of fixing this right away, we leave it open in our editor and open up the test_asana.py test file.

Our objective is to write a test that fails for this exact issue. Below is an example of that test.

assert (
    internalCampaign_schema.pid
    in asana.generate_asana_task_content("stop", internalCampaign_schema)[
        "title"
    ]
)

Now run your tests and ensure that your suite fails.

Fix the bug, pass the test

Now we go back to our buggy function code from above and add our f prior to the string in the "stop" tree title parameter, e.g.

...
  if task_type == "stop":
      return dict(
          title=f":octagonal_sign: STOP {campaign.adTitle} - {campaign.pid}",
          content=generate_asana_task_html(campaign),
      )
... 

We save that file with :w; oops, you don't use vim? Why not?

Now run the test. It passes! Hooray!

You're done

Now commit, push, pass your CICD suite, and deploy. Go have a coffee. Have some lunch.

Hunt for or write more bugs. In short, get on with your life.

✨ Lastly, check out Promo, by Tincre to add a marketing agency to your app, site, or platform. ✨