Ali
Ali

Reputation: 347

How to prevent coupling between our code and third party libraries?

Imagine we want to use the following library like this:

use GrahamCampbell\GitHub\GitHubManager;

class Foo
{
    private GitHubManager $github;

    public function __construct(GitHubManager $github)
    {
        $this->github = $github;
    }

    public function bar(): array
    {
        $this->github->issues()->show('GrahamCampbell', 'Laravel-GitHub', 2);
    }
}

Does it makes sense to create an interface like:

interface GitHubManagerInterface
{
    public function showIssues(): array;
}

Then implement it and bind the implementation to the interface and use it in my code like the following?

class Foo
{
    private GitHubManagerInterface $github;

    public function __construct(GitHubManagerInterface $github)
    {
        $this->github = $github;
    }

    public function bar(): array
    {
        $this->github->showIssues('GrahamCampbell', 'Laravel-GitHub', 2);
    }
}

Or there is a better way to prevent coupling? Or it's over engineering? :)

Upvotes: 0

Views: 146

Answers (1)

R.Abbasi
R.Abbasi

Reputation: 711

If it's a library, like Redis client or MongoDB client library, it's better to use them in the infrastructure layer. Wrapping them in an interface would make your code decoupled, but sometimes you can't eliminate the dependencies.

In my experience with MongoDB, your interface can get polluted with MongoDB driver models because the library has many models to express the outputs and inputs. Then you have two options:

  • Make your way independent by defining models to wrap everything it needs and then translate it to MongoDB models behind the scenes. Of course, it's better to be independent but at the cost of defining more models and writing translations.
  • Accept the coupling and use the 3rd party models. It's easier but at the cost of being dependent on the library. In earlier times of development, it would be reasonable to choose this way (to hit the market faster) till you know what is your product's actual needs and what are the future requirements. When you know your product better, you make decisions more precisely.

Sometimes you know that you won't change the 3rd party library. It helps you to accept the coupling to the library. Yes, your project would be coupled to an external library but it won't hurt you as long as you don't want to change it.

But if it's an external service, you should use the ACL pattern to prevent your project from getting polluted with 3rd party services logic. The ACL pattern suggests defining an interface for the 3rd party service with the client models as inputs and outputs and translating the client models to the 3rd party models in the implementation.

Here are some notes to decide whether to wrap a 3rd party library in an interface or not:

  • You have to measure the probability of breaking the backward compatibility. If the library is well-known and has a good community, they probably would care about the users and support backward compatibility. So your project won't be affected by the library changes.
  • Will you change the 3rd party library or will you not? You can't be sure. If you have multiple well-known libraries for your needs, I think it's reasonable to assume that you might change it in the future. Take your future business requirements into account. If you predict that your business will need to scale or change its needs in time, that will affect your decision.
  • Coupling is not always bad. As it can be counted as a technical debt. You make a debt to deliver software faster. But remember that you have to pay your debt someday.

Upvotes: 2

Related Questions