/gopublicfield

Blocks the writing in public struc fields

Primary LanguageGoMIT LicenseMIT

Go public field linter

CI Go Report Card MIT License Coverage Status

The linter blocks the changing of public fields. Unwritable fields help to avoid validation. The linter is useful when:

  • A project is migrated to Domain Model from Anemic.
  • Business logic should not be broken by a direct variable assigning.
  • You don't want to use snapshot pattern to get data from model and want to protect business logic in the project.

Use

Installation

go install github.com/maranqz/gopublicfield/cmd/gopublicfield@latest

Options

  • --packageGlobs - list of glob packages, in which public fields can be written by other packages in the same glob pattern. By default, all fields in all external packages should be unwritable except local, tests.
    • --packageGlobsOnly - only public fields in glob packages cannot be written by other packages, tests.

Example

BadGood
package main

import (
	"bad"
)

func main() {
	u := &bad.User{}

	u.UpdatedAt = time.Now() // Field 'ID' in bad.User can be changed only inside nested package.`
}
package bad

import "time"

type User struct {
	UpdatedAt time.Time
}
package main

import (
	"good"
)

func main() {
	u := &good.User{}

	u.Update()
}
package user

import "time"

type User struct {
	UpdatedAt time.Time
}

func (u *User) Update() {
	u.UpdatedAt = time.Now()
}

TODO

False negative

All examples shows in unimplemented directory.

Feature, hardly implementable and not planned

  1. Type assertion, type declaration and type underlying, tests.
  2. Unreadable fields.

Problems, hardly fixable and not planed

  1. Updating of slice, map items.
  2. Updating by pointer to the unwritable field.
     //..
     n := nested.Struct{}
     fieldPtr := &n.Int
     (*fieldPtr)++
     //..