This is pretty good, but I recommend going one step further and moving all subpackages from reporoot/cmd/.../ to reporoot — and each command main itself should be limited to stitching together logic from another subpackage, either below reporootor below reporoot/internal. The reasons are basically the same: above the level of a small script-like command, my team finds that separating the command orchestration (e.g. flag handling, output & error reporting) from the actual logic helps encourage more reusable code. This also involves writing deployment-environment–neutral code in the main logic packages: what I mean is writing logic which works on e.g. a channel of domain objects rather than an AWS SQS queue, or which fetches domain objects from an interface passed in (and created) by main rather than commingling internal logic and database or filesystem reads.
I fully understand that this may feel like a YAGNI violation to a lot of folks, but we have found repeatedly that we have needed it and that the resulting code is cleaner, and easier to use & modify.
Are you saying to change @cadey’s example of:
│ ├── paperwork
│ │ ├── create
│ │ │ └── create.go
│ │ └── main.go
To something like the following where create is split out from being in the repo-root/cmd/paperwork namespace?
│ ├── paperwork
│ └──── main.go
I like this pattern, with all packages that could be reused being in the repo-root. There are times, however, when a package could be so specific to the cmd that it should be grouped under the cmd, but then it should most likely go in an internal package in the cmd repo-root/cmd/paperwork/internal/create.
Yup. It is possible that orchestrating-the-create-package-within-an-executable command would logically be a package, too, but that is pretty unlikely. Our main packages are really lightweight, generally a single file and a few screens of text.
We would also probably have lots of files at the repo-root level, implementing whatever the repo does.