monografia

Propaganda
Objetos, tabelas e camada de persistência
Geralmente, as aplicações possuem pouca utilidade sem os dados
pertinentes ao seu fim. Por exemplo, um site de um jornal, sem as notícias
diárias, sem imagens, sem os fatos. Ir a um jornaleiro e comprar a edição
impressa nos daria além da funcionalidade, de nos manter atualizados, nos
daria também a informação propriamente dita. É necessário entender a
importância dos dados e de como eles são processados e armazenados.
Em um projeto de software a manipulação dos dados é crucial para o
sucesso do projeto. Uma pesquisa que consome muito tempo, um dado mal
formatado como saída, imprecisão no armazenamento dos dados, todos esses
fatores devem ser analisados e levados em consideração durante o projeto de
um software.
Ao longo do tempo surgiram vários meios de se realizar o
armazenamento dos dados utilizados pelas diversas aplicações. Nos
primórdios o armazenamento dos dados era feitos de forma bastante precária,
utilizando tecnologias lentas e com capacidade de armazenamento reduzida.
Com o passar do tempo as tecnologias de armazenamento evoluíram
significativamente. Os equipamentos se tornaram mais ágeis e com capacidade
de armazenamento nunca antes imaginada.
Acompanhando
essa
evolução
física,
também
as
metodologias
empregadas no armazenamento e no controle dos dados evoluíram. Novos
paradigmas de programação surgiram a partir da necessidade de melhorar o
processo de desenvolvimento de software. Nesse contexto o paradigma
estrutural de programação foi gradualmente substituído pelo paradigma de
desenvolvimento orientado a objetos.
O paradigma de desenvolvimento orientado a objetos nos leva a dividir
os grandes problemas em problemas menores. Seu principal objetivo é fazer
tudo via objetos, através da interação entre eles e do compartilhamento dos
dados sensíveis ao problema, dessa forma solucionando o grande problema
[Hayder, 2007].
Atualmente o paradigma de orientação a objetos é amplamente utilizado,
este propõe uma visão no qual
classes são definidas imitando o
comportamento de entidades do mundo real. Objetos são instanciados
representando unidades de uma determinada classe. Capaz de conter certos
dados e executar ações. Isto é, manipular os dados de entrada a fim de obter
uma saída coerente com aquilo que foi planejado e programado. Diversos
objetos se comunicam através do uso de métodos previamente definidos. Uma
classe pode, através do uso de herança, estender as funcionalidades e
atributos de outras classes.
Os benefícios do uso da orientação a objetos são diversos entre eles,
Hayder, cita:

Reusabilidade – Um objeto é capaz de ser utilizado em outro
ambiente diferente daquele onde foi planejado. Também é possível,
estender um determinado objeto e assim alterar apenas as
características que são necessárias aproveitando todo o código já
escrito.

Refatoração – Ao criar objetos pequenos e bem definidos, torna-se
mais fácil a correção e refatoração de um projeto ou aplicação.

Capacidade de extensão – Quando for necessário adicionar novas
funcionalidades a um sistema já pronto, a extensão de um
determinado objeto pode oferecer um meio seguro para realizar esta
operação. Uma vez que ao refatorar um determinado objeto, seja
alterando-o ou criando uma nova classe que herda de alguma outra
já existente, você estará estendendo as funcionalidades do mesmo
sem afetar as outras funcionalidades.

Manutenibilidade – A programação orientada a objetos oferece uma
forma de escrita de código intuitiva e de fácil percepção das ações
que estão acontecendo num determinado trecho de código.

Eficiência – A orientação a objetos oferece uma vasta coleção de
padrões de projeto que maximizam a eficiência no desenvolvimento
da aplicação.
Em um projeto orientado a objetos, convém que a aplicação seja
distribuída em diferentes camadas. Cada camada com uma funcionalidade
explicita que deverá ser bem executada e facilmente acoplada ao restante do
sistema. Essa visão de camadas é amplamente difundida.
É comum a criação de uma camada especifica cuja função é a
realização da persistência dos dados da aplicação. Isto é, ela deve ser capaz
guardar as informações de maneira coesa e segura. Esta camada deve ser
capaz de realizar alterações nos dados persistidos quando necessário, bem
como ser capaz também de excluir permanentemente os dados quando
necessário e por fim deve ser capaz de fornecer um método para recuperar os
dados que foram previamente persistidos.
O PHP oferece diversos mecanismos para que o programador realize a
persistência dos dados. Entre as alternativas estão o uso de arquivos, arquivos
XML, arquivos CSV, diversos drivers para conexão com bancos de dados,
entre outros. É comum a escolha do banco de dados para o armazenamento
das informações. O PHP utiliza o driver como mecanismo de troca de
informações entre a aplicação e o SGBD, para o usuário isso é transparente
através do uso de uma API definida.
Os sistemas gerenciadores de bancos de dados (SGBDs), como por
exemplo, Oracle, MySQL, DB2, entre outros. São sistemas que oferecem
mecanismos para gerir o acesso, a manipulação e a organização dos dados
em meios físicos. Estes também oferecem interfaces para que os usuários
sejam capazes de realizar as operações básicas que foram citadas no
anteriormente.
Porém a grande maioria dos SGBDs que o mercado hoje oferece é
relacional, ou seja, não trabalham com o conceito de orientação a objetos. Isso
cria um impasse, pois na camada de aplicação, ou de negócios os dados
representados na forma de objetos enquanto o software SGBD trabalha com
tabelas e relações entre tabelas.
A solução para o problema citado é a criação de um mecanismo que
seja capaz de mediar todas as operações que serão executadas nos objetos e
aplicá-las a camada de persistência. Existem algumas formas de se fazer isso,
por exemplo, na Figura 1 – Relacionamento álbum – artista.
Neste exemplo, percebemos que ao transformarmos o modelo entidade-
Figura 1 – Relacionamento álbum – artista.
relacionamento em um modelo de classes, transformamos o relacionamento
em um atributo da classe Albums que faz referência a classe Artistas, dessa
forma conseguimos ter coerência entre o que está expresso através das
classes com o que está persistido no banco de dados. Porém, é costume que
os diagramas de classes sejam construídos a priori com relação aos diagramas
entidade-relacionamento. Quando esta abordagem é adotada devemos
entender os relacionamentos, entender as chaves primárias e a necessidade
da criação de tabelas extras e então realizar o mapeamento.
Este é um dos problemas mais comuns quando trabalhamos com
programação orientada a objetos e utilizamos bancos de dados relacionais
para realizar a persistência dos dados.
O conflito objeto-relacional
“Enquanto as tecnologia objeto-relacionais supõem a criação de classes
contendo a implementação da lógica de negócio, através dos atributos e da
implementação de métodos. As tecnologias de manipulação de dados supõem
o armazenamento dos dados em tabelas e a manipulação dos mesmos através
de uma linguagem de manipulação de dados (data manipulation language –
DML)”[SCOTT]. Assumindo as considerações do autor citado, podemos afirmar
que existe um conflito objeto-relacional (em inglês numa tradução livre, objectrelational impendance mismatch), uma vez que as tecnologias citadas
coexistem na grande maioria dos projetos que são construídos nas empresas
atualmente.
Enquanto o paradigma de orientação a objetos é fundado sobre uma
sólida base de princípios de engenharia de software. O paradigma relacional é
fundado sobre princípios matemáticos. Cada qual com suas vantagens e
desvantagens.
A grande problemática consiste em unir os dois padrões. Porém caso
esta junção não seja feita de forma coerente pode ocorrer sérios problemas,
como por exemplo, prejudicar a manutenibilidade e o desempenho da
aplicação, uma vez que a complexidade da solução adotada pode aumentar
exponencialmente a quantidade de código produzido e também reduzir a
qualidade do mesmo. Por isso existem vários padrões que buscam simplificar a
questão do relacionamento entre objetos (orientação a objetos) e tabelas
(entidades relacionais).
Estes padrões foram escritos com base em estudos de casos e práticas
comuns identificadas em projetos de sucesso. Várias empresas criaram
projetos que implementaram esses padrões em diversas linguagens, inclusive
no PHP.
Um dos maiores problemas é certamente o mapeamento dos atributos
entre as classes do domínio e as tabelas do banco de dados. Este é um
problema estrutural que pode ser resolvido seguindo-se algumas abordagens
como, por exemplo, a organização das tabelas derivando-as do modelo de
domínio, de forma que para cada classe exista uma tabela no banco de dados.
Existem
outros
problemas
relacionados
ao
mapeamento
objeto
relacional como, por exemplo, os problemas comportamentais. Ao trabalhar
com uma grande quantidade de objetos, onde estes objetos sofrem alterações
durante o tempo de vida da aplicação, existe ainda a possibilidade de um
mesmo objeto ser carregado do banco de dados em outra instância da
aplicação e sofrer alterações nos seus dados. Para resolver este problema de
concorrência podemos utilizar algumas técnicas, como por exemplo o uso de
semáforo e o controle de transações oferecido pela maioria dos SGBDs
atualmente.
Segundo Fowler, “ao carregar uma quantidade de objetos para memória
e manipulá-los, deve-se garantir que todas essas modificações foram também
realizadas no banco de dados”. Essa afirmação implica em garantir que todas
as alterações referentes aos dados da aplicação que foram alteradas durante o
processamento de alguma regra de negócio seja também aplicada aos dados
que estão persistidos. Como este é um processo com alto custo computacional,
uma vez que implica na abertura de uma transação com o banco de dados e na
criação de novos objetos. Torna-se preferível gerenciar as mudanças que
ocorrem no objeto e as mudanças que ocorrem no banco de dados.
Outros problemas podem ainda seguir, como por exemplo, problemas de
desempenho e uso excessivo de memória. Para isso recomenda-se seguir as
recomendações dos fabricantes do SGBD que será utilizado. Por exemplo,
Abhijit Sinha diz que alguns fatores podem prejudicar o desempenho do banco
de banco de dados, como por exemplo, uma arquitetura pobre ou mal
desenhada, configuração inadequada e ainda problemas de hardware[MySQL
ReferencePoint Suite, 2002].
Ao escolher o paradigma de orientação a objetos, fica claro que no
projeto em questão será utilizado herança entre as classes. Porém os SGBDs
relacionais não oferecem suporte nativo ao uso de herança. Este então é mais
um desafio estrutural a ser enfrentado. Fowler apresenta três padrões para
resolver o mapeamento entre herança, são eles herança em tabela única,
herança com tabela concreta e herança entre tabela classe.
No próximo capítulo veremos alguns padrões de projeto que oferecem
subsídios para a implementação de sistemas onde os problemas citados
anteriormente serão solucionados.
Padrões de projetos
Segundo Holub, um padrão de projeto é uma técnica geral para resolver
um conjunto relacionado de problemas [Holub on Patterns: Learning Design
Patterns by Looking at Code, 2004]. Existe uma variedade de padrões para
solver um mesmo problema, cada uma partindo de uma visão distinta. Cabe ao
analista definir qual será mais adequado ao cenário em questão, levando em
consideração o ambiente de software e hardware, os requisitos levantados, a
opinião de outros envolvidos, entre outros parâmetros.
Algumas boas práticas foram adotas para resolver o conflito objetorelacional. Martin Fowler propôs em seu livro, patterns of enterprise application
architecture, um conjunto de padrões de projeto para a resolução deste tipo de
problema. Por exemplo, alguns padrões para mapeamento objeto relacional,
como, table data gateway, row data gateway, data mapper e o active record. E
alguns padrões para tratar mapeamento de herança como, herança em tabela
única, herança com tabela concreta e herança entre tabela classe.
Table data gateway
Fowler define o padrão table data gateway como “o padrão table data
gateway irá conter todos os códigos SQL para acesso a uma determinada
tabela ou view”. Por exemplo, uma determinada classe pessoa que implementa
esse padrão deve ter métodos que acessem a tabela pessoas no SGDB(ver
figura 2 – table data gateway).
Figura 2 - table data gateway
Este padrão é especialmente útil quando as tabelas do banco de dados
foram criadas de acordo com as classes do modelo de domínio. Fowler, indica
que os métodos implementados retornem coleções, mesmo quando é
executado uma pesquisa por um único elemento.
Row data gateway
Fowler descreve este padrão como uma classe que oferece métodos
capazes de retornar objetos exatamente como os registros na base de dados.
Um dos maiores problemas dessa abordagem é o custo excessivo gerado pelo
uso da conexão com o banco de dados em cada operação de pesquisa. Essa
abordagem é especialmente útil quando é necessário um controle rígido sobre
as transações.
Esta abordagem implica na criação de uma classe contendo métodos
estáticos para a pesquisa de um determinado objeto. O usuário ao chamar
estes métodos recebe de volta uma coleção de objetos, onde cada objeto
possui exatamente os mesmos valores que um determinado registro na tabela
que foi pesquisada (ver figura 3 – sequência row data gateway).
Figura 3 - sequência row data gateway
Data mapper
Este padrão é uma camada que busca isolar os objetos que estão em
memória dos registros do banco de dados, segundo Fowler. A classe que
implementa o padrão data mapper, é responsável por mapear todos os
atributos da classe em colunas no banco de dados.
Ao utilizar esse padrão é possível oferecer ao programador um alto nível
de transparência, ou seja, para ele não é necessário sequer saber qual o
SGBD que está sendo utilizado (ver figura 4 – data mapper).
Figura 4 - data mapper
Active record
Fowler define este padrão como sendo uma classe que encapsula um
registro no banco de dados, encapsulando também o acesso e as regras de
negócio.
Os objetos possuem além dos dados e dos métodos comportamentais
também possuem métodos para a persistência (ver figura 5 – active record).
Este padrão utiliza métodos estáticos para a recuperação dos dados
previamente salvos. Uma das principais desvantagens do active record diz
respeito a complexidade do objeto. Quando a implementação das regras de
negócio incluem relacionamentos complexos entre as entidades, herança, o
active record se torna um problema pois não oferece uma forma simples para a
construção desse tipo de regras.
Figura 5 - active record
Herança em tabela única
Para o resolver o problema de herança, uma das possíveis abordagens
é colocar todos os atributos das classes filhas numa mesma tabela. Por
exemplo, ao considerar a classe pessoa como classe raiz e as classes
PessoaFisica e PessoaJuridica como herdeiras da classe pessoa, e a classe
fornecedor como herdeira da classe pessoa jurídica(ver figura 6 – modelo
domínio pessoa). Seria criada uma única tabela no banco de dados que
conteria todos os atributos das classes que herdaram de Pessoa (ver figura 7 –
herança em tabela única). Porém esta metodologia poderá causar grandes
lacunas na tabela criada, por exemplo, se a tabela em questão atingir um
milhão de registros e nenhum objeto da classe pessoa física persistido. A
otimização da tabela fica prejudicada, pois haveria uma coluna sem nenhum
valor.
Figura 6 - modelo domínio pessoa
Figura 7 - herança em tabela única
Herança com tabela concreta
Assumindo o modelo de domínio utilizado anteriormente (ver figura 6 –
modelo domínio pessoa). Para cada classe herdeira deverá ser criado uma
tabela no banco de dados que conterá além dos dados próprios da classe
também os atributos da classe que foi estendida (ver figura 8 – herança com
tabela concreta).
Esta abordagem implica na replicação de colunas no banco de dados
para guardar uma mesma informação, neste caso o nome da pessoa. Isto
aumenta a complexidade das pesquisas, por exemplo, caso seja necessário
pesquisa todos os clientes que comecem com a letra B, isso implica que a
pesquisa será feita em três tabelas.
Figura 8 - herança com tabela concreta
Herança entre tabela classe
Assumindo o modelo de domínio utilizado anteriormente (ver figura 6 –
modelo domínio pessoa). Para cada classe herdeira deverá ser criado uma
tabela no banco de dados também deverá ser criado uma chave estrangeira
que relacionará as classes inferiores com as classes superiores (ver figura 8 –
herança tabela classe).
Esta abordagem implica o relacionamento entre as tabelas inferiores e
as superiores, ao implementar os métodos de pesquisa estes deverão lidar
com o relacionamento entre as tabelas dessa forma reduzindo o desempenho
da aplicação.
Entre os padrões referentes ao mapeamento de herança, deve-se
analisar cuidadosamente o produto e definir aquele que mais se adéqüe as
necessidades do usuário. Esta análise deve considerar a complexidade do
modelo de domínio, os recursos físicos e as exigências do usuário, tornando a
decisão mais complexa de ser tomada.
Figura 9 - herança tabela classe
PHP
PHP é uma das linguagens de programação mais utilizadas no mundo
atualmente, segundo o site tiobe.com(ver tabela 1 – linguagens de
programação). Este site é especializado em definir um ranking com as
linguagens de programação mais utilizadas no mundo,
levando em
consideração os programadores certificados, centros de treinamento, a
quantidade de empresas prestadoras de serviço entre outros parâmetros que
são analisados.
Tabela 1 – Linguagens de programação
Variação
Posição em
Posição em
% em
Linguagem
Agosto de 2009 Agosto de 2008
no período
Agosto de 2009 de 08/2008
08/2009
1
1
Java
19.527%
-2.04%
2
2
C
17.220%
+1.04%
3
4
C++
10.501%
+0.44%
4
5
PHP
9.390%
+0.04%
5
3
(Visual) Basic
8.486%
-2.37%
6
6
Python
4.489%
-0.49%
7
8
C#
4.443%
+0.75%
8
7
Perl
4.028%
-0.67%
9
10
JavaScript
2.812%
-0.08%
10
9
Ruby
2.490%
-0.43%
11
11
Delphi
2.337%
-0.39%
12
13
PL/SQL
0.982%
+0.30%
13
14
SAS
0.817%
+0.27%
14
27
RPG (OS/400)
0.752%
+0.52%
15
26
ABAP
0.739%
+0.51%
até
16
16
Pascal
0.675%
+0.26%
17
12
D
0.662%
-0.69%
18
17
Lisp/Scheme
0.630%
+0.25%
19
41
Objective-C
0.612%
+0.51%
20
25
MATLAB
0.560%
+0.32%
Fonte: Tiobe.com
Podemos citar o PHP como uma linguagem de programação e também
como uma plataforma de desenvolvimento. O PHP possui duas grandes forças,
a simplicidade e um grande conjunto de funcionalidades. Enquanto linguagem
o PHP incorporou a sintaxe elegante utilizada pelo C sem os problemas
provenientes da alocação de memória e do uso de ponteiros. O PHP também
herdou os poderosos construtores do Perl – porém sem a complexidade
normalmente associada aos scripts Perl.
Como
plataforma,
o
PHP
oferece
um
poderoso
conjunto
de
funcionalidades que cobrem uma grande gama de necessidades. O PHP
também é extensível através de um conjunto bem definido de APIs C, o que
torna simples para qualquer desenvolvedor adicionar novas funcionalidades
quando necessário [Zend PHP Certification study guide].
Desde a versão 4 é orientado a objetos, o que significa dizer que este
desenvolveu o paradigma mencionado anteriormente. Sendo capaz de realizar
os conceitos de classe, métodos, herança e as demais facilidades providas
pela orientação a objetos.
O PHP oferece nativamente classes para conexão com diversos SGBDs
e uma API concreta e fácil de usar para a manipulação de arquivos, o que torna
a persistência de dados mais fácil de ser implementada.
Várias empresas e grupos de usuários oferecem soluções para a
camada de persistência de dados, normalmente implementando alguns
padrões de projeto como os que foram mencionados anteriormente.
Zend framework
Por exemplo, a zend foundation, ao lançar o framework Zend, ofereceu a
comunidade uma solução em persistência através de um conjunto de classes.
Essa implementação se deu através de dois padrões de projeto: table data
gateway e row data gateway. Definindo uma série de classes, com métodos e
atributos específicos que podem ser estendidas a fim de se obter um
mapeamento objeto relacional sem muito esforço e com um custo
computacional reduzido. Este framework provê também certo nível de
segurança, pois oferece um conjunto de métodos de validação que são
capazes de prevenir alguns tipos de injeções de código malicioso que
porventura os usuários tentem utilizar. A camada de persistência oferecida pelo
Zend Framework é capaz de utilizar diversos SGBDs alterando apenas o objeto
pelo qual é realizado a conexão com o banco de dados.
Propel framework
Outro exemplo de persistência em PHP é o framework propel, que
propõe o uso de arquivos de configuração em XML como principio para o
mapeamento objeto relacional. Este projeto é baseado no Apache Torque, um
framework para realização de mapeamento objeto relacional escrito em Java
que segue os mesmos princípios de configuração através do uso de arquivos
XML. Também este framework oferece a possibilidade de se trabalhar com
diferentes SGBDs entre eles podemos citar, MySQL, MSSQL, Oracle, DB2 e
PostgreSQL.
Doctrine
O doctrine é um framework mantido pela própria comunidade e liderado
por Jonathan H. Wage. Este foi inspirado no Hibernate, um framework de
persistência escrito em Java.
A principal facilidade do doctrine é oferecer uma linguagem proprietária
de pesquisa (doctrine query languague – DQL), cuja principal função é tornar
transparente o uso dos diferentes dialetos utilizados pelos diversos
fornecedores de SGDBs.
Outra facilidade do doctrine é a implementação do padrão de projeto
Active Record. Também podemos citar a capacidade deste framework de
trabalhar com estruturas hierárquicas, uso de hooks (métodos que são
chamados quando uma determinada condição é encontrada), uso de um
sistema de cache para melhorar o desempenho das operações utilizadas.
Download