golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/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  		"context"                // package context
   129  		"fmt"                    // package fmt
   130  		"golang.org/x/time/rate" // package rate
   131  		"os/exec"                // package exec
   132  	)
   133  
   134  Build tools map package paths onto directories.
   135  The go tool uses the [[https://golang.org/doc/code.html#GOPATH][GOPATH]]
   136  environment variable to find the source files for path `"github.com/user/hello"`
   137  in directory `$GOPATH/src/github.com/user/hello`.
   138  (This situation should be familiar, of course, but it's important to be clear
   139  about the terminology and structure of packages.)
   140  
   141  *Directories.*
   142  The standard library uses like directories `crypto`, `container`, `encoding`,
   143  and `image` to group packages for related protocols and algorithms.
   144  There is no actual relationship among the packages in one of these directories;
   145  a directory just provides a way to arrange the files.
   146  Any package can import any other package provided the import does not create a
   147  cycle.
   148  
   149  Just as types in different packages can have the same name without ambiguity,
   150  packages in different directories can have the same name.
   151  For example,
   152  [[https://golang.org/pkg/runtime/pprof][runtime/pprof]] provides profiling data
   153  in the format expected by the [[https://github.com/google/pprof][pprof]]
   154  profiling tool, while [[https://golang.org/pkg/net/http/pprof][net/http/pprof]]
   155  provides HTTP endpoints to present profiling data in this format.
   156  Client code uses the package path to import the package, so there is no
   157  confusion.
   158  If a source file needs to import both `pprof` packages, it can
   159  [[https://golang.org/ref/spec#Import_declarations][rename]] one or both locally.
   160  When renaming an imported package, the local name should follow the same
   161  guidelines as package names (lower case, no `under_scores` or `mixedCaps`).
   162  
   163  * Bad package names
   164  
   165  Bad package names make code harder to navigate and maintain.
   166  Here are some guidelines for recognizing and fixing bad names.
   167  
   168  *Avoid*meaningless*package*names.*
   169  Packages named `util`, `common`, or `misc` provide clients with no sense of what
   170  the package contains.
   171  This makes it harder for clients to use the package and makes it harder for
   172  maintainers to keep the package focused.
   173  Over time, they accumulate dependencies that can make compilation significantly
   174  and unnecessarily slower, especially in large programs.
   175  And since such package names are generic, they are more likely to collide with
   176  other packages imported by client code, forcing clients to invent names to
   177  distinguish them.
   178  
   179  *Break*up*generic*packages.*
   180  To fix such packages, look for types and functions with common name elements and
   181  pull them into their own package.
   182  For example, if you have
   183  
   184  	package util
   185  	func NewStringSet(...string) map[string]bool {...}
   186  	func SortStringSet(map[string]bool) []string {...}
   187  
   188  then client code looks like
   189  
   190  	set := util.NewStringSet("c", "a", "b")
   191  	fmt.Println(util.SortStringSet(set))
   192  
   193  Pull these functions out of `util` into a new package, choosing a name that fits
   194  the contents:
   195  
   196  	package stringset
   197  	func New(...string) map[string]bool {...}
   198  	func Sort(map[string]bool) []string {...}
   199  
   200  then the client code becomes
   201  
   202  	set := stringset.New("c", "a", "b")
   203  	fmt.Println(stringset.Sort(set))
   204  
   205  Once you've made this change, its easier to see how to improve the new package:
   206  
   207  	package stringset
   208  	type Set map[string]bool
   209  	func New(...string) Set {...}
   210  	func (s Set) Sort() []string {...}
   211  
   212  which yields even simpler client code:
   213  
   214  	set := stringset.New("c", "a", "b")
   215  	fmt.Println(set.Sort())
   216  
   217  The name of the package is a critical piece of its design.
   218  Work to eliminate meaningless package names from your projects.
   219  
   220  *Don't*use*a*single*package*for*all*your*APIs.*
   221  Many well-intentioned programmers put all the interfaces exposed by their
   222  program into a single package named `api`, `types`, or `interfaces`, thinking it
   223  makes it easier to find the entry points to their code base.
   224  This is a mistake.
   225  Such packages suffer from the same problems as those named `util` or `common`,
   226  growing without bound, providing no guidance to users, accumulating
   227  dependencies, and colliding with other imports.
   228  Break them up, perhaps using directories to separate public packages from
   229  implementation.
   230  
   231  *Avoid*unnecessary*package*name*collisions.*
   232  While packages in different directories may have the same name, packages that
   233  are frequently used together should have distinct names.
   234  This reduces confusion and the need for local renaming in client code.
   235  For the same reason, avoid using the same name as popular standard packages like
   236  `io` or `http`.
   237  
   238  * Conclusion
   239  
   240  Package names are central to good naming in Go programs.
   241  Take the time to choose good package names and organize your code well.
   242  This helps clients understand and use your packages and helps maintainers to
   243  grow them gracefully.
   244  
   245  * Further reading
   246  
   247  - [[https://golang.org/doc/effective_go.html][Effective Go]]
   248  - [[https://golang.org/doc/code.html][How to Write Go Code]]
   249  - [[https://blog.golang.org/organizing-go-code][Organizing Go Code (2012 blog post)]]
   250  - [[https://talks.golang.org/2014/organizeio.slide][Organizing Go Code (2014 Google I/O talk)]]