The Most Efficient Struct Configuration Pattern For Golang

Sdílet
Vložit
  • čas přidán 3. 05. 2023
  • ► Join my Discord community for free education 👉 / discord
    ► Pre order (get 30% off) my exclusive Golang course 👉 fulltimegodev.com
    ► Follow me on Twitter 👉 / anthdm
    ► Follow me on GitHub 👉 github.com/anthdm
    In this Golang tutorial, you'll learn about an efficient configuration pattern in Golang that will help you master complex structures and simplify your code. Discover how to unlock the power of configurable structures in Golang and create mind-blowing patterns to enhance your programming skills.

Komentáře • 157

  • @anthonygg_
    @anthonygg_  Před rokem +2

    ► Join my Discord community for free education 👉 discord.com/invite/bDy8t4b3Rz
    ► Pre order (get 30% off) my Golang course 👉 fulltimegodev.com
    Thanks for watching

  • @kafran
    @kafran Před 9 měsíci +125

    This pattern is commonly known as the "Functional Options" pattern. The Functional Options pattern is a design pattern in Go where you pass in functions that alter the state of a type. These functions are often called "option functions". They provide a way to cleanly design APIs and offer a more flexible and readable way to interact with a function or type. Nice demonstration on how to implement them. Thanks.

  • @abiiranathan
    @abiiranathan Před rokem +97

    Functional Options Pattern... popularized by Dave Cheney

    • @wuilliam321
      @wuilliam321 Před rokem

      Any book/reference? Thanks

    • @jamesprendergast7158
      @jamesprendergast7158 Před rokem +3

      Surprised gg didn't know the name TBH

    • @Cruzylife
      @Cruzylife Před rokem +1

      @@jamesprendergast7158 because Ant creates his own meta

    • @TehKarmalizer
      @TehKarmalizer Před 4 měsíci +2

      Looks like functional riff on the builder pattern.

  • @jeezusjr
    @jeezusjr Před rokem +4

    Perfect timing! I am doing something right now that can use this pattern. Thanks!

  • @necroowl3953
    @necroowl3953 Před 7 měsíci +19

    1. Make the config elements private
    2. Make the options type a public interface, with a single private method (apply(config) config)
    3. Expose public functions returning this interface
    4. Add a function type that complies with the option interface, make that type implement the apply method by calling itself.
    5. Add a no-op type for validation when needed.
    6. Validate input before returning a config type.
    Boom, functional options with a restrictive builder pattern, for your constructors. You can make it generic too.

    • @macot79
      @macot79 Před 2 měsíci +2

      Hey! Those suggestions are really great, I'm new at Golang and have tried to adapt Anthonygg's example with your suggestions, but I'm a bit stuck at step 5. Could you clarify what you mean? Thanks

    • @hugorojasmonzon1487
      @hugorojasmonzon1487 Před 22 dny +1

      Could you create a github example of these ideas ?

  • @jex8885
    @jex8885 Před 10 měsíci +2

    This channel is amazing, you're making my Go code better and better for every video!

  • @rajdama205
    @rajdama205 Před 6 měsíci

    The way you make any concept understand is just amazing !!

  • @bigtymer4862
    @bigtymer4862 Před rokem +2

    Love these pattern videos man!!

  • @kylestubblefield3404
    @kylestubblefield3404 Před 9 měsíci +1

    This is a great video. I stumbled onto using this pattern by accident, it was very useful for a previous project I was working on

  • @skyline7349
    @skyline7349 Před 4 měsíci +1

    Thank you for posting this Anthony, very nice pattern and will be trying to incorporate it with my starter projects

  • @Crazyfulization
    @Crazyfulization Před 8 měsíci

    Really helpful, you can see the benefit right away! Awesome stuff

  • @bjugdbjk
    @bjugdbjk Před 10 měsíci +1

    Just love this man !! More like this brother, these r the stuff which really play with the Dopamine !!

  • @grim.reaper
    @grim.reaper Před rokem +2

    This is amazing and used in a lot of places tbh. This is very true that it's used in gRPC, also ssh package if I am not wrong because ssh connection has a lot of options. While putting this in a library the "withXYZ" functions can also be a method where it can have the server receiver methods.
    This is so so so amazing!!!

  • @kajfehlhaber
    @kajfehlhaber Před rokem +2

    Awesome video as always! ❤

  • @kanfit
    @kanfit Před 10 měsíci

    Thanks, I think you also talked about a bit of functional programming in Golang in this video, which is very nice.

  • @fauzi5848
    @fauzi5848 Před 9 měsíci

    This is so useful, thank you so much!

  • @codewithluke
    @codewithluke Před rokem +2

    Nice one. Really enjoy this pattern.

  • @arieheinrich3457
    @arieheinrich3457 Před rokem +9

    Thanks for diving into design patterns Anthony ! This is what separate starting devs to more advanced ones, that we all aspire to be, and that is understanding design patterns. Looks more like the Builder pattern than the Visitor one.

    • @anthonygg_
      @anthonygg_  Před rokem +5

      Apperantly is the “functional options” pattern 🤷‍♀️

    • @arieheinrich3457
      @arieheinrich3457 Před rokem

      @@anthonygg_ yes Functional Options Builder pattern !

    • @dejanranisavljevic
      @dejanranisavljevic Před 7 měsíci

      I also know this as a builder pattern, it's very common and good use for building test fixtures

  • @lotfikamel5947
    @lotfikamel5947 Před rokem +3

    As always very advanced content

  • @sibonelongobese8639
    @sibonelongobese8639 Před rokem +1

    Top notch stuff 👌🏽

  • @vitaliik8315
    @vitaliik8315 Před 3 měsíci

    Thanks for yours lessons. One of the best video lessons for go.

  • @miguelborges7913
    @miguelborges7913 Před rokem +2

    This is great!

  • @whatwhat2573
    @whatwhat2573 Před 5 měsíci +1

    Nice clean pattern to understand too

  • @vitiok78
    @vitiok78 Před rokem +6

    Reinventing the wheel of named function parameters with default values))

    • @susiebaka3388
      @susiebaka3388 Před 2 měsíci

      you're free to use a map or whatever my guy

  • @pserra94
    @pserra94 Před rokem +3

    Hi Antonio, how are you? I'm migrating from nodejs to Golang thanks to you and your videos, always amazing! I don't know if it's asking too much, but could you make a video/tutorial for developing web crawlers with golang, please? I was googling about it but I didn't find any good content about it. Thank you so much my friend, you are amazing!

  • @grise123
    @grise123 Před rokem +3

    nice pattern, seems very helful

  • @user-bh8xz4xy7o
    @user-bh8xz4xy7o Před 6 měsíci +1

    Watch this video for some time ago, remember. And return now to implement this in my project))
    Antony is gigachad, thx for the video

  • @michael_loc009
    @michael_loc009 Před rokem

    I wish you would upload this amazing tutorial when I first learnt Go.

  • @hugorojasmonzon1487
    @hugorojasmonzon1487 Před 22 dny

    Amazing video, thanks for sharing your knowledge!

  • @lokthar6314
    @lokthar6314 Před rokem +6

    Quality Content

  • @mihaiii6720
    @mihaiii6720 Před 7 měsíci

    This pattern is so good !!! I guess you can use it in TS/JS too

  • @vanshajdhar9223
    @vanshajdhar9223 Před 11 měsíci +1

    Beautiful ❤️

  • @johnb7657
    @johnb7657 Před 2 měsíci

    Thank you, perfect

  • @JT-mr3db
    @JT-mr3db Před 22 dny

    Does feel like a take on the builder pattern.
    Incredibly handy pattern a lot of Elm libs use as well.

  • @fluctura
    @fluctura Před 6 měsíci +2

    Meanwhile in TypeScript:
    mergedOpts = {
    ...defaultOpts,
    ...opts
    } as Opts
    But its a cool pattern. Go doesn't have "map spread operator" and thats a good thing probably. But sometimes it would be so handy to have more syntactic sugar

    • @fluctura
      @fluctura Před 6 měsíci

      btw it is a mix of Higher order Functions you write and you use them to compose a struct using Inversion of Control.
      So basically Higher order compositional Inversion of Control based state management (as your config acts as a state) 😂😅

  • @Rohinthas
    @Rohinthas Před 11 dny

    Aah functional stuff is just so pleasing to think about

  • @victorkochkarev2576
    @victorkochkarev2576 Před 12 dny

    This is a beautiful pattern!

  • @matthewbridges3147
    @matthewbridges3147 Před měsícem

    Thanks for the explainer, I'd have been searching docs for a standard way to do this without realising it requires a pattern. In JS I'd just use a default arg param and a spread operator to override

  • @fringefringe7282
    @fringefringe7282 Před rokem +1

    This is pretty cool.

  • @banatibor83
    @banatibor83 Před měsícem +1

    It looks fancy but a bit of a hassle. A simple builder pattern is much more readable I think. The default values are nice. Then just put methods onto the ServerOpts type which return *ServerOpts.
    type ServerOpts struct {...},
    func NewServerOpts() *ServerOpts {...set defaults...} ,
    func (s *ServerOpts) Id(id string) *ServerOpts {... set id ..},
    func (s *ServerOpts) MaxConn(maxconn int) *ServerOpts {...set maxcon..}
    Then you can use it like this:
    s := NewServer(NewServerOpts().Id("my-server").MaxConn(100))

  • @inaccessiblecardinal9352

    Good stuff. Aws' sdk has this pattern in every client (that I've used).

  • @seanknowles9985
    @seanknowles9985 Před 6 měsíci

    Hey big boss, two questions:
    1. How to make an efficient cron job scheduler from scratch?
    2. How to make realtime subscriptions to database values - for example we have key value store but then we build realtime subs that can subscribe to changes of a key and its data?
    Another quality video for the fans homie, love this channel.
    Bests,
    Super fan.

  • @plashless3406
    @plashless3406 Před rokem +1

    amazing.

  • @HiperCode10100
    @HiperCode10100 Před 4 měsíci

    very good thx bro

  • @burionyt
    @burionyt Před rokem +3

    only real world shit in the channel 💪🏼 love your content as always ❤

  • @reikooters
    @reikooters Před 7 měsíci +6

    Isn't this kind of a limitation on the language? If you could specify default values when you declare structs, then this would go from 50 lines down to 10? You mentioned doing this function approach if you were building a library. How would you do this in a way that's easy for consumers of the library to use and know which functions are available to be used for configuration? Would you put them together into a "configuration" package? (I'm not a Go user, just interested)

    • @sunofabeach9424
      @sunofabeach9424 Před 6 měsíci +2

      this language is limited is so many ways that eventually you give up on it and probably on life as well. GO, while being a higher level than C, looks and feels as clunky as C. but what in C is honestly called a hack, in GO called a pattern. C was designed to be as easy to parse and compile as possible and that's why it lacks so much. GO has no such excuse

    • @klamberext
      @klamberext Před 4 měsíci

      The example here is for overriding defaults.
      Imagine instead a environment specific factory configuration or just a variety of options:
      Lets say your server/thingy supports different storage services - S3, ftp, local.
      Now you want to say: withStorageDriverFromEnv, or withFtpStorage or withS3 storage.
      All of them require different kinds of paths, credentials etc..
      Now do that with default values on struct.
      The limit is in the example given.

    • @klamberext
      @klamberext Před 4 měsíci

      For consumers you provide docs. Or you instead implement the OptFunc as an interface . Then it would be possible to view the list of implementations for given interface(if you have good IDE) .

  • @myrachoantonio8832
    @myrachoantonio8832 Před rokem +1

    that was really cool trick i like it

  • @kevinkkirimii
    @kevinkkirimii Před rokem

    I have misused this pattern. Quite useful

  • @Epistemer
    @Epistemer Před rokem +4

    This is honestly really cool, I always hated how there is no way to do kwargs in go

  • @ShadwTrooper
    @ShadwTrooper Před měsícem +1

    Clever. I like it.

  • @MrXperx
    @MrXperx Před 7 měsíci +2

    Looks to be a variation of the builder pattern. (I come from OOPS)

  • @henrisetiawan7547
    @henrisetiawan7547 Před 5 dny

    Gem....amazing explanation..and going sub ..

  • @yogeshdharya3857
    @yogeshdharya3857 Před 9 měsíci

    3:50 to 3:53 Witch Craft and Woo Doo ! . My man's a part-time wizard

  • @orterves
    @orterves Před měsícem

    That's a beautiful pattern

  • @jf3518
    @jf3518 Před 3 měsíci

    Great work around. Though I would not use it, as I cannot use an existing config to initialize the state. Instead I would just use merge function to join default config with provided config.

  • @MENTOKz
    @MENTOKz Před 11 měsíci +1

    oh snap cool man

  • @maninalift
    @maninalift Před 6 měsíci

    Is there an advantage over the builder pattern? It seems to be equivalent in usage but I'd guess harder to optimise.

  • @Md.MitunRahman
    @Md.MitunRahman Před 6 měsíci

    this is unbelievable

  • @FareAlert
    @FareAlert Před 7 měsíci

    Opts
    (Opts, opts), opts
    Opts
    Opts opts😅
    Thank you Op for the video ; I appreciate your talent and time

  • @ivanrachev9409
    @ivanrachev9409 Před 11 měsíci

    Cool approach! Just wondering, why did you go back to VS Code?

  • @ChristopheHa
    @ChristopheHa Před 5 měsíci

    I guess this could also be combined with builder pattern, and then you can just can chain those withX on the builder and build will return the instance

  • @luizfernandopereira5120
    @luizfernandopereira5120 Před 7 měsíci

    This pattern is just an adptation from the Fluent Interface Pattern existing in OOP languages, is nice to see it in go though.

  • @PouriyaJamshidi
    @PouriyaJamshidi Před rokem +3

    This was really informative.
    A side question. Any particular reason for using int instead of uint in maxConn?
    I noticed most people use int where a uint makes more sense. In this case, we cannot have negative maxConn.

    • @anthonygg_
      @anthonygg_  Před rokem +3

      Just for demonstration purposes. Uint is better.

    • @PouriyaJamshidi
      @PouriyaJamshidi Před rokem

      @@anthonygg_ Thanks.
      I think somewhere I heard something along the lines of integer underflow and was wondering if this has something to do with that

    • @helmchen1239
      @helmchen1239 Před 7 měsíci +2

      -1 meaning unlimited could be an option in that case though :)

  • @startengine8838
    @startengine8838 Před 5 měsíci

    how inner function (the one that you retuen in options functions) gets the pointer which it has as input when higher lexical scope doesnt provide it

  • @TheSurvivor1963
    @TheSurvivor1963 Před měsícem

    This is a good pattern, I've been using it for years, but why not make an option function that returns the same option function with the previous value? That way you can change and reset options on the fly. An example could be to elevate debug logging temporarily for some very complex code segment. Rob Pike wrote an article about this for some years ago.
    type Option func(*Some) Option
    type Some struct{
    ...
    dLevel int
    }
    func Debug(d int) Option {
    return func(s *Some) Option {
    t := s.dLevel
    s.dLevel = d
    return SetOption(t)
    }
    }

  • @CaffeineForCode
    @CaffeineForCode Před rokem +5

    The only problem with this pattern is that you lose info from the LSP. Working with the AWS SDK, I often have no idea what is possible or what the opt functions do without reading the documentation. It’s a trade off, especially when you have a lot of config options

    • @tigranrostomyan9231
      @tigranrostomyan9231 Před 8 měsíci

      I think it is possible to solve by putting all 'OptFunc's into another (child) package, e.g. "server/opts". Maybe it's a bit of overkill but if you then type 'opts.' and call autocompletion it will list all 'OptFunc's

    • @jub0bs
      @jub0bs Před 8 měsíci

      You write: "I often have no idea what is possible or what the opt functions do without reading the documentation." But is a classic config struct any better, in this respect?

    • @jurijskobecs2803
      @jurijskobecs2803 Před 3 měsíci

      @@jub0bs of course its better, you got one place/struct to check all the possible options

    • @jub0bs
      @jub0bs Před 3 měsíci

      @@jurijskobecs2803 The fields of a struct type tell you close to nothing about how they're going to be used by the rest of the program. Their names give you clues at best, and their documentation is meant to give you accurate information. But you'll need to dig into the implementation to definitely find out. In this respect, a struct isn't superior or inferior to functional options.

  • @sfsdeniso5941
    @sfsdeniso5941 Před rokem +3

    It is called 'Functional options pattern'

  • @MesheeKnight
    @MesheeKnight Před rokem +3

    We use to call this the Option pattern. Would you have a nice one for Mandatory config where you cannot provide a reasonable default, like a sql.Conn?

    • @anthonygg_
      @anthonygg_  Před rokem

      Thats an amazing question! You could force an interface as option and implement a noop for that interface as default to prevent nil pointers. What do you think?

    • @MesheeKnight
      @MesheeKnight Před rokem

      @@anthonygg_ i see the Idea, but i am looking for a way for large amount of mandatories, noop wont do the trick i think

    • @sfsdeniso5941
      @sfsdeniso5941 Před rokem +2

      It is called 'Functional options pattern' should look like this:
      func NewServer(addr string, opts ...Option) error () {.....}
      so here addr is mandatory.
      Usage example:
      server, err := NewServer("localhost",
      withPort(8080),
      withTimeout(time.Second))

  • @JasonJA88
    @JasonJA88 Před rokem +1

    👍

  • @vasiliyaristov7148
    @vasiliyaristov7148 Před 2 měsíci

    Interesting

  • @robinlioret7998
    @robinlioret7998 Před 8 měsíci

    I think it's a Go version of the Builder pattern, but not sure.

  • @timurgirfanov531
    @timurgirfanov531 Před rokem +2

    It's like Visitor pattern, but in a functional way

  • @metaltyphoon
    @metaltyphoon Před rokem +3

    AWS SDK uses this pattern too.

  • @heartly4u
    @heartly4u Před rokem +7

    why not create a builder pattern, which will do the same as what you are doing, with more readability.

    • @JohnDoe-ji1zv
      @JohnDoe-ji1zv Před rokem +1

      Can you share example how your pattern is more clear than the one shown in a video ?

    • @heartly4u
      @heartly4u Před rokem +5

      @@JohnDoe-ji1zv wouldnt it be more readable this way newServer().withTls().withId().withMaxConnections().build()

    • @tgraupne
      @tgraupne Před rokem

      I was thinking about the same thing. 🤔 Maybe the authors or some other people would like to chime in.

  • @folium5725
    @folium5725 Před rokem +1

    Hi Anthony, what theme do you use?

  • @x0z59
    @x0z59 Před 8 měsíci

    will this thing not make established Go features convoluted? aren't you not reinventing the wheel here?

  • @mozhago8280
    @mozhago8280 Před rokem

    Is this pattern used in go starndard lib?

  • @matiasbpg
    @matiasbpg Před rokem +3

    What is the advantage of this pattern over a builder pattern?

    • @sfsdeniso5941
      @sfsdeniso5941 Před rokem +1

      Error handling
      In go you cannot chain builder calls as each must return error (and not this)

    • @matiasbpg
      @matiasbpg Před rokem

      @@sfsdeniso5941 thanks for the answer! However I think a builder for the opts struct shouldnt have this problem, but now I can see the inconvenience. Maybe a walk around could be that the builder struct could itself carry through the error as a property and the build method could return the value error tuple

  • @quantenlicht
    @quantenlicht Před rokem +1

    Start: 1:03

  • @suikast420
    @suikast420 Před 3 měsíci

    Cool fancy< stuff. What about toi make a fluent api with that style?

  • @user-br3hw1us7k
    @user-br3hw1us7k Před rokem

    docker compose v2 uses this pattern

  • @user-sj3fp2xq2m
    @user-sj3fp2xq2m Před 3 měsíci

    This is essentially a builder pattern written in Go.

  • @caiocesarmelolopes2156
    @caiocesarmelolopes2156 Před 9 měsíci

    That looks like function as parameter that was introduced in java 8 with lambdas xD

  • @yawneed
    @yawneed Před měsícem

    Hello. Where does download your vscode config?

  • @chaitany.a
    @chaitany.a Před 8 měsíci

    This is like a functional builder pattern...?

  • @pyronb
    @pyronb Před 6 měsíci

    Can somone please rephrase what's happening at 6:15 with fn(&o) ? It's not clear to me how everything works together

    • @Aedaeum
      @Aedaeum Před 5 měsíci +2

      He's using the spread operator to allow as many OptFunc's as you want. He then uses the range operator to loop through each OptFunc and executes them with a reference to the options struct (that's the **fn(&o)**), so that the OptFunc can modify the options directly, overwriting the default options.

  • @dmitriyobidin6049
    @dmitriyobidin6049 Před 2 měsíci +1

    The only problem i have with this pattern is that it is not obvious which methods/func you can use as options.

  • @igor-glagola
    @igor-glagola Před 6 měsíci

    Looks like some sort of builder pattern

  • @valcubetaa
    @valcubetaa Před 25 dny

    This looks very oop

  • @TimurSevimli
    @TimurSevimli Před 3 měsíci

    Why not just take configuration data from a JSON file, like config.json?

  • @yjawhar
    @yjawhar Před rokem +1

    Go can easily resolve this issue by providing the option of built in default parameters similar to Python during the definition of the function

  • @codewithtee
    @codewithtee Před 6 měsíci

    I did something with this .... But my approach was quite different,

  • @DemmyDemon
    @DemmyDemon Před rokem +1

    Suggestion: Buy a pop filter.

  • @Edd211
    @Edd211 Před 6 měsíci +1

    How to code??

  • @bhumit070
    @bhumit070 Před 3 měsíci +1

    I think I have seen this pattern in google youtube package

  • @SigmaChirality
    @SigmaChirality Před měsícem

    Why not just make your config a .yaml file and parse it into a Config struct? Then you give your library users a defaults.yaml and they can copy and modify it at their will?

  • @hackastak
    @hackastak Před 3 měsíci +1

    I'll be honest. The accent makes it a little hard for me to understand you at times; HOWEVER, your content is SOO VALUABLE that I don't mind rewatching parts a few times to get better at Go.

    • @anthonygg_
      @anthonygg_  Před 3 měsíci +1

      I try my best. Thanks man! ❤

    • @hackastak
      @hackastak Před 3 měsíci

      @@anthonygg_ you're killing it my dude! great stuff!

  • @ajiwahidin423
    @ajiwahidin423 Před 3 měsíci

    I think more easier like this one below
    ```go
    type Config struct {
    Env "string"
    }
    func getConfig() (config Config){
    env, ok := os.LookupEnv("ENV")
    If !ok{
    env = "your default value of ENV here"
    }
    config.Env = env
    return
    }
    type Data struct {
    pool *pgxpool.Pool
    }
    func NewData(pool *pgxpool.Pool) (*Data, error) {
    if pool == nil {
    return nil, errors.New("no pool ready")
    }
    return &Data{
    pool: pool
    }, nil
    }
    func main(){
    config := getConfig()
    data, err := NewData(config.Env)
    }
    ```

  • @jed271
    @jed271 Před rokem +6

    I wish golang will add a feature where we can add default parameter value. I feel like this is too much just to do optional parameter stuffs.

  • @jaymartinez311
    @jaymartinez311 Před 4 měsíci

    the ‘…’ is called variadic.