A language agnostic approach since I see this problem in both compiled and interpreted languages with the builder pattern.
Let's say I have a Model that has 10 required fields and 5 optional fields. Of course, adding all these fields to the constructor would be a mess, but the constructor would allow us to easily check for failure because it can verify the types of the fields and that all the fields are provided.
Using the Builder pattern, we can make this code much cleaner to read and write, but as far as I see, it'd be hard for the compiler or IDE to know that a required field hasn't been provided.
For instance, let's say email
is required:
instance = new Model(firstName, lastName, phoneNumber);
The compiler, or other forms of checks, can see email
is not provided so it can fail since the constructor defines email
as a required parameter.
instance = new ModelBuilder()
->withName(firstName, lastName)
->withPhoneNumber(phoneNumber)
->build();
Here, the compiler, as far as I know, cannot tell that withEmail()
should have been called in order to define the email which can lead to a runtime exception if you have one instance of the Builder that is missing a required field.
Is this unavoidable? Is there some pattern that can be used to solve this problem?
Beyond making sure every instance that uses Builder has test coverage, I haven't been able to come up with a solution to the runtime exceptions. This problem seems to present itself more when the model has a new required field added after the builder instances have been implemented across the application.
NameModelBuilder
with has the methodPhoneNumberModelBuilder withName(String name)
, thenPhoneNumberModelBuilder
has the methodEmailModelBuilder withPhoneNumber(String phoneNumber)
, etc. until you reach a step where you have all the required field. This has the disadvantage of forcing the order of fields to set, but it would achieve what you want. That being said, this is certainly way too over-engineered, and if you get to this point, I believe you may want to reconsider your design.