Pular para o conteúdo principal

Guia Desenvolvedor

Revisão

Este documento foi aprovado em 28/09/2016 por Robinson Patroni , Diretor da MGA.

1.Designing for Productivity in the User eXperience.
2.UX & Web Design Master Course: Strategy, Design, Development
3.Introdução à Gamificação - Teoria e Aplicações Práticas
4.Seja PMP®: Curso preparatório completo para certificação
5.Curso de Angular JS
6.AWS - Curso Preparatório para Certificação Developer
7.Curso online para certificação ITIL® Foundation
8.Inglês em 10 minutos por dia!
9.O Curso Completo de Inglês
10.Preparatório PMP - Project Management Professional
11.Fundamentos em Gestão de Projetos com PMBOK 5a edicão
12.Curso Completo Unity 5
13.Unity 5 + C#: Simplificando o Desenvolvimento de Jogos
14.Xamarin - Desenvolvimento para Android, iOS e WP.
15.Curso Completo do Desenvolvedor Android M - Crie 10 Apps
16.Curso Completo do Desenvolvedor iOS 10 - Crie 15 Apps
17.Curso Completo do Desenvolvedor Web
18.Curso Completo de Desenvolvimento WEB - Crie 6 Projetos
19.Curso Completo do Desenvolvedor NodejS e MongoDB
20.Aprenda Angular 2 com TypeScript
21.Aprenda C e C++
22.Flutter Essencial
23.Criando Aplicativo Financeiro com Ionic3
24.Ionic 3 para iniciantes
25.Ionic 3 - Guia de Cidades
26.Ionic 3 com banco de dados
27.Ionic 3 - Construindo um App estilo food com NodeJS
28.Introdução ao Sistema Operacional Linux
29.Terminal Linux
30.Introdução à programação de computadores
31.Introdução à lingugem Python
32.Minicurso Qlikview do Zero - Introdução ao Qlik!
33.Criando Páginas Web com o GitHub Pages
34.Unreal Engine 4 Essenstials - Uma introdução detalhada
35.Aprenda Unity 5 - Como criar um jogo de plataforma 3D
36.Aprenda Unity Programando 7 jogos
37.Aprenda Unity 5+ C#: Simplificando o Desenvolvimento de Jogos
38.Python para iniciantes
39.Curso de C++ Intermediário
40.Python 2 na web com Django (Básico e Intermediário)
41.Machine Learning e Data Science com Python de A à Z
42.Construa aplicativos mobile do zero com React Native
43.Desenvolvimento Web Completo 2019
44.Melhor GED com Alfresco e LibreOffice
45.Alfresco 4 Enterprise Content Management Implementation
1.Começando com Spring MVC
2.Começando com Web Services RESTful e Spring
3.Produtividade com Bootstrap
4.Explorando a Linguagem JavaScript
5.Principais Design Patterns Aplicados com Java
6.Angular, REST e Spring Boot
7.Começando com JavaScript
8.Programando em TypeScript

Process/Execute e Update/Render

Process e Execute

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

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.

Exemplo Process e Update:.

Exemplo

Botao1 - Botão Nova Execução - Ao clicar para adicionar uma nova execução.
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:

 <p:commandButton value="Nova Execução" 
icon="ui-icon-circle-plus"
actionListener="#{contratoControlador.novoExecucaoContrato()}"
process="@this"
update=":Formulario:tab-view-geral:panel-nova-execucao"/>

BotaoSalvar - 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:

<p:commandButton value="Confirmar" 
process="panel-nova-execucao"
update=":Formulario:tab-view-geral:panel-geral-execucoes"
actionListener="#{contratoControlador.confirmarExecucao}"
icon="ui-icon-check"/>

BotaoCancela - 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

<p:commandButton value="Cancelar" 
process="@this"
update=":Formulario:tab-view-geral: panel-nova-execucoes "
icon="ui-icon-cancel">
<f:setPropertyActionListener value="#{null}"
target="#{contratoControlador.execucaoContratoSelecionada}"/>
</p:commandButton>

BotaoEdit - 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 Cancelar Execução:

<p:commandButton icon="ui-icon-pencil" 
title="Clique para alterar este registro."
process="@this"
actionListener="#{contratoControlador.selecionarExecucao(execucao)}"
update=":Formulario:tab-view-geral:panel-nova-execucao"
styleClass="mrig05"/>

BotaoExclui - 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:

<p:commandButton icon="ui-icon-trash" 
process="@this"
actionListener="#{contratoControlador.removerExecucao(execucao)}"
title="Clique para remover este registro."
update="tabela-execucoes"/>
  • 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.

    Botões

    Tamanho

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 ‘padrao’, 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 ‘padrao’.

Ex: NewPen confirmaExclui Ok

Cores

Todo botão deve ter a cor padrão do primefaces independente do processo que ele executa.

Ex: NewPen confirmaExclui

Ícones

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.

Ex: Detal confirmaExclui

Botões em tabelas

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.
Ex: Exec

Botão de remoção/exclusão de registro

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:

<p:commandButton icon="ui-icon-close" 
process="@this"
onclick="if (!confirm('Tem certeza que deseja remover este registro?')) {return false; } else {aguarde.show();}"
oncomplete="aguarde.hide()"
actionListener="#{contratoControlador.removerExecucao(execucao)}"
title="Clique para remover este registro."
update="tabela-execucoes"/>

Tempo de processamento/Pesquisa

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. Código fonte de botões:

<p:commandButton value="Nova Execução" 
icon="ui-icon-circle-plus"
onclick="aguarde.show()"
oncomplete="aguarde.hide()"
actionListener="#{contratoControlador.novoExecucaoContrato()}"
process="@this"
update=":Formulario:tab-view-geral:panel-execucao"/>

<p:commandButton value="Confirmar"
styleClass="mrig05"
onclick="aguarde.show()"
oncomplete="aguarde.hide()"
process="panel-novo-execucao"
title="Clique para confirmar esta execução."
update=":Formulario:tab-view-geral:panel-execucao :Formulario:tab-view-geral:panel-itens"
actionListener="#{contratoControlador.confirmarExecucao}"
icon="ui-icon-check"/>

<p:commandButton value="Cancelar"
process="@this"
onclick="aguarde.show();"
oncomplete="aguarde.hide()"
title="Clique para cancelar esta execução."
actionListener="#{contratoControlador.cancelarExecucao}"
update=":Formulario:tab-view-geral:panel-execucao"
icon="ui-icon-cancel"/>

<p:commandButton icon="ui-icon-pencil"
title="Clique para alterar este registro."
onclick="aguarde.show()"
oncomplete="aguarde.hide();"
process="@this"
actionListener="#{contratoControlador.selecionarExecucao(execucao)}"
update=":Formulario:tab-view-geral:panel-execucao"
styleClass="mrig05"/>


Código fonte de p:ajax em input:

<p:ajax event="valueChange" 
onstart="aguarde.show()"
oncomplete="aguarde.hide()"
update=":form-itens-execucao"
process="@this"
listener="#{contratoControlador.validarQuantidadeDoItemExecucao}"/>

Código fonte de p:ajax em autocomplete:

<p:ajax event="itemSelect" 
process="@this"
update="painel-fornecedores-vencedores panel-detalhes-licitacao bt-ver-licitacao"
onstart="aguarde.show()"
oncomplete="aguarde.hide()"
listener="#{habilitacaoPregaoControlador.carregarDependencias}"/>

Title (hint)

Todo botão deve conter um title/hint que indique o processo que ele executará.
Ex:
Tittle Confirm

Botão de informação

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.

Ex: InfoButtom

Código fonte do botão informações descrito acima.

<p:commandButton id="bt-informacao-disponivel-solicitar" 
icon="ui-icon-info"
process="@none"
update="@none"
styleClass="icone-20"/>
<p:overlayPanel for="bt-informacao-disponivel-solicitar"
appendToBody="true"
style="border : solid black 2px;"
showEvent="mouseover"
hideEvent="mouseout">
<h:outputText
value="A quantidade disponível para solicitar é dada a partir da seguinte equação: &lt;br/> &lt;br/>
&lt;b>Disp. Para Solicitar = Qtde. do Contrato - (Qtde. em Requisição + Qtde. Entregue)&lt;b/>"
escape="false"/>
</p:overlayPanel>

Botões de marcação em tabela (ticar)

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;
MarkButtom

Código fonte dos botões de marcação descrito acima.

<p:column style="width: 30px!important">
<f:facet name="header">
<p:commandButton icon="ui-icon-none"
process="@this"
rendered="#{!habilitacaoPregaoControlador.todosItensMarcados()}"
update="tabela-itens-do-fornecedor :form-itens-do-fornecedor:bt-habilitar"
onclick="aguarde.show()"
oncomplete="aguarde.hide()"
actionListener="#{habilitacaoPregaoControlador.marcarTodosItens()}"
styleClass="icone-20"/>

<p:commandButton icon="ui-icon-check"
process="@this"
onclick="aguarde.show()"
oncomplete="aguarde.hide()"
rendered="#{habilitacaoPregaoControlador.todosItensMarcados()}"
update="tabela-itens-do-fornecedor :form-itens-do-fornecedor:bt-habilitar"
actionListener="#{habilitacaoPregaoControlador.desmarcarTodosItens()}"
styleClass="icone-20"/>
</f:facet>
<p:commandButton icon="ui-icon-none"
process="@this"
update="tabela-itens-do-fornecedor :form-itens-do-fornecedor:bt-habilitar"
onclick="aguarde.show()"
oncomplete="aguarde.hide()"
rendered="#{!item.selecionado}"
actionListener="#{habilitacaoPregaoControlador.marcarItemPropostaFornecedor(item)}"
styleClass="icone-20"/>
<p:commandButton icon="ui-icon-check"
update="tabela-itens-do-fornecedor :form-itens-do-fornecedor:bt-habilitar"
onclick="aguarde.show()"
oncomplete="aguarde.hide()"
process="@this"
rendered="#{item.selecionado}"
actionListener="#{habilitacaoPregaoControlador.desmarcarItemPropostaFornecedor(item)}"
styleClass="icone-20"/>
</p:column>

Botão principal

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).
Ex: PesqBut

Código Fonte:

<p:commandButton value="Pesquisar (P)" 
title="Clique para pesquisar"
accesskey="P"
icon="ui-icon-search"
onstart="aguarde.show()"
oncomplete="aguarde.hide()"
actionListener="#{controlador.pesquisar()}"
styleClass="prioritario mrig05 pesquisar"
style="width: 150px">
</p:commandButton>

Tabelas

Cabeçalho e Rodapé

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} &lt;span class='titulo-tabela mrig10'>EXECUÇÕES&lt;/span> {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
currentPageReportTemplate="({startRecord} - {endRecord} de {totalRecords}, Página: {currentPage}/{totalPages})"
rowsPerPageTemplate="10,25,50,100"
var="execucao">

Cor em linhas

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'}" 

Alinhamento

O alinhamento nas colunas das tabelas deve seguir as seguintes especificações:

Tipo do AtributoAlinhamento
DescriçãoEsquerdo
Enum(Descrição)Esquerdo
InteiroDireita
Númerico DecimalDireita
DataCentralizado

Mensagens

Padrões

As mensagens do sistema devem ser claras, limpas e objetivas.

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.

Sumários

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”);

Inputs

AutoComplete

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.

Data (calendar)

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/>

<p:calendar onkeypress="mascara(this, Data)" 
maxlength="10"
style="text-align: right"
autocomplete="off"
title="Digite a data da caução."
value="#{contratoControlador.caucaoContratoSelecionada.dataCaucao}"
locale="pt_BR" navigator="true" pattern="dd/MM/yyyy"
size="10"/>

Dialogs

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:

 <p:dialog header="Itens vencidos por fornecedor" 
modal="true"
dynamic="true"
position="center"
style="position: fixed !important;"
resizable="false"
widgetVar="dialogItensDoFornecedor"
closable="false">

Importância do “Dynamic”

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”)

Loading LoadingX

URL’s

As urls devem ser pequenas e indicar exatamente sua funcionalidade.
Palavras compostas devem ser separadas por um hífen.
Ex:

webpublico/empenho/novo/ webpublico/cadastro-imobiliario/novo/ webpublico/dirf/acompanhamento/ webpublico/relatorio/ajuste-depositos/

Processamentos

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. Ex:

webpublico/dirf/acompanhamento/ webpublico/dirf/acompanhamento/ webpublico/sefip/acompanhamento/ webpublico/folha-de-pagamento/acompanhamento/

Novas Abas

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.
Ex:

NumAnoLic

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.

Converters

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.

Métodos

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

Boas práticas

Indentação do código (indentar)

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.

Changesets específicos

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.

SelectItem

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());

SingletonGeradorCodigo

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.
Ex:

elecionado.setNumero(singletonGeradorCodigo.getProximoCodigo(AprovacaoMaterial.class,"numero"));
selecionado.setNumero(singletonGeradorCodigo.getProximoCodigo(LoteEfetivacaoCessao.class,"numero"));
entity.setNumero(singletonGeradorCodigo.getProximoCodigo(entity.getClass(), "numero")); 

Indices

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.
Ex:

    <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>

Margens

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!

Ex:
margens

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 abaixo com os devidos espaçamentos: Espacamento

SuperEntidade (criadoEm)

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.

Ex:

      public class AprovacaoLevantamentoBem extends SuperEntidade {
}

Quebra de linhas (geração de arquivos txt)

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’.

Fluxo de Trabalho

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/producao).

Code Review

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.

Nomenclatura

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

Métodos

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.

Atributos

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:

Exemplo Incorreto: OnetoMany

Exemplo Correto: OnetoMany2

Atributos Date / Timestamp

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.

Logging

System.out.println()

Nunca deve ser utilizado o System.out.println para “Log”.

Logger

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:

logger

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:

logDebug

PrintStackTrace

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.

Tratamento de Exceptions

“Catch” de Throwable

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.

Banco de Dados

Parâmetros ao invés de concatenação

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. Edit

Controle de WHERE e AND

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.

Criação de Foreign Keys (FKs)

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.

Índices em FKs

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.

Controladores e Façades

Como as regras abaixo acarretam em modificações profundas, serão exigidas apenas em CÓDIGO NOVO.

Controladores devem conter apenas código de tela

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.

Não encadear chamadas de Facades

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.

Facades ou Services não podem depender de Controladores

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.

Boas práticas

Valores padrão

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.

Defesa de NullPointerException

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.

Valores comuns de Objetos Imutáveis

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.

Instanciar BigDecimal com String

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”).

Validação de Valores front-end

Campos Numéricos(não monetários)

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.

<p:inputText title="Digite o valor máximo da compra."           value="#{dispensaDeLicitacaoControlador.numeroDaDispensa}" 
onkeypress="somenteNumeros(event, this, true, true, true);"/>

Declaração do método:

function somenteNumeros(campo, permiteNegativo, permiteZero, permitePositivo)

Definição dos parâmetros acima:

ParâmetroPadrãoObrigatório?Função
EventEventSim
CampoInformarSim
Permite NegativoFalseNãoDefine se o campo será permitido informar um valor negativo, ex -10
Permite ZeroFalseNãoDefine se o valor final do campo poderá ser igual a 0 (Zero)
Permite PositivoTrueNãoDefine se no campo será permitido informar um valor positivo, ex 10

Campos/Mascara Monetária

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.

<p:inputText style="text-align: right" 
size="15"
id="valor-total-contrato"
readonly="true"
value="#{contratoControlador.selecionado.valorTotal}"
converter="#{contratoControlador.moneyConverter}"
title="Informe o valor do contrato."
onkeydown="mascaraMonetaria(this, false);">
</p:inputText>

Declaração do método:
function mascaraMonetaria(campo, permiteValorNegativo)

ParâmetroPadrãoObrigatório?Função
CampoInformarSim
Permite Valor NegativoTrueNãoDefine se no campo será permitido informar um valor monetário negativo, ex R$10,00

Observação Importante

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.

onkeydown="mascaraMonetaria(this);" 

O trecho descrito acima ainda funciona normalmente!

Problema em componente do textarea primefaces

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.

textarea

Validação de regras utilizando exceptions

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:

Deprecados

@Deprecated
public static Boolean validaCampos(Object selecionado) {

@Deprecated
public static void validarCamposObrigatorios(Object selecionado, ValidacaoException ex) {

Novo

public static void validarCampos(Object selecionado) throws ValidacaoException {

As chamadas dos métodos:

Não utilizar assim:

if (!Util.validaCampos(selecionado)){
return;
}

salvar();

Utilizar assim:

try {
Util.validarCampos(selecionado);
salvar();
} catch (ValidacaoException ve) {
FacesUtil.printAllFacesMessages(ve.getMensagens());

Observação Importante

Caso o objeto que deseja validar seja uma extensão de SuperEntidade pode se chamar a validação da seguinte forma:

try {
selecionado.realizarValidacoes();
salvar();
} catch (ValidacaoException ve) {
FacesUtil.printAllFacesMessages(ve.getMensagens());
}

Dentre as duas formas de realizar validações nos objetos, seja pelo próprio objeto através do método ‘realizarValidacoes’ ou do Util.validarCampos(objeto) fica a critério do desenvolvedor escolher a que mais lhe agrada, porém procure sempre utilizar exceptions e evite ao máximo utilizar métodos que retornem boolean.

Clonar Objetos

Util.clonarEmNiveis(Object objetoASerClonado, int nivel)

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

Clonar

O que será clonado?

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.

NivelClone

Alinhamento dos Branchs para Rio Branco

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:

  • Criar um branch a partir do branch producao com o nome NOME_DA_SPRINT/desenvolvimento
  • Baixar o branch master
  • copiar a pasta src para um local qualquer na maquina.
  • Criar um branch a partir do master com nome NOME_DA_SPRINT/alinhamento.
  • No branch de alinhamento, fazer pull do branch de desenvolvimento criado no passo 1.
  • Caso dê conflitos, resolva aceitando de qualquer branch.
  • Realizar um commit local.
  • Copiar e colar a pasta src do passo 3 substituindo a pasta src do branch de alinhamento.
  • Realizar o commit e push do branch de alinhamento.
  • Realizar o pull request para o master a partir do branch de alinhamento.