Skip to content

Introducing Go to a .NET Organization

Hero

The Question

You introduced Go to a .NET organization. How did you get buy-in and manage the risk of adding a new language to the stack?

The Technical Justification

We had specific needs that Go addressed better than .NET. Most of our software consisted of containerized background processes or CLI tools. Our CLI tools needed to run on multiple operating systems—Windows, Mac, and Linux—and across different architectures like amd64 and arm. Cross-compiling and distributing .NET applications for all these platforms was cumbersome.

For our background processes, we regularly needed to implement concurrent processing, and Go's built-in concurrency model made this straightforward. Container image storage costs money, and Go's single-binary executables meant way smaller images compared to .NET apps with all their runtime dependencies.

For these use cases, Go hit the sweet spot of performance, deployment simplicity, and concurrency.

The Organizational Context

Fortunately, I didn't need to fight an uphill battle for organizational approval. Go was already well-established in other teams under my director's organization, so I only needed buy-in from my own engineers. The question wasn't whether Go was acceptable to the company, but whether my team would embrace it.

The Resistance

There was initial reluctance from the team. They had primarily been .NET developers throughout their careers and were quite comfortable doing things the "Microsoft way." This wasn't irrational resistance—it was natural concern about stepping outside their expertise.

One of my Staff Engineers had a specific complaint about Go's error handling approach, which is actually a common criticism even among seasoned Go developers. It was a legitimate technical concern, not just resistance to change.

My Approach to De-Risking

I chose a low-risk pilot project approach. As part of our continuous improvement of MIDS—our identity platform—we were working to separate the operational and management APIs from the core authentication functionality. This was a perfect pilot: valuable to the business, but not mission-critical if something went wrong.

I selected one of my Staff Engineers to lead this pilot—someone who was respected by the team but also skeptical about Go. I wanted him to form his own opinion through hands-on experience.

I was deliberate about how I set it up:

First, I had him design the service using language-agnostic terms. I wanted to ensure we had good architecture regardless of the implementation language. Once I approved the design, I worked with him on realizing that design using Go best practices and working within Go's very opinionated approach to software development.

I didn't create a template at first. Instead, I advised him when he had questions and steered him toward more idiomatic Go when reviewing his PRs. I wanted him to learn how to implement concerns like configuration, observability, and project layout firsthand—to understand why certain patterns exist, not just know how to use them.

Handling the Concerns

When he complained about Go's error handling, I acknowledged it as valid. I told him it sometimes irritates me too. I also pointed out that he had things he didn't like about .NET as well. No language is perfect—that's why there are so many of them.

The key was acknowledging his concerns as legitimate while keeping the focus on trade-offs rather than looking for a perfect solution.

The Outcome

The pilot was successful. We deployed it to production and started using it with some of our own internal admin tools. We didn't open it up to other teams since maintenance and operational processes were our responsibility anyway.

What happened next was the most important part: the Staff Engineer who led the pilot admitted he actually liked Go after all. He particularly appreciated the built-in tooling and how much easier unit testing was compared to what he was used to. He went on to voluntarily use Go for other tasks.

Because this engineer was highly respected by the team, once he gave Go his stamp of approval, the team was sold 100%. The other engineers became excited to start using it. I didn't have to push adoption—social proof from a trusted colleague did the work for me.

After the pilot, I developed project templates for RESTful services and CLI tools with built-in observability. I waited until after the pilot so the first engineer had firsthand experience with the underlying concerns. That understanding meant he could mentor others and make informed decisions when the template didn't fit a use case.