Repository: go
Issue: x/build/internal/gophers: improve internal package design
Labels: Documentation,Builders,NeedsFix

## Problem

> _Total mess, but a functional mess, and a starting point for the future._
> — Commit [`891b12dc`](https://github.com/golang/build/commit/891b12dcbdd4ee448d573a78681b2e785daa71ca)

The `gophers` package is currently hard to use and hard to modify. It's not easy to read its [documentation](https://godoc.org/golang.org/x/build/internal/gophers) and start using it:

```Go
// (no documentation)
func GetPerson(id string) *Person
```

I've used and modified it multiple times, and each time, I had to read its internal code to figure out:

- what kind of value can "id" be?
- what is its exact format?
    - is leading '@' required for GH usernames? optional? unneeded?
- is it case sensitive or not?
- in what order/what type of information to add to the `addPerson(...)` lines?

Despite being an internal package, `gophers` is an important package providing value to 4 other packages, and potentially becoming used in more places. It's no longer just for computing stats, but also for tracking package owners and assigning reviews. Being internal means we can change it easily (even break the API if needed) if we come to agreement on an improved design.

## Proposed Solution

I think it can be made easier to use by:

-	documenting it (so its [godoc](https://godoc.org/golang.org/x/build/internal/gophers) is all you need to use it, no need to read code)

	For example:

	```Go
	// GetPerson looks up a person by id and returns one if found, or nil otherwise.
	//
	// The id is case insensitive, and may be one of:
	// 	- full name ("Brad Fitzpatrick")
	// 	- GitHub username ("@bradfitz")
	// 	- Gerrit <account ID>@<instance ID> ("5065@62eb7196-b449-3ce5-99f1-c037f21e1705")
	// 	- email ("bradfitz@golang.org")
	func GetPerson(id string) *Person
	```

	@bradfitz If you prefer not to be used as an example, let me know, and we can use someone else (I'm happy to volunteer) or use a generic name. But I think a well known real user makes for a better example.

Made easier to modify by:

-	making its internal `addPerson` logic more explicit rather than implicit

	For example, instead of what we have now:

	```Go
	addPerson("Filippo Valsorda", "", "6195@62eb7196-b449-3ce5-99f1-c037f21e1705")
	addPerson("Filippo Valsorda", "filippo@cloudflare.com")
	addPerson("Filippo Valsorda", "filippo@golang.org", "11715@62eb7196-b449-3ce5-99f1-c037f21e1705")
	addPerson("Filippo Valsorda", "filippo@golang.org", "hi@filippo.io", "@FiloSottile")

	// what kind of changes should be done to modify the end result Person struct?
	```

	It could be something more explicit, along the lines of:

	```Go
	add(Person{
		Name:      "Filippo Valsorda",
		GitHub:    "FiloSottile",
		Gerrit:    "filippo@golang.org",
		GerritIDs: []int{6195, 11715}, // Gerrit account IDs.
		GitEmails: []string{
			"filippo@golang.org",
			"filippo@cloudflare.com",
			"hi@filippo.io",
		},
		gomote: "valsorda", // Gomote user.
	})
	```

	The intention is to make it easy for people to manually add and modify their entries, with predictable results, while still being able to to use code generation (ala `gopherstats -mode=find-gerrit-gophers`) to add missing entries.

This is just a quick draft proposal, not necessarily the final API design. If the general direction is well received but there are concerns or improvement suggestions, I'm happy to flesh it out and incorporate feedback. I wouldn't send a CL until I have a solid design.

/cc @bradfitz @andybons