Imagine a hypothetical object with a number of attributes:
pseudocode:
class Student
{
Name: String;
Birthdate: DateTime;
Height: int; //inches
GPA: float; //"Grade Point Average"
Citizenship: string;
}
Now the user enters in values, and the object gets them:
Name: Shelby Lake
Birthdate: 6/19/1991
Height: 63
GPA: 5.6
Citizenship: United States
And the layer with all the business logical can validate it:
BusinessLayer.ValidateStudent(student);
In this example it could, for example, throw an exception:
ClientException
GPA cannot exceed 4.00 (5.60)
Okay, fine. But not everything the user types in can "fit" inside the object:
Name: Shelby Lake
Birthdate: 19 years ago
Height: 5'3
GPA: n/a
Citizenship: n/a
The fact that our users are allowed to enter in more friendly values in a business decision. At the same time there are global business rules that decide when some input is valid, e.g.
GPA: 5.6
(invalid)
GPA: n/a
(valid)
Citizenship: n/a
(valid)
Citizenship: (invalid)
Height: tall
(invalid)
Height: 5'3
(valid)
My problem is, where do i store these string
values, since i cannot store them purely in the object. They need to get to the business layer, which knows how to parse entered text into values.
My first thought is to change the class:
class Student
{
Name: String;
Birthdate: DateTime;
BirthdateFreeForm: string;
Height: int; //inches
HeightFreeform: string;
GPA: float; //"Grade Point Average"
GPAFreeform: string;
Citizenship: string;
}
This allows the more arbitrary values to be sent to the business layer:
Name: Shelby Lake
BirthdateFreeform: 19 years ago
HeightFreeform: 5'3
GPA: 4.6
Citizenship: n/a
BusinessLayer.ValidateStudent(student);
And the business layer can convert free-form values into canonical values, reporting any errors:
ClientException
Country of citizenship must be entered ("n/a")
But that seems like such an ugly answer i don't even want to consider it.
What's the enterprisey way to parse user input with business rules?