DEV Community

Juan Miguel Arias Mejias
Juan Miguel Arias Mejias

Posted on

Builder pattern / improvements

#go

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:

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()
}
Enter fullscreen mode Exit fullscreen mode

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.

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
}
Enter fullscreen mode Exit fullscreen mode

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:

Feel free to follow me on Instagram @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!

Top comments (0)