Builder pattern / improvements
Tags: go
Published: 2024-04-15 02:19:32

Hi everyone,

Today, I want to delve into the Builder pattern—an essential design concept that many developers encounter at some point in their careers. This pattern significantly enhances our ability to construct complex objects in a controlled and scalable manner. However, there's always room for improvement, especially in how we manage the construction process.

**Understanding the Builder Pattern**

The Builder pattern simplifies the creation of complex objects by breaking down the construction process into discrete, manageable steps, handled by a director and a builder. The director controls the order of building steps, while different builders implement the specific details of the object being constructed. Here’s a basic example using a house construction analogy:

```go
package main

type Director struct {
    builder IHouseBuilder
}

func newDirector(b IHouseBuilder) *Director {
    return &Director{
        builder: b,
    }
}

func (d *Director) setBuilder(b IHouseBuilder) {
    d.builder = b
}

func (d *Director) buildHouse() House {
    d.builder.setDoors()
    d.builder.setWindows()
    d.builder.setRooms()
    return d.builder.getHouse()
}
```

In this snippet, the `Director` is tasked with building a house by sequentially initiating the construction of doors, windows, and rooms through the builder. This step-by-step approach ensures that each component is completed before the next begins, traditionally taking about 3 seconds for our hypothetical build.

**Optimizing with Concurrency**

What if we could speed up this process? Instead of constructing each component sequentially, we could leverage concurrency to handle these tasks simultaneously, significantly reducing build time.

```go
package main

import "golang.org/x/sync/errgroup"

type Director struct {
    builder IHouseBuilder
}

func newDirector(b IHouseBuilder) *Director {
    return &Director{
        builder: b,
    }
}

func (d *Director) setBuilder(b IHouseBuilder) {
    d.builder = b
}

func (d *Director) buildHouse() (House, error) {
    var eg errgroup.Group

    eg.Go(d.builder.setDoors)
    eg.Go(d.builder.setWindows)
    eg.Go(d.builder.setRooms)
    if err := eg.Wait(); err != nil {
        return House{}, err
    }
    return d.builder.getHouse(), nil
}
```

By using Go’s `errgroup` package, we can parallelize the construction steps. This alteration allows the building of doors, windows, and rooms to occur simultaneously, potentially cutting down the total build time to approximately 1 second—a significant improvement!

**The Impact of Concurrency**

Implementing concurrency in your Builder pattern can dramatically enhance efficiency, especially in languages like Go that are designed with concurrency in mind. This method ensures that the end result remains consistent while optimizing the construction process.

**Resources and Further Exploration**

If you're interested in experimenting with these concepts, you can access the complete code examples here:
- [Builder Pattern Code](https://bitbucket.org/juan-go-patterns/builder/src/main/)
- [Optimized Builder with Concurrency](https://bitbucket.org/juan-go-patterns/builderx2/src/main/)

Feel free to follow me on Instagram [@i.am.juan.dev](https://instagram.com/i.am.juan.dev) for more insights and updates on software development practices.

I encourage you to explore the potential of integrating concurrency into your Builder implementations. It’s a powerful way to enhance performance and efficiency in your projects. Happy coding!