Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Como diminuir a complexidade ciclomática do código

Como eu diminuo a complexidade ciclomática deste código por exemplo: a finalidade dele é habilitar um botão validar (exibí-lo ou não).

  public boolean habilitaBotaoValidar() {
    if (listaPostoDeTrabalhoSelecionado != null) {
      for (PostoDeTrabalho posto : listaPostoDeTrabalhoSelecionado) {
        if (posto != null && posto.getListaPessoaDTO() != null) {
          for (PessoaDTO pessoaDTO : posto.getListaPessoaDTO()) {
            if (pessoaDTO != null && pessoaDTO.getListaRetencao() != null) {
              for (Retencao re : pessoaDTO.getListaRetencao()) {
                if (re != null && re.getDataValidouRetencao() == null
                    && re.getDataAprovouRetencao() == null) {
                  return true;
                }
              }
            }
          }
        }
      }
    }
    return false;
  }
                                <p:column headerText="Ação" style="text-align: center;">
                                    <p:commandButton actionListener="#{validarRetencaoAction.selecionar(pessoaDTO, retencao)}" icon="ui-icon-refresh" update="@all" process="@all" 
                                                title="Recalcular" disabled="#{validarRetencaoAction.habilitaBotaoValidar() eq false or retencao.dataValidouRetencao ne null}" />
                                </p:column>

O valor da complexidade está em 15.

Em outra parte do código, tbm estou com o mesmo problema:

            <p:commandButton action="#{validarRetencaoAction.validar()}" icon="ui-icon-check" value="Validar" update="@all" style="float: left;" disabled="#{validarRetencaoAction.habilitaBotaoValidar() eq false}">
                <p:confirm header="Confirmação" message="Validar esta retenção?" icon="ui-icon-alert" style="position: absolute; top: 50px !important"/>
            </p:commandButton>
  public void validar() throws Exception {
    Usuario usuarioLogado = new Usuario(usuarioSessao.getLogin());
    Date dataAtual = new Date();

    if (listaPostoDeTrabalhoSelecionado != null) {
      for (PostoDeTrabalho posto : listaPostoDeTrabalhoSelecionado) {
        if (posto != null && posto.getListaPessoaDTO() != null) {
          for (PessoaDTO pessoaDTO : posto.getListaPessoaDTO()) {
            if (pessoaDTO != null && pessoaDTO.getListaRetencao() != null) {
              for (Retencao re : pessoaDTO.getListaRetencao()) {
                if (re != null && re.getDataValidouRetencao() == null
                    && re.getDataAprovouRetencao() == null) {
                  re.setDataValidouRetencao(dataAtual);
                  re.setUsuarioValidouRetencao(usuarioLogado);
                  retencaoDAO.merge(re);
                }
              }
            }
          }
        }
      }
      ...
    }
  }

Se alguém puder dar sugestão de como melhorar, obrigado!

3 respostas
solução!

Olá, Fernando

Entendo que você está procurando maneiras de reduzir a complexidade ciclomática do seu código. Isso é uma ótima prática para tornar seu código mais legível e fácil de manter.

A complexidade ciclomática é uma métrica de software que indica a complexidade de um programa. Ela é calculada usando o número de caminhos independentes através do código-fonte de um programa. Então, uma maneira de reduzi-la é diminuir o número de caminhos independentes no seu código.

Analisando o seu código, percebo que você tem muitos aninhamentos e verificações de nulidade. Uma maneira de reduzir a complexidade seria refatorar seu código para remover esses aninhamentos e verificações.

Por exemplo, você poderia criar uma função separada para lidar com a lógica dentro do loop for. Além disso, você poderia usar o Optional do Java 8 para lidar com a possibilidade de nulidade, o que reduziria a necessidade de verificações explícitas de nulo.

Aqui está um exemplo de como você poderia refatorar o método habilitaBotaoValidar():

public boolean habilitaBotaoValidar() {
    return Optional.ofNullable(listaPostoDeTrabalhoSelecionado)
            .map(this::validaPostosDeTrabalho)
            .orElse(false);
}

private boolean validaPostosDeTrabalho(List<PostoDeTrabalho> postos) {
    return postos.stream()
            .filter(Objects::nonNull)
            .map(PostoDeTrabalho::getListaPessoaDTO)
            .filter(Objects::nonNull)
            .anyMatch(this::validaPessoas);
}

private boolean validaPessoas(List<PessoaDTO> pessoas) {
    return pessoas.stream()
            .filter(Objects::nonNull)
            .map(PessoaDTO::getListaRetencao)
            .filter(Objects::nonNull)
            .anyMatch(this::validaRetencoes);
}

private boolean validaRetencoes(List<Retencao> retencoes) {
    return retencoes.stream()
            .filter(Objects::nonNull)
            .anyMatch(re -> re.getDataValidouRetencao() == null && re.getDataAprovouRetencao() == null);
}

Essa refatoração remove a necessidade de aninhamentos e verificações de nulidade, o que deve reduzir a complexidade ciclomática do seu código.

Espero ter ajudado e bons estudos!

E ai Otávio, obrigado por ter respondido.

Achei a sua solução muito boa, melhorou bastante a legibilidade do código, mais clean e não tinha pensando dessa forma.

Coloquei a sua sugestão pra funcionar e reduziu a zero rsrs não apareceu nenhuma complexidade ciclomática nesse trecho.

Valeu, obrigado!!!

Fico feliz em saber que a solução funcionou para você e ajudou a reduzir a complexidade ciclomática do seu código Fernando :) A refatoração do código para torná-lo mais legível e menos complexo é uma prática importante para facilitar a manutenção e o entendimento do código no futuro.

Abraço