2. How to Design Programs
3. Software Design for Flexibility: How to Avoid Programming Yourself Into a Corner
FYI - The original was written in Scheme. There is a newer version based in python which I haven't tried.
Edit: The python version is highly contested. Scheme is the more difficult and therefore the best way to understand these principles.
2. How to Design Programs
3. Software Design for Flexibility: How to Avoid Programming Yourself Into a Corner