In the Go language, code organization through packages and the visibility system plays a key role in modularity, reusability, and encapsulation of logic.
Unlike many classic object-oriented languages with inheritance, Go was designed from the ground up around simple modules — packages with clear rules for export and imports. This is a legacy of the philosophy of minimalism, simplicity, and strict dependency control.
If components do not have clear visibility, chaos in naming arises, making it difficult to track dependencies between files, and increasing the risk of accidentally using private implementation details. Errors in export organization can lead to hard-to-debug bugs and violations of encapsulation.
In Go, every file must belong to some package (package name). The entire scope of visibility in Go is defined as follows:
All functions, types, variables, constants, methods whose names start with a capital letter are exported from the package and available to other packages after import. The rest are only accessible within the package.
Example structure:
project/
│
├── main.go // package main
└── mathutil/
└── mathutil.go // package mathutil
Example code:
// mathutil/mathutil.go package mathutil // Public - exported function func Sum(a, b int) int { return a + b } // private - unexported function func subtract(a, b int) int { return a - b }
// main.go package main import ( "fmt" "project/mathutil" ) func main() { fmt.Println(mathutil.Sum(2, 3)) // 5 // fmt.Println(mathutil.subtract(3,2)) // Compilation error! subtract is unexported }
Key features:
Can a variable or function declared with a lowercase letter be exported by other means?
No. In Go, there are no keywords like public, private, everything is defined only by the first letter of the name (unicode category — uppercase letter).
Can functions from one file in a package use private functions from another file of the same package?
Yes, the visibility is limited at the package level, not at the file level. All private elements are accessible in all files of the same package.
Example code:
// mathutil/helpers.go package mathutil func hiddenHelper() int { return 42 } // mathutil/mathutil.go package mathutil func UseHelper() int { return hiddenHelper() // available! }
Can you create the same function or type with the same name within one package in different files?
No, there will be a compilation error — names must be unique within a package, even if declared in different files.
xxx_test.go file in the same package)A large team places all utility functions and types in a utility package with everything exported:
Pros:
Cons:
The team carefully divides the code into modules by business areas, exporting only the API:
Pros:
Cons: