GRACE Style Guide
Index
Golang
Linter
GRACE was using the gometalinter to enforce community recommended style guidelines on Go code. However, the gometalinter project has been deprecated in favor of golangci-lint and GRACE will be migrating to this linter instead.
Testing
- Favor using table driven tests (See Figure 1).
- Keep tests focused. Each test case should test a single behavior and be named accordingly.
- Use assertions instead of if statements, where possible (See Figure 2).
- Use sub-tests to differentiate error messages when using assertions. This will make debugging easier.
- Test cases should cover both the Happy path and the Unhappy path (See Happy Path vs Unhappy Path).
Mocking
- Use native go interfaces when feasible (See Figure 3).
- Use GoMock when go interfaces alone are not sufficient (See Figure 4).
Code Coverage
Well written code will generally have line, branch and mutation coverage higher than 80%. Prioritize testing code that is most likely to change in the future.
Figure 1
// Sum ... returns the sum of two numbers
func Sum(a, b int) int {
return a + b
}
func TestSum(t *testing.T) {
tt := map[string]struct {
A int
B int
Expected int
}{
"1+2=3": {1, 2, 3},
"2+2=4": {2, 2, 4},
}
for name, tc := range tt {
tc := tc
t.Run(name, func(t *testing.T) {
actual := Sum(tc.A, tc.B)
assert.Equal(t, tc.Expected, actual)
})
}
}Figure 2
// Read ... reads the file at 'path' and returns the contents as a string
func Read(path string) (string, error) {
byt, err := ioutil.ReadFile(path)
if err != nil {
return "", err
}
return string(byt), nil
}
func TestRead(t *testing.T) {
tt := map[string]struct {
Path string
Expected string
Error bool
}{
"File": {Path: "localfile.json", Expected: `{"data":"this"}`},
"FileErr": {Path: "non_existent", Error: true},
}
for name, tc := range tt {
tc := tc
t.Run(name, func(t *testing.T) {
actual, err := Read(tc.Path)
if !tc.Error { // Assert not used for readability
assert.Nil(t, err)
}
assert.Equal(t, tc.Expected, actual)
})
}
}Figure 3
dog/dog.go
package dog
...
type Dog struct {
}
func New() *Dog {
return &Dog{}
}
func (d *Dog) Bark() string {
return "bark!"
}
type IDog interface {
Bark() string
}
var _ IDog = (*Dog)(nil)main.go
package main
...
func main() {
d := dog.New()
PrintMsg(d)
}
func GetSound(t dog.IDog) string {
return t.Bark()
}main_test.go
package main
...
type MockDog struct {
dog.IDog
bark string
}
func (m *MockDog) Bark() string {
return m.bark
}
func TestGetSound(t *testing.T) {
expected := "yip!"
md := &MockDog{bark: expected}
actual := GetSound(md)
assert.Equal(t, expected, actual)
}Figure 4
dog/mock_dog/mock_dog.go
// Code generated by MockGen. DO NOT EDIT.
// Source: ..\dog.go
// Package mock_dog is a generated GoMock package.
package mock_dog
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockIDog is a mock of IDog interface
type MockIDog struct {
ctrl *gomock.Controller
recorder *MockIDogMockRecorder
}
// MockIDogMockRecorder is the mock recorder for MockIDog
type MockIDogMockRecorder struct {
mock *MockIDog
}
// NewMockIDog creates a new mock instance
func NewMockIDog(ctrl *gomock.Controller) *MockIDog {
mock := &MockIDog{ctrl: ctrl}
mock.recorder = &MockIDogMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockIDog) EXPECT() *MockIDogMockRecorder {
return m.recorder
}
// Bark mocks base method
func (m *MockIDog) Bark() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bark")
ret0, _ := ret[0].(string)
return ret0
}
// Bark indicates an expected call of Bark
func (mr *MockIDogMockRecorder) Bark() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bark", reflect.TypeOf((*MockIDog)(nil).Bark))
}main_test.go
package main
...
func TestSound(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
expected := "yip!"
m := mock_dog.NewMockIDog(ctrl)
m.EXPECT().Bark().Times(1).Return(expected)
actual := sound(m)
assert.Equal(t, expected, actual)
}Terraform
The GRACE development team will use the Terraform Best Practices GitBook by Anton Babenko as a style guide for GRACE Terraform code. The team will document additional clarification, modifications, deviations and addendums to the guide in this repository.
[top]
References for Terraform Style Guides
- Terraform Best Practices
- Hashicorp Terraform Style Conventions
- Hashicorp Terraform Recommended Practices
- Hashicorp Terraform Getting Started - AWS Dependencies
- GRACE IAM Naming Standard-Draft
- Jon Brouse Terraform Style Guide
- ASICS Digital Group Terraform Style Guide
- How to use Terraform as a team – Gruntwork - Gruntwork Blog
- Introducing Terraform at GumGum
- Template/Module iteration terraform style - Google Groups
- Pete's Terraform Tips – Pete Shima – Medium
[top]
AWS Resource Naming
IAM
There is a draft GRACE IAM Naming Standard in Google Docs.
Public domain
This project is in the worldwide public domain. As stated in CONTRIBUTING:
This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the CC0 1.0 Universal public domain dedication.
All contributions to this project will be released under the CC0 dedication. By submitting a pull request, you are agreeing to comply with this waiver of copyright interest.
[top]

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.
