It's good to read from the OP and in this thread yet more explanations of what OOP was supposed to be about. Okay.
So, in my current project, I make a lot of use of the classes in .NET and have defined some classes with some methods, etc. Okay -- the encapsulation seems to help make the code easier to understand and debug.
I have made some use of polymorphism, and mostly I like it. So, I use interfaces, and, really, those are a lot like, but much less powerful than, what I used to do in languages where I passed as an argument to a subroutine or function the name of a subroutine or function the subroutine or function could call. E.g., in solving an initial value problem for an ordinary differential equation, have a function that does that and pass to the function a function that will evaluate the differential equation. For finding the minimum value of a function X, have a function Y that is a general purpose function minimizer and pass X to Y and let Y do the work of finding the minimum value of X.
For inheritance, .NET seems to use a lot of it, at least in their documentation, but so far in the code I've written I've never used any of inheritance. I love hierarchical file systems and the idea of inheritances of capabilities and access control lists (ACLs), but I don't really like the idea of inheritance among OOP classes. Sorry 'bout that.
If I want to build an outhouse, then I don't want to inherit a small house and add a toilet -- instead, I just want an outhouse.
For passing messages, sure, I saw that in Smalltalk but never thought to use it among objects in one program.
My server farm architecture and software does have some message passing among some of the back end servers. For a case of that, sure, OOP helps: For the data to be passed, I define a class, allocate an instance, put data into the members of the instance, serialize the instance to a byte string, send the byte string via just old TCP/IP sockets, wait for the response, a byte string, deserialize the byte string to an instance of the class that is supposed to get the returned data, and continue on. If there is an error, then the code writes a message to the Web site log file and returns a notification of an error to the user. Works fine.
For immutable state, no thanks -- e.g., in software about a car, the current state is position and velocity, and as the car moves that state changes and is not immutable. The speedometer of the car does not have immutable state, either, nor the steering, throttle setting, transmission gear, etc. Sure, could define an immutable state separately for each instance of time, but I guess that speedometer makers didn't think of that. If I put some raw meat in the oven and cook it, what comes out should be a good roast, and not something immutable. I think of state as changing, not as immutable.
Some of what the OP describes that is supposed to be real OOP, I was never tempted! No thanks! I never tried that and never would. To me, those rules were obviously nonsense, like programming standing on my head. Able to do it? Yes. Want to do it? No. A good idea anyway? Nope. Good to read that author of the OP now agrees!
But that de/serialization to/from a byte string, I like that! The .NET classes, sure, they are very nice to have. For sending data from one server to another, sure, define a class, allocate an instance, assign values to the members, and send the data -- terrific, easy to understand, works great. E.g, the data I send might be fairly complicated, but classes usually have enough generality that can define good places for all the complicated data.
And, can have arrays of object instances -- terrific! And one of the members of a class can be an instance of another class -- I do some of that.
And the methods have some name scoping, and I very much like that -- I wish that scope of names was much more finely grained, as in Algol and PL/I.
Otherwise I program much like I always have back through lots of various programming languages.
How to make the code easy to understand? By far the most important way is documentation, clearly written in English. Think of a freshman text in calculus or physics: The equations are like the code, and the text is like the documentation of the code. Math is written in complete sentences; there is never any attempt to make the symbols and expressions understandable by themselves. And my code is understandable mostly only due to the documentation. Between the documentation and the code, the documentation is the more important. I make essentially no attempt to write self documenting code, no more than a calculus text author tried to write self-explanatory equations.
For more, sure, I have a lot of functions. A function does something easy to document with logic easy to understand. It helps if each function is short and has relatively few arguments. The documentation for the function describes what the function does -- this is what you give to the function, this is what the function does, and this is what comes back from the function. If that's all nice and clear, then that's usually good enough for well written code.
Sure, in simple terms, a program has four steps:
(1) Get input data.
(2) Process the input data.
(3) Send output data.
(4) Return to (1).
Step (2) is essentially a function. It reads its argument, processes that data, and returns its results to the arguments and/or the function value. To do this, this function does its version of (1)-(3).
A server? It does (1)-(4).
I call all of this, SCSONUPS -- simple, common sense, obvious, nearly universal programming style. No, no, no, don't thank me. Don't make me famous. No, I won't be writing any books or giving any seminars. I have nothing on Github. If this style is not obviously simple, then I apologize.
I'm not writing code for anyone else. Instead, I own my own business and am writing code for my own business. So, I'm reporting only to myself and am free to write the code anyway I want to. The code I have, I like. With all the documentation, the code is relatively easy to understand and change.
Really the code is organized much like usual work, say, in cooking, lawn maintenance, car maintenance, washing dishes, etc., and the documentation is much like descriptions for how to do such work.
Enough with programming style!