I don't really buy it. I think practice with tackling bigger and bigger problems teaches you more about the need for the specific kinds of abstractions that are most useful for SE. When you get to problems that are too big to fit entirely in your head, you start realizing the absolute necessity for hiding implementation details, and when you work over time with other people using your code, the similar necessity for limiting the flexibility and expansion points in the libraries you write - i.e. not making things too abstract, in many cases.
So much of abstraction in SE is about chunk size - what's comfortable to fit in your head when thinking at any particular level - and minimizing surface area between modules, where enough experience with a wide selection of APIs to develop good taste is important.
Whereas I see a lot of mathematics as being about eliminating redundancy, seeing connections between things and reducing them to their most orthogonal and best factored form, with the minimal number of concepts; but with not a whole lot of concern for complexity specifically. The same approach applied to SE can be useful, but mostly only in central libraries that have the widest variety of uses. I'm thinking of collections in particular; there, you want a wide selection of querying and transformation primitives to make arbitrary data manipulation problems easier to express. But most libraries and APIs don't benefit from that kind of factoring; they are best approached from a UI perspective, looking at use cases and building in affordances that make all the common cases trivial, while making the edge cases possible. This makes them lop-sided and redundant, and probably would offend someone with a heavy mathematical orientation.
tl/dr: mathematical thinking is roughly the right kind of thinking, but practice of reading and writing code teaches thinking that's a better fit.
Reading and writing code does not teach you recursion. Certain abstract ideas fall into the domain of mathematics even if you can pick up some of them outside of a formal mathematical education.
Reading code using recursion certainly does teach you recursion.
Classification of ideas does not lend the classifier ownership over the idea. Ferns were around long before mathematicians.
(To a certain degree, I'm taking a devil's advocate position. I'm not arguing against the worth of mathematics. But not a lot of SE requires much mathematics; what I am specifically disputing is that teaching a lot of abstract mathematics necessarily results in a better software engineer than deliberate practice. Solving simple combinatorial, tree and graph search problems teaches you more about the practical uses of recursion than any amount of recurrence relations, IMO.)
I immediately rethought my assertion when I submitted but left it for argument. Like Picasso saying "computers are useless" to encourage deeper discussion. Mathematics lends rigorous proof, like with an induction proof. It takes a level of abstract thinking to decipher recursive code, the kind of training helped by a mathematics education. Software programming gives you exposure to existing abstractions but direct mathematics training gives rigor to developing new concepts. University disciplines, within the university, do have ownership over domains of knowledge. So computer science is really math and engineering.
Like philosophy, mathematics is about ideas. Understanding the underlying philosophical and mathematical ideas are enlightening and often practical. Benefiting from understanding these ideas or methodology does not necessarily mean I have to be good at the level of philosophical writing, or solving proofs.
Unfortunately, very little of software engineering involves new concepts; and when they are introduced, it's often ill-advised. It's usually better to build something out of two or three well-understood ideas that have stood the test of time in the industry than a single novel one, even if it's a lot shorter and less work for the initial implementer. There will be later maintainers who may not have had as much invested in their experience and training, and it's normally better for whoever is paying the bills that specific and exotic skills are not required on a continual basis.
New ideas really pay off when the constraints are such that conventional composition of existing ideas won't work well. But those situations are rare.
It might sound like I'm arguing against talented software engineers, or against education, training etc., but really it's just business pragmatics and economics.
I tanked at maths at school. I have no formal education after school. I don't know how or when I learnt recursion, but learn it I did. There are a few other things I learnt since then, like breadth- and depth-first tree traversals, shortest paths and so on. A lot I learnt from examples I found online. A lot of it I figured out myself. I can't even articulate how I do a lot of the things I do, but I do them. And they work.
That said, a lot of the higher-level stuff I learnt the hard way, like the difference between tiers and layers. That's abstraction. And it's why I disagree with Keith's post in general, and this comment in particular:
"...mathematics was the only subject that gave them that experience..."
I don't need maths for 99% of what I write.
[Edit] I don't dispute that I'm doing it (mathematics). I do dispute that an expensive maths education is a requisite for good code.
Good of course is an interesting word - there's a difference between the best architecture, the right architecture, and a successful architecture. All can be termed as being "good" architectures, but no amount of maths is going to teach you the difference.
So much of abstraction in SE is about chunk size - what's comfortable to fit in your head when thinking at any particular level - and minimizing surface area between modules, where enough experience with a wide selection of APIs to develop good taste is important.
Whereas I see a lot of mathematics as being about eliminating redundancy, seeing connections between things and reducing them to their most orthogonal and best factored form, with the minimal number of concepts; but with not a whole lot of concern for complexity specifically. The same approach applied to SE can be useful, but mostly only in central libraries that have the widest variety of uses. I'm thinking of collections in particular; there, you want a wide selection of querying and transformation primitives to make arbitrary data manipulation problems easier to express. But most libraries and APIs don't benefit from that kind of factoring; they are best approached from a UI perspective, looking at use cases and building in affordances that make all the common cases trivial, while making the edge cases possible. This makes them lop-sided and redundant, and probably would offend someone with a heavy mathematical orientation.
tl/dr: mathematical thinking is roughly the right kind of thinking, but practice of reading and writing code teaches thinking that's a better fit.