On Sunday, July 9, 2017 at 9:12:06 PM UTC+2, Anmol Sethi wrote: > > Hello everyone! > > I’m writing a new library where I need to be able to configure a struct. > This struct and its configuration will be accessed concurrently. One design > pattern I see throughout the standard library and community is to make the > struct and its configuration fields public but all other fields private. >
> e.g. > > type MyServer struct { > ConfigureMe int > usedInternally string > } > > This nicely complements Go’s default values and is very terse to use. This > is exactly how structs such as http.Server and autocert.Manager (part of > the new acme library) are used. > > As aforementioned, the configuration fields in my struct need to be > accessed concurrently. My issue is that since the configuration fields are > public, they can be freely mutated by a package user and so a race > condition may occur. I’m not sure how big of an issue this is considering > its very unlikely that someone will mutate the struct once its being used > but the design feels a bit fragile to me. > As you point out, race conditions might be a problem. That depends whether your configuration involves maps, or if it involves multiple parts of the configuration that a client might need to change together. If that's the case, then don't do it that way. This depends, in part, on whether or not your object can be seamlessly reconfigured at any time. Another way of configuration options that I've considered involves using shadow configuration. Let clients change publicly accessible fields, and shadow the former values. This approach might be useful if your service can only change the actual configuration at specific times. When you hit those points, check the configuration in the struct versus the one previously used. When different, change and update the shadowed version. > > In search of a better way, I thought about using a config struct but then > I found Dave Cheney’s post > https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis about > using functional options and now I’m thinking of using those. However, I > haven’t seen this API design used anywhere at all in any library I have > ever used (or in the standard library at all) so I was wondering whether or > not it’s idiomatic. > Seems idiomatic to me. However, it does bake in a particular pattern of configuration that can only be done once, with an initialization function, rather than configuration that can be updated at any time. > > I’m not sure if I’m being overly pedantic in my criticism of having the > configuration fields public in the struct. I don’t have too many > configuration fields so maybe functional options will be overkill. > Seems to me the two approaches satisfy different needs. Public fields of a structure imply full configurability on the fly - such as logging configuration, whereas Cheney's approach implies configuration at launch. You might, in fact, need to use both. > > I’m not really sure what I should go with now and I’ve hit a mental block > with my design. I’m hoping someone will have some thoughts on what approach > I should go with. > Start with simpler. If you can change configuration on the fly, but need to worry about race conditions, then provide a method to update the config regardless. Eric -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.