Golang project structures for independent teams: A better way to go

Golang project structures for independent teams: A better way to go Andrea Medda is a software engineer at Curve.


Working in small and independent teams can be tricky for engineers. In my experience as an engineer at Curve, a fast growth scale-up in the fintech sector, I’ve often found that different teams tend to use completely different approaches. This can make moving teams and cross-team communications a challenge. 

At Curve, we use Golang (or Go for short) for programming. Go is an open-source programming language that makes it easy to build simple, reliable and efficient software.

Working with open source language across multiple teams can present its own unique set of challenges. For instance, lots of problems can arise from differences in structure and conforming to different standards.  Trying to maintain high code quality standards while also ensuring every project follows best practices can be tough.

Sharing a defined project structure with the team can help overcome such challenges. It can also increase productivity when working with open-source languages such as Go. 

When this happens, all projects start to look more similar, which makes transitioning between teams much easier. It’s also easier for project members to contribute because experienced Gophers (that’s what we call our Go engineers) can learn what’s going on just by looking at the relevant file or directory.

A clearly defined project structure can also help new Go developers as it’s easier to follow established standards. New team members can make changes and replicate them across other projects without needing to learn how a service behaves. 

The question is, how do you go about achieving this in your organisation? 

There are two options at your disposal. The first involves using a framework such as go-kit or go-micro to suggest a structure and approaches. 

The advantages of using this type of framework include the availability of utilities straight out of the box (logging, tracing), and standards that have already been agreed in advance and shared openly with the community. There are some disadvantages to this method though.  The downside? Such frameworks come with lots of boilerplates and it can be difficult to make changes to core components. The fact that they’re managed by the community also means that binaries will have bigger sizes due to waiting too long for changes. 

The second option is simply to agree on a project structure at company level. By doing this, you get the freedom to use any approach or any library, can make quick changes, have smaller binaries and an easy to follow idiomatic Go. A potential disadvantage to this is that the company’s engineering culture must be mature enough to promote a process of agreeing and applying these changes. Such a long and tedious process might make fellow engineers question whether it's worth it, but some standards occur naturally and evolve over time, and there’s nothing wrong with revisiting agreed standards after finding out more. 

At Curve, we’ve chosen this second approach – which wasn’t without its challenges. For instance, the agreement process took several months, due to multiple meetings and lengthy discussions. In a fast growth company, this can hugely impact productivity levels. Having no clear framework has also meant that the team has had to manually implement elements that would usually be usable ’out of the box’ and, on occasion, there have been instances of accidentally replicated code across multiple services.

It was often a case of learning as you go and most decisions were made after receiving feedback from engineers based on their daily experience, keeping an eye on the community and researching what other successful Go based companies do. 

Adopting this method has led to major improvements over time. We’ve now set up a ‘Go Chapter’ to make Go related decisions, made up of a core team of engineers. They meet every couple of weeks to discuss relevant topics and vote on proposed adoptions of new standards. Every team then adopts it for all the new services and autonomously allocates time to refactor its project to follow it too.

When it comes to project structure, we discuss all topics multiple times before adopting them. We also revise and modify the process as many times as needed to ensure they meet business objectives.

So far, this new approach is working well for us. It means we can ship high quality and stable services more frequently, and it allows us to simplify handover. This makes it easy for all engineers to know what to do and how to solve problems and find bugs. 

However, we have also identified two drawbacks:

  • the refactoring of legacy services
  • replicating changes across existing services.

Regarding the latter, we recently reviewed our logging and monitoring strategy and had to “touch” all our services to follow it.

Maintaining this approach has been relatively straightforward so far. An engineer might find a new and better way of solving a service problem related to structure and code reuse. After experimentation and feedback from teammates, the engineer can propose it during the ‘Go Chapter’. 

A recent example of this is that we decided to split our transport levels based on the need for a service to use http rather than grpc or potentially both. We discovered a great way to facilitate this and it was approved.

This project structure might work for you too if your team or company are mature enough and willing to make mistakes to learn and improve your services. It requires clear communication and hard work but is ultimately worth the effort for a streamlined process. 

Interested in hearing industry leaders discuss subjects like this and sharing their use-cases? Attend the co-located 5G ExpoIoT Tech Expo, Blockchain Expo, AI & Big Data Expo, and Cyber Security & Cloud Expo World Series with upcoming events in Silicon Valley, London, and Amsterdam.

View Comments
Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *