Software Design

No Return: Beyond Transactions in Code and Life

No Return: Beyond Transactions in Code and Life

by Avdi Grimm

In the video titled "No Return: Beyond Transactions in Code and Life," Avdi Grimm presents a thought-provoking talk at RubyConf 2019, exploring the deep connections between personal philosophy and software design. The central theme revolves around the "transactional fallacy"—the misconception of modeling processes as transactions—and how this flawed perspective impacts both our lives and our code.

Grimm reflects on personal experiences, sharing mistakes he made while obsessively striving toward a preconceived life goal, ultimately leading to a profound personal crisis. Key lessons from his journey include:

  • Transactional Fallacy: This concept describes the mistake of viewing processes as goals with a definitive success or failure state, which clashes with the dynamic, adaptive nature of both life and programming.
  • Influence of Object-Oriented Programming (OOP): He discusses his disillusionment with OOP, tracing its original principles to Alan Kay's emphasis on messaging, arguing that the traditional object-centric view restricts contrary fluidity derived from actual messaging processes.
  • Alternative Perspectives: Moving away from transactional thinking, Grimm suggests embracing narratives and processes instead of static goals. He highlights the importance of understanding systems as workflows rather than fixed transactions.
  • Self-Awareness and Interdependence: He stresses the significance of being aware of one's own narrative and interdependence, especially in building local support networks, which many programmers neglect in favor of online connections.
  • Software Design Adaptation: The discussion includes practical implications for coding practices, advocating for an approach that embraces state, acknowledges history, and allows for fluidity in process execution.

Grimm concludes that programming should not merely focus on strict transactional outcomes but rather embrace the evolving nature of narratives, highlighting key practices such as observability in code—affirming that narratives in both software and life should be flexible, adaptable, and human-centric.

Overall, the speaker invites programmers to reconsider how they model their code and their lives, proposing a shift toward embracing narratives that allow for growth, change, and interconnectedness, ultimately leading to a more joyful existence and resilient systems.

00:00:12.680 Good morning! Hi, I'm so happy to be here, back at RubyConf and back in Nashville. So, okay, let's get right into it.
00:00:20.039 Today I want to talk to you a little bit about some mistakes that I've made in life and in code, and some of the lessons that I am learning from those mistakes.
00:00:25.830 A couple of years ago, I lost my dreams and I lost my faith. Let's talk about dreams. I was one of those people who, from a very young age, had a pretty specific idea of the life that I was supposed to arrive at, the life that was correct for me to have.
00:00:32.819 From the age of about 18 onward, I set myself pretty much single-mindedly to arriving at that life. I knew that I had a lot to do to get there, so I set about ticking off these checkboxes towards this goal—things like getting into the software industry, getting married, having kids, leveling up my career, and building my reputation through podcasting, blogging, writing books, and public speaking. I did all these things checking off boxes towards this vision I had of the life I needed to achieve.
00:00:57.299 Along the way, other things—like hobbies and friendships—kind of fell by the wayside. At the age of 35, I achieved that goal. I was done. I had a big house in the mountains, in the woods. I had a wife and lots of kids, and I was running my own business from home with my family surrounding me. I had exactly the life that I had set out to achieve, and I got to enjoy this state of being for about two years.
00:01:23.100 Then, a surprise occurred: my marriage unexpectedly fell apart. I found myself alone in that big house in the woods, reconsidering pretty much everything about the life I had lived up to that point. As I was thinking about this, I realized that I had become Lord Business from the LEGO Movie, trying to get everything fixed in place in the perfect ideal position, aiming for a happily-ever-after state that I could glue in place until the end of time.
00:01:57.299 I realized that for almost two decades, I had been trying to bring my life to an end—not an end in death, but to a static state.
00:02:02.260 I had been trying to achieve a successful return value. Now, as I was pondering this, I was also in the process of losing my faith. And when I say faith, I mean my faith in the dominant religion of our time: object-oriented programming.
00:02:18.859 My entire career has circled around object-oriented programming from the very beginning. Along the way, I learned a lot about what it meant to do object-oriented programming and then eventually unlearned most of that. But who even gets to define what true object-oriented programming is?
00:02:41.909 Well, this guy is good to go to for that. Who knows who this is? This is Alan Kay. Alan Kay invented object-oriented programming; he came up with the concept. I discovered his writings about it and learned that he felt that object-oriented programming meant messaging, encapsulation of state, process, and extreme late binding.
00:02:55.759 Of these three, the most important to him was messaging. He even expressed regret for calling it "object-oriented programming" because it put the focus on the wrong piece.
00:03:07.030 Once I understood this about object-oriented programming, I started trying really hard to just focus on that one piece: messaging. I tried to teach OO in terms of messaging, but along the way, I started to feel more and more cognitive dissonance. Let's think about messaging for a minute.
00:03:38.599 Messaging is built on the physical metaphor of sending a message in the mail. When we send a message in the mail, we sum up all the information that the recipient needs in order to act on the message. We send that summary, and that's all they get. In an OO language, we send a reference to an object; they can reach back through that reference to get all kinds of extra information.
00:04:04.780 When we send a message in the mail, if the recipient doesn't understand it, or maybe it just doesn't reach them at all, what happens? As the sender, nothing bad happens to me. But when we do that in an OO language, what happens? We get an exception, and the sender's whole stack of execution blows up. It's game over for the sender.
00:04:27.250 Most importantly, when we send a real message in the mail, we don't have to freeze at the mailbox until the recipient acts on that message. But that is exactly what happens in any modern OO language. A lot of people will tell you that the original sin of object-oriented programming was mutable state. I disagree.
00:04:49.899 I believe that the original sin of object-oriented programming was returned values retained from the procedural languages that came before. Return values are a fundamental denial of the messaging model.
00:05:12.900 In fact, Alan Kay thought of objects as being like biological cells or individual computers on a network, only able to communicate with messages. Talking about Smalltalk, the language he and his team built to embody the OO idea, he said they never quite got there and that future versions kind of backslid towards the past.
00:05:28.000 Those future versions of Smalltalk are what Ruby and every other modern OO language is based on. Here’s the big lie of object-oriented programming: for the past 40 years, we keep saying we’re sending messages. We keep talking as if messaging is the model, but it’s not. That’s not the actual semantics of what we’re doing; it’s really the same call-and-return semantics of the procedural languages that preceded it.
00:05:52.460 So, I lost my dreams, and I was losing my faith in OO. As I reflected on these things, I realized that they had something in common, that there was something at the core that related both of these things. I realized they both stemmed from the same worldview.
00:06:14.300 They both stemmed from viewing the world in terms of goal-obsessed, uninterrupted, blocking procedures, fixated on success—that successful return value. Another word for this, a shorter word, is "transaction." A transaction is something that is synchronous and blocking; it either completes or it self-destructs.
00:06:34.950 It has no visible or intermediate state; it's totally built around a goal. It has no identity of its own, no persistent state or history, and it’s independent, self-contained. I have come to think of this as the transactional fallacy.
00:06:50.520 The transactional fallacy occurs every time we look at something that is a process and model it as a transaction instead. This transactional fallacy is endemic in programming; it is everywhere.
00:07:10.840 Every time your program freezes up while it’s parsing a particularly big hunk of data, and you realize that just to show an updating progress report while processing that big chunk would take a significant rewrite, that’s the transactional fallacy.
00:07:29.920 When you have an architecture built around a bunch of stateless service objects and a workflow that originally just hits one of those service objects, only to later find that it needs to flow through several different requests hitting different service objects, you end up trying to sneak little bundles of intermediate state from one service object to the next to complete that workflow. That’s the transactional fallacy.
00:07:54.480 I see this all the time with forms. Forms are a way we try to force communication into a transactional model, yet communication is not transactional. We often realize that we need to split a form across multiple pages, which requires some rewriting. Then we discover that people are upset because they fill out part of a form, have to pick up their kids from school, and the form has reset in the meantime.
00:08:16.500 So we start adding code to make it possible for them to save and continue later. Then we find that we need to query data from those incomplete forms, so it's not sufficient to just squirrel it away in the session. We often have to rewrite a bunch more to change our schema. This is the transactional fallacy.
00:08:42.200 Whenever I have to take one of my kids to a new doctor, I have to spend 15 minutes filling out intake paperwork. Anybody else feel my pain? It sucks, right? But at least I know if I put the clipboard down, it won't reset itself. I can take it with me and keep filling it out while they’re getting checked out.
00:09:03.720 And if I leave some fields blank, they can still call me back. It's not a transaction—it's a process. I shudder to think what the intake process would look like if a programmer architected it.
00:09:16.300 The transactional fallacy has a symbol, and it’s one you’re probably already familiar with, even if you don't realize it. The symbol is the spinning beach ball of doom; it's the universal symbol that a programmer thought a process would either finish or fail more or less instantaneously—and it does neither.
00:09:32.400 So what’s the alternative? Looking again to Alan Kay, he thought of objects as being like biological cells or individual computers on a network sending messages to each other.
00:09:53.620 Does this sound like a transactional model? Does this sound like call and return? No, it sounds like something much more asynchronous and independent. When we look at the history of Smalltalk, we can see hints of something very different.
00:10:14.120 For example, this is a snippet of Smalltalk 72 code. What you’re looking at here is a class, and that class is also a function—it’s a function over a stream of events, and it’s pattern-matching on those events to decide what to do with each one.
00:10:41.200 For some of you, this might ring a bell because if you squint, it looks kind of like Erlang or Elixir code—the code for an actor pattern matching on events—and this is not a coincidence. There was a lot of cross-pollination in the history of these two projects.
00:11:04.799 Erlang and Smalltalk share a history, and as you may know, if you’ve worked with Erlang or Elixir, they are built on processes. What I've realized is that message-oriented programming implies process-oriented programming. You can’t have one without the other; you need something like independent active processes, something like actors.
00:11:38.070 When Alan Kay was talking about message-oriented programming, he was implying objects as processes. So much of what we model in software turns out to be a process; it turns out to be a workflow. A purchase order is not just a static entity—it gets created, it goes through various states, it gets filled in with line items, it gets sent for review, finalized, and eventually archived.
00:12:05.110 User accounts are processes as well. They might be introduced in a partial state, validated, confirmed, elevated in privileges, locked, and eventually archived. Even HTTP requests that we try to model as transactions are actually processes. If you look at the actual TCP conversation happening there, HTTP requests are processes.
00:12:30.340 So much of what we model are actually processes, yet we arbitrarily slice them into objects and entities, and we wonder why our systems are so hard to understand. What if we stopped focusing on the static structure and started looking for those processes? What if we began explicitly modeling these workflows in the human systems we’re trying to facilitate?
00:12:54.740 This is the space I’ve started exploring, and early on I realized that one problem with this approach is that the word "process" is a little too ambiguous because it’s highly overloaded in our space.
00:13:20.140 We use "process" to refer to a lot of things already, so I’ve started using the word "narrative" instead. For the rest of this talk, I’ll use "narrative." I believe this captures what I’m discussing.
00:13:32.460 The more you look at the world from this perspective, the more you realize it’s narratives all the way down. Narratives are everywhere—it’s not just the business models; the project you’re working on right now is a narrative. Your software team is a narrative. Your own cells are constantly dying and being replaced, yet you have a coherent identity.
00:13:56.180 It’s not so much that you are a person as that you are personal; you are a living narrative. Your life is a narrative; it is not a transaction with a return value. There is no return, which means there is no finish line. There is no success that makes sense in this context.
00:14:20.590 I strongly believe that the way we design software is unconsciously influenced by our beliefs about how the world works. And it works the other way too: our ways of perceiving the world are influenced by how we model the world in code.
00:14:39.750 You can’t do this stuff eight hours a day or more without it influencing the way you think of the world. Therefore, transactional thinking is a philosophical problem, and it leads to brittle lives and brittle code.
00:15:00.760 This actually turns out to be a point of division among actual philosophers, and it’s a point of debate in the field of metaphysics. The schools of substance metaphysics and process metaphysics. Kelsey Vieira has an article on this where she breaks down the view that we often see the world as a world of things.
00:15:18.820 Objects are seen as the paradigmatic mode of existence—the basic building blocks of the universe. Conversely, process philosophers think we should examine the processes that make up the world. Processes, not objects, are fundamental.
00:15:38.960 Process philosophy invites us to look at longer stretches of time, blurred boundaries, and connected relations. Identity as a process welcomes innovation through small recurring changes.
00:16:03.800 In this sense, programming is not just about coding; it's fundamentally applied philosophy. We use code as a way to reflect our understanding of the world, and therefore, we can’t partition these parts of our lives.
00:16:19.420 I think the best way to start thinking in narratives may be to start with how we approach our lives. With that in mind, I want to spend the rest of my time here talking about what it means to think in terms of narratives, focusing on how I am learning to think about my life and to live it.
00:16:38.480 Along the way, maybe we’ll have hints about how that applies to code. First off, a narrative has a direction, not a goal.
00:16:53.800 As I've started moving away from a goal-oriented life, I’ve found it helpful to have certain images that pull me toward them. These images are concrete but also fanciful. My friend Artie Starr refers to these as 'arrows'—something that gives you direction.
00:17:13.520 For example, my beer list isn't actually a list of beers; it’s a list of people I would love to have a beer with someday. You’ll probably not be surprised to learn that Alan Kay is on that list, along with others like the poet Ruby Cour and dancer Marquise Scott.
00:17:42.570 Here’s the thing about the beer list: it’s not about how I hope to randomly run into them at an airport bar or get a backstage pass. It’s about what would it mean for me to have a beer with these people. What direction should my life take for that to become likely?
00:18:13.449 What kind of impact should I have on the world and the people around me to make those encounters more likely? Who do I need to be becoming for those meetings to occur? I probably will never have a beer with most of the people on this list, but it gives me direction.
00:18:36.270 It gives me a heuristic in making choices. What might it mean for code to have a direction instead of a goal? It could mean embracing the actor model, or simply acknowledging that all-or-nothing thinking isn’t adequate.
00:19:07.680 We need feedback earlier than just an all-done mindset. Structuring our code using streaming or batching models can also serve this purpose.
00:19:22.100 If you want to learn more about doing things with the actor model approach, Elixir is a great way to start. It’s a mash-up of Erlang and Ruby, and many of you here have likely studied some Elixir.
00:19:46.520 Having a direction implies that a narrative is constantly becoming, and becoming requires awareness of where you are so you can see where that direction points.
00:20:09.110 This means that a narrative must be aware of itself. The best teacher you could possibly have for being aware of yourself is one that’s right there with you all the time—your body.
00:20:31.430 Your body is never static; it has no ideal end state. It is constantly dying and being replaced. Your body interrupts you in the middle of trying to achieve some return value with little reminders of the process of life, such as being sleepy, hungry, or cold.
00:20:53.569 As programmers, we try really hard to be brains in jars. We like to pretend that our ideas can be completely separated from our bodies. Learning to embrace narrative as a person means acknowledging that you are an embodied mammal; it means learning to live in your body.
00:21:16.100 This can mean something as simple as embracing a mindfulness practice, such as yoga or running—anything that keeps you in touch with your body. But as you do any of these activities, be careful.
00:21:36.250 We hackers are so addicted to being brains in jars that even in the midst of those activities, we find ways of distancing ourselves from our bodies and returning to our analytical brains.
00:21:59.480 What I’m saying is to throw away your Fitbit. Learn to feel when it’s time to take more steps. Learn to gauge your target heart rate and recognize when you’re dehydrated.
00:22:22.410 What might it mean for code to be self-aware? It could mean building observability into our code instead of treating it as an afterthought.
00:22:43.900 It could involve finding ways to let our algorithms tell the story of their results and the provenance of their data. This can also help in addressing algorithmic bias.
00:23:05.580 If you want to learn more about building observability into your code, I highly recommend following Charity Majors's work; check out what she's written. Knowing where you are and where you’re going means also knowing where you’ve been.
00:23:24.560 Embracing narrative means embracing history and state. I realize that embracing state is not always the most popular suggestion, but state is simply acknowledging that everything we want to accomplish with computers, or otherwise, involves the passage of time.
00:23:43.980 State is the acknowledgment that any narrative in the world, whether it’s a workflow or a human being, is an accumulation of events and their lasting effects. We love the idea of a clean reset—a reboot—because it’s so simplifying, but that’s not what we actually have to deal with.
00:24:11.520 Embracing state means embracing history and acknowledging that there are no clean slates. We have to build with the past, which means embracing that rich legacy project instead of throwing it away and starting new, no matter how tempting.
00:24:28.700 It could also mean exploring temporal modeling, which focuses not on static entities and structures but on events that occur and the commands humans send. This leads naturally into event sourcing architecture, another great topic to study.
00:24:54.040 Modeling systems in terms of the flow of events can also lead to event storming, which is a way of gathering to figure out how your system looks from a temporal perspective.
00:25:14.840 If you want to learn more about event storming, I recommend looking into Alberto Brandolini's work. Embracing history means embracing entropy; it means embracing surprises and failure.
00:25:35.590 In narratives, we look for ways to fail forward because we realize there will always be surprises. For instance, consider a hypothetical scenario where something unexpected falls onto your monitor.
00:26:01.400 In standard OO languages like Ruby, the stereotypical way to handle a surprise of this nature is to raise an exception. This approach results in wiping the whole process—the entire stack of execution—along with all local variables, database connections, and other essential states, effectively burning down the house.
00:26:30.870 What I’ve observed throughout my career is that the more focused we get on preventing failures, the more catastrophic those failures are when they eventually break through, and they always do.
00:26:56.430 We need to be less focused on preventing failure and more focused on how we adapt and move forward. Learning to be okay in a failed state means embracing interdependence.
00:27:20.340 When my transactional life raised an exception and came crashing down, I realized that I had a lot of friends online but had completely failed to build my local tribe. I conducted a Twitter poll about this, and over a thousand people responded, with the majority feeling they did not have an adequate local support system.
00:27:46.230 I think this is an epidemic problem among programmers. We easily settle for online relationships, which may lead us to believe that typing text to a friend is equal to sharing a beer. It may feel that way until it doesn’t.
00:28:09.140 We need genuine connections—someone who can hold your hand, talk things through with you, or even bring you a meal when you can't get out of bed.
00:28:31.240 So if you find yourself in that majority, feeling like you lack an adequate local support network, take this away from my talk: I strongly encourage you to start building those local friendships before something catastrophic happens. If you’re unsure how to get started, please come talk to me.
00:28:51.610 What does it look like for code to be interdependent? We actually have a lot of patterns focused on this, such as backpressure, queues, and circuit breaker patterns.
00:29:11.400 What these patterns have in common is that they involve one component holding state for another component. They illuminate how components should know about each other and not remain black boxes. These are rudimentary forms of empathy in code.
00:29:32.110 If you want to learn more about some of these patterns, I recommend checking out books like 'Release It!' or 'Reactive Design Patterns.' They contain some great insights.
00:29:52.330 These are some of the values I’m learning as I look at life more in terms of narratives: have a direction, sense yourself, embrace state, fail forward, and be interdependent.
00:30:12.640 Transactions either finish or they fail, denying other possibilities, but narratives continue on, flowing like a graceful dance, embracing the potential for growth and change.
00:30:34.880 So I encourage you to weave graceful narratives in both code and in life. Thank you very much.