Back-End

29 jun, 2009

Adicione poder ao seu PHP com aplicações multi-tiered

Publicidade

Como aplicações PHP se tornam cada vez mais e mais
complexas, isso pode ser fácil para acabar com um emaranhado de códigos que faz
a manutenção ser quase impossível. Aplicar o conceito de diferenciação de
aplicativos pode ajudar a aliviar algumas das dificuldades em manter aplicações
complexas.

O que queremos dizer por
Tiered Applications?

Tiered Programming é a prática de manter diferentes
componentes, ideias ou línguas separadas umas das outras. No desenvolvimento
front-end, diferenciar marcação seria usar stylesheets e JavaScript externos.

Ao ligar a um arquivo CSS em vez de encaixar estilos em seu
HTML markup, torna-se mais fácil para alterar a formatação de seus sites porque
agora toda informação estilizada é convenientemente armazenado em um lugar,
separado da marcação do documento. E múltiplas páginas HTML podem puxar
exatamente o mesmo arquivo CSS, todo o seu site pode ser atualizado
simplesmente ao mudar uma linha de CSS.

Em desenvolvimento back-end, as mesmas regras se aplicam,
mas estamos lidando com diferentes componentes. Em termos gerais, estamos
olhando para três níveis: a Database (armazenando e recuperando de dados), Business (processando e manipulando os dados), e Presentation (como os dados são
apresentados).

Por que eu devo ter
cuidado?

Pode não ser imediatamente óbvio, mas separando as suas
aplicações em uma estrutura em camadas terá um enorme impacto sobre a
habilidade do código ao ser mudado no futuro. Por exemplo, se você tem um
sistema de criação de blogs, e torna-se necessário criar um feed RSS para
o blog, as aplicações diferenciadas apropriadas lhe autorizariam a simplesmente
criar um template RSS, e em seguida conectar ao banco de dados e funções empresariais
que você escreveu.

Por outro lado, se o seu cliente de repente decidiu que PostgreSQL
era uma escolha melhor para sua organização do que o MySQL, você teria que
reescrever as funções do seu banco de dados, todos sem tocar o negócio ou
apresentação lógica da aplicação.

Em termos de reutilização, você poderia ter várias
funcionalidades do banco de dados (suportando MySQL, PostgreSQL e Oracle, por
exemplo), que poderiam ser facilmente usadas em novas implantações de sua
aplicação usando apenas algumas linhas de código em um lugar, em vez de editar
várias linhas do seu código através de várias funções.

O caminho errado

Para começar, vamos
ter uma tarefa bastante simples – puxar o título e o corpo do texto de uma
entrada de um banco de dados, criar uma versão abreviada da entrada, e colocar
os dados em HTML markup – e vá completamente no caminho errado. No código
a seguir, vamos escrever uma função para realizar todas as nossas tarefas:

function displayEntry()
{
$entryDisp = NULL;

// Get the information from the database
$sql = "SELECT title, entry FROM entries WHERE page='blog'";
$r = mysql_query($sql) or die(mysql_error());
while($entry = mysql_fetch_assoc($r)) {
$title = $entry['title'];
$text = $entry['entry'];

// Create the text preview
$textArray = explode(' ',$text);
$preview = NULL;
for($i=0; $i<24; $i++) {
$preview .= $textArray[$i] . ' ';
}
$preview .= $textArray[24] . '...';

// Format the entries
$entryDisp .= <<<ENTRY_DISPLAY

<h2> $title </h2>
<p>
$preview
</p>
ENTRY_DISPLAY;
}

return $entryDisp;
}

O código do HTML
markup sai de acordo com estas linhas:

<h2> Entry One </h2>
<p>
This is the shortened description of entry number one. It
displays the first 25 words of the entry and then trails
off with an ellipsis...
</p>
<h2> Entry Two </h2>
<p>
This is the shortened description of entry number two. It
displays the first 25 words of the entry and then trails
off with an ellipsis...
</p>

Embora isso possa parecer lógico, é realmente muito
indesejável. Vamos passar em revista o que torna este um código menos do que
uma ótima abordagem.

O problema com esta
abordagem

Poor Legibility  – Este código é diluído. O seu objetivo,
embora documentado nos comentários (ou algo do tipo), é difícil de discernir. Se
você escreveu isso, quando voltar para ele em seis meses, não será claro o que estava acontecendo, o que significa alguns
segundos/minutos desperdiçados tentando interpretar o seu próprio código.

Too Narrow em Foco – Esta função é falha pela sua especificidade:
a query do banco de dados só funciona para um tipo de entrada; um preview na
criação do código é muito bem codificado para a função, a formatação é
específica para o tipo de entrada que está sendo exibido. A fim de criar uma implementação ligeiramente diferente desta
funcionalidade, seríamos forçados a criar uma segunda função que pareceria quase
exatamente o mesmo, ainda que o necessário fosse apenas mudar o número de
palavras na visualização do texto.

Falta de Escalabilidade – Isso
é muito relacionado com a idéia de ser demasiado em destaque. Se
queremos adicionar mais funcionalidades (como um link ou uma imagem), a nossa
função será maior e mais difícil de gerenciar. E se quisermos acrescentar
condições que afetam o modo como uma entrada é exibida? É fácil ver como
programar assim deixa fácil para o código se tornar rapidamente expansivo e
ingerenciável.

O grande problema: Database, Business e
Display Logic

Esta é a questão que está causando varredura de todos os problemas acima mencionados.

“Ao
combinar os três tipos de nossa lógica, acabamos com um limitado, confuso,
difícil de gerenciar, quase impossível para reutilizar emaranhado de
código.”

Imagine uma aplicação onde cada tipo de visualização (RSS
feed, entrada preview, total entrada no visor, etc.) foi construído com uma
função similar às citadas acima, com acesso a base de dados, lógica empresarial, e
apresentação lógica tudo escrito em conjunto. Agora imagine que há nove páginas
do site, e todas têm a sua própria entrada exibir e visualizar funções.

Mesmo se considerarmos que a aplicação é muito simples e que
existam apenas duas funções por página do site, ainda estamos olhando para quase
vinte funções que terão de ser
atualizadas, se as alterações se tornarem necessárias.

Melhorando o código

Para melhorar o
código acima, nós iremos espalhar nossos diferentes tipos de lógica através de
várias funções. Se feito corretamente, devemos acabar com um conjunto de
funções reutilizáveis, fáceis de entender e que executam uma variedade de tarefas.

Para começar, vamos
planejar as funcionalidades necessárias para ter uma melhor ideia de como ele
deveria ser construído:

  1. Obtenha a entrada e uma coluna de títulos para uma
    determinada página da tabela “entries” no banco de dados
  2. Encurte o corpo da entrada para visualização de 25
    palavras e anexe uma elipse
  3. Insira os dados em tags HTML para exibição no navegador
    do usuário

Como você pode ver, o nosso plano
identifica claramente um banco de dados, negócios, apresentação e grau.
Podemos agora escrever funções para cumprir cada um desses passos com relativa
facilidade.

Passo 1 – A camada do banco de dados

Para obter informação do banco de dados, nós iremos escrever
uma função muito simples. Para incentivar boas práticas de codificação, eu irei
usar a extensão mysqli,
mas não vou me focar em como isso funciona. Se você ainda não está usando, eu te incentivo a explorar o mysqli ou uma extensão similar (i.e. PDO) para garantir suas consultas do MySQL
contra ataques de injeção.

function getDataFromDB($page)
{
/*
* Connect to a MySQL server
*/
$mysqli = new mysqli('localhost', 'user', 'password', 'world');
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit;
}

/*
* Create a prepared statement for pulling all entries from a page
*/
if ($stmt = $mysqli->prepare('SELECT title, entry FROM entries WHERE page=?')) {
/*
* Create a multi-dimensional array to store
* the information from each entry
*/
$entries = array();

/*
* Bind the passed parameter to the query, retrieve the data, and place
* it into the array $entries for later use
*/
$stmt->bind_param("s", $page);
$stmt->execute();
$stmt->bind_result($title, $entry);
while($stmt->fetch()) {
$entries[] = array(
'title' => $title,
'entry' => $entry
);
}

/*
* Destroy the result set and free the memory used for it
*/
$stmt->close();
}

/*
* Close the connection
*/
$mysqli->close();

/*
* Return the array
*/
return $entries;
}

Se você quebrar
o que esta função está fazendo, estamos literalmente solicitando apenas duas
colunas (título e entrada) de nossa tabela (entries) e, em seguida, armazenando
cada entrada em uma matriz associativa multi-dimensional, que é o valor de
retorno da função. Nós passamos um parâmetro, $ page, para que possamos
determinar qual página iremos obter as informações. Ao fazê-lo, temos agora
criada uma função que irá trabalhar para todas as páginas do nosso site (desde
que todas elas tenham as fields “title” e “entry”).

Repare que a nossa função não faz nada para lidar com os
dados, ele simplesmente age como um correio, pegar as informações que
solicitamos e passando-o para o que vem a seguir. Isto é importante, porque se
fez nada de mais, gostaríamos de estar na esfera da lógica empresarial.

Por que isso é
importante para separar a lógica empresarial da lógica do banco de dados?

A resposta curta é que isso autoriza a abstração do banco
de dados, o que significa essencialmente que o dado poderia ser migrado do
MySQL dentro de um outro formato de base de dados, tal como PostgreSQL ou
Oracle, todos, sem alterar as funções dos dados de movimentação (business
tier), desde que a produção continue a ser simplesmente uma
ordem multi-dimensional associativa contendo entradas com uma coluna de título
e de entrada, não importa que tipo de banco de dados que estamos utilizando.

Passo 2 – A camada
Business

Com os dados carregados em nossa matriz, podemos iniciar processando a informação para servir para nossos propósitos. Neste exemplo,
estamos tentando criar uma entrada de visualização. No primeiro exemplo, a
duração da visualização foi dificilmente codificada dentro da função, o que decidimos que é de má prática. Nesta função, vamos passar dois parâmetros
para o nosso código: o texto a processar, e o número de palavras que deseja
exibir como nossa pré visualização.

Dê uma olhada na
função:

function createTextPreview($text, $length=25)
{
/*
* Break the text apart at the spaces and create the preview variable
*/
$words = explode(' ', $text);
$preview = NULL;

/*
* Run a loop to add words to the preview variable
*/
if($length < count($words)) {
for($i=0; $i<$length; $i++) {
$preview .= $words[$i] . ' '; // Add the space back in between words
}
$preview .= $words[$length] . '...'; // Ellipsis to indicate preview
} else {
/*
* If the entry isn't as long as the specified preview length, simply
* return the whole entry.
*/
$preview = $text;
}

/*
* Return the preview
*/

return $preview;

}

Na função acima, simplesmente checamos que o número de
palavras na entrada fornecida é superior ao número de palavras que
queremos exibir em nossa visualização. Em seguida, adicione palavras à
recém-criada variável $preview uma de cada vez até atingir o comprimento
máximo, ao ponto que colocar uma elipse e retornar $preview.

Assim como na camada de nossa base de dados, estamos
mantendo o código dentro dos limites da camada Business. Tudo que nós estamos
fazendo é criando um texto visualização; não há interação com o banco de dados,
nem elementos presenciais, como HTML markup.

Passo 3 – A camada de
apresentação

Finalmente, temos de mostrar os dados que obtivemos e processamos. Para nosso propósito, o que vamos exibir é
extremamente simples com HTML markup:

<?php
$entries = getDataFromDB(); // Load entries into an array
foreach($entries as $entry) {
/*
* Place the title and shortened entry text into two appropriately
* named variables to further simplify formatting. Also note that
* we're using the optional $length parameter to create a 30-word
* text preview with createTextPreview()
*/
$title = $entry['title'];
$preview = createTextPreview($entry['entry'], 30);
?>

<h2> <?php echo $title; ?> </h2>
<p> <?php echo $preview; ?> </p>

<?php
} // End foreach loop
?>

A ideia por trás do código é bem simples: primeiro, carrega
as entradas usando a função da base de dados, então faz um loops nos dados
através das entradas, encurtando a entrada do texto utilizando a nossa função
preview e, em seguida, colocando o título e a entrada preview na marcação da
apresentação.

Agora, para mudar o layout das pré visualizações da entry, somente
duas linhas de HTML são necessárias para serem ajustadas. Este é um grito muito
menos confuso do que a função original que tratava dos três níveis.

Olhando através de
diferentes tipos de programação

Gostaria de salientar que o exemplo acima é muito básico,
e serve somente para demonstrar o conceito de Tiered Programmin. A
ideia é que, mantendo os diferentes tipos de lógica de programação separados,
você pode aumentar enormemente a legibilidade de manutenção do seu código.

Nota: Há um grande artigo sobre TheDailyWTF.com discutindo o uso e abuso de softwares diferenciados de design, e maravilhoso comentário sobre o artigo que apresenta diferentes opiniões.
Aplicações Multi-tiered são extremamente úteis, mas também fácil de se
compreender
mal e o excesso de complicar, por isso lembre-se
de planejar cuidadosamente o seu software antes de construir para evitar que
causem mais problemas do que você está resolvendo.

*

Publicado originalmente em: http://net.tutsplus.com/tutorials/php/add-power-to-your-php-with-multi-tiered-applications/