Scaling Sanctuary through Safety: Functional Programming

Hugh Francis
Sanctuary Computer Inc
7 min readAug 22, 2019

--

When we talk about scaling Sanctuary Computer, we aren’t talking about adding more people to take on more projects. Business growth isn’t via throughput over here. Instead, we see growth as our ability to consistently produce exceptional work, with quality increasing steadily with every line of code written.

Every time flaky code is written, that another developer can’t understand or build on, we’re increasing the amount of time we need to spend understanding work that’s been done, rather than building and improving on the product itself. Because we work to limited budgets, that means less time polishing visuals and improving UX, and more time reading code and being confused.

Hence, we like functional programming!

The many problems with OO

When people start learning to program, one of the first concepts that’s taught is Object Orientated programming. This is the style of programming that allows your system to be described as “objects” that talk to each other. It’s easy to see why this style is so prevalent: it’s a nice analog to the real world! In the real world, we have ancestry (I have my dad’s eyes), we have classes (An aardvark is a mammal), and we do things (Hugh says “hello world”).

How to spot Object Oriented programming

There’s a better way to describe Object Oriented programming: it’s a style of programming where your data structures are coupled to your functions.

Notice how here, we’re describing data (this.givenName & this.familyName), in the same place we’re calling methods that depend on those data points (sayHi)? That’s OO.

Ok, so why’s that bad?

On face value, OO is pretty neat! Your data structure is a dependency for your functions, so why not keep them together? Well — here’s some reasons that aren’t obvious at first:

  1. Using this is considered error prone / dangerous

Every programmer who’s started using Javascript has found it tricky to understand context, or this. It took me years to fully understand the breadth and depth of what you can do with it.

Because this can be, well, anything, and it can be “bound” into, well, anything, it means that if you’re working in a programming environment that uses it heavily, you’re often going to have to assume what it does. Specially when you’re working to a deadline.

That’s a cause for human error, and for that reason, it’s not safe.

2. Side effects === Spaghetti code

Writing functions that do more than what they’re named is easy to do in an imperative or OO paradigm: you’re running methods, and those methods happen to have all the things you need to, well let’s say add a call to Google Analytics.

I mean, all the data is right there on the object, and that function happens exactly when you should record analytics, so why not just pop the call to GA in there?

Well — you’ve just introduced a side-effect! Now, this function doesn’t just do what it says — it does a hidden thing, too. It’s not pure, and that’s not obvious. Anything that’s not obvious to another developer is not safe code.

3. Inheritance actually kinda sucks

Conceptually, inheritance is kinda neat! You can define a set of traits, and then you can keep building on them as your app grows! Kinda great… right?

Cool! Our JazzPopSong has all the properties of a pop song, but only needs a couple lines of code. That’s great!

But what happens when you need a JazzSong? You’re now going to need to refactor your codebase to make up for the extra fragmentation you never saw coming originally.

Having to think of every possible permutation of an inheritance chain is virtually impossible, and designing your code to work in every (unknown) case is basically impossible. For that reason, inheritance is unsafe.

4. OO is impractical to test

As your app gets more complicated, so too do the arguments passed to your constructors: new MenuBuilder(user, menu, location, date) etc. This means that writing tests is hard, and often deferred: at the early stages, you don’t want to write tests: you don’t know how your objects will evolve, so writing tests makes for wasted energy.

At the later stages, it’s too hard to build up a user, menu, location and date in your test environment (some might even need network calls) just for a single test. We’ve got that deadline, right?

Cool cool cool cool cool cool. So what’s FP?

First of all; functional programming gets this wrap like it’s some sort of intellectual high ground in the programming community, and that younger developers aren’t welcome.

Let me tell you what I wish someone told me early on: at face value, Functional Programming is way, way easier to reason about than OO. It’s about using less features of the language, rather than more. The basics of FP are so rudimentary you feel like you’re not doing it right… but suddenly, you’ll notice your code is really easy to maintain and build on. Things you wrote from months ago don’t need to be totally overhauled when someone asks for a new feature. Your fellow developers understand your code better, and woah… you’re actually writing more tests that actually mean something!

Functional Programming is just a different way of structuring things, with an emphasis on making tiny-er blocks of code. Instead of writing big crazy classes, you’re instead just writing sets of functions (modules) that do just 1x thing, and stringing them together.

Let’s look at how we’d re-write the Developer class, above.

Here’s the OO Version:

Here’s the FP Version:

They’re pretty similar, right? However, you’ll notice that:

  • There’s no this in the FP version, meaning it’s more predictable. Internals of function can’t be “rebound”.
  • The functions can’t access anything except their arguments, meaning there’s no way for a function to have side effects! They’re pure.
  • The functions can be called without first called new, meaning they stay super easy to test as the code gets more complicated.
  • There’s no inheritance, meaning that traits don’t have to be assembled in a line, but instead can be mixed and matched from different modules as needed.

Is React Functional Programming?

..

….

……

………

There’s heaps of functions in React, so it is… right?

…………….

………………..

…………………….

……………………………

….

Well…

No. Not really. At least not strictly. If you only write functional components, then sure, but that’s not practical. The original React model was actually rooted in OO concepts.

Let’s take a look at a classic react component:

Wanna know what React does “under the hood”, whenever it sees <UserAvatar />?

Yup, you guessed it (basically):

Ummm ok so what about Redux?

Yup. Redux is FP. Have you ever seen this in your Redux code?

And the new getDerivedStateFromProps stuff?

Yes and yes. getDerivedStateFromProps allows React to be written as a pure function. No more this.setState().

And is that why we’re pushing Typescript so hard?

Uhuh. When your modules aren’t coupled to the data structures they require, you need a better way of guaranteeing that your team members aren’t passing them the wrong arguments. Plus, types have the added benefit of being documentation that your a) computer, b) code editor and c) coworkers can read.

What’s the TLDR?

  • Avoid using this at all costs
  • Learn to love Typescript
  • Use Static Methods & Modules when possible
  • Redux is GREAT, use it over state virtually every time
  • Types help us use functional programming with more guarantees
  • Functional programming helps you write code that your co-developers can’t mistake, and that you will understand when you jump into a different project.

And most importantly, Functional Programming helps Sanctuary spend less time debugging, and more time creating beautiful work. ❤

--

--