DEV Community

Billie
Billie

Posted on

How do you maintain entity state in Golang

Is this the best way in Go to create an Entity that can't be set into an invalid state?

Here's an example of how I might implement it. I'm unsure if this is very idiomatic.

package custom_subdomain

import (
    "errors"
    "regexp"
)

type domainReg struct {
    domainName string
    // Other values ...
}

func NewDomainRegistration(domainName string) (*domainReg, error) {
    reg := &domainReg{}
    if err := reg.SetDomainName(domainName); err != nil {
        return nil, err
    }

    return reg, nil
}

func (r *domainReg) GetDomainName() string {
    return r.domainName
}

func (r *domainReg) SetDomainName(domain string) error {
    matches, err := regexp.Match("\\.example.com$", []byte(domain))

    if err != nil {
        return err
    }

    if !matches {
        return errors.New("all domains must be sub-domains to .example.com")
    }

    r.domainName = domain

    return nil
}

type DomainRegistration interface {
    GetDomainName() string
    SetDomainName(domain string) error
}
package main

import (
    "fmt"
    "github.com/purplebooth/entity-state-example"
    "log"
)

func main() {

    reg, err := custom_subdomain.NewDomainRegistration("test.example.com")

    if err != nil {
        log.Panic(err)
    }

    fmt.Println(reg.GetDomainName())

}

Top comments (3)

Collapse
 
foresthoffman profile image
Forest Hoffman

Would I be correct in understanding that you want to avoid having a domainReg instance with uninitialized values? If so, yes, I believe this is a valid implementation. The vast majority of the packages that I've seen or used have some variety of your custom_subdomain.NewDomainRegistration() function. They allow you to control how things get initialized, which is not possible with plain-old struct instance construction.

Please correct me, if I'm misreading. :)

Collapse
 
purplebooth profile image
Billie

Awesome! Yeah that's exactly what I want to do.

For some reason it didn't feel very "go"

Collapse
 
foresthoffman profile image
Forest Hoffman

Sweet! I felt the same initially. It's almost like one of those "when in Rome" situations. I will say, it's quite nice when you decide you want to mock internal functions in unit tests. Then you only have to build upon the initialization function, like any other new feature, rather than having to adopt it much later.