In Layered Architecture (e.g., Clean Architecture, or Hexagonal architecture), the key idea is to use the dependency inversion principle. This blog post provides the dependency inversion principle in Rust, skipping the details of Layered Architecture.
The sample in this blog post is a news app which gets news asynchronously. I will illustrate the dependency inversion principle with three layers: Use case, Gateway, and Port.
- Use case: app-specific business rules
- Gateway: adapter between a data format (e.g., JSON or ORM ) and a particular Domain object
- Port: abstraction depended by details (concrete implementations)
The diagram below shows dependency relationships.
Now lets’ see the each layer.
news_get_usecase shows what the application can do: We can find 100 latest news. The Use case is not aware of the implementation details (Gateway). It is dependent on abstractions (Port).
The Port’s trait is implemented for the Gateway. The Use Case and The Gateway depend on the Port.
The Gateway implements the Port. It constructs Domain objects by reading from the I/O source and converts Domain objects to a data format to send to an external system (e.g., API Server, Database, Message queue, Object storage, or File system). This allows us to write code that the domain or business logic is independent of any external systems.
Full Source Code: https://github.com/11Takanori/actix-web-clean-architecture-sample
I design to increase the parameter in the Use case’s function when dependencies increase due to the increasing number of external systems. This will keep dependency relationships simple and make us concisely apply the dependency inversion pattern.