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á co...
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 ...
Blocos e Identação● Essa estrutura também implica que as  funções não devem ter muitas estruturas  aninhadas.● Para facili...
Fazer apenas uma Coisa● "Functions should do one thing. They should  do it well. The should do it only."● Funções devem fa...
Fazer apenas uma Coisa● O que faz o programa do exemplo anterior   (RenderPageWithSetupsAndTeardowns):  1. Determina se a ...
Fazer apenas uma Coisa● O motivo de criarmos uma função é para  decompor um conceito maior (em outras  palavras o nome da ...
Seções em Funções● Funções que fazem apenas apenas uma  coisa não podem ser razoavelmente  divididas em seções.● Caso isto...
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  in...
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  pe...
Exemplo● Para incluir setups e teardowns, nós incluimos  primeiro os setups, depois nós incluimos o  conteúdo da página de...
Ler o Código de Cima para Baixo● Acaba sendo difícil para o programador  aplicar essa regra, mas quando ele passa a  domin...
Switch● É difícil criarmos um swtich pequeno.● Mesmo o menor switch possível, com dois  casos, já é maior do que eu gostar...
Switch● Mas nós podemos nos assegurar que cada  instrução está um nível de abstração abaixo  e que nunca se repetem.● Swit...
Use Nomes Descritivos● Devemos criar nomes que descrevem bem o  que as funções fazem.● Princípo de Ward: "Você sabe que es...
Use Nomes Descritivos● Nomes extensos são maiores do que nomes  pequenos e enigmáticos.● Um nome extenso e descritivo é me...
Use Nomes Descritivos● É comum que ao se buscar nomes  adequados     resulte    em     uma      boa  reestruturação do cód...
Parâmetros de Função● O número ideal de argumentos para um  método é zero.● Depois, um argumento, mônade, e em  seguida, d...
Parâmetros de Função● Parâmetros são complicados. Eles requerem  bastante conceito. Nos exemplos eles foram  até retirados...
Parâmetros de Função● Os     parâmetros     são    ainda     mais  problemáticos do ponto de vista de testes.● Imagine cri...
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 esp...
Formas Mônades Comuns● Há duas razões comuns para se passar um  único parâmetro para uma função:  ○ Você pode estar fazend...
Formas Mônades Comuns● Outra forma menos comum é para a  utilização de eventos:  ○ Há um parâmetro de entrada, mas não há ...
Formas Mônades Comuns● Tente evitar funções que não sigam estas  formas, como:  ○ void includeSetupPageInto(StringBuffer p...
Parâmetros Lógicos● "Parâmetros lógicos são feios".● Utilizar um valor booleano como parâmetro  em uma função é certamente...
Exemplo● Um método: render(true) é difícil de ser  interpretado por um leitor simples.● Ele fica melhor: render(boolean is...
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(nam...
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...
Tríades● Funções que recebem três parâmetros são  consideravelmente     mais   difíceis  de  entender do que as que utiliz...
Tríades - Exemplo● assertEquals(message, expected, actual).● O parâmetro message precisa ser deduzido,  e as vezes não é e...
Tríades - Exemplo 2● Um método como:  ○ Circle makeCircle(double x, double y, double radius)● Ser transformado para:  ○ Ci...
Nomenclatura● Como dito anteriormente, é importante que  as funções tenham nomes que expliquem  diretamente o que elas faz...
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/...
Evite Efeitos Colaterais● "Efeitos colaterais são mentiras".● Você promete fazer uma coisa com a sua  função, mas ela faz ...
Evite Efeitos Colaterais - Exemplo
Evite Efeitos Colaterais● O efeito colateral deste código está na  linha:  ○ Session.initialize();● Pelo nome da função (c...
Evite Efeitos Colaterais● Este efeito colateral cria um acoplamento  temporário.● Esta função só poderá ser chamada em  ca...
Parâmetros de Saída● Parâmetros são comumente interpretados  como entradas de uma função.● Quando encontramos parâmetros d...
Parâmetros de Saída● Analisando a assinatura da função:  ○ public void appendFooter(StringBuffer report);● A questão é esc...
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...
Separação Comando-ConsultaExemplo● Analisando o método:  ○ public boolean set(String attribute, String value);● Esta funçã...
Separação Comando-ConsultaExemplo● Do ponto de vista de um leitor:   ○ Está perguntando se o atributo "username"     anter...
Prefira Exceções a Retorno de Códigode Erro● Fazer funções retornarem códigos de erros  é uma leve violação da separação c...
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...
Extraia os Blocos de Try/CatchExemplo
Tratamento de Erro é uma Coisa Só● Funções devem fazer apenas uma coisa.● Tratamento de erro é uma coisa.● Criar classes d...
Tratamento de Erro é uma Coisa Só● Classes como estas são "chamarizes a  dependência".● Muitas outras classes devem import...
Evite Reptição● As vezes não é fácil identificar repetição de  código,consequentemente arrumar erros em  repetições são di...
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...
Como escrever Funções como Esta?● Não é um processo rápido, envolvem vários  passos.● Primeiro pense em como resolver o  p...
Conclusão● Funções são os verbos do sistema.● As Funções são essenciais para o  entendimento do sistema.● As funções preci...
Próximos SlideShares
Carregando em…5
×

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

1.111 visualizações

Publicada em

0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
1.111
No SlideShare
0
A partir de incorporações
0
Número de incorporações
1
Ações
Compartilhamentos
0
Downloads
13
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

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

  1. 1. Código Limpo Capítulo 3 - Funções Bruno Blumenschein Hélios Kárum de Oliveira Bastos Rodrigo Oliveira Andrade
  2. 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. 3. Exemplo
  4. 4. Exemplo - Continuação
  5. 5. Exemplo - Primeira Melhoria
  6. 6. Exemplo - Segunda Melhoria
  7. 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. 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. 9. 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".
  10. 10. 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ó.
  11. 11. 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.
  12. 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. 13. 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.
  14. 14. 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.
  15. 15. 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...
  16. 16. 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.
  17. 17. 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.
  18. 18. 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.
  19. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 29. 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.
  30. 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. 31. 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.
  32. 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. 33. 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.
  34. 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. 35. 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.
  36. 36. 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.
  37. 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. 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. 39. Evite Efeitos Colaterais - Exemplo
  40. 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. 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. 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. 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. 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. 45. 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.
  46. 46. Separação Comando-ConsultaExemplo● 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"))...
  47. 47. Separação Comando-ConsultaExemplo● 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.
  48. 48. Prefira Exceções a Retorno de Códigode 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. 49. Exemplo Ruim
  50. 50. Exemplo Bom
  51. 51. 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:
  52. 52. Extraia os Blocos de Try/CatchExemplo
  53. 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. 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. 55. 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.
  56. 56. Exemplo Reptição
  57. 57. Exemplo Repetição
  58. 58. 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.
  59. 59. 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.
  60. 60. 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.

×