Engineering is much more like plumbing than math.
As a programmer, being productive rarely involves finding new O(log(n)) algorithms. Adding new features and even optimizing for performance has much more to do with trying to figure out how to turn a vector of scoped_ptr<FooFactory>& into const ThreadableFooInstanceWrapper* tuples, regardless of whether the change actually affects the underlying algorithm in a nontrivial way.
My coworker pointed out that this tendency isn't limited to computer science. Modern digital devices come with slick programming interfaces, accessed over buses like I2C, SPI and CAN. All the datasheets have timing diagrams down to the individual bit levels for these standard, widely used interfaces, and at some point you'll get to hook up a logic analyzer to the lines and pull out the diagram to see why your commands don't seem to be affecting the chip. Oh, also, it needs 3 different power supply rails, and the following 6 very specific capacitors placed within 1cm of the power pins, before it'll do anything at all.
The semantic thing you're trying to get the chip to do -- turn off output B, enable automatic black level correction, or set the refresh rate -- is utterly straightforward. But hooking up the plumbing correctly so you can tell it that takes up a huge amount of the development time.
Mechanical engineering has that nature too: brackets, matching up bolt patterns between standard parts, sourcing a flange button head cap screw instead of the ordinary button head cap screw because the head is 2mm shorter and clears the bolts on the other leg of the L bracket.
When faced with a big project, an engineer's first impulse is to throw away what looks like a big mess of plumbing and start reinventing the core machine. That's almost always the wrong thing to do. Expect to spend at least half your time on plumbing by the time the system ships.
I suspect that engineering would benefit from a more explicit focus on plumbing skills. Yes, it's good if a programmer can break quicksort down into little pieces, but how many times have you had to implement quicksort? Okay, now how many times have you spent an hour trying to figure out how to get a new C++ library to work because the author didn't give any example code, and you didn't know which kinds of objects had to be initialized and in what order just to get the library initialized properly?
How much time have you spent pulling data from one source into a data structure so you can stuff it into a different data source in a slightly different format? Maybe CS departments need a Software Plumbing Research Group figuring out how to cut down on all the manual plumbing we have to do, and teaching classes on how to quickly rig up conduits between AJAX data sources and STL data structures used by C++ libraries.
And if you're on the designing end of a system, it suggests that before you write the detailed document for all the clever algorithms at the core of your system, you should write up some very straightforward recipes, with lots of ready-to-compile, complete examples (no pseudocode!) for how to build, use, and safely change what you've built. Make sure to copy and paste the examples into a clean environment and make sure it builds as advertised.
Stop assuming that algorithms are the important part and treating the plumbing as an afterthought, and you'll spend less time being frustrated at how hard it is to reach the semantics to make your tweaks. The plumbing's there; deal with it. And realize that your ability to hack the plumbing efficiently (or simplify it without crippling the system) is a big part of your overall productivity as an engineer.