BOAS PRÁTICAS DE PROGRAMAÇÃO EM GeneXus

Propaganda
BOAS PRÁTICAS DE PROGRAMAÇÃO EM GeneXus
As boas práticas de programação em GeneXus servem p/ melhorar a compreensão e clareza do código, afim de
permitir unificar critérios entre os diferentes programadores de equipe.
Elas partem do pressuposto que o código é a melhor documentação que um sistema pode ter, por isto também é a
melhor ferramenta que os programadores tem para comunicar seus trabalhos entre sí.
Ao utilizá-las, o código da Knowledge Basement obtém um valor agregado, pois adquire:






Fácil integração e reutilização
Fácil compreensão por parte do programador
Unificação de critérios
Eliminação de zonas obscuras de código
Fácil comunicação entre programadores
Clareza e facilidade de correção do código
(Ver também Design Tips sobre recomendações de design).
As boas práticas de programação em GeneXus são compostas de regras e recomendações:
REGRAS

Ao nomear atributos deve-se utilizar a nomenclatura GIK

Os atributos devem ter descrição e Help. Ex.:
Nome:
CliCod
Descrição: Código de Cliente
Help:
Identificador do Cliente no Sistema

As Tabelas devem ter nomes que representem a realidade e sejam herdados pela transação que as cria. Ex.:
Transação:
Tabela:

Cli2SisPro
Clientes
As variáveis que façam referência a um atributo devem ser baseadas nele mesmo e ter o mesmo nome do
Atributo (se a lógica permitir). Ex.:
Atributo: CliCod
Variável: &CliCod
- C(20)
- C(20)
- Código de Cliente
- Código de Cliente

Definição de Subtipos: recomenda-se que ao definir subtipos estes pertençam a um grupo específico e não
sejam definidos no grupo "None" .

Relatório de Especificação: é considerada uma boa prática, que o Analista GeneXus revise com atenção o
relatório de especificação (specification report), já que esta é a principal ferramenta para detecção de erros
no código.

Definição de Regras (Rules): em certas ocasiões ao não existir um critério dentro da equipe para definir as
“Rules”, o código se torna bastante difícil de entender e buscar o comportamento que foi programado para
um atributo em particular. Ex.:
Parm(in:EmpCod, in:&Usuario, in:&CliCod, in:&Mode);
noaccept(CiuCod);
&CliSaldoAux = udp(PcalcSaldo, EmpCod, &CliCod, CliSaldo);
error('Mensagem') If Null(&Usuario);
allownulls(EmpCod, LocCod ) ;
Call(PActInfo, EmpCod, CliCod) if <cond>;
error('Mensaje') IF CliDir = nullvalue(CliDir ) and after(CliDir) ;
prompt(Wclientes, EmpCod, CliCod);
default(CliFchCrea, Now() ) ;
noaccept(EmpCod);
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
nocheck(EmpCod, LocCod);
msg('Saldo menor que zero') if CliSaldo < 0;
Refcall(Wclientes, EmpCod, CliCod);
Call(Pprocedure, EmpCod, CliCod) if <cond>;
default(CliArea, 'A' ) ;
Se observarmos este código, nos damos conta que para buscar algo teremos que recorrer até o final, já que
não é mostrado nenhum critério a seguir. Existem muitas maneiras de definir as “rules” para que sejam fáceis de
entender, mas vamos tomar os critérios abaixo como boas práticas.
Critério Nº 1
Definir as “Rules” agrupadas por atributo; desta maneira podemos seguir o comportamento que foi programo
para um atributo ou variável em particular. Ex.:
Parm(in:EmpCod, in:&Usuario, in:&CliCod, in:&Mode);
error('Mensagem') If Null(&Usuario);
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
allownulls(EmpCod, LocCod ) ;
nocheck(EmpCod, LocCod);
Call(PActInfo, EmpCod, CliCod) if <cond>;
Call(Pprocedure, EmpCod, CliCod) if <cond>;
prompt(Wclientes, EmpCod, CliCod);
Refcall(Wclientes, EmpCod, CliCod);
error('Mensagem') IF CliDir = nullvalue(CliDir ) and after(CliDir) ;
default(CliFchCrea, Now() ) ;
default(CliArea, 'A' ) ;
noaccept(EmpCod);
noaccept(CiuCod);
msg('Saldo menor que zero') if CliSaldo < 0;
&CliSaldoAux = udp(PcalcSaldo, EmpCod, &CliCod, CliSaldo);
Critério Nº 2 (recomendado)
Agrupar as “Rules” por comportamento; desta maneira podemos ir diretamente ao setor do código onde
detectamos o erro para agregar comportamento. Ex.:
Parm(in:EmpCod, in:&Usuario, in:&CliCod, in:&Mode);
noaccept(EmpCod);
noaccept(CiuCod);
allownulls(EmpCod, LocCod ) ;
nocheck(EmpCod, LocCod);
default(CliFchCrea, Now() ) ;
default(CliArea, 'A' ) ;
error('Mensagem') If Null(&Usuario);
error('Mensagem') IF CliDir = nullvalue(CliDir ) and after(CliDir) ;
msg('Saldo menor que zero') if CliSaldo < 0;
Call(PInfoUsr, EmpCod,&Usuario) if <cond>;
Call(PActInfo, EmpCod, CliCod) if <cond>;
Call(Pprocedure, EmpCod, CliCod) if <cond>;
&CliSaldoAux = udp(PcalcSaldo, EmpCod, &CliCod, CliSaldo);
prompt(Wclientes, EmpCod, CliCod);
Refcall(Wclientes, EmpCod, CliCod);
RECOMENDAÇÕES

A descrição dos objetos da KB deve ser clara, independentemente do nome do mesmo.
Nome: ModCliDebito
Descrição: Modificação de Cliente com Débito

Utilizar linguagem mnemônica para as variáveis que não correspondam a nenhum atributo do sistema. Ex.:
Variável p/ a existência de um cliente.
Forma correta:
ExisteCliente
Forma Incorreta:
Flag

Utilizar linguagem mnemônica para os objetos da KB. Ex.:
TrabalharComClientes

No cabeçalho dos programas deve-se fazer um quadro com uma breve descrição do propósito do mesmo e
dados úteis. Ex.:
/*
Autor:
Data da Criação:
Ultima modificação:
Versão:
Descrição:
*/
Fulado de Tal ([email protected])
26-06-2004
27-06-2004
1.2
Muda as autorizações do Usuário

Colocar uma linha em branco entre as definições de eventos ou subrotinas, para separa-los e tornar mais
compreensíveis os programas.

Dentro dos eventos deve-se realizar indentação, para facilitar a visualização do código. Ex.:
// Forma incorreta:
Event 'NovoCliente’
If &CliCod = &Cliente
//Codigo
Endif
EndEvent
// Forma Correta:
Event 'NovoCli'ente’
If &CliCod = &Cliente
//Codigo
Endif
EndEvent

Para que os ForEach fiquem mais claros e fáceis de identificar dentro dos eventos ou do código em geral,
recomenda-se que sejam escritos da seguinte maneira:
// Forma incorreta:
Event 'NovoCliente’
For Each
where CliCod = &CliCod
//Código
EndFor
EndEvent
// Forma Correta:
Event 'NovoCli'ente’
For Each
where CliCod = &CliCod
//Código
EndFor
EndEvent

Para que os filtros dos ForEach fiquem mais claros, recomenda-se ter um where para cada condição e não
utilizar AND.
//Forma incorreta:
For Each
where CliCod = &CliCod and CliStatus = &CliStatus and CliTipo = &CliTipo
//Código
EndFor
// Forma correta:
For Each
where CliCod = &CliCod
where CliStatus = &CliStatus
where CliTipo = &CliTipo
//Código
EndFor
OBS.: Outras opções (vide fim do documento, ou clique no link):

Evitar abreviar excessivamente. Os nomes das variáveis, subrotinas, objetos, etc... devem de ser o mais claro
possível já que se alguém externo tiver que trabalhar com o código, além de ter de entender o código em
geral, terá que decifrar os nomes de cada variável, etc. Ex.: Variável de cliente por provedor
//Forma Incorreta:
//Forma correta:
&CPProv
&ClientePorProvedor

Clareza no código. Em muitos casos, por costume, os programadores abusam do uso do “if” esquecendo que
existe o comando “Do Case”. Em muitas ocasiões isto acontece porque as primeiras versões do GeneXus
não suportavam este comando e o costume é mais forte que a mudança.

Os atributos devem estar baseados em Domínios. Desta maneira é mais fácil adaptar-se as mudanças de
tipos e tamanhos (comprimentos).

Utilização de Patterns. Recomenda-se que toda aplicação web utilize Patterns, os patterns do GeneXus
oferecem uma ferramenta ideal para criar aplicações web. Facilitam a migração de ambiente win para web, e
oferecem uma forma prática de solucionar problemas que antes levavam muito tempo.

Evitar constantes no código. Usar os enumerators em vez de constantes no código. Dessa maneira, caso se
mude a constante, não é necessário mudar em todos os objetos que as utilizam.
&Type = "CR" // BAD
&Type = BalanceType.Credit // GOOD

Manutenção de Kb´s.
A natureza da maioria dos projetos nos leva a estarmos mudando constantemente o
conhecimento inicial que armazenamos em uma KB. As mudanças nos requerimentos dos clientes disparam
um montante de ações que fazem com que modifiquemos grande parte da lógica de negócio.
Isto leva a existência de KB´s que tem muitos objetos, atributos e tabelas que não são mais
utilizados ou que perderam a utilidade por alguma mudança ou ‘refactoring’ no código. Isto provoca uma
duplicidade de conhecimento ou conhecimento desnecessário na KB, e a medida que uma KB cresce
também aumentam os tempos de produção.
Existem tarefas que podem ser feitas freqüentemente visando otimização de diversos
processos. Executando uma boa manutenção, podemos baixar os tempos de:






Build All
Copy Model
Update Model
Generate Help
Publicação de Informação com GXPublic
Endossos
Seria interessante, em certas ocasiões, determinarmos um momento para apagar todos os
objetos, atributos, domínios, subtipos e tabelas que não sejam utilizados. Isto melhorará os tempos de
produção e levará a KB a ter o conhecimento necessário para responder as reais necessidades.
Uma das coisas que fazem com que uma KB cresça é ter modelos sem utilidade, em muitos
casos não há mais remédio anão ser ter vários modelos de protótipo e produção. Como recomendação, seria
bom eliminar todos os modelos que não são utilizados em uma KB.
Outras opções
/* Comentário de Gabriel Icasuriaga
Outra opção é definir toda a declaração do ‘for each’ sem endentar e começar
a indentação no início do código.
Apesar disso, prefiro pôr todos os atributos mesmo que seja redundante,
assim quando outra pessoa ver o código a compreensão é mais rápida.
Também gosto de tabular os sinais de "=".
For Each Clicod, CliStatus
Where CliCod = &CliCod
Where CliStatus
Where CliTipo = &CliTipo
//Código
EndFor
= &CliStatus
/* Comentário de Jorge Ronald Cribb - Vikam Corporation
Sugiro esta outra forma:

as palavras reservadas do GENEXUS com MAIÚSCULAS

Indentação de 4 caracteres para as opções de FOR EACH.

Os conectores AND e OR indentados dentro da opção WHERE.
FOR EACH Clicod, CliStatus
WHERE CliCod
= &CliCod
AND CliStatus = &CliStatus
AND CliTipo = &CliTipo
//Código
ENDFOR
/* Comentário de Edson Geovane - Vikam Corporation
Eu só acrescentaria o uso da cláusula 'defined by' após as sentenças
WHERE. Acho importante porque define a tabela que será lida e ajuda ao
programador identificar rapidamente esta tabela. Vamos incentivar os
programadores ler os programas e entender como se fosse um idioma.
/* Comentário de: Jorge Ronald Cribb - Vikam Corporation
Para melhorar a compreensão do programa eu preferiria que o
ESPECIFICADOR de Genexus escrevesse ao lado de cada FOR EACH
(como comentário) a relação de TABELAS que está usando esse FOR EACH
com toda a seqüência de JOINS e OPÇÕES DE ORDER que será efetuada.
Exemplo:
FOR EACH Clicod, CliStatus // GX: CLIENTES
WHERE CliCod
= &CliCod
AND CliStatus = &CliStatus
AND CliTipo = &CliTipo
//Código
ENDFOR
Nota: Neste caso o comentário que diz "// GX: CLIENTES" seria colocado
automaticamente pelo Genexus depois da especificação do objeto. A
informação que seria colocada pelo Genexus no fonte seria do mesmo tipo
que coloca no informe/lista de navegação do objeto (mas um pouco mais
resumida).
/* Comentário de Demétrio Toledo.
Geralmente costumo identificar sempre a tabela base de onde vou trabalhar
com o For Each, utilizando a cláusula ‘Defined By’, da seguinte maneira:
FOR EACH Clicod, CliStatus // GX: CLIENTES
Where CliCod = &CliCod
Where CliStatus
= &CliStatus
Where CliTipo = &CliTipo
Defined By
CliEstReg
//Código
ENDFOR
Desta maneira se identifica corretamente a tabela base.
FIM
Design Tips

Diferença entre TIPO (Type) e CATEGORIA (Category). Basicamente TIPO (type) é um relacionamento N
para 1, ou seja, quando um objeto só pode ser de um tipo; e CATEGORIA (category) é um relacionamento M
para N, ou seja, quando um objeto pode ter vários tipos/categorias ao mesmo tempo.
REGRA:
“quando for necessário classificar algo, utiliza-se ‘TIPO’ se somente puder ser de um
único tipo, e CATEGORIA se puder ser de mais de um tipo.”
Download