When you hear tight coupling or being loosely coupled, what does that even mean? There are many aspects to coupling that you need to think about. Temporal, Data Schema, Location, Technology. Removing one aspect usually involves having to deal with a whole new set of problems.
YouTube
Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.
Technology Coupling
When it comes to building better software systems, managing coupling is at the forefront. Many developers often think about coupling primarily in terms of dependencies; for instance, how system A depends on system B, and so on. However, the reality is that coupling involves multiple dimensions that go beyond simple dependency chains. In this post, we will explore the various aspects of coupling, especially in the context of microservices, and discuss how to navigate the complexities that arise.
Let’s start with a typical illustration of coupling in microservices. Imagine a service acting as a client, making HTTP calls to another service that exposes an API.
At first glance, it may seem like this setup inherently reduces coupling. While it does help in certain ways, we must dive deeper into what coupling truly means. Gregor Hohpe’s definition of coupling describes it as the “independent variability of connected systems.” In simpler terms, if a change in system A impacts system B, then we have a coupling issue.
Introducing an HTTP call between different services can eliminate some technology coupling, especially if one service is built on .NET and another on the JVM. The network call allows for varying technology stacks to interact, which is a form of decoupling. However, it doesn’t eliminate all forms of coupling.
Temporal
For instance, consider the temporal aspect of coupling.
When discussing message queues and event-driven architectures, where the availability of services does not need to align perfectly.
While service A may place a message on a queue for service B to process later, the dependency still exists; service A must know that service B will process the message eventually.
Many developers tout the publish-subscribe model as an example of loose coupling, where producers and consumers operate independently. This redecues coupling from the publisher because it does not know or care about who the consumers are of the events it publishes.
However, this assertion is somewhat misleading. If the producer stops publishing an event that a consumer depends on, the latter will break. Similarly, if the data structure or format of the message changes, service B must adapt accordingly. This dependency indicates that coupling is still present, albeit in a different form.
Location
We also need to consider location coupling. When making HTTP requests, a service must know the URI, hostname, or IP address of the other service. This knowledge creates a coupling that can become problematic if the service’s location changes.
This is also applicable with any other form of communication such as queues or topics. Publishers and consumers must be aware of the location and how to connect othe message broker, queue and/or topics.
One way to mitigate this is through the use of service registries, which can help abstract away some of the location dependencies.
Data Structure & Format
Data structure coupling is another key aspect. If you’re using an HTTP API or messaging you’re expecting a particular structure/schema to consumer it. Similar to database schemas, you have ot manage how you want to change them in a backward compatible way. Adding new properties can be fine however renaming, removing or changing the structure can cause clients to fail.
If a service expects a specific format, such as JSON, any changes to that format can lead to coupling issues. Content negotiation can help alleviate this problem, but it still requires the client to understand the expected structure of the data.
Tight & Loose
Now, let’s consider a practical example involving Firebase Cloud Messaging APIs. During a migration from legacy to newer versions, I discovered that the way authentication was handled had changed significantly. This shift created technology coupling with a new .NET package that I had to use. By opting to use HTTP client directly instead, I faced multiple layers of coupling: changes in the data structure, the URI where requests were sent, and the overall response format.
Understanding the various aspects of coupling—temporal, location, technology, and data—is essential for software developers. Each aspect presents its own challenges and trade-offs, and simply removing one type of coupling often introduces new problems. For instance, while moving to an event-driven architecture might help with temporal coupling, it can create new dependencies that need to be managed.
As you navigate the landscape of software architecture, remember that coupling is a multifaceted issue. It’s not enough to focus on just one aspect; you must consider how changes in one area can ripple through the entire system. By taking a holistic view of coupling, you can make informed decisions that lead to more resilient and maintainable systems.
Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.
Related Links
- SOLID? Nope, just Coupling and Cohesion
- How to (and how not to) design REST APIs
- Third-order effects and software systems
The post You’re not as loosely coupled as you think! appeared first on CodeOpinion.