The Go language and toolchain did not have a good version control system when created. Systems built on Go could not easily define the levels of the dependencies underpinning the system. Various tools were developed to help with that such as dep
and glide
. But more recently, the Go compiler environment has defined modules as the way forward. The MQ Go packages are now available in a format that works with modules, with a major number version update to match. This post describes what has been done in the core MQ packages.
A separate post talks about changes in the mq-metric-samples repository that exploits these packages and enables monitoring in tools like Prometheus and Influx.
Modules
Many programing languages and tools support some kind of dependency management. If you are writing Java programs and using maven as a build tool, then the pom.xml file defines all your direct dependencies and their versions; if you are writing Node.js programs, then npm with package.json fulfills a similar role.
These dependency managers all have good and bad points. One aspect in particular that can be problematic is when two components declare dependencies on the same package, but at different versions. The decision of which version to use can be confusing, and there may be no guarantees that you end up with a working system.
The design chosen for Go programs is known as modules. Packages declare which version they are, and consumers of those packages say which version they want to use. In this environment, the MAJOR number associated with a package (for example, the “4” in “v4.1”) is especially important as it can help to simplify the multiple-version resolution. The semantic version (semver) rules are assumed and applied. Within a given major version, compatibility is a given – while new function can be added within that major version, nothing that already exists will be removed or changed. Breaking API changes can be made only with a new major number. That simplifies the options for picking which versions to use.
Modules in the MQ Go interface
The mq-golang repository contains two packages: ibmmq and mqmetric. A single module can contain multiple packages and so these share the same version. The repository on GitHub had already gone through several incompatible changes as the APIs evolved, and had reached v4.1.4. I wrote an introduction to the API in its early days in this post.
One aspect of the Go module support is that it is relatively easy to add it for repositories that are still at v0 or v1. But once you get beyond that, migrating to modules essentially requires a new major version. And so there had to be a v5.0.0 release.
There has been no real change to the ibmmq APIs in this release but using modules means that references to it need to change. There were a few changes to the mqmetric APIs used by monitoring programs. While I could have introduced those changes in a compatible way, I took advantage of knowing that there was a new major version.
Application Programming with the MQ module
The changes to use modules in your applications are made in two places.
- You create a go.mod file in the root of your application code that lists all of your application’s dependencies and the versions required:
require ( github.com/ibm-messaging/mq-golang/v5 v5.0.0 )
This file can be automatically created with the go mod init
command with references to the various modules and packages called from your program though you may need to edit it to get the correct version. While there is only a v5.0.0 today as I write this, there will be future v5.x.y levels. It will be possible to force use of those when you need them by updating that reference in the go.mod file.
- In your source code (the .go files), import references to the specific packages need to be modified to use the major number in the path:
import (ibmmq "github.com/ibm-messaging/mq-golang/v5/ibmmq"
mqmetric "github.com/ibm-messaging/mq-golang/v5/mqmetric"
)
Now, when you run go build
the modules can be automatically downloaded, cached, and included in the compilation.
Migration and compatibility
If your application does not already use modules, then you can continue to use the older versions of the MQ packages. Tools like dep
can be used to force use of particular older versions. For example, you might have a Gopkg.toml file containing:
[[constraint]] name = "github.com/ibm-messaging/mq-golang" version = "4.1.4"
Version 4.1.4 was the “final” version before switching over to the v5 stream.
That can continue to be used but newer levels will not be available to you. However, many public packages are now being maintained only via module versioning. So you will likely have to make the small changes at some point, even if it’s just to pick up new fixes or features from some other component.
Summary
My original plan had been to make this release coincident with the next LTS release of MQ itself. There was no technical reason for that plan, it just seemed tidy. But I was finding that there were a number of features queued up, particularly in changes I wanted to make in the monitoring programs. Rather than release them later or piecemeal I decided I would do the whole thing earlier than expected. Especially as I had the module modifications working and waiting.
While getting the mq-golang repository modified to present itself via a module interface took a while to get right, I found migrating application code to use the module has been fairly quick and painless. I’d recommend anyone using these packages to convert.
This post was last updated on June 4th, 2020 at 09:44 am