FAQ
Hello gophers!

I am trying to find what is idiomatic or even a good way to structure a
large "context". So this application has an interface Machine that has its
implementation switched out on different machines. Problem I have is with
testing. If I just want to stub out a single method of that interface I
have to create a stub struct with a bunch of empty functions, it becomes
unwieldy in tests. I have heard of three approaches, mock lib, split the
interface, and have a struct with function values.

Mock lib approach I would rather avoid.

Splitting the interface has the issue that now I have to pass around all
the split interfaces which are roughly equal in number to the functions in
Machine.

Struct with function values is odd because I am still passing this whole
thing around whereas a portion of the application or my tests really only
need the one function. Perhaps small and not measured but I imagine it is
slower because of the extra indirection.

My intuition tells me I should be able to do it with better interface
design but I'm coming up with nothing :(

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Jonathan Gaillard at Apr 17, 2015 at 1:51 am
    On closer inspection to my problem, having the individual interfaces isn't
    that bad. The only thing bad about it is where they are used and stored,
    and constructing that, struct.

    So if you have:
    type A struct {
       Field1 SomeInterface1
       Field2 SomeInterface2
       Field3 SomeInterface3
       Field4 SomeInterface4
       m map[string]int
       c chan struct{}
    }

    What do you provide as a constructor if you want to allow the four fields
    to be pluggable for tests? Perhaps a New() that only creates the map and
    chan and nil fields? Is that idiomatic?
    Perhaps check if map and chan are created everywhere they are used and let
    the default value of the struct be "usable", even if not really until they
    plug a field?

    On Thursday, April 16, 2015 at 6:16:07 PM UTC-7, jonathan...@gmail.com
    wrote:
    Hello gophers!

    I am trying to find what is idiomatic or even a good way to structure a
    large "context". So this application has an interface Machine that has its
    implementation switched out on different machines. Problem I have is with
    testing. If I just want to stub out a single method of that interface I
    have to create a stub struct with a bunch of empty functions, it becomes
    unwieldy in tests. I have heard of three approaches, mock lib, split the
    interface, and have a struct with function values.

    Mock lib approach I would rather avoid.

    Splitting the interface has the issue that now I have to pass around all
    the split interfaces which are roughly equal in number to the functions in
    Machine.

    Struct with function values is odd because I am still passing this whole
    thing around whereas a portion of the application or my tests really only
    need the one function. Perhaps small and not measured but I imagine it is
    slower because of the extra indirection.

    My intuition tells me I should be able to do it with better interface
    design but I'm coming up with nothing :(
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Paul Hankin at Apr 17, 2015 at 3:14 am

    On Friday, 17 April 2015 10:16:07 UTC+9, jonathan...@gmail.com wrote:
    Hello gophers!

    I am trying to find what is idiomatic or even a good way to structure a
    large "context". So this application has an interface Machine that has its
    implementation switched out on different machines. Problem I have is with
    testing. If I just want to stub out a single method of that interface I
    have to create a stub struct with a bunch of empty functions, it becomes
    unwieldy in tests. I have heard of three approaches, mock lib, split the
    interface, and have a struct with function values.

    Mock lib approach I would rather avoid.

    Splitting the interface has the issue that now I have to pass around all
    the split interfaces which are roughly equal in number to the functions in
    Machine.
    One approach that might work for you is to embed the Machine interface.
    This gives you for "free" a test struct that implements the Machine
    interface, and allows you to override specific methods for testing.

    type machineF struct {
         Machine
    }

    func (machineF) F() {
        ... stubbed method here.
    }

    In your test:
    var mf machineF
    ... use mf as a Machine

    --
    Paul

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jonathan Gaillard at Apr 17, 2015 at 5:36 am
    Wow I have totally missed that functionality! Seems a bit cryptic in the
    struct section of the spec and not specifically mentioned, or perhaps I am
    just dense. Is this ability meant for this kind of purpose or is this an
    abuse?

    Thanks for the help!
    On Thursday, April 16, 2015 at 8:13:54 PM UTC-7, Paul Hankin wrote:
    On Friday, 17 April 2015 10:16:07 UTC+9, jonathan...@gmail.com wrote:

    Hello gophers!

    I am trying to find what is idiomatic or even a good way to structure a
    large "context". So this application has an interface Machine that has its
    implementation switched out on different machines. Problem I have is with
    testing. If I just want to stub out a single method of that interface I
    have to create a stub struct with a bunch of empty functions, it becomes
    unwieldy in tests. I have heard of three approaches, mock lib, split the
    interface, and have a struct with function values.

    Mock lib approach I would rather avoid.

    Splitting the interface has the issue that now I have to pass around all
    the split interfaces which are roughly equal in number to the functions in
    Machine.
    One approach that might work for you is to embed the Machine interface.
    This gives you for "free" a test struct that implements the Machine
    interface, and allows you to override specific methods for testing.

    type machineF struct {
    Machine
    }

    func (machineF) F() {
    ... stubbed method here.
    }

    In your test:
    var mf machineF
    ... use mf as a Machine

    --
    Paul
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Egon at Apr 17, 2015 at 5:41 am

    On Friday, 17 April 2015 04:16:07 UTC+3, jonathan...@gmail.com wrote:
    Hello gophers!

    I am trying to find what is idiomatic or even a good way to structure a
    large "context". So this application has an interface Machine that has its
    implementation switched out on different machines. Problem I have is with
    testing. If I just want to stub out a single method of that interface I
    have to create a stub struct with a bunch of empty functions, it becomes
    unwieldy in tests. I have heard of three approaches, mock lib, split the
    interface, and have a struct with function values.

    Mock lib approach I would rather avoid.

    Splitting the interface has the issue that now I have to pass around all
    the split interfaces which are roughly equal in number to the functions in
    Machine.

    Struct with function values is odd because I am still passing this whole
    thing around whereas a portion of the application or my tests really only
    need the one function. Perhaps small and not measured but I imagine it is
    slower because of the extra indirection.

    My intuition tells me I should be able to do it with better interface
    design but I'm coming up with nothing :(
    Can you share what that Machine actually is and what are the interfaces
    etc. It seems that the real world context is necessary to properly analyze
    this situation.

    It seems that somehow and something should be split differently. e.g.
    "Machine" shouldn't be an interface, but

    type Machine struct {
         CPU
         Memory
         Disk
    }

    Where the CPU/Memory/Disk are interfaces. (I'm just making things up at the
    moment).

    + Egon

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jonathan Gaillard at Apr 17, 2015 at 6:04 am
    Hey Egon, Yes those are the kinds of things in Machine, actions too like
    ChangeRaid() or whatever. So this sounds like what Paul was suggesting but
    how do the extra interfaces help? Could you guys point out some usages in
    the standard lib maybe (or stdlib tests) which use interfaces embedded in
    structs?
    On Thursday, April 16, 2015 at 10:41:31 PM UTC-7, Egon wrote:
    On Friday, 17 April 2015 04:16:07 UTC+3, jonathan...@gmail.com wrote:

    Hello gophers!

    I am trying to find what is idiomatic or even a good way to structure a
    large "context". So this application has an interface Machine that has its
    implementation switched out on different machines. Problem I have is with
    testing. If I just want to stub out a single method of that interface I
    have to create a stub struct with a bunch of empty functions, it becomes
    unwieldy in tests. I have heard of three approaches, mock lib, split the
    interface, and have a struct with function values.

    Mock lib approach I would rather avoid.

    Splitting the interface has the issue that now I have to pass around all
    the split interfaces which are roughly equal in number to the functions in
    Machine.

    Struct with function values is odd because I am still passing this whole
    thing around whereas a portion of the application or my tests really only
    need the one function. Perhaps small and not measured but I imagine it is
    slower because of the extra indirection.

    My intuition tells me I should be able to do it with better interface
    design but I'm coming up with nothing :(
    Can you share what that Machine actually is and what are the interfaces
    etc. It seems that the real world context is necessary to properly analyze
    this situation.

    It seems that somehow and something should be split differently. e.g.
    "Machine" shouldn't be an interface, but

    type Machine struct {
    CPU
    Memory
    Disk
    }

    Where the CPU/Memory/Disk are interfaces. (I'm just making things up at
    the moment).

    + Egon
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Egon at Apr 17, 2015 at 7:41 am

    On Friday, 17 April 2015 09:04:55 UTC+3, jonathan...@gmail.com wrote:
    Hey Egon, Yes those are the kinds of things in Machine, actions too like
    ChangeRaid() or whatever. So this sounds like what Paul was suggesting but
    how do the extra interfaces help? Could you guys point out some usages in
    the standard lib maybe (or stdlib tests) which use interfaces embedded in
    structs?
    I don't know such examples in stdlib.

    Maybe these help you out:
    https://github.com/nwidger/nintengo/blob/master/nes/nes.go#L52
    http://gobot.io/

    They also use interfaces a lot and are similar in building "machines".

    The extra interfaces help, by being able to stub them out: e.g.

    type Machine struct {
    CPU
    RAM
    }

    func TestCPU() {
    m := Machine{CPU: NewCPU(), RAM: ramStub{}}
    // ...
    }

    func TestMem() {
    m := Machine{CPU: cpuStub(), RAM: NewRAM()}
    // ...
    }

    Also could you elaborate more on the context. I mean I have no clue what it
    is supposed to do (https://github.com/golang/go/wiki/howtoask). Essentially
    you know what you are talking about and it seems like I got the gist of it,
    but really I don't. (See Barnum effect)

    Essentially... who will use the thing you build, where will it be used, how
    is it valuable to the end user etc.

    + Egon

    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Jonathan Gaillard at Apr 17, 2015 at 6:27 pm
    So it seems like you can stub out methods individually without having to
    stub them all with what Paul suggested even on a single large interface. So
    in this case I am still not sure what the individual interfaces serve?

    Small interfaces are obviously idiomatic, but their utility I thought came
    in when functions only needed to take 1 or 2, out of the say 15 you split
    out. If some method would need 10 out of them, them it seems unwieldy.
    Wrapping those 10 up in another interface doesn't make sense because they
    have no concept together. For example there is a lot of interface
    composition in the io package, but you wouldn't make a
    RunePipeReadWriterMtimeGetterCloser or something like that right?

    I am also extremely curious about the intent behind embedding an interface
    in a struct, which I can find almost zero information on. Embedding a
    struct in a struct and an interface in an interface make total sense but an
    interface in a struct does compile so there must be a purpose? Anyone? This
    is driving my curiosity wild!

    For the background you're asking about, the Machine is the layer inbetween
    different kinds of well, machines, that a single api will be built on top
    of. Machines could be different os's or have different capabilities. That's
    about all I can say on it, probably makes sense to have Machine be a
    collection of components as things get larger, but this problem I am having
    lies at the heart of that.

    Thanks for the help!
    On Friday, April 17, 2015 at 12:41:11 AM UTC-7, Egon wrote:
    On Friday, 17 April 2015 09:04:55 UTC+3, jonathan...@gmail.com wrote:

    Hey Egon, Yes those are the kinds of things in Machine, actions too like
    ChangeRaid() or whatever. So this sounds like what Paul was suggesting but
    how do the extra interfaces help? Could you guys point out some usages in
    the standard lib maybe (or stdlib tests) which use interfaces embedded in
    structs?
    I don't know such examples in stdlib.

    Maybe these help you out:
    https://github.com/nwidger/nintengo/blob/master/nes/nes.go#L52
    http://gobot.io/

    They also use interfaces a lot and are similar in building "machines".

    The extra interfaces help, by being able to stub them out: e.g.

    type Machine struct {
    CPU
    RAM
    }

    func TestCPU() {
    m := Machine{CPU: NewCPU(), RAM: ramStub{}}
    // ...
    }

    func TestMem() {
    m := Machine{CPU: cpuStub(), RAM: NewRAM()}
    // ...
    }

    Also could you elaborate more on the context. I mean I have no clue what
    it is supposed to do (https://github.com/golang/go/wiki/howtoask).
    Essentially you know what you are talking about and it seems like I got the
    gist of it, but really I don't. (See Barnum effect)

    Essentially... who will use the thing you build, where will it be used,
    how is it valuable to the end user etc.

    + Egon
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Egon at Apr 17, 2015 at 7:05 pm

    On Friday, 17 April 2015 21:27:36 UTC+3, jonathan...@gmail.com wrote:
    So it seems like you can stub out methods individually without having to
    stub them all with what Paul suggested even on a single large interface. So
    in this case I am still not sure what the individual interfaces serve?
    These are two alternatives - you most likely wouldn't want to use those two
    together.

    Small interfaces are obviously idiomatic, but their utility I thought came
    in when functions only needed to take 1 or 2, out of the say 15 you split
    out. If some method would need 10 out of them, them it seems unwieldy.
    Wrapping those 10 up in another interface doesn't make sense because they
    have no concept together. For example there is a lot of interface
    composition in the io package, but you wouldn't make a
    RunePipeReadWriterMtimeGetterCloser or something like that right?
    Yes.

    I am also extremely curious about the intent behind embedding an interface
    in a struct, which I can find almost zero information on. Embedding a
    struct in a struct and an interface in an interface make total sense but an
    interface in a struct does compile so there must be a purpose? Anyone? This
    is driving my curiosity wild!
    One recent example (note, code is WIP):
    https://github.com/raintreeinc/kbwiki/blob/43d3bc33584da4228fce10fa923341631e71ea25/auth.go#L30

    Essentially, I wanted to add separate the OAuth2 + routing logic from the
    "Context" (which is intended mainly for setting up all the other services
    rather than something by itself.)...

    And it's much nicer to say:
    sess.LoginURL... rather than sess.Context.LoginURL.


    Similarly for your machine case... lets say you have

    type Memory interface {
    Store(dst uint32, value uint32)
    }

    type Machine struct {
    Memory
    }


    machine := Machine{simplememory{}}

    machine.Store(1, 1241)
    vs.
    machine.Memory.Store(1, 1241)

    Basically, it allows you to compose a bigger thing out of smaller things -
    with making it seem like a single thing.

    Whether you want it to look as a single thing or not is a different
    problem. e.g.

    type V2 struct { X, Y int }

    type Renderable interface {
    RenderAt(V2)
    }

    type Entity struct {
    Pos V2
    Vel V2
    Renderable
    }

    func (e *Entity) Render(){ e.RenderAt(e.Pos) }

    entity := Entity{V2{0,0}, V2{1,1}, NewTexture("example.png")}
    entity.Render()

    Basically the main reason I can think of embedding an interfaces is to make
    things look as a single cohesive thing without actually making them a
    single thing.

    For the background you're asking about, the Machine is the layer inbetween
    different kinds of well, machines, that a single api will be built on top
    of. Machines could be different os's or have different capabilities. That's
    about all I can say on it, probably makes sense to have Machine be a
    collection of components as things get larger, but this problem I am having
    lies at the heart of that.

    Thanks for the help!
    On Friday, April 17, 2015 at 12:41:11 AM UTC-7, Egon wrote:
    On Friday, 17 April 2015 09:04:55 UTC+3, jonathan...@gmail.com wrote:

    Hey Egon, Yes those are the kinds of things in Machine, actions too like
    ChangeRaid() or whatever. So this sounds like what Paul was suggesting but
    how do the extra interfaces help? Could you guys point out some usages in
    the standard lib maybe (or stdlib tests) which use interfaces embedded in
    structs?
    I don't know such examples in stdlib.

    Maybe these help you out:
    https://github.com/nwidger/nintengo/blob/master/nes/nes.go#L52
    http://gobot.io/

    They also use interfaces a lot and are similar in building "machines".

    The extra interfaces help, by being able to stub them out: e.g.

    type Machine struct {
    CPU
    RAM
    }

    func TestCPU() {
    m := Machine{CPU: NewCPU(), RAM: ramStub{}}
    // ...
    }

    func TestMem() {
    m := Machine{CPU: cpuStub(), RAM: NewRAM()}
    // ...
    }

    Also could you elaborate more on the context. I mean I have no clue what
    it is supposed to do (https://github.com/golang/go/wiki/howtoask).
    Essentially you know what you are talking about and it seems like I got the
    gist of it, but really I don't. (See Barnum effect)

    Essentially... who will use the thing you build, where will it be used,
    how is it valuable to the end user etc.

    + Egon
    --
    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+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedApr 17, '15 at 1:15a
activeApr 17, '15 at 7:05p
posts9
users3
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase