random musings on software development and management

Large software project maintenance, the Go way

Rob's Pike's presentation at the SPLASH ACM conference includes a few great insights into maintaining large software projects.

Go was created to solve real and immediate problems at scale. It is not a research language.

Go was not built to test theories or implement research ideas. It was developed in reaction to specific problems identified in the C++ and Java development Pike saw at Google.

Code generation and languages that rely on formatting for syntax (python) don't mix well.

Python's whitespace syntax has always seemed fragile to me. The difficulty faced at Google's scale must be immense. Rather than a fault of the language, this seems more of a tools deficiency. If python had a tool like gofmt that worked at the lexer/parser level, this would likely not be an issue.

C like languages are approachable by the largest number of current and future developers.

Lisp, Erlang, and other non-C-like languages may be expressive, but at the expense of approachability. Go's familiar syntax allows it to be approachable by the largest number of developers.

"Exponentially smaller means exponentially faster."

Nothing more than optimization 101 - do less to be done sooner. The presentation gives some great comparisons between C++ and Go compile times that highlight Go's superior approach to handling #includes.

"Dependency hygiene trumps code reuse."

At some point, updating object oriented software projects that use a lot of inheritance becomes a game of Jenga. The risk of changing decisions made at the start of the project becomes increasingly difficult to mitigate as they are now buried under years of accumulated code.

The lack of default function arguments helps with API clarity.

I agree with this in theory, but this is too easy to circumvent. I wonder if it would have been better to officially support this rather than force those that really want to do this to roll their own potentially inconsistent solution.

Adding exported names to packages cannot break code that uses that package.

To properly evolve and maintain any codebase, you have to be able to make changes at all levels of the codebase in a predictable manner. Go takes this very seriously.

Errors are normal, not exceptional. Think about them and deal with them when they arise.

In my experience, most developers simply to not have enough experience writing "system" code that has to work 100% correctly despite the seemingly pathological behavior of other applications, networks, and hardware. Once you have this experience, the error becomes the expected expected return value and the focus of the code. It makes sense for Go to force the issue considering its focus as a "systems" language.

Coding conventions enforced via tools - effective due to built in lexer/parser in the std library. Use gofix modules to update existing code to align with changes in APIs.

Gofmt and gofix are simply amazing. The recognition that core libraries might need to change, and the foresight to include the ability to automatically address these changes into the core itself will go a long way towards ensuring Go succeeds. I can think of many examples on my own projects where I could have used gofix to make painful refactoring faster and safer. Every language should have these tools.

tags: golang