Código Limpo
     Capítulo 3 - Funções




 Bruno Blumenschein
 Hélios Kárum de Oliveira Bastos
 Rodrigo Oliveira Andrade
Regras
● Primeira Regra:
  ○ As funções devem ser pequenas;
● Segunda Regra:
  ○ "Elas precisam ser ainda menores";
● Não há como provar porque, foi baseado
  nas tentativas e erros do autor.
● Não ultrapassar mais do que 20 linhas, com
  150 carcteres por linha.
Exemplo
Exemplo - Continuação
Exemplo - Primeira Melhoria
Exemplo - Segunda Melhoria
Blocos e Identação
● Seguindo a linha de se minimizar funções,
  instruções como if, else e while devem
  possuir apenas uma linha de código.
● E provavelmente esta linha será uma
  chamada a uma função.
● Além de manter a função pequena agrega
  valor de documentação, já que o nome da
  função deve ser bem descritivo.
Blocos e Identação
● Essa estrutura também implica que as
  funções não devem ter muitas estruturas
  aninhadas.
● Para facilitar a estrutura e identação o
  nível máximo de estruturas aninhadas deve
  ser de uma ou duas.
Fazer apenas uma Coisa
● "Functions should do one thing. They should
  do it well. The should do it only."
● Funções devem fazer uma única coisa. Elas
  devem fazê-la bem. Elas devem fazer
  apenas ela.
● O problema é saber o que é "uma única
  coisa".
Fazer apenas uma Coisa
● O que faz o programa do exemplo anterior
   (RenderPageWithSetupsAndTeardowns):
  1. Determina se a página é de teste;
  2. Se for, inclui setUps e tearDowns;
  3. Renderiza a página em HTML.
● É apenas uma função ou são três?
● Note que as três operações realizadas estão
   a um nível abaixo do nome da função.
● Então ela está fazendo uma coisa só.
Fazer apenas uma Coisa
● O motivo de criarmos uma função é para
  decompor um conceito maior (em outras
  palavras o nome da função) em uma série
  de passos no próximo nível de abstração.
Seções em Funções
● Funções que fazem apenas apenas uma
  coisa não podem ser razoavelmente
  divididas em seções.
● Caso isto aconteça é um sintoma de estar
  fazendo mais de uma coisa.
Um Nível de Abstração por Função
● A fim de confirmar se uma função só faz
  uma coisa, precisamos verificar se todas as
  intruções dentro da função estão no mesmo
  nível de abstração.
● Vários níveis de abstração dentro de uma
  função sempre geram confusão.
● Os leitores podem não conseguir dizer se
  uma expressão determinada é um conceito
  essêncial ou um mero detalhe.
Ler o Código de Cima para Baixo
● O código deve ser lido de maneira top-
  down.
● Desejamos que cada função seja seguida
  pelas outras no próximo nível de abstração,
  de modo que possamos ler o programa um
  nível de cada vez.
● Chamamos isso de regra descendente.
Exemplo
● Para incluir setups e teardowns, nós incluimos
  primeiro os setups, depois nós incluimos o
  conteúdo da página de testes, e então incluimos
  os teardowns;
● Para incluir os setups, nós incluimos o suite
  setup se for uma suite, e então incluimos o setup
  regular;
● Para incluir o suite setup, nós procuramos na
  hierarquia pela página "SuiteSetUp", e então
  adicionamos uma instrução com o caminho para
  aquela página.
● Para procurar a hierarquia a cima...
Ler o Código de Cima para Baixo
● Acaba sendo difícil para o programador
  aplicar essa regra, mas quando ele passa a
  dominar esse truque, ele passa a ter o
  controle de verificação para saber se uma
  função só faz apenas uma coisa.
Switch
● É difícil criarmos um swtich pequeno.
● Mesmo o menor switch possível, com dois
  casos, já é maior do que eu gostaria de ter
  em um único bloco de código.
● É difícil criar um switch que faça apenas
  uma coisa.
● Pela sua natureza eles são criados para
  fazerem N coisas.
● Infelizemente nós não podemos evitar o uso
  de switchs.
Switch
● Mas nós podemos nos assegurar que cada
  instrução está um nível de abstração abaixo
  e que nunca se repetem.
● Switch geralmente tem vários problemas
  com o Principio do Aberto-Fechado. Já que
  para cada alteração, deve-se abrir a função
  e alterar o switch.
Use Nomes Descritivos
● Devemos criar nomes que descrevem bem o
  que as funções fazem.
● Princípo de Ward: "Você sabe que está criando
  um código limpo quando cada rotina que você
  lê é como você esperava."
● Metade do esforço para satisfazer essa máxima
  é escolher bons nomes para as funções que
  fazem apenas uma coisa.
● Quanto menor e mais centralizada for a função
  mais fácil será para se pensar em um nome
  descritivo.
Use Nomes Descritivos
● Nomes extensos são maiores do que nomes
  pequenos e enigmáticos.
● Um nome extenso e descritivo é melhor que
  um comentário extenso e descritivo.
● Use uma convenção de nomenaclatura que
  possibilite uma fácil leitura das funções
  com vários nomes.
● Não se preocupe com o tempo para criar
  um nome, e não tenho medo de modificá-lo
  caso tenha encontrado uma opção melhor.
Use Nomes Descritivos
● É comum que ao se buscar nomes
  adequados     resulte    em     uma      boa
  reestruturação do código.
● Seja consistente nos nomes, utilize sempre
  as mesmas frases, substantivos e verbos.
Parâmetros de Função
● O número ideal de argumentos para um
  método é zero.
● Depois, um argumento, mônade, e em
  seguida, dois argumentos, díade.
● Métodos com três argumentos, tríade, ou
  mais, devem ser evitados sempre que
  possível.    Necessitam     de    uma boa
  justificativa caso sejam utilizados.
Parâmetros de Função
● Parâmetros são complicados. Eles requerem
  bastante conceito. Nos exemplos eles foram
  até retirados.
● É    mais    fácil  enteder  o    método:
  includeSetupPage() do que o método:
  includeSetupPageInto(newPage-Content).
Parâmetros de Função
● Os     parâmetros     são    ainda     mais
  problemáticos do ponto de vista de testes.
● Imagine criar todos os cenários de testes
  posíveis para todas as combinações
  existentes entre os parâmetros.
● Se não houver nenhum parâmetro, esta é
  uma tarefa simples, se já existir um, não é
  tão difícil assim.
● Com dois a situação já passa a ser
  desafiadora.
Parâmetros da Função
● Os parâmetros de saída são ainda mais
  difíces de entender do que os de entrada.
● Geralmente não esperamos dados saídos por
  parâmetros.
● Um parâmetro de entrada é a melhor coisa
  depois do zero parâmetro.
●É facil entender:
  ○ SetupTeardown-Includer.render(pageData)
  ○ E fica bem claro que renderizemos os dados em
    pageData.
Formas Mônades Comuns
● Há duas razões comuns para se passar um
  único parâmetro para uma função:
  ○ Você pode estar fazendo uma pergunta sobre
    aquele parâmetro:
    ■ boolean fileExists(“MyFile”).
  ○ Você pode estar trabalhando aquele parâmetro,
    transformando-o em outra coisa e retornando-o
    ■ InputStream fileOpen(“MyFile”)
    ■ Transforma a String do nome de um arquivo em
       um valor retornado pela InputStream.
Formas Mônades Comuns
● Outra forma menos comum é para a
  utilização de eventos:
  ○ Há um parâmetro de entrada, mas não há um de
    saida.
  ○ O programa em si serve para interpretar a chamada
    da função como um evento, e usar o parâmetro
    para alterar o estado do sistema.
  ○ void passwordAttemptFailedNtimes(int attempts).
Formas Mônades Comuns
● Tente evitar funções que não sigam estas
  formas, como:
  ○ void includeSetupPageInto(StringBuffer pageText)
● Usar um parâmetro de saída em vez de um
  valor de retorno para uma modificação fica
  confuso.
● Se uma função vai transformar o seu
  parâmetro de entrada, a alteração deve
  aparecer como o valor retornado.
Parâmetros Lógicos
● "Parâmetros lógicos são feios".
● Utilizar um valor booleano como parâmetro
  em uma função é certamente uma prática
  horrível, pois ele complica imediatamente a
  assinatura     do     método,     mostrando
  explicitamente que o método faz mais de
  uma coisa.
Exemplo
● Um método: render(true) é difícil de ser
  interpretado por um leitor simples.
● Ele fica melhor: render(boolean isSuite),
  mas nem tanto.
● O melhor seria dividí-lo em:
  ○ renderForSuite() e
  ○ renderForSingleTest().
Funções Díades
● Uma função com dois parâmetros é mais fácil
  de enteder do que uma com apenas um. A
  função writeField(name) é mais fácil de
  compreender do que a writeField(output-
  Stream, name).
● Embora as duas estejam claras, a primeira
  apresenta seu propósito explicitamente quando
  lemos.
● Já a segunda requer uma pequena pausa até
  que aprendemos a ignorar o primeiro
  parâmetro.
Funções Díades
● E é ai que mora o problema, porque é nas
  partes do código que ignoramos que mora o
  problema.
● Díades não são ruins, e certamente terão de
  ser utilizá-dos. Entretanto deve-se estar
  ciente de que haverá um preço a pagar e,
  portanto, deve-se em tirar proveito dos
  mecanismos disponíveis a você para
  convertê-los em mônades.
Tríades
● Funções que recebem três parâmetros são
  consideravelmente     mais   difíceis  de
  entender do que as que utiliza ois
  parâmetros.
● A questão de ordenação, pausa, ignoração
  apresentam mais do que o dobro de
  dificuldade.
● Portanto as utilize somente quando houver
  extrema necessidade.
Tríades - Exemplo
● assertEquals(message, expected, actual).
● O parâmetro message precisa ser deduzido,
  e as vezes não é entendido pelo
  programados qual é a sua função.
Tríades - Exemplo 2
● Um método como:
  ○ Circle makeCircle(double x, double y, double radius)
● Ser transformado para:
  ○ Circle makeCircle(Point center, double radius);
● Pode parecer uma trapaça, mas x e y são
  partes de um conceito maior e merecer ter
  uma denominação diferenciada.
Nomenclatura
● Como dito anteriormente, é importante que
  as funções tenham nomes que expliquem
  diretamente o que elas fazem.
● Mas tão importante quanto isso, é que estes
  nomes também relacionem como o
  parâmetro vai interagir com a função.
Nomenclatura - Exemplos
● Em caso de de mônades a função e o
  parâmetro devem ser criados baseados em
  um bom par de verbo/substantivo.
  ○ write(name)
● O que quer que seja o parâmetro "name",
  sebemos que é ele que será "escrito"
  (write).
● Um nome melhor ainda seria:
  ○ writeField(name)
● Que nos dias ainda que o nome é um campo
  (field).
Evite Efeitos Colaterais
● "Efeitos colaterais são mentiras".
● Você promete fazer uma coisa com a sua
  função, mas ela faz outras coisas
  escondidas, isto é errado.
● Veremos no exemplo a seguir o que seria
  um exemplo de efeito colateral em um
  sistema que está fazendo login.
Evite Efeitos Colaterais - Exemplo
Evite Efeitos Colaterais
● O efeito colateral deste código está na
  linha:
  ○ Session.initialize();
● Pelo nome da função (checkPassword), ela
  verifica a senha, mas não é dito que ela
  inicia a sessão.
● Então alguém que acredita no que diz o
  nome da função, correrá o risco de apagar
  todos os dados da sessão existente caso ele
  deseje autenticar o usuário.
Evite Efeitos Colaterais
● Este efeito colateral cria um acoplamento
  temporário.
● Esta função só poderá ser chamada em
  casos específicos (quando for seguro
  inicializar a sessão).
● Se for chamada fora de ordem sem querer,
  os dados serão perdidos.
● Um nome melhor para o método poderia se:
  ○ checkPasswordAndInitializeSession
Parâmetros de Saída
● Parâmetros são comumente interpretados
  como entradas de uma função.
● Quando encontramos parâmetros de saída
  em alguma função, temos que gastar um
  tempo bem maior para ler e relê-la.
● Como por exemplo:
  ○ appendFooter(s);
● Esta função anexa s como um rodapé
  (footer) em algo? Ou anexa um rodapé a s?
● s é uma entrada ou uma saída?
Parâmetros de Saída
● Analisando a assinatura da função:
  ○ public void appendFooter(StringBuffer report);
● A questão é esclarecida, mas a custa da
  verificação da declaração da função.
● Isto é considerado uma relida, uma
  iterrupção de raciocínio e deve ser evitado.
● De modo geral deve-se evitar parâmetros
  de saída. Uma utilização melhor do método
  seria:
  ○ report.appendFooter();
Parâmetros de Saída
● Caso a função precise alterar o estado de
  algo, faça-a mudar o estado do objeto a
  que pertence.
Separação Comando-Consulta
● Funções devem fazer algo ou responder a
  algo. Mas nunca as duas coisas.
● Sua função ou altera o estado de um objeto
  ou retorna informações sobre ele.
● Efetuar as duas tarefas gera confusão.
Separação Comando-Consulta
Exemplo
● Analisando o método:
  ○ public boolean set(String attribute, String value);
● Esta função define o valor de um dado
  atributo e retorna verdadeiro se obtiver
  êxito e falso se tal atributo não existir.
● Isto leva a instruções estranhas que podem
  ser difíceis de serem interpretadas como:
  ○ if (set("username", "unclebob"))...
Separação Comando-Consulta
Exemplo
● Do ponto de vista de um leitor:
   ○ Está perguntando se o atributo "username"
     anteriormente recebeu o valor "unclebob"?
   ○ Ou se "username" obtêve êxito ao receber o valor
     "ubclebob"?
● Fica difícil adivinhar.
Prefira Exceções a Retorno de Código
de Erro
● Fazer funções retornarem códigos de erros
  é uma leve violação da separação comando-
  consulta.
● Estruturas deste tipo podem gerar trechos
  de códigos aninhados, fazendo com que o
  erro deve ser tratado imediatamente.
● Com a utilização de exções podemos tratar
  os erros em separado.
Exemplo Ruim
Exemplo Bom
Extraia os Blocos de Try/Catch
● Blocos de código de Try/Catch são
  particularmente "feios" a seu modo.
● Por isso, é melhor extrair os corpos de try e
  catch em funções fora da sua própria
  estrutura.
● Como no exemplo a seguir:
Extraia os Blocos de Try/Catch
Exemplo
Tratamento de Erro é uma Coisa Só
● Funções devem fazer apenas uma coisa.
● Tratamento de erro é uma coisa.
● Criar classes de erro em java, como a
  seguir, não é interessante.
Tratamento de Erro é uma Coisa Só
● Classes como estas são "chamarizes a
  dependência".
● Muitas outras classes devem importá-las e
  usá-las.
● O que coloca uma pressão na classe Error.
● Os programadores não querem colocar
  novos erros para não ter que recompilar.
● A melhor maneira de evitar isto é utilizando
  exceções.
Evite Reptição
● As vezes não é fácil identificar repetição de
  código,consequentemente arrumar erros em
  repetições são difíceis.
● Repetições causam trabalhos dobrados caso
  o código precisa ser modificados.
● Repetição de código é o mal de toda
  progamação.
Exemplo Reptição
Exemplo Repetição
Programação Estruturada
● Conceito de Edsger Dijkstra.
● Cada função deve ter apenas uma entrada e
  uma saída.
● Não há muita vantagem em seguir essa
  estrutura em funções pequenas.
● Se você conseguir manter funções
  pequenas, instruções como return, break e
  continue podem sem vantajosas.
● GoTo nunca deve ser utilizado.
Como escrever Funções como Esta?
● Não é um processo rápido, envolvem vários
  passos.
● Primeiro pense em como resolver o
  problema e faça da maneira que desejar.
● Só depois vá refinando as funções e
  aplicando as regras explicadas no capítulo
  para que fiquem melhores estruturadas.
● Não hesite em decompor toda uma classe se
  sentir necessário, valerá a pena no futuro.
Conclusão
● Funções são os verbos do sistema.
● As Funções são essenciais para o
  entendimento do sistema.
● As funções precisam ajudar o
  funcionamento do sistema.
● Funções precisam ser curtas, bem
  nomeadas, e bem organizadas.

Código limpo: Funções Capítulo 3

  • 1.
    Código Limpo Capítulo 3 - Funções Bruno Blumenschein Hélios Kárum de Oliveira Bastos Rodrigo Oliveira Andrade
  • 2.
    Regras ● Primeira Regra: ○ As funções devem ser pequenas; ● Segunda Regra: ○ "Elas precisam ser ainda menores"; ● Não há como provar porque, foi baseado nas tentativas e erros do autor. ● Não ultrapassar mais do que 20 linhas, com 150 carcteres por linha.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
    Blocos e Identação ●Seguindo a linha de se minimizar funções, instruções como if, else e while devem possuir apenas uma linha de código. ● E provavelmente esta linha será uma chamada a uma função. ● Além de manter a função pequena agrega valor de documentação, já que o nome da função deve ser bem descritivo.
  • 8.
    Blocos e Identação ●Essa estrutura também implica que as funções não devem ter muitas estruturas aninhadas. ● Para facilitar a estrutura e identação o nível máximo de estruturas aninhadas deve ser de uma ou duas.
  • 9.
    Fazer apenas umaCoisa ● "Functions should do one thing. They should do it well. The should do it only." ● Funções devem fazer uma única coisa. Elas devem fazê-la bem. Elas devem fazer apenas ela. ● O problema é saber o que é "uma única coisa".
  • 10.
    Fazer apenas umaCoisa ● O que faz o programa do exemplo anterior (RenderPageWithSetupsAndTeardowns): 1. Determina se a página é de teste; 2. Se for, inclui setUps e tearDowns; 3. Renderiza a página em HTML. ● É apenas uma função ou são três? ● Note que as três operações realizadas estão a um nível abaixo do nome da função. ● Então ela está fazendo uma coisa só.
  • 11.
    Fazer apenas umaCoisa ● O motivo de criarmos uma função é para decompor um conceito maior (em outras palavras o nome da função) em uma série de passos no próximo nível de abstração.
  • 12.
    Seções em Funções ●Funções que fazem apenas apenas uma coisa não podem ser razoavelmente divididas em seções. ● Caso isto aconteça é um sintoma de estar fazendo mais de uma coisa.
  • 13.
    Um Nível deAbstração por Função ● A fim de confirmar se uma função só faz uma coisa, precisamos verificar se todas as intruções dentro da função estão no mesmo nível de abstração. ● Vários níveis de abstração dentro de uma função sempre geram confusão. ● Os leitores podem não conseguir dizer se uma expressão determinada é um conceito essêncial ou um mero detalhe.
  • 14.
    Ler o Códigode Cima para Baixo ● O código deve ser lido de maneira top- down. ● Desejamos que cada função seja seguida pelas outras no próximo nível de abstração, de modo que possamos ler o programa um nível de cada vez. ● Chamamos isso de regra descendente.
  • 15.
    Exemplo ● Para incluirsetups e teardowns, nós incluimos primeiro os setups, depois nós incluimos o conteúdo da página de testes, e então incluimos os teardowns; ● Para incluir os setups, nós incluimos o suite setup se for uma suite, e então incluimos o setup regular; ● Para incluir o suite setup, nós procuramos na hierarquia pela página "SuiteSetUp", e então adicionamos uma instrução com o caminho para aquela página. ● Para procurar a hierarquia a cima...
  • 16.
    Ler o Códigode Cima para Baixo ● Acaba sendo difícil para o programador aplicar essa regra, mas quando ele passa a dominar esse truque, ele passa a ter o controle de verificação para saber se uma função só faz apenas uma coisa.
  • 17.
    Switch ● É difícilcriarmos um swtich pequeno. ● Mesmo o menor switch possível, com dois casos, já é maior do que eu gostaria de ter em um único bloco de código. ● É difícil criar um switch que faça apenas uma coisa. ● Pela sua natureza eles são criados para fazerem N coisas. ● Infelizemente nós não podemos evitar o uso de switchs.
  • 18.
    Switch ● Mas nóspodemos nos assegurar que cada instrução está um nível de abstração abaixo e que nunca se repetem. ● Switch geralmente tem vários problemas com o Principio do Aberto-Fechado. Já que para cada alteração, deve-se abrir a função e alterar o switch.
  • 19.
    Use Nomes Descritivos ●Devemos criar nomes que descrevem bem o que as funções fazem. ● Princípo de Ward: "Você sabe que está criando um código limpo quando cada rotina que você lê é como você esperava." ● Metade do esforço para satisfazer essa máxima é escolher bons nomes para as funções que fazem apenas uma coisa. ● Quanto menor e mais centralizada for a função mais fácil será para se pensar em um nome descritivo.
  • 20.
    Use Nomes Descritivos ●Nomes extensos são maiores do que nomes pequenos e enigmáticos. ● Um nome extenso e descritivo é melhor que um comentário extenso e descritivo. ● Use uma convenção de nomenaclatura que possibilite uma fácil leitura das funções com vários nomes. ● Não se preocupe com o tempo para criar um nome, e não tenho medo de modificá-lo caso tenha encontrado uma opção melhor.
  • 21.
    Use Nomes Descritivos ●É comum que ao se buscar nomes adequados resulte em uma boa reestruturação do código. ● Seja consistente nos nomes, utilize sempre as mesmas frases, substantivos e verbos.
  • 22.
    Parâmetros de Função ●O número ideal de argumentos para um método é zero. ● Depois, um argumento, mônade, e em seguida, dois argumentos, díade. ● Métodos com três argumentos, tríade, ou mais, devem ser evitados sempre que possível. Necessitam de uma boa justificativa caso sejam utilizados.
  • 23.
    Parâmetros de Função ●Parâmetros são complicados. Eles requerem bastante conceito. Nos exemplos eles foram até retirados. ● É mais fácil enteder o método: includeSetupPage() do que o método: includeSetupPageInto(newPage-Content).
  • 24.
    Parâmetros de Função ●Os parâmetros são ainda mais problemáticos do ponto de vista de testes. ● Imagine criar todos os cenários de testes posíveis para todas as combinações existentes entre os parâmetros. ● Se não houver nenhum parâmetro, esta é uma tarefa simples, se já existir um, não é tão difícil assim. ● Com dois a situação já passa a ser desafiadora.
  • 25.
    Parâmetros da Função ●Os parâmetros de saída são ainda mais difíces de entender do que os de entrada. ● Geralmente não esperamos dados saídos por parâmetros. ● Um parâmetro de entrada é a melhor coisa depois do zero parâmetro. ●É facil entender: ○ SetupTeardown-Includer.render(pageData) ○ E fica bem claro que renderizemos os dados em pageData.
  • 26.
    Formas Mônades Comuns ●Há duas razões comuns para se passar um único parâmetro para uma função: ○ Você pode estar fazendo uma pergunta sobre aquele parâmetro: ■ boolean fileExists(“MyFile”). ○ Você pode estar trabalhando aquele parâmetro, transformando-o em outra coisa e retornando-o ■ InputStream fileOpen(“MyFile”) ■ Transforma a String do nome de um arquivo em um valor retornado pela InputStream.
  • 27.
    Formas Mônades Comuns ●Outra forma menos comum é para a utilização de eventos: ○ Há um parâmetro de entrada, mas não há um de saida. ○ O programa em si serve para interpretar a chamada da função como um evento, e usar o parâmetro para alterar o estado do sistema. ○ void passwordAttemptFailedNtimes(int attempts).
  • 28.
    Formas Mônades Comuns ●Tente evitar funções que não sigam estas formas, como: ○ void includeSetupPageInto(StringBuffer pageText) ● Usar um parâmetro de saída em vez de um valor de retorno para uma modificação fica confuso. ● Se uma função vai transformar o seu parâmetro de entrada, a alteração deve aparecer como o valor retornado.
  • 29.
    Parâmetros Lógicos ● "Parâmetroslógicos são feios". ● Utilizar um valor booleano como parâmetro em uma função é certamente uma prática horrível, pois ele complica imediatamente a assinatura do método, mostrando explicitamente que o método faz mais de uma coisa.
  • 30.
    Exemplo ● Um método:render(true) é difícil de ser interpretado por um leitor simples. ● Ele fica melhor: render(boolean isSuite), mas nem tanto. ● O melhor seria dividí-lo em: ○ renderForSuite() e ○ renderForSingleTest().
  • 31.
    Funções Díades ● Umafunção com dois parâmetros é mais fácil de enteder do que uma com apenas um. A função writeField(name) é mais fácil de compreender do que a writeField(output- Stream, name). ● Embora as duas estejam claras, a primeira apresenta seu propósito explicitamente quando lemos. ● Já a segunda requer uma pequena pausa até que aprendemos a ignorar o primeiro parâmetro.
  • 32.
    Funções Díades ● Eé ai que mora o problema, porque é nas partes do código que ignoramos que mora o problema. ● Díades não são ruins, e certamente terão de ser utilizá-dos. Entretanto deve-se estar ciente de que haverá um preço a pagar e, portanto, deve-se em tirar proveito dos mecanismos disponíveis a você para convertê-los em mônades.
  • 33.
    Tríades ● Funções querecebem três parâmetros são consideravelmente mais difíceis de entender do que as que utiliza ois parâmetros. ● A questão de ordenação, pausa, ignoração apresentam mais do que o dobro de dificuldade. ● Portanto as utilize somente quando houver extrema necessidade.
  • 34.
    Tríades - Exemplo ●assertEquals(message, expected, actual). ● O parâmetro message precisa ser deduzido, e as vezes não é entendido pelo programados qual é a sua função.
  • 35.
    Tríades - Exemplo2 ● Um método como: ○ Circle makeCircle(double x, double y, double radius) ● Ser transformado para: ○ Circle makeCircle(Point center, double radius); ● Pode parecer uma trapaça, mas x e y são partes de um conceito maior e merecer ter uma denominação diferenciada.
  • 36.
    Nomenclatura ● Como ditoanteriormente, é importante que as funções tenham nomes que expliquem diretamente o que elas fazem. ● Mas tão importante quanto isso, é que estes nomes também relacionem como o parâmetro vai interagir com a função.
  • 37.
    Nomenclatura - Exemplos ●Em caso de de mônades a função e o parâmetro devem ser criados baseados em um bom par de verbo/substantivo. ○ write(name) ● O que quer que seja o parâmetro "name", sebemos que é ele que será "escrito" (write). ● Um nome melhor ainda seria: ○ writeField(name) ● Que nos dias ainda que o nome é um campo (field).
  • 38.
    Evite Efeitos Colaterais ●"Efeitos colaterais são mentiras". ● Você promete fazer uma coisa com a sua função, mas ela faz outras coisas escondidas, isto é errado. ● Veremos no exemplo a seguir o que seria um exemplo de efeito colateral em um sistema que está fazendo login.
  • 39.
  • 40.
    Evite Efeitos Colaterais ●O efeito colateral deste código está na linha: ○ Session.initialize(); ● Pelo nome da função (checkPassword), ela verifica a senha, mas não é dito que ela inicia a sessão. ● Então alguém que acredita no que diz o nome da função, correrá o risco de apagar todos os dados da sessão existente caso ele deseje autenticar o usuário.
  • 41.
    Evite Efeitos Colaterais ●Este efeito colateral cria um acoplamento temporário. ● Esta função só poderá ser chamada em casos específicos (quando for seguro inicializar a sessão). ● Se for chamada fora de ordem sem querer, os dados serão perdidos. ● Um nome melhor para o método poderia se: ○ checkPasswordAndInitializeSession
  • 42.
    Parâmetros de Saída ●Parâmetros são comumente interpretados como entradas de uma função. ● Quando encontramos parâmetros de saída em alguma função, temos que gastar um tempo bem maior para ler e relê-la. ● Como por exemplo: ○ appendFooter(s); ● Esta função anexa s como um rodapé (footer) em algo? Ou anexa um rodapé a s? ● s é uma entrada ou uma saída?
  • 43.
    Parâmetros de Saída ●Analisando a assinatura da função: ○ public void appendFooter(StringBuffer report); ● A questão é esclarecida, mas a custa da verificação da declaração da função. ● Isto é considerado uma relida, uma iterrupção de raciocínio e deve ser evitado. ● De modo geral deve-se evitar parâmetros de saída. Uma utilização melhor do método seria: ○ report.appendFooter();
  • 44.
    Parâmetros de Saída ●Caso a função precise alterar o estado de algo, faça-a mudar o estado do objeto a que pertence.
  • 45.
    Separação Comando-Consulta ● Funçõesdevem fazer algo ou responder a algo. Mas nunca as duas coisas. ● Sua função ou altera o estado de um objeto ou retorna informações sobre ele. ● Efetuar as duas tarefas gera confusão.
  • 46.
    Separação Comando-Consulta Exemplo ● Analisandoo método: ○ public boolean set(String attribute, String value); ● Esta função define o valor de um dado atributo e retorna verdadeiro se obtiver êxito e falso se tal atributo não existir. ● Isto leva a instruções estranhas que podem ser difíceis de serem interpretadas como: ○ if (set("username", "unclebob"))...
  • 47.
    Separação Comando-Consulta Exemplo ● Doponto de vista de um leitor: ○ Está perguntando se o atributo "username" anteriormente recebeu o valor "unclebob"? ○ Ou se "username" obtêve êxito ao receber o valor "ubclebob"? ● Fica difícil adivinhar.
  • 48.
    Prefira Exceções aRetorno de Código de Erro ● Fazer funções retornarem códigos de erros é uma leve violação da separação comando- consulta. ● Estruturas deste tipo podem gerar trechos de códigos aninhados, fazendo com que o erro deve ser tratado imediatamente. ● Com a utilização de exções podemos tratar os erros em separado.
  • 49.
  • 50.
  • 51.
    Extraia os Blocosde Try/Catch ● Blocos de código de Try/Catch são particularmente "feios" a seu modo. ● Por isso, é melhor extrair os corpos de try e catch em funções fora da sua própria estrutura. ● Como no exemplo a seguir:
  • 52.
    Extraia os Blocosde Try/Catch Exemplo
  • 53.
    Tratamento de Erroé uma Coisa Só ● Funções devem fazer apenas uma coisa. ● Tratamento de erro é uma coisa. ● Criar classes de erro em java, como a seguir, não é interessante.
  • 54.
    Tratamento de Erroé uma Coisa Só ● Classes como estas são "chamarizes a dependência". ● Muitas outras classes devem importá-las e usá-las. ● O que coloca uma pressão na classe Error. ● Os programadores não querem colocar novos erros para não ter que recompilar. ● A melhor maneira de evitar isto é utilizando exceções.
  • 55.
    Evite Reptição ● Asvezes não é fácil identificar repetição de código,consequentemente arrumar erros em repetições são difíceis. ● Repetições causam trabalhos dobrados caso o código precisa ser modificados. ● Repetição de código é o mal de toda progamação.
  • 56.
  • 57.
  • 58.
    Programação Estruturada ● Conceitode Edsger Dijkstra. ● Cada função deve ter apenas uma entrada e uma saída. ● Não há muita vantagem em seguir essa estrutura em funções pequenas. ● Se você conseguir manter funções pequenas, instruções como return, break e continue podem sem vantajosas. ● GoTo nunca deve ser utilizado.
  • 59.
    Como escrever Funçõescomo Esta? ● Não é um processo rápido, envolvem vários passos. ● Primeiro pense em como resolver o problema e faça da maneira que desejar. ● Só depois vá refinando as funções e aplicando as regras explicadas no capítulo para que fiquem melhores estruturadas. ● Não hesite em decompor toda uma classe se sentir necessário, valerá a pena no futuro.
  • 60.
    Conclusão ● Funções sãoos verbos do sistema. ● As Funções são essenciais para o entendimento do sistema. ● As funções precisam ajudar o funcionamento do sistema. ● Funções precisam ser curtas, bem nomeadas, e bem organizadas.