+12

Dicas de estilo de programação

criado por Rubens Takiguti Ribeiro em 22/03/2010 1:43am
Grau de Abstração do Código-fonte

Estipular níveis de abstração do código-fonte nada mais é que saber determinar o que pode ser transofromado em uma função, método ou classe e o que é extremamente específico.

No caso de funções, métodos ou classes, pode ser muito útil estipular um limite de linhas ou um limite de níveis de identação para não tornar o código muito complexo. É claro que isso deve ser apenas uma convensão e não uma regra. Existem casos de código com muitas linhas mas muito legíveis. Em geral, a legibilidade de uma função ou método diminui a medida que se aumentam os níveis de identação. Veja um exemplo:

$time = time();
foreach ($itens as $item) {
    if ($item->tamanho > $tamanho_minimo) {
        foreach ($item->elementos as $elemento) {
            if ($elemento->visivel) {
                echo '<p>';
                if ($data > $time) {
                    echo 'teste';
                }
                echo $elemento->nome;
                echo '</p>';
            }
        }
    }
}

O código utilizou 5 níveis de identação em alguns pontos.

Uma alternativa que pode tornar o código mais legível é colocar estruturas condicionais que utilizam break ou continue no início de um bloco de repetição. Desta forma, não é necessário criar um "else" com mais um nível de identação, já que o "continue" ou o "break" irão interromper o fluxo natural do loop. Além disso, utilizar o operador ternário pode ser muito útil para evitar mais um nível de identação.

O código apresentado anteriormente seria convertido para a seguinte forma:

$time = time();
foreach ($itens as $item) {
    if ($item->tamanho <= $tamanho_minimo) {
        continue;
    }
    foreach ($item->elementos as $elemento) {
        if (!$elemento->visivel) {
            continue;
        }
        echo '<p>'.
        echo ($data > $time) ? 'teste' : '';
        echo $elemento->nome;
        echo '</p>';
    }
}

Definir níveis de abstração, é quebrar um bloco de instruções em funções/métodos. O código acima poderia ser convertido para a seguinte forma:

...
imprimir_itens($itens, $tamanho_minimo, $time);

/**
 * Imprime os itens maiores que $tamanho_minimo e os respectivos elementos visiveis
 * @param array $itens Vetor de itens
 * @param int $tamanho_minimo Tamanho minimo exigido para exibicao
 * @param int $data Timestamp da data em que os elementos posteriores a ela serao destacados
 * @return void
 */
function imprimir_itens($itens, $tamanho_minimo, $data) {
    foreach ($itens as $item) {
        if ($item->tamanho <= $tamanho_minimo) {
            continue;
        }
        imprimir_elementos($item->elementos, $data);
    }
}

/**
 * Imprime os elementos visiveis de um item,
 * destacando aqueles posteriores a data informada
 * @param array $elementos Vetor de elementos
 * @param int $data Timetamp da data em que os elementos posteriores a ela serao destacados
 * @return void
 */
function imprimir_elementos($elementos, $data) {
    static $time = time();
    foreach ($elementos as $elemento) {
        if (!$elemento->visivel) {
            continue;
        }
        echo '<p>'.
        echo ($data > $time) ? 'teste' : '';
        echo $elemento->nome;
        echo '</p>';
    }
}

Neste caso, o nível de identação não passou de 3. Note que as operações ficaram mais específicas. Logo, se um programador está interessado em saber apenas o que a função "imprimir_itens" faz, ele terá a resposta mais rapidamente do que lendo o código mostrado anteriormente. A função não precisa de comentários internos, pois é extremamente simples e legível.

A dica para construir códigos em níveis de abstração cada vez mais específicos é utilizando a estratégia top-down. Pensar no problema sob uma perspectiva geral, lançar a chamada da função com os parâmetros imaginados inicialmente, depois implementar a função. Ao implementar a função, ela deve chamar outras funções mais específicas e que ainda não foram implementadas. Depois, implemente-as e, caso necessário, inclua parâmetros não previstos inicialmente.

Comentários:

Mostrando 1 - 10 de 11 comentários
Cara... Muito bom! Aprendi, e muito, com este artigo!
10/05/2012 12:00pm (~6 anos atrás)

Parabéns pelo artigo! :-)

Por isso eu acho importante o uso de frameworks, pois eles seguem certos padrões de desenvolvimento e não vira bagunça.
31/03/2011 2:15am (~7 anos atrás)

Josué, a quantidade de memória usada pelo PHP em uma execução é limitada pela diretiva memory_limit, do php.ini. Você consegue alterar o valor dela em tempo de execução chamando a função ini_set:
ini_set('memory_limit', '128M');

Se não me engano, o padrão é 128M, que já é uma quantidade considerável. O conteúdo gerado por uma página normalmente tem de 50Kb a 300Kb. Em casos extremos, pode chegar a 1Mb, mas é muito abaixo de 128M.

Um detalhe que ajuda a usar menos memória é encapsular bem os métodos. Assim, as variáveis (não estáticas) criadas exclusivamente para os métodos são desalocadas assim que o método termina a execução. Ou, caso alguma variável gigante não precisa mais ser usada em determinado ponto do código, usa-se unset para desalocá-la.
18/01/2011 2:35pm (~7 anos atrás)

Josue Samuel disse:
Há tempos venho ensaiando criar um script com o layout html como o exemplo da página 2 do artigo em questão.

Depois, eu utilizaria uma variável única pra concatenar o conteúdo gerado por uma página em específico e, ao termino de todo o processamento, imprimí-la no local adequado conforme a abordagem do Carlos Eduardo Gomes Monteiro (segundo post de baixo pra cima).

Entretanto, ainda não me sinti confortável em somar essas duas abordagens em especial pelo fato de não ter tando controle da quantidade de dados armazenado na variável que daria o output do conteúdo. Esse desconforto de seve em eu não saber exatamente o tamanho/memória consumida que o PHP/servidor suportaria.

Alguém tem idéia qual o limite máximo de tamanho de uma variável e no que isso pode impactar para o servidor?
18/01/2011 12:20pm (~7 anos atrás)

Não conhecia o heredoc e nowdoc... bem interessante
21/11/2010 12:06pm (~7 anos atrás)

Cara, estou impressionado, cada dia que passa, descubro que conheço menos de PHP hehehe Parabéns !!!
30/09/2010 9:57am (~8 anos atrás)

Anderson disse:
Sou novo no site phpbrail, quero dar os parabéns pelo artigo, achei sensacional.
Abraço.

Anderson de Oliveira Morais.
28/09/2010 12:09pm (~8 anos atrás)

Filipe Mtro disse:
Acho interessante a forma de usar os arquivos .tpl com as variáveis, as vezes vejo coisa como %%TPL_RODAPE%% e Olá você tem %s créditos e %s de débitos.

Alguem pode me explicar o uso dessa tecnologia?
Eu realmente ainda não entendi.
15/06/2010 5:06am (~8 anos atrás)

Wake Up disse:
Muito bom!

Principalmente a parte sobre as notações "heredoc" e "nowdoc" (que eu desconhecia até então).

[]'s
Mario
08/06/2010 1:45pm (~8 anos atrás)

Ótimo artigo!!!
Duas coisas que gostaria de comentar.

Esta parte
$time = time();
foreach ($itens as $item) {
    if ($item->tamanho > $tamanho_minimo) {
        foreach ($item->elementos as $elemento) {
            if ($elemento->visivel) {
                echo '<p>';
                if ($data > $time) {
                    echo 'teste';
                }
                echo $elemento->nome;
                echo '</p>';
            }
        }
    }
}

Eu prefiro ao invés de imprimir, eu gosto sempre de atribuir a variaveis e fazer a impressão apenas no final.
Que inclusive, algo que você citou no começo de forma sutil mas não detalhada.
Eu sempre atribuo tudo à variaveis.
Deixando as impressões apenas para o final.
Pois assim, toda a execução do PHP seria feita, e apenas após concluir é que viria o HTML.
Isso ajuda muito em relação do uso de funções como header(), session_start() e etc...

Outro ponto importante que você comentou foi os parametros nas funções.
Isso realmente é um problema quando se cria muitos parametros.
Eu também faço como você as vezes, utilizando arrays para parametros opcionais.
Mas uma outra forma de faze-lo.
É em caso de métodos de uma classe, utilizar métodos GET e SET para determinar os parametros opcionais.
Ou seja, dentro da classe, já seta os atributos com valores padrões, e utilizando o SET apenas para o caso de setar um valor diferente do padrão.
Isto também dá mais clareza ao código, pois fica mais fácil de ser entendido, sendo que utilizando array, o programador vai ter que ler o código para entender como ele deve escrever o array com os valores opcionais...

Mas estes dois pontos é claro, é tudo uma questão de estilo né...
Só estou deixando o meu ponto de vista, quem sabe agrade alguem né...

Abraço a todos!!!
07/06/2010 12:07pm (~8 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)