Inheritance and Composition in Business Application Design

Why inheritance and composition should not be treated as mutually exclusive concepts in business application architecture.

This note continues from Form AJAX Standardization , Page Lifecycle Coordination , and CotomyElement Boundary .

Early Programming Experience

I first learned programming at technical college. The first language was COBOL, and after that I studied C.

COBOL, however, never became my practical language at work. Unfortunately, by the time I graduated COBOL was already considered a declining technology, and there were plenty of experienced engineers around. A brand-new developer like me was not exactly in high demand.

The first language I actually used professionally was Visual C++. That was also my first real experience with object-oriented programming. In the early 2000s, inheritance was used very naturally when modeling domain structures. Encapsulation, polymorphism through inheritance, and the idea that data and behavior should be packaged together were often described as a major conceptual shift from structured programming.

To be honest, I did not strongly feel that shift at the time, probably because my own skill level was still low. I was still busy learning how to build things that simply worked. But for engineers who were already performing at a high level in that period, I believe the transition was much more impactful.

How Object-Oriented Thinking Was Drilled Into Us

At that time, junior programmers were drilled on two relationships as core foundations: is-a and has-a. I was taught those repeatedly, and I treated them as one of the most important practical anchors when learning object-oriented design.

Looking back, I sometimes think even other OOP elements were often explained through that lens by the people teaching us. Whether that was their explicit intention or not, at least in my case the message was very consistent: understand is-a and has-a first, then build the rest of your design thinking on top of that.

After more than ten years of mostly solo development, one thing has become clear to me recently. The industry perspective around those concepts has shifted quite a lot.

Cotomy and Classical OOP

Cotomy itself is still built in what many people today would call a more classical object-oriented style. Many frameworks, even modern ones, still rely heavily on inheritance internally when they need to structure behavior at scale. CotomyPageController and other base classes in Cotomy follow that approach.

This is not a claim that inheritance is universally superior. My personal view is simpler. The most important practical value of object-oriented programming is that data and the operations acting on that data are defined together.

Humans are not very good at connecting data defined in one place with behavior defined somewhere else. When those two are separated too much, mental distance grows. That distance is not an abstract concern for me. It is one of the main causes of fragile design in real projects.

Cotomy itself is designed to reduce those distances wherever possible. One visible example is that CotomyElement accepts HTML and scoped CSS together. That choice was intentional. I did not avoid TSX-style embedded HTML because of technical limitations. I avoided it because I preferred a different architectural boundary.

The Modern Frontend Position

In modern frontend development, inheritance is often discouraged.

Ideas like this already existed more than ten years ago, but the context was different. Earlier discussions were often about inheritance in data modeling. In that area, a base class can create strong pressure against change. Once many parts of the model depend on one inheritance line, even small changes can become expensive. Systems can become harder to evolve while they are still under active development.

I am relatively comfortable with inheritance and tend to use it more than many current frontend discussions would suggest. Even then, I do not use inheritance just to share processing, especially in domain models. That kind of inheritance often creates accidental coupling rather than design clarity.

At the same time, if a base type is semantically complete and truly stands as a valid abstraction, I think it should be inherited even when it is an abstract class. For me, the key is not whether inheritance is fashionable, but whether the meaning of the base remains structurally sound.

The Composition Recommendation

Modern guidance often says composition should be preferred over inheritance.

I understand why that recommendation spread, but the phrase has always felt a little strange to me. Inheritance and composition represent different kinds of relationships in object-oriented design. They solve different problems.

Inheritance and Composition in Practice

A very ordinary example is Windows Forms. A screen class inherits from Form. Then controls are placed inside the form. That second part is composition.

This pattern is natural and common. Cotomy follows the same pattern. A page controller is inherited as a structural base, and then elements and forms are composed inside the page.

I do not believe inheritance should solve everything. But composition also does not solve everything.

Cotomy itself intentionally uses both approaches. Page controllers are defined through inheritance, while UI elements and forms are composed inside the page. This separation keeps responsibilities clear.

React and Composition-Driven Frameworks

Frameworks such as React are designed around composition from the beginning. With that architecture, inheritance is less practical as a primary design mechanism.

React itself still uses inheritance internally through React.Component, but component reuse and extension are expected to be implemented through composition rather than subclassing.

I personally do not prefer that style, but I can understand why it became dominant.

A Broader View

Most modern language features exist for one practical purpose: helping humans understand large and complex systems.

Software systems are fragile logical constructions. Encapsulation, inheritance, composition, and modularization are all tools for reducing cognitive load. None of them is perfect, and each can be misused.

For that reason, I am cautious about arguments that fully reject one feature only because it can be abused. Misuse is real, but complete rejection is not always productive.

Conclusion

Inheritance can certainly be abused, and many teams have painful examples of that. Still, rejecting it entirely may also discard a useful conceptual tool.

For engineers who need to deliver reliable systems under time constraints, the goal is not ideological purity. The goal is clarity of design.

Design Series

This article is part of the Cotomy Design Series, which explores architectural decisions behind the framework.

Series articles: CotomyElement Boundary , Page Lifecycle Coordination , Form AJAX Standardization , Inheritance and Composition in Business Application Design, API Exception Mapping and Validation Strategy , and Why Modern Developers Avoid Inheritance .

Next article: API Exception Mapping and Validation Strategy

Learn Cotomy

Cotomy is a DOM-first UI runtime for long-lived business applications.