Disfunctional RSS

Where misquotes, misinformation, and misspellings occur daily.

Archive

Jul
22nd
Sun
permalink

I do declare

Brian vs Abstraction Round 1

Martin Fowler once said something to the effect that programming, at it’s finest, should be nothing more than the configuration of abstractions. This made a little bit of my brain leak out my ear the first time I read it. It was a statement that made me question everything I’d written up until that point. It was brilliant! I was going to make abstractions, then configure them in every application from then on out. No more inline, single use nonsense.

Over the next week at work, after spending half of each day abstracting things, I realized that no one really has the time to pull this off. It’d have to be a group effort: Everyone making super configurable abstractions and explaining to each other how to use them via doc or tutorial or whatever. But things keep changing, the ground moves below our feet, technology, languages, etc. It was useless to try to abstract everything.

But back then, I hadn’t seen the whole story. I was trapped in OO land where nouns and specific implementations dominated. Where functions were tucked away for use with only their owning objects. Where the specific application’s data was tangled up with the very functions we were trying to make data agnostic. Where generic behavior was forced into the back alleys of abstract interfaces. Now, after functional programming changed my perspective, I could revisit the dream.

In functional programming, we build bigger systems from the same old reusable set of functions. We look at shared behavior and functionality more like traits and say a thing is a functor or a monoid, not an address or a user. We create contexts so we can use those same functions in different ways on different things, but in the end, it’s the same set of functions. The dream may be possible after all!

Brian vs Abstraction Round 2

Anyways, this is a post on declarative programming. Declarative programming gets to the heart of what Fowler was saying as we will see.

Declarative programming is where you say what should happen in your application and walk away - you don’t actually do anything. You then allow the underlying mechanism, be it a framework or language or some other (higher order) code, to accomplish the tasks however it sees fit. Imperative programming, on the other hand, is where you take the reigns and tell the computer how to do each step right then and there in the midst of your business logic.

Maybe that’s not the most unbiased definition, but let’s keep digging and you’ll see what I mean. The primary example I see everywhere is SQL. You express a query as a single expression and let the computer do it’s job. This is much different than say, a typical c program where you specify each individual step down to memory allocation right there in your function.

Another example is relationships in rails. ActiveRecord users will recognize the example of adorning models with has_many and belongs_to. You declare the relationship and leave it to the superclass to make it happen.

There are many benefits to this style of programming. Most of them stem from the fact that you’re kind of forced to abstract all the functionality in order to write a declarative line. But the style itself leads you to an agile application that reads like a book if you do it right.

Here’s a bite size example:

Imperative

var chargeCard = function(credit_card) {
  if(chargeCard(credit_card)) {
    sendReceipt(credit_card);
    updatePaidStatus(credit_card);
  } else {
    cancelAccount(credit_card.user);
  }
  return credit_card;
}
Declarative

//+ chargeCard :: CreditCard -> CreditCard
var chargeCard = ifelse(chargeCard, compose(updatePaidStatus, sendReceipt), compose(cancelAccount, '.user'));
You might initially think they are about the same, except the declarative one is much worse on the eyes. But wait, there are some hidden benefits beside brevity. For one, the declarative version has the ability to alter the strategy of how these functions work together. Just by changing compose, we might parellelize some things or we could alter ifelse to do some tracing in between each step.

Another benefit is the ability to compose small pieces together to build up a bigger, more readable function. One expression of self contained bits can be manipulated much easier than several lines of separate steps with loose variables and such lying around. You simply copy and paste little chunks of code around and wrap them in compose.

//+ cancelUsersAccount :: CreditCard -> void
var cancelUsersAccount = compose(cancelAccount, '.user');

//+ finishPayment :: CreditCard -> CreditCard
var finishPayment = compose(updatePaidStatus, sendReceipt);

//+ chargeCard :: CreditCard -> CreditCard
var chargeCard = ifelse(chargeCard, finishPayment, cancelUsersAccount);
And and there it is. If you look at chargeCard, there’s that declarative “what” I was looking for written out in plain english.

Showing off

Let’s do a few optimizations to show off a bit.

//+ cancelUsersAccount :: CreditCard -> void
var cancelUsersAccount = memoize(compose(cancelAccount, '.user'));

//+ finishPayment :: CreditCard -> CreditCard
var finishPayment = parallel(updatePaidStatus, sendReceipt);
We’ve just memoized(cached) the cancelUsersAccount function so it doesn’t actually run that function twice with the same user - it will just return the result the second time. Usually, that helps with long calculations, but in this case it just prevents us from accidentally running a db call again for no reason since it’d already be cancelled. Then we sendReceipt and updatePaidStatus at the same time with the use of parallel*.

And perhaps, we’d also like to parallelize the whole charge process itself. Instead of a manual, imperative loop, we can use the declarative abstraction for iteration. Here’s the imperative loop:

var results = [];

for(credit_card in credit_cards) {
  results.push(chargeCard(credit_card));
}

runReport(results);
And here’s the declarative one:

map_p(chargeCard, runReport, credit_cards);
In this case, we used map_p instead of a normal map. This takes a function to run, a callback, and an array and it will run everything in parallel or at least concurrently.

People say I’m just a dreamer…

So declarative programming says what should be done and lets the underlying code decide what to do. Imperative, order of execution style programming has a funny way of hindering that freedom. Like doing our own garbage collection in code, when we hard code these low level steps, we steal responsibility away from the compiler or interpreter or preprocessor or framework or language or other code or whatever and place it right in the middle of in our application.

This has many benefits. Perhaps, we should no longer fear premature-optimization as much anymore. Bug fixes can be made without touching your app. Good people like the SQL folks can make their functions better and you don’t have to change a single line to reap the benefits.

Ladies and gentlemen, we’ve risen to a higher level. The dream of abstracting the world may be come true after all.

* The parallel function uses setTimeout in my version on functional.js. Webworkers, node, titanium, etc all have the ability to make this work today in whatever environment you choose. However, you can alter it to thread in many different strategies that work for you.
blog comments powered by Disqus