在Go应用程序中实施SOLID Design

What's the best way to model a model (user) and a database without running into circular dependencies?

I have a Go application that I'm trying to set up. The structure of imports is confusing because it doesn't cleanly appear to divide along separation of concerns. I would like to have a database store that requires access to the names of models to migrate them. It seems odd to have models migrate themselves and that seems like an unrelated concern to the models. At the same time, I would like to have validations per model that require the importing of the database store. It seems even more odd to have the store validate individual models. This creates a circular dependency however.

structure:

models
  - user.go
config
  - store.go

store.go

...
// CreateDb - creates table
func (i *Store) CreateDb() {
    ...
    i.DB.AutoMigrate(&models.User{})
    ...
}
...

user.go

package models

type User struct {
  Email string
}

func (u *User) ValidateUser() (err []error) {
    messages := make([]error, 0)

    // Uniqueness Validations
    email := ""

    email = config.Database.DB.Where("email LIKE ?", u.Email).First(&User)
    if email != "" {
        messages = append(messages, errors.New("Email has to be unique"))

    }

    return messages
}

I've tried putting them into a third package but that fails because they both require the same dependency - store. I've also tried putting them all into the same package which I suppose works but that seems to breakdown all structure and sep of concerns.

Advice?

My solution

I ended up decoupling the database pointer into a separate package and then made the migrations a part of a bootstrap process. I kept validations in line with the models package however.

I am not a Go guy but since it's a design question, it doesn't matter. Disallowing duplicate emails is a business requirement. Moreover as per business requirements there can be other stuff that you need to do before/after validations but before hitting database store.

I would put validations in another package which will act as a business logic layer and references model and store packages. I will keep models clean like we have POCO, POJO in C#, Java respectively. Don't know what to call them in Go context. POGO is reserved for Groovy :).

See the pseudo code below:

// business
function AddUser(email) {
    User user;
    // validate
    user = store.GetUserByEmail(email);
    if (user) {
        // shout
    }
    else {
        user = new User { Email = email }; // basically initialize user instance to store
        store.InsertUser(user); 
    }
}

That's just basic I talked about. You could define interfaces that your business package uses to talk to store, followed by dependency injection and what not.