Bad Smells (mal cheiros) em Bancos de Dados
timbira
A empresa brasileira de PostgreSQL
Palestrante
timbira
• Fabrízio de Royes Mello • Desenvolvedor PostgreSQL • Líder do PostgreSQL Brasil • Pós-Graduando Uniritter (Agile) • @fabriziomello
• http://fabriziomello.blogspot.com • Timbira
• Consultor/Mentor/Coach
• A empresa brasileira de PostgreSQL • Consultoria
• Desenvolvimento • Suporte 24x7 • Treinamento
Sobre este material
timbira
• esta apresentação está disponível em: http://www.timbira.com.br/material
• esta apresentação está sob licença Creative Commons
Atribuição 3.0 Brasil:
http://www.creativecommons.org/licenses/by/3.0/br
• Embora este material tenha sido elaborado com toda precaução, os autores não assumem quaisquer
responsabilidades por erros, omissões ou danos resultantes da utilização das informações aqui contidas.
• Se você encontrar qualquer erro, por favor reporte-o a contato@timbira.com.br
Resumo
timbira
1 Prelúdio 2 Introdução
3 Bad Smells
4 Considerações Finais
Como tudo começou na minha vida...
timbira
• 1993 - Basic
• 1994 - CLIPPER (e um pouco de C)
• 1996 - C e Pascal
• 1998 - SQL - mudou minha vida ;-)
• 1999 - Teoria Relacional • ... • 2004 - Web (PHP, HTML, CSS, Javascript) • ... • 2009 - Database Refactoring • ...
Resumo
timbira
1 Prelúdio
2 Introdução 3 Bad Smells
4 Considerações Finais
Bancos de Dados
timbira
Tendem a se deteriorar ao longo do tempo. Alguns motivos: • crescimento volume de dados/transações;
• aumento natural de usuários que o utilizam;
• dificuldades na evolução do schema;
Refatoração em Bancos de Dados
timbira
Deterioração + Mudanças em Requisitos = Necessidade de Refatoração.
Mas não é tão simples assim:
• além de manter comportamento também é preciso manter informação (dados);
• acoplamento com diversas origens (apps, bds, integrações, 3rd, ...)
Refatoração em Bancos de Dados
timbira
Deterioração + Mudanças em Requisitos = Necessidade de Refatoração.
Mas não é tão simples assim:
• além de manter comportamento também é preciso manter informação (dados);
• acoplamento com diversas origens (apps, bds, integrações, 3rd, ...)
Resumo
timbira
1 Prelúdio
2 Introdução
3 Bad Smells
4 Considerações Finais
Code Smell
timbira
É uma categoria comum de problema no código fonte que indica a necessidade de refatoração. (Martin Fowler)
Database Smell
timbira
Similarmente aos Code Smells existem problemas comuns em bancos de dados que indicam uma potencial necessidade de refatoração. (Scott Ambler)
Database Smell
timbira
Multi-purpose column
Se uma coluna for utilizada para vários fins, é provável que exista um código extra para garantir que a mesma seja usada
corretamente e, muitas vezes, verificando valores de uma ou mais colunas.
Multi-purpose column
timbira
CREATE TABLE pessoa (
id SERIAL PRIMARY KEY,
tipo CHAR(1) CHECK (tipo IN (’F’, ’J’)), nome VARCHAR(100) NOT NULL,
data DATE );
• Se tipo = ’F’ então DATA = nascimento
• Se tipo = ’J’ então DATA = inicio atividades
Multi-purpose column
timbira
CREATE TABLE pessoa (
id SERIAL PRIMARY KEY,
tipo CHAR(1) CHECK (tipo IN (’F’, ’J’)), nome VARCHAR(100) NOT NULL,
data DATE );
• Se tipo = ’F’ então DATA = nascimento
Multi-purpose column
timbira
Sugestão(ões) Database Refactoring: • Split Column
• Move Column
Database Smell
timbira
Multi-purpose table
Quando uma tabela é utilizada para armazenar vários tipos de entidades provavelmente existe uma falha de projeto.
Multi-purpose table
timbira
CREATE TABLE pessoa (id SERIAL PRIMARY KEY,
tipo CHAR(1) CHECK (tipo IN (’F’, ’J’)), nome VARCHAR(100) NOT NULL,
nome_fantasia VARCHAR(100), cnpj CHAR(14), cpf CHAR(11), rg CHAR(10), data DATE );
• Se tipo = ’F’ então NOME = nome,
• Se tipo = ’J’ então NOME = razão social
• Se tipo = ’F’ então CNPJ e NOME_FANTASIA = NULL
• Se tipo = ’J’ então CPF e RG = NULL
Multi-purpose table
timbira
CREATE TABLE pessoa (id SERIAL PRIMARY KEY,
tipo CHAR(1) CHECK (tipo IN (’F’, ’J’)), nome VARCHAR(100) NOT NULL,
nome_fantasia VARCHAR(100), cnpj CHAR(14), cpf CHAR(11), rg CHAR(10), data DATE );
• Se tipo = ’F’ então NOME = nome,
Multi-purpose table
timbira
Sugestão(ões) Database Refactoring: • Split Column
• Move Column
• Split Table
Database Smell
timbira
Redundant data
É um problema sério em bases de dados porque quando o dado é armazenado em vários locais, ocorre uma oportunidade de inconsistência.
Redundant data
timbira
CREATE TABLE sys.usuario (id SERIAL PRIMARY KEY, nome VARCHAR(100) NOT NULL, endereco VARCHAR(100),
numero INTEGER, complemento VARCHAR(40) );
CREATE TABLE rh.funcionario (
id SERIAL PRIMARY KEY, nome VARCHAR(100) NOT NULL, endereco VARCHAR(100),
numero INTEGER, complemento VARCHAR(40) );
Redundant data
timbira
Sugestão(ões) Database Refactoring: • Merge Tables
• Move Data
Database Smell
timbira
Tables with too many columns
Quando uma tabela tem muitas colunas é indicativo de falta de coesão, pois está armazenando dados de várias entidades.
Tables with too many columns
timbira
CREATE TABLE pessoa (
id SERIAL PRIMARY KEY, nome VARCHAR(100) NOT NULL, end_entrega VARCHAR(200), end_cobranca VARCHAR(200), end_residenc VARCHAR(200), end_profiss VARCHAR(200), fone_celular VARCHAR(20), fone_casa VARCHAR(20), fone_fax VARCHAR(20), fone_contato VARCHAR(20)
Tables with too many columns
timbira
CREATE TABLE parametro (
parametro1 VARCHAR(100), parametro2 VARCHAR(100), parametro3 VARCHAR(100), parametro4 VARCHAR(100), parametro5 VARCHAR(100), parametro6 VARCHAR(100), ... parametroN VARCHAR(100) );
Tables with too many columns
timbira
Sugestão(ões) Database Refactoring: • Split Table
Database Smell
timbira
Tables with too many rows
Tabelas muito grandes podem nos levar a problemas de performance.
O custo (memória e tempo) para buscar ou alterar dados em uma tabela varia de acordo com o número de linhas.
Tables with too many rows
timbira
CREATE TABLE measurement (
city_id int not null, logdate date not null, peaktemp int,
unitsales int );
CREATE TABLE measurement_y2006m02 ( ) INHERITS (measurement); CREATE TABLE measurement_y2006m03 ( ) INHERITS (measurement); ...
CREATE TABLE measurement_y2007m11 ( ) INHERITS (measurement); CREATE TABLE measurement_y2007m12 ( ) INHERITS (measurement);
Tables with too many rows
timbira
Sugestão(ões) Database Refactoring: • Split Table
• Move Rows
• Move Column
Database Smell
timbira
Smart columns
Coluna onde em diferentes posições do dado representam conceitos diferentes.
Smart columns
timbira
CREATE TABLE processo (
numero CHAR(10) PRIMARY KEY, ...
);
CREATE TABLE debito (
processamento CHAR(15) PRIMARY KEY ...
);
• numero = 4 digitos ano + 6 digitos sequencial
• processamento = 4 digitos ano + 6 digitos sequencial + 2 digitos parcela + 2 digitos total parcelas + 1 digito verificador
Smart columns
timbira
CREATE TABLE processo (
numero CHAR(10) PRIMARY KEY, ...
);
CREATE TABLE debito (
processamento CHAR(15) PRIMARY KEY ...
);
Smart columns
timbira
Sugestão(ões) Database Refactoring: • Split Column
Database Smell
timbira
Phantom foreign-key
Quando uma coluna em uma tabela pode receber um valor que dependendo de outra coluna estabelece relacionamento de chave estrangeira com outra tabela.
Phantom foreign-key
timbira
CREATE TABLE tabela ( ...
tipo INTEGER, codigo INTEGER, ...
);
• Se TIPO = 1 entao CODIGO é ref. TABELA1
• Se TIPO = 2 entao CODIGO é ref. TABELA2
• Se TIPO = 3 entao CODIGO é ref. TABELA3
• ...
Phantom foreign-key
timbira
CREATE TABLE tabela ( ...
tipo INTEGER, codigo INTEGER, ...
);
• Se TIPO = 1 entao CODIGO é ref. TABELA1
• Se TIPO = 2 entao CODIGO é ref. TABELA2
Phantom foreign-key
timbira
Sugestão(ões) Database Refactoring: • Introduce new table
• Introduce table constraint
• Move Column
Database Smell
timbira
Wrong data type
Tipos de dados possuem uma assinatura, que descreve as validações mínimas para seu uso.
Wrong data type
timbira
CREATE TABLE pessoa (id SERIAL PRIMARY KEY, nome VARCHAR(100) NOT NULL, cnpj CHAR(14),
cpf CHAR(11),
rg CHAR(10)
);
CREATE TABLE atributo_dinamico ( nome VARCHAR(100),
tipo INTEGER, valor TEXT );
• CNPJ, CPF e RG não são números?
• VALOR é um campo "flex"
Wrong data type
timbira
CREATE TABLE pessoa (id SERIAL PRIMARY KEY, nome VARCHAR(100) NOT NULL, cnpj CHAR(14),
cpf CHAR(11),
rg CHAR(10)
);
CREATE TABLE atributo_dinamico ( nome VARCHAR(100),
tipo INTEGER, valor TEXT );
Wrong data type
timbira
Sugestão(ões) Database Refactoring: • Replace column
Database Smell
timbira
Smells detectados pela minha experiência (não estão na literatura):
• Phantom foreign-key
• Wrong data type
Database Smell
timbira
Fear of change
Dentre os database smells citados, devemos ter atenção especial a este, pois pode ser considerado o pior de todos, pois:
• inibe a inovação,
• reduz a efetividade,
• produz ainda mais bagunça e
• ao longo do tempo a situação fica cada vez pior.
"Lempre-se do valor Coragem do XP!!!!"
Resumo
timbira
1 Prelúdio
2 Introdução
3 Bad Smells
Considerações Finais
timbira
• Coragem para evoluir
• Taxonomia dos Database Smells
• Ferramenta para detecção
Referências
timbira
• Refactoring Improving the Desing of Existing Code (Martin Fowler)
• Refactoring Databases: Evolutionary Database Design (Scott Ambler e Pramod Sadalage)
• http://martinfowler.com/books/refactoring.html
• http:
//agiledata.org/essays/databaseRefactoring.html
• http://www.agiledata.org/essays/ databaseRefactoringSmells.html
Perguntas
timbira
?
Fabrízio de Royes Mello @fabriziomello fabrizio@timbira.com.br http://www.timbira.com.br http://slideshare.net/fabriziomello