A Developer’s Fear of Null
I still remember the first time I looked through a codebase and saw almost every database call wrapped in a sea of question marks. It looked something like this in C#:
var student = _repository?.GetStudent(id)?.Name;
And in JavaScript, it wasn’t much different:
const grade = studentDataStore?.data("transcript")?.grade;
At first, it seemed neat—no NullReferenceException in C#, no TypeError: Cannot read properties of undefined in JS. Just smooth sailing.
But as I dug deeper, I realized something unsettling: developers weren’t actually handling errors; they were hiding from them.
The null-conditional operator (?.) had become a shield, a quick fix for runtime errors. Instead of asking why a value might be null or undefined, the code was quietly sweeping the question under the rug.
And it wasn’t just in one place. I saw it everywhere:
// C#
if (_repository?.GetStudent(id)?.IsActive == true)
Console.WriteLine("Active student");
_logger?.LogInformation($"User {_httpContext?.User?.Identity?.Name} logged in");
var timeout = _config?["Timeout"] ?? "30";
At first glance, this looks safe. But in reality, these question marks were band-aids—covering up the fear of nulls without actually addressing the root cause.

The Problem with Overusing Null-Conditional (?.)
Take this line in C#:
// C#
var grade = _repository?.GetStudent(id)?.Transcript?.Grade;
Or in JavaScript:
const grade = responseData?.student?.transcript?.grade;
At runtime, this might give you a grade… or null/undefined. But here’s the catch: we don’t know why it’s missing.
- Was the repository/responseData not initialized?
- Did the student not exist?
- Was the transcript missing?
- Did something fail silently deeper in the chain?
By the time we get null/undefined, we’ve lost all contexts. What looks like “safe code” is actually ambiguous code.
Debugging Becomes a Nightmare
Imagine a bug report: “Some students don’t have grades showing up.”
You open the code and see the one-liner above. Now you’re stuck asking: “Where did the chain break?” You have to sprinkle logs everywhere or step through with a debugger just to track down the missing link.
The truth is, ?. didn’t handle the problem—it just hid it.
Silent Failures Hurt Business Logic
Even worse, overusing null-conditional checks can introduce logical errors.
C#:
if (_repository?.GetStudent(id)?.Transcript?.Grade >= 50)
Console.WriteLine("Passed!");
JavaScript:
if (studentDataStore?.getStudent(id)?.transcript?.grade >= 50)
console.log("Passed!");
In both cases, if the grade is missing, the comparison fails, and the student is silently treated as if they didn’t pass. No errors, no warnings—just incorrect behavior that no one notices until much later.
The Developer vs. Tester Gap

Here’s the sneaky part:
- Developers self-test → Their happy-path test data always has a grade, so everything “just works.”
- Testers explore edge cases → They remove the grade, skip a step, or try invalid data… and suddenly the system behaves incorrectly.
Because ?. swallows the problem, developers don’t notice it during coding. But when testers push the system harder, these silent failures show up instantly.
This creates friction:
- Developers feel frustrated — “but it worked on my machine!”
- Testers feel frustrated — “how did this pass dev testing?”
All because the code chose to hide a null instead of making it explicit.
Understanding Error Handling
Before fixing null issues, we need to clear up a common misunderstanding: nulls and errors are not the same thing.
- Errors mean something unexpected happened (DB connection failed, file missing, invalid input).
- Null/undefined means “there’s nothing here.” Sometimes valid, sometimes not.
When developers use ?. everywhere, they blur the line. A missing student, a bug in initialization, and a failed query all collapse into the same outcome: null/undefined.
That’s not error handling—it’s error hiding.
How to Handle Nulls and Errors Correctly
Validate Assumptions Early
C#:
var student = _repository.GetStudent(id);
if (student == null)
throw new ArgumentException($"Student with ID {id} not found.");
JavaScript:
const student = studentDataStore.getStudent(id);
if (!student)
throw new Error(Student with ID ${id} not found.);
Use Defaults Explicitly
C#:
var studentName = _repository.GetStudent(id)?.Name ?? "Unknown Student";
JavaScript:
const studentName = studentDataStore.getStudent(id)?.name ?? "Unknown Student";
Wrapping It Up
?.is a tool, not a silver bullet. Overusing it hides problems instead of solving them.- Null ≠ Error. Sometimes
null/undefinedis fine; sometimes it’s a bug. - Fail fast when assumptions break.
- Use explicit defaults when null is valid.
- Lean on compiler features (nullable types in C#, strict null checks in TypeScript).
- For complex cases, wrap results in structured objects instead of sprinkling
?..
By handling nulls deliberately—in both C# and JavaScript—we write code that’s not only safer but also easier to debug, easier to maintain, and far more trustworthy in production.
Stop hiding from nulls. Start handling them with intent.