Location>code7788 >text

Hanging the Interviewer! How are inter-app interactions designed?

Popularity:554 ℃/2024-10-18 10:29:14

Hello, I'm Master Tang~

Application interaction refers to the way data is exchanged and communicated between different application structures.

In a complex system, applications do not exist in isolation; they often need to collaborate with each other to accomplish more complex business processes.

Application interactions are designed to ensure that these systems and components "talk" to each other smoothly and achieve the overall goals of the system.

There are various forms of application interaction, including synchronous invocation, asynchronous message communication, and so on. Each type of interaction has its specific application scenarios and advantages and disadvantages.

Through rational interaction design, the various parts of the system can work together efficiently to reduce coupling and increase the flexibility of the system.

At the same time, good interaction design can also significantly improve the performance and fault tolerance of the system, even in the case of high traffic access and complex business requirements, it still maintains stable operation.

Upstream and downstream of application services

Application services are the core business functions provided by the system to the outside world.

The same is true for application services, which can evolve and be implemented independently, but they are not completely independent and must interact with each other to achieve overall system goals.

How to design interactions between application services? First you need to understand clearly the concept of service upstream and downstream.

1. The concept of upstream and downstream services

The upstream and downstream relationships of services can be defined through DDD (Domain Driven Design) modeling methods, mainly using the concepts of bounded context and context mapping.

Upstream and downstream indicate the direction of dependency between contexts, where downstream needs to understand upstream's domain knowledge to realize the business, while upstream does not need to understand downstream.

In other words, the upstream service does not need to care about the existence of the downstream service, but the realization of the downstream service depends on the capabilities provided by the upstream service.

This concept sounds a bit abstract and does confuse many people. Let's go through a few of the application services of the online shopping center to illustrate it in concrete terms:

  • User Services: Manage users' account information, including registration, login, authentication, and personal data. Handle user permissions and role management.
  • Commodity Services: Manage basic information of commodities, including name, description, price, picture, classification, etc. Provide query, filtering and browsing functions for commodities.
  • Inventory Services: Manage inventory quantities of merchandise. Handles pre-possession, deduction and backfill operations for inventory.
  • Transaction Services: Handle order creation, modification, cancellation and inquiry. Manage the status and lifecycle of orders.
  • Payment Services: Handle payment transactions and support multiple payment methods. Manage payment status.
  • Fulfillment Services: Handle order fulfillment, including picking, packing, and shipping. Manage logistics information and delivery status.

As shown in the figure, we can see the upstream and downstream relationships of each service.

Commodity services and user services are upstream services that provide the underlying data on which other services depend.

Transaction services are located in the middle. For both user services and commodity services, the transaction service is downstream because it relies on the underlying data for both services.

For inventory services, transactional services are also downstream, as the process of placing an order for a transaction requires inventory services to preoccupy and deduct inventory.

For fulfillment services, the transaction service is upstream as it provides the order data that drives the subsequent order fulfillment process.

2. Why differentiate between upstream and downstream?

The central goal of distinguishing between upstream and downstream relationships is for decoupling.

The word "decoupling" is not new to anyone, but its meaning is often too abstract and vague. Here, we explore what decoupling actually means.

Coupling is the interaction and influence between two or more structures. In software development, this can be understood as the interdependence and influence between different modules, systems or teams.

As the business problems that software needs to solve become more and more complex, it is difficult for a single system or team to achieve business goals independently. Therefore, the purpose of decoupling is not to completely eliminate coupling, but to reduce unnecessary dependencies.

In the above we mentioned that upstream services do not need to care about the existence of downstream services, but the realization of downstream services depends on the capabilities provided by upstream services.

Therefore, when a team in a downstream service iterates on a new feature, there is no need to assess whether it affects the upstream service because it can quickly determine that it will not affect the upstream service based on a clear upstream/downstream relationship. It only needs to assess whether it affects its own downstream service.

For example, when the functionality of a transactional service changes, only the fulfillment service's team needs to be notified to assess whether it will affect them; the upstream service team does not need to know.

This approach can significantly reduce the assessment of impact surfaces and increase the efficiency of teamwork.

Conversely, if the upstream and downstream relationships are confusing and there are various circular dependencies, it is difficult to accurately assess the impact surface of changes to any one service. At this point it is necessary to gather the teams of all the services to assess whether there is any impact one by one.

In real-world scenarios, it takes a room full of people to assess the impact of each project meeting, which makes collaboration extremely inefficient.

3. Core usage scenarios for upstream and downstream relationships

Upstream and downstream relationships play an important role in many key scenarios during software development.

  • Clarify dependencies between services: Upstream and downstream relationships give developers a clear understanding of dependencies between services. This helps reduce unreasonable dependencies and ensures service independence and modular design. It also avoids circular dependencies between services and reduces the risk of a failure in one service triggering a chain reaction.
  • Evaluating the impact surface: When upstream services are changed, the impact on downstream services can be foreseen so that corresponding response strategies can be developed.
  • Guiding teamwork: Upstream and downstream relationships help to clarify the responsibilities and scope of work of each team. Upstream teams need to consider the needs of downstream teams and provide stable interfaces and services; downstream teams need to adapt to changes upstream.

Interaction of application services

Application services interact in a variety of ways, the two most prominent of which are synchronous calls and asynchronous messages.

1、Synchronized call

A synchronous call is a type of communication in which the caller (client) sends a request to the callee (server) and waits for the server to complete processing and return the result. In the meantime, the caller blocks until it receives a response from the server. This approach requires that both the caller and the callee are online at the same time, and that the caller cannot perform other operations while waiting for a response.

Typical technical implementation protocols for synchronous calls in microservice architectures include HTTP, REST API, Dubbo, Thrift, gRPC, and SOAP.

Synchronous calls are used in scenarios where downstream services need immediate access to data or functionality from upstream services. This type of communication is simple and straightforward, but requires dealing with availability issues between services.

For example, when a user places an order, the order service needs to synchronize the call to the commodity service to get the latest price and inventory information of the commodity to ensure that the order is valid.

In general, upstream services should not call downstream services synchronously. If the upstream service calls the downstream service synchronously, it will lead to the upstream needing to understand the domain knowledge of the downstream, violating the design principles of DDD upstream and downstream, deepening system coupling, and increasing the complexity of team collaboration.

In addition, this practice may cause cascading failures and reduce system reliability. If the upstream and downstream call each other directly, then the failure of the downstream service will also directly affect the availability of the upstream service, which may lead to the whole system being unavailable.

2、Asynchronous message

Asynchronous messaging is another type of communication in which the sender (producer) and receiver (consumer) of a message communicate through a message queue or message middleware.

The sender does not need to wait for the receiver to finish processing before continuing with other operations. After the message is sent to the message queue, the receiver fetches it from the queue and processes it asynchronously. This approach removes the time dependency of the sender and receiver and allows them to operate independently, increasing the flexibility and scalability of the system.

In microservices architectures, asynchronous messaging is typically implemented through messaging middleware, such as RabbitMQ, Kafka, and RocketMQ.

Asynchronous messages are suitable for scenarios in which an upstream service issues an event or notification to a downstream service, which can effectively decouple services and improve system resilience and reliability. The downstream service can also feedback information to the upstream service through asynchronous messages, realizing two-way communication.

For example, when a user submits an order, the order service calls the payment service to initiate payment. After the user completes the payment, the payment service releases the message "Payment Successful", and the order service receives the message, updates the order status and sends a notification.

3. Other interactions

1) Shared database approach

Multiple services access the same database and read or write data directly.

In microservices architectures, a shared database approach is usually not recommended because it violates the principle of service autonomy and increases the coupling between services.

2) File Transfer

Data files are exchanged between services via shared file systems or FTP, for example. This type of interaction is usually batch and less real-time.

3) Service Bus (ESB)

A unified communication bus is used to connect different services and systems. The services do not communicate directly with each other, but are mediated through the bus, making it suitable for large enterprise-level systems that need to integrate multiple heterogeneous systems and services.

However, this approach introduces additional architectural layers and increases system complexity. All services are coupled to the bus and there is a risk of a single point of failure.

This article has been featured on, my tech site: Inside there are, algorithm Leetcode detailed explanation, interviews eight stock text, BAT interview questions, resume templates, architecture design, and other experience sharing.