Decouple Third Party Code From Core React Code

And reduce the size of your future PRs with the Open/Closed Principle
KNOW YOUR ENEMY
(image by Klara Kulikova, meme from Programming Memes)

Suppose I use a third party service provider to process payments for my E-commerce app, and I need to embed some third party code to integrate the payment service into my app.

In this oversimplified example, let’s say the payment service is responsible for checking whether a given payment method (e.g, Apple Pay and Google Pay) is available based on the customer’s device, region, etc. While my “core” UI component PaymentOptions is responsible for rendering the available payment methods as options. Lastly, I want the flexibility of adding new payment methods in the future (for 📈💰reasons).

I can write it this way.

However, the UI code is tightly coupled with the third party code from the payment service, i.e., I have to modify the PaymentOptions component in order to add a new payment method or to make third party code updates.


I can perhaps break out the third party code into a separate hook.

However, I still have to modify PaymentOptions and any other components that share the usePaymentMethods hook if I wanted to add, for example, isPaypalAvailable.


To minimize the size of future PRs, I’ve been thinking about the Open/Closed Principle, the “O” in SOLID (check out this excellent explainer): “A software artifact should be open for extension but closed for modification.”

In my own words: I should design this feature in such a way that I don’t have to touch any of the original code I wrote (closed for modification) if I were to add new payment methods in the future (open for extension).

Here’s my take on this principle. Let’s separate the payment service into its own module: a simple object where each key represents a payment method. Every payment method key points to an object with an isAvailable property (a function that uses the third party code) and a component property (the UI component for the payment option).

Import paymentServiceModule into the PaymentOptions component.

PaymentOptions is now decoupled from the third party implementation details, and is ignorant of the particular payment methods.

When I want to extend this feature with a new payment method (i.e., PayPal), I simply slot in a new key/value pair to paymentServiceModule without having to modify either the PaymentOptions component or the original payment methods.

The UI code should in theory also be protected against modification if I were to change payment service providers (for 💸 reasons) as long as the payment method’s duck typing remains unchanged.

Am I applying the Open/Closed Principle correctly? Curious to learn other React or JavaScript patterns in the wild that follow this principle.


Bonus

In paymentServiceModule, lazy load each payment option using the React.lazy API.

In PaymentOptions, wrap each payment option in Suspense, to lazy load the component based on availability.


Resources


Read More


📫 Let’s connect on LinkedIn or Twitter!