Altamar Labs
Back to Blog
architecture· 2 min read

Extending a third-party framework without touching its core

When the right answer isn't forking or patching, but designing your feature as a well-behaved external citizen of the system you're extending.

Any mature e-commerce framework, CMS, or backoffice eventually hits a point where it doesn't cover exactly what your business needs. The instinctive reaction is usually one of two things: fork the framework and modify it directly, or scatter business-specific patches through the framework's own logic. Both solve the problem in the short term and make it worse long term. The first desyncs you from future updates, the second turns every update into a negotiation with your own code.

The question that changes the design

Before writing a single line, it's worth asking a simple question: does this feature need to live inside the framework, or can it live alongside it, observing and reacting to its events?

A concrete example: building a referral program on top of an existing e-commerce framework. The temptation is to modify the framework's order model to add referral fields. The alternative, almost always better, is to treat the referral program as its own module, with its own models (ReferralCode, ReferralCredit, ReferralUse), subscribing to events the framework already emits (an order completed, a user created) without needing to touch a single line of the core.

Why this matters more than it seems

The difference isn't cosmetic. It's a matter of coupling surface:

  • If your code lives inside the framework, every update to that dependency is a potential merge conflict between your business logic and the maintainer's internal changes.
  • If your code lives alongside the framework, reacting to events and extending through composition (hooks, callbacks, an observer pattern), a framework update rarely breaks your module, because your module never depended on its internals, only on its public event contract.

This is, in essence, the dependency inversion principle applied to the relationship between your business and an external dependency you don't control: depend on abstractions (events, contracts), not on the framework's concrete implementation.

The cost you do have to accept

This discipline isn't free. Designing as an external module forces you to solve problems that direct core access would trivially solve, for example, how to prevent two concurrent processes from using the same referral code twice, or how to expire credits consistently without a job that depends on internal framework details. The discipline of staying out of the core forces you to solve those problems explicitly, in your own domain, instead of silently leaning on internal framework guarantees that can change without notice.

The lesson that generalizes

This isn't unique to e-commerce. Any integration with a third-party system, a CRM, an ERP, a payment platform, faces the same decision: do I extend the system from within, or build around it? The answer almost always favors building around it, and the cost of doing it right, modeling your own domain, depending on public contracts rather than internal implementation, gets paid once. The cost of not doing it gets paid on every update, forever.