This post follows on directly from Going Functionally SOLID
In our first session looking at SOLID and functional programming, we tried to apply some SOLID principles to an example piece of code.
We ended up with a set of interfaces like those below, and robot classes could then implement the interfaces to define their capabilities and state. I mentioned the example code was for a giant robot game, yes?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
For anyone who's worked with SOLID OO code before, this should be looking fairly familiar, and it should be obvious how you could build a class that accepted implementations of these interfaces in it's constructor and then carried the state of the robot (location, hits remaining, etc) around as mutable fields.
But… this is a turn based game, and we've decided that we want to use a minimax approach to choosing moves for the computer player. Minimax is effectively a tree search, which means that implementing it looks like it would be a prime moment for a bit of concurrency. Each branch of the tree can be calculated independently, after all.
Unfortunately… our SOLID OO approach is not looking very thread safe. Functional programming revolves around the idea that code is referentially transparent and that data types are immutable. These two properties immediately lead to thread safe code.
So the rest of the session was spent trying out how different parts of the API code be modelled in a more functional way - splitting out state into separate immutable value objects, using functions in the place of single method interfaces and playing with discriminated unions (not strictly functional programming related, but they do seem to crop up regularly in functional style languages).
The end results, raw from the discussion, are below. A bit of a mix of the "interface" and experiments in how you would use it. I think it came out quite nicely, showing how all of the SOLID principles (apart from maybe "L"!) fall out naturally in nicely designed functional code just as they do in good OO code. In fact some of them, such as "Interface Segregation" and "Single Responsibility" are things you almost have to work to avoid - they both fall out naturally from passing around pure functions to implement behaviour.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
|
Enjoy, and comments welcome - this was live coded in a group environment, so I'm sure plenty of opportunities for nicer code were missed!