Hacker News new | ask | show | jobs
by maccard 541 days ago
If I want to build and test a golang app and push it to a container repository, what value does a makefile provide over go build && docker push?

All the tools do their own dependency tracking already (unfortunately).

3 comments

You want to use GNU Make, and then you can ignore the Make dependency tracking. GNU Make is much easier when you only use so-called phony targets (consult the manual), which always execute without doing any dependency tracking.

As for the advantage, a makefile will definitely perform both go build and docker push, rather than just (say) docker push, an ever-present risk if you have to rely on your fingers to type these things in, or rely on your eyes to check that you recalled the right command from the history. It will also explicitly tell you the build failed rather than relying on you to do echo $? or for the tools to have some obvious output in the error case.

A shell script is also an option. Makefiles have some helpful extra features: by default, commands are echoed; by default, the build fails if any command exits with a non-0 exit code (please consult local Unix person for the details); a Makefile inherently has multiple entry points; and, a Makefile can also be easier to get working on Windows than a shell script, though if you can demand that people run it from Git Bash then maybe there's not much in this.

If you're still not convinced: that's fine! This is not a sales pitch.

(I've more recently switching to using a do-everything Python script for this stuff, which is more annoying when it comes to invoking commands but has obvious advantages in terms of how easy it is to add extra logic and checks and some UI creature comforts and so on.)

fabfile (Fabric/invoke: https://www.pyinvoke.org) may be an alternative to .PHONY-heavy Makefile (shell commands glued together by Python code)
Maybe none, but at some point you may want to do other things at buildtime, such as generating an sqlite db or generate code stubs for protobuf. Having a universal, and highly refined, tool like Make will help developers without domain knowledge. It also does not exclude the use of other tool like Just and Docker. A Makefile is also an easy jump-off point for a build pipeline.
Then introduce it for those things. But a makefile to call go build, go test, docker push, Ecs update-services provides no value other than all of a sudden not working on windows without another tool.
I use make on windows under WSL. I've mostly given up on getting everything to run under every OS. There's always some quirk.
Honestly I like it just to keep it as a command runner with the needed flags. Then in the unholy YAML there's just make build, make test, etc
At that point you end up with a makefile that has a 1:1 mapping with targets in my experience. At a previous job, we had an enormous makefile, most of which was defining phone targets and translating make arguments into maven arguments. All the actual targets were calling maven. Make provided no value at all in that, other than requiring you to know Make and maven to modify anything in the build.

Personally I’d rather a shell script for a command runner in most cases

Yeah, mine often just defers back to some shell scripts. But it's useful to enumerate them in the Makefile.
If you have a telltale prefix for any internal phony targets (I use "_"), then you can have the Makefile list all the interesting targets itself. Cat the Makefile, print every line matching "^\.PHONY:[[:space:]]*[^_]", then strip out the prefix. Leave any suffix, as you can put a trailing comment in, e.g.,

    .PHONY:build_windows # build for Windows. Supply DEBUG=1 for a debug build
I find this super useful. Even if you remember exactly what the target was called, it still gives you a nice list of words you can double click on to pull into the command line.
The `just` tool is a better and much easier to understand command runner than `make`, however. Much less feature surface, too, which eliminates nasty surprises coming from the unnecessary complexity of `make`.
There are a pletora of tools better than Make. But it's a standard tool, everyone is familiar with it, you probably don't even have to install it.
`just` is 90% similar to `make` in syntax, only it has 100x less foot guns. :)

Also I'll never understand the appeal of "not having to install a tool". We're not in the 1980s anymore when that was an actual chore. You run a command, the tool is there (including in CI/CD), boom, done. What am I missing here?

The advantages you list are flimsy at best.

Bootstrapping can be painful in some languages or frameworks. Not everyone is running containerised builds where there are ephemeral environments that you just install a tool (and pay the 30+ second cost per build to run apt-get update). There’s certainly value in having a front door entry point. But I think it should be a shell script, not a makefile.
Yes to your last. Either sh/bash script or a precompiled Golang program. If installing a tool is really such a problem then having a precompiled strongly typed program doing various tasks should be a no-brainer.

I started openly hating `make` because I re-learned its specifics and quirks several times over the course of 10-ish years and then figured that I want to learn stuff with a staying power in my brain. I don't use `make` every work day so eventually any quirks disappear -- that's how our brains work.

So that's why I learned most of `just` and it hasn't betrayed me so far, not once. Though I did write a few Elixir and Golang programs for running various tasks in production environment, too.