In the previous blog post, I've discussed all the possible parameters and factors that you could encounter when designing your notification system. So with that knowledge, we can use it and forge ahead with the architecture.
Definitions and scope:
Before we architect a notification system, it is crucial to outline some definitions and scope. Why you might ask? Well, in order to tackle a problem, it is necessary to fully understand and know precisely what we are about to architect. This will automatically start to introduce not only a ubiquitous language, but give us the power to focus on things that matter within our system without deviating much out of scope while designing such architecture.
According to Cambridge dictionary, notification is defined as follows: “the act of telling someone officially about something, or a document that does something”, which we could infer from it that that notifications are mainly consumed by humans. A user action might trigger multiple events within your system that could reflect a notification on another user’s end (e.g. a user has been added, user have lost certain rights in the application, etc…). Moreover, a system domain event could trigger a notification that can be also consumed by the user.
These kind of systems are behavioral systems, and I think you already seeing it coming from a far, we are most probably going to utilize the observer pattern to model this system, perhaps an extended variation of it.
The following diagram shows the architecture and the flow of notifications while observing "Creating post action" by an actor as an example:
Figure 1: System flow overview
Dissecting the system:
In the above diagram, you can see a 10000-meter view of a system, where an actor is adding is performing a post action on the system. There are many things that might take place depending on what your enterprise system does; however, I've intentionally omitted all other details since it's outside of the scope of this blog series.
In this stage, when an action occurs, we start a domino effect process, where a domain event gets triggered (i.e. Action domain event), and then all sorts business rules start to activate accordingly within Service 1 or Service 2 in this particular case. You can imagine that all sorts of intricate service calls that have already took place. What we care about here though, is when the notification service receives these domain events.
Here I'm proposing that we have an observable per domain in our architecture. This will not only help satisfying the single responsibility principle, but will keep our code base clean and make it easier to keep track of notifications in the future. Moreover, we could deploy each of the observers in its own container, such that when a spike happens in any of them, it will be relatively easier to expand the number of nodes to handle the spike in that specific observer in case of a fan out. Furthermore, if the stake holders of the organization decided to introduce a new domain, you can just spawn up a new observer for that specific domain without the need to modify any of other observers.
The following diagram gives an overview of the Notification service
Figure 2: Inside the notification service
In this particular case, because of the raised action domain event, the targeted clients shall receive the appropriate notification on the appropriate notification channel(s). Since the domain event was raised in Service 1, couple notifications could be broadcast at the same time. For example, Notification 1 of Observer Service 1 (N1OS1) is sent to the end consumer U1, N2OS1 and N2OS1 are consumed by end users "U2" and "U3" respectively. It is important to note that each observer can have (N) number of notifications that can be dispatched to whatever target and whatever form you want (SMS notifications, email notifications, browser pop-up notifications, etc...). Of course, many actions could take place with other services as shown in the above diagrams, which should as a result dispatch the appropriate notifications for the targeted subscribers. Moreover, an end user(s) can be subscribed to multiple types of notifications as with U4 in this particular case.
Now that we have a clearer vision and architecture to follow, the next blog shall discuss implementing the seed for such a system.