Inside the Belly of the Beast: Building Teamwork Desk


August 26, 2014. The day a repository was created for a product that would soon become the support tool that would drive the industry forward: Teamwork Desk.

On March 26, 2015, at approximately 3:00pm in Cork, Ireland, Teamwork Desk was announced to the world. In just eight short months, Teamwork Desk was transformed from an idea to a full-fledged product, already seeing over 5,000 signups. Though in getting it to the market, there were some lessons to be learned, many of the decisions early on have proven themselves to be catalysts for success.

The Stack

> 33,272 lines of Golang;
> 15,642 lines of CoffeeScript; Socket Servers; Haproxy Load Balancer cluster; Redis Clusters; 20 MySQL Shards; SpamAssassin;

I could go on and on about the stack that Desk is built on top of. It really is in many ways a thing of beauty to bring all of the complexities and components together in creating a product built to scale and handle the demands of customers surrounding the globe. But even in the midst of all of those technologies, we have found it to be the day to day decisions that make the biggest difference for the long-term health of the product, as well as developer happiness. Over the next several blog posts we will be highlighting a few of the paradigms that we feel have given us the biggest wins and allow us to rapidly and confidently build Desk for the long term. Today’s topic is function arguments in Go.

Function Arguments

If you are a programmer (or have even seen code in the wild), I’m sure you have seen signatures that look like this-

Seemed like a good idea at the time, right? Wrong. One of the biggest decisions that we made in Desk was to, as frequently as possible, build functions that would accept a custom type. This changed the game for us. Now most of our function signatures look similar to func (someObj *ObjectWithPower) DoSomthing() (result ResultType, err error). This provided three distinct benefits-

  1. Cleaner method signatures
  2. Optional values are much easier to handle
  3. ApplyDefaults

Wait. ApplyDefaults? What is that you ask? ApplyDefaults is another GoodIdea that came from custom data types (often structs) being passed around from one function to another. Many languages use the concept of a constructor or initializer. Golang has make and new, but they don’t exactly give you the control to set defaults, just to initialize memory. So that is where ApplyDefaults comes in for us. Almost all types in our code base have the ApplyDefaults method on them which gives us better control, more safety, and generally ensures that the code stays DRY.

So what exactly is ApplyDefaults? In most cases it would look something like this-

This approach, in my opinion has quite a bit more power and use than the NewPerson approach that many people use because it allows us to ensure the integrity of the data at any point in the lifecycle, not just at instantiation time.

The Product

Though we love the technical decisions we have made and the team of amazing programmers that we have, what we love even more is that Desk is set up to deliver amazing results to our customers day after day, month after month, and year after year. We have a product that is a joy to work on and, as such, will quickly become more of a force to be reckoned with.

That leads me to two final thoughts- first, if you are interested in hearing more about the Desk roadmap, make sure to follow our blog over at, and finally if all of this talk of code gets your spidey senses tingling, get in touch with us! We are always looking for talented developers to join us in building software that powers the world.