Go Language, Relational Databases and ORMs

Fernando Eugenio Correa
Mercado Libre Tech
Published in
8 min readJul 12, 2022

Esta é a primeira história da série “Golang: ORM or not ORM at Mercado Libre”. Aproveite!

Quando comecei no Mercado Livre, fui apresentado a uma cultura incrível e também a novos desafios profissionais.

No primeiro mês na nova equipe (Code Ecosystem), cada nova pessoa enfrenta um desafio de crescimento. Esta atividade consiste na implementação de uma aplicação simples que nos permite estar conectados com a maioria das experiências que encontraremos no nosso dia-a-dia de trabalho. Permite:

  • interagir com nossos pares;
  • trocar de informações por meio de diferentes canais e com diferentes equipes e pessoas;
  • ter conhecimento do ambiente de desenvolvimento e ferramentas, metodologias e padrões seguidos.

A implementação desse desafio é bastante simples até que tenhamos que interagir com um banco de dados de um projeto Golang. Eu e os que vieram antes de mim costumávamos dizer: “Ah, entrei para uma grande empresa. Está tudo feito”; Mas não funciona assim para nós. À medida que continuamos avançando e inovando nossos produtos, o mesmo acontece com nossa tecnologia. É por isso que queríamos responder a uma grande pergunta:

Como devemos trabalhar com bancos de dados no Mercado Livre usando a linguagem Go?

Antes de ir mais fundo, gostaria que todos vocês, meus leitores incríveis, estejam na mesma página. Vamos dar uma olhada em alguns conceitos obrigatórios juntos. 👇

Linguagem & Conceitos Chave

Um pouco sobre Golang

Golang é basicamente uma linguagem de programação procedural (e estruturada), como C, Fortran e Pascal. Go é essencialmente uma versão atualizada do C projetada para ser mais acessível aos desenvolvedores e para atender a algumas prioridades da computação moderna, como networking systems architecture e concorrência.

Algumas características importantes são (que você pode consultar neste artigo ou nesta parte da documentação):

  • simplicidade (legibilidade e manutenção são o foco aqui);
  • padronização (sua poderosa biblioteca padrão provê muito do que é essencial);
  • velocidade de compilação;
  • performance;
  • facilidade de aprendizado e uso (é amigável e com vantagens claramente identificáveis);
  • um design semelhante a C para programação em nível de sistema;
  • suporte a testes;
  • concorrência;
  • a sintaxe sucinta (como Python).

É estranho pensar que Golang está entre uma linguagem de sistema (propósito original) e uma linguagem de script (como na verdade é usada por desenvolvedores em muitas empresas ao redor do mundo).

Relational Database Management System (RDBMS)

Um sistema de gerenciamento de banco de dados relacional é um programa que permite criar, atualizar e administrar um banco de dados relacional. A maioria dos RDBMs usa a linguagem SQL (e variações de SQL) para acessar o banco de dados.

Banco de Dados Relational

Um banco de dados relacional é um tipo de banco de dados que usa uma estrutura que nos permite identificar e acessar dados relacionados a outro dado no banco de dados. É uma coleção de itens de dados que apresentam relacionamentos pré-definidos entre eles.

Esses itens são organizados como um conjunto de tabelas com colunas e linhas (como você pode ver abaixo na Imagem 1). As tabelas são usadas para armazenar informações sobre os objetos a serem representados no banco de dados. Cada coluna em uma tabela contém um determinado tipo de dados e um campo armazena o valor real de um atributo. As linhas na tabela representam uma coleção de valores relacionados de um objeto ou entidade. Cada linha em uma tabela pode ser marcada com um identificador exclusivo chamado chave primária, e as linhas entre várias tabelas podem ser relacionadas usando chaves estrangeiras. Esses dados podem ser acessados ​​de muitas maneiras diferentes sem reorganizar as próprias tabelas do banco de dados.

Image 1: simple relational database organization
Imagem 1: organização de banco de dados relacional simples

Structured Query Language (SQL)

SQL é uma linguagem de programação usada para se comunicar com dados armazenados em um sistema de gerenciamento de banco de dados relacional. A sintaxe SQL é semelhante ao idioma inglês, o que torna relativamente fácil escrever, ler e interpretar.

SQL tornou-se um padrão do American National Standards Institute (ANSI) em 1986. O padrão ANSI SQL é suportado por todos os mecanismos de banco de dados relacionais populares, e alguns desses mecanismos também possuem extensões para ANSI SQL para oferecer suporte a funcionalidades específicas. SQL é usada para adicionar, atualizar ou excluir linhas de dados, recuperando subconjuntos de dados para processamento de transações e aplicativos de análise e para gerenciar todos os aspectos do banco de dados.

ORM (Object-Relational Mapping)

Um ORM é uma técnica ou — para simplificar — uma biblioteca que automatiza a transferência de dados armazenados em tabelas de banco de dados relacionais em objetos — e é extremamente útil para linguagens de programação orientada a objetos. ORM é uma camada de abstração que permite comunicar dados relacionais com paradigmas orientados a objetos. O problema de mapeamento objeto/relacional é difícil, e em POO (Programação Orientada a Objetos), os principais pontos de referência são os objetos. A abstração apresentada para ORMs pode resolver esse problema e o problema do paradigma entre dados relacionais e linguagens OOP.

Bancos de Dados e Golang

Agora é hora de mergulhar em alguns pacotes ORM (e outros não ORM) que serão úteis para comparação e talvez para estudos futuros. Apenas alguns pacotes são mencionados abaixo, mas nos ajudarão a obter uma pesquisa mais completa ou iniciar uma nova pesquisa.

É possível trabalhar com uma grande variedade de soluções. Como desenvolvedor, você pode optar por manipular suas próprias consultas SQL puras, apenas gerar suas estruturas, atribuir gerenciamento total ao ORM, manter algum foco no desempenho, seja o que for.

  1. database/sql: é um pacote SQL que fornece uma interface genérica em torno de bancos de dados SQL (ou semelhantes a SQL). O pacote sql deve ser usado em conjunto com um driver de banco de dados. Para usá-lo, você precisará do próprio pacote, bem como de um driver para o banco de dados específico que deseja. É recomendável que você não use o pacote de driver diretamente. Em vez disso, seu código deve se referir apenas aos tipos definidos no database/sql, se possível. Isso evitará que seu código seja dependente do driver, portanto, se no futuro você quiser mudar para um driver diferente, poderá fazê-lo com uma alteração de código mínima. Este é apenas um dos muitos benefícios que você encontrará ao fazer programação baseada em interfaces (talvez outro dia possamos aprofundar este tópico).
    Para ter uma visão clara, algumas das complexidades de baixo nível na conexão com o banco de dados e no gerenciamento do pool de conexões, as APIs expostas parecem fazer um pouco mais do que você realmente espera, o que pode criar um pouco de confusão sobre como usá-las.
  2. dbr: o pacote dbr fornece adições ao database/sql do Go para desempenho e conveniência “super” rápidos, mas a documentação é escassa e pobre.
  3. GOQU: não é um ORM, mas um construtor e executor de SQL. O GOQU não fornece recursos ORM comuns, como bindings e hooks. A melhor parte de sua proposta é uma solução leve de meio-termo.
  4. sqlx: este pacote ORM torna possível simplificar a implementação da camada de banco de dados mantendo dois pontos importantes (comparado com database/sql). Este pacote expressa a semântica do SQL claramente para otimização posterior, especialmente em análises de dados e outros SQLs complexos, e reduz alguns encapsulamentos “inúteis” melhorando o desempenho do programa.
  5. dbq: este pacote visa erradicar o código padrão em operações relacionadas ao banco de dados. Recentemente (junho de 2020), o criador fez uma grande reformulação em toda a biblioteca para melhorar drasticamente seu desempenho. Alguns resultados de benchmark apresentados após essas mudanças mostram uma vantagem insignificante sobre o uso do sqlx (o melhor ORM para Go considerando o desempenho).
  6. rel: é uma camada de acesso de banco de dados moderna para Golang — testável, extensível e criada em uma API limpa e elegante. Ele fornece um repositório testável com um pacote reltest integrado. A estrutura é ótima, mas muito nova para permitir que os desenvolvedores confiem em um projeto que pode não ter atualizações constantes, participação da comunidade, que não suporta alto tráfego ou simplesmente ainda não é comprovadamente capaz de suportar.
  7. ent: é um ORM do Facebook e um projeto open source. Fornecendo ORM para modelagem e consulta de dados, a estrutura ent renderiza uma API para modelar qualquer esquema de banco de dados como objetos Go. Os usuários podem executar consultas e agregações e percorrer estruturas gráficas. O projeto ent foi inspirado no Ent, um framework de entidades usado internamente no Facebook. O Roteiro para uma versão oficial V1 pode ser visitado em https://github.com/ent/ent/issues/46 .
  8. GORM: Este é um ORM amigável ao desenvolvedor que tem grande suporte da comunidade e uma documentação fácil de seguir. O GORM fornece operações CRUD e também pode ser usado para a migração inicial e criação do esquema do banco de dados. Mais algumas coisas que o GORM faz bem incluem sua extensibilidade com suporte a plug-ins nativos, sua confiabilidade em testes e grupos de associações um-para-um e um-para-muitos. GORM também suporta sqlite, mysql, postgres e mssql.

Agora estamos prontos, vamos ao nosso ponto de discussão principal 😬.

Como devemos trabalhar com bancos de dados no Mercado Livre usando a linguagem Go

Provavelmente você já pesquisou essa resposta antes (se ainda não o fez, talvez tenha feito uma pesquisa rápida agora). A resposta é sempre obtida, não como um padrão ou recomendação de uso que considera fatores técnicos, mas como um posicionamento particular de preferência ou facilidade de uso pessoal (e há amantes e inimigos em todos os lugares). Isso deixa claro que não existe uma bala de prata para todos os cenários.

Buscando possíveis respostas na internet, geralmente vemos o mesmo viés, apresentando um lado como o correto sem apresentar uma análise ou mais informações técnicas.

Experiências pessoais não são verdadeiras ou falsas, boas ou ruins; são simplesmente experiências diferentes com muitas coisas para aprender. No entanto, às vezes podem não ter os argumentos e exemplos técnicos necessários para uma grande empresa basear suas decisões. E é exatamente isso que fazemos na equipe do Code Ecosystem: fornecemos os argumentos e a base técnica que sustentam nossas experiências, a fim de construir um ecossistema de desenvolvimento de tecnologia mais maduro, sustentável, resiliente e saudável.

Leia mais na segunda parte desta série chamada “Using Go at Meli: ORM or !ORM” onde também apresentaremos dados técnicos sobre as possibilidades existentes que usamos atualmente em nossas soluções. O que nos motivou a compartilhar essas informações com os desenvolvedores é que geralmente é difícil definir se deve-se buscar ORM ou !ORM e quais “filtros” seriam ideais para atingir o objetivo.

References

The Go Programming Language: https://golang.org/

A Mini-Guide on Go Programming Language: https://appinventiv.com/blog/mini-guide-to-go-programming-language/

Effective Go: https://go.dev/doc/effective_go

The Go Programming Language: by Alan A. A. Donovan, Brian W. Kernighan

sql — database/sql: https://pkg.go.dev/database/sql

dbr — database/sql addictions: https://pkg.go.dev/github.com/gocraft/dbr

goqu — SQL builder and query lib: https://github.com/doug-martin/goqu

ORM — sqlx : http://jmoiron.github.io/sqlx/

ORM — dbq: https://github.com/rocketlaunchr/dbq

ORM — rel: https://go-rel.github.io/

ORM — ent: https://entgo.io/docs/getting-started/

ORM — GORM: https://pkg.go.dev/gorm.io/gorm

Schneider, Bill — Foo/Foo Impl : http://wrschneider.github.io/2015/07/27/foo-fooimpl-pairs.html

Fowler, Martin — Interface Implementation Pair: https://martinfowler.com/bliki/InterfaceImplementationPair.html

Fowler, Marin — ORM Hate: https://martinfowler.com/bliki/OrmHate.html

Roadmap for V1 — ent ORM: https://github.com/ent/ent/issues/46

Object-Relational Impedance mismatch: https://en.wikipedia.org/wiki/Object%E2%80%93relational_impedance_mismatch

Generate CRUD Golang code from SQL | Compare db/sql, gorm, sqlx, sqlc: https://dev.to/techschoolguru/generate-crud-golang-code-from-sql-and-compare-db-sql-gorm-sqlx-sqlc-560j

Database Layer with Golang by Holanda, Rafael

Bases Relacionales by Marsollier, Nestor

--

--