The Open-Closed Principle, for GUIs

Remember, systems should be open for extension and closed for modification.

September 9, 2021

Today's main task was adding database persistence to my tic-tac-toe app so that an unfinished game could be resumed the next time the application is opened. Up until today, the GUI has been roughly split into 3 screens/phases:

   +-->  Choose Grid
   |          |
   |          V
   |    Configure Players
   |          |
   |          V
   +------- Arena

Going through each of these phases is what constituted playing a complete game, at which point the cycle was restarted (until the player closed the app).

The first thing I did was sprinkle in TO-DO comments roughly where all of the database operations needed to take place. I was about to dive in and start adding database stubs to all the tests for those locations but it really didn't feel right.

Then I remembered that I had been very deliberate in applying the open-closed principle to the design of the GUI by dividing the code into phases corresponding with different screens the user would interact with. I could keep each phase (mostly) untouched and still be able to extend the behavior of the GUI by adding/removing/re-ordering the phases. At the end of the day, this is what the flow-chart of the application phases looks like (newly added phases in ALL CAPS):

 +----- RESTORE GAME
 |            |
 |            V
 |      Choose Grid <------+
 |            |            |
 |            V            |
 |    Configure Players    |
 |            |            |
 |            V            |
 |      ESTABLISH GAME     |
 |            |            |
 |            V            |
 +--------> Arena <--------|--> STORE TURN
              |            |
              V            |
        CONCLUDE GAME -----+

There's definitely more complexity in the diagram now, which required that each phase become very aware of which phase to transition to (given the right conditions) but this was a price worth paying. These new phases are very much concerned with database operations, not so much with GUI operations. So, in practical terms this means that the frames in which these phases are 'active' are essentially lost (I simply draw the redraw previous screen). Fortunately, in this case, high frame rates aren't the priority.