Code is law is often frowned upon by many. I think it’s because it is often used as an excuse to not do something which otherwise would have been sensible, or as an excuse to being allowed to do something which clearly wasn’t the intent of the developer. But as with many things, it’s a double edged sword.
As observed recently, compound.finance’s COMP bug, deployed as part of a contract upgrade through their normal DAO process, allowed people to obtain more COMP tokens than they otherwise should have been allowed to do. And due to their DAO process, they can’t fix this before 7 days later, which is more than enough time for people to exploit the bug and drain all the tokens.

What’s at fault here? Clearly bugs can happen, anyone involved with software development will know this. So in a normal production setup, you have a run book that also allow you to quickly fix the issue. Maybe “code is law” isn’t the problem here, but rather poor risk management?
Because without “code is law”, there could not have been any compound.finance to begin with. That’s the other side of the coin.
What needs to happen is we need to stop trying to build smart contract systems like we build normal software. While it is possible to upgrade smart contracts, through the use of proxy contracts and other methods, it doesn’t mean it’s a good idea. Because as talked about elsewhere on this site, any upgrade mechanism is a door to more centralization. It’s an unmitigated risk. It’s an opportunity for a power grab. It’s a way towards failure.
Keep smart contracts as simple as possible. Spend time up front on locking in their feature set, testing it fully. Then leave the code alone. You want to upgrade? Deploy a new contract and let people migrate their liquidity as and when they are ready. That’s the proper decentralized approach. That’s the proper “code is law” way.