Yes. This is Spider Man. You may wondering what he is doing here, in an article about programing, about patterns and other computer-science related marketing bullshit.
So, he just wants you to recall one thing:
With great power comes great responsibility
Lets enumerate powers
we do have:
— Functions
— Classes
— Variables
Nothing more. And these are not powers
, these are elements
.
And you can use that elements to create powerful spells in a different forms:
— FP
— FRP
— OOP
— imperative style
— anything else
Thats the secret — “Favor object composition over class inheritance” does not means “classes are sux, function rules!”, or ”there is not other way that FP”.
That means —”With great power comes great responsibility”, and you have to handle everything with a care. Or magic powers will burn you.
I deside to write this article after mediumtating at Eric Elliott`s the “Composing Software” series_._
Let me first hightlight some articles, which I highly recomend you to read first:
The Rise and Fall and Rise of Functional Programming (Composing Software)_Note: This is part 1 of the “Composing Software” series on learning functional programming and compositional software…_medium.com
Composing Software: An Introduction_Note: This is the introduction to the “Composing Software” series on learning functional programming and compositional…_medium.com
It sounds like you’re talking about architecture._FP vs OOP is a false dichotomy._medium.com
They all are very very interesting but we will try to dig from another point of view.
In the beginning of computer science, before most of computer science was actually done on computers, there lived two great computer scientists: Alonzo Church, and Alan Turing. They produced two different, but equivalent universal models of computation. Both models could compute anything that can be computed (hence, “universal”).
Alonzo Church invented lambda calculus. Lambda calculus is a universal model of computation based on function application. Alan Turing is known for the turing machine. A turing machine is a universal model of computation that defines a theoretical device that manipulates symbols on a strip of tape.
Together, they collaborated to show that lambda calculus and the turing machine are functionally equivalent.
— The Rise and Fall and Rise of Functional Programming
And now you may found a turing machine inside any digital signal processor, and even imperative programming style.
This is how turing works — step by step.
Lambda calculus working in a different manner. Program is a endless flow
thought inputs and output. Thought pipes.
And a some value in a some point is a combination of inputs and outputs. Only. Pure math. Pure functions.
And lambda creates a world of analog devices.
From now please treat imperative style as turing “TODO list”, and functional style as lambda “vacuum lamp”.
And do not forget — they are equal. And all FP code you may write will be compiled to bytecode and executed in a turing machine. But that turing machine will physically runs on analog atoms of CPU module.
This is endless.
I hope you know, but first computer were analog. And first devices were analog. And near to all modern military or space devices are still analog.
Long story short, but my father was a programer, and actually he had launched rockets to the sky.
In a real, not like Google do.
And one day I asked him — “What were you doing at work”.
He replied: “I was told to build analog schemes with self testing mechanics”.
I asked again: “Analog? But why? You should use normal digital processing!”
And got an answer: “Cos static wiring is resistant to any changes. Nothing can change the way “program” work. Rewire it. Nor exeption, Nor radiation, Nor Americans”.
Let me rephrase:
With a functional approach you will get more testable, maintainable and predictable code.
But, as long functional approach is functionally equivalent to imperative — you can use imperative style inside functional block.
Just because this is not a programing approach, but architecture.
If you build your application from an isolated blocks, connected to each other via functional pipes
— you will get something like microscheme, like a analog device. And each element is a black-box. No mater that lays inside.
So, 30 years later computers evolve a bit, and digital era begins. Brand new CPUs enables every one to use high level languages, and..
One use that great power without great responsibility.
New languages were new, they were fast, they were build to handle new CPUs, they change the world.
But they werent designed well to handle old functional style like Lisp can handle.
Ok, any reason why you should support some old crapy shit/shitty crap?
And if now someone asks me — what do you prefer Lisp, Closure or Java — I will chose Java (ok, I will chose JavaScript).
Our fathers do the same. And functional programing had fallen.
And then someone invent classes and OOP. In 1966. And 30 years later one of “fathers” of OOP said:
Actually I made up the term “object-oriented”, and I can tell you I did not have C++ in mind. — Alan Kay.
So “classes” and “OOP” in C++, Java, JavaScript — are not “classes” or “OOP”. And they are “NOT” only in Alans “meaning”.
Like: you are not a man, you are not a lady, you know nothing Jon Snow.
This is just a names. And they can differs from language to languare.
And if Alan did not treat modern classes as classes — that does not mean that modern classes are bad, or even “not a real classes”.
It is an open question why he awaits for 30 years, and why computer science could not evolve by its own way and must stay in some limits.
But Gang of Four said “Favor object composition over class inheritance” not today. They did it 20 years ago.
And, if you read a book, you may remember why they said so.
And now, please, try to understand next:
People, who invent and implement OOP and classes were VERY smart people. Smarter than you.
They actually can handle the power of OOP, and had NO issues with it.
Unfortunately you are dumb, or just not as smart as founders, or just do not use BDUF.
And even, if you are smart, have a lot of time for BDUF and etc — someone after you might be not.
As internet said:
This is a relic from the waterfall era before everyone became cool and Agile.
This acronym is here to remind us not get over carried with super complex architecture. We shouldn’t spend 3 months designing our application before even writing the first line of code. Start small and iterate.
You will NOT have any problems on well designed system, and can just ignore any articles and advices. They all for others, not such pretty designed, ones.
All advices, books and patterns, tests and best practices aimed to solve only one issue:
Help to build and maintain NOT well designed systems. Help someone after you maintain your code. Force someone before you, to leave code you will understand and accept.
Helps work as and in a team.
And, in case of any friction, you will not get well designed system. And, in my experience — even if you will design a well designed system
— in few years you can realize - it was not.
PS: JFYI, most of application does not live so long.
But I still did not provide an information about why “Favor object composition over class inheritance” is misunderstand.
Let me once again post a phrase by Eric Elliott
FP vs OOP is a false dichotomy.
And I can say:
Object composition over vs class inheritance is like a micro vs soft.
There is nothing similar between composition and inheritance.
They both can do different things in a different ways.
They both gives you a power. It is up to you how to use it.
You can create an object, which will compose functionality from other objects, and next use inheritance to modify it behavior.
Or you can create a static wiring scheme, and use inheritance to modify behavior of atoms.
Let me cite Eric one more (last!) time
I was told that software development is “the act of breaking a complex problem down into smaller problems, and composing simple solutions to form a complete solution to the complex problem.”
One of my biggest regrets in life is that I failed to understand the significance of that lesson early on.
Object composition — is an artitecture. The greedy way to break complex problem to smaller and doable ones.
Class inheritance — is a tool. A building block. A saw.
And most of problems of class inheritance has roots in uncompleted decomposition.
Just think about — if you can achieve perfect results without using advanced tools — what can you do with it?
The last trap is the hardest one.
If you used inheritance “too much” — you will entangle you code. It will be hard to “unentangle” then the time comes.
If you used decomposition “too much” — you will also entangle you code. It will hard to find the way thought threads between small-small-small atomic components build with a “single responsibility principle”.
You have to think about tiers, inputs and outputs, slots and signals, blocks, and trying to build whole application using standalone black boxes.
Divide and Conquer!
Always keep in mind —
Expect Responsibility.
All magic comes with a price.
PS: CSS! Atomic CSS! Functional CSS! BEM! — that is the real battle area….