ibm-messaging / mq-golang

Calling IBM MQ from Go applications
Apache License 2.0
168 stars 60 forks source link

Use the Functional Options pattern for Connx/MQCNO? #115

Closed evankanderson closed 5 years ago

evankanderson commented 5 years ago

I'm reviewing some go code using mq-golang, and it's not very go-like. In particular, there seems to be a repeated pattern:

connOptions :=ibmmq.NewMQCNO()  // C++ like constructor
connOptions.Options = ibmmq.MQCNO_CLIENT_BINDING  // No use of struct initialization
connOptions.ClientConn = channelDef
connOptions.SecurityParams = userPass

// Usage:
// Options field required, hard to figure out what's needed
queue, err := ibmmq.Connx(manager, connOptions)

You might want to look at using https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis to redefine the Connx API:

func Connx(manager string, options ...func(*MQCNO)) (MQQueueManager, error)

// ClientBinding configures the connection to use MQCNO_CLIENT_BINDING.
func ClientBinding(opts *MQCNO) {
  opts.Options = opts.MQCNO_CLIENT_BINDING
}

func ClientConn(client *MQCD) func(*MQCNO) {
  return func(opts *MQCNO) {
    opts.ClientConn = client
  }
}

...
// Usage:
queue, err := ibmmq.Connx(
    manager,
    ibmmq.ClientBinding,
    ibmmq.ClientConn(channelDef),
    ibmmq.SecurityParams(userPass),
)
evankanderson commented 5 years ago

You could use this same pattern for MQQueueManager.Open. Note that one benefit of the functional options pattern is that you can have a single function that sets more than one field of MQOD:

func OpenQueue(name string) func(*MQOD) {
  return func(def *MQOD) {
    def.ObjectType = MQOT_Q
    def.ObjectName = name
  }
}
ibmmqmet commented 5 years ago

I don't see this as something I'd implement here. There are many verbs, with many options and structures, that adding new functions that would handle all of them is likely to be very confusing. It would take the API a lot further away from all the existing knowledge from other languages, making it much harder to repurpose existing code, samples and skills. One thing, for example, you often need to do is to modify options - for example to change browse_first to browse_next. These patterns do not seem to lend themselves to that requirement.

For a simpler Go API for MQ, you might prefer to use the JMS-style layer which is at https://github.com/ibm-messaging/mq-golang-jms20