7 ms·
IMO, the most important philosophy in all of software engineering is "Separation of responsibilities." The best way to achieve it is through the principle of "H
by socketcluster 3mo ago
IMO, the most important philosophy in all of software engineering is "Separation of responsibilities." The best way to achieve it is through the principle of "High cohesion, loose coupling."
OOP is just another layer of philosophy which builds on top of that. It's more specific, imposes additional guardrails. It requires objects with state encapsulation (locality) and message-passing as the mechanism for components to interact with each other; each component is responsible for changing a subset of the state of the system. Each component is responsible for handling messages (calls to action) by performing local state changes and potentially also sending messages to other components which have more specific sub-responsibilities.
OOP without "High cohesion, loose coupling" is almost worthless IMO. It must build on top.
I think were most people fail with OOP is that they think coming up with good separation of concerns, good abstractions is easy. They just start implementing the first idea which comes out of their heads and then figure out the scope of responsibilities as they go.
The test for good separation of concerns is that you should be able to explain your architecture to someone with the intellect of a 9 year old child who happens to understand the business domain. I'm not exaggerating. It has to be that obvious or else you will not be able to maintain clean separation... You will not be able to maintain alignment in your team.
If the responsibilities of a specific object are somewhat vague, what will happen is that the scope of responsibilities between objects will soon blur and the messages between objects will start to look increasingly elaborate; your system will look like a bunch of horrible incompetent managers trying to micromanage junior employees using long, convoluted instructions and occasionally throwing chairs at them...
If your system is passing around object references all over the place; that's usually a sign of poor separation of concerns; passing around complex objects by reference is tight coupling, by definition. Each object, each person should be able to fulfill their responsibilities and finish the job using communication only.
- sirwhinesalot 3mo agoI agree "high cohesion, loose coupling" is a good architectural property to strive for, but OOP is terrible at it and there's no reason to use it for this. Trying to achieve "high cohesion, loose coupling" in OOP has led to the creation of (supposedly) best practice recommendations like the SOLID principles, and the development of monstrosities like dependency injection frameworks. If OOP was actually good at "high cohesion, loose coupling", you wouldn't need them.
- KayEss 3mo agoI think this is looking at what OOP has become (as implemented by systems and programming languages that don't care a wit about what OO was meant to be) rather than what Alan Kay described. If you think about something like a web server as an object, it has arbitrarily high cohesion and arbitrarily low coupling. You can only communicate to it through messages (HTTP); binding happens at the point in time that the message arrives (notwithstanding that this may be cached in all sorts of interesting ways in the implementation of any given server); and the web server is fully encapsulated (security flaws notwithstanding). I think it's perfectly reasonable to argue that much of what gets called OOP doesn't deliver on the promise, but then it doesn't deliver on the premise either, and I think these are inextricably linked.
- sirwhinesalot 3mo agoThe Alan Kay variant of OOP is superior in this regard, and I'd argue the Erlang variant even more so (Actors are just asynchronous objects). But both of them are still suboptimal because they allow objects to instantiate one another and to directly communicate with whomever they come in contact with. That creates strong coupling and you have to "fight the paradigm" to avoid it. Other engineering domains have this figured out: components can only send and receive data through ports, they are never aware of their siblings. Only a component at a higher level of abstraction can decide how the ports of lower level components connect to one another. That completely eliminates coupling. (You can of course replicate this type of architecture with OOP, but you can also replicate it with any turing complete paradigm, that's neither here nor there)
- Folcon 3mo agoWhen you say other engineering domains have figured this out, can you give a more specific example?
- sirwhinesalot 3mo agoYes, for example if you are doing any sort of mechatronic systems engineering (cars, planes, rockets, etc.), you're typically using tools like Simcenter Amesim or Modelica or Simulink/Stateflow to digitally prototype the system. These tools are all oriented around blocks with ports. They receive data on their input ports and emit data on their output ports. They do not know where that data is coming from nor where it is going. They cannot instantiate other blocks. To create a new block you either create a primitive one (described directly in terms of differential equations, since these are physical simulations, or as actual code, be it C or MATLAB or whatever else), or you connect blocks together to form a larger block. This creates a strict hierarchy, connections between blocks can only happen at the same level of abstraction. You can just rip out a component and replace it with another with the same ports, or with multiple components each filling in part of the job, or you can plop another component in the middle that's only used to process the data inbound and redirect it somewhere else. This makes coupling extremely loose by design. The paradigm enforces it.
- Fire-Dragon-DoL 3mo agoThis resonates strongly with me, which is why I find more important having some form of namespacing than anything else. OOP has been muddied so much too, it would be interesting if we taught only the "separation of responsibilities" part and principles related to that. Often it comes up: who has write authority, that's something we don't teach as part of OOP, yet realizing that only one thing should do writing improves the code dramatically. Now that you see it, seems so obvious