I'm building a go web service and trying to follow the "clean code" or "domain driven design" principles. My stripped down folder structure looks something like this:
- api
- postgre
employee_service.go
employee.go
The basic layout is my root(api) folder is all of my domain code. And all the packages are adapters to make my domain work but are easy to swap out if needed. My employee.go
file might looks something like this:
type EmployeeService interface{
CreateEmployee(e *Employee) error
}
type Employee struct {
ID string
Name string
}
The question I have is where to place certain things on my app because they feel to me like they are part of my domain logic; however the domain logic should not have any external dependencies so it leaves me stuck. Here is an example I want to create a new employee:
postgre/employee_service.go:
type EmployeeService struct {
DB *pg.DB
}
func (s *EmployeeService) CreateEmployee(e *api.Employee) error {
e.ID = uuid.NewV4().String()
// insert to db
}
Now you can imagine the Employee
struct has a lot more fields than just an ID or name I need to set before inserting it to the DB. So my thought was to add a method to the User
struct in the root of my app something like this:
/employee.go
func (e *Employee) New() {
e.ID = uuid.NewV4()
// add any other fields I need
}
And the postgre user service would look like this:
postgre/employee_service.go:
func (s *EmployeeService) CreateEmployee(e *api.Employee) error {
e.New()
// insert to db
}
Now the issue with this is that the domain of my app is dependent on the uuid
package. In my mind that is fine because if I were to swap out postgre for mysql or mongo or any other DB that New()
method would not change. Another more "complicated" example is password hashing no matter what the DB is my password hashes will be generated the same so I believe this belongs in my root folder where my domain logic is. Yet again to hash a password I would the crypto/bcrypt
dependency breaking the DDD rule that your domain should have no external dependencies.