Getting Started with Functional-Style Programming
I was talking with my friend Chris after watching high-school football, and the topic of functional programming came up. If you’re just getting started with functional-style programming there are a few easy wins right off the bat you can start using.
Step One: State is Evil
State is Evil. State is the Devil. State is the destroyer of sleep and deadlines. If you only try one thing, recognize this fact.
It is a necessary evil- you won’t get very far if you don’t keep state somewhere, but within your domain objects and calculations you want to be very conservative about where and how you keep state.
Unnecessary state is evil primarily due to how it introduces order dependency.
What happens if you change the order of those operations? Can you bingo the bongo before froobing the flanger?
At first keeping state in your object ~feels~ helpful by reducing parameter lists but it quickly leads to bugs and is a maintenance nightmare. Let’s pretend that yes, indeed, you have to froob the flanger before bingo-ing the bongo.
In a functional style, you state your order dependence (state dependence / data dependence) via the function call stack.
$obj->bingo_bongo( $obj->froob_flanger() );
Now, ask the same question again. Can you bingo the bongo before froobing the flanger? Not unless you can get the froob data from somewhere else. GASP! This leads directly to the next point.
Step Two: Explicit Dependencies
$obj->bingo_bongo( $obj->froob_flanger() );
Before, the object contained state that was modified by different functions. Now, you have all the same code in that object but you’ve explicitly declared that bongos depend on froobing.
This makes maintenance easier as well as making things more modular. All of a sudden you can get that froobing data from some other place because bingo_bongo doesn’t care where it comes from, only that you pass it what it needs.
The generic term to look up here is “dependency injection” or “DI” as an architectural decision. For now I’ll gloss over it and just suggest that you should understand what it offers and consider how it might be applicable to your use cases.
Step Three: Testability / Idempotent Operations
Yes, idempotent. The $0.10 word that basically means “you can test it”.
If you know that the output of a particular function depends only on the input that you give it, it becomes trivial to test. If you know that function doesn’t modify any state (indeed - if it can’t modify state) then you can call that function as many times as you want and not have to worry.
Let’s go back to our example above:
$result = $obj->froob_flanger();
This function doesn’t take any arguments. If it didn’t depend upon state, it would always return the same value, meaning you could just replace it with a constant. Obviously it’s doing something or depending on something but:
WHAT STATE DOES IT DEPEND ON? WHAT STATE DOES IT MODIFY?
Right now, it’s impossible to tell.
Let’s pretend it depends on a username and password:
$result = $obj->froob_flanger( $username, $password );
Aha! Now we can test it. Now it’s idempotent (output only depends on it’s inputs - it can be run as many times as you’d like with the same effect).
Does the function verify the user is logged in? Does it check password strength? Does it change the user’s password?
Well, if you’re truly trying to be functional, you’d say it can’t depend on accessing the database because you’re not specifying it as a depedency in the argument list:
$result = $obj->froob_flanger( $db, $username, $password );
But in any case it is infinitely easier to test what the function does and that it works properly when you can simply change the arguments and call it a few times in a row. The setup / teardown requirements for testing are simpler and easier when you write your programs in a functional style.
Step Four: Naming Conventions
On a final note, I would suggest some simple naming conventions to make it more clear what’s going on in your program.
“do”, “get”, and “calc”
You cannot avoid modifying state, but you should always defer to the caller, let the caller choose to modify state or not, not you. This basically means your libraries get split up into two types of functions - those that modify state, and those that do not.
Prefix the ones that modify state with do and use some other verb that means “just returning what you told me to”.
$obj->do_bingo_bongo( $obj->get_froob_flanger( $username, $password ) );
Now, you can see the structure and dependencies in the code immediately.
You know there are three discrete actions which most likely have an ordering dependency.
You know that froob_flanger depends on $username and $password.
You can validate that get_froob_flanger works right in all your major test cases simply by calling it a few times with your requirements.
You can switch out what do_bingo_bongo operates on by simply calling it with a different function.
You can validate that do_bingo_bongo does the right thing simply by calling it with static data. There’s no need to set up a whole request chain, just validate that do_bingo_bongo( 1 ); do_bingo_bongo( 2 ); do_bingo_bongo( 3 ); all do what you want.
And you can sleep a bit better know your code is testable (hopefully tested!), and easier to maintain.
20:07 CST | category / entries
permanent link | comments?