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 eitherNone
(no edge) orTreeNode
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 bothNone
, 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.
🧐 Mental Model: Nodes as Potential, Edges as Realized Links
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.