Book Image

Go Design Patterns

By : Mario Castro Contreras
Book Image

Go Design Patterns

By: Mario Castro Contreras

Overview of this book

Go is a multi-paradigm programming language that has built-in facilities to create concurrent applications. Design patterns allow developers to efficiently address common problems faced during developing applications. Go Design Patterns will provide readers with a reference point to software design patterns and CSP concurrency design patterns to help them build applications in a more idiomatic, robust, and convenient way in Go. The book starts with a brief introduction to Go programming essentials and quickly moves on to explain the idea behind the creation of design patterns and how they appeared in the 90’s as a common "language" between developers to solve common tasks in object-oriented programming languages. You will then learn how to apply the 23 Gang of Four (GoF) design patterns in Go and also learn about CSP concurrency patterns, the "killer feature" in Go that has helped Google develop software to maintain thousands of servers. With all of this the book will enable you to understand and apply design patterns in an idiomatic way that will produce concise, readable, and maintainable software.
Table of Contents (17 chapters)
Go Design Patterns
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Libraries


Until now, most of our examples were applications. An application is defined by its main function and package. But with Go, you can also create pure libraries. In libraries, the package need not be called main nor do you need the main function.

As libraries aren't applications, you cannot build a binary file with them and you need the main package that is going to use them.

For example, let's create an arithmetic library to perform common operations on integers: sums, subtractions, multiplications, and divisions. We'll not get into many details about the implementation to focus on the particularities of Go's libraries:

package arithmetic 
 
func Sum(args ...int) (res int) { 
    for _, v := range args { 
        res += v 
    } 
    return 
} 

First, we need a name for our library; we set this name by giving a name to the entire package. This means that every file in this folder must have this package name too and the entire group of files composes the library called arithmetic too in this case (because it only contains one package). This way, we won't need to refer to the filenames for this library and to provide the library name and path will be enough to import and use it. We have defined a Sum function that takes as many arguments as you need and that will return an integer that, during the scope of the function, is going to be called res. This allows us to initialize to 0 the value we're returning. We defined a package (not the main package but a library one) and called it arithmetic. As this is a library package, we can't run it from the command line directly so we'll have to create the main function for it or a unit test file. For simplicity , we'll create a main function that runs some of the operations now but let's finish the library first:

func Subtract(args ...int) int { 
    if len(args) < 2 { 
        return 0 
    } 
 
    res := args[0] 
    for i := 1; i < len(args); i++ { 
        res -= args[i] 
    } 
    return res 
} 

The Subtraction code will return 0 if the number of arguments is less than zero and the subtraction of all its arguments if it has two arguments or more:

func Multiply(args ...int) int { 
    if len(args) < 2 { 
        return 0 
    } 
 
    res := 1 
    for i := 0; i < len(args); i++ { 
        res *= args[i] 
    } 
    return res 
} 

The Multiply function works in a similar fashion. It returns 0 when arguments are less than two and the multiplication of all its arguments when it has two or more. Finally, the Division code changes a bit because it will return an error if you ask it to divided by zero:

func Divide(a, b int) (float64, error) { 
    if b == 0 { 
        return 0, errors.New("You cannot divide by zero") 
    }  
    return float64(a) / float64(b), nil 
} 

So now we have our library finished, but we need a main function to use it as libraries cannot be converted to executable files directly. Our main function looks like the following:

package main 
 
import ( 
"fmt" 
 
"bitbucket.org/mariocastro/go-design-patterns/introduction/libraries/arithmetic" 
) 
 
func main() { 
    sumRes := arithmetic.Sum(5, 6) 
    subRes := arithmetic.Subtract(10, 5) 
    multiplyRes := arithmetic.Multiply(8, 7) 
    divideRes, _ := arithmetic.Divide(10, 2) 
 
    fmt.Printf("5+6 is %d. 10-5 is %d, 8*7 is %d and 10/2 is %f\n", sumRes, subRes, multiplyRes, divideRes) 
} 

We are performing an operation over every function that we have defined. Take a closer look at the import clause. It is taking the library we have written from its folder within $GOPATH that matches its URL in https://bitbucket.org/ . Then, to use every one of the functions that are defined within a library, you have to name the package name that the library has before each method.

Note

Have you realized that we called our functions with uppercase names? Because of the visibility rules we have seen before, exported functions in a package must have uppercase names or they won't be visible outside of the scope of the package. So, with this rule in mind, you cannot call a lowercase function or variable within a package and package calls will always be followed by uppercase names.

Let's recall, some naming conventions about libraries:

  • Each file in the same folder must contain the same package name. Files don't need to be named in any special way.

  • A folder represents a package name within a library. The folder name will be used on import paths and it doesn't need to reflect the package name (although it's recommended for the parent package).

  • A library is one or many packages representing a tree that you import by the parent of all packages folder.

  • You call things within a library by their package name.