Basically my question is ErrorAccumulator a pattern or anti-pattern?
With a few exceptions, a design can be good or bad depending on context (some designs are awful no matter how you use them). A pattern may make one design really good, but can be misapplied in another design to make it worse. Context matters.
In general, it is a good idea for functions not to modify their parameters. This is how mathematical functions operate, and it makes code clearer because of fewer side effects.
However: you need to look at each object and its purpose. When I see ErrorAccumulator
I see an object designed to be modified on a whim. By its name alone, it tells me "I am a bucket to throw your errors in, and you can dump them out later."
Or better yet just log errors inside of the function?
There are some good reasons for not doing it this way, but there are a few issues here that are intertwined.
- Logging errors works okay if the code can recover from an error itself, and errors can simply go to a log file and not the user.
- Exceptions may be better if the code cannot recover from the error itself, but code higher up the call stack can do something useful.
- Accumulating errors in an object may be a good idea if the code can recover from errors itself, but you need to make a list of all the errors to show to the user as one unit.
Regarding that last bullet point, a good way to visualize this is a web form. Several fields need to be validated: maybe some only allow numbers, others must follow a specific pattern (e.g. match a regex). In this case, it may make sense to use something like that ErrorAccumulator
to compile a list of errors, which can then be printed as one unit for display to the user.
Basically my question is ErrorAccumulator a pattern or anti-pattern?
Back to this question: both. If used correctly, it can solve a specific problem in software. If used incorrectly, it can solve the problem incorrectly and create confusion.