Este Guia do Desenvolvedor serve como um manual ao desenvolvedores. Indicando os padrões de desenvolvimento adotados pela MGA.
Process e Execute tem a mesma finalidade, porém o process é utilizado no primefaces e execute é nativo do JSF.
Ao utilizar um p:ajax o atributo process estará disponível, com um f:ajax o atributo disponível será o execute.
A função de ambos é a mesma: Enviar as informações digitadas para o controlador (servidor), obviamente, neste processo serão executadas as fases do JSF, como conversão dos valores, validação de valores etc, mas não entraremos nesses detalhes devido ao objetivo deste documento.
Sua função é de extrema importância, pois sabendo utilizá-lo você enviará somente o necessário para o controlador (servidor) melhorando o desempenho da aplicação consideravelmente. Entender o funcionamento de tal comando é primordial para quem deseja programar em JSF, faça o que for necessário: pesquise na internet, peça ajuda de amigos etc., mas entenda-o e seus resultados na programação serão surpreendentemente melhores.
Para os exemplos abaixo será utilizado o process, do primefaces, por ser mais cabível para nossa situação.
Update e Render tem a mesma finalidade, porém o update é utilizado no primefaces e render é nativo do JSF.
Ao utilizar um p:ajax o atributo update estará disponível, com um f:ajax o atributo disponível será o render.
A função de ambos é a mesma: Recuperar as informações do controlador (servidor) e trazê-las para a tela, obviamente, neste processo serão executadas as fases do JSF, como conversão dos valores, validação de valores etc, mas não entraremos nesses detalhes devido ao objetivo deste documento.
Sua função é de extrema importância, pois sabendo utilizá-lo você atualizará somente o necessário para na tela melhorando o desempenho da aplicação consideravelmente. Entender o funcionamento de tal comando é primordial para quem deseja programar em JSF, faça o que for necessário: pesquise na internet, peça ajuda de amigos etc., mas entenda-o e seus resultados na programação serão surpreendentemente melhores.
Para os exemplos abaixo será utilizado o update, do primefaces, por ser mais cabível para nossa situação.
Botão Nova Execução – Ao clicar para adicionar uma nova execução, o único componente que deve ser processado é o próprio botão ‘Nova Execução’ para que o método seja de fato chamado no controlador. Porém é necessário um ‘update’ no Painel Nova Execução para que o mesmo seja apresentado na tela, pois até então ele estava oculto.
Código Fonte Botão Nova Execução:
Botão Confirmar Execução – Ao clicar no botão confirmar, somente as informações que estão dentro do Painel Nova Execução (Inputs e o próprio botão confirmar) devem ser processadas e enviadas para o controlador. A atualização em tela (update) deve ocorrer em dois locais: No Painel Nova Execução que deve ser ocultado quando a operação for concluída com sucesso e a Tabela de Execuções que deve ser atualizada.
Código Fonte Botão Confirmar Execução:
Botão Cancelar Execução – O cancelamento neste caso deve somente setar um atributo no controlador e atualizar o Painel Nova Execução para escondê-lo. Para isso, combinada com o botão, foi utilizada a opção f:setPropertyActionListener para setar o atributo com nulo, mas caso fosse necessária a execução de alguma operação por parte do servidor deveria ser utilizado o atributo actionListener do Botão Cancelar Execução.
Código Fonte Botão Cancelar Execução
Botão Editar Execução – A edição deve somente executar o método que faz a seleção do objeto da tabela e atualizar o Painel Nova Execução para que os campos da execução selecionada sejam preenchidos na tela.
Código Fonte Botão Editar Execução:
Botão Remover Execução – A remoção deve somente executar um método no controlador e atualizar a Tabela de Execuções.
Código Fonte Botão Remover Execução:
Obs.: Em todos os códigos descritos acima faltaram as chamadas para os dialogs que apresentam o status da requisição (‘aguarde’) assim como a pergunta se o usuário deseja realmente remover o registro no botão de remoção etc, tais funcionalidades não foram adicionadas pois o foco deste tópico é somente o uso do process e do update e no decorrer do documento cada uma dessas funcionalidades será tratada pontualmente
Obs.: Existem várias formas de passar objetos da view para o controlador, seja por f:setPropertyActionListener, f:attribute ou até diretamente actionListener=”contratoControlador.selecionarExecucao(execucao)”. Não existe forma melhor ou pior, ambas possuem variações de desempenho insignificantes, o que realmente importa neste caso é a praticidade durante a programação, ou seja, utilize a que mais lhe agradar, mas certifique-se acima de tudo de utilizar o process corretamente, pois este sim influenciará no desempenho.
Todo botão deve ter a altura do próprio Primefaces. Salvo em raras exceções em que se torna obvio a necessidade de mudar a altura.
Todos os botões de ‘meio de tela’ devem estar associados à classe css ‘padrão’, esta classe define uma largura mínima para os botões. Note na imagem abaixo o botão ‘Ok’, sua largura foi automaticamente ajustada devido à classe ‘padrão’.
Exemplos:
Todo botão deve ter a cor padrão do primefaces independente do processo que ele executa.
Exemplos:
Todo botão deve possuir um ícone que indique sua função. Por mais difícil que seja encontrar um ícone adequado para determinadas funções ele se faz necessário para harmonizar as telas do sistema.
Exemplos:
Todo botão quando estiver em uma tabela (ver exemplo abaixo) deve conter somente o ícone que ilustre sua função. O header da coluna da tabela indicará sua funcionalidade ou parte dela. Existe somente uma exceção para os botões editar/remover/visualizar que por serem consideradas operações básicas e genéricas para todo o sistema devem ficar na mesma coluna.
A coluna que contém os botões editar/remover/visualizar deve ser chamar ‘Ações’.
Os botões devem ser colocados na parte esquerda da tabela, respeitando sempre a regra de que a primeira coluna é para as operações básicas (editar/remover/visualizar) quando houver.
Exemplos:
Todo botão de remoção/exclusão de registro deve primeiro requisitar a confirmação por parte do usuário da operação executada. A remoção de um registro é tida como algo delicado e o usuário pode clicar sem querer no botão de remoção. Com a mensagem de confirmação há uma segurança a mais para a integridade do sistema.
Código fonte para botões com remoção de registros:
Toda e qualquer ação, por mais simples e rápida que possa ser deve obrigatoriamente exibir a mensagem com o dialog ‘Processando. Por favor, aguarde...’ para que o usuário perceba o processo e possa aguardá-lo.
Quando executamos a aplicação em nossos computadores (localhost) as requisições são praticamente instantâneas e não há gargalos na rede. Porém em ambiente de produção podem ocorrer inúmeros imprevistos que atrasam uma requisição, gerando confusão e stress ao usuário.
Todo botão deve conter um title/hint que indique o processo que ele executará.
Exemplos:
O Botão de informações pode e deve ser utilizado sempre que determinada opção ou operação não ficar clara para o usuário. Este botão é o único que deve ter seu tamanho alterado. Há uma classe específica com o tamanho para ele ‘icone-20’.
O painel com a informação adicional deve ser apresentado quando mouse for posicionado sobre o botão.
Código fonte do botão informações descrito acima
Como é de conhecimento de muitos desenvolvedores, este recurso não funciona plenamente no primefaces. Com isso se faz necessário criar manualmente tal funcionalidade.
A ideia é muito simples, criar dois botões:
Um com um ícone em branco que adiciona/marca o objeto;
Outro com o ícone ticado (tick) que remove/desmarca o objeto;
Toda tela deve o seu ‘botão principal’ que nada mais é do que um botão que se destaca entre os outros indicando que naquela tela em questão ele é mais executado/prioritário. Em telas de cadastros simples, o botão principal é o ‘Salvar’.
Para definir o botão principal é muito simples, basta utilizar a class ‘prioritario’. (O botão ficará azul).
Código Fonte
O cabeçalho das tabelas deve ser sempre completo com todas as informações possíveis inclusive com o título que informa o que a tabela contém.
Código Fonte do cabeçalho:
<p:dataTable paginator="true" id="tabela-execucoes" rowStyleClass="#{empty rowIx or rowIx mod 2 ne 0 ? 'linha-selecionada' : 'trintaAltura'}" rowIndexVar="rowIx" styleClass="mtop05" emptyMessage="Não foram localizados registros para serem apresentados" value="#{contratoControlador.selecionado.execucoes}" rows="10" paginatorTemplate="{CurrentPageReport} <span class='titulo-tabela mrig10'>EXECUÇÕES</span> {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" currentPageReportTemplate="({startRecord} - {endRecord} de {totalRecords}, Página: {currentPage}/{totalPages})" rowsPerPageTemplate="10,25,50,100" var="execucao">As linhas da tabela devem ter suas cores alternadas entre branco e azul claro (classe : ‘linha-selecionada’).
Código Fonte para colorir a linha corretamente
rowStyleClass="#{empty rowIx or rowIx mod 2 ne 0 ? 'linha-selecionada' : 'trintaAltura'}" O alinhamento nas colunas das tabelas deve seguir as seguintes especificações:
As mensagens do sistema devem ser claras, limpas e objetivas.
O Artigo http://www.ibrau.com.br/artigomensagensdeerro.htm aborda muito bem o assunto de mensagens para o usuário.
A dica básica é evitar mensagens negativas. O cérebro humano gasta mais tempo e mais esforço para concluir o raciocínio de uma negação. Isso parece somente um pequeno detalhe mas faz uma grande diferença, principalmente em sextas-feiras a tarde. E além do mais o usuário deve/quer saber exatamente o que fazer e se você diz a ele ‘o que não fazer’, está errando. Obviamente existem casos em que será necessário usar a negação (Ex 02) mas sempre, sempre analise bem antes de escrever uma negação.
Ex 01:
O valor unitário não pode ser maior que o valor total de cada grupo.
O valor unitário deve ser menor que o valor total de cada grupo.
Ex 02:
Um item com o número 02 já foi localizado.
Não é permitido cadastrar um item com o número repetido.
Informe um número diferente para o item atual.
Para este caso ao invés de separar cada frase com (,) vírgula, adicione 3 mensagens não há problema algum nisso e o caso se torna mais fácil de entender.
Ex 03:
A data de entrada deve ser menor que a data de saída.
A data de entrada deve ser anterior à data de saída.
Utilize as regras corretas do português, datas são anteriores e/ou posteriores. Não utilize data menor, data inferior, data maior ou data superior.
Ex 04:
A Data de Entrada deve ser ANTERIOR à Data de Saída.
A data de entrada deve ser anterior à data de saída.
Evite letras maiúsculas nas mensagens, pois sua utilização reduz a velocidade de leitura. Esta regra deve ser aplicada para as palavras ‘Data de entrada’, ‘ANTERIOR’ e ‘Data de Saída’.
Se quiser evidenciar uma palavra na mensagem use o negrito.
Ex:
A data de entrada deve ser anterior à data de saída.
Os sumários das mensagens já estão pré-definidos e devem ser utilizados com coerência. O Enum SummaryMessages possui todos os sumários necessários para qualquer operação do sistema. As opções são as seguintes:
CAMPO_OBRIGATORIO(“Campo Obrigatório!”): Algum campo obrigatório não foi informado.
FacesUtil.addCampoObrigatorio(“Detalhes da mensagem”);
OPERACAO_REALIZADA(“Operação realizada!”): A operação foi realizada com sucesso. A operação que o usuário solicitou foi concluída sem problema algum.
FacesUtil.addOperacaoRealizada(“Detalhes da mensagem”);
OPERACAO_NAO_REALIZADA(“Operação não realizada!”): A operação não foi realizada devido a algum erro, alguma situação não esperada por parte do sistema. Para facilitar, no FacesUtil há um método que adiciona uma mensagem com este sumário:
FacesUtil.addOperacaoNaoRealizada(“Detalhes da mensagem”);
OPERACAO_NAO_PERMITIDA(“Operação não permitida!”): A operação não foi realizada devido a alguma regra que não permitiu sua continuidade. Utilizar esta mensagem quando o sistema não permitir à validação de regras de negócios que não foram aceitas.
FacesUtil.addOperacaoNaoPermitida(“Detalhes da mensagem”);
ATENCAO: Quando uma mensagem de atenção deve ser emitida para o usuário. Esta serve mais como uma ressalva, levando mais informações ao usuário sobre determinadas ações.
FacesUtil.addAtencao(“Detalhes da mensagem”);
A lista de opções do autocomplete deve aparecer para baixo e com um limite de 10(dez) registros. Verificar também suas queryes, tente de todas as formas melhorar o desempenho.
Os métodos de autocomplete devem sempre estar em seus respectivos controladores. Se um autocomplete é de pessoa jurídica, obviamente ele deve estar no controlador de pessoa jurídica e o método de acesso ao banco deve estar no facade de pessoa jurídica. Mesmo que ele nunca vá ser utilizado em uma tela de pessoa jurídica, seu retorno é uma ou mais pessoas jurídica e com isso se faz necessário que ele esteja no controlador e facade correspondente.
Os inputs deve preencher as barras automaticamente. Há uma função em javascript que faz tal processo e ajuda muito na usabilidade das telas.
Código fonte de um p:calendar:
Os dialogs são dimensionados automaticamente de acordo com o conteúdo que possuem. Portanto não é necessário definir um tamanho fixo para eles. (width=”100”, height=”200”).
A posição dos dialogs deve ser sempre no centro da página. (position=”center”)
Utilize o seguinte atributo para garantir que um dialog sempre aparecerá para o usuário, pois em muitos casos principalmente em páginas grandes o usuário ‘rola’ a página e o dialog não é aberto na posição desejada. (style=”position: fixed !important;”)
Utilize o atributo modal nos dialogs para evitar confusões durante as requisições do usuário.
Exemplo de código fonte para dialogs:
Procure utilizar o atributo dynamic para que ao carregar a página não sejam criados componentes do dialog sem necessidade, pois às vezes o dialog nem será aberto pelo usuário. (dynamic=”true”)
Durante o desenvolvimento de novas páginas ou alteração de páginas já existentes procure utilizar o componente fc:aguarde “aguarde.show()/aguarde.hide()”.
O statusDialog está deprecado e não deve mais ser utilizado e o mesmo deve ser substituído pelo aguarde. Faça essa substituição nas telas que você alterar.
As urls devem ser pequenas e indicar exatamente sua funcionalidade.
Palavras compostas devem ser separadas por um hífen.
Exemplos:
webpublico/empenho/novo/
webpublico/cadastro-imobiliario/novo/
webpublico/dirf/acompanhamento/
webpublico/relatorio/ajuste-depositos/
Todos os processamentos longos devem ser executados em uma janela a parte indicando para o usuário o status da operação desejada. Sua url deve conter o sufixo ‘acompanhamento’ para deixar claro que é um processo.
Exemplos:
webpublico/dirf/acompanhamento/
webpublico/dirf/acompanhamento/
webpublico/sefip/acompanhamento/
webpublico/folha-de-pagamento/acompanhamento/
Por mais informações que um objeto contenha ele nem sempre apresentará todos os detalhes que o usuário precisa. Sempre que possível, para objetos que seu toString não puder distingui-lo de forma clara, abra a página de visualização do mesmo em outra aba. É um processo simples, e que aumenta a usabilidade do sistema.
O exemplo mostra as informações básicas de uma licitação. Porém sempre é preciso ver mais informações, e tais informações são facilmente encontradas na página de visualização da licitação (webpublico/licitacao/ver/123456/).
Código fonte do botão citado acima:
<p:commandButton process="@none" id="bt-ver-licitacao" icon="ui-icon-lupa" styleClass="icone-20 mrig10" disabled="#{habilitacaoPregaoControlador.selecionado eq null}" update="@none" onclick="window.open('#{request.contextPath}/licitacao/ver/#{habilitacaoPregaoControlador.selecionado.id}/','_blank');"/>Fique atento, sempre que for necessário abrir uma nova aba use o ‘_blank’ pois é a opção correta segundo a especificação HTML.
Todo controlador, possui por padrão um converter de sua própria entidade que é implementado automaticamente quando existe a herança do ‘PrettyControlador’. Com isso, para a maioria dos casos, não é necessário ficar criando converters no seu controlador.
Se precisar de um converter de Empenho, faça a chamada:
converter="#{empenhoControlador.converterGenerico}" Se precisar de um converter de Contrato, faça a chamada:
converter="#{contratoControlador.converterGenerico}" Se precisar de um converter de PessoaFisica, faça a chamada:
converter="#{pessoaFisicaRHControlador.converterGenerico}" Note que o atributo é sempre o mesmo, a única mudança fica por conta do controlador.
Por convenção, os métodos devem sempre estar nos facades de acordo com seu tipo de retorno.
Em alguns casos não existe o facade adequado, principalmente para casos de Agregação e/ou Composição e para tais casos os métodos devem ser implementados no facade do item que os contem (Ex. 03).
Ex 01:
Método que retorna uma instancia ou lista de Empenho, deve estar em EmpenhoFacade.
Ex 02:
Método que retorna uma instancia ou lista de Licitacao, deve estar em LicitacaoFacade.
Ex 03:
Método que retorna uma lista de ItemProcessoDeCompra, deve estar em ProcessoDeCompraFacade
Indente seu código! É fácil e prático e além do mais na grande maioria das IDEs sempre há um comando via teclado para esta função. Pense no próximo desenvolvedor que analisará seu código, ele deve no mínimo ter um código legível e indentado em mãos para fazer o trabalho com eficiência.
Como fora pactuado no passado, para evitar grandes problemas, confusões e principalmente, evitar paralização de bases e outros desenvolvedores devido a problemas em changesets recomenda-se que cada changeset contenha operações pequenas.
Ao invés de “Criar Tabela”, “Criar PK”, “Criar Foreign Key” em um changeset. Crie 3 changesets um para cada função descrita acima.
Se você vai criar uma lista de selectItem, dê uma olhada no método “getListSelectItem” da classe “Util”. Este método fora criado com o objetivo de eliminar a criação de diversos outros métodos que criam um List de objetos ‘SelectItem’. Existem diversas utilizações deste método no projeto que servirão como exemplo.
Ex:
Quando Enum:
return Util.getListSelectItem(Arrays.asList(SituacaoCadastralContabil.values()));Quando objetos persistidos:
return Util.getListSelectItem(corFacade.listaDecrescente());Em diversas operações no sistema nos deparamos com a necessidade de gerar números para o usuário, números sequenciais que NÃO são os IDs das entidades e que devem possuir seu controle sequencial. Esse é aquele ‘número gerado automaticamente pelo sistema‘.
Para que não hajam repetições em tais números devido a usuários fazendo a mesma operação simultaneamente e que sempre o número buscado seja o próximo valor disponível foi criado um Singleton que auxilia com eficácia esse controle.
Exemplos:
selecionado.setNumero(singletonGeradorCodigo.getProximoCodigo(AprovacaoMaterial.class,"numero"));selecionado.setNumero(singletonGeradorCodigo.getProximoCodigo(LoteEfetivacaoCessao.class,"numero"));entity.setNumero(singletonGeradorCodigo.getProximoCodigo(entity.getClass(), "numero")); A criação de PKs e FKs é algo comum entre os nós desenvolvedores, porém há algo a mais que precisamos criar que ajuda e muito no desempenho do sistema: Os Indices, basicamente siga a regra de que onde houver FK deve haver também um índice. Não se esqueça do prefixo IDX quando cria-los.
Exemplos:
<createIndex tableName="GESTORLOCALESTOQUE" indexName="IDX_GETOR_LOCALESTOQUE"> <column name="LOCALESTOQUE_ID"/></createIndex><createIndex tableName="CALCULO" indexName="IDX_CALCULO_PROCESSO"> <column name="PROCESSOCALCULO_ID"/></createIndex><createIndex tableName="ATRIBUTOSPROPRIEDADEAGATA" indexName="IDX_ATRBAGATAPROP_PROPRIEDADE"> <column name="PROPRIEDADE_ID"/></createIndex>Uma tela bem montada apresenta harmonia para o usuário e torna o seu trabalho mais agradável.
As margens merecem sem dúvida uma atenção importante, pois definem a forma que os componentes são apresentados na tela.
Tenha em mente que sempre que houverem componentes ‘colados’, uma margem de 5px resolve o problema. Nem mais e nem menos!
As linhas vermelhas na imagem acima indicam os locais onde é necessário colocar uma margem de 5px para que os componentes fiquem bem distribuídos na tela.
Para isso basta utilizar as classes já definidas no css.
mtop05 = margin-top : 5px!important;mrig05 = margin-right : 5px!important;mlef05 = margin-left : 5px!important;mbot05 = margin-bottom : 5px!important;Note que a nomenclatura é obtida através de:
m(margin);
3 primeiras letras da próxima propriedade(top, right, left, bottom);
Número de pixels, no caso 05;
Existem várias classes pré-definidas com as margens mais utilizadas.
Procure utilizá-las no seu dia-a-dia para tornar o código mais limpo.
Os valores de tais classes são: 02, 03, 05, 10, 20, 30, 50, 100.
E conforme aprendizado acima podem ser usados com: mtop, mrig, mlef, mbot.
Ex: mrig20, mtop30, mbot10 etc...
Não se esqueça de que o padrão é a margem com 5(cinco) pixels.
A imagem acima com os devidos espaçamentos:
A SuperEntidade deve ser utilizada como superclasse de todas as entidades do sistema. Entenda sua necessidade para empregá-la da melhor forma possível.
Sua maior utilidade é a implementação automática dos métodos equals() e hashCode(), ela também possui alguns métodos genéricos que podem lhe auxiliar no dia-a-dia.
A partir de agora você não precisa mais criar o atributo ‘criadoEm’ nas entidades que for dar manutenção. Como dito acima, basta ‘extender’ da SuperEntidade.
Exemplo:
public class AprovacaoLevantamentoBem extends SuperEntidade {}Para quebrar linhas em arquivos TXT utilize o comando:
System.getProperty("line.separator");Utilizando este comando você garante que a será executada a quebra da linha independente do sistema operacional. Não utilize os comando ‘\r’ ou ‘\n’.
a. O desenvolvedor aceita um ticket, e cria um branch a partir do branch principal;
b. Durante o desenvolvimento, são feitos commits a cada passo do ticket;
c. Ao termino do ticket o desenvolvedor irá criar o Pull Request;
d. Caso haja conflito ao criar o Pull Request, o desenvolvedor irá criar outro branch a partir do branch principal e fará o merge do branch do seu ticket para este novo branch. Feito o merge para o novo branch, fará novo Pull Request, desta vez a partir do novo branch criado, onde foi feito o merge
e. O Pull Request passará pelo processo de code review;
f. Caso aceito, será integrado ao branch principal, ficando disponível para testes do P.O na aplicação de homologação
g. Sendo Rejeitado, írá corrigir os problemas apontados pelos reviewers, solicitando ajuda destes, se necessário.
h. Após corrigir os problemas, voltará à etapa C.
i. Após o ticket ser testado e aprovado pelo P.O. deve ser criado um novo pull request para o branch de produção (Ex. riobranco/produção).
O processo de code review é uma maneira de aplicação de padrões e convenções no código-fonte de um projeto, visando maior homogeneidade, organização e qualidade do mesmo. Este processo consiste na revisão do código antes que o mesmo faça parte do repositório central, feito por ferramentas automatizadas e por determinados membros de uma equipe. Caso o código esteja dentro das regras previamente estabelecidas, será aceito, do contrário será rejeitado, com o devido apontamento de qual, ou quais, padrões não estão contemplados, e o posterior auxílio do autor do código para a adequação do mesmo.
No code review não é feito o teste do código em conformidade com o ticket. Este teste é realizado pelo P.O. na etapa de aceitação do ticket, sendo, portanto, uma etapa de negócio, enquanto o code review é uma etapa técnica, visando apenas código homogêneo, padronizado, em todo o projeto.
Nomes de classes, variáveis, métodos, etc, devem ser significativos, indicando claramente o que um método faz ou o que um atributo representa. A intenção deve ser visível através dos nomes. Crie nomes pronunciáveis para facilitar a comunicação, evite acrônimos e siglas.
No caso de métodos, variáveis e outros trechos de código que não precisem de mudança no banco de dados, as regras devem ser aplicadas mesmo para código já existente, renomeando métodos e variáveis já existentes
Com cada método realizando apenas uma função, seu nome deve começar com o verbo da função que ele executa, no infinitivo, seguido dos alvos da ação. Por exemplo, efetivarVenda, adicionarItemNaLista, processarLoteDePagamentos.
Obrigatóriamente todo método que realiza uma consulta na Base de dados deve se iniciar pelo termo “buscar”, por exemplo um método que recupera o usuário pelo seu login deve se chamar “buscarUsuarioPorLogin”.
Preocupe-se em tornar o método entendível pelo seu nome e por seus parametros, como o exemplo acima que recebe o login e retorna o usuário, caso tenha mais que um parâmetro, deve se usar o complemento And, por exemplo um método que consulte na base de dados as Folhas de Pagamento por Servidor e periodo deve se chamar buscarFolhaPagamentoPorServidorAndPeriodo. Alternativamente, se a consulta do método utilizar or ao invés de and, utilizar o termo "Or", por exemplo buscarFolhaPorServidorOrMatricula.
Getters e Setters, por terem função especial, são uma exceção à regra.
Os atributos de classes devem sempre estar no singular, exceto Collections, estas devem sempre estar no plural correto de acordo com a língua portuguesa, atente-se que a IDE de desenvolvimento pode gerar no plural, mas nem sempre certo, por exemplo:
O exemplo acima está errado, o correto nesse caso é:
Para atributos do tipo Date ou TimeStamp não utilize o termo que remete ao tipo do atributo, por exemplo dataEstorno ou ainda dataDeEstorno. Caso se tratem de vigência a nomenclatura deve ser inicioVigencia e finalVigencia, sempre que se tratar de periodos priorise essa nomenclatura, se for imprecindível mudar, permaneça com os termos inicio e final, por exemplo inicioCobranca e finalCobranca. Caso se trate de uma data em que o fato foi ocorrido utilize ocorridoEm, por exemplo a classe Estorno tem o atributo ocorridoEm, ou ainda a classe Parcelamento tem o atributo canceladoEm.
Atributos do tipo Boolean sempre devem priorizar o positivo, por exemplo a classe Parcelamento tem um atributo que indica se ele está ativo, esse atribo deve se chamar ativo. Além disso, atributos Boolean devem ter nomes que aceitam de forma clara os valores verdadeiro e falso. Por exemplo, "ativo", "parcelado". Exemplo de como não fazer: "situação" - situação verdadeira ou situação falsa não dá clareza ao significado.
Nunca deve ser utilizado o System.out.println para “Log”.
Para Log sempre utilizar a classe Logger do pacote org.slf4j.Logger, criando um atributo constante (estático e final) no início da classe, como o exemplo abaixo:
O parametro do método estático getLogger da classe LoggerFactory deve sempre ser a classe em que ele se encontra.
Utilize apenas em modo DEBUG:
Ao tratar uma exception, jamais deve ser invocado o método printStackTrace() da classe Exception. Idealmente, deve-se jogar (throw) uma nova exception com a mensagem.
No java existem 2 tipos de problemas: Exceptions e Errors. Exceptions são problemas internos da aplicação que a mesma pode resolver, ou contornar. Errors são problemas que normalmente envolvem a JVM, ou o ambiente onde esta é executada (o Sistema Operacional ou o Hardware), e portanto não há nada que a aplicação possa fazer a respeito. Por exemplo, NullPointerException, e OutOfMemoryError.
A classe java.lang.Throwable é a superclasse de ambas as classes acima, e por isso, é errado num try/catch tentar capturar Throwables, uma vez que a aplicação poderia “engolir” o problema de forma que é impossível determinar a causa. O correto, quando se deseja fazer um catch universal, é sempre fazer catch de Exception, e nunca de Throwable.
Exceto em casos onde não é possível passar parâmetros, como a implementação atual do Pesquisa Genérico, todas as queries que recebam um valor, deverão fazê-lo por parâmetros, e não concatenando o valor direto na query, mesmo em queries onde o parâmetro é fixo.
Ao misturar parâmetros com valores fixos na query, é impossível para o banco de dados analizar e otimizar a query adequadamente. Além disso, o oracle utiliza o texto da query como chave para seus caches.
Nas funcionalidades com parâmetros dinâmicos, onde o usuário pode escolher zero ou mais parâmetros, deve-se controlar o uso de WHERE ou AND no código de negócio, ou seja, fora da query, diferente de alguns lugares que possuem cláusulas ‘WHERE 1 = 1’ ou similares.
Sempre que uma tabela se relacionar com outra, deve-se criar a chave estrangeira (foreign key - fk) do relacionamento, de forma que seja possível para desenvolvedores verificarem a associação direto pelo banco de dados. Ainda, toda FK criada deve ser nomeada, evitando nomes aleatórios gerados pelo banco de dados, facilitando a posterior identificação em mensagens de erro. A nomenclatura deve, quando possível, começar com FK_ e em seguida incluir as tabelas de origem e destino, e um nome para a associação, por exemplo fk_unid_hierarq_administrativa
Além do efeito documentativo que a chave estrangeira cria, a restrição também garante que não serão gravados valores inválidos, e facilita a análise e otimização da query feita pelo banco de dados.
Além das chaves estrangeiras, deve-se criar também um índice no campo da chave estrangeira, melhorando assim a performance de consultas que envolvam essa associação. Da mesma forma que a FK, o índice deve ser nomeado, quando possível iniciando com o termo IDX_ seguido do nome da tabela e nome do campo, por exemplo IDX_VINCULOFP_MATRICULAFP_ID
Como o campo criado para associar as tabelas é utilizado nos joins entre elas, a criação de um índice permite que o banco de dados busque mais rapidamente apenas os registros da tabela associada relacionados àquele registro da tabela principal.
Como as regras abaixo acarretam em modificações profundas, serão exigidas apenas em CÓDIGO NOVO.
As classes de controladores devem ter apenas código relativo a interface com o usuário (tela, frontend), mantendo a regra de negócio nos Façades. Como código de tela, pode-se citar, por exemplo, converters, retorno de auto completes (que normalmente vai acessar um Façade), quando mostrar ou não mostrar uma aba, ou div, navegação de uma tela para outra, mensagens de erro, dentre outros.
Com essa separação, ao trocar a tecnologia de front-end (de JSF para AngularJS, por exemplo), a regra de negócio fica inalterada.
Quando é necessário utilizar um método de um Facade em outro Facade ou em um Controlador, esse Facade ou Controlador deve injetar o Facade desejado. Por exemplo, a chamada this.hierarquiaFacade.getSistemaFacade().algumMetodo() deve ser evitada. A classe que contém essa chamada deve injetar o SistemaFacade e usá-lo diretamente.
Antes entendia-se que havia um impacto de performance e consumo de recursos ao injetar vários Facades, e recomendávamos reutilizar os Façades sempre que necessário. Hoje verificamos que isso não acontece, e a injeção direta mantém o código independente e organizado.
O fluxo de chamadas deve sempre ser um Controlador chamar um Facade ou Service, e nunca o contrário, desta forma, um controlador deve injetar o seu facade ou service e esse facade ou service injeta as outras dependências, nunca deve injetar em uma dessas dependências um Controlador.
Caso um Façade ou Service dependa de um Controlador, a camada de interface com o usuário interfere na camada de negócios, ou seja, uma alteração de interface pode quebrar a camada de negócios. Idealmente, apenas a interface com o usuário depende de negócios e nunca o contrário.
Quando um atributo de uma classe possuir um valor padrão, e o mesmo não depender da chamada de um método, esse valor deve ser atribuído na declaração do atributo.
A fim de evitar problemas de NullPointerException e a necessidade de sua verificação em todos os pontos da aplicação, sempre que possível esse controle deve ser feito na origem do problema. Por exemplo, métodos getter de Booleans, ao invés de null podem retornar um valor padrão, e comparações com String ou Enums podem ser feitas de forma “invertida”, ou seja, comparar o valor com a variável, e não o contrário.
Por exemplo, o trecho de código variavel.equals(“teste”) pode jogar NullPointerException quando variavel for null. Já no código “teste”.equals(variavel) o problema não acontece, e não é necessário verificar se variável é null, pois o objeto “teste” nunca é null. O mesmo é válido para enums: valorEnum.equals(Enum.VALOR_UM) pode jogar NullPointerException mas Enum.VALOR_UM.equals(valorEnum) não.
Algumas classes possuem objetos imutáveis, ou seja, sua instância nunca muda. Como exemplo disso temos as classes String e BigDecimal. Assim, a fim de organizar melhor o código, os valores comumente utilizados dessas classes devem ser declarados como constantes. Por exemplo, BigDecimal zero, ou cem.
A classe BigDecimal possui um construtor que recebe um número, e outro que recebe uma String. Pela forma como a classe BigDecimal armazena os valores e realiza a conversão de números Integer e Long, em alguns casos ao construir um BigDecimal a partir de um número acarreta em um número diferente. Por exemplo, new BigDecimal(100) pode gerar um objeto BigDecimal com valor 99.99999999999999999999999999999999991 ou algo parecido. Por isso, ao instanciar um BigDecimal, devemos utilizar o Construtor que recebe uma String, então ao invés de new BigDecimal(100) devemos utilizar new BigDecimal(“100”).
Foi criada uma função que se associada a um determinado campo limita seu conteúdo para que sejam aceitos somente caracteres numéricos. Na mesma função existem também alguns parâmetros que podem ser utilizados limitando ainda mais os possíveis valores de entrada.
Declaração do método:
Definição dos parâmetros acima:
Já existia uma função no sistema encarregada de aplicar a mascara monetária nos campos, porém nela sempre era possível informar valores negativos. Tal função foi melhorada e através de um segundo parâmetro pode se definir se são permitidos ou não valores negativos.
Declaração do método:
function mascaraMonetaria(campo, permiteValorNegativo)
Se a função for chamada sem passar o parâmetro opcional ‘permiteValorNegativo’ não há problema algum pois javascript possibilita isso, portanto as chamadas anteriores para esta função não foram alteradas e continuam funcionais.
O trecho descrito acima ainda funciona normalmente!
Havia um problema no front-end com o textarea do primefaces no qual mesmo colocando um limitador de caracteres era possível submeter um conteúdo maior. Tal funcionalidade foi corrigida e agora os valores são enviados corretamente. Segue abaixo uma imagem da utilização do componente para ajudar a recordar.
Para realizar validações em regras de negócios, evite utilizar o boolean como retorno de funções e procure utilizar exceptions, desta forma o código fica mais encapsulado e da forma correta segundo os padrões de boas práticas.
Para que todos sigam os novos padrões houveram algumas modificações na classe Util, nas quais dois métodos foram deprecados e um novo método foi adicionado como segue:
Novo
As chamadas dos métodos:
Não utilizar assim:
Utilizar assim:
Caso o objeto que deseja validar seja uma extensão de SuperEntidade pode se chamar a validação da seguinte forma:
ObjetoASerClonado – Define qual objeto será clonado e retornado pelo método;
nivel – Define o nível de profundidade em que as entidades relacionadas serão clonadas.
Para edição de registros em listas, utilize o método Util.clonarEmNiveis para garantir que não ocorram problemas durante as operações do usuário. Conforme imagem abaixo, segue exemplo da utilização da forma correta de se clonar um objeto, sendo este, feito no momento em que o usuário escolhe por editar um registro da lista.
Durante o clone em níveis é possível passar o nível de clonagem que será feito para garantir a integridade dos dados. Para o exemplo abaixo vamos supor que a entidade a ser clonada seja Unidade Organizacional, com isso o nível buscará recursivamente todos os atributos que sejam entidades até que se chegue ao valor informado no parâmetro. Por padrão, aconselha-se utilizar o valor 2, podendo este ser ajustado de acordo com a necessidade da implementação.
Todo inicio de Sprint, deve-se realizar o processo de alinhamento do branch master com o novo branch de desenvolvimento, para tanto é necessário realizar os seguintes passos: