I usually think of the ideas behind "composition" as "how do I assist a future developer to replace the current (exported) implementation of a type with a new one by restricting external visibility of its internal implementation through the use of private methods and data".
In "inheritance", it often feels like the programmer's mindset is static, along the lines of "here is a deep relationship that I discovered between 2 seemingly unrelated types", which ends up being frozen in time. For example, a later developer might want to make a subtle innovation to the base type; it can be quite frightening to see how this flows though the "derived" types without any explicit indiction.
Of course, YMMV, but I think of "composition" as "support change" and "inheritance" as "we found the 'correct way to think about this' and changes can be quite difficult".
Since I think that the key to building large systems handling complex requirements is 'how do we support disciplined change in the future' (empowering intellectual contributions by later generations of developers rather than just drudge maintenance).
Legacy corporations have a very hard time incorporating fundamental technology shifts (moving from ICE engine/drivetrain dominant designs to software dominance).
They walk into the future looking backward, unable to identify/vet the team skills needed going forward, leading to silly hacks like: 1) hire from "big s/w companies", 2) pay high salaries to poorly vetted people, 3) adopt all the new fashionable buzzwords like "software defined vehicle", 4) force new teams every inch of the way to justify design choices to mediocre legacy management.
The only formula I know that works is "hire good people and listen to them".
From experience, the only way legacy companies can do this is acquire and/or seriously partner with companies that have established a track record in what you need (even if it is only a couple of years, as long as they are _delivering product_).
As software effectiveness/innovation speed/productivity continue to increasingly crush legacy industries, it is extraordinarily frustrating to see how hard it is to make (seemingly simple!) changes.
Instead of looking at your high quality software as an "asset to monetize", I would recommend thinking of it as a "way to introduce your high quality skills to attract high quality customers that are more than willing to pay for your time".
This allows you to get money for customizing the software for specific applications, but still build up a valuable asset over time (instead of just being a T&M slave).
I spent ~11 years in Japan, porting/building telecom protocol software and, more importantly, trying to build software development and business competence in our teams. Sadly, although I had a reasonable impact on individual software engineers technical ability, I was unable to find any path to leverage that into "software business building" expertise.
Of course, the attribution of causes to this is highly subjective and I expect every person to come away from the elephant with a different interpretation.
In my case, the very, very top down 'age hierarchy' culture was (and continues unabated) to crush any ideas and proposals that come up from younger and more competent engineers. In the last 30 years with Japan, I have met only a small handful of people that are willing to take input, let alone change direction, from someone younger than them. (a trivial example was a fellow company director of mine that was born 5 _days_ earlier than me. In 4 years working together, not once would he take anything I said seriously. Hmm...)
Give the number of excellent Japanese software engineers that I know, the burden of this "culture" is (to me) quite tragic on its impact slowing down national progress in an important global field. If anyone as ideas how to get around this, I would love to know and learn.
When I first met him in 1978 and asked for his last name, he replied "Arvind is my name". He was very deeply against the caste system and felt that using last names (IIRC, which also indicated caste) was something that he refused to do from high school (his high school diploma name is just 'Arvind'). It seemed that this was a hassle his whole life, but one he continued because he felt so strongly.
He said that after 9/11, the US government came down very hard on MIT to force use of last names and that is the first time I ever knew what it was.
Deeply thoughtful, highly caring and warm to all the people he met, he will be deeply missed!
In "inheritance", it often feels like the programmer's mindset is static, along the lines of "here is a deep relationship that I discovered between 2 seemingly unrelated types", which ends up being frozen in time. For example, a later developer might want to make a subtle innovation to the base type; it can be quite frightening to see how this flows though the "derived" types without any explicit indiction.
Of course, YMMV, but I think of "composition" as "support change" and "inheritance" as "we found the 'correct way to think about this' and changes can be quite difficult".
Since I think that the key to building large systems handling complex requirements is 'how do we support disciplined change in the future' (empowering intellectual contributions by later generations of developers rather than just drudge maintenance).