How to Write Less Broken Code

As we all know, I’m a professional dev and I write broken code.

I have found some ways to write less broken code though!

I apologize in advance for a somewhat lengthy post. It is mostly pictures of the same piece of paper and some code snippits, so I hope it isn’t to long of a read.

BLUF: Sketch out a plan with pencil and paper before you start coding!

Lets talk about the following challenge. WARNING! The challenge is somewhat technical, but it is representative of an actual function I needed to write.

You are given an array of integers offsets broken into numelements chunks of length elemsize. We call these chunks elements. Create a new array blockoffsets where the integers are permuted so that elements are interlaced by blocksize. That is to say, the first integer in the first blocksize elements will be next to each other, then the second integer in the first blocksize elements and so on. Pad the final block with copies of data from the last element.

Whew, that sounds messy in words. Lets make a small example.

If I have

offsets = [10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18]
numelements = 8
elemsize = 2
numblocks = 2
blocksize = 5

the desired output is

blockoffsets = [10, 11, 12, 13, 14, 11, 12, 13, 14, 15, 15, 16, 17, 17, 17, 16, 17, 18, 18, 18]

It’s still a bit tricky to understand. Here is a diagram:

# In this 1D example, the offsets are given by
# 
#  ________________________________________________________________________________________
# |  x --  x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x  -- x |
# | 10 -- 11  | 11   12  | 12   13  | 13   14  | 14   15  | 15   16  | 16   17  |  17   18 |
# 
# We block elements into groups of 5:
#  ________________________________________________________________________________________
# |                   block 0:                            |         block 1:               |
# |     e0    |    e1    |    e2    |    e3    |    e4    |    e0    |    e1    |    e2    |
# |                                                       |                                |
# |  x --  x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x  -- x |
# | 10 -- 11  | 11   12  | 12   13  | 13   14  | 14   15  | 15   16  | 16   17  |  17   18 |
#
# Intermediate logical representation:
#  ______________________________________________________________________________
# |               block 0:               |               block 1:               |
# |     node0:                 node1:    |     node0:                 node1:    |
# | 10-11-12-13-14        11-12-13-14-15 | 15-16-17- *- *        16-17-18- *- * |
# | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 |
#
# Permuted and padded output:
#  ______________________________________________________________________________
# |               block 0:               |               block 1:               |
# |     node0:                 node1:    |     node0:                 node1:    |
# | 10-11-12-13-14        11-12-13-14-15 | 15-16-17-17-17        16-17-18-18-18 |
# | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 |

The diagram makes things a little bit clearer. As is sometimes the case, describing the problem and understanding what is going on here is harder than solving the problem.

You are welcome to try this challenge. This isn’t from Free Code Camp. This challenge is from a supercomputer software library that I work on. (The interested can see it here) These sorts of coding challenges that you work on in Free Code Camp pop up in all sorts of useful contexts! In this case, I need to make blocks of size 8 to make full use of AVX 512 vectorization.

This challenge description isn’t great, but it’s what I had to work with when I needed to write this function. I wrote it in C, but I’ll go ahead and write it in Python this time.

The first thing I do is put away my computer and grab a sheet of paper. Seriously! The best coding starts without your computer.

Now I outline a simple example and some context for the problem.
image

With that out of the way, I can start outlining the inputs and outputs I need for my function.
image

Next, I write a general flow that my function needs to follow. I am adding some space so that I can put in pseudocode later.

Lastly, I put in some pseudocode.

As you can see, I did some erasing and some notes, but I think I’m finally ready to touch the keyboard! The sooner you leap to your keyboard, the more bugs you will write!

I’m going to start by writing the frame of the function and some comments.

def permute_pad_offsets(offsets, numblocks, numelements, blocksize, elemsize):
    # Loop over blocks of elements

        # Loop over elements in block

            # Loop over element size

    # Return new array

Whew, I’ve got the second hardest piece done. The hardest piece is debugging, but I’ll be able to debug much more easily now that I know what I’m trying to do!

Now I will start adding in some code. I’m adding spoiler tags in case you want to try this challenge at home!

def permute_pad_offsets(offsets, numblocks, numelements, blocksize, elemsize):
    # Initialize output - Python needs to know the length of the array
    blockoffsets = [None]*(numblocks*blocksize*elemsize)

    # Loop over blocks of elements
    for b in range(numblocks):
        # Loop over elements in block
        for e in range(blocksize):
            # Loop over element size
            for i in range(elemsize):
                blockoffsets[b*blocksize*elemsize + i*blocksize + e] = offsets[min(b*blocksize + e, numelements - 1)*elemsize + i]
                # Note - the min() adds copies so that we pad out to the vector length

    # Return new array
    return blockoffsets

I’ll be the first to admit that I glossed over debugging, unit tests, etc, here. There is a lot of work going from the comments to the final code. But it’s much much easier with a plan!

I hope that this gives you the basic idea of how I write less broken code!

You can see my final working solution in C here.

TLDR: Writing out a plan with pencil and paper will make your code less broken and easier to debug!

4 Likes

This is a great post for helping new devs learn how to write code with less bugs, thanks for adding it.

I do think the code example itself is going to go over a lot of peoples’ heads but your points are definitely valid.

1 Like

Agreed. The example is hard to describe. I’m trying to fix the description : )

1 Like

Hopefully the diagram makes this a little bit clearer now. I’m now remembering now how much difficulty we’ve had in describing this ‘interlacing’ to collaborators!

I picked this because it wasn’t a complete toy problem, but it turns out that it can be tricky to describe problems that aren’t complete toys.

Thank you for useful post! Plan, code, debug :slight_smile:

1 Like