DEV Community

Manuele Conti
Manuele Conti

Posted on

I stopped trusting step-by-step debugging for complex state

If you’ve ever stepped through code for minutes only to realize

you still don’t understand what your program looks like in memory,

you already know the problem.

Most debuggers are great at answering:

“What line of code am I on?”

But many real-world bugs don’t live in control flow.

They live in state.

When step-by-step debugging breaks down

Traditional debuggers start to struggle when you deal with:

  • deeply nested data structures
  • pointer-heavy models
  • complex object graphs
  • non-trivial runtime relationships between variables

In these cases, stepping line by line gives you movement,

but very little understanding.

The code executes correctly —

the data shape doesn’t.

That’s the gap qddd tries to explore.


qddd: visualizing program state, not just execution

qddd is an experimental Qt-based graphical debugger frontend

focused on understanding runtime program state.

Instead of treating variables as flat text trees,

qddd aims to represent:

  • object relationships
  • pointer connections
  • nested structures as actual structures

The goal is simple:

Make complex runtime state easier to reason about.

Under the hood, qddd communicates with GDB via the Machine Interface (MI)

and keeps a strict separation between the debugger backend and the UI layer.

⚠️ Experimental project

APIs, internal models, and UI are still evolving.

Screenshot

qddd main window

UI and layout are still evolving as the project develops.


Understanding the graphical state view

One of the core ideas behind qddd is treating runtime state as a spatial structure, not just a textual list.

The graphical variables view is built around a few key concepts.

Variables as nodes

Each top-level variable is rendered as a node:

  • the header shows the variable name and, when available, its memory address
  • the body shows its internal structure
  • complex variables can be expanded and collapsed incrementally

This mirrors how data actually exists in memory:

objects containing other objects, not flat name/value pairs.

Each node is an independent visual unit that can be moved, inspected, and compared spatially.


Hierarchical state with controlled expansion

Inside each node, variables are displayed as structured rows:

  • nested variables are indented, not flattened
  • expansion is explicit and local
  • pagination is used to avoid vertical explosions for large structures

This is intentional.

The goal is to preserve shape, not to show everything at once.

You expand state only where it matters, keeping the mental model stable.


Pointer relationships as edges

When a variable represents a pointer and its target can be resolved, qddd draws an edge between nodes.

This turns invisible relationships like:

  • object references
  • linked structures
  • shared or aliased data

into explicit visual connections.

Instead of mentally resolving addresses and dereferencing values, you can see how objects relate to each other.

This becomes especially useful when debugging graphs, trees with back-references, or complex ownership models.


State over execution

This view is intentionally not step-centric.

You don’t watch values change line by line.

You stop execution and ask:

“What does my program look like right now?”

The canvas, zooming, panning, and free layout support this kind of inspection.

You navigate state space, not instruction flow.


Why focus on state-first debugging?

Most debuggers optimize for execution flow:

  • breakpoints
  • stepping
  • stack navigation

But many bugs come from:

  • invalid object relationships
  • corrupted graphs
  • broken invariants inside complex structures

qddd flips the usual question.

Instead of:

“How did execution get here?”

It asks:

“What exists in memory at this moment?”

Execution control becomes secondary to state comprehension.


What qddd is not

To set expectations clearly, qddd does not aim to:

  • replace a full IDE debugger
  • compete on feature parity with IDEs
  • optimize for beginners

qddd targets developers dealing with

complex in-memory state where textual inspection is insufficient.


Project status

qddd is a work in progress:

  • features are incomplete
  • internal models are evolving
  • UI is experimental

At this stage, conceptual feedback and discussion

are more valuable than bug reports.


Source code

The project is open source on GitHub:

👉 https://github.com/manux81/qddd

Feedback, ideas, and prior-art pointers are very welcome.

If you’ve struggled with understanding complex runtime state,

I’d love to hear how you approach it.

Top comments (1)

Collapse
 
manux81 profile image
Manuele Conti

Happy to discuss tradeoffs or similar approaches you’ve used to understand complex runtime state.