I distinctly remember one of the things in the book, which in retrospect isn't even really a refactoring, called something like "null object". The idea was that if you were going to return null from a function (e.g. get student by ID but that ID doesn't exist) then you could instead return a concrete singleton object that represented null. That way, if you forgot to check for it then at least your program wouldn't crash. Now, the merits of this idea are debatable and I don't think I've ever used it in the years since. But I strongly remember thinking at the time that it was the only idea in the book that wasn't totally obvious.
There was a good chapter early on about testing, which I think was my first exposure to that idea. It was a bit brief but that's not a surprise given it was a bit of a digression from the main topic. A whole book on that might've been quite a bit more interesting.
If I forgot to check for null (or missing data) then I would rather have my program to raise an exception (to prevent data corruption). Then my error handling code will email that exception to me. I will analyze exception message (NPE) and stack trace. Then I will fix my program and deploy it to production.
before:
public Student GetStudentById(int id)
{
var record = db.findStudentById(id)
if (record == null) return null;
return new Student(record.id, record.name, ...);
}
Then in say a student record controller class: public View Get(int id)
{
var student = getStudentById(id);
if (student == null) return View("NotFound");
return View("Display", student);
}
After: [ContractAnnotation("=> notnull")]
public StudentSearchResult GetStudentById(int id)
{
var record = db.findStudentById(id);
if (record == null) return StudentSearchRsult.NotFound;
return new StudentSearchResult(record.id, record.name, ...);
}
Then: public View Get(int id)
{
var student = getStudentById(id);
return new View(student.ViewName, student); // look no null check becase student.ViewName is always valid here
}
Note: of course this is entirely simplified for the purposes of example. Perhaps your real world example doesn't return null from the db, but a RecordSet with either 0 or 1 elements. Perhaps your db uses exceptions that you translate into results like this.The cool thing there is that you get tool support (from e.g. ReSharper) telling your that this is entirely safe to do without a null check and tool support when it's not.
There are many ways that this can be implemented that avoid an if result != null / == no value, often a map suffices.
This is basically a workaround for a defect of certain typed programming languages that allow null everywhere.
Worst mistake of computer science.
https://www.lucidchart.com/techblog/2015/08/31/the-worst-mis...
The problem with "everything can be null" is the type system is prevented from finding very common "you can't do this thing" errors.
Without it, everyone uses null objects (or Maybe, a generic for of this) and there are no segmentation faults/dereferencing errors. (Yes there can be other sorts of errors, but the problem has been made far better.)