Thinking about it, I come to the conclusion that programming -- at least, the way I do it -- is roughly equal parts craft, engineering discipline, science (although not in anything I learned in school) and art. Here's the breakdown:
Craft: The essence of programming well is that it is a craft, and I learned it much like one would learn any craft. My first lessons were at my father's knee, from the time I was maybe seven. I did a more-or-less formal apprenticeship to him through high school and a bit beyond -- perhaps not quite the traditional seven years, but a good five or six anyway. In those years I learned most of the deep-down elements of the craft: how to put a program together, how to think of it, how to fashion it with care and how to deal with the customers. After college I struck out very much as a journeyman, skilled and experienced but still lacking the fine points. And somewhere in the past five years, I've come to think of myself as essentially a master progrogrammer, capable of working on my own and producing the occasional masterwork.
Engineering: While simply writing code is a craft, doing major projects has a lot more to do with engineering. It's all about the processes: how to start with an idea, proceed through the blueprints and eventually wind up with a structure that people can actually use. Industrial-strength programming is all about teams, not individuals -- how they work together and how they communicate. Little projects have room for big egos, but serious ones require that you set them aside. The bigger the project, the more it matters how you build, not just what, because you can't create a sound structure of real size unless you have the right processes for creating it and checking what you're doing.
Science: There's an important element of science in my day-to-day work, but it has nothing to do with the programming -- rather, it's in the debugging. When something goes wrong, my approach suddenly gets much more scientific. I gather all the information I can about the problem, and formulate theories about what might be behind it. I conduct experiments that can support or disprove those theories. Once I think the evidence is strong enough for one theory, I construct an experiment around it, which breaks before I fix the bug and succeeds afterwards. This scientific approach is slower than the usual slapdash approach to debugging, but it means I'm usually right, and am less likely to break additional things along the way.
Art: Art? Yes, art. Just as the serious potter needs to be both craftsman and artist, I've found it's the same way for me and code. The adjectives I use to describe bits of code are telling: a program is "elegant" or "crude", "pretty" or "ugly". I look at a program, and I see it as an aesthetic construct. As with any art, the rules aren't hard-and-fast -- there is lots of room for argument about whether a particular example is good art or bad. And I program very much like sculpting. Given the initial idea, I'll throw together a rough sketch, which might have roughly the right shape, but isn't very pretty. Then I'll begin to mold and shape it, poking and prodding at the code, changing a curve here and slicing off that unneeded bit there. Given the time and care, I can occasionally turn the original lump of clay into something of crystalline beauty, so achingly right that I am forced to admit that I can't improve it any more. Those moments are what keep me in this field -- not so much the ego-boo of seeing the product shipping, or even necessarily the pay, but those occasional moments of getting to produce some little system, hidden away from the user, that I know is an expression of my art.