Decouple SDK Code From Core React Code

And reduce the size of your future PRs with the Open/Closed Principle

Suhan šŸŽƒ Wijaya
JavaScript in Plain English

--

KNOW YOUR ENEMY (image by Klara Kulikova, meme from Programming Memes)

Suppose I use an external service provider to process payments for my E-commerce app, and I need to embed some external SDK 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 external 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 SDK updates.

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

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 SDK code) and a component property (the UI component for the payment option).

Import paymentServiceModule into the PaymentOptions component.

PaymentOptions is now decoupled from the SDK 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.

šŸ“« Letā€™s connect on LinkedIn or email!

--

--