I think you'll agree with me when I say:
One of the most difficult problems in software development is dealing with all the complexity that comes along with our job.
Rich Hickey, author of the language Clojure, understands that problem, too, and his talk Simple Made Easy has helped me learn how to think better about complexity in my own work.
Here's a few things I learned from his talk that I have helped me, and I hope will help you.
- Why easy isn't (necessarily) simple
- The difference between the construct and the artifact
- How complexity hurts our understanding
- What's true of every bug
- What it means to complect
- How to make hard things easy
- How to make complex things simple
- The true benefits of simplicity
They aren't synonyms for one another even if we use them that way.
But developers love to pretend they are. The most egregious examples is all of the libraries that describe themselves as being "dead simple."
What do they even mean by "dead simple?"
Urban Dictionary describes it well: "So easily done that even a complete idiot could figure it out."
So, "dead simple" means so easy a cave man could do it. But is that really what simplicity is?
To understand the difference between simple and easy you need to understand what they contrast with.
Simple contrasts with complex while easy contrasts with hard.
Looking at the root of simple we find sim and plex which means one fold or braid. Complex means braided or folded together.
Something is more or less simple depending on how interconnected or interweaved. Think of a rope here.
Easy origins look something like this: ease < aise < adjacens. You can see the word adjacent there
Easy has the idea of lying near or being at hand. We can think of something that's easy as being near our capabilities.
Simplicity is measured by how interconnected a program is. Whether or not it's interleaved is something that anyone can see. In other words, it's objective.
Easiness can only be measured from person to person.
In other words, it's subjective and personal.
Easy for whom? Or hard for whom?
For instance, speaking Spanish is hard for me. I don't know it and have never had any formal or informal learning of it.
It's easy for my wife because she grew up with it as her first language.
Playing piano is hard for me because I stopped practicing 20+ years ago. I couldn't play a single song today if I tried.
It's easy for my sister because she never stopped practicing and has been playing now for around 30 years.
I could make Spanish easier for myself by spending time learning it, same with piano, but the only way to make something complex simple is by spending the time untangling the web of knots.em
Simple != Easy
We tend to think easy = good. Easier things are better than hard things, right?
Don't you want to use easy tools? Well, yeah, I do.
But should that be your primary focus?
Hickey says no, and the reason he says no is because our primary concern shouldn't be our own convenience of the tools and languages we use, but the results of those tools.
Hickey calls them our constructs. The things we use to build our software which is our artifacts.
We're focused on the wrong metrics. It doesn't how convenient it is to use if that convenience just sends us further down the road of complexity.
We should instead be focused on how easy it is to change down the line.
Now, this does not mean that all easy tools produce complexity, but it does mean that ease of use alone shouldn't be the deciding factor.
The world record for most balls juggled is something like 11. That's not too distant from the guy above with 3. He looks like he could probably handle a few more, but what would happen once he got beyond
4 or 5 or 6?
My guess is he would quickly come to his limit and start dropping the balls.
Juggling things with our hands isn't so different from juggling ideas with our minds.
Like a juggler has a hard upper limit on how many balls they can keep in the air we have an upper limit to how much stuff we can hold in our brains at the same time.
And there's not so great a distance between the most intelligent among us and the least.
We can only hold so much in our mind at once.
The more complicated and interconnected our codebase becomes the more difficult it becomes to understand all of it. When things are interweaved together we can no longer think about the different parts in isolation, but have to look at them together.
So if every time I think I pull out a new part of the software I need to comprehend, and it's attached to another thing, I had to pull that other thing into my mind because I can't think about the one without the other. That's the nature of them being intertwined. So every intertwining is adding this burden, and the burden is kind of combinatorial as to the number of things that we can consider. ^^So, fundamentally, this complexity, and by complexity I mean this braiding together of things, is going to limit our ability to understand our systems^^.
What's true of every bug?
It passed the type checker (assuming you have one).
It passed the tests (you should have at least a few of those!).
Types and tests are not enough to ensure a simple codebase. We need our code to be simple enough that we can reason about it on our own.
The more complex our code becomes, the more difficult that is, and if we're relying on the guardrails of our types and our tests alone they won't prevent us from writing a big ball of mud.
Those are orthogonal concerns to simplicity.
In other words, you can have complex code and static types **and **tests. Focus on the simplicity and don't think you're getting that for free types and tests.
Who doesn't love new vocabularly? Hickey introduces us to a new old word "complect."
What does that mean?
It means to interleave, entwine, braid. It's the verbal form of complex.
You don't want to be complecting your code.
Look at this diagram. Look at the first one. Look at the last one. Right? It's the same stuff in both those diagrams, the exact. It's the same strips. What happened? They got complected.
We need to be asking the question of every decision we make, every library we pull in, and any code we write: "is this complecting my program?"
Say you don't know a particular programming language. It's hard for you, in other words. How do you make it easy?
When you put it that way it becomes pretty obvious: learn, experiment, try.
Go to the tutorials and learn from others further along than you. Work on a small toy project.
Work through exercises and problems in the language on a site like Exercism. Making hard things easy is all about making them familiar.
Yes, there's more involved than just that, but there's not less.
This is trickier than making hard things easy.
It's a matter of disentangling.
You're going to get this. You're going to need to first sort of figure out where it's going. You're going to have to follow stuff around and eventually label everything. This is the start. This is roughly what the process is like. But again, it's a whole separate talk to try to talk about simplification.
That's easier said than done, especially if you're working in a very large complex codebase.
But it's fundamentally a matter of taking the twisted and intertwined parts and untwisting them.
Ease of understanding. Ease of change. Ease of debugging.
The knitted castle and the Lego castle both look beautiful from the outside, but say you had to change the layout. Which would you want to have?
If any of that piqued your curiosity, I encourage you to run (not walk) to watch the Rich Hickey's talk Simple Made Easy.
It's changed how I think about the code I've written and going to write. Maybe it can do the same for you.
The talk itself: https://www.infoq.com/presentations/Simple-Made-Easy/
The transcript for those of you who prefer to read: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/SimpleMadeEasy.md