Currently, in our service layer, we pass an id as well as a new updated value, something akin to
updatePersonName(Person person, Name name)
which, in turn, calls the corresponding repository functions. Now this works fine if we want to update only a single value. But once we start wanting to update multiple values at the same time, we're either stuck calling various service methods in a row or defining a service method that takes multiple arguments to update. It is bearable, but it gets even worse when we need to update multiple values that are forced to be updated together, which means we are forced to define a (maybe new) method in the service that makes sure the combination is met. And if you start having some limitations (perhaps a Person that's marked as non-updatable due to different reasons), it just increases the complexity even further.
Recently I've been thinking of using the builder pattern, but not for object creation, but updating. Something like this (all the methods chosen completely arbitrary, but you get the point):
PersonService.updater(person)
.setName("newName")
.addRole(newRoleObject)
.setFlag(PersonFlag.NOT_UNDERAGE)
.overrideBlock()
.withEventDescription("Person changed her name on birthday!")
.update();
The builder could internally resolve the logic without exposing too much complexity to the outside. The fluent API is easy to use in every other service/component that needs access. I don't need to create a plethora of methods to cover whatever requirement came up. Multiple updates are easy to chain together, and if you want to update something that's now allowed, it could block that internally unless you override said block. And it would be able to force specific fields due to type safety, for example, an EventObject.
More importantly, this could also, in turn, make sure we only make a single trip to the repository, instead of multiple. It would improve runtime, especially in critical algorithms that require many passes to the database otherwise.
I can see a few issues with this approach, as well. It's bulky, is an unconventional API for people not experienced with it, and could lead to some misuse. Implementing it is not trivial while making sure the internal logic keeps together. However, I think the positives outweigh the negatives in my situation.
Am I missing something?
Edit: I know that usually, you have a save() function inside of your DTO that takes care of saving, but due to existing infrastructure, that isn't an option at this point.