It might be false in biology, but in computer-science, "ontogeny recapitulates phylogeny" pretty nearly. A historical overview of computer architectures since the first computers is a great way to understand the subject of computer architecture from a programmer's perspective; computer designs are almost all refinements of earlier designs.
That is, I recommend studying complete working older system designs, insted of theoretical "computer architecture" books they give you in computer science. To really understand systems design, and to do a really great job at writing software. Intuitive grasp of architecture of computer systems requires mastery of many concepts. I think if you start back when computer architectures were more manageable in size and scope, you might get father along in your goal to write better code.
(That "write great code" book series that another guy mentioned looks great, by the way, and I've edited my question to remove any aspersion that I had previously cast on learning-from-a-book, because it looks great!)
Some things that teach computer architecture really well:
I like to pick machines from the 1980s as starting places for explaining and demonstrating things to people, because that's when I started using computers. I have used the commodore 64 programmer's reference guide, to show people a jumping off place where knowledge of programming, and knowledge of computer architecture meet each other.
With such a book, and perhaps a commodore 64 emulator running on your PC so you can try stuff, you'll learn about how computer systems in the classic 1980s incarnation of computer architecture, are really built. In my view, one concrete example is a better place to start, than a dozen theoretical models that are missing the real world details that make things work. If you know what a register is, what an ALU is, what a bus is, and what a clock is, and what signalling systems are used in an old 1980s design, that will give you the fundamentals that you need to know to understand something recent, like Intel's "sandy bridge architecture". Historically, look back at the originals, for example look up "Von neumann" architecture, on wikipedia.
Moving forward from my first point a few years; Learn about the original IBM PC architecture, 8086 assembly language, and the ISA bus. From this, and its limitations, understanding of what an "Intel COre i7" CPU contains, and what the PCI and PCI-e buses do and why you need them, can proceed more naturally. PC architecture today still has a bit of "hangover" from the original IBM PC design. The way initial program (operating system) loading (boot-up) happens on a 2011 PC still owes a lot to the heritage of the original IBM PC and its ROM BIOS, and its CMOS settings in an original PC.
Use and modify a pre-configured build of Linux that works on some embedded non-PC device, and you'll learn a lot about embedded computer architecture, not only the technical architecture, but why some of the features are there. A nice example that is available cheap is the TS-7200, which has a nice PC-104 (ISA Bus, as in the original PC). PC-104 (embedded 16 bit ISA-bus that is pin compatible with the IBM PC/AT 80286 era PCs) computers are a great way for a non-board-designer to build an embedded system, because the modules are stackable. Want some extra IO or peripherals? Just stack up a few modules. The TS-7200 has a non-x86 core (an ARM9 cpu) that is capable of running either big-endian or little-endian. If you haven't run into "endianness" in your architecture learning journey yet, that's a good place to encounter it.