This approach is very useful for clarifying the dependencies of implementations we are working on or designing. It helps in understanding if each change is being made in the best possible way.
1. Arrow with Linear Body and Empty Head
"Inherits from" / "Is a"
Used to indicate that something inherits from or is something else. For example:
In this case, the MyViewController
class is a UIViewController
.
2. Arrow with Dotted Body and Empty Head
"Conforms to" / "Implements"
Used when something conforms to or implements a certain contract.
Here, the URLSessionHTTPClient
implements the HTTPClient
.
3. Arrow with Solid Body and Filled Head
"Depends on" / "Has a" / Strong Reference
Used when talking about direct dependencies between different concepts or things.
class RemoteFeedLoader {
private let client: HTTPClient
init(client: HTTPClient) {
self.client = client
}
In the example above, the RemoteFeedLoader
class directly depends on (has a strong reference to) the HTTPClient
. Whether it's an interface, a direct implementation, or if it needs something external to function, or even if this dependency is necessary to create the resource, we're talking about a strong dependency.
Therefore, this dependency can be represented as:
4. Arrow with Dotted Body and Filled Head
"Depends on" / Weak Reference
For this, the dependency exists but is not mandatory for creating the resource.
If we change the approach of RemoteFeedLoader
to:
class RemoteFeedLoader {
func load(with client: HTTPClient) {
client.doSomething()
}
}
Notice that the dependency exists, but it's not necessary to create a RemoteFeedLoader
resource. However, when the resource is called, it will be necessary to continue the process.
With this approach, we gain more flexibility in creating our instances, but in return, whoever uses the RemoteFeedLoader
will need to know about the HTTPClient
, while in the first case, we don't have this issue.
So we can represent it as follows:
5. Colors for Each Context
This approach clearly shows when something being used comes from inside or outside the context. This makes it easy to understand if something is breaking the project's architectural pattern.
Conclusion
In conclusion, dependency diagrams are powerful tools for visualizing and understanding relationships between different components in software architecture. By using various arrow styles and colors, we can clearly represent inheritance, implementation, strong and weak dependencies, and contextual relationships. This visual approach not only helps in designing robust systems, but also in identifying potential architectural issues, making it an invaluable asset for developers and architects alike.
Thanks everyone! See y'all
Top comments (0)