Style question about database create functions

blov · 2017-07-22 05:00:06 · 550 次点击    
这是一个分享于 2017-07-22 05:00:06 的资源,其中的信息可能已经有所发展或是发生改变。

An bad title I know, basically it comes down to these two different situations.

First if we have a create method which accepts a pointer to the model:

func Create(model *Model) error {
    model, err := db.Insert(model)
    if err != nil {
         return err
    }
    return nil
}

Second we have a method which also returns the pointer

func Create(model *Model) (*Model, error) {
    model, err := db.Insert(model)
    if err != nil {
         return nil, err
    }
    return model, nil
}

I was erring towards the second signature because it lets you use a literal as the argument to create and still have a reference at the end of the method.

Views?


评论:

tmornini:

Why not:

func (model *Model) Create() error

ROFLLOLSTER:

Because then you can't do:

model, err := Create(&Model{fields...})
tmornini:

Fair enough

func (model *Model) Create() (*Model, error)

Allows

model, err := &Model{fields ...}.Create()
shovelpost:

I don't think it is is a good idea to add database logic to your application's structs.

tmornini:

I would have agreed with that in the past.

Now that I'm thinking purely in terms of HTTP microservice systems, I find there's no benefit in the additional complexity.

OP code implied the Create func was already in the Model struct's package.

EDIT: 180 degree turn around after thinking it through.

ROFLLOLSTER:

They are actually in different packages, just wrote it that way for brevity because I'm on mobile.

tmornini:

All good!

shovelpost:

I believe there is a 3rd option:

func Create(u User) (User, error)  or  func Create(u User) (*User, error)

You pass a copy with only the required values filled like say Name and you return a brand new user that contains the rest like ID and Created.

I think it makes a little more sense than:

func Create(u *User) (*User, error)

Because if we are passing a pointer then why return it? Is it the same one? If it is then why not modify the original one instead? Of course there is still the argument that User might be big and we do not wish to copy it. So...

I think my favorite option is :

func Create(u *User) error

Where you pass a pointer and after the function ends successfully if we inspect the fields of u the fields like ID and Created have been filled with the values from the database. It feels a little more "lightweight" to me and the fact that you pass down a pointer it means that the function is planning to modify its values.

In the end I don't think it matters too much. Just be consistent across the codebase.

P.S. I know it was an example but I detest seeing things like models.Model with models being the worst part.

dasopranos:

I like the second one. It makes the code smaller which is always good, and IMHO it makes it more readable too.

Infact I go even futher, i would do: https://play.golang.org/p/6e_Er9PtdH

(sorry i couldnt get reddit code formatting to work)

tmornini:

You're headed down the road to creating your own ORM.

The path to hell is paved with good intentions!

dasopranos:

I don't see it. What I see is the orthognality of the DB and Model concepts in my program.

"Simplicity comes from orthogonality and predictability." -- Rob Pike


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

550 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传