loading...

How do you maintain entity state in Golang

purplebooth profile image Billie ・1 min read

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())

}

Posted on by:

purplebooth profile

Billie

@purplebooth

I write PHP but other things when I am at home/I also have curly hair.

Discussion

pic
Editor guide
 

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. :)

 

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

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

 

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.