- Posts tagged functional-programming
- Explore functional-programming on posterous
In Favour of Test Driven Development
"It sounds very mechanical, but the effect is the exact opposite. What it does is free you to write. It liberates you to write."
John McPhee on having a system to write to.
"Art is freedom; and in art, as in life, there is no freedom without law."
Martin Amis on the importance of having rules and a code of conduct.
While referring to literature, these quotes resonate strongly with my feelings on writing software (JavaScript in particular) Imposing constraints on the process leads to greater clarity of thought. In writing: correct grammar, consistent style and brevity; in code: strict lint rules, clear design and, again, brevity.
Test Driven Development (TDD) is another self-imposed constraint. The following relates to a recent StackExchange Podcast, who's hosts are not enthusiastic about its supposed benefits and have evidence to back up their assertions.
"[...] a survey of all of the studies that have been done on TDD have shown that the better the study done, the weaker the signal as to its benefit."
A small concession is made that, for the majority of projects, TDD is poorly understood and executed. In which case I agree; used for its own sake or inappropriately: TDD has little value. For example, retrofitting unit tests misses the point entirely.
Used on functional, self-contained, code (JavaScript, perhapse) TDD provides constraining benefits that free the developer to solve their problem. Thinking about and exploring a solution is never a waste of effort, writing a test is a chance to frame a problem with greater clarity. Each test further tightens focus on the task. Each test is a tangible step forward, a possible break point and a starting point for the next push.
TDD has little benefit when interacting with existing APIs (DOM interactions, UI or web services). Only code, over which the developer has complete control (new, independent functions), can be discovered creatively. Otherwise the tests are simply a collection of roll-played guesses. The do not clarify the author's thoughts and intentions, instead they can easily reinforce her misconceptions.
"The fact is that everything I've written is very soon going to be absolutely nothing - and I mean nothing."
John McPhee, again, on leaving a legacy.
If it isn't providing satisfaction or feels like a drain on progress then TDD is counterproductive. In the hands of a developer who enjoys the process it becomes valuable aid.
Functional, TDD JavaScript (influenced by Haskell, Lisp, Erlang...)
Having developed a taste for Functional Programming (FP), I've found that there are many aspects that make building software in a TDD style easier. Functions are the basis of FP, a function that takes arguments and returns values is easy to test. If this function is side effect free (i.e. doesn't effect the program from outside its internal scope; has no infulence on, or effect from, state), you can be confident that that function will always work the way your tests expect.
// SIDE EFFECT FREE
fAddOne = function (num) {
return (num + 1);
};
test("fAddOne", function () {
eq(fAddOne(0), 1);
eq(fAddOne(1), 2);
});
// SIDE EFFECT DEPENDENT
obj = {
num: 0,
pAddOne: function () {
this.num += 1
}
};
test("pAddOne", function () {
obj.num = 1;
obj.pAddOne();
eq(1, obj.num);
});In the above examples, fAddOne will work anywhere within the app, pAddOne is side-effect based and needs to be called within the scope of an object with a num property. If a refactor in needed, fAddOne, and its tests, can move arround or change applications. pAddOne has some requirements that unit tests don't describe as easily, refactoring will be a little trickier. In effect pAddOne's tests are testing side effects not functionality.
However, the example oversimplifies the problem. In reality side effects are essential, I/O can't be avoided. In (browser based) JavaScript this is usualy in the from of DOM API interaction. In GB.js I attempt to keep a CYOA/GameBook engine independent of side effects, in the demo, DOM building and events are kept to a minimum and try not to overlap. This is fine for individuals working to their own requirements. Teams have different problems; in JS, side effects are easy and the syntax encourages them, in most cases it's easier to just cave in. It may even get work done faster (at first). But, from a Unit Testing perspective quality drops or, at least, refactoring become trickier.
FP is a tool industry could gain more of value from, as does by adopting its features and principals (closures, currying, recursion etc...). The problem for me is blending Object Oriented (OO) and FP styles with TDD. Refactoring and reuse are important, and when a shortcut is made with OO then quality can suffer.
Another gain with FP can be shorter code, but when using TDD with loosely typed languages (JS, Erlang, Lisp etc...) type checking causes length to creep up. While rewriting some of excersises from "The Little Schemer" (with TDD JS) it became apparent that if you want high confidence in the Unit Tests then a lot of type checking happens. This is why I have a set of type checking functions that I use constantly. So, if I'm typechecking a lot am I just re-inserting the type safty of a strongly typed language?
Looking at other FP languages, Haskell currently satisfys me the most. Sepparating side effects into Monads (I'm still in the process of learning this concept) and using strong typing (and a compiler) feels like it provides real confidence in quality. In fact, by having to decide types in the function definitions there is no need to have tests to cover type safety. So the extra "boiler plate" (that isn't even required by the compiler) can reduce the overall lines of code typed.
I'm hoping that by delving deeper into Haskell's approach I can get a clearer steer on how to construct functional JavaScript applications.
Which Language Combination?
I'm trying to be a better programmer. I have been writing and learning as much code as I can, the benefits are a threefold positive feedback loop:
- Learning is, in itself, very pleasurable (it makes you feel clever, which is nice)
- New knowledge transfers to, and enhances, existing skills
- New tools and skills provide a greater resource for providing solutions
But, how does a developer know which skills to learn and which languages are best to learn with? (Assuming that you're learning for fun rather than as a work requirement.)
If Google is a good bench mark (assuming that they can take their pick of the best developers), one requirement (taken from an ad for a Software Engineer) asks for:
Fluency in two or more of C, C++, Java, Shell, PHP, Perl or Python.
If you are specifically aiming for a career at Google then making sure you are fluent in two major languages is probably the way to go, and there is certainly no downside to a developer broadening their skill set. In my experience, each foray into new languages has improved my PHP, and in turn, I feel pretty comfortable in Ruby and Python.
When deciding to learn something new: you could argue that PHP, Ruby, Python, Perl etc... are pretty much different brands of the same tool (procedural, interpreted languages). It's great to have the option to use each, but these languages are not necessarily complimentary. It is unlikely that you would write a system with a combination of PHP, Python and Ruby. But, it is conceivable that you could have a project requiring C, PHP and Erlang skills.
Rather than learning interchangable skills, complementary languages might offer the opportunity to become a more rounded developer:
- Interpreted, procedural (PHP, Ruby, Python, JS)
- Compiled, procedural (C/C++, Java)
- Functional, concurrent (Erlang, Scala, F#)
Assuming that side stepping between similar languages is easier than picking up a completely new concept: it would seem learning these varied skills opens up more possibilities.
Sometimes I worry that by learning a particular, none mainstream, language (like Erlang) I could be backing the "wrong horse". However, bearing in mind my earlier ramblings, there's little downside to picking up a new way of doing things, for example Elang may not prove popular, but the functional approach will give me a head start learning F# or Scala.
This slide from Painless Payment Processing by Erik Stenman points out other benefits of learning more "unusual" languages:
Nice paradox:
The lack of Erlang programmers makes it easier for us to find great programmers.
- There are many great C and Java programmers, I'm sure, but they are hidden by hordes of mediocre programmers.
- Programmers who know a functional programming language are often passionate about programming.
- Passionate programmers makes Great Programmers
Or am I talking nonsense?

