Photo by Joao Branco on Unsplash

Reactive programming: writing loosely coupled software in web

In software development, there are two key concepts when designing a maintainable architecture: coupling and cohesion. We should always aim for loosely coupled and highly cohesive software, and although it’s possible to achieve this in paper, to express it in the implementation could sometimes be difficult — if not impossible — if we don’t choose the right tools and solutions available for the language/environment we are using.

Why reactive programming?

First, why is reactive programming a good fit for web? Take a look at the following statements:

  • “When the user buys a product, send the data to the analytics tool”
  • “When the user account information is fetched and the location settings are available, then redirect the user to their preferred city”
  1. Decoupled code: minimal dependencies between different software components as they need only to know the available events so they can subscribe to them. No need to know implementation details like under which circumstances they are emitted or how exactly

How to do reactive programming in web (properly)

Although JavaScript is event-driven, it doesn’t mean reactive programming is built-in in the language — It requires a change of mindset and some basic setup. If you want to achieve it, you can follow these recommendations:

#1 Find a technically reliable global data stream that you can subscribe to

JavaScript provides many ways to do this, among which we can mention:

  1. RxJS library
  2. Angular + NgRx Store action stream
  3. Vue + Vuex action stream
  4. React + Redux action stream

#2 Consider all logic as a potential event for the stream

As JS is event-driven, all logic runs inside a handler of an existing event — even top-level code is executed on window.onload(or when the file is downloaded and executed).

async onAuthenticationFormSubmit(credentials) {
const session = await authenticateUser(credentials)
storeSession(session)

const accountDetails = await fetchAccountDetails(session.userId)
storeAccountDetails(accountDetails)
}
async onAuthenticationFormSubmit(credentials) {
const session = await authenticateUser(credentials)
storeSession(session)
dispatchEvent(
new CustomEvent('onUserAuthenticated', { details: session })
)
}
async onUserAuthenticated({ details }) {
const { userId } = details.session
const accountDetails = await fetchAccountDetails(userId)
storeAccountDetails(accountDetails)
}
  1. To populate the data stream with relevant events, making it reliable

#3 Never dispatch events that are not cohesive with the current handler

Following the same example, this is a big code smell:

async onAuthenticationFormSubmit(credentials) {
const session = await authenticateUser(credentials)
storeSession(session)
dispatchEvent(new CustomEvent('onFetchAccountDetails', {
details: session.userId
})
dispatchEvent(new CustomEvent('onSendAuthAnalyticsData', {
details: session
})
dispatchEvent(new CustomEvent('onUpdateUserLocation', {
details: session.userId
})
}
async onAuthenticationFormSubmit(credentials) {
const session = await authenticateUser(credentials)
storeSession(session)

dispatchEvent(new CustomEvent('onUserAuthenticated', {
details: session
})
}
window.onload = () => {
addEventListener('onUserAuthenticated', fetchAccountDetails)
addEventListener('onUserAuthenticated', sendAuthAnalytics)
addEventListener('onUserAuthenticated', updateUserLocation)
}
async fetchAccountDetails(event) { ... }
async sendAuthAnalytics(event) { ... }
async updateUserLocation(event) { ... }

#4 Expose the events to consumers as a contract

Think of the events you expose as a public API contract so you take them seriously when making changes — providing backward compatibility for example.

export const ON_USER_AUTHENTICATED = 'ON_USER_AUTHENTICATED'
export const ON_USER_SIGNED_OUT = 'ON_USER_SIGNED_OUT'
...

Summary

To write loosely coupled software is not an easy task and we need to choose the right solutions and tools so we can express our design in the implementation. In the case of web development, reactive programming is a natural and straight-forward way to achieve it.

Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store