When developing applications / domain models in general, I am wondering what would be the best way to deal with incomplete or optional data. Typed languages such as TypeScript and C# give us the power of typing our models. Sometimes this is powerful, as it put constraints on our model and can force it to be integer. However, usually, real-life data is incomplete and that appears to reduce the advantages of typing constraints drastically.
Imagine a simple data model in a sample application (TypeScript frontend and some backend) of an entity called Project which has an id, a name and an optional description. The data is retrieved from a backend.
The data model is defined in the frontend using interfaces:
export interface IProject {
id: number;
name: string;
description: string;
}
The data is retrieved from the backend as follows:
export class ProjectService {
public getProject(projectId: number): Observable<IProject> {
const url = 'http://server/api/project/' + projectId;
return this.httpClient.get<IProject>(url);
}
}
Example response of a project which actually has a description.
{
"id": 1
"name": "My first project",
"description": "My first project is just a demo"
}
In the frontend application we display the retrieved data. For example, let's display the first 10 characters of the project description.
alert(project.description.substr(0,10));
So far, everything fine.
But imagine that our user created "Project two" without filling in the optional description. Now the backend can respond with:
{
"id": 2
"name": "Project two"
}
or
{
"id": 2
"name": "Project two",
"description" : null
}
Now we get a null-reference exception in the frontend: Cannot read property 'substr' of null. Of course it's possible to add an if statement that checks for the description to be null:
if(project.description) {
alert(project.description.substr(0,10));
}
This works, but it means adding null checks across the whole application. The whole code base would be full with those checks, along with the dangers of masking bugs instead of preventing them. That just does not feel right to me.
A possible solution could be to always return a description, hence returning an empty string if none was filled in.
{
"id": 2
"name": "Project two",
"description": ""
}
Now the frontend does not need null checks for description any more, but it is no longer possible to distinguish between an explicitly filled-in empty description and a not(-yet) filled-in description.
What is the best way to deal with these kind of problems? The example above is just to illustrate, the scope is quite generic. It seem to plague all typed languages in which a typed contract/interface is defined which cannot always be fulfilled.