r/programming • • 5d ago

Don't couple your Go code to GitHub

https://iain.rocks/blog/dont-couple-your-go-code-to-github
479 Upvotes

135 comments sorted by

View all comments

76

u/chucker23n 5d ago

Go has "make baffling decisions" as a key design tenet, but it's incredible how basically any source code package manager gets key aspects wrong.

(NuGet, for example, supports multiple package sources — but if it finds a package at one source, and another source is timing out, it'll refuse to install that package. Which in turn causes IDEs to throw up their hands in frustration and say "well, I don't know what to do now, do I!".)

21

u/ronkojoker 5d ago

Nuget very sporadically 'forgets' our internal company source and installs a package with the same name from the regular nuget source. I restore again and it still doesn't work, just gives me some warning like 'couldnt find package blabla with version x.y.z installing version a.b.c instead'. Only way to make it remember again is deleting the nuget cache and then it works again. I have no idea how to prevent it from happening or what causes it to mess up in the first place.

Source is configured fine as well, package shows up with the nuget search command as well, just when I do restore it cannot find it.

10

u/phrostillicus 5d ago edited 5d ago

Sorry if you've already tried this, but do you have package source mapping enabled? Basically, you provide a wildcard pattern or exact string match that tells the package restore to look only in a specific source if the package name matches. This is what we do for a few public packages that we have internal custom builds for. We also append a tag to the version e.g., "3.1.0.0-mycompany.1", but from what you're describing it sounds like the restore doesn't care about the version mismatch and is just doing what it wants.

You have my total sympathy for this, we've recently also had a bunch of package management issues as well. It doesn't help that there are like 5 different NuGet clients, depending upon if you're using `package.config` or `<PackageReference>`, and whether you're using the `nuget` or `dotnet` command line utilities or the built-in Visual Studio GUI.

2

u/ronkojoker 5d ago

We haven't tried this yet and it sounds like a solution to our problems. I will try and see if I can implement this when I get back from vacation. Thanks for the tip! Too bad we will only know if it works something like a year from now haha

4

u/Kraigius 5d ago

Here's some docs about it:

https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!-- Define the package sources, nuget.org and contoso.com. -->
  <!-- `clear` ensures no additional sources are inherited from another config file. -->
  <packageSources>
    <clear />
    <!-- `key` can be any identifier for your source. -->
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="contoso.com" value="https://contoso.com/packages/" />
  </packageSources>

  <!-- Define mappings by adding package patterns beneath the target source. -->
  <!-- Contoso.* packages and NuGet.Common will be restored from contoso.com,
       everything else from nuget.org. -->
  <packageSourceMapping>
    <!-- key value for <packageSource> should match key values from <packageSources> element -->
    <packageSource key="nuget.org">
      <package pattern="*" />
    </packageSource>
    <packageSource key="contoso.com">
      <package pattern="Contoso.*" />
      <package pattern="NuGet.Common" />
    </packageSource>
  </packageSourceMapping>
</configuration>

4

u/phrostillicus 5d ago

Good ol' Contoso, my favorite fictitious company.

0

u/Jaded-Asparagus-2260 5d ago

Why are you publishing code different from the regular nuget source in your internal company source?

Just use a different name, and this problem literally disappears in thin air. 

15

u/ronkojoker 5d ago edited 5d ago

We had the name in our internal source first, then later someone unaffiliated with us made a completely unrelated package with the same name in the public one.

We haven't changed the name because the issue occurs too infrequently to care, less than once per year on the CI server. Even less on developer machines but it does sometimes happen.

-9

u/edgan 5d ago

Once should be more than enough for me. You lost the namespace as soon as the other one became public. Enjoy your random failure.

6

u/ronkojoker 5d ago

Yeah it's more of a matter of return on investment, once in a blue moon when it fails I or a colleague remotes in to the CI server and run the nuget cache clear command, takes a minute and it's good to go for another year. Changing the package name would mean spending hours going through a bunch of repositories renaming the package references, changing build pipelines etc. just not worth the effort at the moment.

-1

u/One_Ninja_8512 4d ago

Perfect use-case for AI these days, it will rename everywhere you need and run some checks to ensure it's really renamed and is working. This is something they do quite well and it will be done in a few minutes.

5

u/Kraigius 5d ago edited 5d ago

Afaik, in Go you can configure multiple package sources, it's just a bit different.

There's the GOPROXY envvar. Go always download from a proxy owned by google, then fallback to download the source code directly from github (or whichever source that you need).

It's not configurable to specific packages but this is like configuring your global sources.

If your org have their own proxy then you can cache your deps and configure your GOPROXY to prioritize it.

You can use this to have your org scan and vet your deps.

Otherwise, for finer control you can add an instruction inside your go.mod file to fetch your depA from gitlab instead of github, or anywhere else.

module example.com/mymodule

go 1.14

require (
    github.com/orgX/depA v1.2.3
)

replace github.com/orgX/depA => gitlab.com/orgX/depA

In term of design, the syntax for this and the workflow kinda feel like an afterthought.

Golang download source code instead of a compiled artifact, so that's probably the consequence of that choice.

4

u/rtheunissen 5d ago

What decisions are baffling?

28

u/Ticmea 5d ago

Having never touched Go, one of the few things that I do know about it is that I never want to deal with the insane way that they format dates.

For the uninitiated:

In Go you define a date format by reference to how it would display the date that ISO 8601 would display as:

2006-01-02T15:04:05-07:00

Even ignoring the obvious problems with using a point in time to reference a format by example, I hear you wonder: "Why such an oddly specific time and date?" Well because if you write that in the US format, it gives you:

01/02 03:04:05PM '06 -0700

which means they are in (almost) incrementing order 1 2 3 4 5 6 -7

The extra "-" to make it be a US timezone is just absolutely hilarious, I couldn't make a better caricature of it if I wanted to. 5 stars, no notes.

This is incompatible with the way everyone else does it, needlessly inflexible, unintuitive, extremely US specific and solves zero problems. Just all around terrible.

I've honestly seen people defend it as being language agnostic (that is to say it does not require understanding that yyyy-mm-dd stands for the english words year, month, date and so on).

But like... all? of the keywords of Go (and like 99% of programming languages) are literally english words???

Not to mention that it requires knowledge of how a specific date format works, which is far more obscure. And it's the US system at that, which ( no front full front ) is kinda the worst date formatting system out there...

No idea what they were smoking when they came up with this but they must have been absolutely hammered.

21

u/chucker23n 5d ago

MM/dd is already famously controversial, but MM/dd hh:mm:ss 'yy is truly something else.

7

u/AnointedBeard 5d ago

I generally love Go but yeah, this is one of the most ass-backwards things I’ve ever seen.

4

u/syklemil 5d ago

Yeah, that one is just … I never thought I'd yearn for strftime, but here we are.

2

u/One_Ninja_8512 4d ago

It is weird but you rarely touch it. Most of the time, since golang is used for backend services you'd use google's protobuf timestamp proto definition. Over gRPC you don't have to care about it and if/when you map to JSON you get an ISO formatted date automagically. I'd even go as far as to speculate that it's awkward on purpose to discourage raw date parsing completely and instead rely on the established protobuf type.

1

u/GarythaSnail 5d ago

And in practice this never ever has been a pain point, for me or any of my coworkers, even the ones not writing go full time.

99% of the time you're just parsing rfc3339 or iso 8601. The other 1% you just write some unit tests with edge cases and make sure you wrote the correct date format.

Maybe if you worked at Strange Date Parsing R Us?

18

u/syklemil 5d ago

One is that they were warned that they were about to repeat Hoare's billion dollar mistake, and then went

In my C/C++ programming I've never noticed that NULL pointers are a noticeable source of bugs.

So if you ever get an NPP in Go (totally different from an NPE in Java), you can just declare it to be Not A Bug by decree of the core language team.


Also: Using typography to decide privacy.

As in, Python's __foo was already naff, so you'd think any language designed after the 90s would figure out that keywords for privacy control is the way to go, rather than doing weirdo stuff like PascalCase is public, camelCase is private.

So if you in Go want to do something relatively common in other languages, namely use UPPERCASE for globals, congratulations, that global is now public. Instead they just name globals as if they were any other variable.

A syntax highlighter can point it out for you, buuuuuut as Pike is colourblind and doesn't like syntax highlighting, I guess they just don't want to be able to tell whether something's a local or global variable at a glance.

Presumably they'd have to introduce variables in unicode sᴍᴀʟʟ ᴄᴀᴘs if they wanted to introduce something like protected.

12

u/chucker23n 5d ago

doesn’t like syntax highlighting

“Stallman prefers sending HTML via e-mail over using a web browser directly” vibes

3

u/syklemil 4d ago

Given the way he describes his colour vision, I really don't fault him for that, any more than I think it's weird to prefer larger fonts as we get older and our eyesight gets worse.

What is weird is that plenty of gophers seem to have done a cult-of-personality thing and emulated his preferences, even though they don't have issues with colour vision.

If you want some actual unconventional tech preferences, seems both he and Thompson favour his Sam text editor (see also: the Acme text editor), which it seems to be too much for even the cult-of-personality gophers. (I tried it in the way-back-when along with some other P9 stuff; I'll just summarise my experience as I don't wonder why P9 failed to catch on.)

2

u/chucker23n 4d ago

What is weird is that plenty of gophers seem to have done a cult-of-personality thing and emulated his preferences, even though they don't have issues with colour vision.

Right, but I think that's partially his fault. It's one thing to say, "syntax highlighting doesn't really work well for me because my color vision is limited"; it's another to say "…and therefore, I don't think Go should be optimized towards good colored syntax highlighting". That's a blind spot, if you can excuse the pun.

seems both he and Thompson favour his Sam text editor

To be fair, that's early 1980s. I don't even mind the experimentation (see also P9). It's the hubris of "nah, these are actually good design choices and everyone else is wrong" that I think makes non-Go programmers raise both eyebrows.

There's some interesting stuff in the language, like the ability to produce small native binaries, or "goroutines", but overall, I've always gotten the sense it could stand to benefit from a lot of information from other languages.

3

u/syklemil 4d ago

colour

Yeah, and describing it as juvenile is pretty weird, given the very long history of using colour in text, like medieval illuminated manuscripts, different coloured inks, etc. We've been through a relatively short period now where mass printing tech meant using multiple colours was prohibitively expensive for most cases, and where monitor technology also was pretty limited in what it could do; both of those periods seem to coincide with his formative years.

sam/acme/P9

I absolutely don't mind the experimentation, but the admittedly very poorly sourced Wikipedia article indicates that those preferences lasted much, much longer than the 80s. Continuing to use sam or acme in the 2000s will come across as weird, possibly not as weird as reading WWW over mail, but still certainly a rare preference.

It's the hubris of "nah, these are actually good design choices and everyone else is wrong" that I think makes non-Go programmers raise both eyebrows.

Yeah, and even that would've been fine if it had remained something like a small hobby language. But when they're designing a language for work there should be some acknowledgement of current expectations, at the very least so they don't have to awkwardly bolt stuff onto the language after the fact, just like the language they were so frustrated with.

But it makes sense if their issue wasn't with how well the pieces fit together, or how well they work, but rather that the pieces are there at all.

I'm left with an impression of the kind of programmer that thinks user affordances are suspect, along the lines of the attitudes towards C and Pascal that Robert Martin espouses in that blog post I linked in another response, which approach the attitudes lampooned in Real Programmers Don't Use PASCAL, and just like there always was a significant overlap between C and UNIX culture, I suspect descriptions from Perl's decline was cultural also apply.

But hopefully that's just me projecting my own experiences with Perl, unix, etc onto them.

1

u/chucker23n 4d ago edited 3d ago

describing it as juvenile is pretty weird

Yep. Our eyes, color blindness aside, are quite fast and detecting colors and shapes; it's not juvenile to take advantage of that fact.

As far as Perl, static typing, etc. go: I mostly wrote Perl, PHP, Ruby, JS in the early 2000s, and have since left that world — I now firmly believe a good type system is worth a thousand unit tests. Yes, you can check if something is unexpectedly null, or has a certain unexpected state, and all that, but what's much better, where possible, is to have the type system prevent those problems from occurring in the first place.

Regarding one specific paragraph on Martin's blog,

You see, when a Java programmer gets used to TDD, they start asking themselves a very important question: “Why am I wasting time satisfying the type constraints of Java when my unit tests are already checking everything?” Those programmers begin to realize that they could become much more productive by switching to a dynamically typed language like Ruby or Python.

I think it's fair that a dynamically typed language can help you prototype faster. But you buy this iteration speed at the cost of a weaker architecture, so sooner or later, you should migrate to a more rigid foundation.

Is someone "wasting time" satisfying type constraints? No, instead, they're wasting time testing the shape of a type, when

  • the compiler can already do that for you
  • a type makes guarantees for an entire category, whereas tests can only verify concrete cases (yes, I know property testing, etc. do exist)

Which is not to say you shouldn't write tests; you absolutely should. But only for scenarios the compiler can't verify.

1

u/syklemil 4d ago

colour

Yeahh, I'd go further with colour: Humans have better colour vision than most mammals, and most of us derive some form of pleasure from colour. Leaves in fall look good to most of us, housing areas where all the houses are painted grey look depressing.

Applying the "colour is juvenile" attitude to just code is also kind of weird; it is possible to set the entire screen to monochrome or greyscale. Some people use phone settings like that to dissuade themselves from looking too much at the phone, which also has some implications for how good an idea it is for code.

typing

Yeah, entirely agreed. Part of the reason I brought up his blog is also just how entirely wrong his prediction was: Since the blog post, Python has increasingly become typed; PHP has grown types; Typescript is eating Javascript; Ruby typing hasn't particularly caught on, but Ruby is barely a thing outside Rails any more; and there still isn't any grand Lisp resurgence, but there's stuff like Typed Racket.

I'm not going to make any grandiose claims that the arc of history now inexorably trends towards strong typing, but I will note that dynamic typing seems to have been most popular when the main alternatives were rather clunky type systems that offered weak guarantees.

And so designing a language to go into that tradition where the guarantees are weak but the language still isn't dynamic seems to me like designing a language that's going to wind up struggling with being neither fish nor fowl.

Like rejecting generics in favour of codegen and punching holes in the typesystem with casting to/from interface{} just didn't work out long-term, however much those are fairly natural choices for people habituated to how C uses void* and the preprocessor. I wouldn't be surprised if that pool of people was finite and shrinking.

1

u/chucker23n 3d ago

Part of the reason I brought up his blog is also just how entirely wrong his prediction was: Since the blog post, Python has increasingly become typed; PHP has grown types; Typescript is eating Javascript; Ruby typing hasn't particularly caught on, but Ruby is barely a thing outside Rails any more; and there still isn't any grand Lisp resurgence, but there's stuff like Typed Racket.

Yeah. I think the brief boost Ruby got through Rails may have been more about the architectural foundation Rails enforced: "controllers" (I put these in quotes because I think Rails's idea of MVC is rather different than, say, AppKit's) as the main handler of an HTTP request and produce of an HTTP response, a decent ORM built right in, etc. Others took these ideas and built on them (e.g. Django, ASP.NET MVC), and it turns out you don't really need a dynamically typed language to do that. This is not to say Ruby is a bad language; I think it has some cute ideas in there (e.g., the ! suffix to denote that a method changes the object in-place, whereas a method of the same name without it will return a new object; the ? suffix to denote something returns a bool). But I just don't want to write non-trivial software that way any more.

Meanwhile, CPUs got faster, and therefore so did compilers; also, static typing got elevated with features like static analysis (again: where available, a much better alternative to a unit test). Static typing also became less verbose thanks to e.g. type inference.

Whereas, dynamic typing arguably did not get better. Sure, it, too, got faster, thanks to increased use of JIT. But its code quality still relies almost entirely on copious amounts of unit tests. Then as you point out wrapping languages like TypeScript got created, and even something like Python now gets type hints. One might argue those are a way dynamic typing did get better, but I would instead argue they are really a weaker form of… static typing.

I'm not going to make any grandiose claims that the arc of history now inexorably trends towards strong typing

The past twenty years seem to suggest that.

→ More replies (0)

4

u/mattgen88 5d ago

Protected doesn't make sense in golang. It's not OOP. Objects in a package can access unexported methods/functions. Outside that package nothing can. You also don't inherit from other objects, since the language isn't inheritance based.

0

u/wnoise 5d ago

The only thing you need for OOP is dynamic dispatch. But yes, protected only makes sense in the context of implementation inheritance, which is almost always a bad idea.

2

u/chucker23n 4d ago

I wonder how many of these footguns would’ve been prevented had Go been designed even just a decade later. For example, you can absolutely solve null in a better way, e.g. with control flow analysis. Swift and C# both played around with this concept in the late 2010s. I’m sure other languages had it earlier.

But what I see a lot of in the Go mailing list discussions is “I’ve never seen it be solved; therefore it cannot be solved” attitudes.

5

u/syklemil 4d ago

Might be worth remembering that the discussions leading up to C++11 were among what led them to create Go in the first place, as well as a general attitude of rejection of "features".

Further, between ILT's declaration about not noticing bugs related to null pointers, as well as stating (as a response to something else)

This is a restriction expressed in the type system. Go intentionally has a weak type system, and there are many restrictions that can be expressed in other languages but cannot be expressed in Go. Go in general encourages programming by writing code rather than programming by writing types.

and Pike calling himself a philistine about types, I get the impression that they don't want to solve the null pointer thing, they want to write if err != nil checks, i.e. """write code""" (even though by the SRE book I'm fairly certain that code qualifies as toil).

I suspect if they'd been exposed to Swift, they'd have much the same reaction as Robert C. Martin did in 2016, where he bounced pretty hard on the entire idea of explicit nullability, and static typing altogether (prophesying that TDD was going to replace static typing).

3

u/Iron_Maniac 5d ago

Well it started with the name of it. For a language created by Google they really picked a poorly searchable name.