When you connect your computer with an embedded device over CAN, Serial or Ethernet, you plug a USB-to-CAN, USB-to-Serial or USB-to-Ethernet adapter into the USB port of the computer. As long as the adapters comply with the USB specification, you can use adapters from different manufacturers. The USB port shields the computer and its user from the specific way of the communication.
The ports-and-adapters or hexagonal architecture uses the same idea. The application core, which implements the business rules, communicates with other components like GUI, cloud, machine and database through well-defined interfaces, the ports. The core doesn’t know, whether the communication with the machine uses J1939 over CAN, MQTT over Ethernet or any other way, whether the database is an SQLite database or just a JSON file, and whether the GUI is implemented with Qt, Slint or Flutter.
Each port is implemented by one or more adapters – including one product and one test adapter. For example, the machine port has a J1939, an MQTT and a test adapter. As their client, the core defines and uses the ports. Each adapter depends on its port – never the other way round. One adapter never communicates directly with another adapter. They always go through their ports.
Thanks to the ports, the components of the ports-and-adapters architecture are loosely coupled, cohesive, easy to test and easy to extend. By applying the inverse Conway manoeuvre, you get a loosely coupled team topology as well. This is an excellent condition for successful product development.