The whole idea of OO has fundamental issues which prevent it from ever being properly reliable. The first of these is that from a fundamental philosophic level the idea is, in itself, broken. “Objects” (strictly, “types”) are intended to model “real world” behaviour. So you have a type called Aircraft
, a type called Flight
, a type called Passenger
, and so on. And then the types have behaviours which present a consistent interface to internal state management which the outside types aren’t privy to. So you might have an interface on the Aircraft
type along the lines of Aircraft.board(Passenger, Flight)
.
But is that right? Does that model the “real world”? Does the passenger board the Aircraft? Or the Flight? Thus, we could have multiple differences in perspective on whether the Flight is assigned the Aircraft, or vice-versa, or if the Passenger should board the Aircraft or the Flight. However the bigger issue is that we are trying to ascribe behaviours to a single object, and that is not how the world really works. Remember “object orientation” was about creating code “objects” that resembled “things” in the world, and relationships between them. Class electricCar
extends car
extends vehicle
.
Consider your laptop. Does your laptop have a hinge and a screen? Should it have a method
(a verb) called openScreen
? I mean, sure, maybe, but the world isn’t like that. The screen doesn’t open by itself. The screen opens when you reach out and open it with your hand.
We know where this all leads. We separate the “model”, the “view”, and the “controller”. The model is where our objects are, emptied of behaviours, except for a hundred getX
and setX
methods that add no value, just LOC. The behaviour is pushed to the view (screen composition) and to the controller (the “business logic”). These layers are often modelled as objects (BookingController
, FlightAssigner
, SeatMapView
), but they are not really. They’re just a collection of related verbs (functions) that operate on the model. The model is basically a gigantic struct
with mutator methods that offer little value. Nothing is “encapsulated.”
What’s the alternative? Some people will tell you it’s functional programming. And that’s certainly part of the piece. I’ve been finding the Akka framework very useful in helping me think about this. Akka implements an old, 1970s idea of “Actors.” These actors send and receive asynchronous messages. Actors can encapsulate both noun and verb: they are on object that encapsulates behaviour which is only available to other actors via the interface of the message. Actors can be written in either functional style, or in OO style: this is then a matter of preference (or language, as Akka is written in Scala and used a lot in that world, but as Scala is a “JVM” language, the developers ensure that it does come with a comprehensive Java API).
Of course, as I’ve said above, that’s not the only way to think about the world and model it with software. However in my world, where there is a lot of asynchronous event messaging, it becomes a natural way to express the domain problems that we face. Trying to force the domain into a bunch of synchronous services interconnected with only an ever-increasing complex model and a handful of CRUD verbs is mostly wrong.
More on this in a future post.