sourcegraph / thesrc

Example of a 3-layer (frontend, API, datastore) Go web app (based on the code that powers https://sourcegraph.com)
https://sourcegraph.com/github.com/sourcegraph/thesrc
MIT License
398 stars 29 forks source link

MockPostsService setup #2

Open ezbercih opened 10 years ago

ezbercih commented 10 years ago

Could you elaborate on the design of the MockPostsService in posts.go and decisions around how it is setup? To be more specific:

I see you got inspired quite a bit from https://github.com/google/go-github when designing the client and options interface ideas, with a departure from implementing services as interfaces with types that implement them instead of directly creating them as types. I am going back and forth on this on my implementation but leaning towards the interface approach for better testing.

And I just wanted to say this is an awesome project for hashing out best practices. I really appreciate the effort you guys put in it, as I am working on an SDK for a set of REST APIs and it helps to validate some of the decisions I made.

beyang commented 10 years ago

Answering questions point by point:

go-github was a big inspiration for the design of the API client. I think the main difference is that go-github is solely an API client, whereas we wanted to reuse the same code for not just the API client, but also the datastore in the server. Hence defining the interface, which gets implemented at multiple layers in the stack.

Thanks for the kind words. Look forward to the SDK, would love to explore it when it's releaseD!

ezbercih commented 10 years ago

Thanks for the detailed explanation. Much appreciated!

I will make sure to let you know when I release the SDK.

ezbercih commented 10 years ago

Regarding the third point, I know you mentioned arrays but in this case it looks like it is a slice and based on the comment in the second paragraph at http://golang.org/doc/faq#pass_by_value slice values behave like pointers:

Map and slice values behave like pointers: they are descriptors that contain pointers to the underlying map or slice data. Copying a map or slice value doesn't copy the data it points to.

So actually creating a slice of pointers must allocate more memory than creating a slice of values. Since slice elements are pointers to an underlying array's elements, we already have the desired effect. We would be doing double indirection (a pointer to a value in an array element vs. a pointer to a pointer in an array element that points to a value) in this case and storing an extra pointer per value. I might totally got it wrong but that's how I interpreted.

beyang commented 10 years ago

Sorry, substitute "slice" for "array" in my previous comment.

And you're right. If you do

foo := []Post{Post{ ... }, Post{ ... }, ... }
bar := foo

this doesn't actually copy the slice data. The slice itself is passed by reference.

But if you get a specific element out of a slice, it will copy that data.

foo := []Post{Post{ ... }, Post{ ... }, ... }
fooElem = foo[0]
fooElem.ID = 20394
fmt.Println(fooElem.ID)
fmt.Println(foo[0].ID)

will print different values. Whereas if it were a slice of pointers, then only the pointer would be copied. I'm not claiming this is a huge perf win. Either one probably works fine.

Also, the way the modl library deserializes data from SQL might also require an array of pointers (I can't remember specifically), but that'd be just an implementation detail.

gbbr commented 9 years ago

@beyang I've remember this approach you were using to verify interfaces are implemented. I've found a better one that is used in the stdlib and thought you might like to find out about it:

var _ PostsService = (*MockPostsService)(nil)

That works too. See Line 248 & 249 here http://golang.org/src/pkg/testing/testing.go

beyang commented 9 years ago

cool, thanks for sharing!