Skip to content

Commit

Permalink
Refine configuration design docs (open-telemetry#1841)
Browse files Browse the repository at this point in the history
* Refine configuration design docs

* Remove repetition

* Fix typo

* Unify code blocks

Co-authored-by: Tyler Yahn <[email protected]>
  • Loading branch information
pellared and MrAlias authored Apr 27, 2021
1 parent 62cd933 commit 392a44f
Showing 1 changed file with 33 additions and 29 deletions.
62 changes: 33 additions & 29 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ join the meeting or get in touch on

You can view and edit the source code by cloning this repository:

```bash
```sh
git clone https://github.com/open-telemetry/opentelemetry-go.git
```

Expand Down Expand Up @@ -166,16 +166,16 @@ to the reasons why.

### Configuration

When creating an instantiation function for a complex `struct` it is useful
to allow variable number of options to be applied. However, the strong type
system of Go restricts the function design options. There are a few ways to
solve this problem, but we have landed on the following design.
When creating an instantiation function for a complex `type T struct`, it is
useful to allow variable number of options to be applied. However, the strong
type system of Go restricts the function design options. There are a few ways
to solve this problem, but we have landed on the following design.

#### `config`

Configuration should be held in a `struct` named `config`, or prefixed with
specific type name this Configuration applies to if there are multiple
`config` in the package. This `struct` must contain configuration options.
`config` in the package. This type must contain configuration options.

```go
// config contains configuration options for a thing.
Expand All @@ -184,7 +184,7 @@ type config struct {
}
```

In general the `config` `struct` will not need to be used externally to the
In general the `config` type will not need to be used externally to the
package and should be unexported. If, however, it is expected that the user
will likely want to build custom options for the configuration, the `config`
should be exported. Please, include in the documentation for the `config`
Expand All @@ -203,7 +203,7 @@ func newConfig([]Option) config {
// Set default values for config.
config := config{/* […] */}
for _, option := range options {
option.Apply(&config)
option.apply(&config)
}
// Preform any validation here.
return config
Expand All @@ -224,10 +224,14 @@ To set the value of the options a `config` contains, a corresponding

```go
type Option interface {
Apply(*config)
apply(*config)
}
```

Having `apply` unexported makes sure that it will not be used externally.
Moreover, the interface becomes sealed so the user cannot easily implement
the interface on its own.

The name of the interface should be prefixed in the same way the
corresponding `config` is (if at all).

Expand All @@ -250,11 +254,11 @@ func With*(…) Option { … }
```go
type defaultFalseOption bool

func (o defaultFalseOption) Apply(c *config) {
func (o defaultFalseOption) apply(c *config) {
c.Bool = bool(o)
}

// WithOption sets a T* to have an option included.
// WithOption sets a T to have an option included.
func WithOption() Option {
return defaultFalseOption(true)
}
Expand All @@ -263,15 +267,15 @@ func WithOption() Option {
```go
type defaultTrueOption bool

func (o defaultTrueOption) Apply(c *config) {
func (o defaultTrueOption) apply(c *config) {
c.Bool = bool(o)
}

// WithoutOption sets a T* to have Bool option excluded.
// WithoutOption sets a T to have Bool option excluded.
func WithoutOption() Option {
return defaultTrueOption(false)
}
````
```

##### Declared Type Options

Expand All @@ -280,23 +284,23 @@ type myTypeOption struct {
MyType MyType
}

func (o myTypeOption) Apply(c *config) {
func (o myTypeOption) apply(c *config) {
c.MyType = o.MyType
}

// WithMyType sets T* to have include MyType.
// WithMyType sets T to have include MyType.
func WithMyType(t MyType) Option {
return myTypeOption{t}
}
```

#### Instantiation

Using this configuration pattern to configure instantiation with a `New*`
Using this configuration pattern to configure instantiation with a `NewT`
function.

```go
func NewT*(options ...Option) T* {…}
func NewT(options ...Option) T {…}
```

Any required parameters can be declared before the variadic `options`.
Expand All @@ -313,38 +317,38 @@ For example.
```go
// config holds options for all animals.
type config struct {
Weight float64
Color string
MaxAltitude float64
Weight float64
Color string
MaxAltitude float64
}

// DogOption apply Dog specific options.
type DogOption interface {
ApplyDog(*config)
applyDog(*config)
}

// BirdOption apply Bird specific options.
type BirdOption interface {
ApplyBird(*config)
applyBird(*config)
}

// Option apply options for all animals.
type Option interface {
BirdOption
DogOption
BirdOption
DogOption
}

type weightOption float64
func (o weightOption) ApplyDog(c *config) { c.Weight = float64(o) }
func (o weightOption) ApplyBird(c *config) { c.Weight = float64(o) }
func (o weightOption) applyDog(c *config) { c.Weight = float64(o) }
func (o weightOption) applyBird(c *config) { c.Weight = float64(o) }
func WithWeight(w float64) Option { return weightOption(w) }

type furColorOption string
func (o furColorOption) ApplyDog(c *config) { c.Color = string(o) }
func (o furColorOption) applyDog(c *config) { c.Color = string(o) }
func WithFurColor(c string) DogOption { return furColorOption(c) }

type maxAltitudeOption float64
func (o maxAltitudeOption) ApplyBird(c *config) { c.MaxAltitude = float64(o) }
func (o maxAltitudeOption) applyBird(c *config) { c.MaxAltitude = float64(o) }
func WithMaxAltitude(a float64) BirdOption { return maxAltitudeOption(a) }

func NewDog(name string, o ...DogOption) Dog {…}
Expand Down

0 comments on commit 392a44f

Please sign in to comment.