I have difficulties refactoring code in go, since the lint detects duplication of pattern but the function is different.
the code goes like this, it is implemented for grpc with protobuf definition
func (svc *UserService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
err := svc.validateCreateUser(req)
if err != nil {
return nil, err
}
user, err := svc.repo.CreateUser(ctx, req)
if err != nil {
return nil, err
}
return user, nil
}
func (svc *UserService) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.UpdateUserResponse, error) {
err := svc.validateUpdateUser(req)
if err != nil {
return nil, err
}
user, err := svc.repo.UpdateUser(ctx, req)
if err != nil {
return nil, err
}
return user, nil
}
thanks in advance.
I have no clue how to avoid duplication since the function also have different param type.
CodePudding user response:
Not all lint issues must be fixed
If you think it will sacrifice readability, add a // nolint
However… you can refactor them code using generics
func [T, V any] someNameToBeDefined(
ctx context.Context,
target T,
validator func(T) error,
executor func(context.Context, T) (V, error),
) (V, error){
if err := validator(target); err!= nil { … }
return executor(ctx, target)
}
func (svc *UserService) CreateUser(
ctx context.Context,
req *pb.CreateUserRequest,
) (*pb.CreateUserResponse, error) {
return someNameToBeDefined(ctx,
req,
svc.validateCreateUser,
svc.repo.CreateUser,
)
}
If you think this is readable, go ahead.
But perhaps this may not the right way.
For instance, your repo can validate the request before create/update.
This is a more readable approach than use generics and function pointers IMHO