For example I'm developing guestbook. It allows to add records, that need to be approved by moderator. But when developing further functionality, it's a pain to approve each record, that is added during testing. So, is it possible to build dev version of application that creates such records with appropriate flag set?
For example prod build is compiled with the following fucntion:
func NewRecord() Record {
return Record{Moderation: Awaiting}
}
And in dev build is compiled with:
func NewRecord() Record {
return Record{Moderation: Approved}
}
I know in frontend, when you building some JS app, it's a common practice to set NODE_ENV=production environment variable when building for production. I'm looking for something similar in Go. I see two ways, but don't like any of them:
Awaiting = Approved
while developing and then change it back to actual value when building prod version. But I afraid that one day I will forget about this mock, will commit it to repo or something like that.Change function to something like
func NewRecord() Record {
if os.Getenv(mykey) == "production" {
return Record{Moderation: Awaiting}
} else {
return Record{Moderation: Approved}
}
}
But I don't like that this condition is evaluated in runtime for each new record. It just seems to be wrong for compiled language.
As a bonus it would be nice, if such application can show warning (to stdout/stderr) if it's build as dev version.
Thanks.
Personally I think using environment variables as you've done in your example is the "correct" way to do this. This allows you to tweak the behavior without rebuilding the application, which may be very useful while debugging. However, if you really want this done at compile time it can be accomplished with build constraints.
A built constraint is a special comment placed at the top of a file that says "only build this file if a specific condition is met". Conditions can be things like the machine architecture we're building on, the OS we're running, or custom build tags that the user specifies when building.
For example, you could tweak your function to something like:
func NewRecord() Record {
return Record{Moderation: ModLevel}
}
and then define ModLevel twice, once in a file modlevel_prod.go
that looks like this (Note that the syntax for build constraints is changing, the second line is the new syntax and the first one wont' be valid for much longer. See the link at the end of this post for more info):
// +build !dev
//go:build !dev
package mypackage
const ModLevel = Awaiting
and one in modlevel_dev.go
(or whever, the filename doesn't matter in this case) that looks like this:
// +build dev
//go:build dev
package mypackage
const ModLevel = Approved
Now, when you build, the production version of the file is the default and if you want to build the dev version of the file you have to explicitly include the build tag:
$ go build -tags dev
EDIT: the syntax for build constraints is changing. I have updated the examples to include both the old and new versions (which currently coexist). See https://golang.org/issues/41184 for more info and a timeline for deprecating the old one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With