When I started teaching, I thought my job was to know the material. Know it cold. Know it forward and backward. Be ready for every question. What I learned instead is that knowing something and explaining something are two very different skills.
That realization followed me back into software development.
In the classroom, I could solve a problem in my head in seconds. But when I tried to explain it the same way I solved it – jumping steps, skipping assumptions, compressing logic – I would lose half the room. The students weren’t confused because the material was impossible. They were confused because I had teleported from A to D and forgot to walk them through B and C.
Code works the same way.
When I look at a function now, I don’t just ask, “Does this work?” I ask, “Could someone else understand this without me narrating it?” That question has reshaped how I write everything – from variable names to comments to how I structure logic.
Early in my development journey, I wrote code the way many of us do at first: clever, compact, and slightly smug. One-liners that technically worked. Conditionals nested inside conditionals. Variable names like x, data2, and tempVal. It functioned. It even felt efficient.
But it wasn’t explainable.
Teaching taught me that clarity beats cleverness every time. If I wouldn’t present a math solution to students without showing my steps, why would I ship code that hides its reasoning?
Instead of this:
if (u && u.a && u.a.length > 0) doThing(u.a[0]);
I’ve learned to lean toward something like this:
if (!user) return;
const userAddresses = user.addresses;
if (!userAddresses || userAddresses.length === 0) return;
const primaryAddress = userAddresses[0];
processPrimaryAddress(primaryAddress);
Is it longer? Yes.
Is it clearer? Absolutely.
If another developer opens that file six months from now, they don’t need to roll an Investigation check to figure out what’s happening.
Teaching also trained me to anticipate confusion before it happens. In a classroom, you start to notice patterns. There are moments in a lesson where students almost always stumble. Fractions. Word problems. That one algebraic step where signs flip and chaos erupts.
Code has those same “trip points.” Async logic. State updates. Off-by-one errors. Data transformations.
Now when I write something even slightly tricky, I pause and ask: where would someone misunderstand this? That’s usually where a short comment belongs – not narrating the obvious, but clarifying the intent.
// We subtract 1 because array indices start at 0,
// but the UI displays positions starting at 1.
const selectedIndex = userSelection - 1;
That comment isn’t decorative. It’s preventative teaching.
Another lesson from the classroom: don’t assume prior knowledge. In education, we call this scaffolding. You build understanding layer by layer. You don’t start with abstract theory; you start with something concrete.
I’ve found this mindset invaluable when working with junior developers or even just explaining my own work in a pull request. Instead of saying, “I refactored the state management for performance,” I try to explain what changed and why:
I separated data transformation from rendering so the component doesn’t recompute values on every re-render. This makes the UI more predictable and easier to test.
That explanation isn’t just helpful for others. It forces me to validate my own reasoning. If I can’t explain the change clearly, I probably don’t understand it as well as I think I do.
Teaching also humbled me. In the classroom, if students consistently don’t understand something, the answer isn’t, “They just don’t get it.” The answer is usually, “I need to explain it differently.”
The same is true in code reviews. If multiple people struggle to follow a function, it’s rarely because they’re incapable. It’s usually because the code could be clearer.
That shift – from defending my implementation to improving its clarity – has made me a better collaborator.
And then there’s the storytelling piece.
Good lessons have narrative flow. There’s a beginning, a middle, and an end. Code benefits from that same structure. A well-written function tells a small story: we receive input, we validate it, we transform it, we return a result.
When functions get too long, it’s like a campaign session that never ends. No checkpoints. No clear objective. Just wandering through logic forests hoping we eventually stumble upon the exit.
Breaking large functions into smaller, purpose-driven pieces doesn’t just improve testability. It improves readability. Each function becomes a scene. Each variable a named character with a clear role.
And here’s the subtle D&D truth I’ve come to appreciate: not every developer at the table has the same stats. Some are stronger in architecture. Some in UI polish. Some in performance tuning. Writing explainable code is how we support the whole party.
Clear naming, thoughtful structure, intentional comments – those are the bardic inspirations of software teams. They don’t change what the code does. They change how well everyone else can use it.
Ultimately, teaching taught me that explaining is not an afterthought. It’s the work.
Whether I’m standing in front of students, writing a blog post, submitting a pull request, or building a small feature, the goal is the same: reduce cognitive load. Make the path visible. Respect the reader.
Because someone will read your code. It might be a teammate. It might be a future employer. It might be you in six months wondering what past-you was thinking.
Write it so they don’t need a map, a torch, and divine intervention to understand it.
That’s the lesson I carried from the classroom into development: don’t just solve the problem.
Explain it.



