Soletrar as coisas pode ajudar não apenas na legibilidade, mas também na capacidade de escrita.
Isso pode parecer uma pergunta boba da entrevista, mas me pediram uma vez em uma entrevista para escrever uma função para girar uma imagem em 90 graus. A origem e o destino são fornecidos (você não precisa fazer nenhuma alocação de memória) e a largura e a altura da fonte. Sim, é um problema fácil. Eu sugiro que você faça isso antes de continuar e veja se você tem algum problema.
.
Você fez? Você testou isso? Desde que me perguntaram em uma entrevista eu usei a pergunta em entrevistas também e o que eu encontrei foi que muitos programadores se confundiam. Eles escreveriam código como este
void Rotate90(const Pixel* src, Pixel* dst, int width, int height)
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
dst[???] = src[???];
E é aí que eles ficariam presos. Eles gastariam às vezes até 20 minutos no quadro branco tentando descobrir o que acontece neles ??? área. Muitas vezes eles acham que têm a resposta e escrevem coisas como
dst[x * width + (height - 1 - y)] = src[y * width + x];
recebendo o fato de que usar width
com dst
está errado. Ou, muitas vezes, eles teriam o x
e o y
misturados em um lado ou outro.
O problema é que x
, y
, width
e height
trocam de significado porque, ao girar 90 graus, o destino fica com largura e altura altas, o que torna a referência a essas variáveis confusas. Eu sempre desejei que um programador adicionasse mais algumas variáveis para ajudar a torná-lo mais claro, como este
void Rotate90(const Pixel* src, Pixel* dst, int src_width, int src_height)
{
int dst_width = src_height;
int dst_height = src_width;
for (int src_y = 0; src_y < src_height; ++src_y)
{
for (int src_x = 0; src_y < src_width; ++src_x)
{
int dst_x = src_height - src_y - 1;
int dst_y = src_x;
dst[dst_y * dst_width + dst_x] = src[src_y * src_width + src_x];
}
}
}
Pareceu-me quebrar as coisas em seus significados explícitos que tornaria muito mais fácil escrever o código e muito mais fácil evitar erros. Eu senti que se eu visse um programador fazendo isso eu pensaria neles como sábio e os classificaria mais alto.
Sim, existem algumas otimizações que você pode fazer. Essa não é a questão. Sim, a matemática dentro da última declaração também pode ser dividida em linhas separadas. Isso também seria bom. O ponto é que adicionar mais linhas facilitou a compreensão para a pessoa que está escrevendo o código, e não apenas para uma pessoa que o leu mais tarde. Nesse caso, porque o significado de x
, y
, width
e height
é diferente em relação a dst
vs src
, fazer variáveis separadas para cada torna o código muito mais claro para ler AND escreva .
Continuando ... Da mesma forma, é útil poder inspecionar os valores antes que uma função seja chamada, especialmente se for uma função de uma biblioteca ou o sistema no qual você não pode entrar. Se você escrever um código como este
ctx.lineTo(x + Math.cos(angle) * radius, y + Math.sin(angle) * radius);
vs isso
var circleX = x + Math.cos(angle) * radius;
var circleY = y + Math.sin(angle) * radius;
ctx.lineTo(circleX, circleY);
No segundo estilo, você pode parar o depurador na linha ctx.lineTo
e inspecionar circleX
e circleY
. Você pode achar que eles são NaN
, o que provavelmente faria você verificar se x
, angle
e radius
são realmente os nomes corretos, algo que você não seria capaz de fazer no depurador. (modo "estrito" provavelmente pega isso). Também permite que você registre facilmente os valores
console.log("cx: " + circleX = ", cy: " + circleY);
Ainda outro exemplo,
class Person
{
public:
...
const String& name() const { return m_name; }
int age() const { return m_age; }
private:
string m_name;
int m_age;
};
vs
class Person
{
public:
...
const String& name() const
{
return m_name;
}
int age() const
{
return m_age;
}
private:
string m_name;
int m_age;
};
Eu sei que alguns de vocês vão gritar com este exemplo porque seu estilo pessoal quer que getters e setters sejam de 1 linha, mas me ouçam ... quando depurar, dependendo do depurador, no primeiro estilo se você colocar um ponto de interrupção age
or name
o depurador não poderá inspecionar this
nem m_age
nem m_name
, portanto você não terá como verificar antes que a função retorne o que ela retornará ou a que objeto está fazendo referência. No segundo estilo você pode colocar pontos de interrupção nas linhas return
e você poderá inspecionar tudo.
O ponto desta resposta é que mais linhas geralmente não são boas apenas para a legibilidade. Também costuma ser bom para gravabilidade e depuração.