When you work with your own apps you can be as messy as you like. In a team there is some incentive to make the code readable to other developers. At the lightweight end you have coding standards and linting, then design patterns then finally big refactorings. It’s all trade offs. Bug team products can have islands of code that are like one person projects and those can be messy for example.
Code with duplications isn't less readable. Quite the opposite. Fighting your way through layers of abstractions and generalizations can make it harder to understand for someone new to the code. Especially code that will rarely be touched except for bug fixes, having it as simple as possible can often be worth it.
And in the end, users will also appreciate this. Any time spent refactoring is time not spent on new features or bug fixes. A user doesn't care if your code is cleaner (unless it was buggy before), they'd rather have new features or improved usability.
It's gotta be case-by case, but upon shallow reflection I feel like 1 layer of abstraction is the sweet spot. I've worked on code where I have to "Go-to definition" a dozen times to figure out what is going on, and I hate it. And I have seen code where it's just a big wall of text hundreds or thousands of lines long, and I hate it.