These are all judgement calls. Sometimes it's good to refactor to avoid duplication, sometimes it isn't. Only experience gives some hints at which way to go each time.
If unsure, I tend to at least break down these cases down by writing low-level building blocks and express the duplicated code in terms of those blocks. Those blocks should be low-level enough that they can't have a say about how they should be used in all these cases.
You could say it's basically abstracting out the stuff that's so small there's no risk of overabstracting but that's not the point. Rather, it's like building a language for expressing the kind of problems that are solved by duplicate code all around.
I'm sure in the original example there would've been some things that are common for resizing all shapes. You would still have repetition under individual cases but you would replace raw math (I assume) with certain basic operations that you know are common.
Of course, this isn't a generic solution either. Just another step between raw duplication and finely abstracted model.
If unsure, I tend to at least break down these cases down by writing low-level building blocks and express the duplicated code in terms of those blocks. Those blocks should be low-level enough that they can't have a say about how they should be used in all these cases.
You could say it's basically abstracting out the stuff that's so small there's no risk of overabstracting but that's not the point. Rather, it's like building a language for expressing the kind of problems that are solved by duplicate code all around.
I'm sure in the original example there would've been some things that are common for resizing all shapes. You would still have repetition under individual cases but you would replace raw math (I assume) with certain basic operations that you know are common.
Of course, this isn't a generic solution either. Just another step between raw duplication and finely abstracted model.