Skip to content

Go development

Go is small on purpose. It is very good at services that hold a lot of connections open, move a lot of data, and ship as a single file with nothing to install beside it. It is mediocre at systems whose value is a thick pile of business rules. Which one you have decides the language.

01Capabilities

Four service shapes where a small language pays for itself

Go, often written Golang because that is what people type into a search box, earns its place where handling many things at once, deploying simply and behaving predictably matter more than expressive power. These are the four shapes of work where we would propose it, and between them they account for almost every engagement we take on here.

  • Gateway

    The service everything else arrives at

    Services that hold many connections open, sit in front of several systems behind them, and have to stay uneventful under load. Handling many things at once is cheap to write here, and a single file with nothing to install is cheap to deploy and cheap to roll back when a release goes wrong at four in the afternoon.

  • Intake

    High-volume intake that must not lose events

    The workload behind fleet tracking in logistics and transportation or charger readings in EV charging platforms. The engineering is what happens when the far end slows down or a batch is delivered twice, not the reading of the messages themselves.

  • Adapters

    The connective layer between systems that never met

    Translators, adapters and long-lived connections between things that were never designed to talk to each other. This is platform integration work in the cases where how much memory and startup time the connector uses is part of the requirement.

  • Tools

    Internal tools your own team runs

    Migration utilities and command-line software for operators, built once per platform with nothing to install first. That property is why Go quietly took this category over. We build these under an ISO 27001:2022 certified information-security management system.

02Fit

Choosing between a plain language and an expressive one

Go is a deliberate trade: fewer language features in exchange for fast builds, easy handling of many things at once, and one file to ship. That trade is excellent for plumbing-shaped software and poor for rules-shaped software. Five of the six rows below end somewhere other than a Go project with us.

Six situations, and what we would tell you in each
Your situationWhat we recommend
Many callers at once, a simple set of rules, and simple operation matters more than elegance Use GoThis is the case the language was designed around, and it holds up in production rather than only in benchmarks.
A thick set of business rules, many of them, changing often We argue againstThe language gives you less help describing rules, so C# or Java will cost less per change over a decade.
The product is data science, analytics or machine learning We argue againstThe library ecosystem is not there, and pretending otherwise costs a quarter. Our Python page covers that side.
A hard limit on response time, with no room for the occasional pause Different pageOur Rust page. Go's automatic memory cleanup is good, and it is still cleanup, which shows up as an occasional pause.
A small team, all of them fluent in TypeScript, and one product between them Usually Node.jsOur Node.js page. One language across the whole product beats a better one when there are five of you.
You want to split a working system into small Go services because Go is fast Stop firstFind the actual bottleneck. Changing language and architecture together means you cannot tell afterwards which of the two helped.

Scope

What we own here is how the service handles many things at once, and everything downstream of that. What happens when a caller gives up, what gets retried, and how the service behaves when one dependency is slow. Also whether your own team can operate it, rather than only the people who wrote it. We run that work under an ISO 27001:2022 certified information-security management system, alongside ISO 9001:2015. unicrew has been building software since 2012, with 100+ senior in-house engineers across six countries. If the honest recommendation is a smaller change to what you already run, that is what you get.

Go is a good answer when the thing you are building is mostly network and concurrency, and when you want a new engineer productive in a fortnight. It is a weaker answer when your problem is a rich domain model, because the language deliberately gives you fewer ways to express one. That constraint is the point, and it is also the reason we would sometimes argue for something else.

Oleksandr TrofimovChief Technology Officer, unicrew

03Delivery

Settling the four decisions the language will not take for you

Go's plainness moves most of the design out of the language and into these four places. We settle them early because all four are expensive to retrofit and cheap to agree at the start.

  1. Fix what the service owns, and what it never touchesThe boundary and the exact shape of what it exposes, written down before any code. Go makes it easy to spin up more services than you need, and a fleet of chatty little programs is worse to operate than the single system it replaced.
  2. Decide once how work is cancelled and retriedWhat times out, what is retried, how deep a queue is allowed to get, and what happens when a caller walks away. Runaway workloads are the two failures we see most often in inherited Go, and both are design choices rather than bugs.
  3. Make failures and measurements first-classErrors carrying the context you will want at three in the morning, structured logs, and measurements on the paths that saturate first. Nothing here does this for you, which means it is a decision you take deliberately or by accident.
  4. Keep the list of outside dependencies shortThe standard library first, with a written reason for every outside package that goes in. This is not purism: the cost of running a Go service for five years is mostly the cost of keeping its dependencies current.

04Stack

What a service like this is deployed into

The decisions that usually arrive with a service like this, each with its own page if that is the one you are actually taking.

05Questions

Asked when a team is sizing the learning curve

Answered the way we would answer them live. If yours is not here, it is a good first message.

Yes, and it is a reasonable arrangement when you own the roadmap and want more delivery capacity. What we will not do is supply developers into a design nobody is accountable for, which is how a Go project becomes fifteen services and one shared database. Boundaries get reviewed by an architect outside the delivery team, and the work goes through the same QA practice as our own projects. Capacity is managed teams; an outcome is custom software development.

Go for volume, Rust for control. If the requirement is handling many callers at once with a team that can be productive quickly, Go is the cheaper answer and raw speed will not be your bottleneck. If the requirement includes a response-time ceiling that an occasional pause would breach, or code running somewhere with nothing installed at all, that is Rust. The tie-breaker is usually who has to maintain it.

Probably not for the reason you are thinking. Language rarely causes the pain people attribute to it: the usual causes are how the database is queried, calls that should have been queued, and releases that cannot be made independently. If measurement shows the runtime genuinely is the constraint, we would carve out the hot path as one Go service rather than bet the roadmap on a full rewrite.

The standard library for most services, with a small router where the routing is genuinely complicated. What ships with the language is good enough that most frameworks add opinions rather than capability, and every one you adopt is an upgrade obligation for as long as the service lives. Where your team already standardised on something, we work inside that choice instead of introducing a second one.

Less than most language changes, and it is still a real line item. Go is deliberately small, so an experienced engineer can read it almost immediately and the review culture transfers. What takes longer is the judgement about cancellation, retries and shutdown, because those are decisions rather than syntax. We would rather pair on those directly with your people than hand over a codebase and a link to the documentation.

A scoping call with an engineer. For a new service we want to know what it talks to and what its real load looks like, because that decides whether Go is even the interesting question. For an existing one we ask for the repository and whatever measurements you have. What comes back is written and specific. Most engagements start within two to four weeks.

Three shapes, and which fits depends on how settled the scope is. Time and materials is billed hourly and quoted per project, which suits work still moving. Fixed price is outcome based and quoted per project, and we only offer it after the first read, because a fixed number on a system nobody has opened is a guess. Team extension is billed monthly per engineer, and the rate depends on the seniority mix, so it is quoted rather than listed.

Weighing a new service against the one you already run?

Tell us what it has to do and what it has to talk to. You will get a straight recommendation, including the version where we tell you Go is not the interesting decision here.

Book a scoping call

Thank you

Thanks for your message. We will get in touch with you shortly.