Decoupled Package Communication in Go
Tags: go, pubsub, eventbus, messagebus
Published: 2019-04-28 23:14:24

---
title: Decoupled Package Communication in Go
published: true
description: Bus is a package that allows different packages to communicate with each other without knowing about each other. A package can emit an event without knowing which handlers will consume.
tags: go, pubsub, eventbus, message-bus

---

Go is very powerful language for software development with its simplicity, concurrency, first-class functions and tools. 

In Go, usually, a package is responsible only for one thing. Applications grows with several packages with their own responsibilities. When the number of packages in the project and responsibilities of the project increase, it is possible to mess up on communication with other packages. (In here, the communication means calling functions on different packages/modules on the flow with/without waiting result. Like incrementing counter metric when an order received/full-filled)

---

One of the known ways of decoupling on communication is the event driven software designs. Usually, using an external event/message-bus server is the way distributing the responsibility to internal/external services. But this also brings another external component to your stack. And each stack comes with its own problems. 

For small services, packages/libraries, and embedded systems adding an external bus could be unnecessary addition. To overcome this problem, adding an internal message-bus package to your package may help. And when things getting bigger, it is possible to communicate with this internal message-bus to external message-bus services.

![event bus](https://thepracticaldev.s3.amazonaws.com/i/lkcb2tnjgsjipad3st5e.png)

Assume that, a project needs to do several things on user registration like; incrementing counters, sending email, logging, and/or sending webhook to external service; instead of directly calling each of the functionalities directly, a message-bus can help to execute multiple functionalities asynchronously without knowing the caller.

---

Decoupled packages help us to write cleaner code, focus on only one thing at a time. With [bus](https://github.com/mustafaturan/bus) Go package, you can get benefit of real message bus system and write decoupled packages easily. The `bus` package allows any handler to listen any events, without knowing who generates the event. Thus, packages can communicate without depending on each other. Moreover, it is very easy to substitute a consumer function. As long as the new function understands the `Event` struct that are being sent and received, the other functions will never know.

---

### Get Started With `Bus` Go Package in 4 Steps

#### Configure

The [`bus`](https://github.com/mustafaturan/bus) package requires a unique id generator to assign ids to events. You can write your own function to generate unique ids or use a package that provides unique id generation functionality. Here is a sample configuration using monoton id generator:

```go
import (
    "github.com/mustafaturan/bus"
    "github.com/mustafaturan/monoton"
    "github.com/mustafaturan/monoton/sequencer"
)

func init() {
    // configure id generator (it doesn't have to be monoton)
    node        := uint(1)
    initialTime := uint(0)
    monoton.Configure(sequencer.NewMillisecond(), node, initialTime)

    // configure bus
    if err := bus.Configure(bus.Config{Next: monoton.Next}); err != nil {
        panic("whoops")
    }
    // ...
}
```

#### Register Event Topics

To emit events to the topics, topic names need to be registered first:

```go
func init() {
    // ...
    // register topics
    bus.RegisterTopics("order.received", "order.fulfilled")
    // ...
}
```

#### Register Event Handlers

To receive topic events you need to register handlers; A handler basically requires two values which are a `Handle` function and topic `Matcher` *regex pattern*.


```go
handler := bus.Handler{
    Handle: func(e *Event){ 
        // fmt.Printf("Event: %+v %+v\n", e, e.Topic)
        // do something
        // NOTE: Highly recommended to process the event in an async way
    },
    Matcher: ".*", // regex pattern that matches all topics
}
bus.RegisterHandler("a unique key for the handler", &handler)
```

#### Emitting Events

The `bus` package provides a generic event struct to standardize what an event is for all of its handlers. Before delivering an event, it is good to know what an event is for the [`bus`](https://github.com/mustafaturan/bus) package. If this is your fist moments with the library, it is highly recommended to check the data structure of the [`Event`](https://godoc.org/github.com/mustafaturan/bus#Event) struct.

```go
txID  := "some-transaction-id-if-exists" // if it is blank, bus will generate one
topic := "order.received"                // event topic name (must be registered before)
order := make(map[string]string)         // interface{} data for event

order["orderID"]     = "123456"
order["orderAmount"] = "112.20"
order["currency"]    = "USD"

bus.Emit(topic, order, txID) // emit the event for the topic
```

Congratulations!!! You emitted your first event with the `bus` package. Now, the all matched handlers will receive the same event. Please try yourself and share your experience as comment. 

Also a **sample project** using [`bus`](https://github.com/mustafaturan/bus) package can be found on [bus-sample-project Github](https://github.com/mustafaturan/bus-sample-project).

---

{% github mustafaturan/bus %}