I really liked A Philosophy of Software Design by John Ousterhout. It is compact and short, only 170 pages, so it is a quick read, but it contains many good ideas. The focus is on how to structure systems to make them easy to understand and work with. The author is a professor of Computer Science at Stanford, but he has also spent 14 years developing commercial software.
The book starts with a good chapter on complexity. The author defines complexity as anything related to the structure of a software system that makes it hard to understand and modify. There are three symptoms of complexity: change amplification (a change requires code modifications in many different parts), cognitive load (how much you, as a developer, need to know in order to complete a task), and unknown unknowns (it is not obvious which parts of the program that need to be modified to do the task).
The causes of these symptoms are dependencies and obscurity. Method calls create explicit dependencies. But there are also implicit dependencies. An example is when you have implemented a message protocol with a sender and a receiver. Any change to the sender usually also requires a change to the receiver. Obscurity can often be related to unclear dependencies. An example is if you add a new exception, and you then also need to add a new entry in an error message table, but the connection between them is not obvious.