Don’t call methods
Send and receive messages instead
Recap
In the previous article we explored the idea of passing structured messages to objects:
const nameMessage = { type: Name };
const spot = Dog(“Spot”);
spot(nameMessage)
And we simplified things using functions (with closures) instead of classes:
function Dog(name) {
const base = Animal(name);
return message => message?.type === Speak
? “woof”
: base(message);
}
Returning messages
Now, we go one step further. Instead of returning raw values from our object, return a message instead.
import { Cart } from "./Cart.js";
import { AddedToCart, AtCheckout, Message } from "./taxonomy.js";
import { skippingRope, yoyo } from "./catalog.js";
const cart = Cart();
// 2 yoyos
cart(Message(AddedToCart, { ...yoyo, quantity: 2 }));
// 1 skpping rope
cart(Message(AddedToCart, { ...skippingRope, quantity: 1 }));
// checkout
const cartTotals = cart(Message(AtCheckout));
console.log(cartTotals.items, "items, total cost:", cartTotals.total);
cartTotals
refers to a message of type CartTotals
although we’re not inspecting the message type.
In fact, the code looks more awkward than it would be using normal class-based code. But, that’s because we’re at the awkward half-way point in our transition.
Changing paradigms
When you switch paradigms, you often reach this awkward half-way point. You are bridging two worlds. Here we are expecting a `return` message. The real magic happens when we no longer distinguish between the sent and the received.
But, for that we need a few more pieces of the puzzle which will come next time.
Taxonomy
Normal communication relies on a taxonomy of sorts. The _Type_ of a message (not the `object` class or method) is the ultimate signifier.
In today’s code sample, we import the taxonomy from a module which looks like this:
export const Type = Symbol("Message type");
export const AddedToCart = Symbol("Added to cart");
export const AtCheckout = Symbol("Checkout");
export const CartTotals = Symbol("Cart totals");
export const Message = (type, props) => ({
[Type]: type,
...props
});
Time
Notice that the messages above refer to events in time. Over the last twenty years or so, advances in modelling leverage time. Think of event-based programming, DDD, event modelling et al. Time is the common distinguishing factor.
When implementing OOP, I use messages which state an event in time. This leads to a clean model because it’s how human beings think.
What is absent is the idea of “command”. I find this isn’t necessary. Commands allow for a multitude of outcomes. If instead, objects state what has happened, it is unambiguous.
Conclusion
We’re at the tipping point toward a message-based OOP implementation. Next we’ll look at how to get rid of the necessity of “request-response” / “call-return”.
https://github.com/goofballLogic/modd/tree/article-2023/articles/002-CallAndResponse