Dave Cheney - Functional Options
Dave Cheney (@davecheney) is a Go contributor who blogs at dave.cheney.net.
—
photo credit: Nicolas Ravelli
A story
Dave Cheney's talk is titled "Functional Options" and started with a story where a developer is tasked with writing a crucial server component, which appears to be simple in the beginning but later is flooded with requests such as TLS support, user feedback, load support, concurrency, all of which require changes to the original API in order to incorporate the new requirements.
An option: Structuring the API
Dave (sarcastically) shows an over-documented API example, which makes its usage ambiguous. Rather than trying to provide one single function to accommodate multiple use-cases, maybe write multiple simple and small functions for each-use case, with short documentation?
Another option: A config structure
Another option, with most advantages would be to use a configuration structure, allowing it to grow in the future while not touching the original API. "What used to be a big doc comment, now becomes a simple comment on that configuration object". This pattern isn't perfect though, because it makes it a bit more difficult to have default values. It is advised to use pointers to configuration objects rather than the object itself, so that when default behavior is desired that parameter can be set to nil, rather than an empty config object.
This is still not the optimal solution because it's not desired to receive nil parameters.
The optimal solution?
Go does not support optional function parameters, but it does support variadic params, and as such, we have the liberty to rid ourselves of pointers while we can continue to use the API by optionally passing it a config function.
But is this still the best way do to things?
The answer: Functional options
In functional options, we initialize our server by passing it a list of functions as arguments, each one of these functions take the server as a parameter and act upon it imposing the behavior that they are assigned too.
IE: NewServer(addr string, options ...func(*Server)) (*Server, error)
In this way we rid ourselves of config objects, nil values, and allow as many functional options as we need, similar to the middleware pattern.
Dave demoes a terminal interface that he has implemented using the above pattern. (https://sourcegraph.com/github.com/pkg/term@master/.GoPackage/github.com/pkg/term/.def/Open)
Functional options allow you to:
let you write beautiful APIs that can grow over time
enable the default use case to be its simplest
give more memorable, meaningful parameters
provide direct control over the initialization of complex values
—
Want to hear more from Dave? Follow him at @davecheney, read his blog at dave.cheney.net, check out his GitHub projects, and see his open-source contributions on Sourcegraph.











