archview

Buses (CQRS / events)

Recover precise routing through a command, query or event mediator.

A CQRS or event-driven app dispatches through a mediator: a command/query/ event bus stores handlers in a map and looks them up by name at runtime.

bus.Register(CreateOrder{}.CommandName(), NewCreateOrderHandler(...))
bus.Dispatch(ctx, CreateOrder{ID: id})   // routed by name, at runtime

A static call graph can't follow that map. It sees Dispatch calling the handler interface, so it fans every dispatch out to every handler — a star that loses the real command → handler routing, and pollutes the graph with the bus internals and marker methods.

Turn it on

av, _ := archview.New(archview.Options{ DetectBuses: true })

archview then:

  1. Reads the registration sites (Register, Subscribe, …) to learn which message type routes to which concrete handler, and which types are buses.
  2. Stops the call graph at the bus so the over-approximated fan-out is dropped (and marker methods like CommandName() fall away as dead nodes).
  3. Resolves each dispatch site back to its exact handler, drawing a precise caller → handler dispatch edge (amber).

Result

Without DetectBusesWith DetectBuses
every command → every handlereach command → its own handler
event → every subscriberevent → only its real subscribers
bus + marker methods clutter the graphgone

Event fan-out stays precise too: a handler that publishes OrderCreated links only to the subscribers of that event, not to every event handler.

Detection keys off the idiomatic shape — a Register/Subscribe-style method that binds a Msg{}.Name() key to a handler value, dispatched on the same bus type. Buses built purely on reflection or func(any) closures, with no typed registration, remain invisible.

See the CQRS example.

On this page