I almost never want to use the word “clean” when I’m talking about code.
These days, when someone asks me to review code, and they start talking about “clean” code, I shift the discussion to two points—code should be correct and easy to understand. I think “correct and easy to understand” is a much more useful rubric than “clean”. Obviously it’s still subjective. Code that is easy to understand for you may be hard for me to understand. Likewise, code that is correct for your use cases may be incorrect for my use cases. But it’s much easier to come to an agreement about “correct and easy to understand”, or at least communicate issues with the code using that basis.
Like, “you shouldn’t use boolean flags as parameters, you should use enums” becomes “I can‘t understand the meaning of true/false at the call site, so let’s use an enum instead”. This gives us a very clear, articulable basis for how we talk about code quality.
Of course, “correct and easy to understand” is not the be-all and end-all for describing good code. It’s just a nice substitute for the horribly vague, terribly subjective “clean”.