Observer Versus Pub-Sub Design Patterns
Author: David Dieruf
What are the differences between the Publish Subscribe (Pub-Sub) pattern and the Observer pattern? Let’s compare and contrast the two with use cases and look at how Apache Pulsar can be that missing link.
Design patterns play a vital role in software engineering, providing a template for everyday use cases or problem statements. A design pattern helps improve code reusability, readability, and maintainability. While messaging patterns fall under the broad category of design patterns, the focus of messaging patterns is communication. Messaging patterns also play an essential role in software design. Almost all recent, scalable software applications depend on a messaging pattern. So what is this messaging pattern, and why is it so important?
Messaging patterns determine the method of communication or data exchange between different software application components. As it’s advantageous and a best practice to have loosely coupled components in a system, many software projects and products are trending towards microservices-based application development. A microservices architecture segregates each service. However, there’s always a need for one service to talk to another for data exchange and dependencies. Consequently, data architects design messaging patterns to facilitate data exchange in such scenarios.
Several data exchange messaging patterns are in use, like SOAP, the REST API, Publisher to Subscriber (Pub-Sub), Observer, Push-Pull, and so on. Each has its application areas, pros, and cons.
This article explains the Observer and Pub-Sub patterns, their similarities, and their differences. The article also describes a use case for each of these patterns.
Note: The terms data, event, and message are interchangeable in this article, and they have the same meaning in the messaging patterns and application spaces.
The Observer Design Pattern
The Observer pattern is a popular, easy-to-understand, and widely used messaging design. Let’s look at an example of the Observer pattern to understand it better.
Assume that you like to receive really simple syndication (RSS) feeds of any news from a particular news provider or agency. So, you head to the site or app and subscribe to the RSS feed. Once subscribed, any new events, in this case, the news, come to you through an RSS feed in real-time. In this example of the Observer pattern, you are the observer, the news is the subject, and the news agency is the provider.
The following scenario is also possible in the RSS feed example, where an observer (you) can choose a specific news article or category (a subject) to observe for changes. You may decide to watch the news feed on a stock price. Whenever the price changes for a stock (a state change), the observer gets only the relevant news update from the news agency (provider).
In an Observer pattern, the producer (i.e. subject) knows where to send the content (the observer), and there can be many observers. Others can subscribe to the RSS feed of the same news agency, and everyone will receive the feed whenever a new event occurs. Technically, you can perform this data exchange on every create, update, or delete event in a system. Although the subject knows the observers in an Observer pattern, the subject does not care or know what each observer will do with the data received. Each observer has full control over what to do with the events that they receive at their end.
The Pub-Sub Design Pattern
The Pub-Sub pattern is another easy-to-understand and widely used messaging pattern. In a Pub-Sub pattern, the data publisher produces or sends the data to a broker from which the subscribers can consume or read the data. A broker is a kind of bridging party between the publisher and subscribers. The broker retains the data exchanged through them in a storage layer, and we can configure that retention period based on the system implementing the Pub-Sub pattern. We can logically segregate data based on specific criteria or programming logic when it reaches the broker layer.
For example, in specific Pub-Sub applications, the application pushes a particular category of data from a temperature sensor to the temperature readings topic. It then pushes another data class, such as pressure reading from another sensor, to the pressure-readings topic.
The publisher doesn’t know about subscribers in a Pub-Sub pattern because of the intermediate broker component. The subscribers don’t know about the publishers either. Both publishers and subscribers are interested only in the topics with stored data. A publisher can continue publishing data on these topics when subscribers are offline. Similarly, a subscriber can continue to consume messages from topics (if the subscriber has not consumed them before or during the replay of messages) even when the publisher is down. Due to such characteristics, this design pattern is a loosely coupled architecture.
Remember that publishers and producers are interchangeable terms in messaging patterns and applications as they both mean an entity that generates an event. Similarly, subscribers and consumers are synonymous terms that mean an entity consuming events.
The Observer and Pub-Sub patterns aim to transfer data from one component to another in an application or website. Both the designs deal with a producer producing events and a consumer consuming the events generated.
Developers mainly use Observer patterns to carry out data exchange between components of a single application. To a large extent, such an exchange happens synchronously. In the Pub-Sub pattern, the data exchange can happen across various applications and occurs asynchronously in many cases. However, synchronous communication is possible with producer APIs and consumer APIs of applications implementing Pub-Sub patterns.
In the Observer pattern, the data provider knows the observer. In the Pub-Sub pattern, the publisher does not know about its subscribers, and these two groups can exist and operate without each other. The data exchange in Pub-Sub happens through the bridging component, the broker.
Pub-Sub patterns promote a decoupled architecture, unlike the Observer pattern.
Use Cases for Observer Patterns
Developers can also use Observer patterns for RSS feeds, as explored earlier.
Use Cases for Pub-Sub Patterns
Pub-Sub design patterns are suitable for refreshing application caches. For example, assume an application reads from a remote database and holds field values in a cache. Whenever a user requests the data relevant to that field, the application can render it from the cache instead of asking for it from a remote database. However, when the field’s value changes in the database, the updates must reach the cache to serve the user with the latest data. How can we achieve this?
A Pub-Sub pattern can push the updates to a topic, and the application can subscribe to the topic to receive the updates and refresh its cache. When reading sensor feeds, we can use a Pub-Sub pattern for the Internet of things (IoT). This might look be a program that pushes temperature readings from temperature sensors to a temperature topic that a consumer can render in a report or dashboard.
Due to their loosely coupled architecture and asynchronous messaging support, many industries use Pub-Sub patterns. Apache Pulsar is one popular program that uses a Pub-Sub pattern.
Apache Pulsar implements the Pub-Sub design in its architecture by supporting the concept of broker nodes that exist between the producer and consumer client applications. The producer application can publish the message to an intended topic, the message reaches the broker in a Pulsar cluster, and the broker sends the message to bookies to persist the data (if the data is for a persistent topic, as Pulsar supports non-persistent topics as well). The topic subscribers can then start receiving messages once the data is available on the topic.
How do you decide which one of these patterns is best for your application? When you want to exchange data asynchronously from one application to another entirely different one or require a loose coupling between your data producer and data subscriber, choose a Pub-Sub pattern over an Observer pattern. On the other hand, if the data exchange scope lies within a single application component, choose an Observer pattern as it involves fewer resources, less administration effort, and cost.
All microservices architecture-based applications use a messaging method to exchange data from one service to another. These messaging patterns are so crucial that their design pattern plays a vital role in software engineering.
The Observer pattern is a widespread, simple-to-use messaging method where the subject knows the observers. You should use Observer patterns mainly to carry out data exchange between components of a single application. And, it is ideal to use the Observer pattern for synchronous communications. Whereas, in the case of the Pub-Sub design, the publisher and subscriber do not know each other. A Pub-Sub pattern is suitable for asynchronous data exchange between multiple services of the same or different applications.
So, choose the design pattern for your application based on your needs.