[ad_1]

Como desenvolvedores, queremos escrever um código que funcione, seja legível, eficiente, conciso e, se possível, reutilizável.

Quando muitos de nós pensam em código limpo, provavelmente caímos na armadilha de pensar que menos código é um código melhor. Embora esse seja frequentemente o caso, nem sempre é assim.

Se eu puder fazer o trabalho de uma maneira que outros desenvolvedores possam seguir atrás de mim e entender imediatamente (ou pelo menos facilmente) o que eu fiz, é isso que eu farei.

Então, o que é código limpo?

Hoje em dia, é muito mais importante que você e eu possamos ler o código com eficiência do que o dispositivo (em na maioria dos casos).

Quando escrevo código, meu primeiro objetivo é sempre fazer o trabalho. Depois disso, escrevo código para legibilidade humana, complexidade de tempo de execução e concisão. Finalmente, se eu puder, tornarei o código facilmente reutilizável.

Se eu precisar escrever um código de maneira que não seja mais facilmente legível por humanos, a fim de satisfazer um requisito de complexidade / tempo ou reutilização, você pode ter certeza de que ele será muito bem documentado.

Um exemplo do que eu considero código limpo

Recentemente, recebi o desafio de encontrar um único número ímpar em uma matriz de números pares ou vice-versa. Recebi uma matriz de números inteiros como entrada e não sabia se continha ou não números pares ou ímpares. Definitivamente, haveria no mínimo 3 valores na matriz e apenas um deles seria ímpar / par.

Esta foi a minha solução:

func findOutlier(_ array: [Int]) -> Int {  //since we're guaranteed to have 3 values, grab the first 3  let parityArr = [      array[0],      array[1],      array[2]  ]  //track any odd or even numbers found in parityArr || O(1) - (technically O(n) but we know the input won't grow)  var odd = 0  var even = 0  for num in parityArr {     //number is even     if num % 2 == 0 {         even += 1     //number is odd     } else {         odd += 1     }   }  //track and test whether there were more odd or even numbers in the array  var isEven = false  if even > odd {      isEven = true  }    //return the first match that's an outlier based on the array containing more even or more odd numbers || O(n) - we don't know the input size   if isEven {      return array.first(where: ({ $0 % 2 != 0 }))!  } else {      return array.first(where: ({ $0 % 2 == 0 }))!  }}

Se você perceber, deixei notas que incluíam a complexidade do tempo de execução ou a eficiência com que um algoritmo é escalado – mesmo que isso seja provavelmente bastante óbvio se você se importa com esse tipo de coisa. Também deixei notas sobre qual era o tamanho da entrada de uma determinada operação (embora, novamente, seja bastante óbvio).

Quando ser conciso e quando “escrever”

Há casos em que o código conciso pode reduzir o tempo de compilação, a execução do tempo de execução ou várias outras coisas. Mais uma vez, porém, minha principal preocupação é se o próximo desenvolvedor pode ou não lê-lo, acompanhá-lo com facilidade e trabalhar com ele.

Como o fato de ser conciso demais afetar a legibilidade?

No meu retorno, por exemplo, eu poderia ter feito essa linha return array.first(where: ({ $0 % 2 != 0 }))! em um loop for onde retornei a primeira partida. Mas estaria fazendo exatamente a mesma coisa e, devido à maneira como isso é chamado, acho que é igualmente legível.

Mas talvez você não entenda a sintaxe de fechamento ou seu colega de trabalho não. Tudo bem – soletrar. Eu escolhi não, porque isso parece tão legível para mim, mas é mais conciso.

return array.first(where: { ... “gravado” é:

for num in array {    if num %2 !=0 {        return num    }}

Existem algumas oportunidades para tornar o código neste exemplo mais conciso e ainda permanecer legível para a maioria dos desenvolvedores.

Como tal, eu também poderia ter feito este bloco:

var isEven = falseif even > odd {    isEven = true}

Parece mais com isso:

var isEven = even > odd

O bloco de retorno mencionado acima pode ser transformado em uma verificação de uma linha usando o operador ternário, mas parece haver um número crescente de desenvolvedores que não estão familiarizados com o operador ternário. Eu acho que um bloco if / else também é mais legível na maioria dos casos:

if isEven {    return array.first(where: ({ $0 % 2 != 0 }))!} else {    return array.first(where: ({ $0 % 2 == 0 }))!}

return isEven ? array.first(where: {$0 %2 != 0}) : array.first(where: {$0 %2 == 0})

Pessoalmente, acho que as duas frases concisas de uma linha são um pouco menos fáceis de ler – especialmente quando o operador ternário está envolvido.

De qualquer forma, fiquei bastante satisfeito com minha solução – ela passou em todos os testes de unidade, foi bastante eficiente e foi legível por humanos. Mas quando vi as soluções de outras pessoas, no começo fiquei com um pouco de vergonha da minha rudimentar…

Muitos deles estavam usando filtro, muitos estavam usando o operador ternário. A maioria deles era muito mais concisa.

Um exemplo de ser muito conciso

A resposta mais bem classificada foi duas linhas de código que eu tive dificuldade de ler no começo – mas esse código definitivamente fará o trabalho. Pode ser mais eficiente do que minha solução em alguns casos, e é obviamente muito conciso:

func findOutlier(_ array: [Int]) -> Int {    let odd = array.filter{$0 % 2 != 0}    return odd.count > 1 ? array.filter{$0 % 2 == 0}[0] : odd[0]}

Ambos os exemplos atendem aos primeiros critérios para escrever código limpo (ou realmente qualquer) – eles funcionam. Os dois também são concisos, embora minha solução possa ser mais concisa. À primeira vista, achei a solução mais concisa ótima. É elegante, é eficiente e é … conciso.

Então comecei a dividir o retorno em um if / else e percebi que minha solução é provavelmente mais eficiente na maioria das vezes. Eu só estou repetindo toda a matriz uma vez e apenas se a paridade externa for o número final da matriz.

Ainda é uma boa solução, mas eu não diria que é ótimo (ou tantos no site mencionados – uma prática recomendada).

No caso de uma matriz par majoritária na solução concisa, ela seria filtrada duas vezes. Uma vez para criar a matriz chamada ímpar (que também pode ser nomeada como melhor) – é a matriz inteira que está sendo iterada. Então, novamente, se não for uma matriz ímpar majoritária.

Isso não é grande coisa se houver apenas 3 números. Mas, considerando uma matriz de 10.000 números, você está observando um pouco do tempo em que seu usuário fica aguardando algo computar que não precisa ser calculado.

Outra coisa a ser observada sobre a minha solução versus a solução concisa é que minha resposta é retornada assim que encontrada na matriz.

Digamos que a matriz de entrada seja ímpar e o número par seja o primeiro número na matriz. Na minha solução, isso seria calculado e retornado quase imediatamente, enquanto na solução concisa, estaríamos aguardando a filtração de toda a matriz antes de retornar a resposta.

Uma nota sobre reutilização

Eu toquei na reutilização desde o início, mas não conversamos muito sobre isso. Código reutilizável significa que você pode usá-lo em mais de uma situação.

Essa é uma das principais preocupações de escrever código limpo, mas somente quando aplicável. Podemos fazer isso usando parâmetros em funções que são flexíveis para diferentes casos de uso e outras coisas que podem ser usadas para usar nosso código em outro lugar sem nenhuma ou muita modificação.

Mas como escrever código reutilizável pode afetar a legibilidade?
Eu poderia ter tornado toda essa função genérica. Ainda atenderia aos critérios e o tornaria mais reutilizável. Poderíamos verificar qualquer tipo numérico, por exemplo, mas isso não estava no escopo deste projeto, e isso tornaria menos legível se você não estiver familiarizado com a sintaxe genérica.

Mantê-lo limpo evita armadilhas

Uma das armadilhas da escrita de código que é um pouco concisa é que é difícil dar conta de casos extremos. Isso ocorre porque torna mais difícil ver as “peças em movimento” de relance.

Definitivamente, não estou dizendo que minha solução é perfeita. Já vejo uma maneira de torná-lo mais eficiente (em alguns casos, podemos pular a operação O (n) final) e ainda assim permanecer legíveis.

Mas o ponto é que posso voltar a esse código a qualquer momento em um futuro próximo ou distante, ver facilmente como está funcionando e como posso torná-lo melhor.

Lembre-se de que há muita coisa para escrever código limpo. Limpo não somente significa conciso! Escreva seu código para que outros desenvolvedores possam trabalhar com ele – todos os humanos que trabalham nele agradecerão.

Às vezes, ser um bom desenvolvedor significa tornar menos mágica

Com que frequência você desenvolveu uma operação um tanto complexa envolvendo diferentes partes móveis? Você empacota tudo de forma organizada, teste de bugs, está tudo funcionando … Então você percebe depois da sua próxima …

1*oW8MYZszJuEw ObwrjWtpA

[ad_2]

Fonte