(This is just one recommendation - and doesn't talk about error-free data structure design.)
Let's say there is a Project
class that needs a convenience builder for testing.
This Project
consist of a company who owns the project and a list of tickets - where a ticket is just a name and the same company denormalized (for reasons).
Since this company attribute is just a denormalization - it is/must-be consistent.
When redundancy exists in data, do not prepare final objects too early. It will allow an inconsistent setup.
class ProjectBuilder
def intialize(company_tag)
@company = Company.new(company_tag)
@tickets = []
end
def add_ticket(ticket)
@tickets.push(ticket)
end
def build
Project.new(
company: @company,
tickets: @tickets,
)
end
end
builder = ProjectBuilder.new(:ACME)
builder.add_ticket(Ticket.new("Paint a tunnel entrance", company: Company.new(:ROADRUNNER))) # Erroneus company.
builder.add_ticket(Ticket.new("TNT the cliff", company: Company.new(:WILEECOYOTE))) # Another erroneus company.
builder.build # Inconsistent company.
Allow late building of attributes and consider re-normalizing (avoid redundant and diconnected attribute collection):
class ProjectBuilder
def intialize(company_tag)
@company = Company.new(company_tag)
@ticket_names = []
end
def add_ticket(ticket_name) # No redundant attribute (company).
@ticket_names.push(ticket)
end
def build
Project.new(
company: @company,
tickets: @ticket_names.map { Ticket.new(_1, @company) }, # Late building.
)
end
end
builder = ProjectBuilder.new(:ACME)
builder.add_ticket("Paint a tunnel entrance")
builder.add_ticket("TNT the cliff")
builder.build # Consistent company.