In chapter 1 we said Go stays small on purpose. That single idea explains almost every difference you will notice coming from another language. This chapter goes one level deeper: the specific design choices behind Go, what they buy you when you build backend services, and an honest look at where Go is the wrong tool. No code yet, just the mental model you will lean on for the rest of the course.
Go's designers had a rule that sounds almost too simple: when there is an obvious way to do something, the language should offer that one way and stop there. Most languages grow by adding features. Go grew by saying no.
That choice ripples outward into a few concrete goals:
When something feels missing in Go (you may catch yourself thinking "where are the ternary expressions? where is inheritance?"), the missing feature is often deliberate. The team left it out to keep the language small and the code predictable. You will not always agree with those calls, and that is fine. Knowing they were calls, not oversights, makes the language easier to learn.
If you are coming from Python, JavaScript, or Ruby, the first real difference is that Go is compiled and statically typed. Compiled means your code is turned into a single machine-code program ahead of time rather than interpreted line by line as it runs. Statically typed means the compiler knows the type of every value (int, string, your own struct) before the program ever runs, so a whole class of mistakes gets caught at build time instead of in production.
That usually sounds like more ceremony, and in some typed languages it is. Go softens it with type inference. You can write count := 0 and Go figures out that is an integer; you do not have to spell the type out every time. So you get the safety of static types without most of the typing that usually comes with them.
countIf you are coming from Java or C#, Go will feel lighter for a different reason. It is typed and compiled like those languages, but it skips a lot of what makes large codebases in them feel heavy: no class hierarchies to design, no generics-everywhere, far less boilerplate. The result sits in a comfortable middle: as safe as a typed language, but quick to write like a scripting language.
One more thing in this bucket: Go is garbage collected. You create values and the runtime cleans up memory you are no longer using. You do not manually free memory the way you would in C or C++. For backend work this is the right default, and you rarely have to think about it.
This is the difference that changes how you ship software, so it is worth slowing down on.
When you build a Go program, the output is usually one file: a static binary. Static here means it bundles everything it needs to run, including the Go runtime and the libraries it depends on, into that single executable. There is no separate interpreter to install on the server and no folder of dependencies to copy alongside it.
Compare that to a typical interpreted or JVM app. To run it on another machine you usually ship your code plus the language runtime (the Python interpreter, the JVM) plus all the third-party libraries it imports. Those pieces have to be present and at the right versions, or the app will not start.

Here is why this matters in practice, and we will live it later in the course:
A small honesty note so the simplification stays safe: Go binaries are static by default, but you can opt into dynamic linking in certain situations (for example, some libraries that call into C). For the kind of pure-Go backend service we build here, the one-file mental model holds.
Modern backends spend most of their life waiting: waiting on the network, waiting on a database, waiting on disk. To stay fast, a server needs to handle many requests at the same time. Concurrency is the ability to make progress on lots of these tasks at once, and Go was built around it from day one.
In many languages, doing many things at once means reaching for an external library, a thread pool, or an async framework that was added on top of the language later. Go puts the tools in the language itself:
go in front of a function call. Goroutines are cheap, so a program can run thousands of them at once, and Go's runtime schedules them onto a small number of operating-system threads for you.Here is the payoff that matters for this course, and it is mostly free: Go's built-in HTTP server runs each incoming request in its own goroutine. You write a handler as if it deals with one request, and the server quietly runs many of them concurrently. We will look at goroutines and channels properly in the language section, but this is the headline: handling load is something the language helps with, not something you bolt on.
Every team that writes code eventually argues about style. Tabs or spaces? Where do the braces go? How long can a line be? These debates burn real time and settle nothing.
Go's answer is a tool called gofmt that formats your code to one canonical style automatically. It ships with Go, most editors run it every time you save, and the whole community uses it. The effect is that essentially all Go code in the world is formatted the same way.
For a beginner this is quietly wonderful. You never have to decide how to format anything, you never get a code review comment about spacing, and any Go file you open online looks like the code you write. One less thing to learn, and one less thing to argue about.
No language is good at everything, and pretending otherwise would not help you. So here is the honest version, starting with the strengths.
Go is an excellent fit for:

Now the other side. These are real, and knowing them up front will save you frustration later.
Error handling is verbose. Go does not use exceptions for ordinary failures. Functions return an error value, and you check it explicitly, so you will write if err != nil { return err } a lot. The upside is that every place something can fail is visible in the code, which makes Go programs easy to reason about. The downside is that it can feel repetitive at first. Most Go developers come to appreciate the clarity, but it is fair to find it noisy on day one. We cover this model carefully in its own chapter.
Generics arrived late and are used sparingly. Generics (writing one function or type that works for many types) only landed in Go 1.18, released in March 2022, more than a decade after the language launched. They work well, but the community uses them lightly rather than everywhere. If you come from a language where generics are central, Go's restraint here can feel limiting.
It is not the tool for every job. Go is a poor fit for heavy data science and machine learning, where Python's ecosystem dominates, and it is not a natural choice for desktop GUI applications. Picking the right tool means knowing where a language does not shine, and these are honest gaps.
The minimalism frustrates some people. The same small feature set that makes Go easy to learn can feel restrictive once you know it well. Developers who love expressive, feature-rich languages sometimes find Go too plain. Whether that is a strength or a weakness depends on what you value. For learning backend development and shipping reliable services, the simplicity tends to help far more than it hurts.
None of these trade-offs should scare you off. They are the cost of the design choices that make Go great at building backend services, which is exactly what you are here to do.
You now know what makes Go different and where it fits. Next we take a bird's-eye tour of the Task API you will build across this course, so you can see the destination before we start writing code.