Learning Outcome 11th - 18th Dec 2020
Introduction
In this talk by Rafal Ditwald on Solving problem the Closure way, he attempts to distill the particular blend of functional and data-driven programming that makes up "idiomatic Clojure", clarify what it looks like in practice (with real-world examples), and reflect on how Clojure's conventions came to be and how they continue to evolve. I have captured and aligned what I learned from his session into refactoring my TicTacToe game to reflect this approach.
What is Functional Programming essentially about?
Avoids using state, pass functions around, thinks of the program as input/output(what is the data we are expecting and how do we transform that data)
Functional programming avoids the mutating state by
Minimizing _ Less state, less value to keep around, Lets only have little parts in code that change values, reduce the number of places we do side effects. How do we minimize?
Derive values - states that you want to keep, but you can actually avoid it eg: keeping track of whose player’s turn it is in a Tic Tac Toe game when you can get that by determining how many grids(cell) are taking
Copy instead of Mutate-in-place - E.g you can derive a new array from a previous array and perform an operation on the new array without affecting the previous array
Using Anonymous functions: Create functions dynamically that will remember values in their scope. Like Lambdas and higher-order functions that recursively handle an operation under the hood.
In my
TicTacToe
Board class, I minimised with the `hasWinner` function where I separated concerns(rows, columns and diagonals). From my previous implementation we were overly mutating state. this is what
2. Concentrate_ if we have a value, let’s keep them in one place rather than throughout the program, If we need to have mutations, let’s keep them together rather than spread throughout the program, concentrate on the places we do side effects.
I concentrated by extracting the inbuilt readLine interface from the
askUserForMove()
andaskToPlayAgain()
(nowaskToRestartGame()
) into aCommandLineIO
class. With that I now have one source of truth for CLI interaction I can re-use.
3. Defer _ Defer mutating states or side effects to possibly the last step of the program, or to a completely separate system
Bonus:
A. I also minimized with the print board(now constructBoard()
) by making a copy of the 2D board returned by the rows()
function and constructing a new flat board representation with strings 1 - 9 which is been rendered in the console.
What are some pros of the Functional Programming approach?
Pure functions are good and Functional Programming is the ability to program with as many pure functions as possible and figuring out the details
Pure functions are easy to test
Pure functions are easy to understand
Pure functions are easy to use
What makes pure functions easy to understand, test, and use?
Well I will simply say because they do not have side-effects, they always return the same result giving by the parameter passed and they don't depend on or modify state outside their scope.
Data-Driven Programming
What is Data-driven programming?
Data first approach
It is better to have a common simple way of transferring data around your system rather than typing it all
Configuration driving development - Store your code as data and
So one will as what does data first mean? It simply means that the data itself controls the behavior of the program and not the program logic
More Explanation into the IO interface
Challenges
I figured out some of these challenges with the help of my mentor's feedback and some over our sync while pair programming.
Dependency Injection
Dependency injection is basically providing the objects that an object needs (its dependencies) instead of having it construct them itself. It's a very useful technique for testing since it allows dependencies to be mocked or stubbed out.
Dependency Inversion
A class should depend on abstractions (e.g interface, abstract classes), not specific details (implementations).
Cohesion and Coupling
Cohesion is a way of describing how closely the activities within a single module are related to each other.
Coupling is used to refer to the degree of interdependence among the different parts of a system.
Law of Demeter
The Law states that a module should not have the knowledge of the inner details of the objects it manipulates. In other words, a software component or an object should not have the knowledge of the internal working of other objects or components.