Is there a standard practice for splitting packages into modular components? - go

I'm working on a library with multiple layers of functionality. I want developers to be able to import only the parts they need, ie mylib-core, mylib-feature1, mylib-feature2, etc. Each lives in its own git repo. I'd also like to provide a simple mylib package which exposes a default set of functionality which is useful for developers new to the library. See d3.js version 4+ for something very similar to what I'm trying to accomplish.
The problems I've run into are
Apparently you can't share a package name between packages. This is a problem because it would be nice to import all the desired repos and then simply have everything available under the mylib name.
I don't see an obvious way to re-export functionality, in order to build the default mylib package.
Are there good solutions or a more idomatic go way to accomplish what I'm shooting for?

Answering your question, there is no idiomatic way of doing what you want. It is common in JavaScript to import a library and export its members without interference. This is not the case in Golang.
I advise you to host your whole library under a single repo, and split the functionality to packages. The Go compiler will only compile and use the imported packages.
And a tip for the future, Go is very different than almost any other language you previously know 😅

Related

How to annotate symbols that they are shared among other projects?

Suppose I have a Go project which act as shared library in another Go project. How do I markup Go symbols (consts, structs, vars) that they are used outside this project?
I guess the underlying problem is that I have a hard time knowing which code uses said symbols.
Please note: This is not about semantic versioning, of which I am very well aware and which I use. I know Semver can help to identify breaking changes.
Instead, this is about finding out if I actually break one of my own projects (compared to: This symbol should be unexported or used outside the package). I am thinking of some sort of annotation which don't exist in Go.
As an aside, IntelliJ doesn't know either and marks those symbols as "Unnecessarily exported". Maybe an IntelliJ-centric solution could suffice.
To illustrate my problem:
package sharedlib
import "time"
// MyFavoriteTimeFormat is a blablabla...
const MyFavoriteTimeFormat = Time.RFC3339
package dependingproject
import "github.com/thething/sharedlib"
import "time"
func convertToString(timestamp time.Time) string {
return timestamp.Format(sharedlib.MyFavoriteTimeFormat)
}
When I happily rename MyFavoriteTimeFormate and release it, the code will break in the depending project when it updates the dependency.
Don't export anything until some other package needs it. If another package needs something, then do export, and then you'll know that if something is exported, it is because it is used outside of the package. And do not do breaking changes on exported identifiers. If you really must, then increment major version. Using go modules, that won't break existing other packages, they will continue to use the old version.
If your module is broken down into multiple packages (because it is "big"), and you wish to export something solely for the other packages of your module, then use the internal package concept, so it will still be "unexported" (unimportable) to other modules. For details, see Can I develop a go package in multiple source directories?

Import ReactiveCocoa, or PromiseKit, or BrightFutures as sources?

I have an OSX project (xcode plugin) and I want to use the ReactiveCocoa paradigms in it (PromiseKit andBrightFutures` are the other implementations of the same paradigms so I need to import at least one from these 3 frameworks/libraries).
The problem is it seems impossible to import them as compiled frameworks into my project because it is plugin. In my project I used dispatch_async and dispatch_after functions only but their nested blocks look awful.
The only solution I found is import one from these frameworks as sources but I don't know how to detach their code. So could anybody help with this trouble? Or maybe are there any other similar libraries which are already represented as source files only?
Short Answer:
Use a dependency manager like Cocoapods or Carthage.
Longer Answer: You can do it manually, but even if you don't want to use any of those, you can look at the .podspec file and see how it's supposed to be used. For example BrightFutures.podspec says:
s.source_files = 'BrightFutures/*.swift'
s.dependency 'Result', '0.6.0-beta.6'
That means that you need to import all the .swift files inside the BrightFutures folder, and that it won't work unless you also import the files from another project called Result.
But please, just let the tools do that for you. You'll be happier. :)

Handle dependencies in Go

In Go, if you reference another package, e.g. something on GitHub, then Go always gets the latest version from the master branch. While this is great for development, I guess it's a problem in production: This way a build is not reproducible.
So, what is the correct way in Go to fix a version of a dependency, and how to handle this efficiently?
A friend pointed me to godep, and this seems fine, but I wanted to know what alternatives are there, and what's good / bad about godep?
Update 2018 with Go 1.11
Dependencies should now be referenced with modules (derived from the vgo project):
Go 1.11 adds preliminary support for a new concept called “modules,” an alternative to GOPATH with integrated support for versioning and package distribution.
Using modules, developers are no longer confined to working inside GOPATH, version dependency information is explicit yet lightweight, and builds are more reliable and reproducible.
See Defining a module. (and the original design proposal)
Update June 2015: first support for vendoring is making its way in Go 1.5!
See c/10923/:
When GO15VENDOREXPERIMENT=1 is in the environment, this CL changes the resolution of import paths according to the Go 1.5 vendor proposal:
If there is a source directory d/vendor, then, when compiling a source file within the subtree rooted at d, import "p" is interpreted as import "d/vendor/p" if that exists.
When there are multiple possible resolutions, the most specific (longest) path wins.
The short form must always be used: no import path can contain “/vendor/” explicitly.
Import comments are ignored in vendored packages.
Update March 2015: the go team is thinking about defining a go dependency management system integrated to the language: the debate is in this thread.
We think it’s time to start addressing the dependency & vendoring issue, especially before too many conflicting tools arise and fragment best practices in the Go ecosystem, unnecessarily complicating tooling. It would be nice if the community could converge on a standard way to vendor.
Our proposal is that the Go project,
officially recommends vendoring into an “internal” directory with import rewriting (not GOPATH modifications) as the canonical way to pin dependencies.
defines a common config file format for dependencies & vendoring
makes no code changes to cmd/go in Go 1.5. External tools such as “godep” or “nut” will implement 1) and 2). We can reevaluate including such a tool in Go 1.6+.
One possible downside of godep is that you can no longer use "go build" or "go test" directly.
You need to precede those commands with godep (or type godep save).
An alternative is glide, which remains compatible with classic go commands.
Manage project-specific GOPATHs
Ease dependency management
Support versioning packages
Support aliasing packages (e.g. for working with github forks)
Remove the need for "vendoring" or munging import statements
Work with all of the go tools
More generally, the article "Know your guarantees, Go edition" is interesting:
It’s also a deliberate choice, where the Go authors chose not to implement a feature when they felt that the trade-offs were no good.
One low-level reason they made this choice is to avoid slow compilation and bloated binaries (which are two sides of the same coin).
Remember, packages depend on other packages. So Foo might depend on Bar 2.1. Foo might also depend on Baz which in turn depends on Bar 1.9, and on down the tree. So that would mean compiling and linking several copies of nearly identical code.
Depending on several versions of the same package also means knowing which version one is calling, whereby the dependency mess seeps into your source code.
Which leads us to the high-level reasoning behind the Go platform punting on this feature: they did not have a logical solution they considered acceptable. It’s not that they don’t understand the problem; it’s that, at the moment, there is not a solution they like. So they choose no feature over over a regressive one.
You handle dependencies like you do handle dependencies in other languages too: You vendor. For Go there is no Nexus which does the vendoring so most just copy external libraries into a "vendor" folder, there are tools helping here. Personally I found all this "fix version" panic a bit exaggerated as it works pretty well without.
You might wanna take a look at http://labix.org/gopkg.in and search golang-nuts for dependency management. I think there is even a whole mailing list devoted to this.

How to create an extension for Thunderbird/Lightning

I had to create an extension for contacts import into Thunderbird. This part is done, now I need to import tasks. But tasks/calendar are not handled by default in thunderbird, so I need Lightning. Here is my problem. I have no idea if I can detect an other extension and use some of its features.
Easiest way to detect Lightning is checking whether its interfaces are defined, e.g.:
if ("calICalendar" in Components.interfaces)
alert("Lightning is installed!");
Using its features is a different thing - depends on what you are trying to do. For most things importing Lightning's modules and using them should do:
Components.utils.import("resource://calendar/modules/calUtils.jsm");
alert(cal.getCalendarManager().getCalendars());
I don't think it is properly documented however, you will have to look at the source code.

Tracing source to binary

I'm trying to understand the way a particular package fits into a project I'm working on. I believe only a portion of this package actually makes it into the binary of the project, and I need to find out exactly which parts. Library functions from this package are called from many other places (i.e. several other packages depend on it).
I plan to build the project and distribute it. Is the only way to determine which source->binary files I'll distribute by looking at all of the headers in my dependent packages? Or is there a more clever way to approach this?
Thanks in advance,
You haven't given us much information to go on, but here's a method that will work: remove parts of the package and see if the project will still compile.
Use nm to unpack a static lib. This will list all the files and methods included in the lib.
You could also try using strings.
This displays strings that are defined in the binary.
Look through your source and see if the strings you define are in the library.
Something like gprof could also be used to see which methods are called by your executable.

Resources