On Mon, Aug 8, 2022 at 11:27 PM Henry <henry.adisuma...@gmail.com> wrote:

> I am sure that many of us have been on that journey. After using Go for
> some time, we discover some practices that are not necessarily in agreement
> with the existing "adages" but effectively solve our problems.
>
> For me, if the data type is mutable, I prefer returning interfaces. It
> would be something like this:
> ```
> type Student interface {
>    //...
> }
>
> type studentImpl struct {
>    //...
> }
>
> func NewStudent(id string) Student {
>    return &studentImpl{
>       //...
>    }
> }
> ```
> There is a bit of history why I use this approach. For a struct with a
> mutex, I wanted to ensure that the user did not accidentally copy the
> struct. Nowadays we have *go vet* to give us a warning, but this was
> before *go vet* had this functionality. So, I return a pointer to the
> struct and hide it behind an interface. That way, it hides the
> implementation details from the user and the user can pass the object
> around without knowing whether it has a mutex or not.
>
> And then I ended up with some *constructors* returning structs and some
> returning interfaces. To ensure consistency, my colleagues and I decided to
> return interfaces for all mutable objects. For immutable objects, we return
> structs.
>
> The nice thing about this approach is that it makes the syntax a lot
> cleaner as you have to deal with fewer pointers.
> ```
> //instead of this
> func Update(student *Student) {
>   //...
> }
> func UpdateMany(students []*Student){
>   //...
> }
>
> //now you have this
> func Update(student Student) {
>   //...
> }
> func UpdateMany(students []Student){
>   //...
> }
> ```
> Some members in the team came from higher level languages and they found
> working with pointers a bit awkward, so we made some accommodation for
> them.
>

> There are times when I need to *upgrade* some of these mutable objects,
> and this approach has proven to be quite flexible. It also plays nicely
> with code generators.
>
> Some people may disagree with this approach, but I have been using it ever
> since: return interface for mutable objects, return structs for immutable
> objects.
>

I am one of those who disagrees. I have not seen any benefit from having
interfaces for data objects other than making other developers happy. In my
opinion, this amounts to emulating another language in Go. There are cases
where this might make sense, but as a general principle, I think it should
be avoided. Data is data. There are no implementation details to hide.



> On Tuesday, August 9, 2022 at 3:09:10 AM UTC+7 t...@timpeoples.com wrote:
>
>> I can't speak to the *auto-generated swagger client* case but I believe
>> gRPC is still doing things the right way -- in that the framework defines
>> an interface I (the framework API consumer) then implements.  IOW: I don't
>> see that as a "java style interface" (where the interface defines the API
>> contract).
>>
>> I suspect you and I are saything the same thing.
>>
>> t.
>>
>> On Monday, August 8, 2022 at 12:51:29 PM UTC-7 bse...@computer.org wrote:
>>
>>> On Mon, Aug 8, 2022 at 12:51 PM Tim Peoples <t...@timpeoples.com> wrote:
>>>
>>>> I don't necessarily consider the "multiple implementations" case as
>>>> being truly preemptive -- if there really are multiple implementations
>>>> (e.g. the "hash" package from the standard library).
>>>>
>>>> I'm much more concerned about interfaces that are defined by an API
>>>> producer -- for one and only one impl -- and then adding a bunch of extra
>>>> (often autogenerated) code to deal with that.
>>>>
>>>
>>> Like a gRPC client/server, or auto-generated swagger client/server?
>>>
>>> I've had many instances where such an auto-generated client had to be
>>> passed down components that have no knowledge of those services. Writing
>>> such components using interfaces declaring only parts of those service
>>> implementations have benefits. An example that I can think of is an
>>> audit-trail service that deals with recording transaction metadata, looking
>>> them up, etc. It makes sense to write components that use only the writer
>>> part of that service, instead of requiring the whole thing. It makes
>>> writing tests easier. It lets you decouple services better, add
>>> adapters/interceptors etc.
>>>
>>>
>>>>
>>>> t.
>>>>
>>>> On Monday, August 8, 2022 at 11:02:31 AM UTC-7 bse...@computer.org
>>>> wrote:
>>>>
>>>>> On Mon, Aug 8, 2022 at 11:17 AM Tim Peoples <t...@timpeoples.com>
>>>>> wrote:
>>>>>
>>>>>>
>>>>>> For years I've read the old adage, "Accept interfaces, return
>>>>>> structs" and have spent years working to instill this understanding among
>>>>>> my colleagues. I gathered a great many skills while learning Go (and
>>>>>> acquiring readability)  back in the day -- and one of the strongest of
>>>>>> those is the idea that interfaces should be defined by their consumer
>>>>>> instead of an API producer -- but I've now been away from Google longer
>>>>>> than I was there and I'm beginning to suspect that the general consensus
>>>>>> among the *Go Literati* may have shifted around some things -- like
>>>>>> preemptive interfaces.
>>>>>>
>>>>>> My arguments against preemptive interfaces have recently run into
>>>>>> more and more pushback  -- especially among the influx of developers 
>>>>>> coming
>>>>>> from the Java and/or C# world who seem to continually reject any notion
>>>>>> that Go should be any different from the way they've always done things.
>>>>>>
>>>>>> This has recently come to a head with a brand new job (I'm 3 weeks
>>>>>> in) where virtually all of their services are built atop a dependency
>>>>>> injection framework having a data model with dozens (if not hundreds) of
>>>>>> preemptive interfaces and my initial, cursory review tells me the 
>>>>>> codebase
>>>>>> is at least an order of magnitude more complex that it needs to be.  
>>>>>> (Note,
>>>>>> I was told that none SWEs at this company (other than myself) knew any Go
>>>>>> before they started).
>>>>>>
>>>>>> So, my questions to the group are thus, "Should I even care about
>>>>>> this at all?  Are preemptive interfaces now considered the norm with Go?
>>>>>> Or, should I just shut up and crawl back into my hole?
>>>>>>
>>>>>
>>>>> I believe both approaches have their uses. What you call preemptive
>>>>> interfaces can be effectively used to hide implementation details where
>>>>> multiple implementations can exist. This approach can coexist very well
>>>>> with interfaces defined by the consumer. For example we have services that
>>>>> are written to implement an interface, so it becomes a logical deployment
>>>>> unit. Then we have consumers of that service that define parts of the
>>>>> interface service implements, so the consumer is not dependent on the
>>>>> complete service, and we can add any interceptors/filters.
>>>>>
>>>>> However, I agree with your assessment that especially newcomers tend
>>>>> to choose the traditional "interface is a contract" approach. In addition
>>>>> to the effect of other languages, people seem to like "clean 
>>>>> architecture".
>>>>> Nevertheless, even with people dedicated to clean architecture, the idea 
>>>>> of
>>>>> "interface parts" seems to resonate, especially when you show that you can
>>>>> define an interface on the consumer side that combines parts of multiple
>>>>> "contracts".
>>>>>
>>>>>
>>>>>>
>>>>>> TIA,
>>>>>> Tim.
>>>>>>
>>>>>> --
>>>>>> You received this message because you are subscribed to the Google
>>>>>> Groups "golang-nuts" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>> send an email to golang-nuts...@googlegroups.com.
>>>>>> To view this discussion on the web visit
>>>>>> https://groups.google.com/d/msgid/golang-nuts/f4777928-875d-4c0a-a4a7-9fb57bf9d51fn%40googlegroups.com
>>>>>> <https://groups.google.com/d/msgid/golang-nuts/f4777928-875d-4c0a-a4a7-9fb57bf9d51fn%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>> .
>>>>>>
>>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "golang-nuts" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to golang-nuts...@googlegroups.com.
>>>>
>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/golang-nuts/34469b98-c37e-4a1d-af13-729b639a71ben%40googlegroups.com
>>>> <https://groups.google.com/d/msgid/golang-nuts/34469b98-c37e-4a1d-af13-729b639a71ben%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/3774ae88-45ea-4181-909d-f18c788c7395n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/3774ae88-45ea-4181-909d-f18c788c7395n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMV2RqrP9Jy2mYhYtxo2zjjwJyMyVb8RakKwyKDaiuKwJy%3DTpw%40mail.gmail.com.

Reply via email to