SQL vs ORM

Na persistência de dados de um projeto, é comum o uso de linguagens de consulta estruturada (Structured Query Language – SQL) para se conectar a um banco de dados e realizar operações como inserção, consulta, atualização e exclusão de dados. No entanto, ao trabalhar com grandes quantidades de dados ou em projetos complexos, pode ser desafiador escrever e manter códigos SQL de forma otimizada e segura.

Para simplificar o trabalho com o SQL, as ORMs (Object-Relational Mapping – Mapeamento Objeto-Relacional) surgiram como uma alternativa. As ORMs permitem que o desenvolvedor trabalhe com objetos em seu código, enquanto a ORM cuida da conversão desses objetos em consultas SQL para serem enviadas ao banco de dados.

Uma das principais vantagens do uso de ORMs é a diminuição do tempo de desenvolvimento, já que o desenvolvedor não precisa se preocupar em escrever consultas SQL complexas e pode se concentrar mais na lógica de negócio do projeto. Além disso, as ORMs geralmente fornecem recursos de cache de consulta e pool de conexão, o que pode aumentar o desempenho da aplicação.

É importante dizer que o uso de ORMs carece de atenção na qualidade das consultas produzidas. Em alguns casos, as ORMs podem gerar consultas SQL pouco ou nada otimizadas, o que pode afetar o desempenho da aplicação e causar muitas dores de cabeça. Além disso, se usada sem parcimônia, o uso de ORMs pode aumentar a complexidade do código, já que é necessário compreender como a ORM está mapeando os objetos para as consultas SQL.

Em resumo, o uso de SQL puro ou ORMs depende do projeto e das necessidades do time de desenvolvimento. Em projetos menores ou com menos complexidade, o uso de SQL puro pode ser suficiente. Já em projetos maiores ou com mais complexidade, o uso de ORMs pode ser uma opção vantajosa para simplificar o trabalho com o SQL e aumentar a produtividade do time.

Posso misturar SQL puro com ORM no mesmo projeto?

A resposta mais direta é sim. É viável misturar o uso de SQL puro e ORM em um mesmo projeto. Na verdade, é comum que projetos usem a combinação de ambos os métodos de acesso a dados, dependendo das necessidades e das características de cada caso.

Porém, é importante que na fase de definição das tecnologias do projeto, esses limites sejam definidos e que conste na documentação esse tipo de cenário, no qual parte dos acessos a dados serão feitos via ORM e parte via SQL puro, de preferência explicando o motivo da escolha de cada abordagem.

Por exemplo, é possível utilizar ORMs para realizar operações básicas de CRUD (Create, Read, Update, Delete) e usar SQL puro para consultas mais complexas ou otimizadas, geração de relatórios, etc. Dessa forma, o time de desenvolvimento pode aproveitar as vantagens de ambas as abordagens, sem precisar se preocupar em escrever consultas SQL complexas para as operações mais simples e comuns.

No entanto, é importante lembrar que a mistura de SQL puro e ORM pode aumentar a complexidade do código e exigir mais atenção do time de desenvolvimento para garantir a integridade e otimização das consultas. Por isso, é importante avaliar as necessidades do projeto e as vantagens e desvantagens de cada abordagem antes de decidir misturar o uso de SQL puro e ORM.

Como melhorar esse tipo de cenário?

Existem algumas abordagens para manter o controle desse tipo de cenário, em que optamos por usar parte do acesso aos dados do banco de dados com SQL puro e parte com ORM. Uma das opções seria o uso do padrão de projeto Repository.

O padrão de projeto Repository

O padrão de projeto Repository (Repositório) pode ser uma opção viável para melhorar o cenário de mistura de SQL puro e ORM em um projeto, já que consiste em criar uma camada de acesso a dados que se concentra em gerenciar as operações de persistência de dados, enquanto o resto da aplicação trabalha com objetos de negócio. Dessa forma, a camada de acesso a dados pode ser responsável por esconder a complexidade de trabalhar com SQL puro ou ORM.

Utilizar o padrão de projeto Repository pode trazer diversas vantagens para o projeto, como:

  • Facilita a manutenção do código: ao centralizar as operações de acesso a dados em uma camada separada, fica mais fácil manter e modificar o código quando necessário, sem afetar o resto da aplicação.
  • Aumenta a flexibilidade: com o padrão Repository, é possível mudar a forma de acesso aos dados (por exemplo, de SQL puro para ORM ou vice-versa) sem precisar alterar o resto da aplicação.
  • Facilita o teste: ao separar a camada de acesso a dados, fica mais fácil testar as operações de persistência de dados de forma independente do resto da aplicação criando mocks dos repositórios ou injetando uma base de dados em memória, por exemplo.

É importante lembrar que a adoção de um padrão de projeto, com o Repository, pode aumentar a complexidade do projeto e exigir mais tempo de desenvolvimento inicial. Por isso, é importante avaliar as necessidades do projeto, as vantagens e desvantagens de utilizar o padrão antes de adotá-lo.

A seguir, um exemplo de uma classe Repository em TypeScript que utiliza uma ORM (neste caso, o TypeORM) e SQL puro para realizar operações de persistência de dados em um banco de dados:

import { EntityManager, getConnection } from 'typeorm';

export class UserRepository {
  private entityManager: EntityManager;

  constructor() {
    this.entityManager = getConnection().manager;
  }

  async findById(id: number): Promise<User | undefined> {
    // Utiliza a ORM para buscar um usuário pelo ID
    return this.entityManager.findOne(User, { id });
  }

  async create(user: User): Promise<void> {
    // Utiliza a ORM para inserir um novo usuário
    await this.entityManager.insert(User, user);
  }

  async update(user: User): Promise<void> {
    // Utiliza a ORM para atualizar um usuário existente
    await this.entityManager.update(User, user.id, user);
  }

  async delete(id: number): Promise<void> {
    // Utiliza a ORM para excluir um usuário pelo ID
    await this.entityManager.delete(User, { id });
  }

  async findByName(name: string): Promise<User[]> {
    // Utiliza SQL puro para buscar usuários pelo nome
    const query = `SELECT * FROM users WHERE name = $1`;
    const result = await this.entityManager.query(query, [name]);
    return result.map((row: any) => new User(row));
  }
}

Neste exemplo, a classe UserRepository possui métodos para realizar as operações de CRUD (Create, Read, Update, Delete) em um objeto do tipo User. Os métodos findById, create, update e delete utilizam a ORM (TypeORM) para realizar as operações, enquanto o método findByName utiliza SQL puro para buscar usuários pelo nome.

A classe UserRepository pode ser utilizada pelo resto da aplicação para realizar operações de persistência de dados de forma simples e centralizada, sem precisar se preocupar em escrever códigos SQL ou trabalhar diretamente com a ORM.

No exemplo acima, podemos observar que o TypeORM foi utilizado tanto para executar as queries via ORM quando para executar a query com SQL puro. Poderíamos ter outra biblioteca para executar as queries de SQL puro, mas sempre é interessante avaliar se uma biblioteca mais estável já resolve o problema sem que adicionemos outra.

Conclusão

Quando o objetivo é criar código limpo e legível e buscar sempre a melhor performance possível, é necessário dispor de princípios anteriores ao uso ou não de ORMs ou SQL puro. O desenvolvedor precisa decidir sobre o uso de SQL puro ou ORMs baseado em suas experiências, sempre focado nas necessidades e características específicas do projeto.

O uso de SQL puro pode ser vantajoso em projetos menores ou com menos complexidade, pois permite um maior controle sobre as consultas e pode resultar em código mais legível. No entanto, ao trabalhar com grandes quantidades de dados ou em projetos mais complexos, pode ser desafiador escrever e manter códigos SQL de forma otimizada e segura.

Por outro lado, o uso de ORMs pode simplificar o trabalho com o SQL e aumentar a produtividade do time em projetos maiores ou mais complexos. As ORMs permitem que o desenvolvedor trabalhe com objetos em seu código, enquanto a biblioteca cuida da conversão desses objetos em consultas SQL para serem enviadas ao banco de dados. Em alguns casos, as ORMs podem gerar consultas SQL não otimizadas, o que pode afetar o desempenho da aplicação, então, muita cautela ao escolher a biblioteca de ORM.

Para equilibrar as vantagens e desvantagens de ambas as abordagens, é importante avaliar as necessidades do projeto e utilizar a que melhor atenda às necessidades do projeto, seja SQL puro ou ORM. Além disso, é importante lembrar que o padrão de projeto Repository pode ser uma opção viável para misturar o uso de SQL puro e ORM de forma organizada e flexível.

Espero que gostem das reflexões contidas nesse artigo, e se, de alguma forma, for útil para você, comente e compartilhe.

Vlw ;=)

Facebook
Twitter
LinkedIn
Arquitetura de Software

Observabilidade: Dados e métricas antes de Ferramentas

E aí, pessoal! Beleza? Hoje vamos falar sobre um assunto elementar no desenvolvimento e manutenção de produtos de software como serviço (SaaS): Dados e métricas antes de ferramentas, em especial no contexto

Arquitetura de Software

O Códificador Limpo – Robert C. Martin

“O Codificador Limpo” de Robert C. Martin é um livro essencial para todos os desenvolvedores de software que desejam aprimorar suas habilidades em programação e produzir um código limpo e de qualidade.

Resumos de livros

Resumo do livro: Mindset

“Mindset: The New Psychology of Success” é um livro escrito pela psicóloga Carol S. Dweck. O livro fala sobre a importância da mentalidade em relação ao sucesso e apresenta duas tipos de

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *