Live data from Hacker News

Practical Go: Real-world advice for writing maintainable Go programs

dave.cheney.net

131–140 of 237 posts

Re: Practical Go: Real-world advice for writing maintainable Go programs

#131

I don't understand something. > 5.1. Consider fewer, larger packages > 5.2. Keep package main small as small as possible If you have one package, which is the main package, then how are you supposed to keep it small, and at the same time not creating more packages because somehow that is the work of the devil? He is telling me to try to fit everything into one package, but at the same time keep it really small. It is…

In golang packages named "main" are special. They're not importable and they correspond to a single executable.

If you want to be able to reuse code in different packages in the future or have more than one compiled binary, you won't be able to put everything into a single "main" package

Re: Practical Go: Real-world advice for writing maintainable Go programs

#132
post #35

> Naming the Config parameter config is redundant. We know its a Config, it says so right there. > In this case consider conf or maybe c will do if the lifetime of the variable is short enough. This seems petty. Is it really that problematic to type out a few extra characters?

Yeah, I used to go by this advice, and I found the maintainability of my code dramatically increased when I typed out full names. I don't even use "i" for loop variables anymore. If the length is a problem, invest in an editor with autocomplete. Well-known abbreviations are fine, like "iter" and "prev", but single-letter variable names notoriously impede readability for me.

Readability is a problem -- long variable names are harder to skim, and rapidly begin to blur together for me.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#133
post #71

About half-way through and I think this is a great article, in particular the quotes and I also agree that the first 4 sections are generally applicable. One thing I disagree with is the remark about having fewer, big packages. Though conceptually I agree that avoiding having too many public APIs that aren't widely used makes sense, in practice --at least on the types of projects I tend to work on--I find that direct…

I often find myself wishing Go either allowed import cycles between packages, or allowed namespaces within a package. Because they can become unwieldy.

For example, a common convention is to avoid redundancy. Let's say you have a package "builder". Your encouraged to have "builder.New()" as a constructor, not "builder.NewBuilder()". Fine. Now let's say you need two types of builders: One for building "schemas", one for "objects". Your original constructor now needs to be something like "builder.NewSchemaBuilder()" ("NewSchema" would be confusing, since the function creates builders, not schemas). Or maybe turn it into a verb: "builder.BuildSchema()", "builder.BuildObject()". Part of this is due to the lack of statics, or we could've had "builder.Schema.Build()" or something.

You can also split the package up into two packages, one for schema building and one for objects. (Naming here can be tricky, too. Will it be "schemabuilder.New()", or "schemas.NewBuilder()"?) But if the two builders need to share types, you may end up refactoring the common types into a common package that exists only because of the split.

I have a concrete example of this right now for a small query language. The language has data types (common interface Type) and values (Value). Values can tell you their type. Types can construct values. But they're two distinct sets of declarations. The type implementations and the value implementations can't easily be split across separate packages without having a common package that exists only to hold the shared types. It'd be nice to have "types.String" (in types/string.go) and "values.String" (values/string.go), not "lang.StringType" (lang/string_type.go) and "lang.String" (lang/string.go).

Having a namespace option would help here. Everything could be in one package, but under separate namespaces.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#134
post #9

Came from Java world, I find the Go comment and godoc are really limited. We can't link between functions, types. We don't have a standard way to declare input, output, don't have any distinction between a normal word and a Go identifier Refactoring using tool (e.g: Goland) usually lead to unexpected text replacements. Take following functions, for example: // Auth check if user credential is existed in bla, bla... /…

You should put the docs for AuthProvider on AuthProvider, not on Auth or AuthDefault.

I agree. If the documentation seems duplicated, chances are the code is too. Worded oppositely, if the code is duplicated, chances are the documentation is duplicated or repetitive. Both the documentation and the main logic it describes should live in one place.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#135
post #9

Came from Java world, I find the Go comment and godoc are really limited. We can't link between functions, types. We don't have a standard way to declare input, output, don't have any distinction between a normal word and a Go identifier Refactoring using tool (e.g: Goland) usually lead to unexpected text replacements. Take following functions, for example: // Auth check if user credential is existed in bla, bla... /…

You should put the docs for AuthProvider on AuthProvider, not on Auth or AuthDefault.

You didn't get my point. Of course the doc should be long to where it should. In this case, I want the doc for my base function is easier to be discovered from the helper functions.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#136
So I don't know how to fly a commercial airliner, but I could probably figure my way around a small single prop airplane. That's basically the difference between Go and a language like Rust or C++ or any language that requires a lot of up front investment, but then let's you work at power level 9000.

So yeah, Go will get you there. It will take you a lot longer to get there when you aren't going 600MPH, and you can carry a lot less people, but at least you aren't driving a car like the people using Python. Sure it's probably not going to be as rigorously inspected as the Boeing borrow checker, but Go is at least getting an inspection, whereas your Python code is just going to break down on the side of the road when the problems surface itself because you didn't check the oil light.

To me, Go is a better Python. It's easier to learn, faster, more scalable, and safer, and just as easy and quick to write. It's just not a language for big projects.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#137

Earlier quoted context omitted.

This is one reason I like nested functions. They’re not available to the surrounding scope so they don’t succumb to these weaknesses, while also allowing you to organize your very long function internally by task. I use ‘em in Python all the time. It’s a bummer that more languages don’t support them, though you can get there with lambdas too, sometimes at the cost of more syntax.

GNU C supports nested functions as an extension. I use them for the exact reasons you mention.

That extension results in executable stack memory, which is going to be a non-starter for many developers.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#138

So I don't know how to fly a commercial airliner, but I could probably figure my way around a small single prop airplane. That's basically the difference between Go and a language like Rust or C++ or any language that requires a lot of up front investment, but then let's you work at power level 9000. So yeah, Go will get you there. It will take you a lot longer to get there when you aren't going 600MPH, and you can c…

But Go will never be a data science language like python, because Go is too limited to express that domain.

Python may leave you in the lurch when it comes to maintainability, but for some domains python is infinitely better than Go.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#139

So I don't know how to fly a commercial airliner, but I could probably figure my way around a small single prop airplane. That's basically the difference between Go and a language like Rust or C++ or any language that requires a lot of up front investment, but then let's you work at power level 9000. So yeah, Go will get you there. It will take you a lot longer to get there when you aren't going 600MPH, and you can c…

i'm riding that car for nearly a decade and never needed to pull to side. you can't ride a plane without airports, but you can travel to everywhere with a car - because roads are everywhere.

Re: Practical Go: Real-world advice for writing maintainable Go programs

#140

Earlier quoted context omitted.

I could not disagree more. When I'm skimming code, I want to immediately know what a variable means. I don't want to go cross-reference elsewhere.

If you have to go "cross-reference" elsewhere you are modifying something "to far away" from you. That's a giant sign of spaghetti code. Also names vary with there contextual scope. Larger scopes mean longer names generally. Russ Cox gives a succinct description here: https://research.swtch.com/names A name's length should not exceed its information content. For a local variable, the name i conveys as much informatio…

> For a local variable, the name i conveys as much information as index or idx and is quicker to read

This is only true because i is a specific, common abbreviation for index. When writing arbitrary glue code, a single letter variable would be a meaningless abbreviation without shared context. If you encounter "i" and it doesn't mean "index of a for loop", you're going to be taking additional time parsing meaning.

Post reply on HN