textlize pricing account
19. Rob Pike - What We Got Right, What We Got Wrong | GopherConAU 2023
Cover

00:47:21

Go at 14: A Retrospective on What Succeeded and What We Learned

On the 14th anniversary of Go's open-source launch, co-creator Rob Pike reflects on the project's original goals, its surprising successes, and the hard lessons learned in building a language for modern software engineering.

Beyond the Language: The Real Goal of Go

The creation of Go was not fundamentally about designing a new programming language. The team's primary goal was to create a better way to write software at scale. The frustrations that sparked Go's development—like a 45-minute build time for a single binary—stemmed from the complexities of the software development process, not the languages themselves.

Go was conceived as a project to make building production-grade server software easier and more productive. It aimed to solve problems like:

  • Controlling dependencies in large codebases
  • Programming effectively with large, evolving teams
  • Easing software maintenance and testing
  • Harnessing multicore CPUs and networking efficiently

The language was the enabler for these larger software engineering ideals, not the sole objective.

What We Got Right: Foundations for Success

Several early, deliberate decisions were crucial to Go's adoption and long-term health.

1. The Go Gopher: A Unifying Mascot

The creation of the Go Gopher by Renee French was a masterstroke. This "goofy yet intelligent" mascot became a powerful banner for the community, fostering a spirit of technical excellence and fun. It provided a shared identity for early adopters and remains an iconic symbol at conferences like GopherCon.

2. Core Technical & Community Choices

  • Formal Specification: Started with a precise spec, enabling multiple compatible implementations and locking down behavior.
  • Multiple Compilers: Ian Taylor's early compiler (based on the draft spec) proved the value of this approach, leading to a ecosystem of implementations (gccgo, llvm-go, etc.).
  • Trivial Cross-Compilation: Broke the assumption that a compiler is native to its host machine, a powerful feature for developers.
  • Strong Compatibility Guarantee: Go 1.0's promise of stability was a dramatic factor in its uptake, providing a rare island of stability in the software world.
  • Standard Library: Provided a solid, well-made toolkit for writing 21st-century server code, unifying the community around common solutions.
  • Tools & Fast Builds: The ease of parsing Go enabled excellent tooling. The `go` command integrated the entire build process, and Go's reputation for fast builds was a major attractor.

3. `gofmt`: A Cultural Touchstone

Robert Griesemer's `gofmt` was transformative. It showed that automated code formatting could be done well and became a non-negotiable standard. The time saved by ending debates over style is incalculable. Furthermore, `gofmt`'s implementation as a library enabled countless other tools, from simplifiers to the coverage tool.

What We Got Wrong: Lessons Learned the Hard Way

Even successful projects have missteps. A common theme was a failure in communication—the team thought their goals were self-evident, but they often weren't to the broader community.

1. Concurrency: A Powerful but Misunderstood Feature

Go played a significant role in popularizing concurrency in mainstream programming. However, two key mistakes were made:

  • Lack of Use Case Guidance: The team envisioned concurrency for server libraries (like `net/http`), but many newcomers struggled to see how it applied to their problems. They failed to explain that its primary value was in structuring server software.
  • Concurrency vs. Parallelism: The difference was not clarified early enough. Many programmers tried to make code faster by adding goroutines, only to be baffled by slowdowns. Concurrent code only speeds up when parallelized if the problem is intrinsically parallel (like handling HTTP requests).

This confusion likely drove some early adopters away. The 2012 talk "Concurrency is not Parallelism" helped but came too late.

2. Interfaces and the Long Road to Generics

Interfaces are one of Go's best-designed features. Their dynamic, implicit nature became the bedrock for composition, testing, and dependency management. However, their success "colored our thinking" and became a significant barrier to introducing generics.

The presence of interfaces meant any new form of polymorphism had to integrate with them seamlessly. This required multiple attempts, aborted implementations, and years of discussion. The eventual solution—a generalization of interfaces to sets of types—was subtle and profound, but the journey was long and fraught.

3. The Initial Compiler: A Pragmatic but Unpopular Choice

Writing the first compiler in C (in a Plan 9 style) was pragmatically the right choice for bootstrapping and rapid iteration. It allowed the team to implement novel features like segmented stacks quickly. However, this approach offended many in the language community who expected the use of LLVM or self-hosting from the start.

The translation to a Go-based compiler for Go 1.5 was the right eventual move, bringing all of Go's tooling advantages to the compiler's development. The lesson: use the best tool for the task at hand, even if it's unorthodox.

4. Engaging with the Open-Source Community

The transition to open source was a huge educational process. The team took too long to understand the best way to work with the community, leading to wasted time from mismatched expectations.

A key learning was around the team's insistence on high code quality through mandatory review before commit. This approach is more efficient but pushes more work onto contributors, who need to understand its value to feel welcome. This process has improved significantly over time.

5. Package Management: A Bumpy Road

The initial package design in the language was excellent. However, the transition to a world with external package versioning was poorly managed. The core team, familiar with Google's monorepo model, lacked experience with the complex problems of dependency graph resolution across many versions.

The process of engaging the community to solve this was well-intentioned, but the final design left many feeling slighted. The resulting system is technically excellent but took too long to arrive, and the journey was rocky.

6. Documentation: Showing, Not Just Telling

The team wrote extensive documentation but initially failed to grasp that the community wanted examples of how to use features, not just descriptions of what they did. This was eventually corrected, and the addition of the Go Playground—an online sandbox for running code snippets—was a massive improvement.

The Enduring Outcome: A Unified Ecosystem

The most significant consequence of Go's design choices is that Go code looks and works the same everywhere. It is largely free of factions using different language subsets and is guaranteed to compile and run for years to come. This combination of a strong standard library, concurrency, composition, fast tools, readability, and stability has created a uniquely consistent and productive environment for software development.

© 2025 textlize.com. all rights reserved. terms of services privacy policy