Game of life inspector

✒️ DescriptionAn IDE-integrated tool for visualizing Game of Life board states that maintains the visual representation and the code in sync.
⚡ TechnologiesKotlin, LivePlugin system for JetBrains IDEs, Python
🗂️ Source CodeGist with Implementation

Self-documenting code: how?

In many of the courses I’ve taught, we talked about the importance of self-documenting code[1]. Developers are often tempted to introduce explaining comments in their code, when they could have made the code more readable, eliminating the need to put the comments in.

The problem with comments is that they’re not fully connected into the software we are making. A consequence of this is that the program implementation can diverge away from the comments that refer to it, leaving them outdated. There are large-scale studies[2] that confirmed that, in most cases, code and comments do not co-evolve.

The usual advice given in these cases is to refactor the code by extracting some variables or methods, and improving names. While this is often enough, there are situations where something else might be needed.


On one occasion, we were implementing Conway’s Game of Life as a Test-Driven Development exercise, using Python. A typical test can look like this:

python
game = GameOfLife({
    Position(1, 3), Position(1, 2), Position(2, 1)
})

game.advance_generation()

self.assertEquals(game.alive_cells(), {
    Position(1, 2), Position(2, 2)
})

The problem is that the starting and expected end state of the board are not obvious only by reading the code. One must look at the coordinates and imagine the board, acting like an interpreter of the program. Of course, this is problematic because parsing the board state by hand is not the problem we’re trying to solve whenever we look at the tests… and having to do it manually is both tiring and error-prone.

So, how could the code be written so that it’s self-documenting, with the same expressiveness that we could have by looking at a diagram? Is it even possible to do it?

Well, one option could be to write a comment describing the state of the board in each case:

python
game = GameOfLife({
    # - - - -
    # - - * -
    # - * - -
    # - * - -
    # - - - -
    Position(1, 3), Position(1, 2), Position(2, 1)
})

game.advance_generation()

self.assertEquals(game.alive_cells(), {
    # - - - -
    # - - - -
    # - * * -
    # - - - -
    # - - - -
    Position(1, 2), Position(2, 2)
})

However, despite this being easy to do, we obviously have the main inconvenience of comments we’ve discussed before: nothing prevents them to expressing something different from what the code does.

💭 You can think about this problem before reading on.

A possible tool

As I was thinking about this, fantasizing about what the best solution could be, I thought about the possibility of making an integrated tool to inspect code that defines a set of positions. So, I got to work and made a series of prototypes; here I’ll show you the last one.

When your cursor is inside a set literal that has Positions as elements, you can inspect the expression to see a representation of the board: An animated GIF showing a usage example of the tool. When selecting an expression and choosing to inspect it, the tool depicts a grid with alive cells at specific positions, such as (1, 3), (1, 2), and (2, 1), based on the inspected expression.

You can also interactively change the alive cells —i.e. the positions that are elements of the set: An animated GIF that shows that if you click on the shown cells, their state is toggled between alive and dead (by adding or removing them from the set).

As a result, this provides the best of both worlds: a visual representation of the board that’s based on the actual code (and therefore cannot diverge and become outdated), and a back and forth connection between the graphical view and the textual view.

The tool works for Python in the JetBrains’ IDEs (like IntelliJ). I programmed it in Kotlin, using the LivePlugin plugin to be able to develop it interactively. The source is available here.

A different way to tackle the problem

Another option to solve our original problem could be to make a test-specific mini-DSL[3] to express the board states:

python
game = self.game_with_alive_cells("""
    - - - -
    - - * -
    - * - -
    - * - -
    - - - -
""")

game.advance_generation()

self.assert_alive_cells_in(game, """
    - - - -
    - - - -
    - * * -
    - - - -
    - - - -
""")

In this case, we’d have to implement methods for game_with_alive_cells and assert_alive_cells_in so that they parse the provided string and create the necessary sets of positions. With this, we’ve also created a view so that the result of the code is not independent of the representation (therefore preventing inconsistencies). Of course, the parsing logic should be tested separately.

One characteristic of this approach is that the interface that we’ve defined to see the board state is text-based. This gives us an advantage in terms of easiness of implementation: the tools we have and are accustomed to are text-based, and the APIs offered by programming languages implement lots of useful text-manipulation functions. However, this also constraints us: we cannot interact with the view except through text-manipulation commands, and cannot implement more complex views that don’t map well to a text representation.

Closing remarks

We started by exploring some considerations regarding a specific case where the popular advice of “writing self-documenting code” and “avoid code comments” is not immediate to implement. One interesting aspect of this exploration was the possibility to think about better integrated tools, that are tailor-made to tackle a specific problem. The contrast of the two presented solutions gives us material to think about the bias we have for text-based tools.


  1. A definition of self-documenting code can be found in the C2 Wiki:

    Code that allegedly explains itself without the need for extraneous documentation, like flowcharts, UML diagrams, process-flow state diagrams, etc.

    ↩︎
  2. Such as the article from F. Wen, C. Nagy, G. Bavota and M. Lanza, “A Large-Scale Empirical Study on Code-Comment Inconsistencies,” 2019 IEEE/ACM 27th International Conference on Program Comprehension (ICPC), Montreal, QC, Canada, 2019. PDF. ↩︎

  3. DSL means Domain-Specific Language. In this context, I’m referring to a text-based representation of the state of the board (using specific —albeit very simple— syntax inside a string literal), in order to make it easily readable. ↩︎