The reason why modern software engineering is so bad is because there aren't guard rails protecting against bad code.
Because something can be implemented in so many different ways, software inevitably becomes a big ball of mud, unless sufficient restrictions are put in place and enforced.
Ideally, such restrictions wouldn't need to be enforced — they'd be an automatic requirement in the development environment. Plus, if the restrictions aren't rock solid, then exceptions will be made to the rules, and the software will slowly devolve.
Better abstractions and interfaces are needed in order to make sure that software can be written in a way that works.
Because software is free to write, i.e. the materials are digital and thus can be built without cost, the cost becomes solely a matter of developer time.