I'm surprised no one has mentioned the David Parnas papers: "On the Criteria To Be Used in Decomposing Systems into Modules" is an all-time classic [1]. Much more philosophical than most of the suggestions here so far, but this paper really drove home to me the importance of abstraction in software design. (Also covered in the Morning Paper [2].)
An excellent textbook that teaches Parnas' approach is "Software
Engineering: Planning for Change" by David Alex Lamb. The
chapter Detailed Design is especially pertinent to this thread. The book is from 1988. I once wrote the author
to ask if there would be another edition. He replied, "publishers aren't interested because it isn't object oriented". In fact, its lessons are as relevant to object-oriented programs as any others.
[1] https://www.cs.umd.edu/class/spring2003/cmsc838p/Design/crit.... [2] https://blog.acolyer.org/2016/09/05/on-the-criteria-to-be-us...