Separação
de Interesses, do termo em inglês Separation of Concern
(SoC), esse é um conceito amplamente usado no desenvolvimento de
projetos complexos e com requisitos altos de escalabilidade,
portabilidade e de fácil manutenção. O desenvolvimento de software
sob o paradigma orientado a objetos procura elicitar principios que
facilitam o uso de SoC e também conduzam para um melhor
reaproveitamento e reutilização do código para novas gerações ou
versões do sistema.
Segundo
Martin Fowler, obter alta granularidade não é uma tarefa fácil, a
granularidade é um tipo de métrica empregada em orientação a
objetos e outros tipos de paradigmas que tem como característica
medir o grau que uma parte do sistema deve ser fatorado, de forma a
se criar um componente que possa ser reaproveitado. Existem dois
tipos de granulariade conhecidas, granularidade grossa e
granularidade fina, a primeira relaciona um alto grau de acoplamento
e um sistema pouco coeso e a segunda mede o inverso, um sistema
fracamente acoplado e fortemente coeso. Em geral, é desejável que
se tenha níveis de granularidade coerentes com o projeto
desenvolvido. Para se alcançar esses níveis deve-se realizar um
"trade-off" entre os princípios de orientação a objetos
e as necessidades do projeto, algumas variáveis que devem
ser identificados e controladas como pontos de prova são: (1)
desenvolvedores com conhecimento na linguagem; (2) flexibilidade do
sistema; (3) portabilidade do sistema; (4) desempenho; (5) tempo de
desenvolvimento; (6) capacidade de testar o sitema e efetuar a
depuração; (7) garantia de manutenção; (8) compreensão do
código; (9) duplicidade; (10) encapsulamento (Fowler; Larman; Booch;
Runbaum; Beck).
Esses
dez princípios enumerados anteriormente, estão diretamente
associadas com dois fatores
constantes ao
desenvolvimento de software
– Banco de Dados (BD) e Linguagem de Programação (LP). Essas duas
constantes levam a decisões de projetos importantes, um deles é se
a codificação da regra de negócio do sistema deve estar localizada
no banco de dados de dados, na forma de Stored Procedures (SP) ou
codificada na aplicação.
Em
seu artigo "Domain Logic and SQL"
(http://martinfowler.com/articles/dblogic.html), Martin Fowler,
explora esse tópico para um exemplo de Clientes que possuem muitos
pedidos e para cada pedido existe um Item cadastrado, cada item pode
sofrer um desconto agregado no pedido como um todo. A listagem 1 é
um exemplo de um método em Java recuperar pedidos a partir do mês
atual.
class
LogicaPedido{
Collection
result;
//outras
variaveis de instancias DAOCliente DAOPedido
public
Collection pedidoMesAtual(){
int
clienteID = daocliente.busca_cliente("bia");
for(Pedido
dataPedido: daopedido.busca_pedido(clienteID))
if(
dataPedido.pedidoAtual() )
result.add(dataPedido);
return
result;
}
}
class
DAOCliente{
public
int busca_cliente(String nome) throws SQLException{
String
sql="SELECT * FROM cliente WHERE nome=?";
int
id;
//Rotina
para usar o PreparedStatement
return
id;
}
}
class DAOPedido{
public
Collection busca_pedido(int id) throws SQLException{
String
sql="SELECT * FROM pedido WHERE id=?";
Collection
pedidos;
//Rotina
para usar o PreparedStatement
return
pedidos;
}
}
Listagem
1: Código
em Java para recuperar o pedido atual (adaptado de Fowler).
A
listagem anterior mostra apenas o DAOCliente, o objeto DAOPedido foi
omitido mas segue o mesmo princípio. Na listagem é possível
observar claramente a separação de interesses entre a aplicação e
o código SQL do banco de dados. A separação de interesses foi
obtida com auxílio do padrão de projeto DAO, nesse caso o padrão
de projeto consegue separar com alta granularidade os componentes do
sistema responsáveis pela camada de persistência, centralizando
assim a responsabilidade da lógica. Um modelo ideal para esse
exemplo, seria a integração dos padrões DAO e MVC.
Em
contrapartida, uma segunda abordagem é apresentada na listagem 2:
class
LogicaPedido{
Collection
result;
//outras variaveis de instancias DAOCliente DAOPedido
public Collection pedidoMesAtual() throws
SQLException{
int clienteID;
String nome;
PreparedStatemente st;
Collection
result;
String sql ="SELECT DISTINCT
MONTH(o.data) AS mes
INNER JOIN cliente c ON p.clienteID = c.clienteID WHERE (c.nome = ?) AND
(ip.produto = 'IPhone') GROUP BY ip.pedidoID, ip.data, c.nome HAVING
(SUM(ip.preco) > 5000)";
//cria
PreparedStatement
...
ResultSet rs = st.executeQuery(sql);
while(rs.next()){
result.add(rs.getDate("mes").toString());
}
return result;
}
}
Listagem
2: Código em Java para recuperar o pedido atual com SQL
(adaptado de Fowler).
A
listagem 2, é um exemplo de código em Java que usa diretamente uma
associação com a linguagem SQL. Embora o exemplo SQL não seja
complexo, essa listagem é um exemplo claro que a medida em que a
aplicação vai necessitando de novos recursos e consultas, o código
SQL pode se tornar cada vez mais complicado e de difícil manutenção.
Um outro exemplo é mostrado abaixo, na Listagem 3, onde é usado
para retornar um Pedido uma Stored Procedure (SP) em
Postgres/plpgsql. Essa SP usa um cursor para retornar um conjunto de
itens, esse cursor é aberto com um comando SQL equivalente ao da
listagem 2, observe no entanto as diferenças entre as diferenças
entre as formas de declaração entre as listagens anteriores.
CREATE OR REPLACE FUNCTION fn_retorna_pedido(integer) RETURNS TEXT AS
$$
DECLARE
ppedido
ALIAS FOR $1;
cursor
REFCURSOR;
col_data
exemplo.itens_pedido.data%TYPE;
result
TEXT;
BEGIN
result:='''';
OPEN
cursor FOR SELECT DISTINCT MONTH(ip.data) AS mes
cliente c ON p.clienteID = c.clienteID WHERE (c.nome = ppedido)
AND (ip.produto = ''IPhone'') GROUP BY ip.pedidoID, ip.data, c.nome
HAVING
(SUM(ip.preco) > 5000);
LOOP
FETCH cursor
INTO
col_data
EXIT
WHEN NOT FOUND;
result:=result||col_data
|| '' \n ''; /* || é uma concatenacao */
END
LOOP;
RETURN result;
END;
$$
LANGUAGE
''plpgsql'' VOLATILE
Listagem
3: Código de uma Stored Procedure em Postgres/plpgsql.
Como pode-se observar, da primeira listagem até a última (Listagem de 1 a 3), que o nível de abstração e semântica vai do maior para um menor grau de abstração. A última listagem não apresenta, um nível desejádo de SoC e também viola condições e conceitos importantes de orientação a objetos como encapsulamento e reutilização de código. Pode-se observar que a última listagem apresenta um alto nível de acoplamento e baixa coesão, pois a função fn_retorna_pedido() não pode ser um componente e "plugada" facilmente em outras partes do sistema (observe os métodos da listagem 1).
Dessa forma, como BD e LP são constantes deve-mos então observar as variáveis apresentadas no início deste artigo.
Desenvolvedores com conhecimento na Linguagem
A
Figura 1 ilustra dez Linguagens de Programação (LP''s) em função
da porcentagem/popularidade dos principais motores de buscas da
Internet.
Figura
1: Dez linguagens de
programação (adaptado TIOBE - http://www.tiobe.com/).
Como
pode-se observar, as linguagens de referência no índice TIOBE (mes
de referência junho de 2010), com aproveitamento acima de 50% são
as linguagens C/C++ e Java. É conveniente notar, que segundo o
índice TIOBE essas linguagens são as linguagens mais populares a
patir dos principais motores de buscas atuais. Nota-se uma mínima
popularidade em relação a família de linguagens PL/SQL (3,94%)
contra (90,17%) da linguagem Java.
Essa
característica tem um impácto direto na quantidade de
desenvolvedores que tem conhecimento sobre linguagem de banco de
dados (SP), isso pode em certo sentido prejudicar o bom
desenvolvimento do sistema caso o sistema seja desenvovido com prazos
críticos e com pessoal não treinado.
Flexibilidade
do sistema, Portabilidade e Desempenho
Linguagem
de Programação como PL/SQL são linguagens que estão diretamente
ligadas a banco de dados como Oracle, mySQL, Postgres, SQL Server,
Informix, Sybase, DB2 entre outros. Segundo Martin Fowler, existe
uma dependência direta entre um sistema de banco de banco de dados e
a capacidade do sistema se tornar mais flexível. O código
totalmente implementado no banco de dados, caracteriza por outro lado
um alto desempenho se comparado com as chamadas preparadas em Java. O
desenpenho do banco de dados se comparado com rotinas alocadas no
pool de conexão da linguagem Java e servers containers como o Apache
Tomcat e Glassfish podem executar cerca de vinte vezes mais rápidas.
Esse
resultado, em alguns casos, é tomado como o primeiro na decisão de
projeto e arquitetura de um sistema, no entato tal prática deve ser
claramente analisada. Como comparação, considere uma implementação
em linguagem C para uma tarefa de troca de valores, esse tipo de
operação é muito comum para algoritmos de ordenação como o
Bubble
Sort.
A
Listagem 4, abaixo mostra um exemplo de uma chamada em Assembly
(AT&T) para realizar uma operação de troca.
void troca_lm(int a, int
b){
int aTemp,bTemp;
asm ("movl
%2, %%eax;"
"movl
%3, %%ebx;"
"movl
%%eax, %%edx;"
"movl
%%ebx, %%eax;"
"movl
%%edx, %%ebx;"
"movl
%%eax, %0;"
"movl
%%ebx, %1;"
:"=r"(aTemp),"=r"(bTemp)
/* output */
:"r"(a),"r"(b)
/* input */
:"%eax",
"%ebx", "%edx" /* clobbered register */
);
}
A
Figura 2 ilustra o tempo de troca em função do tempo.
Figura
2:
Número de troca em função do tempo para código em C e AT&T.
Como
era de se espera, observa-se uma acentuada melhora da linguagem de
montagem sobre a linguagem C. Contudo, assim como linguagens de
consultas como PL/SQL e Stored Procedures (SP), o programador deve
conhecer em detalhes a linguagem a reconhecer que também não são
todos os pontos ou partes do sistema que devem ser implementados no
banco de dados. Para esse caso simples de uma troca, o problema em C
torna-se trivial, mas para outros tipos de rotinas se torna
praticamente inaceitável o uso de linguagem de montagem nos dias
atuais.
A
linguagem C com o uso da inner
function – asm(), permite
facilmente a integração de código de máquina em um programa
estruturado. Pode-se, constatar também que o desenvolvimento em
linguagem C em ambientes Linux é totalmente facilitado pela adoção
de técnicas de depuração como o uso da ferramenta GDB. Uma aspecto
contraditório quanto ao uso de Stored Procedures em banco de dados é
o uso de uma ferramenta de depuração e teste. Atualmente é escasso
o número de ferramentas que facilitam a depuração e o teste, a
ferramenta dbUnit é uma extensão do JUnit que permite realizar
teste de unidade em banco de dados, mas que não fornece nenhuma
garantia estrutural ou de cobertura.
Outro aspecto ainda não muito bem definido é o uso de Stored Procedures com o desenvolvimento Ágil, em eXtreme Programming (XP) procura-se usar o desenvolvimento focado em TDD (Test-Driven Development), contudo ainda não é muito claro a integração e a real vantagem de SP com a Agilidade.
Outro aspecto ainda não muito bem definido é o uso de Stored Procedures com o desenvolvimento Ágil, em eXtreme Programming (XP) procura-se usar o desenvolvimento focado em TDD (Test-Driven Development), contudo ainda não é muito claro a integração e a real vantagem de SP com a Agilidade.
Para
finalizar a tabela abaixo ilustra os prós e contras quanto ao uso de
linguagem PL/SQL/SP.
Variáveis
|
Prós
|
Contra
|
Desenvolvedorescom
conhecimento na linguagem
|
|
-
|
Portabilidade
do sistema
|
|
-
|
Tempo
de desenvolvimento
|
|
-
|
Desempenho
|
+
|
|
Capacidade
de testar o sitema e efetuar a depuração
|
|
-
|
Garantia
de manutenção
|
|
-
|
Compreensão
do código
|
+
|
|
Duplicidade
|
|
-
|
Encapsulamento
|
|
-
|
Flexibilidade
do sistema e Reuso
|
|
-
|
Tabela
1:
Tabela comparativa entre prós e contras.
Conclusão
Como pode-se constatar o artigo apresenta uma visão geral sobre metricas em OO e também discute algumas das boas práticas de programação. É importante observar que o presente artigo discutiu de forma abrangente o emprego de SP no banco de dados versus a sua respectiva implicações que isso pode provocar. O artigo também apresente 10-variáveis que são fortes candidatas na tomada de decisão de projetos complexos. Vale observar que um aspecto não identificado no artigo é o caráter segurança, mas que será abordado em futuras pesquisas.
Referências
dbUnit - http://www.dbunit.org/
Martin Fowler - http://martinfowler.com/articles/dblogic.html
TIOBE - http://www.tiobe.com/
Design Patterns - http://sourcemaking.com/design_patterns