Feeling Safe with people but not with the code
We often see and try to make teams and workspaces welcoming and safe for people to express their thoughts and ideas, no judgement, you can be yourself and share how you feel with others. This is also expected for you to be proactive and tackle problems and come up with solutions and ideas!
But this might not be the same for your systems, imagine you’re assigned to work on a critical part of your company’s codebase. As you stare at the entangles lines of code, you start to get nervous because you remember this part is complex and can affect other parts of the system, and a small but familiar sense of dread builds. It’s not because you lack the skills, but because the code itself is fragile—a minefield where a single change might explode into unexpected consequences. And often you don’t know here and when it will creep out.
Psychological safety—the belief that one can take risks without feeling insecure or embarrassed—is crucial for effective teams. While we often focus on team dynamics, we must also consider the code itself. Bad code, inflexible design, and poor documentation are more than just technical debt—can become psychological burdens.
Code that no one wants to mess with
We all have faced a codebase that feels like a bully that any tweak you make, you might get punched in the face with a new obscure edge case bug. From my experience this codes usually either are clever and not clear or seems like a patchwork of many developers that passed by, each learning a little more of the code and trying its best to solve the problem at the time. Also one tool that developers use to go around this problems is to create new abstractions over the current one to “make it easier” instead of tackling the root cause.
“Unsafe code” not only is a problem for engineers to deal with but also to the business as developers become afraid and unsecure to change it, making new features and evolving the solution become a slow and uncertain problem. Giving estimations become harder, as well as onboarding new engineers to the code base, this way sometimes making the more senior engineers doomed to always work in the codebase instead of working with the business to come up with new solutions and ideas. They become babysitters of a never-ending problematic system.
How to make it less bad?
I don’t have an answer to don’t have this systems, they will always be there and happen, due to tight timelines or just many people over the years working on the same system. But some things I’ve seem to ease this process
Debugging tools
Having good debugging tools and tracing mechanisms that is easy for the developer to mimic production state or isolate some parts of the system to be able to test it and evaluate the expected behavior of the application. I’m used to Clojure, and REPL debugging tools work as a charm! Another one is if you can, for complex systems be able to locally mock production systems, like a snapshot so you can bench test it with different scenarios and flows to know how the Blackbox magic system is behaving.
Modularized components
Modularizing code means breaking down large, interconnected parts into smaller, independent units that can be understood, tested, and modified easily. With clear boundaries, modular components lower dependencies and simplify the codebase. Developers can focus on specific pieces, making debugging, onboarding, and changes easier. This avoids tangled spaghetti code - because let’s face it, nobody wants to be lost in a pasta of nested loops and mystery sauce conditions.
Well written and descriptive tests
Tests, people many times create “Should work” tests, and having well descriptive tests like using the Gherkin Syntax and BDD approaches that makes understanding the code way easier and intuitive. Specially for Integration tests as they reflect how the world see our systems.
Documentation - can be even docstrings
Documentation doesn’t need to be 1-2-6 pagers documentation about a function or an endpoint. A well written docstring can many times be crucial for the developer working on the code understand how it behaves, docstrings shouldn’t be a Lib exclusive thing. Another tip is to leverage things like ADRs (Architecture Decision Records, post), as your system changes its good to have persisted the context and decisions taken over the time. ADRs can be less than a page and still be very impactful when providing support for teams, imagine it like a Git for all the decisions you take in your system!
Conclusion
Code quality isn’t just about efficiency or performance—it’s also about how the code makes developers feel. Safe code encourages contribution, experimentation, and confidence. It’s about keeping our systems running smoothly while ensuring that our developers thrive.
If you or your team feel like a repo or a part of the code is a wasp nest, its time to revisit it, because in an emergency you might need to go there and face the wasps 🫠
Any fool can write code that a computer can understand. Good software developers write code that humans can understand.
- Martin Fowler