DEV Community

Cover image for # Golang Beginner Mistakes: If You Know Every Field, You Probably Don't Need a Map
perez odiyo
perez odiyo

Posted on

# Golang Beginner Mistakes: If You Know Every Field, You Probably Don't Need a Map

When I first started learning Go, I discovered structs before I discovered maps.

So naturally...

Everything became a struct.

Need a user?

type User struct {
    Name  string
    Email string
}
Enter fullscreen mode Exit fullscreen mode

Easy.

Need application settings?

type Settings struct {
    Theme         string
    Notifications bool
}
Enter fullscreen mode Exit fullscreen mode

Still easy.

Need categories users can create themselves?

...

I still made a struct.

type Categories struct {
    Fitness string
    Reading string
    Coding  string
}
Enter fullscreen mode Exit fullscreen mode

It looked fine until someone wanted to add "Meditation."

Then another user wanted "Gaming."

Then another wanted "Cooking."

That's when it hit me.

Structs aren't meant to grow while your program is running.

I was using the wrong tool.


What a struct actually is

A beginner usually hears:

"A struct groups related data."

That's true.

But it misses the important part.

A better definition is:

A struct describes something whose shape is already known.

For example, every user in your application has the same fields.

type User struct {
    Name  string
    Email string
    Age   int
}
Enter fullscreen mode Exit fullscreen mode

You already know those fields before writing the program.

That's why a struct exists.

Think of it as a blueprint.

Every house built from the same blueprint has the same rooms.


What a map actually is

A map is completely different.

A map doesn't care what keys you'll use tomorrow.

prices := map[string]float64{
    "apple": 0.50,
}
Enter fullscreen mode Exit fullscreen mode

Later...

prices["banana"] = 0.30
prices["mango"] = 1.20
prices["orange"] = 0.75
Enter fullscreen mode Exit fullscreen mode

No problem.

Maps are designed for data whose keys are discovered at runtime.


The question that changed how I write Go

Nowadays, before writing any type, I ask myself one question.

Do I already know every field this data will have?

If the answer is yes, I create a struct.

If the answer is:

"Well...the user decides."

or

"It depends on the API."

or

"It depends on the environment."

I immediately reach for a map.

That one question has saved me countless rewrites.


⚠️ Beginner Mistake #1: Treating dynamic data like fixed data

Imagine you're storing HTTP headers.

A beginner might write this.

type Headers struct {
    ContentType  string
    Authorization string
    UserAgent    string
}
Enter fullscreen mode Exit fullscreen mode

Looks reasonable...

Until a request contains:

  • X-Request-ID
  • X-Forwarded-For
  • Or some completely custom header.

Now your program needs another field.

And another.

And another.

Instead, use a map.

headers := map[string]string{
    "Content-Type": "application/json",
}
Enter fullscreen mode Exit fullscreen mode

Now any header can exist without changing your code.

That's exactly what maps were made for.


⚠️ Beginner Mistake #2: Using maps because they feel flexible

Then comes the opposite mistake.

You discover maps.

They're cool.

They're flexible.

So suddenly everything becomes

map[string]interface{}
Enter fullscreen mode Exit fullscreen mode

Even users.

user := map[string]interface{}{
    "name": "Perez",
    "age":  22,
}
Enter fullscreen mode Exit fullscreen mode

This works.

But you've thrown away one of Go's biggest strengths.

Type safety.

This typo compiles.

fmt.Println(user["nmae"])
Enter fullscreen mode Exit fullscreen mode

Notice the spelling?

The compiler doesn't.

It happily runs your program.

Now compare that with

type User struct {
    Name string
}
Enter fullscreen mode Exit fullscreen mode
fmt.Println(user.Nmae)
Enter fullscreen mode Exit fullscreen mode

Go immediately says:

"Nope."

Compilation fails.

That's exactly what you want.

Let the compiler catch mistakes before your users do.


Structs and Maps Are Teammates, Not Enemies

One thing took me embarrassingly long to realize.

Structs and maps aren't competing.

They're usually used together.

A very common pattern is

type Product struct {
    Name  string
    Price float64
}

inventory := map[string]Product{}
Enter fullscreen mode Exit fullscreen mode

Notice what's happening.

The Product has a known shape.

The inventory doesn't know how many products exist.

One models an object.

The other stores a growing collection of those objects.

You'll see this pattern everywhere.

  • User sessions
  • Product inventories
  • Cache systems
  • Feature flags
  • Configuration
  • Backend services

Once you notice it, you can't unsee it.


Struct vs Map: A Quick Decision Guide

Situation Struct Map
Known fields
Unknown keys
Type safety
Dynamic user input
Real-world objects
Fast lookups by key

My Rule of Thumb

Whenever I'm unsure, I ask myself:

Can I confidently write every field name before running the program?

If yes...

➡️ Use a struct.

If no...

➡️ Use a map.

Simple.


Final Thoughts

One of my favorite things about Go is that it gives you only a handful of data structures.

That means learning when to use them matters more than memorizing how to use them.

I spent weeks treating every problem like a struct.

Then I spent weeks treating every problem like a map.

The sweet spot was realizing they solve completely different problems.

A struct answers:

"What is this thing?"

A map answers:

"How do I find this thing?"

Once that clicked, my Go code became much simpler.


Over to You

What beginner Go mistake took you the longest to understand?

I'd love to hear it in the comments. Chances are, someone else is struggling with the exact same thing.

If you enjoyed this article, consider following the Golang Beginner Mistakes series, where we break down the kinds of mistakes almost every new Go developer makes—and how to avoid them.

Top comments (0)