Thinking Functionally

I had a moment of deep understanding recently. The skies cleared, the earth moved, angels sang and I finally understood why functional programming is just great. It is a little embarrassing because I’ve been using Clojure in personal projects off and on for years now, I’ve dabbled in OCaml, devoured the Functional Javascript book, but I still didn’t really get it.

Like most programmers that came on the scene in the mid-2000’s I’ve spent a lot of time thinking about objects. Objects have encapsulation and hierarchies. Objects have interfaces and collaborators. There are books written on the best ways for objects to collaborate. I was double dispatching and visitor-patterning to my hearts content. I was happy, I understood how the world works. The I started reading about functional programming.

I’m sure a lot of you have seen this slide

It is from Scott Wlaschin’s fantastic talk on Functional Design Patterns. You should go check out is stuff on fsharpforfunandprofit.

My world collapsed. The years of study and practice around Object Oriented Programming needed to be thrown out. “I can do this” I thought. So I starting looking around for advice to understand how to best write functional programs. A few hours later I was curled in a heap on the floor, rocking back and forth, repeating “A monad is just a monoid in the category of endofunctors”.

I was taken back to my third semester of Physics in college where we stopped talking about Newtonian theory and began talking about Relativity. Things became very abstract and I changed majors. Instead of focusing on how objects collaborate and send messages to each other, I was trying to understand algebra and category theory. Monads were burritos, then they weren’t. It was impenetrable.

I stuck with it though. There were a lot of appealing ideas coming out of the Clojure community. Immutability and simplicity really resonated with me. I kept doing side projects that were just atrocious, terrible want-to-be-OO Clojure code, but slowly it improved. I started to understand the value of 100 functions for 1 data structure over 10 functions for 10 data structures. Then I noticed -> showing up in my code more and more. That is when inspiration struck.

You see, all these OO patterns are really trying to teach you is to think about how objects interact with each other and how they manage state. Often when you are visualizing an object-oriented program, you are thinking in graphs. Nodes are the objects that hold state and the edges are the functions that they use to collaborate. Here is a fairly common example of transferring money between two bank accounts.

class TransferService
  def transfer(from_account_id, to_account_id)
    from_account = AccountRepository.find(from_account_id)
    to_account = AccountRepository.find(to_account_id)
    from_account.transfer_to(10, to_account)
    AccountRepository.save(from_account)
    AccountRepository.save(to_account)
  end
end

I think if you were to draw this out, it would look something like this.

+-----------------+   find    +-------------------+
| TransferService +-----------+ AccountRepository |
+--------------+--+   save    +-------------------+
               |
               |             +---------+
               +-------------+ Account |
                  transfer   +---------+

So, let’s think about this program functionally using stateless function and immutable data. Here’s what it could look like.

module TransferService
  def self.transfer(db_connection, from_account_id, to_account_id)
    from_account = AccountRepository.find(db_connection, from_account_id)
    to_account = AccountRepository.find(db_connection, to_account_id)
    updated_from_account, updated_to_account = Account.transfer(from_account, to_account, 10)
    AccountRepository.save(db_connection, updated_from_account)
    AccountRepository.save(db_connection, updated_to_account)
  end
end

The difference is subtle, but very important. In the OO example, our state is found in objects. The AccountRepository has the database connection as part of its state and knows how to find and save records. The Account object has the state of each account and knows how to move money between itself and other Account objects. In the functional example, all the state is explicit. The state is not maintained by functions, it flows through the functions. Because from_account and to_account are just data, not objects, we treat them as immutable. The transfer method returns new copies of the data containing the new account balances. It is best visualized as data flowing through functions, like so.

            +
            |
            | db_connection, from_account_id, to_account_id
            |
+-----------v------------+
| AccountRepository.find |
+-----------+------------+
            |
            | db_connection, from_account, to_account
            |
  +---------v--------+
  | Account.transfer |
  +---------+--------+
            |
            | db_connection, updated_from_account, updated_to_account
            |
+-----------v------------+
| AccountRepository.save |
+------------------------+

Notice, that the edges and nodes are reversed. When we model the problem functionally, we are moving our data through our functions. Functions are the core building block of the system. Data is the contract of how functions interact. This is the exact inverse of OO where functions are the contract of how objects interact.

I mentioned -> or what is called the threading macro in Clojure. This is what lead me to that insight. The threading macro will translate (-> 1 (a) (b)) to (b (a 1)) basically it will pass the result of the previous value as the first value of the next function. Sounds useful, but not life altering. Here is how we can write this code in Clojure, using the threading macro.

(-> {:db-connection db-connection :from-account-id "123" :to-account-id "456"}
    (find-accounts)
    (transfer 10)
    (save-accounts))

It looks just like the diagram. When you start “thinking functionally” you will see opportunities to use the threading macro everywhere. Thankfully, Clojure is not the only place you can find this functionality. Elixir has a pipe operator |>, F# has several different pipeline operators built into the language. There is even a proposal to introduce it into JavaScript

That’s my tale, hopefully it can help you get over the hump of understanding functional programming.

blog comments powered by Disqus