Modules... why it has to be so painfull?

1,235 views
Skip to first unread message

Slawomir Pryczek

unread,
Apr 7, 2021, 5:31:07 PM4/7/21
to golang-nuts
Hey Guys, I'm struggling with the new "modules" approach and after checking several help files it seems it's inconvinient beyond belief. Basically i have an app:

...src/
/myapp/main.go package main
/pool/pool.go package pool

And i can't even include package pool into main without manually initializing module, then installing it, and then when i do any change to pool i'll have to re-get / re-install the package, so it even breaks things as simple as conviniently building a basic app with >1 shared package.

Question is why it's no longer possible to break the project into independent packages and easily re-use them. I have eg. a webserver which implements each operation as separate package, and also it has slab allocator which other projects are using. And it works great.

Maybe someday i'd like to convert the slab allocator into separated module, but why forcing users to do so much unnecessary work and pretend everyone wants to expose everything they're writing as module from earliest stage of the project?

Is there any way to retain this kind of structure without countless hours wasted on manually initializing modules and other completely pointless maintenance tasks. Previously i was just able to create a package in gopath and use it everywhere, refactoring was very easy and i could easily split any project into multiple packages. Actually go was so good because refactoring and reorganizing code was so easy. Now it seems that's no longer possible and in docs I found info that gopath approach will be obsolete, so i'm trying to go with the new one. Which seems so painfull...

Also read several posts about local packages. Complexity of this is beyond ridiculous. Really i need to install a local proxy or use some special directives to allow my appa and appb to use packagec? Really it needs to be so complex and so user unfriendly so instead of writing code we'll be thinking about setting up proxies and configuring dependencies just to share some code between 2 local apps because this has to be done via HTTP or special configuration?

Anyone has an idea for a reasonable solution which will allow easy refactoring and code organization in packages, in this new model?

Thanks,
Slawomir.

Alex Howarth

unread,
Apr 7, 2021, 5:54:02 PM4/7/21
to Slawomir Pryczek, golang-nuts
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/bb6d0bd0-e411-4c93-a1ee-5eec44e1bc48n%40googlegroups.com.

Kevin Chadwick

unread,
Apr 7, 2021, 5:55:03 PM4/7/21
to golang-nuts


The how to code docs need improving for packages but once you initialise a module. You can create folders to hold different packages within the root folder containing the .mod file. I'm not sure modules are not a regression compared to gopath in some respects though? One solution is apparently to use a module like a giant mono repo, aka gopath.  I never used gopath extensively myself.

Slawomir Pryczek

unread,
Apr 7, 2021, 8:14:40 PM4/7/21
to golang-nuts
Thanks for all replies. Actually the docs are good (imo) just these  solutions proposed in docs are a horror.

Inside root folder of the module... so im unable to share packages between projects and code structure gets horrible, because now instead of nicely organized 2 levels of nesting i have 3 levels and i need to repeat name of the project 5 times inside every of 25 different root packages. Maybe for small  apps. If i'm having eg. slab allocator used by both webserver and k-v storage it'd be good to put it outside and not having half of the modules in other apps imported from webserver and other half from k-v storage. It introduces unneeded complexity if package pretends to have something in common with something which is totally unrelated just because it's easier to put it in there. Next i'll have to do v2 of webserver when API of some of packages will change, so the version number won't reflect version number of my app... but changes to some single package in it.

Putting main app dir/files as a parent of general purpose packages is a bad idea. Having tax app to be a parent of decimals package is like having a 3d graph library to be a parent of network I/O package. There is no relation so it should be separated for readability.

>Have you tried go mod edit -replace github.com/foo/bar=/path/to/local/bar ?
I'll have to do hundreds of such edits and then re-edit it each time anything changes (package rename, moving files, etc.)

My point is why this module approach broken the ability to organize code conviniently and logically... If we're in /src/foo and there is /src/bar and we do import "bar" in foo... it should just (what a surprise) import the local bar :D And another issue with this approach is that... should we put this abomination inside git? So really, everyone who downloads my code will have to waste 4 hours of his life replacing imports or he'll be forced to do edits inside C:\Users\slawomir\go or maybe he'll edit in F:\users\michael\my\nice\go\path and put it in repo so i'll have to change it back :D

I know it's easier said than done but we have all this nice things like goroutines, GC, channels, peemption... and everything is so simple. Just to manually babysit package manager when previous model was working? Even having the user go to command line and issue module init for something without remote imports is a step backwards, because it's a waste of time, added complexity and totally unneeded.

Having like tens of pages of "instructions" and blog posts telling users how to configure package manager just to run 10 lines of code if we want to organize it well is a step forward? With GOPATH you did one simple thing and it was working. Just once not 1000 times over and over, for each package or after anything in your dev enviroment changed. So not sure why everyone should be forced to migrate to this cumbersome model when we have nicely organized, self containted projects and the only issue is versioning for the PART of projects which are actually ... libraries, not applications.

>One solution is apparently to use a module like a giant mono repo, aka gopath
Still it requires for this replace and keeping absolute paths everywhere. It's not even possible to put your project on github this way because it won't compile without configuring everything. That's a huge regression because you'll have to copy-paste all shared code inside each individual app folder if you don't want to publish 30 packages as separate modules or put unrelated things together. Each solution is sub-optimal because separation can't just be done right in sane amount of time in this model because PM isn't able to conviniently handle local packages nor initialization nor changes in the packages...

My point is, that it's so inconvinient that you'll organize your code badly just to save time... GOPATH is much better approach for bigger apps and it shouldn't be made obsolete. At least not if the only solution is putting things where they don't belong or setting up proxies to pretend local files are remote and then re-running some command line tools each time you add a line in one of these...

Justin Israel

unread,
Apr 7, 2021, 11:07:09 PM4/7/21
to golang-nuts
On Thursday, April 8, 2021 at 12:14:40 PM UTC+12 Slawomir Pryczek wrote:
Thanks for all replies. Actually the docs are good (imo) just these  solutions proposed in docs are a horror.

Inside root folder of the module... so im unable to share packages between projects and code structure gets horrible, because now instead of nicely organized 2 levels of nesting i have 3 levels and i need to repeat name of the project 5 times inside every of 25 different root packages. Maybe for small  apps. If i'm having eg. slab allocator used by both webserver and k-v storage it'd be good to put it outside and not having half of the modules in other apps imported from webserver and other half from k-v storage. It introduces unneeded complexity if package pretends to have something in common with something which is totally unrelated just because it's easier to put it in there. Next i'll have to do v2 of webserver when API of some of packages will change, so the version number won't reflect version number of my app... but changes to some single package in it.

Putting main app dir/files as a parent of general purpose packages is a bad idea. Having tax app to be a parent of decimals package is like having a 3d graph library to be a parent of network I/O package. There is no relation so it should be separated for readability.

>Have you tried go mod edit -replace github.com/foo/bar=/path/to/local/bar ?
I'll have to do hundreds of such edits and then re-edit it each time anything changes (package rename, moving files, etc.)

My point is why this module approach broken the ability to organize code conviniently and logically... If we're in /src/foo and there is /src/bar and we do import "bar" in foo... it should just (what a surprise) import the local bar :D And another issue with this approach is that... should we put this abomination inside git? So really, everyone who downloads my code will have to waste 4 hours of his life replacing imports or he'll be forced to do edits inside C:\Users\slawomir\go or maybe he'll edit in F:\users\michael\my\nice\go\path and put it in repo so i'll have to change it back :D

I know it's easier said than done but we have all this nice things like goroutines, GC, channels, peemption... and everything is so simple. Just to manually babysit package manager when previous model was working? Even having the user go to command line and issue module init for something without remote imports is a step backwards, because it's a waste of time, added complexity and totally unneeded.

Having like tens of pages of "instructions" and blog posts telling users how to configure package manager just to run 10 lines of code if we want to organize it well is a step forward? With GOPATH you did one simple thing and it was working. Just once not 1000 times over and over, for each package or after anything in your dev enviroment changed. So not sure why everyone should be forced to migrate to this cumbersome model when we have nicely organized, self containted projects and the only issue is versioning for the PART of projects which are actually ... libraries, not applications.

>One solution is apparently to use a module like a giant mono repo, aka gopath
Still it requires for this replace and keeping absolute paths everywhere. It's not even possible to put your project on github this way because it won't compile without configuring everything. That's a huge regression because you'll have to copy-paste all shared code inside each individual app folder if you don't want to publish 30 packages as separate modules or put unrelated things together. Each solution is sub-optimal because separation can't just be done right in sane amount of time in this model because PM isn't able to conviniently handle local packages nor initialization nor changes in the packages...

My point is, that it's so inconvinient that you'll organize your code badly just to save time... GOPATH is much better approach for bigger apps and it shouldn't be made obsolete. At least not if the only solution is putting things where they don't belong or setting up proxies to pretend local files are remote and then re-running some command line tools each time you add a line in one of these...

My take on this is that you appear to be aggressively ranting about modules with assertions about how it does or does not function, before actually discovering what modules truly do or do not do. People are more likely inclined to be helpful if you just present your situation, what you tried, and what you expect. But leave out the bits where it is assumed to be a broken implementation that can not do what you want, that it is poorly conceived, and how frustrated and angry those assumptions makes you feel. Your frustrations are valid, but they are likely based on incomplete or wrong information.

So to me it sounds like there could be a mix of misunderstandings about modules, and maybe some things modules actually don't do, with regards to your expectations. Given ProjectA and ProjectB, sitting in whatever location you prefer on you filesystem, you should be able to use the "replace" directive to make ProjectA use the local ProjectB without the need for pushing any changes to an external source control or installing any kind of local module proxy server.

my_source_location/
    ProjectA/
        go.mod
            "module mydomain.com/group/ProjectA"
            "replace mydomain.com/group/ProjectA => /path/to/my_source_location/ProjectB"
    ProjectB/
        go.mod
            "module mydomain.com/group/ProjectB"

Changes to ProjectB should be immediately available when compiling ProjectA.
Yes you are correct that the go tool does not try to do a kind of local path lookup if your ProjectA has 'import "ProjectB"' and ProjectB happens to be in a directory relative to the directory containing ProjectA. Yes it would have found it under the GOPATH mechanism if the projects lived immediately under your GOPATH, but that is not a flexible approach when it comes time to deploy you ProjectA, and it expects ProjectB dependency to live under a users GOPATH.
The module approach is quite easy when it comes to achieving local development, since your source code stays the same with correct qualified import path strings, and should a developer want to hack on a dependency, then they can just add a "replace" directive to the go.mod. 

Now given a number of packaged within the same module, this should not require any special handling. All packages under a single module will all build locally. If you have a package within a module that is trying to pull from an external source control, then something is wrong in the project structure.

I feel that if you can end up getting to a point where you fully understand the features of Go modules, that you will find them superior to the GOPATH mechanism.

Justin

Nick Keets

unread,
Apr 8, 2021, 6:48:28 AM4/8/21
to Justin Israel, golang-nuts
I think the problem is that this process is inconvenient, not that it is not possible.

Modules work great if you publish everything on GitHub, or something similar. But what if you don't even have a domain for your source code? Sure you can use a fake domain like "foo.example" and then use replace, and then remember to not commit the replace because someone else may have the code in a different location, etc etc. Imagine if it was the other way around:

my_source_location/
    ProjectA/
        go.mod
          module ProjectA
          replace /home/nick/src/ProjectA => mydomain.com/group/ProjectA
    ProjectB/
        go.mod
          module ProjectB
          replace /home/nick/src/ProjectB => mydomain.com/group/ProjectB

It would still be possible to publish your project, you'd just have to use the replace line and remember to not commit it. Would it be fair if people complained about it?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Carla Pfaff

unread,
Apr 8, 2021, 7:09:06 AM4/8/21
to golang-nuts
On Thursday, 8 April 2021 at 12:48:28 UTC+2 nick....@gmail.com wrote:
But what if you don't even have a domain for your source code? Sure you can use a fake domain like "foo.example"

It doesn't have to be a fake domain name, just a module name, e.g. "foo".
 
and then use replace, and then remember to not commit the replace because someone else may have the code in a different location, etc etc. Imagine if it was the other way around:

my_source_location/
    ProjectA/
        go.mod
          module ProjectA
          replace /home/nick/src/ProjectA => mydomain.com/group/ProjectA
    ProjectB/
        go.mod
          module ProjectB
          replace /home/nick/src/ProjectB => mydomain.com/group/ProjectB

If you're only tinkering without publishing you can put the go.mod directly under "my_source_location", then you have your own GOPATH-like environment.

Nick Keets

unread,
Apr 8, 2021, 7:49:51 AM4/8/21
to Carla Pfaff, golang-nuts
On Thu, Apr 8, 2021 at 2:08 PM 'Carla Pfaff' via golang-nuts <golan...@googlegroups.com> wrote:
On Thursday, 8 April 2021 at 12:48:28 UTC+2 nick....@gmail.com wrote:
But what if you don't even have a domain for your source code? Sure you can use a fake domain like "foo.example"

It doesn't have to be a fake domain name, just a module name, e.g. "foo".

Right, I don't actually do that, I just see that mentioned a lot.
 
 
and then use replace, and then remember to not commit the replace because someone else may have the code in a different location, etc etc. Imagine if it was the other way around:

my_source_location/
    ProjectA/
        go.mod
          module ProjectA
          replace /home/nick/src/ProjectA => mydomain.com/group/ProjectA
    ProjectB/
        go.mod
          module ProjectB
          replace /home/nick/src/ProjectB => mydomain.com/group/ProjectB

If you're only tinkering without publishing you can put the go.mod directly under "my_source_location", then you have your own GOPATH-like environment.

In my case, we have an internal git server at work that we just access over ssh. We have a few dependencies between repositories and a few developers working on the same repository.  I'm assuming this is a rare scenario, but it is one use case that I think modules have made the work flow more inconvenient. 

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Axel Wagner

unread,
Apr 8, 2021, 9:18:15 AM4/8/21
to golang-nuts
On Thu, Apr 8, 2021 at 1:49 PM Nick Keets <nick....@gmail.com> wrote:
In my case, we have an internal git server at work that we just access over ssh. We have a few dependencies between repositories and a few developers working on the same repository.  I'm assuming this is a rare scenario, but it is one use case that I think modules have made the work flow more inconvenient.

Perhaps, but you do get proper versioning in return, which I do feel is valuable.
And setting up a module proxy is relatively straight-forward, IMO. You just need a shared NFS/Samba volume, for example. Or, with a little bit more fancy, an HTTP server serving a static directory (and some magic to update it).

It might be worth to document a couple end-to-end workflows for small-scale deployments, I think. i.e. "a 5 person company sharing some private code and wanting full control over their 3rd party dependencies".
 
 

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/57f57bcf-2c13-4a98-936f-8f7f54b4351en%40googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Kevin Chadwick

unread,
Apr 8, 2021, 10:22:56 AM4/8/21
to golang-nuts
> >>One solution is apparently to use a module like a giant mono repo, aka gopath>
Still it requires for this replace

You do not need replace, unless you are amalgamating multiple modules.

You can just create a folder named e.g. library with a .go file; package lib

Then in your other folders with package main, .go files:

You can

import (
lib "{moduleName}"/library
)

Slawomir Pryczek

unread,
Apr 8, 2021, 10:55:10 AM4/8/21
to golang-nuts
Thanks for the help, so i think i get it fully now.

@Nick:  Sure works great if you're making a project with github modules. Having local modules is possible. But so cumbersome people would be occupied with managing files rather than writing code (if you have >20 of them).

@Carla: Actually i think the process is convinient now. Thanks for the suggestion. Actually tried that before but failed as how it works is little misleading because from reading the docs I got an impression that you need to keep the go.mod inside app's main package. While module should be created one level lower, then you can have local packages shared between projects and you're not forced to be bound to your main package for imports.

Not the modules itself but the way of handling the issue or using modules most people are suggesting are broken. The docs give impression i should convert everything to modules while like @Carla said we should just say create /src dir with module called src, put everything there, prefix imports with "src" and if some code is stable/mature enough you could publish it by converting to a "proper", hosted module later.

Not sure why almost everyone is mentioning local proxies, replace or some other complex stuff and documentation is so complex, when you can just do it like that. Was sitting on this module stuff and docs for it for 3 days, probably more than 15h just to realize this is so simple and i was going in totally wrong direction.

Robert Solomon

unread,
Apr 8, 2021, 7:40:57 PM4/8/21
to golang-nuts
I agree w/ your basic premise, that modules are quite painful. 
However, after much trials, tribulations, and posting here, I received the solution that allows me to structure my code as before (and like you, all in ~/go/src).  I only had to edit the import strings to reflect "src/mypackage" instead of "mypackage".
That is, I just had to add "src/" to all of my import statements for my own code.  I am able to leave the directory structure as is.
I also had to set GOBIN

Look at the responses I received under the subject "package <whatever> is not in GOROOT"

You are probably frustrated for the same reason as I, ie, the documentation for module mode is not written for us dummies.  I went over the docs and found them most unhelpful and needlessly complex.  They fall into the category of "understood only if previously understood."

Again, read the responses I received to my most recent thread, and you, too, will be ready to GO. :-)

gonutz

unread,
Apr 9, 2021, 11:38:12 AM4/9/21
to golang-nuts
Justin Isreael said

"Changes to ProjectB should be immediately available when compiling ProjectA."

which is not true when you simply insert a replace in your go.mod file.

My current problem is that I have a main module that uses a library module. I want to debug an issue so I insert a print statement in my main module. That works. But now I want to insert a print statement in the library. How do I do that?

A replace in the go.mod file is of no help here because I still have to specify a require with a concrete version or commit hash for the library. This means I cannot just change the code in the library module, I also have to create a commit and check it in, then go back to my main module and udpate not only the replace but also the require in go.mod, every time I want to simply place a simple, temporary print statement for debugging purposes into the library.

Does anybody have an easy workflow for the common use case?

Carla Pfaff

unread,
Apr 9, 2021, 12:01:34 PM4/9/21
to golang-nuts
On Friday, 9 April 2021 at 17:38:12 UTC+2 gonutz wrote:
A replace in the go.mod file is of no help here because I still have to specify a require with a concrete version or commit hash for the library. This means I cannot just change the code in the library module, I also have to create a commit and check it in, then go back to my main module and udpate not only the replace but also the require in go.mod, every time I want to simply place a simple, temporary print statement for debugging purposes into the library.

Does anybody have an easy workflow for the common use case?

oldCoderException

unread,
Apr 9, 2021, 1:26:45 PM4/9/21
to golang-nuts
I certainly agree with everyone who has been saying that implementing modules can be painful.  Implementing them was initially a multi-week nightmare of sleepless nights for me, and I still sometimes shake my head with their use.  I think that a large part of the problem is that the documentation, which is actually pretty good, is (or was, haven't looked lately) rather bereft of "non-GitHub" and "local, non-domain name" examples.  I also think that when you are in the early development stages of a system when there are many library changes taking place, and those libraries all need to be tagged with version numbers each time they change, it just seems a bit much for such early stage development on a system.  I can definitely see the benefits, especially if your team is large, and I definitely appreciate them with regards to using open source GitHub modules, but for small teams or single developers with libraries that are in the midst of lots of change, it can be challenging.  I didn't see any of the good ideas that I'm seeing in this thread when I changed over, which is unfortunate.  Live and learn.

I work on Linux and ended up writing scripts to modify the import statements in hundreds of source files, and other scripts that somewhat automate the "go install, git add, git commit, git push, git tag, git push tag" sequence needed for one or all modules.  I've also been meaning to look for or write some tool that nicely shows which modules are dependent on which modules, but just haven't had the time.  I know they're in each module's go.mod file, but it would be nice to see some kind of big-picture dependency tree or something.  It would also be nice to have tools that know which modules are affected by a library module change and just rebuild those when needed.

Anyway, it's slowly becoming a part of my standard development practice and is less painful as time goes by.   :)

-Paul

Volker Dobler

unread,
Apr 9, 2021, 1:43:49 PM4/9/21
to golang-nuts
On Friday, 9 April 2021 at 17:38:12 UTC+2 gonutz wrote: 
A replace in the go.mod file is of no help here because I still have to specify a require with a concrete version or commit hash for the library. 

Why do you think so? Replace with your local filesystem path
of the library requires neither.

V.

Wojciech S. Czarnecki

unread,
Apr 9, 2021, 5:34:37 PM4/9/21
to golan...@googlegroups.com
Dnia 2021-04-07, o godz. 14:31:07
Slawomir Pryczek <slawe...@gmail.com> napisał(a):

> Anyone has an idea for a reasonable solution which will allow easy
> refactoring and code organization in packages, in this new model?

Idea is here: https://github.com/golang/go/issues/44347

Whether is it reasonable or not — objectively — I can not tell as I am an author.
Though I'd like to see other's opinion whether proposed solution would work for them.

TC.

--
Wojciech S. Czarnecki
<< ^oo^ >> OHIR-RIPE

roger peppe

unread,
Apr 9, 2021, 7:24:09 PM4/9/21
to gonutz, golang-nuts
You might find that https://github.com/rogpeppe/gohack helps you here - it's designed for this use case.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Justin Israel

unread,
Apr 9, 2021, 7:47:41 PM4/9/21
to gonutz, golang-nuts
Yes I omitted the fact that the "replace" directive implies that there was already a "require" directive that needs replacing. But I still maintain that my original suggestion works. I don't see any requirement that your library be committed or pushed anywhere, or have a real github hosting, for the case of pure local development between a number of separate modules. 

Here is a structure of two module projects, neither of which have any git configuration:

.
├── projectA
│   ├── go.mod
│   └── main.go
└── projectB
    ├── go.mod
    └── lib.go
// projectB/lib.go
package projectB

import "fmt"

func Foo() {
        fmt.Println("ProjectB")
}
// projectB/go.mod
module mydomain.com/projects/projectB
// projectA/main.go
package main

import  "mydomain.com/projects/projectB"

func main() {
        projectB.Foo()
}
// projectA/go.mod
module mydomain.com/projects/projectA

require mydomain.com/projects/projectB v0.0.0
replace mydomain.com/projects/projectB => /tmp/gotesting/projectB

So I didn't have to commit and push my code anywhere and could just use an arbitrary version for the "require", and then replace. Now I can do local development across modules. I guess I am missing the pain point here. 


Does anybody have an easy workflow for the common use case?

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/_BqV6Rk15UA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

Michael Ellis

unread,
Apr 9, 2021, 8:20:54 PM4/9/21
to golang-nuts
FWIW, I completely agree with the sentiment that confusing documentation has created pain and unnecessary difficulty for solo developers.  I try to keep in mind that Go was developed for use by large teams working on million line programs and that I'm lucky to be able to piggyback on the efforts of top-notch talent. 

That being said, here is a recipe that seems to work -- for my purposes at least.  It's really just a restatement of what others have said in this and related threads:

1. Create a directory that will hold your local projects.  I think it best not to use ~/go/src.  My directory is ~/localgo,  I'll use that name in in what follows, though there's nothing special about it.
2. Undefine GOPATH, e.g. unset GOPATH
3.  Initialize a module named for the directory, i.e. cd ~/localgo; go mod init localgo
4. Move your package and cmd project underneath ~/localgo. 
5. When importing local package named "somepkg" use import localgo/somepkg
6. If a package in your local directory is something you've published, you have three choices when importing it:
  • Import it from your published repository,
  • Import from your published repository and use "replace" to force the import to use the localgo copy,
  • Import directly from localgo (as in item 5).
To make this a little more concrete here's a portion of my localgo tree with two packages and two command projects.  Notice that mypkg and myprog do not have go.mod files yet myprog is able to import mypkg and build without error.  Package tbchrom, on the other hand, is already (privately) published and versioned on GitHub.  It's still under development. Having it cloned under localgo allows me to reference it from command tbflash which is not yet published.  I'm using the replace statement in tbflash's go.mod file, i.e.,  replace github.com/Michael-F-Ellis/tbchrom v1.0.0 => /Users/mellis/localgo/tbchrom

localgo
├── go.mod
├── mypkg
│   └── pkg.go
├── myprog
│   └── main.go
├── tbchrom
│   ├── .git
│   ├── .gitignore
│   ├── .vscode
│   ├── go.mod
│   ├── go.sum
│   ├── parser.go
│   ├── parser_test.go
│   ├── rhythm.go
│   ├── rhythm_test.go
│   ├── smf.go
│   └── smf_test.go
└── tbflash
    ├── go.mod
    ├── go.sum
    ├── main.go
    ├── main_test.go
    └── tbflash.json

I like this solution because it's consistent and flexible. It's consistent in that all the go toolchain commands,  vet, build, ... etc., work the same regardless of whether a package or command if version controlled or has a go.mod file.  It's flexible, in large part, because it's consistent. I can start a project with bare Go code and add module support and version control as needed.

Hope someone finds it useful.  If you know of any awful pitfalls, please let me know.

Johann Höchtl

unread,
Apr 20, 2021, 2:33:26 AM4/20/21
to golang-nuts
This sounds like it would warrant a howto go modules blog post. Thank you for sharing your experience.

dk charter

unread,
May 19, 2023, 1:03:01 PM5/19/23
to golang-nuts
I must admit, module management in go is still a torture, I haven't had worst experience yet, I'd spend less time programming my own language, also the type system is still quite primitive and the syntax feels outdated.

Howard C. Shaw III

unread,
May 19, 2023, 3:17:23 PM5/19/23
to golang-nuts
Workspaces make this all much easier for me.

go work

I was going mad trying to get modules to work reasonably until I found that. Now, new directory, go mod init <url>, go work use ., go work sync, go tidy, and everything works reasonably without major headaches.

Howard
Reply all
Reply to author
Forward
0 new messages