I solved the following Mars Rover kata focusing on the design.
Develop an api that moves a rover around on a grid.
- You are given the initial starting point (x,y) of a rover and the direction (N,S,E,W) it is facing.
- The rover receives a character array of commands.
- Implement commands that move the rover forward/backward (f,b).
- Implement commands that turn the rover left/right (l,r).
- Implement wrapping from one edge of the grid to another. (planets are spheres after all)
- Implement obstacle detection before each move to a new square. If a given sequence of commands encounters an obstacle, the rover moves up to the last possible point and reports the obstacle.
I am not interested in describing each step that I implemented to solve this kata, as you could check each commit on the history. Instead I will point out the most interesting parts.
From the beginning it was clear to me the relevance of using an Enum for the directions, since some business logic should be wrapped in it - even though it was not obvious how it was going to be used when I started.
The first version was something like:
An interesting functionality was the direction inversion, which I refactored as:
I did not feel a good design that the responsibility to move the Rover was in Coordinate. AFAIK, a coordinate should only define a pair of points in space.
So I refactored it by decoupling the responsibility to move the Rover between Direction that decides where to move, and Rover which decides how to move.
I ended up with something like:
As you can notice, it is the Direction which is responsible for where to move and how to rotate.
Then the rover adds the logic of how to move as:
To me it makes sense that it is the rover who decides how to move. And it is the Point which has the logic to get to the next point, increasing or decreasing, solving the problem of wrapping from one edge of the grid to another.
If you have other thoughts or comments, please post them, I would be really interested in seeing other solutions.
The Point has the responsibility to get the next Point and for wrapping:
Once I started to add the obstacles, it became clear that the decision to add the World/Planet/Terrain concept was right. It was easy to add the obstacles having a World which contains them, the limits of the World and the coordinates of the Rover.
At the end the rover is moving in a surface.
I am pretty sure that using DDD helps me to decouple the responsibilities and makes the code more expressive.
Recently a well-known friend Felipe told me a sentence which I think it is very interesting
“70-90% of the time we are reading code and only the rest we are coding.”
so why don’t we build more expressive code to avoid spend a lot of time to try to figure out what it is actually doing?
The full source is on a github repo mars-rover
Please post your solution as a comment so that we can compare different ways to solve it.