The Developer’s Blind Spot

From the ivory tower of our IDEs, it is easy to mistake a clean pull request for a successful product. We spend weeks architecting “perfect” systems, only to be blindsided when users find them confusing or irrelevant. In our frustration, we often ask, “How stupid are these users?” But this question exposes our own ignorance.

Software does not exist in a vacuum; it exists in a high-pressure human context. Your user isn’t just an abstract “actor” in a use case. They are a person with a job to do—often while a customer is yelling at them or while they’re fumbling with a physical paper invoice. When we focus purely on the computer, we neglect the reality of the person behind it. To build truly resilient software, we must adopt an “Outside-In” philosophy. We stop building systems and start solving human problems.

BDD Is About People, Not Systems

Traditional Behavior-Driven Development (BDD), as originally articulated by Dan North, focuses on “system behavior.” While that was a necessary step away from raw TDD, a “People-First” approach is more radical and more effective.

The shift from technical output to human outcome changes everything. Consider a ride-sharing app. A system-centric view focuses on GPS coordinates and API pings. A human-centric view recognizes the anxiety a commuter feels while waiting for a ride. The technical output is a map update; the human outcome is peace of mind. As I often say:

“Nobody gets up in the morning and says, ‘Oh, I’m going to spend eight hours today using that system.’ The rest of the world is like, ‘No, I have a job to do.’”

This philosophy is enforced through the story structure: “In order to [achieve value]…” This is the soul of the story. If the “In order to” statement doesn’t resonate with the business stakeholders or solve a tangible human pain point, we don’t even look at the code. The technical implementation must remain a servant to value.

Considering Other Paths

Most development teams obsess over the Happy Path (everything works) and the Angry Path (handling errors). However, an important driver of business results is often found in the “Forgetful Path.”

Think of an e-commerce customer who abandons their cart because they got distracted by another browser tab. This is a human behavior—distraction—that directly impacts the bottom line. By identifying these behaviors during the BDD process, we can prioritize features like automated reminders or targeted coupons.

More importantly, the Forgetful Path acts as a prioritization tool. When a story becomes too complex, we don’t just “power through” the technical debt. We identify the scenarios—like the forgetful user—and move them into separate stories. This allows the Product Owner to decide whether that specific human behavior is worth the investment now or should remain in the backlog, keeping our Bounded Contexts clean and our delivery focused.

True Decoupling: The Marten Evolution

One of the most powerful indicators of a successful Outside-In approach is “stress-free refactoring.” If your tests are truly decoupled, they shouldn’t care if you’re using a SQL database, a flat file, or the latest cloud-native storage.

Take this sample project as a case study. We were building an inventory control system to track cases of potatoes—purchases, sales, and damaged goods. Early on, the “math” was the priority. I implemented the initial business logic using simple in-memory dictionaries. The tests were written entirely in a business-centric language, focusing on “Lot Adjustments” and “On-Hand Quantities.”

As the project evolved, we swapped the storage mechanism twice. We moved from dictionaries to Marten for its document database and Event Sourcing capabilities, and later refactored how we handled projections within Marten itself. Because the tests were focused on the problem domain rather than the tech stack, we didn’t have to change a single line of our business tests across two architectural shifts.

“When we write the test first, we are tailoring the implementation based on the desired outcome. If the implementation is ugly, you can refactor it indefinitely as long as you don’t change the externally visible behavior.”

The “English-First” DSL and Context-Based Testing

To bridge the gap between code and the CFO, we must create a Domain Specific Language (DSL). In the .NET world, this often means intentionally “bending the rules” of C#. I favor using snake_case in test methods—a direct violation of standard PascalCase conventions—because it allows the test to read like a natural English sentence.

This isn’t just a stylistic choice; it’s an organizational strategy. I practice Context-Based Testing, structured as follows:

  • One folder per Operation: (e.g., Adjusting Inventory or Rounding Calculations)

  • One file per Scenario: (e.g., Adjusting lot for damaged cases)

This granularity ensures that we aren’t testing “classes” or “modules,” but rather the “bread and butter” operations of the business. When a non-technical stakeholder looks at the file structure, they don’t see a mess of technical jargon; they see a directory of business rules.

AI as the Ultimate BDD Reverse-Engineer

AI has transcended simple autocomplete; it is now a Senior BDD Partner that can bridge the gap between legacy code and business value. In my current workflow, AI acts as a strategic orchestrator in three ways:

  • Closed-Loop Documentation: AI can analyze our C# DSL tests and reverse-engineer them back into clean User Stories and acceptance criteria. This allows us to provide the CFO with a business-language summary of exactly what the system does, derived directly from the source of truth.

  • Identifying Hidden Standards: In a recent sprint, our AI analyzed a set of financial rounding tests. It identified that the logic wasn’t just “correct”—it was following US Accounting Standards. The AI recognized an industry-standard Bounded Context that even the developers hadn’t explicitly named.

  • Rapid Prototyping through Orchestration: We use AI to design API endpoints from stories and “stub” them immediately. This allows the front-end team to build against a contract while the back-end team focuses on the complex logic.

Conclusion: The Confidence of the Passing Test

Quality software is not a result of “checking the code”; it is a byproduct of understanding human problems and verifying them through robust, decoupled tests. When you focus on human behavior from the outside in, the technical details become secondary to the value delivered.

The ultimate test of your architecture is simple: If you replaced your entire database layer tomorrow, would your tests be your greatest ally or your biggest obstacle?

Leave a Reply

Trending

Discover more from Claudio Lassala's Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading