Finding Joy in Programming
This post is based on my talk at Ăredev 2017. Watch the video.
Iâve been thinking about this for a while now - what actually makes me happy when Iâm programming? Because hereâs the thing: Iâm pretty sure Iâm intrinsically motivated to code. I genuinely enjoy it. There are plenty of fun things I could be doing with my time, and yet Iâd often rather be programming, creating something.
And yet⊠there are times when I feel deeply unhappy programming. Sometimes for very long periods of time. So whatâs going on?
I figured if I could tease apart what was making me happy versus unhappy, I could communicate my decisions and preferences more clearly to my coworkers. Maybe even help others think about their own choices.
The âBest Tool for the Jobâ Problem
Thereâs this mantra that goes around at conferences: âuse the right tool for the jobâ or âuse the best tool for the job.â I particularly dislike this statement.
I was at a CSS-in-JS talk where the speaker had a slide with literally 60 different libraries. And he said, âuse the best tool for the job.â I thought: I have no idea what the best tool for the job is. Youâve imparted no information to me.
At the very least, if youâre not going to tell me what the best tool is, tell me how to decide. What are the criteria?
This matters because when weâre sharing information at talks or in blog posts, weâre rarely sharing understanding. Understanding is an embodied experience. Youâve tried something, youâve felt the good parts and the bad parts. And itâs part of why reasoning by analogy is so important - if you can give me an analogy, I can figure out the differences from there.

Selling Power vs. Selling Restraint
Selling power to developers is a much, much easier proposition. âLook how powerful this thing is! Look how quickly I can do this! Why wouldnât I want all this power?â
This includes me - especially if I look back at a much younger me who was much more confident in his ability to program. I was quite arrogant, maybe. I thought Iâm not the one thatâs going to make mistakes. I deserve this power. Why wouldnât I want it?
Itâs only after shooting yourself in the foot several dozen times that you realize maybe there are trade-offs inherent with this power.
The challenge when selling restraint is that it almost entirely relies on the audience having some experience and understanding what the trade-offs are. The market for selling restraint is, by definition, smaller than the market for selling power. And this devolves into âjust trust me, youâll try it for a while and then youâll love it.â
Thatâs not a compelling argument. I listen to you for three weeks, and it turns out to be a total waste of my time? No thanks.
Three Dimensions of Programming Happiness
So what makes me happy when Iâm programming? Iâd argue itâs when I hit success points. And success - whatever that means to you - has three dimensions that matter:
- Time to initial success - How quickly can I get something working?
- Intensity of success - When I do succeed, how good does it feel?
- Regularity/interval between success points - How often do I keep hitting that success state?
This sounds like a tautology - âhappiness is successâ is like saying good things are great and water is wet. But actually, I think itâs really powerful to apply precise language to specific concepts.
If youâve seen Rich Hickeyâs âSimple Made Easyâ talk, he differentiates between what is simple and what is easy. This separation makes conversations much more effective because weâre no longer talking past each other with fuzzy terms.

The Chemical Reality of Success
Hereâs something important: success is a chemical process in our brain. We feel good when we hit some success point. And we want that success - sometimes no matter what the cost.
This often manifests as fake work or even negative work. The canonical example: a tech founder who is very good at tech builds a product with no users. What do they do? Rewrite it in some new better tech. Refactor it using some new pattern.
Why? Because learning to speak with users, discovering their problems, feeding that back into the development lifecycle - thatâs going to be a long time until you get any success. But I can solve a technical problem right now and feel like I did something.
Itâs like drug addict behavior, honestly. We prioritize that quick hit of success - our tests pass, we fix a minor bug - rather than the medium or long-term concerns.
Iâm particularly careful with myself whenever I notice itâs been a while since Iâve had success. I get more self-critical: Am I doing this because itâs the real problem? Or am I doing this because I just want some success right away?
The Pit of Success
This leads to the concept of the âpit of despairâ versus the âpit of success.â This originally comes from Eric Lippert, who worked on compilers at Microsoft. He talked about C++ as his personal pit of despair - so many ways to mess things up. Youâre constantly walking on a precipice where just centimeters to either side is this pit you can fall into.

Rico Mariani and Brad Abrams (also at Microsoft) extended this, arguing we should search for the pit of success instead. To the extent that we allow people to get into trouble, thatâs our failing as tool makers. What we want is for people to accidentally be successful without even thinking about it - they accidentally climb the mountain.
Restrictions in technology often lead to accidental success.
React is a good example. They really focus on the pit of success. By default, most React users - new or experienced - will do the right thing without thinking about it. It is possible to do the wrong thing, but itâs annoying. It becomes very clear when youâre reaching around the system. Youâre entering dangerous territory.
Accidental success is important because if we can stay in that success state, we minimize the risk of decay and starting to do counterproductive work. Weâre much more likely to ship product - which is the biggest success of all.
Redux and the Power of Restriction
Redux is another example. Itâs a state management library that sees massive adoption, and it does so by encouraging a pattern thatâs very, very restrictive compared to alternatives. It takes longer to set up. But in return, you get predictability and shared tooling.
Patterns are literally just a dampening coefficient in how quickly decay increases over time and code-base size.
The whole point of patterns is this: as our code scales over time, size, and people, inevitably the interval between successes grows. Our programs become more complicated, and our ability to reason about them becomes less. Patterns slow that growth.

Redux does this by being very explicit. It takes on one of the biggest challenges in UI programming - state-space size. From the root of your application, a user can do some number of things. Each represents a state change. From there, more options. Itâs like a continuously expanding tree.
Redux requires you to explicitly state: from this state, here are all the transitions that are possible. Because of this enumeration, we can reason about how quickly our state space is scaling, and with the right tooling, make sure we never forget to handle a case.
Compare this to a powerful JavaScript approach using global variables - the most powerful, right? You can do anything! They can be updated from anywhere. Maybe via observers. Maybe via proxies.
(Proxies! You can wrap objects so that a read-only accessor like x.width actually goes and changes something. Youâre reading it, it looks like straight-line code, but inside that proxy you can mutate global state. Fun times.)
With this power, state transitions are completely implicit. Itâs very hard to understand all the transitions a user could actually do. And the state-space grows extremely quickly.
The Debugging Scenario
Letâs say a user is five minutes into your app, has transitioned states about a hundred times, and hits a bug. Theyâre kind enough to send you a report. Now what?

In both cases, you start from the root and know the user is somewhere deep in this tree. Your job is to apply graph traversal algorithms in your head to figure out how they got there.
But in the Redux example, the tree is pre-pruned. The edges are explicit, clear. You have a much sparser graph to traverse. Whereas with that powerful JavaScript app, you may be in a desert of success for a long time before you can reason your way out.
And during that time? Youâre going to feel unhappy. Burnt out. You may start doing dangerous things.
The Illusion of Success
One of the most dangerous things about powerful tools is they can lead to an illusion of success. It feels successful. As developers, we start from the root, have a goal, and trace the shortest line to it. Weâre focused. Weâre unaware that just because weâve traced a path doesnât mean there isnât a pit of despair centimeters away that our users will hit.
Because of the sheer number of states possible and the lack of tooling, itâs possible our apps are more often broken than working. Weâve proven itâs possible to succeed - not that itâs likely.
These powerful tools allow the freedom to ignore cases, ignore state transitions - often accidentally. âI forgot that if someone logs in first, they have this thing happening over here, and I didnât handle that edge case.â
Why Reason?
So how does all this relate to ReasonML?
Reason has an unusual focus on time to initial success. This is often overlooked or even belittled in more rigorous engineering disciplines.
We can all agree JavaScript is very, very quick to get to some level of success. NPM install anything, hot code reloading, REPL - within seconds you have a huge ecosystem at your fingertips.
As engineers, we often argue that doesnât matter. The area to the left of initial success is so short compared to everything on the right. Who cares if it takes ten times as long to get started?
But this isnât compelling to someone who literally just felt success. âWhat do you mean I have to go for days, weeks, or months feeling unsuccessful to reach this supposed promised land?â

We talk about these trade-offs as if theyâre inherent - as if because a technology gives you benefits on the right side, itâs required to be hard to get started. I donât think thatâs true.
OCaml has spent 20+ years worrying about the right side of the graph - really good type system, powerful runtime, very fast. Reason can build on top of that without giving anything up. We can just drag the graph to the left and make it more accessible.
The Syntax Experiment
Reason is built entirely on OCaml - 100% compatible. Just different syntax and tooling with polish.
The hypothesis was: by making syntax closer to JavaScript, we enable people to jump into functional programming much more quickly. When someone tweeted their Reason code and someone asked âwhat version of JavaScript is that?â - the community loved it. People werenât focusing on unfamiliar syntax. They were saying âthat looks reasonable, I understand that. Now what are the actual differences?â

BuckleScript (the compiler from OCaml/Reason to JavaScript, now called ReScript) has an explicit goal: generate JavaScript that looks like what you would write by hand. This is important for onboarding - you can look at the generated JavaScript and work backwards. When we did a workshop with 80 people, theyâd immediately focus on the compiled JavaScript output. âOK, I see what this is doing. Now let me see what the Reason thing is doing.â
The Trade-off Space
JavaScript: quick to get started, get some success, then potentially crumble under code-base weight.
Elm: takes a long time to learn, but gives you severe and amazing guarantees. NoRedInk has over 80,000 lines of Elm in production for two years with zero runtime exceptions. The language guarantees you cannot have them. But anytime you reach out to existing JavaScript, you have to stop and set up infrastructure.
Reason: straddles the middle. We donât want to give up time to initial success unless it buys us something on the right side. Syntax doesnât buy us anything there, so letâs make it familiar. Bad tooling doesnât help anyone, so letâs have good tooling. Integration with NPM means we can pull in modules quickly. We have fewer guarantees than Elm - you can have runtime exceptions. There are trade-offs.
tl;dr
Happiness in programming comes from hitting success points. Those success points have three dimensions: time to initial success, intensity, and regularity.
Weâre all chemically motivated to seek success, sometimes at the cost of doing fake work. The right restrictions can lead to accidental success - keeping us in the pit of success rather than the pit of despair.
Patterns and tools that are more restrictive arenât just being annoying - theyâre dampening the rate at which our ability to succeed decays over time.
Reason tries to give you the benefits of a mature type system and functional programming without sacrificing time to initial success. Because both sides of that equation matter.
If you want to dig deeper into Reason specifically, Iâd recommend checking out Cheng Louâs âTaming the Meta Languageâ talks and Jared Forsythâs Strange Loop talk on Reason. But regardless of what tools you use - think about your success metrics. It might change how you evaluate your choices.
References
- Rich Hickey - âSimple Made Easyâ (Strange Loop 2011)
- Eric Lippert - Fabulous Adventures in Coding (Microsoft compiler engineer)
- Jeff Atwood - âFalling Into the Pit of Successâ (Coding Horror)
- React - react.dev
- Redux - redux.js.org
- ReasonML - reasonml.github.io
- OCaml - ocaml.org
- ReScript (formerly BuckleScript) - rescript-lang.org
- Elm - elm-lang.org
- NoRedInk - Scaling Elm (case study)
- Cheng Lou - âTaming the Meta Languageâ (React Europe 2017)
- Jared Forsyth - âReason: JavaScript-flavored OCamlâ (Strange Loop 2017)