DEV Community

Kevin Mungai
Kevin Mungai

Posted on

Simple Explanation of Ports and Adapters

TL/DR;

  1. Ports and Adapters help us define boundaries between our program and the outside world.
  2. Ports and Adapters also help us define the behavior of the outside world.
  3. Extra: don't call me let me call you.

Boundaries and the Behavior.

Every time our code calls the outside (think database, external API etc) there is a chance it might succeed or fail.

And when it succeeds or fails you will have to deal with it somehow. One cool way of dealing with the potential success or failure is to define the behavior of the "outside" (adapters).

By defining I mean creating a data structure (ports) that describes what might happen. e.g.

  • success
    • A
    • B
  • failure
    • X
    • Y
    • Z

The data structure could be a simple JavaScript object or Clojure map with a key indicating the type.

Some programming languages give us the ability to use Inheritance to define different behavior while others give us the ability to define behaviour via Algebraic Data Types e.g Elm, F#, TypeScript.

At the end of the day all we want to do is to define the behavior of the outside and use that to determine what is going to happen next.

Do we wish to:

  1. retry the API call
  2. log that error and move on
  3. use that newly found data for something.
  4. forward that for processing

Adapters could be implemented via Polymorphism and examples include service objects in Rails and Django, MultiMethods in Clojure etc.

What if I receive data that I don't know how to deal with?
This means that chances are not all behaviors have been catered for and you needs to review this.

While the process of defining all these discrete behaviors might be a laborious task to do even for a small project, your future selves with thank you.

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live

Don't call me, I'll call you.

don't call me I'll call you

The outside code should not call your code, remember your code is in-charge i.e events from outside should not emit directly into your code.

This means that you must maintain control by using the tools you have access to such as Reactive Extensions, or Channels or Actors etc.

This is not all but one can use or create libraries built on these tools to create simple to maintain logic.

A pattern that one can use in JavaScript land is the Meiosis Pattern.

One example of this is the BLOC Library in Dart that uses Streams to create a Business Logic Components (BLOCs) that has one sink, stream, plus other goodies. I have to attest that one can create some complex logic without knowledge of the Dart Streams package.

shoutout to the makers of the Flutter Bloc Project

Thank you for reading up to this point.

Is there anything I have missed or misunderstood? Please comment.

Top comments (0)