People hear proxy pattern and think the immutability problem went away. It moved. The proxy holds the state and forwards calls with delegatecall, so the implementation's code runs against the proxy's storage. Every later implementation has to agree with every earlier one about which slot holds what.
State variables are laid out in declaration order, packed into 32-byte slots where they fit, with inherited variables first. Insert a field in the middle, reorder base contracts, or widen a packed uint128 to uint256, and the new code reads old bytes with a new meaning. The compiler has no idea an old layout exists. It compiles the new source as if this were the first deployment.
Constructors don't help. A constructor runs when the implementation itself is deployed, against the implementation's own storage, so proxies rely on an initializer function that must be guarded to run only once.
My rule is append only. Review compares the storage layouts of the old and new versions before anyone reads the logic diff. The logic diff is the easy part.