Something I have come to feel myself but haven't found a good way to articulate is asking "is what I am doing favoring authorship over maintenance?". I find that a lot of times the way DRY or other programming principles are used tend to be done to optimize authorship. This optimization sometimes happens at the expense of maintainability.
Anticipating maintenance is tricky; I had a scenario where a developer on my team created a utility function to abstract away some code that was being repeated multiple times in the same file. As an author that made sense because he was writing the same code over and over again, but down the line when we wanted a specific instance of this copied code to work in a slightly different way we ended up making the utility function handle the edge case.
Over time this utility became extremely hard to work with, because you weren't always sure if you made a change it wouldn't create a regression in other places it was used.
When we sat down and asked ourselves "Is this utility assisting in authorship at the expense of maintenance", the answer was clear. We removed it and put back the repetitive code. We felt good about it because in reality, 90% of the time we were interacting with this code we were doing it in maintenance mode, tweaks and small updates. When in maintenance mode I don't feel the strain of a specific part of my code being repeated, I'm only looking at a small subset of the code. Sure, if I need to author a new case in this code it might be a bit more wordy, but I think the tradeoff is worth it.
I am sure there are perhaps better ways to abstract things, or that we were doing DRY wrong, and our utility function could have been smarter, but I've seen this same thing play out over and over again and usually trying to make my abstraction better hasn't helped.
I tend to agree with your premise, though I wouldn't say the two are mutually exclusive. In fact, I imagine favoring authorship would more often trend to maintainable code than not, depending on what is being optimized for (writing less code, etc.)
I think in the case you described, instead of handling edge cases within that function, it might have been better to create an entirely new function to be called in those cases. You could then go a step further and identify shared logic, extract those and call them separately. At least that's what I tend to do when I find myself having to branch logic, especially established logic. Obviously I'm assuming a lot of the details here, and most likely what y'all ended up doing was the best right thing for your project/team.
Anticipating maintenance is tricky; I had a scenario where a developer on my team created a utility function to abstract away some code that was being repeated multiple times in the same file. As an author that made sense because he was writing the same code over and over again, but down the line when we wanted a specific instance of this copied code to work in a slightly different way we ended up making the utility function handle the edge case.
Over time this utility became extremely hard to work with, because you weren't always sure if you made a change it wouldn't create a regression in other places it was used.
When we sat down and asked ourselves "Is this utility assisting in authorship at the expense of maintenance", the answer was clear. We removed it and put back the repetitive code. We felt good about it because in reality, 90% of the time we were interacting with this code we were doing it in maintenance mode, tweaks and small updates. When in maintenance mode I don't feel the strain of a specific part of my code being repeated, I'm only looking at a small subset of the code. Sure, if I need to author a new case in this code it might be a bit more wordy, but I think the tradeoff is worth it.
I am sure there are perhaps better ways to abstract things, or that we were doing DRY wrong, and our utility function could have been smarter, but I've seen this same thing play out over and over again and usually trying to make my abstraction better hasn't helped.