People make the same mistake again and again with code generation and this goes back as far as CASE tools and Microsoft wizards. The key thing is that you should never use anything where you cannot "debug at the level of the abstraction" as Dave Thomas puts it (Smalltalk Dave, not the pragprog guy). That's why the analogy with a compiler breaks down: You never have to debug the assembly or look at it for any reason except if you are doing real embedded stuff and even there if you end up having to look at or debug the generated assembly frequently then it would be better to work exclusively in assembly. i.e. Its hard enough to map a program into your head, doing it at two levels is impossible to do without making a mess.
People (including me) like to delude themselves though. "I'm not a web/database/embedded developer. Here's a tool that will give me a quick win". But in the end because you find yourself debugging the mess that it generates you have to rewrite by hand anyway meaning that in the long run a quick win turned out to be twice as long as just sitting down and learning how to do it. BTW I think that DSL's could be the next thing that leads people down this path. A great idea but...
People (including me) like to delude themselves though. "I'm not a web/database/embedded developer. Here's a tool that will give me a quick win". But in the end because you find yourself debugging the mess that it generates you have to rewrite by hand anyway meaning that in the long run a quick win turned out to be twice as long as just sitting down and learning how to do it. BTW I think that DSL's could be the next thing that leads people down this path. A great idea but...