Skip to main content

I Thought in Graphs. I Just Didn’t Know How to Code Them.

🧠 I Thought in Graphs. I Just Didn’t Know How to Code Them.

I didn’t struggle with object-oriented programming. I got it right away.

And I loved graphs — visually. Conceptually. I naturally think in terms of connections, dependencies, and relationships.

But when it came to graph traversal — actually writing the code to walk through nodes and edges — I hit a wall.

Why?

Because I wasn’t thinking about nodes as self-containing structures, or about edges as properties that may or may not point somewhere. I saw the connections, but didn’t yet see the code for them.

This is the mental unlock that changed it all:

A node is a node.
A property on that node might be another node.
If that property is non-null — congrats, that’s your edge.

Suddenly, the system made sense.


📀 Visual Graphs vs. Traversable Graphs

I always saw graphs as diagrams:

  • Circles (nodes)
  • Lines (edges)
  • Directions, weights, relationships

I could sketch dependencies, data flows, semantic connections — no problem.

But turning those into code? That’s where the friction was.

Why?

Because I hadn’t internalized that in graph traversal code:

  • A node is literally an object that can contain more of itself
  • An edge is just a property that points to another node of the same type
  • If that property is null (or an empty list)? There’s no edge. It terminates naturally.
class Node:
def __init__(self, neighbors=None):
self.neighbors = neighbors or []

Here:

  • The node is structurally recursive — it contains references to instances of its own type
  • The edge is implicit — it exists only if that property is populated

Structural recursion doesn’t mean “calls itself.” It means “contains itself.”


🔍 Example: Nullable Properties as Optional Edges

Take a binary tree:

class TreeNode:
def __init__(self, left=None, right=None):
self.left = left
self.right = right

Here:

  • .left and .right are either None (no edge) or TreeNode instances (an edge exists)
  • This is a graph with directional edges to zero, one, or two children

The recursion isn’t running — it’s shaped.

If .left and .right are both None, then you're at a leaf node. There are no child nodes. Therefore, there are no edges.

Even though the object has .left and .right properties in its definition, those are placeholders, not actual connections.


A property like .left or .child is potential.

If it holds a node, it's an edge. If it’s null, it’s not.

In other words:

No node = no edge.

The edge only exists if it leads to something.

This helped me understand graphs in code like never before. Now, graph traversal feels like navigating a structure I already understood — just with the right framing.


✨ The Flexibility Unlock: Traversal as Pattern, Not Prescription

What used to trip me up about graph traversal was the sense that there was a "correct" pattern I had to follow: pre-order, post-order, in-order, etc.

These felt rigid and over-specified.

But once I internalized structural recursion, I saw that traversal is just a convention over a flexible structure.

You choose:

  • When to visit a node
  • What to do before or after visiting children
  • Which branches to skip

You don’t need to memorize the patterns — you can create them.

That freedom was a huge leap forward. It made traversal feel like an expressive tool rather than a ritual.


🌀 The Broader Realization

I had no problem understanding OOP. I could visualize graphs. I just didn’t see the connection between the structure of my objects and the execution of graph algorithms.

The moment I understood that:

Recursion is not always control flow. Sometimes it’s shape.

…everything started falling into place.


💡 Final Reflection: Build Your Own Entry Point

If you’ve written tons of code, understand OOP, and still feel weird when people say “model this as a graph” — you’re not alone. Maybe you just haven't yet stumbled upon the structural recursion concept.