Documento: Guia de boas práticas - Legibilidade de código

Guia de padronização do desenvolvimento da linha Microsiga Protheus.Documento eleborado para os desenvolvedores da linha Microsiga Protheus.


Entende-se por legibilidade de código, a facilidade de ler e entender o que foi escrito pelo desenvolvedor. Usando as regras de legibilidade de código, fica fácil para outro desenvolvedor entender o programa e fazer as intervenções necessárias.
Pode parecer trivial e você ser tentado a deixar de ler os parágrafos seguintes, mas é primordial o conhecimento e o domínio dos conceitos passados a seguir. Lembre-se um bom programa é aquele que não precisa ser alterado com freqüência, porém um GRANDE programa é aquele que pode ser alterado, quando necessário, e sua estrutura garanta que não seja criado um bug. Para isto o programa deve ser simples! Seja admirado pela facilidade de leitura de seus programas.
Estilo de programação
Um programa da Linha Microsiga Protheus pode ser composto por dois estilos diferentes de programação:
·         Programação estruturada
·         Programação orientada por objetos
Não vamos entrar no mérito de qual dos estilos é o melhor, ambos tem pontos positivos e negativos, porém pode-se dizer que a programação estruturada ainda é muito influente, uma vez que grande parte das pessoas aprende programação através dela. O principal motivo é a simplicidade, justamente o que buscamos e um dos pilares de nossa solução.
No quadro abaixo podemos notar onde iremos utilizar cada um dos estilos de programação:
Tipo de Programa
Programação estruturada
Programação orientada por objetos
Formulários
Na estrutura do código e nas validações do campo
No consumo do framework
Consultas
Na estrutura do código
No consumo do framework
Relatórios
Na estrutura do código
No consumo do framework
Processamento
Na estrutura do código
No consumo do framework
Biblioteca de regras de negócio
Preferencialmente
Somente sob consulta a GDP de Framework
Web Services
Indisponível
Preferencialmente
 
Neste momento você deve ter percebido que o uso de programação orientada por objetos é controlada. Isto se deve a característica do nosso Server Application. O Server Application utilizado pela Linha Microsiga Protheus compartilha numa única instância/slave, várias conexões de usuário. Estas conexões dividem a memória desta instância/slave e seus limites. Por esta razão e pelo fato da programação orientada por objetos consumir mais memória que a programação estruturada, seu uso é restrito apenas onde há vantagens significativas.
Para a correta compreensão deste tema, precisamos observar o cenário de trabalho de nossos programas. Uma instância/slave de uma aplicação de 32 bits tem alocação máxima de 1,8 Gbytes de memória, qualquer valor acima disto pode causar um GPF na aplicação e forçar o Sistema Operacional a derrubar a instância/slave.
A meta da linha Microsiga Protheus é possibilitar 30 usuários ativos em cada instância/slave, algo em torno de 61 Mbytes por usuário. Uma classe que represente uma interface ou regra de negócio em AdvPL consume em média 1 Mbyte de memória, muito em relação ao máximo de alocação que temos.
Muito bem, neste ponto você deve ter percebido que não é apenas com programação orientada a objetos que devemos ter cuidado. Devemos ter cuidado com qualquer estrutura que aloque ou possa alocar muita memória, tais como: XML´s, Array´s e grandes strings, mesmo utilizando programação estruturada.
A seguir veremos a formatação dos programas da Linha Microsiga Protheus.
Formatação dos programas
Os programas devem ser estruturados em blocos. Entende-se por blocos de programas os trechos que fazem alguma ação lógica ou seqüência de comandos. Todo bloco de programa deve ter uma única entrada e uma única saída, evitando-se assim o uso de desvios incondicionais, tais como loop, exit, etc.
O não uso de desvios incondicionais ( loop, exit, etc... ) é uma das principais diferenças entre a programa estruturada e sequêncial.
Os blocos devem ser documentados apropriadamente e para cada bloco temos uma forma de documentação e formatação:
·         Área de identificação
·         Área de declaração de variáveis e ajustes iniciais
·         Corpo do programa
·         Área de encerramento
Área de identificação
Todas as funções, classes e métodos, devem ser documentados e identificados. Lembre-se, trabalhamos em equipe, portanto continuamente iremos fazer e alterar códigos de outras pessoas. Um código documentado facilita a manutenção, reduz o tempo de desenvolvimento e reduz o risco de bug.
Toda vez que for criar uma nova função ou classe verifique se ela não existe. Tome como base o escopo da função e veja se realmente você tem domínio sobre esta função. Exemplo: uma função genérica deve ser desenvolvida e mantida pela GDP de Framework, uma função financeira, deve ser construída e mantida pela GDP de Controladoria, uma função de movimentação de estoque, pela GDP de Materiais, e assim por diante. Mesmo em customizações devemos seguir este padrão e privilegiar pelo uso de funções documentadas pela TOTVS, evitando-se assim custos desnecessários em migrações de versão ou atualizações do produto.

 

Acima podemos observar a área de identificação de uma função da Linha Microsiga Protheus. Note que ela é formada por tags que podem ser facilmente identificadas. Estas tags são utilizadas para integrar a documentação do código com o site de documentação da Linha Microsiga Protheus.
Na tabela abaixo destacamos a função de cada uma das tags
{Protheus.doc}
Identifica o inicio do bloco de documentação. Deve ser precedido do nome da função ou método e no parágrafo seguinte deve ter a descrição completa do bloco.
@param
Parâmetros de entrada, listados na ordem de passagem. Exemplo:
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@param cFederalId Informe.
@param nErro Retorna.
@param aIDs Retorna.
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@protected
Se inserida indica que a função tem uso restrito pela GDP criadora e não pode ser reaproveitada em customizações e/ou integrações.
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@protected
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@author
Autor ou revisor do bloco
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@author Eduardo Riera
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@version
Versão da Linha de produto Microsiga Protheus em que o bloco teve inicio. Utilize a nomenclatura definida pela GDP de Framework, exemplo:
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@version MP11.5
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@build
Versão mínima da Build do Application Server que o bloco é suportado.
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@build 7.00.100812P - Sep 1 2010
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@deprecated
Se inserida indica que a função não possui mais manutenção e/ou foi substituída por outra, tendo seu uso depreciado. Recomenda-se assim a substituição pela nova função.
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@deprecated
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@see
Indica as funções que devem ser observadas pelo desenvolvedor antes do uso. “Veja também”.
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@see FWTeste2,FWTeste3,FWTeste4
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@since
Data de criação da rotina
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@since 9/10/1995
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@return
Indicador do retorno da função
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@return ExpL: indica se a rotina foi executada corretamente.
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@todo
Indicativo de função incompleta ou com pendências de desenvolvimento
 
//----------------------------------------------------------
/*/{Protheus.doc} FWTeste1()
Função teste
 
@todo proteger a função de chamadas por customização.
/*/
//----------------------------------------------------------
Function FWteste1(cFederalId,nErro,aIDs)
 
@sample
Exemplo de uso do bloco
@obs
Observação complementar ao bloco.
Área de declaração de variáveis e ajustes iniciais
Nesta área devem ser feitos os ajustes iniciais, importantes para o correto funcionamento do programa. Entre esses ajustes iniciais se encontram declarações de variáveis, proteções e inicializações.
As variáveis devem ser declaradas seguindo a notação húngara. A notação húngara consiste em colocar prefixos nos nomes de variáveis, de modo à facilmente identificar seu tipo. Isto facilita na criação de códigos-fonte extensos, pois usando a Notação Húngara, você não precisa ficar o tempo todo voltando à definição de uma variável para se lembrar qual é o tipo de dados que deve ser colocado nela. Variáveis devem ter um prefixo de Notação Húngara em minúsculas, seguido de um nome que identifique a função da variável, sendo que a inicial de cada palavra deve ser maiúscula.
É obrigatória a utilização desta notação para nomear variáveis.
Notação
Tipo de dado
Exemplo
a
Array ou Matrix
aValores
c
Caracter ou String
cNome
d
Data
dDataIni
l
Lógico ou boleano
lContinua
n
Numérico
nVlrConta
o
Objeto
oMainWin
x
Indefinido
xBuffer
 
As variáveis de entrada devem ser protegidas e inicializadas. Para tanto, utilize o comando PARAMTYPE ou DEFAULT, conforme demonstrado no exemplo abaixo:
#INCLUDE “PARAMTYPE.CH”
//-------------------------------------------------------------------
/*/{Protheus.doc} New
Método construtor da classe
/*/
//-------------------------------------------------------------------
METHOD New( cID , bPre, bPost, bCommit, bCancel ) CLASS FWFormModel
 
Local aArea := GetArea()
PARAMTYPE 0 VAR cID     AS CHARACTER
PARAMTYPE 1 VAR bPre    AS BLOCK OPTIONAL DEFAULT {|| .T.}
PARAMTYPE 2 VAR bPost   AS BLOCK OPTIONAL DEFAULT {|| .T.}
PARAMTYPE 3 VAR bCommit AS BLOCK
PARAMTYPE 4 VAR bCancel AS BLOCK
 
Tenha o hábito de proteger a entrada de seu programa. Se uma variável não precisa ser passada ou ela foi criada numa mantenção, tenha em mente que outros desenvolvedores não conhecem a mudança, portanto inicialize a variável de modo que a função tenha o comportamento anteriormente esperado. Lembre-se você dificilmente terá condições de alterar todos os lugares onde seu programa foi utilizado.
Tenha o hábito de posicionar as WorkAreas utilizadas pelo seu programa. Existem funções que garantem o posicionamento da WorkArea sem prejudicar o desempenho, tais como MsSeek e MsGoto.
Lembre-se seu programa deve ser uma caixa preta. Quem o utiliza precisa apenas da documentação para consumi-lo, não do código-fonte.
Corpo do programa
É nesta área que se encontram as linhas de código do programa. É onde se realiza a tarefa necessária através da organização lógica destas linhas de comando. Espera-se que as linhas de comando estejam organizadas de tal modo que no final desta área o resultado esperado seja obtido, seja ele armazenado em um arquivo ou em variáveis de memória, pronto para ser exibido ao usuário através de um relatório ou na tela.
Para fornecer legibilidade à área do corpo do programa é necessário utilizar comentários e regras de formatação.
Os comentários devem ser utilizados para explicar cada bloco das linhas de código do corpo do programa. Não é necessário exemplificar trechos óbvios, porém faz-se necessário exemplificar a linha de pensamento utilizada naquele trecho, bem como a fonte da regra de negócio. Exemplo:
//----------------------------------------------------------------------
// Calculo do ICMS de Goiás, Decreto 23.756 de 12/12/1970.
//----------------------------------------------------------------------
 
Ao colocar um comentário, tenha em mente o que você precisará saber para fazer a manutenção daqui há 10 anos. Algo óbvio hoje pode não ser daqui há 10 anos.
O tamanho da linha do código-fonte ideal é aquele que não necessita de ser deslocado para ser visualizado. Uma linha de 130 caracteres é ideal em muitas resoluções de monitores.
Quando houver necessidade de dividir um trecho de código formado por uma sentença lógica, prefira dividir as sentenças completas para facilitar a visualização dos fechamentos. Exemplo:
                Prefira: If (              !Empty(cNome) .And.;
 !Empty(cEnd) .And.;
 !Empty(cTel) .Or. !Empty(cFax))    .And.;
 nValor != 0 )
GravaDados(cNome,cEnd,cTel,cFax,cEmail)
Endif
                Em vez de: If ( !Empty(cNome) .And. !Empty(cEnd) .And. (!Empty(cTel) .Or.;
!Empty(cFax))    .And. nValor != 0 )
GravaDados(cNome,cEnd,cTel,cFax,cEmail)
Endif
 
Embora o AdvPl suporte a abreviação de comandos para quatro letras (“Replace” pode ser escrito como “Repl”) é expressamente proibida a utilização dessa funcionalidade. Isto apenas torna o código mais difícil de ser lido e não torna a compilação mais rápida ou simples.
 
A identação do código é obrigatória, pois torna o código muito mais legível. A utilização da identação seguindo as estruturas de controle de fluxo (while, if, case, etc) torna a  compreensão do código muito mais fácil. Para identar o fonte utilize a tecla ">".
 
Uma convenção amplamente utilizada é a de capitular as palavras chaves, funções, variáveis e campos utilizando uma combinação de caracteres em maiúsculo e minúsculo, visando facilitar a leitura do código fonte. Exemplo:
dbSelectArea, MsSeek, dbGoto, MsGoto, FWUserAccount, FWUserAuth, etc...
 
Por fim, tenha o hábito de utilizar caracteres maiúsculos para constantes, defines e campos de tabelas e/ou variáveis de memória destes campos. Exemplo: SC6->C6_QTDVEN, M->C5_CLIENTE, SD2->D2_TOTAL, SF2->F2_TIPO, M->C2_FORNECE.
 
Área de Encerramento
É nesta área onde as finalizações são efetuadas e onde o resultado da execução do programa é utilizado. Pode-se exibir o resultado armazenado em uma variável ou em um arquivo ou simplesmente finalizar, caso a tarefa já tenha sido toda completada no corpo do programa.
As WorkAreas modificadas devem ser protegidas de modo a manter o estado inicial quanto a posicionamento ( RecNo ), Ordenação ( IndexOrd() e área default selecionada (DbSelectArea). Utilize o par de funções GetArea e RestArea para isto.
Os arquivos temporários abertos devem ser fechados e deletados. Arquivos desnecessários consomem os recursos do ambiente, deixando todo o sistema mais lento. Reveja o bloco de código e verifique se todos as query´s foram fechadas, se os arquivos binários e ISAM foram fechados e apagados .
Lembre-se seu código-fonte é uma caixa-preta!

  • Sem rótulos