Home > software_development > Golang local module package implementation guide

Golang local module package implementation guide

A detailed example of creating and using Golang local module.

By :Thomas Inyang🕒 30 Jun 2024

Golang

Introduction

As a software developer who knows that 90% of my projects will grow into complex ones, there is a need to organize my codebase for both productivity and maintainability. Go is one of the languages with the strength to build a robust module system that facilitates code reusability through packages.


Irrespective of what you're building as a developer who writes Go programs, you need to understand how to create and leverage local packages as they are critical skills that can dramatically improve your development workflow.


This guide will cover the following:

  1. How to create reusable functions in Go.
  2. How to import and use the local modules across project structure.
  3. How to write tests for the local modules.

Prerequisites:

  1. Code Editor (VsCode)
  2. Go Basics

Why Developers Should Prioritize Code Reusability.

You should write reusable functions because as best practice in software development. Aside from this, here are some advantages for writing reusable code:

  1. Efficiency Through DRY (Don't Repeat Yourself): This ensures you don't keep writing the same logic multiple times across your codebase, you can encapsulate functionality in a single location and invoke it with a simple function call whenever needed. This action will reduce the time spent writing and testing duplicate code.
  2. Enhanced Code Quality: A reusable function becomes easier to test, optimize, and maintain. This leads to more reliable software with fewer bugs.
  3. Superior Maintainability: You only need to update the code (function) in one place rather than hunting down every instance throughout your project.
  4. Improved Readability: A well-named function acts as documentation, making your code more accessible to other developers (including your future self).
  5. Scalable Architecture: It enforces separation of concerns As your application grows and has clean architecture.

How to Create Local Modules in Go: A Step-by-Step Implementation.

Now that you've understood the importance of function reusability, I will walk you through a practical example to create a local module (mathematical functions) that calculates the geometric areas in GO

See Also: Modularization In Software Development.

Step 1: Setting Up The Project Structure.

First, establish a clean project structure. For this tutorial, create a project called "maths" with a main entry point and a separate package for the reusable functions.


Create and open the math folder with your preferred code editor. If you're using Visual Studio Code, you can right-click on the folder and select "Open with Code" to launch the editor.


Next, enter this in the main.go file, which will serve as the entry point for our application:

package main
import "fmt"
func main() {
fmt.Println("Hello World")
}

This is the standard entry structure for a Go application. The `main` package with a `main()` function is required for any executable Go program.


Initialize the Go module. Open your terminal in the main project directory and run:

go mod init example.com/deviceusername/main
go mod tidy

⇒Note: Replace "deviceusername" with your device username. This establishes a unique import path for the module.


The `go mod init` command creates a new Go module, defined by a go.mod file that tracks your dependencies. The `go mod tidy` command ensures that the go.mod file matches the dependencies used in the code.

After initializing the module run the application with:

go run main.go

This should output "Hello World" in the terminal, confirming that the basic setup is working correctly.


Step 2: Creating Your Reusable Functions Package (Local Module).

First, create a subdirectory and call it "formula". Include functions to calculate the areas of different geometric shapes.

Inside this formula folder, create a file named `formula.go` with the following content:

package formula

// AreaOfCircle
func AreaOfCircle(radius float64) float64 {
return 3.142 * radius * radius
}

// AreaOfTriangle
func AreaOfTriangle(base, height int) float64 {
return (float64(base*height) * 0.5)
}

The package is defined as `formula`, and two exported functions are created (capitalized function names in Go indicate they're accessible outside the package):

1. `AreaOfCircle` - Takes a radius as input and returns the area of the circle

2. `AreaOfTriangle` - Takes base and height measurements and returns the triangle's area

Now, initialize this package as a module:

cd formula
go mod init example.com/deviceusername/formula
go mod tidy
cd ..

This creates a separate module for your formula package, making it independently versioned and potentially shareable across multiple projects.


Step 3: Using The Go Local Package in The Main Application.

With the package created, make the main application aware of it by modifying the module configuration and importing the package.


From the main project directory, run:

go mod edit -replace example.com/deviceusername/formula=./formula
go mod tidy

The `go mod edit -replace` command tells Go to look for the `formula` module in the local `./formula` directory rather than attempting to download it from a remote repository. The `go mod tidy` command updates your dependencies accordingly.

See Also: What you need to know about NodeJs.

Now, update the `main.go` file to use the functions from your formula package:

package main
import (
"fmt"
"example.com/deviceusername/formula"
)

func main() {
areaOfCircle := formula.AreaOfCircle(16)
areaOfTriangle := formula.AreaOfTriangle(6, 9)


fmt.Printf("The area of a circle with radius 16 is %.2f\n", areaOfCircle)

fmt.Printf("The area of a triangle with base 6 and height 9 is %.2f\n", areaOfTriangle)
}

Re-run the application and see the functions in action, use:

go run .

The output should show the calculated areas:

The area of a circle with radius 16 is 803.15
The area of a triangle with base 6 and height 9 is 27.00

How to Handle Nested GO Local Module Structures.

For more complex projects, you might have nested package structures. When importing local packages from different directory levels, then adjust the replace directives accordingly:

# For a package one level up

go mod edit -replace example.com/deviceusername/otherpackage=../otherpackage

# For a package two levels up

go mod edit -replace example.com/deviceusername/deeperpackage=../../deeperpackage

The number of dots corresponds to how many directory levels you need to traverse to reach the target package.

What are the Best Practices for Creating Reusable Go Packages (Local Modules)?

Based on industry experience and Go's official recommendations, here are some guidelines to follow when creating reusable packages:

Go's Naming Conventions:

  1. Package names should be short, concise, and descriptive. Use lowercase, single-word names.
  2. Function names should be in camelCase and exported functions (accessible outside the package) should start with an uppercase letter.


Design for Interface Satisfaction:

  1. Use interfaces rather than concrete types. When designing your packages, consider defining interfaces that your functions or types will satisfy, making your code more flexible.


Document Your Code Thoroughly

  1. Use Go's standard comment (double forward slash //) format to document your packages and functions: // Package formula provides mathematical functions for calculating geometric properties.

These comments will appear in Go's documentation tools like `godoc`.


Write Tests for Your Packages

  1. Reliable packages include tests. For example, Create a file named `formula_test.go` alongside your `formula.go` file:
package formula
import "testing"
func TestAreaOfCircle(t *testing.T) {
got := AreaOfCircle(5)
want := 78.55

if got != want {
t.Errorf("AreaOfCircle(5) = %.2f; want %.2f", got, want)
}
}

Run tests with `go test ./...` from the project root.

See Also: How to Write Tests for REST APIs.

Keep Packages Focused on a Single Purpose:

  1. Each package should have a clear, cohesive purpose. If you find your package growing to handle multiple distinct responsibilities, consider splitting it into separate packages.

See Also: How to Build a RESTful Api with Golang and Supabase.

Conclusion:

In this comprehensive guide, I shared the process of creating and using local packages in Go, by transforming simple functions into reusable modules that can be leveraged across a project structure.


By implementing the techniques discussed here, you can:

  1. Organize your code more effectively
  2. Reduce duplication through strategic function reuse
  3. Improve maintainability by centralizing related functionality
  4. Build more robust applications with well-tested, isolated components


Remember that effective package design is as much an art as it is a science. As you gain experience, develop an intuition for how best to structure your code for reusability, readability, and maintainability.


Happy coding, and may your Go packages be clean, concise, and eminently reusable!