7. Merge TransportAdapter and TransportOptions into Transport#

Date: 2025-09-29

Related: PR #220

Status#

Accepted

Context#

FastCS transports are implemented using two separate classes: TransportAdapter for implementation and separate *Options classes for configuration. This pattern requires:

  • Two classes per transport

  • Pattern matching logic in FastCS to create the right adapter from options

  • Inconsistent constructor signatures across transports

  • Redundant Options classes that only carry configuration data

Decision#

Merge TransportAdapter and *Options classes into a single Transport dataclass that combines configuration and implementation.

All transports should follow a unified pattern: configuration fields are dataclass attributes, and connect() and serve() methods handle initialization and execution. FastCS accepts Transport instances directly.

Key architectural changes:

  • All transports use @dataclass decorator combining configuration and implementation

  • Standardized connect(controller_api, loop) method to load controller API into transport

  • Standardized async serve() method for running the transport service

Consequences#

Benefits#

  • Reduced API Surface: 5 classes instead of 10 (one Transport per protocol)

  • Simpler Mental Model: Configuration and implementation in one place

  • Consistent Interface: All transports follow same initialization pattern

Migration Pattern#

Before (Options + Adapter pattern):

# Configuration separate from implementation
@dataclass
class MyOptions:
    param1: str
    param2: int = 42

class MyTransport(TransportAdapter):
    def __init__(self, controller_api: ControllerAPI, options: MyOptions):
        self._options = options
        # Setup using self._options.param1

After (Unified Transport):

# Configuration and implementation unified
@dataclass
class MyTransport(Transport):
    param1: str
    param2: int = 42

    def connect(self, controller_api: ControllerAPI, loop: asyncio.AbstractEventLoop):
        self._controller_api = controller_api
        # Setup using self.param1 directly