RRuna

Dependency Model

Dependency boundaries behind on-demand installation

Runa’s dependency model has one goal: unused capabilities should not enter the dependency graph, and unused drivers should not enter go.sum.

Dependencies converge toward the kernel

Dependencies must converge toward the kernel:

Driver block -> Capability block -> Kernel contracts
Transport block -> Kernel contracts
Application -> Blocks it needs

The kernel does not import transports, capabilities, or drivers. Because of this, a program that only imports github.com/duxweb/runa is not polluted by HTTP, Redis, S3, ORM, or similar dependencies.

How to decide module boundaries

A module boundary should match a real dependency boundary. Heavy dependencies, external service drivers, and optional UI should be split into separate modules.

Recommended split points:

  • External dependencies such as Redis, S3, NATS, AMQP, MQTT, Oro, Excel, and WebSocket.
  • Opt-in capabilities such as console, observe adapters, and devtools.
  • Future large transport blocks.

Not recommended:

  • Very small pure function helpers.
  • Internal helper code with no external dependencies and strong cohesion.
  • Adding modules only to make directories look cleaner.

Boundaries CI should enforce

CI should check:

GOWORK=off go list -deps .
for mod in $(find . -name go.mod -not -path './.git/*'); do
  (cd "$(dirname "$mod")" && go test ./...)
done

If a module introduces a heavy dependency, the PR must explain why that dependency belongs to the module instead of the core.

Edit this page