Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
39: Organizing Code into Packages
Wait, does my folder name have to match the package name?
Technically? No. But in practice? Yes. Absolutely yes. If you try to name your folder billing_logic but put package payments at the top of the files inside it, you're going to confuse every other developer on your team—and probably yourself in two weeks.
In Go, the convention is that the package name should match the directory name. When you import something, you use the path to the directory, but you refer to the package by the name declared in the source file. If they differ, your import looks like this: import "myapp/billing_logic", but you call the functions using payments.DoSomething(). It's jarring and unnecessary. Just keep them the same.
I'm trying to use a function from another package, but Go says it's undefined. What's going on?
This is the "aha!" moment for most people learning Go. Go doesn't have public or private keywords like Java or C#. Instead, it uses capitalization. If a function, struct, or variable starts with an uppercase letter, it's exported (public). If it starts with a lowercase letter, it's unexported (private to that package).
Let's look at a payment processor example. If I'm building a payments package, I want the outside world to trigger a payment, but I don't want them messing with my internal validation logic.
// payments/processor.go
package payments
// ProcessPayment is exported because it starts with 'P'
func ProcessPayment(amount float64) bool {
if validateAmount(amount) {
// logic to hit a gateway...
return true
}
return false
}
// validateAmount is unexported because it starts with 'v'
func validateAmount(amount float64) bool {
return amount > 0
}
If you try to call payments.validateAmount(10.0) from your main.go, the compiler will yell at you. I personally love this approach because it forces you to think about your package's public API before you even write the code.
Can I put multiple packages in one folder?
Short answer: No. You can't. Every single file in a directory must belong to the same package. If you try to mix package payments and package shipping in the same folder, the Go toolchain will throw a fit.
If you feel like a folder is getting too crowded or your package is doing too many things, that's your signal to create a sub-directory. For example, if your payments package is getting huge, you might move the credit card logic into payments/stripe and the PayPal logic into payments/paypal. Each of those sub-directories becomes its own package.
Just be careful: Go does not allow circular dependencies. If package A imports package B, then package B cannot import package A. If you hit this wall, it usually means your packages are too tightly coupled and you need to extract the shared logic into a third, smaller package that both A and B can depend on.
📋 Practical Task
Build a Multi-Package Currency Converter
Your goal is to move the logic for currency conversion out of the main package and into its own dedicated package to practice visibility and organization.
- Create a folder named
converter. - Inside
converter/converter.go, create a package namedconverter. - Implement a struct called
ExchangeRatewith an exported fieldRate. - Implement an exported function
Convert(amount float64, ex ExchangeRate) float64that returns the converted amount. - Implement an unexported helper function
logTransaction(amount float64)that simply prints a message to the console. Call this helper inside yourConvertfunction. - In your
main.go(root directory), import theconverterpackage and use it to convert 100 USD to EUR (using a rate of 0.92). - Verify that you cannot call
logTransactionfrommain.go.
There are no comments for now.