Home avatar

A collection of dev guides, tutorials and thoughts on various tech stacks, tools and programming languages.

The Streams API in JavaScript and Go

JSON Parsing
Checkout Adventures with the Streaming API to find out more about parsing JSON data from streaming APIs.

If you ever had to build a realtime web app and you’ve built yourself a REST backend (or you need to use same legacy REST backend), you most likely stumbled upon a pretty common issue: how do I stream a bunch of data from the backend to make it seem it’s updated in realtime?

The proxy pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

The proxy pattern is a design pattern in which a class (proxy) acts as an interface to something else. The proxy could be an interface to anything: a network connection, another class, a file, etc.

A proxy can be useful in a variety of situations:

  • A frontend for load balancing
  • Hide private infrastructure
  • Caching layer
  • etc

A good example of a proxy that can be used as a load balancer (and other purposes) is nginx or net/http/httputil (the ReverseProxy).

The observer pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

The observer pattern is a design pattern in which an object (a subject) keeps track of all of its dependents (observers) and notifies them of any state changes.

In Go, the closest example of this pattern are the builtin channels and the use of goroutines:

sub := make(chan interface{})

go func(c <-chan interface{}>) {
    for data := range c {
        fmt.Println(data)
    }
}(sub)

sub <- "Hey there"

Though, for multiple observers to be notified, you need to send the message once for each observer.

The adapter pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

A while back I was playing around with a Raspberry Pi 4 and some temperature sensors. Some of the sensors I was using were exposing data over the SPI communication interface and some were exposing it over the I2C interface.

But I didn’t want the client app that was reading the temperature to change every time I swapped a sensor, so I ended up making a simple wrapper that exposed a single method to read the temperature and which could be initialized with different protocols.

The command pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

The command pattern is a design pattern that encapsulates an action or request as an object that can be parameterized. And it’s commonly associated with terms like receiver, command, invoker and client.

Usually, the invoker doesn’t know anything about the implementation details of the command or receiver, it just knows the command interface and its only responsibility is to invoke the command and optionally do bookkeeping of commands.

The iterator pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

The iterator pattern is a frequently used design pattern in software and it’s very simple. It entails that a collection must provide an iterator that can be used to iterate through its objects.

To put it in simple terms:

c := MyCollection{}

for c.Next() {
    v := c.Value()
    ...
}

Though, I haven’t seen this used very often in Go (it doesn’t mean it’s true). I could only find a single instance of this while going through my code (a Firestore DocumentIterator).

The prototype pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

While going through some of the code I found a couple of instances where I was making copies of some structs, but I wasn’t using the built in copy() method. I was, instead, using some custom copy logic.

The reason for that was that the struct had some properties that were slices of other structs and if I were to use copy(), it would get me in trouble as there was a possibility that the source struct could be mutated.

The factory method pattern in Go

This is a continuation of the common design patterns I found in my old code series, which I started in a previous post.

Another common pattern I found is the factory method pattern, which is a design pattern used to create different types of objects using the same interface.

This pattern is actually pretty common in Go. Some good example of this are the builtin I/O libraries:

package main

import (
  "bytes"
  "encoding/csv"
  "fmt"
  "io"
  "os"
)

func main() {
  f, _ := os.Open("avengers.csv")
  records, _ := parseCsv(f)
  fmt.Println("Records from file", records)
  
  data := []byte("name,surname\nJohn,Snow\n")
  r := bytes.NewReader(data)
  records, _ = parseCsv(r)
  fmt.Println("Records from bytes", records)
}

func parseCsv(r io.Reader) ([][]string, error) {
  cr := csv.NewReader(r)
  return cr.ReadAll()
}

Both the bytes.NewReader() and os.Open() implement the io.Reader interface which comes in handy for the parseCsv() method above as we can use it to parse data from multiple sources.

The singleton pattern in Go

I recently started going through some of my old code and I was trying to identify some common design patterns. I thought it could be a good memory exercise and refresher on software design patterns as it’s been quite some time since I last read through that.

And while I was doing that, I thought it might be a good idea to write about the patterns with the most occurrences.

Cross-compile gRPC for ARM with Docker

If you’re building a micro-service architecture you’ll most likely end up using some sort of networking lib to manage the communication between services.

This is where gRPC fits in. I’m not gonna go through why it’s a good choice, most of the time, but let’s just say that interoperability between different programming languages becomes a lot better.

There’s also a decent amount of documentation and a relatively large community where you can find help.