do that:</p><div id="2e8b"><pre>eventHandler<span class="hljs-selector-class">.Handle</span>(event1,
<span class="hljs-built_in">ExampleMiddlewareFoo</span>(<span class="hljs-built_in">ExampleMiddlewareBar</span>(handle)))</pre></div><h1 id="a8a5">Managing Events with Handlers and Middleware</h1><p id="f869">Most articles I read explain how to use this design pattern; this one deals with implementing the internal logic. So let's start coding.</p><p id="35c4">The full code for this article can be found <a href="https://github.com/xNok/slack-go-demo-socketmode/blob/main/examples/middleware/main.go">here</a> to help you follow along.</p><h2 id="0f88">Designing events</h2><p id="b622">First, we are going to enumerate the list of events that our system can handle. The way we create enumeration in Go is a bit different than in other programming languages. In Go, we are going to use a set of constants sharing the same <code>type</code>. Here I define a type <code>EventType</code>that represents a string with the event's name.</p><div id="b181"><pre>// <span class="hljs-keyword">type</span> <span class="hljs-type">used </span>to enumerate events
<span class="hljs-keyword">type</span> <span class="hljs-type">EventType </span>string</pre></div><div id="4817"><pre>const (
event1 EventType <span class="hljs-operator">=</span> <span class="hljs-string">"event1"</span>
event2 EventType <span class="hljs-operator">=</span> <span class="hljs-string">"event2"</span>
)</pre></div><p id="e041">Next, we define the event itself. In our example, the<code>Event</code> as a type which can be selected among the list of <code>EventType</code> created above.</p><div id="2bc9"><pre><span class="hljs-keyword">type</span> <span class="hljs-type">Event</span> struct {
<span class="hljs-type">Type</span> <span class="hljs-type">EventType</span>
<span class="hljs-type">Data</span> interface{}
}</pre></div><h2 id="df6c">Create an event sender (for test purpose)</h2><p id="60aa">To test our system, we will need to create a small function to send events every 2s. Each<code>Event</code> is transmitted via a <a href="https://tour.golang.org/concurrency/2">channel</a> and, the <code>eventSender</code> below sends a random <code>Event</code> of type <code>event1</code> or <code>event2</code> to a channel.</p><blockquote id="53f3"><p><i>Channels are a type which you can send and receive values, they are great for communication among goroutines. In other words, there are perfect for sending and receive event through your application.</i></p></blockquote><div id="ffd1"><pre><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">eventSender</span><span class="hljs-params">(c <span class="hljs-keyword">chan</span> EventType)</span></span> {</pre></div><div id="7f57"><pre> for {
// Send <span class="hljs-selector-tag">a</span> random event <span class="hljs-selector-tag">to</span> the channel
rand<span class="hljs-selector-class">.Seed</span>(<span class="hljs-selector-tag">time</span><span class="hljs-selector-class">.Now</span>()<span class="hljs-selector-class">.Unix</span>())
events := []EventType{
event1,
event2,
}
n := rand.<span class="hljs-built_in">Int</span>() % <span class="hljs-built_in">len</span>(events)</pre></div><div id="6101"><pre> c <- events[n] <span class="hljs-comment">// send event to channel</span></pre></div><div id="5285"><pre> // <span class="hljs-keyword">wait</span> a <span class="hljs-built_in">bit</span>
<span class="hljs-built_in">time</span>.Sleep(<span class="hljs-number">2</span> * <span class="hljs-built_in">time</span>.Second)
}
}</pre></div><h2 id="000c">Handler and dispatcher</h2><p id="e562">We first need a struct to hold the list of events we want to listen to and which function to call whenever that event is transmitted. This struct also contains the channel used for communicating events.</p><div id="280d"><pre><span class="hljs-comment">// Create a struct to hold config</span>
<span class="hljs-comment">// And simplify dependency injections</span>
<span class="hljs-keyword">type</span> EventHandler <span class="hljs-keyword">struct</span> {
<span class="hljs-comment">// Event channel</span>
Events <span class="hljs-keyword">chan</span> Event
<span class="hljs-comment">// hold the registedred event functionss</span>
EventMap <span class="hljs-keyword">map</span>[EventType][]<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(Event)</span></span>
}</pre></div><p id="aa6c">Next, we need to provide an initializing constructor for our <code>EventHandler</code>.</p><div id="a4ed"><pre><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewEventHandler</span><span class="hljs-params">()</span></span> *EventHandler {
eventMap := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[EventType][]<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(Event)</span></span>)
event
Options
s := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> Event)</pre></div><div id="78bb"><pre> return <span class="hljs-variable">&</span>EventHandler<span class="hljs-punctuation">{</span>
<span class="hljs-symbol"> Events:</span> events,
<span class="hljs-symbol"> EventMap:</span> eventMap,
<span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span></pre></div><p id="98fe">Then, we can create our <code>Handle</code> function that associates the event with a callback function.</p><div id="308c"><pre><span class="hljs-comment">// register the handler function to handle an event type</span>
func (h *EventHandler) <span class="hljs-built_in">Handle</span>(e EventType, f <span class="hljs-built_in">func</span>(Event)) {
h<span class="hljs-selector-class">.EventMap</span><span class="hljs-selector-attr">[e]</span> = <span class="hljs-built_in">append</span>(h<span class="hljs-selector-class">.EventMap</span><span class="hljs-selector-attr">[e]</span>, f)
}</pre></div><p id="e42a">Finally, we create the <code>EventDispatcher</code> function, the core of this mechanism. The <code>EventDispatcher</code>process any event sent to a channel, check its type, and if any function has been registering for that type, we call all registered functions.</p><div id="6597"><pre><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *EventHandler)</span></span> EventDispatcher() {
<span class="hljs-keyword">for</span> evt := <span class="hljs-keyword">range</span> h.Events {
log.Printf(<span class="hljs-string">"event recieved: %v"</span>, evt)
<span class="hljs-keyword">if</span> handlers, ok := h.EventMap[evt.Type]; ok {
<span class="hljs-comment">// If we registered an event</span>
<span class="hljs-keyword">for</span> _, f := <span class="hljs-keyword">range</span> handlers {
<span class="hljs-comment">// exacute function as goroutine</span>
<span class="hljs-keyword">go</span> f(evt)
}
}
}
}</pre></div><h1 id="13e4">Using our system</h1><p id="4d4e">Everything is ready; we can start using our event handling system.</p><ol><li>Instantiate our event Handler</li><li>Register which event to listen to and what function to callback</li><li>Start the event sender</li><li>Start the event dispatcher</li></ol><div id="62ab"><pre><span class="hljs-keyword">func</span> <span class="hljs-title function_">main</span><span class="hljs-params">()</span> {</pre></div><div id="5b09"><pre> <span class="hljs-variable">eventHandler</span> := <span class="hljs-function"><span class="hljs-title">NewEventHandler</span>()</span></pre></div><div id="d244"><pre> eventHandler.Handle(event1, <span class="hljs-keyword">func</span><span class="hljs-params">()</span> {
<span class="hljs-built_in">log</span>.Printf(<span class="hljs-string">"event Handled: %v"</span>, event1)
})</pre></div><div id="5c56"><pre> <span class="hljs-variable">go</span> <span class="hljs-function"><span class="hljs-title">eventSender</span>(<span class="hljs-variable">eventHandler.Events</span>)</span></pre></div><div id="30f2"><pre> eventHandler<span class="hljs-selector-class">.EventDispatcher</span>()</pre></div><div id="9bf2"><pre>}</pre></div><p id="e590">The result should be along those lines:</p><figure id="5ee7"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*_D-GCRSu3K8CgTBXewJjJQ.gif"><figcaption></figcaption></figure><p id="19d6">Since we only handle an event of type <code>event1</code>, only <code>event1</code> shows as <code>Hansled</code>. All is good!</p><p id="d48a">The full code for this article can be found <a href="https://github.com/xNok/slack-go-demo-socketmode/blob/main/examples/middleware/main.go">here</a>.</p><h1 id="6f5e">Interesting Articles tackling the same topic</h1><ul><li><a href="https://drstearns.github.io/tutorials/gomiddleware/">Middleware Patterns in Go</a></li><li><a href="https://sathishvj.medium.com/web-handlers-and-middleware-in-golang-2706c2ecfb75">Web Handlers and Middleware in GoLang</a></li><li><a href="https://readmedium.com/lightweight-event-management-implemented-by-go-a654d59ac65">Lightweight event management implemented by Go</a></li><li><a href="https://readmedium.com/the-7-most-important-software-design-patterns-d60e546afb0e">The 7 Most Important Software Design Patterns</a></li></ul><p id="13e7"><i>Do you want <b>unlimited access</b> to all my content and many other writers’ content on Medium? Consider using my affiliate link to <a href="https://couedeloalexandre.medium.com/membership">become a Medium member today</a></i></p><h2 id="853a">Further reads</h2>
<figure id="81d2">
<div>
<div>
<img class="ratio" src="http://placehold.it/16x9">
<iframe class="" src="https://couedeloalexandre.medium.com/embed/list/3f9d03f2cb8f" allowfullscreen="" frameborder="0" height="184" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure></article></body>
From two authors and dedicated writers who never stopped training
First, I want to share a piece by August Birch, who, a few months back, was making $2k a month so. He’s working very hard at not only maintaining his visibility but he’s also offering programs which are helpful to those in the middle of the doldrums. Here is his piece:
If you aren’t currently following August, and you are really determined to pull yourself up by the bootstraps, I recommend his articles. He’s very honest about where he is, which is reflective of where many of us are. It’s smart, helpful advice. I appreciate reading about how someone who is sticking with it is sticking it out. Lot to learn there.
For my part I am also an author, and a prize-winning one. I had a lovely laugh a few weeks ago when a regular commenter wrote me in some surprise that, in effect, I clearly couldn’t be having problems because I was, indeed, a prize-winning author. Sadly, that has little to do with much.
I don’t tend to write about what goes viral, like weird sex or what it’s like to turn thirty. I don’t pilfer others’ material. I write a lot about personal responsibility. I did write more than four thousand articles since April 2018. That kind of production got me followers. I am by no means everyone’s cuppa, and I would never insult my readers by blaring about how “the pandemic is over.” Because not only do I not have a fucking clue, neither do those writers. (Kindly, not a single epidemiologist has a clue, so I guess I struggle to understand how some thirty-ish kid has suddenly figured it all out for the rest of the world. However, it sure gets them eyeballs. But I digress).
For a while that worked. Much of my work focused on travel. Like all my peeps in that industry, that all fell off a cliff.
Other things are just more important right now.
From August’s article:
We all start with zero subscribers.
Many of us were damned near back to just that. If you’re young, and not accustomed to having the bottom fall out of your life (I am, it happens, and you by god get used to it), it can seem hopeless. It rarely is. When you’ve been through some really rough times it teaches you a few things, like how to stick with it when most folks throw in the towel. Ask Helen Cassidy Page how that works. Funny how when you’re much later in life, moving through very hard times is a very different experience.
Those of you who read my stuff regularly (my heartfelt thanks), you know that Secretariat is my favorite movie. Here’s the part that aligns with August’s message, and mine to all of us:
After Secretariat won the Preakness Stakes 1973 with the very aggressive Sham right on his heels, his trainer and owner struggled to decide whether to train him even harder or to let him rest. Sham’s owner believed that by resting Sham while Secretariat was pushed even harder every day was the key to victory. They believed that Secretariat would burst his heart trying to keep up.
In the lead-up to the final leg of the Triple Crown, Secretariat trained even longer distances while Sham lounged quietly in his stall or did less-demanding runs. Just like a lot of writers who have given up, waiting for the “race” to begin again.
Secretariat and Sham left the rest of the field behind in a blistering pace, the remainder of the horses falling back like platers*. As the two streaking horses approached the final turn, Secretariat literally exploded away from his head-to-head duel with Sham.
Never in racing history has anything like it happened before or since. Because he kept training, because he loved to run, because he pushed even harder right up to the Belmont, Secretariat rocketed away from Sham and won by 31 lengths.
This scene is what I call to mind every time I am out in the early dawn running my three miles. It’s what I call to mind when I really, really want to quit. Winners never stop training, preparing. They rest, yes. They have rough days and bad days and shit days.
But they never give up.
Unlike a lot of my Medium fellows, at 67 I don’t have the luxury of many decades in the future. Maybe two or three at top performance. However I do have five decades of work behind me. I’ve learned that when so many others give up, slow down and head to the couch to watch Groundhog Day for eighth time, I am writing. August is writing. Illumination writers are writing. We are training for the long run. As are many of us: we are sticking with it.
I have absolutely no idea when things will return to any semblance of normalcy. However right now I am up at three every single day. I workout. I write, workout, write. I publish at least one or more articles every single day. I do pushups and pullups and run miles and practice yoga and kickboxing. And write and interview and work steadily. I keep myself in top shape as best I can. I eat smart and stay focused. I write stories for and about my distant clients who are doing good work in Africa and elsewhere. We’re all in training.
Because at some point there will be some kind of new normal or N2. I have no intention of lagging so far behind that the leaders are only a distant dot up ahead. I plan to be head-to-head right with them.
I hope you do, too.
Over the last month, I have watched my stats rise slowly. Just like August’s. Those are new people finding my work. People are clapping for articles I wrote last year and before. This is a new audience. New people that I am earning slowly and surely, just like I did the first time. I’m tagging and engaging and acknowledging just like before but now even more so because there’s more time. It’s still half of what I had, but it’s growing.
It’s growing because, just like before, I take an interest in my readers. I care about what they think and feel and what they have to say. I tag others and read and link to their stuff and support them as best I can.
Because I don’t have time to quit. When the starting gates open I plan to be in absolute top shape, ready to welcome my previous readers back and continuing to build my stats.