Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Coding Standards

Adam Hanna edited this page Jul 23, 2018 · 9 revisions

Package Implementation

All packages should define an interface and at least one implementation of that interface. Types should be in a separate file or optionally a subdirectory.

All service properties should be private and all interfaces should include a function (s Service) Props() Props { return s.props } method that returns the service's properties.

project
│   README.md
│   main.go    
│
└───pkg
│   │
│   └───foo
│   │   │   interface.go
│   │   │   types.go
│   │   │   service.go
│   │
│   └───bar
│       │   interface.go
│       │
│       └───types
│       │   │   types.go
│       │ 
│       └───implementation1
│       │   │   service.go
│       │ 
│       └───implementation2
│           │   service.go
│   
└───cmd
    ...

To use a package, import the interface.

package foobar

import "pkg/foo"

// Props are passed to the New function
type Props struct {
    FooService foo.Interface
}

// Service implements the package interface
type Service struct {
    props Props
}

// New returns a new service
func New(props Props) *Service {
    return &Service{
        props: props,
    }
}

// Props returns the service's props
function (s Service) Props() Props {
    return s.props
}
...

Testing

Tests should be categorized into one of three types:

  1. Unit
  2. Integration
  3. End-to-end (e2e)

Tests should be denoted in two ways. First, the test file name should end in the test type. e.g. foo_unit_test.go. Secondly, use a build tag inside the test file.

// +build unit

func TestFooBar(t *testing.T) {
    ...
}

Each category of test can then be run as such: $ go test -tags=unit


Note to Adam:

Below is another pattern to consider. This pattern is more commonly seen in Go projects (e.g. Docker, IPFS).

Response to Miguel:

I'm fine with just, just so long as Foo foo.Foo and/or mystore foo.MyStore are interfaces so the package can be unit tested

Package Implementation

project
│   README.md
│   main.go    
│
└───pkg
│   │
│   └───foo
│   │   │   foo_test.go
│   │   │   foo.go
│   │
│   └───bar
│       │   bar.go
│       │
│       └───types
│       │   │   types.go
│       │ 
│       └───qux
│       │   │   qux.go
│       │ 
│       └───baz
│           │   baz.go
│   
└───cmd
    ...
package foobar

import "pkg/foo"

// Config is the configuration settings for the package constructor.
type Config struct {
    Foo foo.Foo
}

// Foobar is the structure that holds information regarding the instance.
type Foobar struct {
    mystore foo.MyStore
}

// NewFoobar returns a new foobar instance.
func NewFoobar(config *Config) *Foobar {
    f := foo.NewFoo()
    return &Service{
        myStore: f.MyStore,
    }
}

// MyStore returns the mystore instance.
function (foobar *Foobar) MyStore() {
    return foobar.myStore
}
...

Naming Conventions

Projects are named as follows: <project>-<library>-<language> and examples are <project>-<library>-<language>-example-<example_name> per this issue.