I'm Sorry -- when I said "readability reviewer" I was referring to a very 
google-specific term about how they ensure the author of a change 
understands the language they're writing. Granted, it's been a while since 
I worked there but, at that time, each change request (aka MR, PR, etc...) 
required approval from (1) a code owner and (2) someone with *readability* for 
the language in question -- and, if the author covered both of those, an 
"LGTM" from someone else was still required (i.e. *Minimum Two Brains*). 
Regardless, no code change could be submitted without someone with 
*readability* being involved (either the author or a reviewer).

Each language had their own procedures about how *readability* would be 
granted. For Go, each and every CR from a non-readability SWE would get 
assigned to a random *readability reviewer*  to ensure the code meets 
certain standards and is *idiomatically Go.*  It took me ~15 months and 
just under 60 CRs to get Go *readability* (compared to 4 months and 3 CRs 
for Python).

On Tuesday, August 9, 2022 at 1:08:42 PM UTC-7 bse...@computer.org wrote:

> On Tue, Aug 9, 2022 at 1:52 PM Tim Peoples <t...@timpeoples.com> wrote:
>
>> Yeah, I'm with Burak on this one. The interface usage you're describing 
>> Henry is exactly the kind of thing I'm talking about.  While on the surface 
>> it may seem advantageous -- in fact, I also tried writing Go that way when 
>> I first started -- my *readability* reviewers at Google did well to 
>> enlighten me about the many problems this can cause with Go -- some of 
>> which rog was kind enough to enumerate.
>
>
> I think "readability" is not the right metric to use here. "Code 
> comprehension" (comprehensibility?) should be the right metric. Readability 
> does not always imply it can be easily comprehended. Java is readable, but 
> not necessarily comprehensible. I argue that Go code is more comprehensible 
> than code written in most other languages, because you can understand all 
> the implications of the code using mostly "local knowledge", that is, 
> knowledge you can gain by reading pieces of code "close" to the point of 
> interest. Wherever you have interfaces, you need non-local knowledge to 
> understand what's going on.
>
>  
>
>>
>> Also, since originally posting this yesterday, I've come to learn that my 
>> new shop is not only utilizing preemptive interface definitions but also a 
>> complete dependency injection framework and rather strict adherence to 
>> *Clean 
>> Architecture*™ 
>> <https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html>
>>  
>> -- (likely from the scripts in this repo 
>> <https://github.com/thnkrn/go-gin-clean-arch>) which goes a long way 
>> towards explaining why so much of the code looks like Java written in Go 
>> syntax.
>>
>> On Tuesday, August 9, 2022 at 8:33:07 AM UTC-7 bse...@computer.org wrote:
>>
>>> On Mon, Aug 8, 2022 at 11:27 PM Henry <henry.ad...@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...@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...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/e8bc57a6-bcee-4904-82f6-f52cdf371b6bn%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/golang-nuts/e8bc57a6-bcee-4904-82f6-f52cdf371b6bn%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/3f44f55e-853c-4bbd-991f-e7abc339a2b0n%40googlegroups.com.

Reply via email to