Abstractions aren't merely for duplication removal. Abstractions are for symbolic chunking; for thinking about things at different levels.
We don't use e.g. units-of-measure types [1] because they remove duplication from our code; if anything, they add duplication. They do however clarify our thinking with help from the type checker.
I think a lot in terms of flows / pipes / functional transforms. So I tend to try and express problems in that shape, because I have a lot of mental tools that I can apply, and I know they're extremely easy to test in isolation. Creating a pipe-like thing means reducing it to a simple common push or pull stream pattern. But it's not duplication I'm removing here; I'm actively introducing an abstraction because it has proven power for creating good software and solving problems.
I try and create few, minimal abstractions that can be applied widely. Take a cue from functional languages and split out types from algorithms; if you make your types more general, you increase the reusability of your algorithms. Classical OO design tends to create a lot of types that are specific to the domain model. I happen to think that OO designs are usually poor; they tend to have a high code complexity to implemented logic ratio, and require awkward composition that leaves details hanging out.
I spent 20 years writing OO software and was a big fan, especially in the early 2000s. I still work in OO languages, but most OO code I read makes me wretch now.
I don't recognize either Kent Beck or Bob Martin as particularly noteworthy for good architectural design (Beck is on the right path with agile though). In fact, I blame TDD for Java-itis: proliferation of single-implementation interfaces (has there ever been a worse idea more often propagated by cargo culters?), poorly abstracted object graphs, leaky implementation abstractions, and more.
> Start with what you know, and work toward what you don't know
I've been programming for more than 25 years. A lot of stuff has changed in that time; what hasn't changed is patterns of abstraction. So I start out with abstractions, chosen from experience.
Read Norvig on TDD [2] - his experience matches mine. If you know a lot of software tools (i.e. abstractions, algorithms, approaches), you can apply them to a problem. TDD is a poor tool for creating new tools, though. And if you rely on code duplication for creating a tool, well, you're going to have a bad time with hard problems.
[1] https://blogs.msdn.microsoft.com/andrewkennedy/2008/08/29/un...
[2] http://pindancing.blogspot.co.uk/2009/09/sudoku-in-coders-at...