Go Language Modularization: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(169 intermediate revisions by the same user not shown)
Line 1: Line 1:
=External=
=Internal=
=Internal=
* [[Go_Language#Modularization|Go Language]]
* [[Go_Language#Modularization|Go Language]]
=Overview=
=Overview=
A standard organization of the files that are part of a project makes easier to share code with other people who also use the same standard. Go [[#Workspace|workspaces]] encourage such a standard.
Go modularization builds upon the concepts of package and module. [[Go_Packages#Overview|Packages]] provide a [[Go_Packages#Packages_as_Namespaces|namespace]] for their members, and they are a way to [[Go_Packages#Packages_as_Encapsulation_Mechanism|encapsulate]] code, hide implementation details and only expose features, such as [[Go_Language#Variables|variables]], [[Go_Functions|functions]] or [[Go_Language#Type|type]] definitions that are meant to be publicly consumed. Packages can be published as part of [[Go_Modules#Overview|modules]]. Modules have been introduced in Go 1.11.
 
=<span id='Workspace'></span>Workspaces=
The standard workspace layout is:
<font size=-2>
.
├─ src
├─ pkg
└─ bin
</font>
 
This layout is recommended, but not enforced.
 
A workspace may contain multiple [[#Project|projects]].
 
<font color=darkkhaki>Define the relationship between workspace and the <code>[[Go Development and Execution Environment#GOPATH|GOPATH]]</code> variable.</font>


=<span id='Project'></span>Project=
=Packages=
{{Internal|Go Packages#Overview|Packages}}
=Modules=
{{Internal|Go Modules#Overview|Modules}}
==Module-Aware or <tt>GOPATH</tt> Mode==
{{External|https://go.dev/ref/mod#mod-commands}}
The compiler must locate packages on the local file system every time it handles an [[Go_Packages#Import_Statement|<code>import</code> statement]].


=<span id='Package'></span>Packages=
The [[Go_Tool#Overview|<tt>go</tt> tool]] has two modes of resolving package dependencies: '''module-aware mode''' or '''GOPATH mode'''.  
A package is a group of related source files. A package can be imported by other packages. Always, there must be one package called <code>[[#main|main]]</code>, which produces an executable as result of its compilation. Other packages do not produce executables as result of their compilation.  


<font color=darkkhaki>Must the package live in a directory with the same name?</font>
In module-aware mode, the <code>go</code> commands use <code>[[Go_Modules#go.mod|go.mod]]</code> files to find versioned dependencies and typically load packages out of the [[Go_Modules#Module_Cache|module cache]], downloading modules if they are missing. As of Go 1.16, the module-aware mode is enabled by default, regardless of whether <code>[[Go_Modules#go.mod|go.mod]]</code> is present or not. The behavior can be controlled with the <code>[[Go_Environment_Variables#GO111MODULE|GO111MODULE]]</code> environment variable.


In GOPATH mode, <code>go</code> commands use the value of the <code>[[Go_Environment_Variables#GOPATH|GOPATH]]</code> environment variable and vendor directories to resolve packages.


==<span id='Idiomatic_Package_Naming_Conventions'></span>Idiomatic Package Conventions==
Also see: {{Internal|GoLand#Module-Aware_or_GOPATH_Mode|GoLand Module-Aware or <tt>GOPATH</tt> Mode}}{{Internal|Go_Environment_Variables#GOPATH|<tt>GOPATH</tt>}}
Package names are generally given lowercase, single-word names. They should be short, concise and evocative, and it should provide context for their contents.
=Project=
{{Internal|Go Project|Project}}


Package-exported names start with an uppercase character.
=Repository=
A Go repository typically contains only one [[Go Modules|module]], located in the root of the repository. Repository may contain more than one module.


The contents of a package should be consistent with the name. If you start noticing that a package includes extra logic that has no relationship to the package name, consider exporting it as a separate one, or use a more descriptive package name.
=Packages, Modules, Projects and Repositories=


Every package should have a [[Go_Language#Comments|comment]] describing its contents.
Designing your [[Go_Project#Overview|project]], to live in its own repository and host a single module in its root directory will help keep maintenance simpler, particularly over time as you publish new versions.  


Also see: {{Internal|Go_Style#Naming|Go Style}}
It is possible to maintain more than one module in a project and repository <font color=darkkhaki>TODO: https://go.dev/doc/modules/managing-source#multiple-module-source</font>.


==Declaring Packages==
=<span id='Standard_library'></span>Standard Library=
===<span id='main'></span>The <tt>main</tt> Package===
Go comes with a set of over 100 "built-in" packages, which are available as part of the locally installed Go development environment.
The <code>main</code> package produces an executable as result of its compilation. The <code>main</code> package must have a function called <code>main()</code>, which is where the code execution starts. For more details see: {{Internal|Go_Functions#main.28.29|<tt>main()</tt>}}


The name of the source code file that declares the <code>main()</code> function does not matter. The following code, declared in a <code>blue.go</code> source file, placed in any directory, not necessarily in a <code>main</code> directory, produces an executable named <code>blue</code>:
Standard library package documentation is available online here: {{External|https://pkg.go.dev/std}}
<syntaxhighlight lang='go'>
package main


import "fmt"
The standard library is a good source of code examples, comments and [[Go_Style#Overview|style]] guidance.
 
func main() {
  fmt.Printf("hello\n")
}
</syntaxhighlight>
<syntaxhighlight lang='bash'>
go build ./blue.go
./blue
hello
</syntaxhighlight>
 
==Importing Packages==
 
When a package is imported during compilation, the compiler searches directories specified by the <code>[[Go_Development_and_Execution_Environment#GOROOT|GOROOT]]</code> and <code>[[Go_Development_and_Execution_Environment#GOPATH|GOPATH]]</code> environment variables.
===<tt>import</tt> Keyword===
The <code>import</code> is a [[Go_Language#import_keyword|keyword]] use to access other packages.
<syntaxhighlight lang='go'>
import "fmt"
</syntaxhighlight>
<syntaxhighlight lang='go'>
import (
"bufio"
"fmt"
"os"
"strings"
)
</syntaxhighlight>
 
==Relationship between Source Code Files and Packages==
<font color=darkkhaki>TODO: how do we add source code files to package? Is it a flat space? It is a hierarchy? What kind of names should the files use?</font>
 
==<span id='Standard_Library'></span>Standard library==
Go comes with a set of "built-in" packages, which come with the Go development environment.
 
The content of the Standard library is available here: https://pkg.go.dev/std
 
The standard library is a good source of code examples, comments and [[Go_Style#Overview|style]].


Standard library packages:
Standard library packages:
:::{|class="wikitable" style="text-align: left;"
:::{|class="wikitable" style="text-align: left;"
| <font face='menlo' size='-2'><span id='archive'></span>[[Go Package archive|archive]]</font> || <font face='menlo' size='-2'><span id='atomic'></span>[[go Package atomic|atomic]]</font>  || <font face='menlo' size='-2'><span id='bytes'></span>[[go Package bytes|bytes]]</font>  || <font face='menlo' size='-2'><span id='container'></span>[[go Package container|container]]</font> || <font face='menlo' size='-2'><span id='database'></span>[[go Package database|database]]</font>  || <font face='menlo' size='-2'><span id='encoding'></span>[[go Package encoding|encoding]]</font>  || <font face='menlo' size='-2'><span id='errors'></span>[[Go Package errors|errors]]</font>  
| <font face='menlo' size='-2'><span id='archive'></span>[[Go Package archive|archive]]</font> || <font face='menlo' size='-2'><span id='atomic'></span>[[go Package atomic|atomic]]</font>  || <font face='menlo' size='-2'><span id='bytes'></span>[[go Package bytes|bytes]]</font>  || <font face='menlo' size='-2'><span id='bufio'></span>[[Go_Package_bufio#Overview|bufio]]</font> || <font face='menlo' size='-2'><span id='container'></span>[[go Package container|container]]</font>  || <font face='menlo' size='-2'><span id='context'></span>[[go Package context|context]]</font>  || <font face='menlo' size='-2'><span id='database'></span>[[go Package database|database]]</font>  
|-
|-
| <font face='menlo' size='-2'><span id='flag'></span>[[go Package flag|flag]]</font> || <font face='menlo' size='-2'><span id='fmt'></span>[[go Package fmt|fmt]]</font> || <font face='menlo' size='-2'><span id='io'></span>[[go Package io|io]]</font> || <font face='menlo' size='-2'><span id='ioutil'></span>[[Go Package ioutil|ioutil]] || <font face='menlo' size='-2'><span id='json'></span><span id='encoding_json'></span>[[Go Package encoding/json|encoding/json]] || <font face='menlo' size='-2'><span id='hash'></span>[[go Package hash|hash]]</font>  || <font face='menlo' size='-2'><span id='log'></span>[[go Package log|log]]</font>  
|   <font face='menlo' size='-2'><span id='encoding'></span>[[go Package encoding|encoding]]</font>   || <font face='menlo' size='-2'><span id='json'></span><span id='encoding_json'></span>[[Go Package encoding/json|encoding/json]]  || <font face='menlo' size='-2'><span id='errors'></span>[[Go_Language_Error_Handling#The_errors_Package|errors]]</font> || <font face='menlo' size='-2'><span id='filepath'></span>[[File_Paths_and_Names_in_Go#filepath|filepath]]</font> || <font face='menlo' size='-2'><span id='flag'></span>[[go Package flag|flag]]</font> || <font face='menlo' size='-2'><span id='fmt'></span>[[go Package fmt|fmt]]</font>  || <font face='menlo' size='-2'><span id='io'></span>[[go Package io|io]]</font>
|-
|-
| <font face='menlo' size='-2'><span id='math'></span>[[go Package math|math]]</font> || <font face='menlo' size='-2'><span id='net'></span>[[Go Package net|net]]  || <font face='menlo' size='-2'><span id='os'></span>[[Go Package os|os]]</font> || <font face='menlo' size='-2'><span id='path'></span>[[go Package path|path]]</font> || <font face='menlo' size='-2'><span id='reflect'></span>[[Go Package reflect|reflect]]</font>  || <font face='menlo' size='-2'><span id='regexp'></span> [[go Package regexp|regexp]]</font> || <font face='menlo' size='-2'><span id='runtime'></span>[[go Package runtime|runtime]]</font>  
| <font face='menlo' size='-2'><span id='ioutil'></span>[[Go Package ioutil|ioutil]] || <font face='menlo' size='-2'><span id='hash'></span>[[go Package hash|hash]]</font> || <font face='menlo' size='-2'><span id='html'></span>[[go Package html|html]]</font> || <font face='menlo' size='-2'><span id='html_template'></span>[[go Package html/template|html/template]]</font> || <font face='menlo' size='-2'><span id='log'></span>[[go Package log|log]]</font>  || <font face='menlo' size='-2'><span id='maps'></span>[[go Package maps|maps]]</font> || <font face='menlo' size='-2'><span id='math'></span>[[go Package math|math]]</font>  
|-
|-
| <font face='menlo' size='-2'><span id='slices'></span>[[Go Package slices|slices]]</font> || <font face='menlo' size='-2'><span id='sort'></span>[[Go Package sort|sort]]</font>  || <font face='menlo' size='-2'><span id='strings'></span>[[go Package strings|strings]]</font>  || <font face='menlo' size='-2'><span id='strconv'></span>[[Go Package strconv|strconv]]</font>  || <font face='menlo' size='-2'><span id='sync'></span>[[Go Package sync|sync]]</font> || <font face='menlo' size='-2'><span id='text-template'></span>[[go Package text/template|text/template]]</font>  || <font face='menlo' size='-2'><span id='time'></span>[[Go Package time|time]]</font>  
| <font face='menlo' size='-2'><span id='net'></span>[[Go Package net|net]] || <font face='menlo' size='-2'><span id='net_http'></span>[[Go Package net/http|net/http]]   || <font face='menlo' size='-2'><span id='net_url'></span>[[Go Package net/url|net/url]]   || <font face='menlo' size='-2'><span id='os'></span>[[Go Package os|os]]</font>  || <font face='menlo' size='-2'><span id='path'></span>[[File_Paths_and_Names_in_Go#path|path]]</font> || <font face='menlo' size='-2'><span id='rand'></span>[[Go Package rand|rand]]</font>  || <font face='menlo' size='-2'><span id='reflect'></span>[[Go Package reflect|reflect]]</font>  
|-
|-
| <font face='menlo' size='-2'><span id='unicode'></span>[[Go Package unicode|unicode]] ||   ||  ||   ||   ||   ||   
| <font face='menlo' size='-2'><span id='regexp'></span> [[go Package regexp|regexp]]</font>  || <font face='menlo' size='-2'><span id='runtime'></span>[[go Package runtime|runtime]]</font>  || <font face='menlo' size='-2'><span id='runtime_debug'></span>[[go Package runtime/debug|runtime/debug]]</font>  || <font face='menlo' size='-2'><span id='slices'></span>[[Go Package slices|slices]]</font>  ||  <font face='menlo' size='-2'><span id='slog'></span>[[Go_Package_slog|slog]]</font> ||  <font face='menlo' size='-2'><span id='sort'></span>[[Go Package sort|sort]]</font>  || <font face='menlo' size='-2'><span id='strings'></span>[[go Package strings|strings]]</font> 
|-
| <font face='menlo' size='-2'><span id='strconv'></span>[[Go Package strconv|strconv]]</font>   || <font face='menlo' size='-2'><span id='sync'></span>[[Go Package sync|sync]]</font>  || <font face='menlo' size='-2'><span id='text-tabwriter'></span>[[go Package text/tabwriter|text/tabwriter]]</font> || <font face='menlo' size='-2'><span id='text-template'></span>[[go Package text/template|text/template]]</font>  || <font face='menlo' size='-2'><span id='testing'></span>[[Go Package testing|testing]]  || <font face='menlo' size='-2'><span id='time'></span>[[Go Package time|time]]</font> || <font face='menlo' size='-2'><span id='unicode'></span>[[Go Package unicode|unicode]]  
|-
|-
|}
|}


=<span id='Dependency'></span>Dependencies=
=<tt>pkg.go.dev</tt>=
=Vendoring=
The place to look for published third-party packages is {{External|https://pkg.go.dev}}
"Vendoring" is the act of making a local copy of a third party package your project depends on. This copy is traditionally placed inside each project and then saved in the project repository.


=<span id='Workspaces'></span>Workspace=
<font color=darkkhaki>This section needs refactoring after reading:
* Tutorial: Getting started with multi-module workspaces https://go.dev/doc/tutorial/workspaces
* Get familiar with workspaces https://go.dev/blog/get-familiar-with-workspaces
</font>


Vendoring is using local copies of external dependencies to satisfy imports of those dependencies.  
The workspace is a concept introduced in Go 1.18. A workspace allows organizing the code for a project that has several [[Go_Modules#Overview|modules]] which share a common list of dependencies. The workspace maintains metadata, especially dependency metadata, in a file called <code>go.work</code>. The dependencies declared in this file can span modules and anything declared in <code>go.work</code> will override dependencies in the modules's <code>go.mod</code>. The packages and modules maintained in a workspace are managed with the [[Go_Tool#Overview|<code>go</code> tool]].


For a directory structure referred by <tt>[[Go Concepts - Runtime#GOPATH|GOPATH]]</tt>, code below a directory named "vendor" is importable only by code in the directory tree rooted at the parent of "vendor", and only using an import path that omits the prefix up to and including the vendor element.  
A workspace may contain multiple [[#Project|projects]].


Code in vendor directories deeper in the source tree shadows code in higher directories. Within the subtree rooted at <tt>foo</tt>, an import
The standard workspace layout is:
of "<tt>crash/bang</tt>" resolves to "<tt>foo/vendor/crash/bang</tt>", not the top-level "<tt>crash/bang</tt>". Code in vendor directories is not subject to import path checking.
<font size=-2>
 
. <font color=teal>← GOPATH should point to this directory, it contains src, pkg and bin</font>
When 'go get' checks out or updates a git repository, it now also updates submodules.
 
├─ src
Vendor directories do not affect the placement of new repositories being checked out for the first time by 'go get': those are always
│  ├─ a  
placed in the main <tt>GOPATH</tt>, never in a vendor subtree.
│  │  └─ b
 
│  │    └─color  <font color=teal># "color" package directory, with the "a/b/color" import path</font>
=Export=
│  │        ├─ colors.go
 
│  │        ├─ aux.go
<span id='Encapsulation'></span>The functions and variable that start with a capital letter in a package get '''exported''': somebody who imports the package can access the exported names, but not the "private" names, which start with lower case letter. "Hidden" names is also used in this situation. This is how '''encapsulation''' is implemented for packages.
│  │        └─ ...  
 
│  │
In the following example:
│  ├─ weight  <font color=teal># "weight" package directory, with the "weight" import path</font>
 
│  │  ├─ weights.go
<syntaxhighlight lang='go'>
│  │  ├─ aux.go
package colors
│  │  └─ ...  
 
│  │
var color string = "blue"
│  ├─ novaordis.com
 
│  │  └─ tools
func GetColor() {
│  │      └─ hammer <font color=teal># "hammer" package directory, with the "novaordis.com/tools/hammer" import path</font>
  return color
│  │          └─ ...  
}
│  │
</syntaxhighlight>
│  └─ github.com
 
│      └─ blue-org
the <code>color</code> variable is private to the package, but it can be accessed with the public <code>GetColor()</code> function.
│          └─ tools
 
│              └─ wrench <font color=teal># "wrench" package directory, with the "github.com/blue-org/tools/wrench" import path</font>
=<span id='Module'></span>Modules=
│                  ├─  .git
 
│                  └─ ...  
<font color=darkkhaki>Explain <code>go.mod</code></font>
 
├─ pkg
=Package as Namespace=
│  └─ darwin_amd64
 
│      ├─ weights.go
Each package defines a namespace for its [[Go_Language#Identifiers_.28Names.29|identifiers]], which include variables, types (structs, interfaces), functions.
│      ├─ a/b/color.a
 
│      ├─ novaordis.com/tools/hammer.a
=Package Initializer=
│      └─ github.com/bue-org/tools/wrench.a
 
└─ bin
=TO DEPLETE=
</font>
 
==Content==
<font color=darkkhaki>
===<tt>src</tt>===
==External==
The <code>src</code> subdirectory holds source code. Each package resides in a directory whose name relative to <code>${GOPATH}/src</code> represents the package's [[Go_Packages#Import_Path|import path]].  
 
* Language Specification - Packages: https://golang.org/ref/spec#Packages
 
==Internal==
* [[Go Keyword import|<tt>import</tt> keyword]]
 
 
==Overview==
 
A ''package'' is a unit of compiled code and a namespace: it consists in one or more source files that declare [[Go Concepts - Lexical Structure#Constants|constants]], [[Go Concepts - Lexical Structure#Variables|variables]], [[Go Concepts - The Type System#Type_Definition|types]] and [[Go Concepts - Functions#Function_Definition|functions]] belonging to the package and which are accessible in all files of the same package. Packages are Go's way of organizing and reusing code, according to the principle [[DRY|Don't Repeat Yourself]].
 
Every Go source code must belong to a package, and it must declare the package it belongs to with the <tt>[[Go_Language_Modularization#The_package_keyword|package]]</tt> keyword.
 
All source file declared as being part of the same package '''must''' be in the same file system directory. You cannot split a package across multiple directories.
 
A directory cannot contain source files for more than one package (or the compiler will complain).
 
Identifiers declared by a package can be [[#Exported_Identifiers|exported]], and in order to refer those identifiers from other packages, the enclosing package must be [[#Importing_Packages|imported]] and the identifiers must be prefixed with the name of the package:
 
<pre>
package B
 
import "A"
 
...
 
func something() {
 
    A.SomeFunctionExportedByA()
 
}
</pre>
 
Each package can be imported and used individually, so developers can import only the functionality they need.
 
The benefits offered by the package mechanism are:
* Different namespaces allow for identifiers with the same name - as long as they belong to different namespaces. This allows keeping the identifier names short and succinct.
* It speeds up the compiler by only requiring compilation of smaller chunks of the program. For example, when we use "fmt" we don't need to recompile it every time we change ''our'' program.
 
It is common in Go to see packages that are relatively small: they have a small API and perform a single task. This is normal and expected.
 
==The <tt>package</tt> keyword==
 
The <tt>package</tt> keyword is used in ''package declarations''. All Go files must start with a package declaration, which consists start with the <tt>package</tt> keyword and it is followed by the [[#Package_Names|package name]]:
 
<pre>
package blue
 
...
</pre>
 
==Package Names==
 
A ''package name'' is an [[Go_Concepts_-_Lexical_Structure#Identifiers|identifier]], which means it consists in a sequence of one more letter, digits and possibly underscores, where the first character is a letter. Even if we might be tempted to think about packages hierarchically, "project1/blue" is NOT a package name, even if, as we will see below, we will use "project1/blue" string literal to import the package.
 
Conventionally, the name of the directory that contains the package files should coincide with the name of the package. It is usually a good idea to follow the convention: while compiling the file, the compiler won't complain if the convention is not followed, but it will run into troubles if other packages that are referred do not follow the convention. For more details, see <tt>[[Go Concepts - Runtime#GOPATH|GOPATH]]</tt>.
 
Note that in order to import the package, the package name may not be sufficient and we may need to use a path fragment in the <tt>import</tt> statement: the string literal that follows the <tt>import</tt> keyword and the package name are two different things. For more details on importing packages, see <tt>[[Go Keyword import|import]]</tt>.
 
===Package Name Conventions===
 
* A package name should coincide with the name of the directory that holds the files.
* The package names should be short, concise, lowercase names.
 
==Writing a Package==
 
Place the package files under a directory hierarchy that makes it obvious where the package comes from, if imported. For example, if planning to write a reusable "blue" package as part of the "airplane" project, place the package source under:
 
<pre>
$LOCAL_PROJECT_HOME/src/io/novaordis/airplane/blue
</pre>
 
Thus the package will be imported as:
 
<pre>
import io/novaordis/airplane/blue
</pre>
 
==Exported Identifiers==
 
In order to be visible outside the declaring package, an identifier must be ''exported''. This is achieved by any of the following is true:
# The identifier's first character is an upper case letter.
# The identifier is declared in the [[#Package_Block|package block]] or it is a [[Go Concepts - The Type System#Fields|field name]] or a [[Go Concepts - Functions#Methods|method name]] of an exported type.
 
An identifier that is not explicitly exported is ''unexported''.
 
Note that identifiers, and not values, can be exported or unexported.
 
It is a good practice to only expose the package elements that we explicitly want other package to use, and hide everything else. This allows to change the hidden parts later, without affecting the package's consumers.
 
Note that just because an identifier is unexported, it does not mean other packages can't indirectly access it: for example a function can return the value of an unexported type and this value is accessible by an calling function, even if the calling function has been declared in a different package. This can be coupled with the short declaration operator ([[Go_Concepts_-_Operators#:.3D|:=]]), which infers the type of the variable. A variable of that type cannot be explicitly declared with <tt>var</tt>.
 
===<tt>struct</tt> Fields Export===
 
The fields of an exported <tt>struct</tt> type can be exported or unexported on a field basis, by naming them with an upper case and respectively lower case letter.
 
===Embedded Type Export===
 
If the name of an inner type starts with a lower case, it is unexported even if its outer type is exported. Even if the name of the inner type is not exported, its fields may be individually exported, and thus accessible from outside the package.
 
For more details on embedded types see:
 
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;">
:[[Go Type Embedding|Type Embedding]]
</blockquote>
 
==Importing Packages==
 
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;">
:<tt>[[Go Keyword import|import]]</tt>
</blockquote>
 
==The "main" Package==
 
A package named "main" that exposes a [[Go Concepts - Functions#The_main.28.29_Function|<tt>main()</tt> function]] is used by the Go linker as a start point for walking the package dependency graph when building the binary executable. All of the executable programs must have a package called "main", and their "main" package must have a <tt>main()</tt> function, otherwise the executable won't be built. More about the <tt>main()</tt> function, the main package and Go executables can be found here: [[Go Concepts - Runtime#Compiling_an_Executable|compiling an executable]].
 
==Hierarchical Packages==
 
<font color=red>'''TODO'''</font>


==Package Block==
The <code>src</code> subdirectory may contain multiple version-control repository workareas.


Each package has a ''package block'' containing all source text for that package. More about blocks is available here:
===<tt>pkg</tt>===
The build tool stores compiled packages in the <code>pkg</code> directory, under <code>${GOOS}_${GOARCH}</code> subdirectories.


<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;">
===<tt>bin</tt>===
:[[Go Concepts - Lexical Structure#Blocks|Blocks]]
The <code>bin</code> directory is where the executables are stored.
</blockquote>
===<tt>vendor</tt>===
<font color=darkkhaki>TODO: expand this and link to [[Go_Packages#Vendoring]].</font>


=Package and Encapsulation=
==Relationship between Workspace and <tt>GOPATH</tt>==
<code>[[Go_Environment_Variables#GOPATH|GOPATH]]</code> should point to the root of the workspace, the directory that contains <code>src</code>, <code>pkg</code> and <code>bin</code>. <font color=darkkhaki>Further research is required.</font>
=Program=
Go programs are constructed by linking together [[Go_Packages#Overview|packages]]. There must be a [[Go_Packages#The_main_Package|<code>main</code> package]], which contains the <code>main()</code>, to trigger the linker.

Latest revision as of 17:42, 4 September 2024

Internal

Overview

Go modularization builds upon the concepts of package and module. Packages provide a namespace for their members, and they are a way to encapsulate code, hide implementation details and only expose features, such as variables, functions or type definitions that are meant to be publicly consumed. Packages can be published as part of modules. Modules have been introduced in Go 1.11.

Packages

Packages

Modules

Modules

Module-Aware or GOPATH Mode

https://go.dev/ref/mod#mod-commands

The compiler must locate packages on the local file system every time it handles an import statement.

The go tool has two modes of resolving package dependencies: module-aware mode or GOPATH mode.

In module-aware mode, the go commands use go.mod files to find versioned dependencies and typically load packages out of the module cache, downloading modules if they are missing. As of Go 1.16, the module-aware mode is enabled by default, regardless of whether go.mod is present or not. The behavior can be controlled with the GO111MODULE environment variable.

In GOPATH mode, go commands use the value of the GOPATH environment variable and vendor directories to resolve packages.

Also see:

GoLand Module-Aware or GOPATH Mode
GOPATH

Project

Project

Repository

A Go repository typically contains only one module, located in the root of the repository. Repository may contain more than one module.

Packages, Modules, Projects and Repositories

Designing your project, to live in its own repository and host a single module in its root directory will help keep maintenance simpler, particularly over time as you publish new versions.

It is possible to maintain more than one module in a project and repository TODO: https://go.dev/doc/modules/managing-source#multiple-module-source.

Standard Library

Go comes with a set of over 100 "built-in" packages, which are available as part of the locally installed Go development environment.

Standard library package documentation is available online here:

https://pkg.go.dev/std

The standard library is a good source of code examples, comments and style guidance.

Standard library packages:

archive atomic bytes bufio container context database
encoding encoding/json errors filepath flag fmt io
ioutil hash html html/template log maps math
net net/http net/url os path rand reflect
regexp runtime runtime/debug slices slog sort strings
strconv sync text/tabwriter text/template testing time unicode

pkg.go.dev

The place to look for published third-party packages is

https://pkg.go.dev

Workspace

This section needs refactoring after reading:

The workspace is a concept introduced in Go 1.18. A workspace allows organizing the code for a project that has several modules which share a common list of dependencies. The workspace maintains metadata, especially dependency metadata, in a file called go.work. The dependencies declared in this file can span modules and anything declared in go.work will override dependencies in the modules's go.mod. The packages and modules maintained in a workspace are managed with the go tool.

A workspace may contain multiple projects.

The standard workspace layout is:

. ← GOPATH should point to this directory, it contains src, pkg and bin
│
├─ src 
│   ├─ a 
│   │  └─ b
│   │     └─color  # "color" package directory, with the "a/b/color" import path
│   │        ├─ colors.go 
│   │        ├─ aux.go 
│   │        └─ ... 
│   │
│   ├─ weight  # "weight" package directory, with the "weight" import path
│   │   ├─ weights.go 
│   │   ├─ aux.go 
│   │   └─ ... 
│   │
│   ├─ novaordis.com
│   │   └─ tools
│   │       └─ hammer # "hammer" package directory, with the "novaordis.com/tools/hammer" import path
│   │           └─ ... 
│   │
│   └─ github.com
│       └─ blue-org
│           └─ tools
│               └─ wrench # "wrench" package directory, with the "github.com/blue-org/tools/wrench" import path
│                   ├─  .git
│                   └─ ... 
│ 
├─ pkg 
│   └─ darwin_amd64 
│       ├─ weights.go 
│       ├─ a/b/color.a 
│       ├─ novaordis.com/tools/hammer.a
│       └─ github.com/bue-org/tools/wrench.a
└─ bin

Content

src

The src subdirectory holds source code. Each package resides in a directory whose name relative to ${GOPATH}/src represents the package's import path.

The src subdirectory may contain multiple version-control repository workareas.

pkg

The build tool stores compiled packages in the pkg directory, under ${GOOS}_${GOARCH} subdirectories.

bin

The bin directory is where the executables are stored.

vendor

TODO: expand this and link to Go_Packages#Vendoring.

Relationship between Workspace and GOPATH

GOPATH should point to the root of the workspace, the directory that contains src, pkg and bin. Further research is required.

Program

Go programs are constructed by linking together packages. There must be a main package, which contains the main(), to trigger the linker.