Talks
Message Oriented Programming

Message Oriented Programming

by Brian Knapp

In this talk, Brian Knapp delves into the concept of message-oriented programming, exploring how it differs from and enhances traditional object-oriented programming (OOP) and functional programming (FP). He emphasizes that the core idea behind OOP, as originally envisioned by Alan Kay, centers not on objects or classes, but on messaging systems. This talk outlines the following key points:

  • The Fragility of Modern Code: Knapp discusses the prevalence of broken and fragile code in our systems, highlighting the urgency to improve software reliability, especially in critical systems that affect everyday life.
  • Comparison of Programming Paradigms: While OOP and FP are often viewed as opposing approaches, Knapp argues that both paradigms can produce brittle code under poor input conditions. He describes how input, processing, and output form a foundational concept in programming.
  • Definition of Messaging: He presents messaging as the fundamental method of communication between software components and compares it to input-output processes familiar in applications and games.
  • Importance of Protocols: Protocols, which dictate how messages are communicated, are crucial in maintaining clear communication among components. This can be likened to languages that facilitate understanding, such as English.
  • Computers as Objects: Knapp relates Kay’s view of computers as objects that have local state and communication capabilities through messaging, suggesting that many implementations of OOP fall short of this vision.
  • Refining Code for Robustness: Through a practical coding example, he illustrates how code may appear straightforward yet overlooks critical error handling and context considerations. By enhancing documentation and error management, systems can achieve greater reliability.
  • Shifting Focus in Development: Knapp concludes that developers should prioritize communication and protocols over mere algorithmic efficiency, especially as systems grow more complex and interconnected.

The talk emphasizes the necessity for programmers to acknowledge the role of messaging in software systems and improve communication protocols for better code reliability and effectiveness. Knapp encourages developers to integrate these principles into their practices to harness the full capabilities of modern technology.

00:00:14.920 Um.
00:00:23.359 Hi, I'm Brian. Today, I'm going to be talking about message-oriented programming. A few things about me: I'm a Ruby developer, of course, or I probably wouldn’t be here. I've made a few things; one was an architecture called Obvious, which had the distinguished honor of being referenced by DHH as maybe some of the worst code he's ever seen attached to Rails, which was pretty exciting.
00:00:40.399 Last year, I did the Ruby Web Benchmark Report, which is the most comprehensive hello world web app benchmark ever made in the Ruby world. I tested every framework and every runtime that I could find. It was a crazy project for me, as I tend to obsess over things that most people don't worry about. If you want to follow along with more of my adventures, there's my website and my Twitter. I also enjoy puns, so if you follow me on Twitter, you'll get a lot of those.
00:01:28.320 So, why this talk? Why are we discussing message-oriented programming? Our code is broken. How many of you have broken code? How come some of you don’t raise your hands? We create fragile, terrible, broken code all the time, and we should strive to write better systems. We should aim to create code that doesn't have so many broken windows.
00:01:39.040 You know, we give XP and Windows a hard time, but that OS has been around for about ten years, and people still want to use it every day, which is quite remarkable despite how terrible the code is. The other reason to improve our software is simple: the software we write is essentially what our families and kids will use. Many of us develop web apps, but the software we create powers critical systems: life support systems, traffic systems, airline systems.
00:02:02.560 Over time, software needs to be reliable and safe. Unfortunately, many of our existing systems cannot be classified as either. If you want to see just how broken our code can be, I recommend watching Gary Bernhardt's talk. He discusses how profoundly broken software is on a regular basis.
00:02:40.080 Often, when people talk about broken software, they compare object-oriented programming (OOP) and functional programming; it’s set up to seem like they are opposing camps. But, in reality, this argument is more about organization. In object-oriented programming, we use objects, classes, and polymorphism to solve specific kinds of problems. Meanwhile, functional programming relies on data, recursion, functions, closures, and monads.
00:03:03.360 However, you can write object-oriented programs that solve the same problems as functional programs. The heart of the matter is that this argument often comes down to what I would call "big versus small." In functional programming languages, there is a focus on small, composable functions used to build larger systems, while OOP has traditionally been utilized in enterprises where large teams of average developers tackle large systems.
00:03:22.080 Typically, this results in a collection of objects and code piled together in a messy fashion. This practice leads to larger systems—something we often criticize. When people complain about object designs, it's usually because the objects are large and the methods are bloated. Yet this size-oriented thinking avoids the deeper issue regarding the reliability of our software. It's a misguided focus because both OOP and FP systems can be fragile, yet in different ways. Subsequently, they are both prone to fragility, especially in the face of bad input.
00:03:51.760 Bad input is omnipresent; you cannot control user input, no matter how hard you try. We’ve all experienced scenarios where we encounter bad input leading to SQL injection, cross-site scripting, buffer overflows, or nil errors. Each of these outcomes results from poor input management. It's crucial to recognize that the database can also be a source of input in our programs.
00:04:22.960 The database functions just as much as a source of input as a keyboard or a button click. What's concerning is that bad input can frequently result in bad output. When we have a bad input value, we might see an error screen, maybe a 500 error page. We've all come across websites that display this type of response. I don’t want to visit a site and see an error page if I submit a value; I want a functional output.
00:04:50.960 When bad output then finds its way into the database, the database in turn becomes part of our input. This means we can get stuck in a cycle where bad input causes bad output, leading to a cascade of failures throughout our system. As we have numerous components communicating with each other, once bad input occurs, systems begin to break down, leading to the standard error pages and Rails error dumps we’re all familiar with.
00:05:10.960 Let’s return to a basic concept that we all comprehend: input, processing, and output. How many here understand what that is? I imagine everyone does—it’s a straightforward concept. You input something, it processes, and you receive a result.
00:05:24.960 Think back to that command line app where perhaps after you enter your name, it replies with a greeting like "Hi, my name is Brian." That model exemplifies the simplicity of input, processing, and output. Similarly, consider games like Minesweeper: you click, something happens, and you receive an output. Calculators also reflect this process; you input a value, and you receive an answer.
00:05:48.720 Now, we often overlook the web's fundamental mechanics in favor of frameworks, Rails, or other technologies. However, the web operates on a request-response model, defined by protocols like HTTP, RPC, and JSON APIs. It's straightforward: you type a URL in your browser, it reaches the server, processes, and returns a webpage. To me, this resembles the input, processing, and output model.
00:06:18.720 So what was Alan Kay discussing and thinking when he developed OOP? Alan Kay is credited with creating OOP, but what he was really working on seems disconnected from how we typically perceive OOP today. I don’t think his focus was solely on classes.
00:06:35.680 He famously stated, "The big idea is messaging— not classes, not polymorphism; it’s messaging." This raises the question of what messaging has to do with object-oriented programming. Often, we focus on classes, structures, and taxonomies, but when do we really concern ourselves with how messages pass between objects?
00:06:48.960 Almost never. I suspect that Kay wasn’t thinking about object-oriented systems as we now do; he was likely considering network systems. He was involved with ARPA, which led to the internet— a remarkably useful system for us.
00:07:04.720 So, if he was creating OOP with an emphasis on messaging, what truly defines an object? A code object can be viewed as a piece of code with local state and functionality for processing. The question often arises in discussions among programmers about the role of static methods in classes: "Why not just use standalone functions or methods?" This prompts an evaluation of the purpose of having objects altogether.
00:07:27.680 Indeed, a code object should maintain its local state and encapsulate functionality. What about processes, threads, and coroutines? Are these also considered objects? When we contemplate processes, each has local state and some functions for processing. To communicate with another process, a message must be sent; direct memory access is generally a recipe for disaster.
00:08:00.000 But what role do physical computers play in this discussion? Alan Kay implies that real computers function as objects themselves. He states that computers possess local state, perform processing, and communicate with one another through message-passing. He asserts that this perspective illustrates a fundamental disconnect between how we traditionally understand an object versus how real computers work.
00:08:21.920 He famously remarked that the internet might be the only true object-oriented system in working order today. This is a fascinating assertion, especially considering that we use OOP each day but find that many of our implementations are lacking. He also notes that any language extensibility can be achieved simply by agreeing on conventions for message forms.
00:08:43.600 This piques interest: why is the creator of OOP concerned about message conventions? Because he developed network systems. This brings us to the question of whether humans function as objects too. In some regard, we operate similarly; we have local state, local processing, and we communicate via messages and protocols.
00:09:01.440 In essence, objects are units that communicate with each other to accomplish work. So, how do objects—and in what context—communicate? Most commonly, they do so through request-response interactions. For instance, the dynamics of a browser and server interacting mirror human communication.
00:09:24.240 You could consider message-passing analogous to sending letters to friends; you package your message into a packet and submit it. The recipient then processes the packet and might respond in return. Protocols serve as established methods to exchange messages, much like postal services.
00:09:41.440 Let’s define a message: a container used for transporting information between two or more parties. Messages assume various roles and formats, but fundamentally, they relate to communication. Protocols are vital to this process; without them, communication cannot occur. Think of protocols as standard structures for transmitting messages.
00:10:13.440 Protocols are ubiquitous— consider English as a protocol. We can understand each other because we share a common language. If I spoke Portuguese, most of you wouldn't understand me, which would be a significant barrier to effective communication. Other examples of protocols include Facebook, email, text messaging, Wi-Fi, and USB connections. Without such standards, we wouldn't enjoy the conveniences we take for granted.
00:10:34.560 Now, let’s switch gears and think about how valuable communication is. The English language itself carries an immense value; consider its worth in global commerce. Likewise, things we communicate with, like telephones, are priceless. Many of the wealthiest individuals globally are those who own our communication infrastructures. The implications of having standard interfaces ripples through our society.
00:11:05.280 Without these protocols, the complexity and chaos of information systems would skyrocket— imagine power going out at a conference: how useless the devices would become without communication standards! Without protocols, effective communication halts entirely. Think of those early dial-up days: communication hinges on reliable protocols.
00:11:40.160 Thus, I wonder about your business focus. Are you just writing web applications, or are you designing systems? Is your goal really to create tools for building robust communication systems? When we can't communicate information effectively, it loses value. Therefore, we should acknowledge the importance of communication protocols in our software.
00:12:06.560 As an example, I have some code I’d like to show you: a trivial example of dividing two numbers. So, is it clean code? It’s pretty simple, but let’s analyze what's happening. We can call it with two numbers, say one and two, and we get some processing, yielding an output of 0.5. What’s important here is that these inputs and outputs comprise messages.
00:12:36.960 Now, don’t overlook the context of the input, and let’s delve into assumptions: what happens if we input integers? Generally, that works fine. What if we input decimals? Generally acceptable as well. But what happens with pi? It’s a long number, and we can only approximate it, which raises further questions.
00:13:01.680 What if we send a string, or attempt to divide words? How should the system behave then? Additionally, does the order matter? Certainly, in division, order is critical; the first input becomes the numerator, and the second acts as the denominator. If they get switched, the results can be erroneous.
00:13:29.680 Also, what about the context of usage? Is it local, global, private, or subject to an API key? The context influences how protocols should be managed. Lastly, what if we input a zero? Could be catastrophic, especially if it’s a denominator—there are nil errors to contend with.
00:14:07.440 And what about error handling? The earlier code lacked provisions for error management, meaning we’d hope that whatever language or runtime we’re using deals with errors adequately. If we accept this trivial example as good code, yet, it fails to account for edge cases and errors, we see the fragility here.
00:14:32.640 So let’s consider enhancing our code; instead of relying on simple protocols, we can improve documentation and error handling. For simplicity, let’s enhance this further and package the division functionality into an object, ensuring clear, explicit documentation. We'll revisit our initial division structure, substituting x and y with explicit parameter names, numerator and denominator respectively.
00:15:03.680 These adjustments facilitate cleaner interactions that do not mandate a particular order. Furthermore, they incorporate consistently formatted messages, combining results and errors in one coherent output. This upgrade adds protocol complexities, but ultimately clarifies intentions. Yes, the code appears messier.
00:15:49.680 However, I contend that robust systems inherently include this complexity. Effective communication, whether within an internal application or across networked systems, necessitates precision in protocols. It’s easy for developers to overlook vital aspects of communication amidst code simplicity, leading to unmanageable integration if left unaddressed.
00:16:31.680 It’s crucial to explore our need for well-documented systems; if an application lacks clear documentation, effective engagement becomes impossible. Inconsistent error handling builds further complications; ensure that error handling remains standardized when creating APIs.
00:17:04.760 Likewise, API user experience should be seamless. As our programming paradigms evolve, the leverage of modern languages offers us varied capabilities. Emphasizing robust tooling indicates a shift in developing communication structures to handle messaging in software.
00:17:53.680 As we build new systems, they understandably adopt more complex communication mechanisms. We live in a world moving toward more devices, more networks, and more features. It is vital to maintain discussions around the effectiveness of error handling protocols and demand for documentation.
00:18:29.920 Ultimately, our expectation for reliability will grow. Communication errors will be met with user frustration; if they want to send a message, they expect it to be received without obstacles. We'll need consistent improvements, whether in the Ruby framework or in other languages, and we must not underestimate the importance of messaging and interaction.
00:19:04.720 In closing, we must focus less on algorithms and functions while paying far more attention to communication and the protocols governing our interactions. The growth of network systems, advances in technology, and more complex devices will amplify the significance of effective communication patterns.
00:19:38.720 Thank you for your attention, I hope I did not go too long. I am available for questions, and here are the image credits.
00:20:08.720 No, like, that's real code. You want that to happen. What I'm saying by building that is I'm suggesting that is code that genuinely attempts to understand and manage those errors and edge cases. With absolute clarity, I can say our current tooling doesn't always provide good abstractions to handle those aspects in various situations.