I've eventually come around to flipping this idea on its head, though. If I design not just some kind of product or solution, but a whole process, starting basically with how I want to run my life and then drilling into specific details from there, the technical knowledge stands on more even ground with other forms of knowledge, and with seeing life itself in a more precious sense.
With that mindset, good scheduling of every day as an end in itself grows vastly more important, and abstraction-for-its-own-sake falls away: All programming problems start by assuming they are solved first with "code that looks like breadboard wiring" [0] and then working up the abstraction ladder from there. Automating the technical parts of the solution won't guarantee that it's right in any other way, but it will ease the pain of changing the specification. Acknowledging that the problem is messy, that breadboard coding is messy, and that I won't know how to solve everything immediately and cannot depend on a silver bullet, all constitute crucial first steps.
Now I always look for really basic groundwork to be laid out early on - typically, transforming the breadboard code into something that uses a new data structure, or generating the code flow from a stack or a list or a tree - and that no shortcut is possible without compromising the ability of a potential future abstraction - that it just takes a lot of layers to get where I want to go. Breadboard code is assumed to be ideal until demonstrated otherwise, while "x in y lines" hype is to be avoided under the assumption that the solution is brittle and over-modeled towards the demo code. I cannot assume that my valuable production code will need x or work in y lines. I don't abstain from adding dependencies, but I will preference towards copy-paste-own when I find a reason to reuse code.
[0] http://www.instructables.com/id/How-to-Build-an-8-Bit-Comput...