github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/package-names.article (about)

     1  Package names
     2  4 Feb 2015
     3  Tags: package, names, style
     4  
     5  Sameer Ajmani
     6  
     7  * Introduction
     8  
     9  Go code is organized into packages.
    10  Within a package, code can refer to any identifier (name) defined within, while
    11  clients of the package may only reference the package's exported types,
    12  functions, constants, and variables.
    13  Such references always include the package name as a prefix: `foo.Bar` refers to
    14  the exported name `Bar` in the imported package named `foo`.
    15  
    16  Good package names make code better.
    17  A package's name provides context for its contents, making it easier for clients
    18  to understand what the package is for and how to use it.
    19  The name also helps package maintainers determine what does and does not belong
    20  in the package as it evolves.
    21  Well-named packages make it easier to find the code you need.
    22  
    23  Effective Go provides
    24  [[https://golang.org/doc/effective_go.html#names][guidelines]] for naming
    25  packages, types, functions, and variables.
    26  This article expands on that discussion and surveys names found in the standard
    27  library.
    28  It also discusses bad package names and how to fix them.
    29  
    30  * Package names
    31  
    32  Good package names are short and clear.
    33  They are lower case, with no `under_scores` or `mixedCaps`.
    34  They are often simple nouns, such as:
    35  
    36  - `time` (provides functionality for measuring and displaying time)
    37  - `list` (implements a doubly linked list)
    38  - `http` (provides HTTP client and server implementations)
    39  
    40  The style of names typical of another language might not be idiomatic in a Go
    41  program.
    42  Here are two examples of names that might be good style in other languages but
    43  do not fit well in Go:
    44  
    45  - `computeServiceClient`
    46  - `priority_queue`
    47  
    48  A Go package may export several types and functions.
    49  For example, a `compute` package could export a `Client` type with methods for
    50  using the service as well as functions for partitioning a compute task across
    51  several clients.
    52  
    53  *Abbreviate*judiciously.*
    54  Package names may be abbreviated when the abbreviation is familiar to the
    55  programmer.
    56  Widely-used packages often have compressed names:
    57  
    58  - `strconv` (string conversion)
    59  - `syscall` (system call)
    60  - `fmt` (formatted I/O)
    61  
    62  On the other hand, if abbreviating a package name makes it ambiguous or unclear,
    63  don't do it.
    64  
    65  *Don't*steal*good*names*from*the*user.*
    66  Avoid giving a package a name that is commonly used in client code.
    67  For example, the buffered I/O package is called `bufio`, not `buf`, since `buf`
    68  is a good variable name for a buffer.
    69  
    70  * Naming package contents
    71  
    72  A package name and its contents' names are coupled, since client code uses them
    73  together.
    74  When designing a package, take the client's point of view.
    75  
    76  *Avoid*stutter.*
    77  Since client code uses the package name as a prefix when referring to the
    78  package contents, the names for those contents need not repeat the package name.
    79  The HTTP server provided by the `http` package is called `Server`, not
    80  `HTTPServer`.
    81  Client code refers to this type as `http.Server`, so there is no ambiguity.
    82  
    83  *Simplify*function*names.*
    84  When a function in package pkg returns a value of type `pkg.Pkg` (or
    85  `*pkg.Pkg`), the function name can often omit the type name without confusion:
    86  
    87  	start := time.Now()                                  // start is a time.Time
    88  	t, err := time.Parse(time.Kitchen, "6:06PM")         // t is a time.Time
    89          ctx = context.WithTimeout(ctx, 10*time.Millisecond)  // ctx is a context.Context
    90          ip, ok := userip.FromContext(ctx)                    // ip is a net.IP
    91  
    92  A function named `New` in package `pkg` returns a value of type `pkg.Pkg`.
    93  This is a standard entry point for client code using that type:
    94  
    95           q := list.New()  // q is a *list.List
    96  
    97  When a function returns a value of type `pkg.T`, where `T` is not `Pkg`, the
    98  function name may include `T` to make client code easier to understand.
    99  A common situation is a package with multiple New-like functions:
   100  
   101  	d, err := time.ParseDuration("10s")  // d is a time.Duration
   102  	elapsed := time.Since(start)         // elapsed is a time.Duration
   103  	ticker := time.NewTicker(d)          // ticker is a *time.Ticker
   104  	timer := time.NewTimer(d)            // timer is a *time.Timer
   105  
   106  Types in different packages can have the same name, because from the client's
   107  point of view such names are discriminated by the package name.
   108  For example, the standard library includes several types named `Reader`,
   109  including `jpeg.Reader`, `bufio.Reader`, and `csv.Reader`.
   110  Each package name fits with `Reader` to yield a good type name.
   111  
   112  If you cannot come up with a package name that's a meaningful prefix for the
   113  package's contents, the package abstraction boundary may be wrong.
   114  Write code that uses your package as a client would, and restructure your
   115  packages if the result seems poor.
   116  This approach will yield packages that are easier for clients to understand and
   117  for the package developers to maintain.
   118  
   119  * Package paths
   120  
   121  A Go package has both a name and a path.
   122  The package name is specified in the package statement of its source files;
   123  client code uses it as the prefix for the package's exported names.
   124  Client code uses the package path when importing the package.
   125  By convention, the last element of the package path is the package name:
   126  
   127  	import (
   128  		"fmt"                       // package fmt
   129  		"os/exec"                   // package exec
   130  		"golang.org/x/net/context"  // package context
   131  	)
   132  
   133  Build tools map package paths onto directories.
   134  The go tool uses the [[https://golang.org/doc/code.html#GOPATH][GOPATH]]
   135  environment variable to find the source files for path `"github.com/user/hello"`
   136  in directory `$GOPATH/src/github.com/user/hello`.
   137  (This situation should be familiar, of course, but it's important to be clear
   138  about the terminology and structure of packages.)
   139  
   140  *Directories.*
   141  The standard library uses like directories `crypto`, `container`, `encoding`,
   142  and `image` to group packages for related protocols and algorithms.
   143  There is no actual relationship among the packages in one of these directories;
   144  a directory just provides a way to arrange the files.
   145  Any package can import any other package provided the import does not create a
   146  cycle.
   147  
   148  Just as types in different packages can have the same name without ambiguity,
   149  packages in different directories can have the same name.
   150  For example,
   151  [[https://golang.org/pkg/runtime/pprof][runtime/pprof]] provides profiling data
   152  in the format expected by the [[https://code.google.com/p/gperftools][pprof]]
   153  profiling tool, while [[https://golang.org/pkg/net/http/pprof][net/http/pprof]]
   154  provides HTTP endpoints to present profiling data in this format.
   155  Client code uses the package path to import the package, so there is no
   156  confusion.
   157  If a source file needs to import both `pprof` packages, it can
   158  [[https://golang.org/ref/spec#Import_declarations][rename]] one or both locally.
   159  When renaming an imported package, the local name should follow the same
   160  guidelines as package names (lower case, no `under_scores` or `mixedCaps`).
   161  
   162  * Bad package names
   163  
   164  Bad package names make code harder to navigate and maintain.
   165  Here are some guidelines for recognizing and fixing bad names.
   166  
   167  *Avoid*meaningless*package*names.*
   168  Packages named `util`, `common`, or `misc` provide clients with no sense of what
   169  the package contains.
   170  This makes it harder for clients to use the package and makes it harder for
   171  maintainers to keep the package focused.
   172  Over time, they accumulate dependencies that can make compilation significantly
   173  and unnecessarily slower, especially in large programs.
   174  And since such package names are generic, they are more likely to collide with
   175  other packages imported by client code, forcing clients to invent names to
   176  distinguish them.
   177  
   178  *Break*up*generic*packages.*
   179  To fix such packages, look for types and functions with common name elements and
   180  pull them into their own package.
   181  For example, if you have
   182  
   183  	package util
   184  	func NewStringSet(...string) map[string]bool {...}
   185  	func SortStringSet(map[string]bool) []string {...}
   186  
   187  then client code looks like
   188  
   189  	set := util.NewStringSet("c", "a", "b")
   190  	fmt.Println(util.SortStringSet(set))
   191  
   192  Pull these functions out of `util` into a new package, choosing a name that fits
   193  the contents:
   194  
   195  	package stringset
   196  	func New(...string) map[string]bool {...}
   197  	func Sort(map[string]bool) []string {...}
   198  
   199  then the client code becomes
   200  
   201  	set := stringset.New("c", "a", "b")
   202  	fmt.Println(stringset.Sort(set))
   203  
   204  Once you've made this change, its easier to see how to improve the new package:
   205  
   206  	package stringset
   207  	type Set map[string]bool
   208  	func New(...string) Set {...}
   209  	func (s Set) Sort() []string {...}
   210  
   211  which yields even simpler client code:
   212  
   213  	set := stringset.New("c", "a", "b")
   214  	fmt.Println(set.Sort())
   215  
   216  The name of the package is a critical piece of its design.
   217  Work to eliminate meaningless package names from your projects.
   218  
   219  *Don't*use*a*single*package*for*all*your*APIs.*
   220  Many well-intentioned programmers put all the interfaces exposed by their
   221  program into a single package named `api`, `types`, or `interfaces`, thinking it
   222  makes it easier to find the entry points to their code base.
   223  This is a mistake.
   224  Such packages suffer from the same problems as those named `util` or `common`,
   225  growing without bound, providing no guidance to users, accumulating
   226  dependencies, and colliding with other imports.
   227  Break them up, perhaps using directories to separate public packages from
   228  implementation.
   229  
   230  *Avoid*unnecessary*package*name*collisions.*
   231  While packages in different directories may have the same name, packages that
   232  are frequently used together should have distinct names.
   233  This reduces confusion and the need for local renaming in client code.
   234  For the same reason, avoid using the same name as popular standard packages like
   235  `io` or `http`.
   236  
   237  * Conclusion
   238  
   239  Package names are central to good naming in Go programs.
   240  Take the time to choose good package names and organize your code well.
   241  This helps clients understand and use your packages and helps maintainers to
   242  grow them gracefully.
   243  
   244  * Further reading
   245  
   246  - [[https://golang.org/doc/effective_go.html][Effective Go]]
   247  - [[https://golang.org/doc/code.html][How to Write Go Code]]
   248  - [[https://blog.golang.org/organizing-go-code][Organizing Go Code (2012 blog post)]]
   249  - [[https://talks.golang.org/2014/organizeio.slide][Organizing Go Code (2014 Google I/O talk)]]