> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Understanding Codebases with Claude

> Demonstrates using Claude Code to explore, diagnose, and fix concurrency and architecture issues in a Retro Racer JavaScript frontend and Go backend codebase.

Now there's a powerful capability you can use with [Claude Code](https://learn.kodekloud.com/user/courses/claude-code-for-beginners): analyze and modify a medium-to-large codebase directly from your terminal or IDE. This lesson walks through using Claude Code to explore, diagnose, and fix issues in a real example repository — Retro Racer: a JavaScript / Three.js frontend with a Go backend handling multiplayer game logic over WebSockets.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/Xs8Ruv7b0QCZf7iM/images/Claude-Code-for-Beginners/Introduction/Understanding-Codebases-with-Claude/understanding-codebases-claude-demo-kodekloud.jpg?fit=max&auto=format&n=Xs8Ruv7b0QCZf7iM&q=85&s=b045e690ba58f4d47a073b0eb12da61b" alt="A presentation slide titled &#x22;Understanding Codebases with Claude&#x22; with a large &#x22;Demo&#x22; label on a dark curved panel at the right. A small &#x22;© Copyright KodeKloud&#x22; appears in the bottom-left." width="1920" height="1080" data-path="images/Claude-Code-for-Beginners/Introduction/Understanding-Codebases-with-Claude/understanding-codebases-claude-demo-kodekloud.jpg" />
</Frame>

## Getting started — launching Claude in a repo

Launch Claude from a terminal inside the repository. When it starts, Claude will list the permissions it requires (reading files, executing commands). For repositories you control, granting those permissions enables deeper analysis and automated edits.

Typical actions Claude can help with:

* File analysis and navigation
* Applying edits across many files
* Running builds and tests
* Executing bash commands and git operations
* Integrating with editors like VS Code

Example: initial prompt and tips shown by Claude Code

```text theme={null}
Enter to confirm · Esc to exit

* Welcome to Claude Code!

/help for help, /status for your current setup

cwd: /Users/jeremy/Repos/RetroRacer

Tips for getting started:

1. Run /init to create a CLAUDE.md file with instructions for Claude
2. Use Claude to help with file analysis, editing, bash commands and git
3. Be as specific as you would with another engineer for the best results
4. ✓ Run /terminal-setup to set up terminal integration

✳ Tip: Cmd+Escape to launch Claude in your IDE

> Try "refactor <filepath>"

? for shortcuts
```

### Terminal setup (VS Code integration)

Run `/terminal-setup` to configure terminal keybindings and IDE integration; for example, Claude can install a Shift+Enter terminal snippet shortcut in VS Code:

```text theme={null}
> /terminal-setup
└ Installed VSCode terminal Shift+Enter key binding
See /Users/jeremy/Library/Application Support/Code/User/keybindings.json
```

<Callout icon="lightbulb" color="#1CB2FE">
  Tip: Only allow trusted code execution for repositories you control. Claude may propose running build or test commands; grant them when you expect the tool to read or modify source files.
</Callout>

## High-level overview — Retro Racer at a glance

Ask Claude for a high-level summary to quickly map the project structure and tech stack. Below is a consolidated example output Claude might produce.

Table: Project structure and tech stack

| Area | Notes / Example files |
| - | - |
| Frontend | JavaScript web client using Three.js<br />`index.html`, `main.js`, `multiplayer.js`, `connection-manager.js`, `SkidMarkSystem.js`, `ui-helpers.js` |
| Backend | Go server with WebSocket multiplayer logic<br />`backend/main.go`, `server/`, `game/`, `network/`, `config/` |
| Build / Tooling | Vite for frontend development and bundling; `go` toolchain for backend |
| Testing | Jest (frontend), Go testing (`go test`) for backend |

Technology summary

* Frontend: JavaScript ES6+, Three.js
* Backend: Go 1.23.2 with Gorilla WebSocket
* Communication: WebSocket real-time messages (JSON-based)
* Concurrency: goroutines + channels, mutex for critical sections

This high-level map helps direct deeper analysis (e.g., where to inspect WebSocket handling, game loop, or client registration flow).

## Exploring the Go backend architecture

Ask Claude to "Explain the main architecture of the Go backend app" and it will analyze key files (for example: `backend/main.go`, `server/server.go`, `hub.go`, game logic files) and produce a focused summary. Key architecture points from the Retro Racer example:

* Event-driven hub model: a central hub manages client registration, inputs, and broadcasts.
* Concurrency model relies on goroutines and channels for inter-goroutine messaging.
* Fixed game tick (60 Hz) for deterministic physics and state updates.
* Separate channels for registration, input, and broadcasting.
* Mutex-protected shared state for critical sections.
* Per-client goroutines for read/write operations over WebSocket.
* JSON-based message protocol mapped to Go structs.
* Designed for small lobbies (current config: up to 8 players per hub).

## Finding database usage

When prompted to locate DB access, Claude can scan `go.mod` and the codebase. In this Retro Racer iteration Claude found:

* No database dependencies in `go.mod`
* No SQL or DB imports in Go files
* Game state stored in-memory (e.g., `game/state.go`)
* Logs written to `retroracer_server.log` (file-based logging)

## Log analysis — diagnosing runtime issues

Claude can scan logs to surface errors and suspicious patterns. Example issues detected in `retroracer_server.log`:

1. Player-client map synchronization problem
   * Example: `[DEBUG] Removing player 1748150421520079300-2524 from players map - no client found`
   * Symptom: players removed immediately after joining → indicates race between registration and sync.
2. Client count discrepancy
   * Example: `[DEBUG] Broadcasted updated player list to 0 clients` while players exist.
3. Phantom heartbeat messages
   * Heartbeats arrive from connections that appear removed in internal state.
4. WebSocket connection events
   * Normal disconnects (`close 1001`), but timing suggests premature cleanup.

Root cause summary

* The server used two separate maps: `clients` (connections) and `players` (registered player state). A synchronization routine compared them and could remove a player before registration finished, causing a race across goroutines handling WebSocket reads/writes and hub synchronization.

## Suggested fixes — make registration atomic and use a single source of truth

Claude recommended the following high-level changes to resolve the race condition:

* Move to a single canonical map (e.g., `clients`) representing active connections.
* Introduce a registration flag on each `Client` (e.g., `registrationComplete bool`) protected by a mutex.
* Route registrations through the hub's main event loop using an atomic registration message so the hub owns state transitions.
* Ensure helper methods (e.g., those that build player lists) ignore clients with `registrationComplete == false`.
* Mark registration complete only after the client sends the join message and the hub processes it.

Example change: atomic registration channel and message

```go theme={null}
// In server.go or hub.go (conceptual)
type registrationMessage struct {
    client *Client
    done   chan bool
}

// Hub struct addition:
type Hub struct {
    // ... existing fields
    registerClient chan registrationMessage
}

// Hub main loop:
case regMsg := <-h.registerClient:
    h.handleAtomicRegistration(regMsg.client)
    regMsg.done <- true
```

Example change: Client registration flag and mutator

```go theme={null}
// In server/client.go (conceptual)
type Client struct {
    // ... existing fields
    registrationMutex    sync.Mutex
    registrationComplete bool
    registeredAt         time.Time
}

func (c *Client) MarkRegistrationComplete() {
    c.registrationMutex.Lock()
    defer c.registrationMutex.Unlock()
    c.registrationComplete = true
    c.registeredAt = time.Now()
}
```

Rationale: by centralizing registration state and updates inside the hub event loop, you avoid cross-goroutine races tied to separate maps and ad-hoc synchronization.

## Implementing and validating fixes

Claude can apply edits across files, then run builds/tests to validate compilation. Typical iterative flow:

1. Apply code changes (add flag, remove redundant map, add registration channel).
2. Run `go build` and fix compilation errors caused by removed symbols.
3. Update all call sites to use helper methods that respect `registrationComplete`.
4. Re-run `go build` or `go test` until successful.

Example build interaction where Claude runs a build:

```bash theme={null}
# From backend/
cd /Users/jeremy/Repos/RetroRacer/backend && go build .
# If successful, Claude reports:
# Build successful!
```

Iterative compile-fix cycle

* After initial edits, Claude reported compile errors where code still referenced the removed `players` map:

```text theme={null}
server/hub.go:377:23: h.players undefined (type *Hub has no field or method players)
server/multiplayer.go:97:16: s.defaultHub.players undefined (type *Hub has no field or method players)
...
```

* Fix: update those call sites to use the single `clients` map plus helper functions that only include `registrationComplete == true` clients when producing player lists.

Final validation

* Once references were updated, Claude re-ran the build:

```bash theme={null}
go build . && echo "Build successful!"
# Build successful!
```

## Result and reasoning

Before:

* Dual maps (`clients` vs `players`) and separate synchronization logic left a window where a connection existed in `clients` but the corresponding `player` entry had not been created — sync logic sometimes removed the (not-yet-registered) player, causing inconsistent behavior.

After:

* Single source of truth (`clients`) plus `registrationComplete` semantics ensures:
  1. Client connects → added to `clients` with `registrationComplete = false`.
  2. Helper methods and broadcasts ignore incomplete registrations.
  3. Client sends the join message → hub marks `registrationComplete = true`.
  4. Client appears in game state and broadcasts.
  5. Reduced race surface and more predictable multiplayer behavior.

## Summary — what Claude Code adds to your workflow

Claude Code can:

* Inspect large repositories and produce architecture summaries.
* Locate files and code paths relevant to a bug (e.g., WebSocket flow).
* Scan logs and surface likely root causes for runtime anomalies.
* Propose concrete code edits (concurrency fixes, event loop updates, struct fields).
* Apply edits and run builds/tests to validate fixes iteratively.

In this Retro Racer example, the root cause was a synchronization race caused by duplicated state. The recommended fix — a single source of truth plus atomic registration via the hub — reduces race conditions and stabilizes multiplayer behavior.

## Next steps — choose how you want to proceed

* Show the concrete diffs Claude produced (file-by-file).
* Walk through a safe minimal patch you can manually apply.
* Run unit/integration tests to validate behavior under simulated multiplayer clients.

If you'd like, we can dive into any of these next steps: produce the diff, create a manual patch with step-by-step instructions, or write tests to reproduce and validate the race condition and the fix.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/claude-code-for-beginners/module/0bd6d2b4-0fbf-4c4d-a348-af6c3321121c/lesson/709c4c9d-b735-4e66-b0bc-01f48971bdb3" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.