Hehe, essa é uma questão polêmica, eu entendo a visão. Do ponto de vista de desenvolvedor, quando “criamos” alguma funcionalidade (como um ORM, ou um framework MVC), temos a “vontade” de atender todos: gregos e troianos. Daí a grande quantidade de configurações e parametrizações possíveis que a maioria dos frameworks acaba tendo.
Mas já ouviu aquele ditado: “mais vale um pássaro na mão do que dois voando”. Qual foi a idéia de um HQL ou uma classe Criteria no Hibernate? No meu ponto de vista foi um objetivo nobre: digamos que você fez seu sistema com JDBC (e um DBCP ou C3P0 para pooling de conexão, não sejamos tão 1999 também :-). Sua empresa usava MySQL. Um ano depois ela resolveu que não sabe usar MySQL e quer colocar Oracle no lugar. Ferrou-se! Temos que vasculhar todo o código e sair dando replaces, copy & pastes, e toda gama de gambiarras pra fazer as coisas funcionares. Ao passo que se fosse tudo feito com HQL, seria só o caso de retestar tudo e fazer alguns poucos tweaks no código.
É óbvio que o Gavin King tentou cobrir essa possibilidade e eu acho que foi uma boa idéia na época. Porém, na vida real, quantos projetos você já viu que realmente passou por esse cenário. Eu vi alguns, mas a maioria eram bancos de dados extremamente velhos, Ingres, Adabas, etc pulando para versões mais recentes de DB2, Oracle ou SQL Server. E os programas antigos foram jogados fora, muitos deles feitos sobre 4GL, Cobol, etc.
No fundo, é muito raro - não impossível - de se ver um sistema feito em Java recente, sofrendo uma mudança de infraestrutura, sem sofrer também uma revisão dos processos implementados.
Portanto, HQL é uma boa idéia, mas ela é uma complexidade extra que com que acabamos tendo que lidar em projetos que dificilmente serão plug-and-play de banco pra banco num futuro próximo. Claro, para desenvolvedores de produtos, a coisa pode ser diferente: eles precisam aceitar vários bancos justamente para ficar mais fácil de vender. Mas acredito que a proporção de projetos tailor-made é ordens de grandeza maior do que projetos de produtos com um life-cycle maior.
Ou seja, o ActiveRecord, por exemplo, não tem algo semelhante ao HQL. Ele usa SQL puro do banco. O bom e velho string. Isso é um problema? Se você for um desenvolvedor de produtos, pode até vir a ser caso não se planeje com mais cuidado. Mas não chega a ser um impeditivo. E para a grande maioria dos casos, dificilmente fará falta.
O uso de Surrogate Keys (primary keys numéricas auto-incrementáveis, nesse caso) é uma convenção, mais uma vez, porque na maioria dos casos é tudo que você precisa. Você quer Composite Keys? Não tem problema, existe plugin para isso, mas a maioria não precisa principalmente se for começar um projeto do zero, quando você pode planejar com antecedência para ser aderente às convenções.
Mais do que isso, o ActiveRecord tem convenções para nomenclatura das tabelas, das classes models, das colunas para foreign keys, etc. Seguindo as convenções, num novo projeto, não é esforço algum. Você gostaria de usar uma base de dados já existente sem mexer nela? Não tem problema, o ActiveRecord aceita isso.
E em uma época de Mesh ups, S3, serviços, também não vejo problema em, por exemplo, criar uma camada de aplicação de serviço (Web Service SOAP, REST) e criar uma aplicação Rails que, em vez de conversar diretamente com o banco, conversa via API com um serviço.
Existem inúmeras possibilidades se houver disposição para arquitetar uma solução que melhor se encaixe ao seu problema. “Arquitetar uma solução” é moldar sua solução ao problema em mãos, não o contrário. Os requerimentos são importantes. Se não existe perspectiva de uma requisição como “vamos migrar de fornecedor de banco daqui 2 anos”, uma funcionalidade como HQL não cheira nem fede. E se for uma empresa que prima por time-to-market, um requerimento pode ser “precisamos ter esse produto no mercado em 2 meses, mas o investimento é limitado”. Nesse caso, um Rails pode ajudar, por exemplo.