When I started learning Go, one of the first questions I had was:

“How do I actually structure my code?”

In languages like C, it’s common to throw everything into a single file, or maybe separate header and implementation files. But in Go, project structure is a big deal: it affects how easily you can scale, test, and share your code. In this article, I’ll walk through why structure matters, how to access functions from different files, and what best practices I’m learning as I move forward.


The Simplest Go Program

A Go program can live entirely in a single file:

package main

import "fmt"

func main() {
  fmt.Println("2 + 2 =", 2+2)
}

This works fine for “hello world” or quick experiments.

But as soon as you add more functionality (subtraction, multiplication, division…), the file gets messy and hardly scalable.

That’s where Go’s packages and folders come in.


Introducing Packages

In Go, every file belongs to a package.

By convention:

Here’s how I split the calculator project:

calculator/
│
├── main.go
└── calculator/
    └── operations.go

Example: operations.go

package calculator

func Add(a, b int) int {
  return a + b
}

func Subtract(a, b int) int {
  return a - b
}

func Multiply(a, b int) int {
  return a * b
}

func Divide(a, b int) (int, error) {
  if b == 0 {
    return 0, fmt.Errorf("cannot divide by zero")
  }
  return a / b, nil
}

Example: main.go

package main

import (
  "fmt"
  "GoLang-progress/calculator"
)

func main() {
  fmt.Println("2 + 3 =", calculator.Add(2, 3))
  fmt.Println("10 - 4 =", calculator.Subtract(10, 4))
  fmt.Println("6 * 7 =", calculator.Multiply(6, 7))

  result, err := calculator.Divide(8, 0)
  if err != nil {
    fmt.Println("Error:", err)
  } else {
    fmt.Println("8 / 0 =", result)
  }
}

Notice how main.go is now clean: it doesn’t worry about the math itself, just how to use it.


Accessing Functions from Different Files

A common beginner question:

“How do I call a function from another file or folder?”

In my repo, I structured it like this:

calculator/
│
├── main.go
└── internal/
    └── calc/
        └── operations.go

Here, the math functions live under internal/calc.

operations.go (inside internal/calc)

package calc

import "fmt"

func Add(a, b int) int {
  return a + b
}

func Divide(a, b int) (int, error) {
  if b == 0 {
    return 0, fmt.Errorf("cannot divide by zero")
  }
  return a / b, nil
}

main.go (importing internal/calc)

package main

import (
  "fmt"
  "github.com/turman17/GoLang-progress/calculator/internal/calc"
)

func main() {
  fmt.Println("2 + 3 =", calc.Add(2, 3))

  result, err := calc.Divide(10, 0)
  if err != nil {
    fmt.Println("Error:", err)
  } else {
    fmt.Println("10 / 2 =", result)
  }
}

Why this import path is required

Your import must match your module path from go.mod plus the folder path.

In your repo, go.mod contains:

module github.com/turman17/GoLang-progress

The calculator code you want to use lives in the folder:

calculator/internal/calc

So the full import path is:

github.com/turman17/GoLang-progress/calculator/internal/calc

A few important notes


Common errors and fixes

❌ import "GoLang-progress/calculator/internal/calc"

→ Missing GitHub org/username. Must use full path.

❌ import "github.com/turman17/GoLang-progress/internal/calc"

→ Missing calculator directory in the path.

❌ go: module not found errors

→ Ensure go.mod has module github.com/turman17/GoLang-progress and run go mod tidy.


Quick checklist

go run ./calculator

or

go build ./calculator

Scaling the Structure

As projects grow, you’ll often see this pattern:

project-name/
│
├── cmd/        → executables (main entrypoints)
├── internal/   → private code (not for external use)
├── pkg/        → reusable packages
├── api/        → API definitions (gRPC, OpenAPI, etc.)
└── go.mod

For beginners, this might be overkill. But as you move into web apps, services, or MLOps tools, this layout becomes essential.


Best Practices I’m Learning

Lessons from the Calculator Project

I’ll continue sharing what I learn as I explore Go for MLOps and backend development. Next up: error handling and testing in Go.

👉 Check out my repo here: https://github.com/turman17/GoLang-progress

And stay tuned for the next article!