July 22nd, 2024

When Objects Are Not Enough

Tony Messias examines Object-Oriented Programming's foundations, emphasizing actions in Laravel, historical context from Smalltalk, and critiques modern interpretations, advocating for a deeper understanding of OOP principles and experimentation.

Read original articleLink Icon
When Objects Are Not Enough

Tony Messias explores the foundations of Object-Oriented Programming (OOP) in his article, focusing on the concept of Actions within the Laravel community. He references the book "Smalltalk, Objects, and Design" to highlight the historical context of OOP, particularly its origins in Smalltalk, which introduced key concepts like inheritance and message-passing. Alan Kay, who coined the term OOP, argues that objects alone do not provide a complete architecture; rather, the interactions between objects are crucial for building scalable systems. Messias discusses the misconception of equating objects with types, emphasizing that objects should encapsulate state and behavior, while types are merely abstractions.

He critiques modern interpretations of OOP, particularly in languages like Java and C++, suggesting they have strayed from the original principles of messaging, encapsulation, and late-binding. The article also delves into the concept of reification, where abstract concepts are treated as tangible objects in software design. Messias illustrates this with a banking example, demonstrating how to model transactions as objects rather than merely manipulating account balances. He introduces polymorphism as a means to implement different transaction types while maintaining a consistent interface. The article concludes by encouraging experimentation with OOP principles to adapt to evolving requirements in software development, advocating for a deeper understanding of OOP's foundational concepts.

Related

Smalltalk syntax in 7 minutes [video]

Smalltalk syntax in 7 minutes [video]

The YouTube video explains Smalltalk syntax, emphasizing readability and message-based object interaction. It covers keywords, arrays, closures, and method execution in Pharo Smalltalk, providing a practical example and additional learning resources.

Optimizing JavaScript for Fun and for Profit

Optimizing JavaScript for Fun and for Profit

Optimizing JavaScript code for performance involves benchmarking, avoiding unnecessary work, string comparisons, and diverse object shapes. JavaScript engines optimize based on object shapes, impacting array/object methods and indirection. Creating objects with the same shape improves optimization, cautioning against slower functional programming methods. Costs of indirection like proxy objects and function calls affect performance. Code examples and benchmarks demonstrate optimization variances.

Post-Architecture: Premature Abstraction Is the Root of All Evil

Post-Architecture: Premature Abstraction Is the Root of All Evil

The article explores Post-Architecture in software development, cautioning against premature abstraction. It promotes simplicity, procedural programming, and selective abstraction for maintainable and efficient code.

Reflection: Smalltalk's Most Enduring Idea? By Bryan Foote (2017)

Reflection: Smalltalk's Most Enduring Idea? By Bryan Foote (2017)

The video discusses the importance of small talk in programming, drawing from object-oriented training and Smalltalk experience. The speaker explores meta objects in their master's thesis, emphasizing the need for additional resources.

My programming beliefs as of July 2024

My programming beliefs as of July 2024

Evan Hahn emphasizes tailored programming approaches, distinguishing "simple" from "easy," promoting testability through modularity, and advocating for ethical coding practices prioritizing societal impact and nuanced thinking in software development.

Link Icon 15 comments
By @bob1029 - 4 months
The objects are just one tool. You usually need a few to do the job well.

The biggest thing I've seen blow up actual OOP projects has been a lack of respect for circular dependencies in the underlying domain. If you have one of those problems where it is ambiguous which type "owns" another type, then the moment you start writing methods in these types you are treading into the dark forest. Often times it is unclear that your problem exhibits circular dependencies until code is already being written and shipped.

My approach to these situations is to start with a relational data model. A SQL schema (and its representative DTOs) can model circular dependencies competently. You can then have additional object models (views) that can be populated by the same relational data store (just a different query). One other advantage with the relational modeling approach is that it is very easy to explain things to the business before you write a single line of code [0]. The purpose of a SQL table can be demonstrated with a sample excel sheet with mock business data.

This path was largely inspired by Out of the Tar Pit [1] and practical experience in fairly wicked domains (semiconductor mfg., banking, etc). I am not sure Functional Relational Programming is the answer for everything, but the "Relational" part certainly seems to be universally applicable.

[0]: https://en.wikiquote.org/wiki/Fred_Brooks#:~:text=Show%20me%....

[1]: https://curtclifton.net/papers/MoseleyMarks06a.pdf

By @mattgreenrocks - 4 months
I want to re-read this and think about it more.

But one thing stuck out: I never liked most of the distillation of actions as clean architecture would advocate for, be they lambdas in class form (DepositAction) or interactors. I feel strongly that they are the right thing in describing business logic, however.

What did click for me is the conceit of a service, which the JVM world embraces. Services are plain old objects that have a method for each action you'd like to model. This is nicer than the aforementioned approaches because there is often common code to different actions. Like actions, services are the place where validation happens, persistence happens, and all of the interesting business logic. IO and orthogonal concerns are injected into them (via constructor), which lets you write tests about the core logic pretty easily.

What you get is the ability to reason about what happens without the incidental complexity of the web. Web handlers then boil down to decoding input, passing it to the service, examining the result of calling an action, and then outputting the appropriate data.

That's all they should've ever been doing. :)

By @ChrisMarshallNY - 4 months
> An object has state and operations combined.

My own definition has always been that an object has state and identity.

I have never considered functions/methods to be a requirement for something to be an object.

By @PaulHoule - 4 months
+1 for use of the word "Reification"!

There's another universe of object-adjacent systems that may or may not be connected with conventional OO programming languages. Two examples I'd point to are Microsoft's COM (designed so it is straightforward to write and call COM objects from C) and the "objects" in IBM's OS/400. In both of those cases I think the reification is the important thing, although you can see reification in Java's object headers where objects get a number of attributes necessary for garbage collection, concurrency control, etc.

By @ryandv - 4 months
> Smalltalk was one of the first Object-Oriented Programming Languages out there. It's where ideas like inheritance and message-passing came from (or at least where they got popular, from what I understand);

It may be worth pointing out that while Smalltalk is arguably one of the key languages that popularized such ideas and other OOP concepts, these were first introduced by Simula 67.

By @adityaathalye - 4 months
I enjoyed this post a lot. I happened to blog about the same thing from the FP side of things [1] (well, because Closures are just the poor man's Objects).

Generally, I don't know how to (philosophically) navigate the tensions between Functional / Object Oriented / Imperative / Declarative paradigms, except to remind myself about The Thing That Actually Matters (in my estimation)... to always remember that The State is the frenemy.

For the love of State is the root of all evil: which while some coveted after, they have erred from Lambda the Ultimate, and pierced themselves through with many sorrows. --- Yours Truly.

:)

[1] https://www.evalapply.org/posts/what-makes-functional-progra...

(edit: forgot to link to blog post)

By @artemonster - 4 months
I never liked „OOPs world“ obsession with a receiver. Why the hell receiver of a message gets to dispatch the implementation at very late moment? Why not context? And when there are many receivers? I.e. a composite object of an int and a float receive message „add“ - who decides which implementation to use and why the heck any of them may even know how to add self to another? There were many attempts to solve this and all were horrible (i.e. extension methods). I have been experimenting with these concepts too (i.e. a receiverless message is a throw, which will be picked up by an enclosing effect handler via pattern match), but its all unreadable and unmaintainble mess. Anyone doing the same thing? I would love to exchange thoughts :) extras to read: ian piumarta‘s papers on his OOP system and a paper on Korz programming language
By @stonethrowaway - 4 months
I want to agree with this but it’s a surface level concern. I’m not trying to belittle the author’s point but I do want to emphasize something that isn’t talked about enough.

Reification has two meanings in software development. Author uses one, the more familiar one - it’s discussed in many books on DDD. The other is a bit more vague and unapproachable. It’s the one I want to bring to peoples attention. It can be summed up as: “Accounts, transactions and balances are not enough.”

Jim Weirich hints at this perfectly in his approach to solving the Coffee Maker [0]. I’ll quote the punch line for everyone:

> Some people may be uncomfortable with the divergence of the Analysis and the Design models. Perhaps they expect that the design model will just be a refinement of the analysis. Remember that analysis is an attempt to understand the problem domain. Although we use OO tools to represent our understanding, that understanding has only an indirect influence on the structure of the software solution (in that the software must actually provide a solution). In fact, as we refine our software design, we will find that it moves even farther away from the analysis model. Solutions oriented classes, which do not appear in analysis, will be added to the design. Classes that came from the analysis model may mutate or even disappear entirely.

This is the form of reification that I believe is more closely associated with how the term is used in classical OOD (f.e. Object Oriented Software Engineering: A Use Case Driven Approach), but I suppose people’s experiences may disagree. This is a kind of “right layer of abstraction” that has to be pontificated and not just put down as an object because it’s a process or a “thing” from the outwardly-behavioural view of the situation.

As I mentioned, it’s not talked about enough. Jim is right to call it out: it’s uncomfortable because it’s having to dig deep into the system ontology.

[0] http://www.cs.unibo.it/cianca/wwwpages/ids/esempi/coffee.pdf

By @deterministic - 4 months
What works for me:

There are two types of objects: State objects and Tool objects.

The purpose of a State object is to maintain a state. Think strings, databases, files etc.

The purpose of a Tool object is to operate on State objects. Think loaders, printers, editors, transformers etc.

It’s a simple way to organise OO code. And it works. At very large scale (millions of lines of C++).

It is similar to the functional Data/Function thinking. However it actually works better because State objects can enforce constraints, and Tool objects can cleanly maintain an internal temporary state while operating on State objects.

By @wseqyrku - 4 months
Objects are just the poor man's actors. If you want to see what encompasses objects and more, look up the actor model.

That's what I thought this article is going to talk about but not even a honorary mention.

By @smitty1e - 4 months
Needs "2021" in the headline
By @menotyou - 4 months
Yet another article about problems you'd never have if you wouldn't use object oriented paradigm.