TLDR; Comparing implementations is not done to criticise, it is done to learn, and understand that different motivations and end goals create different code. Different models of the application, lead to different code. The programmer implements models of the domain, and behaviour, as code.
In this post I am going to compare the code and implementation approach to see what we learn.
Angie invited me on to her weekly live stream, and we discussed the implementations (and a bunch of other stuff) in the live stream embedded below:
Time To Create
Both implementations, in terms of coding time, are less than an hour, and probably less than 30 minutes.
Also, when ‘thinking aloud’ during coding, and trying to explain what you are doing and thinking takes longer, and can lead to coding mistakes, losing train of thought etc.
So neither videos actually show what coding approach is really like. But both come in ‘fast’ which makes them good examples of Tactically automating to get something working, which can be built on later.
Both demonstrate that the chosen technologies can be used for experimenting, prototyping, and exploring.
When you look at different code implementations they often differ based on.
- Requirements Implemented
- Models Used
- Implementation of Models
Neither solution had formal requirements, so the requiremnts listed here are ‘aims’ derived from watching the videos and reading the blog posts.
At a high level both implementations have the same stated requirement.
- play the game of Tic Tac Toe at PlayTicTacToe.org using a specific technology
But the interpretation of that requirement is very different. Which leads to very different solutions.
The interpretation of this requirement for the Java implementation has a lot of additional implicit requirements:
- play the game, reporting information to the human observer
- demonstrate various coding approaches to teach the viewer
- demonstrate use of the tooling and research during the coding
- prototype a ‘tool’ that could be run as an external executable
This adds more of an application structure to the implementation.
- simulate playing the game
One of the biggest differences in the solutions relates to the modelling of the Application Under Test.
- ignores all concepts of the Tic Tac Toe or Game Domain
- views the application as a simple state machine
- treats the application as an event handler
The Java implementation:
- models the game board
- models the Tic Tac Toe concept of a ‘space’
- models the concept of a ‘game’ (winner, loser, over, start)
- models the concept of an application to Play the game
- the application main method actually models playing the game e.g. 5 plays, etc.
The underlying models change the shape of the solution and its implementation.
The Java implementation would be potentially easier to:
- build on to add a ‘find best position’ strategy
- write Unit tests for
The Java model is much more ‘programmer’ and ‘reviewer’ friendly, and is better positioned to build on.
The differentiator here is that the Modelling was driven by the aims or requirements of the solution creation exercise.
The Java implementation was also influenced by the need to explain how to write an implementation that plays the game.
It leads to an implementation that could be used on almost any game that relies on clicking on stuff randomly.
To amend to other implementations we change the locators to identify the end state and the clickable items.
It would be harder then to implement any domain assertions. e.g. did we win? did we click in the right place? did any game rules become violated during gameplay?
Since none of this is in the model, we can’t assert on it.
When we automate more strategically modelling the domain helps.
Because we can compare the model of the domain, with the actual running implementation to assert on the validity of the model. i.e. is the application ‘working’.
The Java implementation models the domain.
This allows the Java code to tell the user if they won or lost. And enables expanding the code to automatically assert on conditions in the gameplay.
Modelling the domain in code can lead to more abstractions which can protect us from change when the implementation changes. i.e. the underlying domain might not change, so some parts of our automated execution code do not have to be amended, only those parts of the code which map on to the changed domain actually change.
e.g. the game of tic-tac-toe will never change, so if we have a model of the ‘game’ then we can apply it regardless of the implementation. The parts of the code that would change relate to the implementation e.g. how does the implementation tell us that we ‘won’, or ‘lost’, how do we ‘play a cell’. This can make it easier to maintain longer term.
The Java code has more resilience in the face of a changed implementation.
Understanding if our code is tactical or strategic allows us to review it in terms of:
- did we go far enough?
- did we go too far in modelling the domain when we don’t need to for the activity we are doing?
- have we made our code more complicated than it needs to be?
- have we created a sub-optimal implementation that will be hard to build on?
Looking at different implementations also helps us to make appropriate decisions when coding:
- are we adding additional risk to the project due to our approach?
- do we need to create a separation between the domain and implementation models?
Automation vs Test Automation
Both are examples of “Automation” or “Automating” rather than “Test Automation”.
The are designed to automate the system, rather than provide specific information to support testing.
They could both be used to support testing, i.e. by having a human observer monitor the application, or memory usage etc.
The Java version has created abstractions that could be re-used from
@Test methods to create automated execution with assertions specific for “Testing”.
Automating can be a completely separate activity from Automating to support testing.
I prefer to think of Automating as a completely separate activity. But one which I often use in the context of a testing effort.
Too often automated execution solutions are so tied to ‘testing’ that they can’t be used for anything else e.g. when the automating is heavily tied to a framework such that it can’t be re-used.
This is partially biases from the programmers i.e. each will have a preference.
The Java implementation has the choice of XPath or CSS, or a combination of both at different times.
document.evaluate was brought to my attention by Alex Riviere in a comment to the blog post.
I would still lean towards CSS because I do a lot of web development as well, and I think programmers I work with understand CSS more than XPath. But it is great to know I have that option available to me.
And this is one reason why we share what we learn, so that other people can comment and help us learn even more. Thanks Alex.
Different technology platforms can restrict our choices.
This is because the execution is not being used to detect errors, so will ignore any errors encountered.
I encourage you to:
- review both implementations
- compare the coding styles with your own
- is there anything you need to look up and learn?
- is it different from how you would code?
- Experiment with the implementations
- code for both is available
- run it, and try it for yourself
- amend it and see what happens
- change it to match your coding style, did the style make a difference?
Ultimately, I encourage you to create your own implementation and communicate it to others because the more implementations people see, the more we learn, and the more possibilities we have open to us.