Minimalist, Programmer-Oriented Programming

As I discussed before, simple isn’t the same thing as easy. Simplifying programming means detangling unnecessary relationships that are adding complexity to your code. One way to simplify is avoid side effects.

When a function (or method) has side effects, it creates an ad-hoc relationship between all parts of the code that use that function. Let’s illustrate this with some JavaScript. Suppose we have a class for managing contacts.

Simple isn’t the same as easy. Sure, we often use the words interchangeably, but they really aren’t the same thing. I first came across this concept when I watched Rich Hickey’s fantastic presentation called Simple Made Easy (slides). To elucidate the concepts, Rich goes back to the word origins for simple (“sim-plex”, “one fold/braid”, not “complex”) and easy (“lie near”).

The difference is profound. Simple is objective. Easy is relative. Let me state that differently: simple is independent of you, easy is dependent on you. If we can untwine something into two smaller, related but independent parts, we have created two simpler things by definition. That makes no statement on how easy it would be for you to create or use those parts. This nature of simplicity versus easy leads to a counterintuitive paradox: something “simple” could actually be “hard” if it is rather unfamiliar or quite different than your personal experience. Likewise, something “easy” might not be “simple” at all.

I’ve you haven’t heard of the CAP theorem, either you haven’t been working on server-side code anytime recently, or you might be a great candidate for your company’s early retirement program. I don’t believe CAP has to be difficult to understand, but I haven’t found an explanation of it that I like very much. On one end of the spectrum, you have the theory laden proof which is just perfect for academics. On the other, you have an entertaining story about fighting with your wife.

For what it’s worth, this is how I think of the CAP theorem. The greatly oversimplified version goes:

If you have two nodes of a distributed system that become separated by a network failure, an update to one node cannot be visible to the other node. Because of this, you can refuse updates and sacrifice availability, or update anyway and sacrifice consistency between the two nodes.

I believe programming, like any form of human expression, affects the writer and the reader profoundly. Too often, we become so enamoured with the functionality, we forget about the readers. Sure, I can have a 6-layer deep outline of a novel which communicates all the same plot information as the prosaic version, but does it really affect the reader the same way?

Why should we care about the readers of the code? After all, isn’t that audience far more limited than those that experience the functionality of the program? Isn’t that simply programmer elitism? Of course, we could write a program that is an end unto itself, though even that could serve its purpose (a prototype, a reduced problem, etc.) But how we think about a problem domain is highly related to how we describe it. And, as humans, we’re really not good at keeping lots of details in our heads, and we’re highly sensitive to how a problem is stated. It’s hard to tell if a problem is isomorphic to another problem we know, or if the problem is ill-structured and clouds our thinking.

So why should we care about the reader? Because we are the primary readers of our own code, and we are the most deeply affected by its misconceptions, mischaracterizations, hidden consequences, and complexities. The degree to which the program works correctly is only as good as our ability to understand problem domain correctly and properly enchant or enrich the “experiencers” of the program.

We must express our intent as simply as possible with no more and no less. We must always strive for clarity. We must always remember the reader: our future selves or any others that join us in our particular endevor.