O código puro parece uma prosa bem escrita.
Grady Butch em Código Limpo
Rebus como código

O que é um rébus? Esta é uma mensagem criptografada. O autor do rébus pega o texto humano comum e o codifica usando desenhos, números e letras. E olhamos para essa criptografia e tentamos ler o texto de origem.
O rébus tem duas formas. Por um lado, o rébus é o texto original não criptografado e, por outro, os desenhos cifrados. O texto é o "o quê" do rébus, seu significado, mensagem. As imagens são "como":
como exatamente a mensagem é criptografada, de
que maneira. Adivinhando o rébus, traduzimos "como" para "o quê".
Os desenhos são a linguagem do rébus, seu arsenal de meios expressivos. O rebusnik, por assim dizer, fala conosco com a ajuda desses desenhos, comunica algo. Ele não tem permissão para usar palavras humanas normais.
Veja como os quebra-cabeças são lidos:

O código é como um rébus
O código do programa tem algo em comum com o rébus: ele também possui seu próprio "o quê" e "como". E às vezes também precisa ser descriptografado.
O "quê" de um código é seu propósito, significado, esse efeito e o resultado final que esperamos dele.
O que exatamente ele está
fazendo ?
“Como” do código - de que maneira concreta ele cumprirá seu “quê”, com quais atribuições, multiplicações, comparações específicas; implementação do algoritmo, instruções para o processador. É uma linguagem de código permitida, seu arsenal de meios expressivos.
Martin Fowler fala sobre isso desta maneira (
"Function Length" ,
original ):
Smalltalk naqueles anos trabalhava em máquinas preto e branco. Se você precisava destacar texto ou gráficos, precisava reverter o vídeo. A turma no Smalltalk, responsável pelo cronograma, continha o método 'realce' e, em sua implementação, havia apenas uma linha - uma chamada ao método 'reverso'. O nome do método era mais longo que a implementação, mas não importava, porque há uma grande distância entre a intenção e a implementação desse código.
Aqui o destaque é o "o quê". Na terminologia de Martin -
intenção : "destaque um fragmento da imagem". O nome expressa o que essa função faz. Reverso é como,
implementação .
Como exatamente o realce é realizado (usando inversão de imagem). Essa é a diferença entre "o que" e "como".
Apesar do nome do método ser mais longo que sua implementação, a existência de um método desse tipo faz sentido por uma razão muito simples. Quando vemos uma chamada reversa no código, devemos entender ou lembrar que a inversão da imagem é usada para tornar essa imagem mais visível. Quando vemos o destaque, acabamos de ler: "torne esse fragmento mais visível". No primeiro caso, dedicamos um pouco de esforço mental para entender a missão atribuída ao código, no segundo - não. No primeiro caso, vemos uma réplica à nossa frente, exigindo descriptografia, no segundo - uma história em uma linguagem compreensível.
Um programador, quando escreve um programa, é como um rébus. O programador criptografa a descrição humana do algoritmo usando as ferramentas da linguagem de programação disponíveis (mais primitivas que a linguagem humana). Criptografa "o quê" com "como". E mais tarde, ele ou seu colega lê o código, decifrando
esses rebuses na descrição inicial do algoritmo.
Se no processo de leitura do código não pudermos entender imediatamente a que resultado a execução de cada fragmento levará, ou seja, qual é o objetivo, o significado do código, esse código será uma réplica e precisará ser reescrito em uma linguagem clara.O problema com os quebra-cabeças no código é que eles
sempre exigem esforço mental. Mesmo se não realizarmos o conjunto completo de operações de descriptografia em nossas mentes, mas apenas lembrar estupidamente o significado de algum rebus, isso ainda criará uma carga: primeiro, para lembrar seu significado e, em segundo lugar, no momento da gravação da transformação rebus neste valor.
Decifrar o rébus enquanto você lê o código é a transformação mental que Tim Ottinger fala no livro Código Limpo. É verdade que ele os discute no contexto de atribuir nomes inteligíveis a variáveis, mas o problema é afetado exatamente pelo mesmo. Palavra para Tim:
Como regra, os programadores são muito inteligentes. E as pessoas inteligentes às vezes gostam de mostrar o poder da inteligência, demonstrando sua capacidade de fazer malabarismos mentais. No final, se você se lembrar de que a variável r contém uma URL com um host remoto e um esquema convertido em minúsculas, isso é claramente indicativo de sua opinião.
Uma das diferenças entre um programador inteligente e um profissional é que um profissional entende: a clareza é fundamental. Os profissionais usam seu poder para o bem e escrevem códigos compreensíveis para outras pessoas.
Mesmo uma pequena carga de cada rebus pode se tornar um problema se houver muitos desses rebus. Você provavelmente já encontrou um código cuja leitura é simplesmente exaustiva.
Saiba: os abusos no código são os culpados pelo seu cansaço. Os rebuses exacerbam o cansaço de seu próprio autor diretamente no processo de escrever código. Afinal, ao escrever o código, o programador também relê continuamente o que foi escrito. Apesar do fato de o autor não decifrar seus próprios quebra-cabeças, mas simplesmente se lembrar, eles ainda criam uma carga. A armadilha é que o
autor simplesmente não vê quebra-cabeças em seu próprio código ! Tente imaginar quanto esforço mental você pode economizar à noite, se começar a se livrar dos quebra-cabeças do seu código pela manhã!
Portanto, para reduzir o cansaço ao escrever e ler código, você precisa evitar quebra-cabeças. Mas como fazer isso?
O idioma do código. Força do identificador
Concordo com a afirmação de Grady Butch de que o código limpo parece uma boa prosa. Essa é uma condição necessária, embora não suficiente. Muitos de nós entenderão intuitivamente o que está em jogo, mas eu gostaria de ter pelo menos alguma definição: o que é isso - boa prosa.
Perguntei aos meus colegas escritores: como a boa prosa é diferente da prosa ruim? Todos responderam de maneira diferente, mas de alguma forma enfatizaram a importância da linguagem: ela deve ser rica, deve criar imagens claras na mente e na alma do leitor. Quando o leitor facilmente tem uma imagem clara que o autor quis desenhar para ele, estamos lidando com uma boa prosa.
O código informa ao processador o que ele deve fazer. Um bom código ao mesmo tempo informa ao programador - e, além disso, com muita sinceridade! - o que ele está fazendo aqui? Ou seja, ele define seu algoritmo o mais próximo possível de como o próprio autor o faria em uma linguagem natural. Nosso código deve fazer isso muito bem, caso contrário, um
maníaco desenfreado com uma serra elétrica ou espingarda pode chegar a nossa casa. O código não deve ser um rébus.
Quais ferramentas o código possui para não ser uma réplica?
Uma história em nome do código será facilmente compreendida por uma pessoa se o próprio código falar em linguagem humana. Isso pode ser alcançado apenas com a ajuda de identificadores: nomes de funções, classes, variáveis e constantes - porque
somente nos identificadores podemos usar as palavras da linguagem humana de que precisamos .
Obviamente, as palavras-chave de uma linguagem de programação também são palavras humanas, mas seu vocabulário é muito ruim. Algo como a linguagem de Ellochka, o Ogro - você não pode escrever uma boa prosa.
Portanto, é vital que o código do programa contenha o maior número possível de identificadores escolhidos corretamente. De modo que sua totalidade forma a prosa muito bem escrita.
Veja como é fácil ler linhas de código quando os nomes de variáveis e métodos são bem escolhidos:
pageData.hasAttribute("Test") dom_tree.to_html() emails_str.split(',')
Observando essas frases curtas, é fácil entender do que elas estão falando. Sabemos o resultado que obtemos, porque os identificadores nos dizem sobre isso. Agora imagine que, no local de cada chamada, é a sua implementação - quanto diminuirá a velocidade de leitura desse código "criptografado"?
Muitas das técnicas mais simples de refatoração: constantes nomeadas, seleção de um método, substituição de uma variável por uma chamada de método, variável explicativa, divisão de uma variável temporária etc. são sobre
como fazer o código falar a linguagem humana, ou seja, como evitar quebra-cabeças .
Método Rebus
Quando li o Pure Code, fui periodicamente visitado pelo pensamento: "Que diabos!".
Do auge de seus 40 anos de experiência, Robert Martin nos dá dicas sobre como melhorar o código. Por exemplo:
Primeira regra: as funções devem ser compactas. A segunda regra: as funções devem ser ainda mais compactas.
E então ele admite que não pode fundamentar cientificamente sua afirmação. Honestamente, não científico, ele também se sai mal. O requisito para compactação de função já está começando a parecer um dogma - é por isso que o
debate sobre a questão do tamanho de uma função não diminuiu por tantas décadas.
E Bob também se oferece para escrever cada função para que ela execute apenas uma operação. Além disso, o que é essa única operação - também não é muito clara. Temos que pedir ajuda ao princípio de um único nível de abstração, que confunde ainda mais a situação. Tudo isso é muito nebuloso.
Martin Fowler é mais pragmático.
Parece-me que o argumento sobre a separação entre intenção e realização tem mais significado. Se, olhando para um trecho de código, você precisar fazer um esforço para entender o que está fazendo, será necessário colocá-lo em uma função e dar um nome a ele de acordo com este "o quê". Da próxima vez, o objetivo da função será imediatamente óbvio e, na maioria dos casos, você não se preocupará com o desempenho da função.
O originalO argumento que faz mais sentido para mim, no entanto, é a separação entre intenção e implementação. Se você tiver que se esforçar para analisar um fragmento de código para descobrir o que está fazendo, deve extraí-lo em uma função e nomear a função depois disso "o que". Dessa forma, quando você lê novamente, o objetivo da função salta diretamente para você e, na maioria das vezes, você não precisa se preocupar com o modo como a função cumpre seu objetivo - que é o corpo da função.
Já está melhor. Você vê agora o que Martin queria dizer nesta passagem? Ele quis dizer: vamos eliminar os quebra-cabeças. Deixe o próprio código nos dizer qual será o resultado e como - deixe-o oculto em algum lugar mais distante, na definição da função. Que todos os quebra-cabeças sejam decifrados. Sem quebra-cabeças - sem esforço.
Em nenhum caso você deve aplicar cegamente os métodos de refatoração. Isso é tão óbvio, mas como entender quando a refatoração é realmente necessária e quando não?
O método rebus diz: se após a refatoração, o rebus não desaparece, a refatoração não é necessária .
Se você não conseguir encontrar um nome para uma nova função que explique claramente o que está acontecendo nela, é sinal de que você está fazendo algo errado aqui. Tente selecionar um fragmento de código um pouco diferente na função - para o qual você pode encontrar rapidamente um nome curto e compreensível.Um exemplo de decodificação de quebra-cabeças em código (não muito bem-sucedido)
Como tal, citarei um fragmento do livro "Código Limpo" de que gostei. Antes da refatoração, vemos um código cheio de quebra-cabeças. A refatoração foi feita pelo autor do livro de acordo com as regras de bom código promovidas por ele e - apenas uma coincidência - o código refatorado se parece exatamente com o código no qual os rebuses são descriptografados.
O autor da refatoração aplicou completamente identificadores legíveis por humanos (nomes de classes, métodos e variáveis) para indicar o que o código realmente faz. É uma pena que nem todos os lugares tenham saído com sucesso e, em alguns lugares, novos enigmas apareceram em vez dos quebra-cabeças anteriores.
Por exemplo, o método include mais comumente usado nesta passagem
private void include(String pageName, String arg) throws Exception { WikiPage inheritedPage = findInheritedPage(pageName); if (inheritedPage != null) { String pagePathName = getPathNameForPage(inheritedPage); buildIncludeDirective(pagePathName, arg); } }
O nome não reflete o que está acontecendo na implementação. O que inclui e onde?
Observando a chamada para este método:
include("TearDown", "-teardown");
é impossível dizer que resultado o autor do código alcançaria aqui.
Próximo: o que o buildIncludeDirective faz? A julgar pelo nome, ele deveria elaborar algum tipo de diretiva de inclusão, e daí? Trazê-la de volta? Mas não. Ele adiciona imediatamente ao resultado geral.
E aqui está outro updatePageContent. O que updatePageContent nos diz sobre o resultado obtido após a chamada do método? Nada. Algum conteúdo da página será substituído por ninguém sabe o quê. Por que a refatoração chamada extração de método foi realizada aqui? Ele ajudou a se livrar do rébus? Não ajudou, mas apenas confundiu o código. Aqui temos o caso exato em que o corpo do método é preferível. Construção civil
pageData.setContent(newPageContent.toString());
muito mais claro que o updatePageContent () enigmático.
Como entretenimento, sugiro que os leitores procurem quais outros lugares ruins estão no
código refatorado .
Para justificar Bob, posso dizer que esse código não está mais na versão atual do FitNesse. Aparentemente, por sua vez, ele também foi refatorado.
Conclusão
O comprimento da função é um critério muito vago para determinar a qualidade da função. “Funções curtas” não é igual a “boas funções”. O comprimento da função não é um critério, esqueça tudo.
Um bom código deve dar respostas às perguntas do programador - por que ele (o código) está aqui, o que
diabos ele está fazendo aqui,
ele está alcançando o resultado. Essas respostas só podem ser dadas usando identificadores.
Como exemplo de que tipo de respostas o código não deve fornecer, quero dar um trecho de um livro divertido.
"Eu sou Ronan, vencedor do mal", disse ele lentamente. - E este é Tarl. Nós queremos um pouco
faça perguntas. Se você mente, você morre. Entendi
"Eu, tio, para sempre", ele respirou. Por favor. Vou dizer tudo.
"Isso é legal", Ronan continuou. Nome?
- Ronan, vencedor do mal.
- Sim, não meu, idiota!
"Ah, sim, então Tarle", o orc respondeu se desculpando.
- E não meu! Tarle murmurado. - Seu nome, clube! Primeiro nome!
"O nome é o nome que eu uso para me distinguir dos outros", o orc murmurou.
- Bem, dê esse nome aqui! Tarle gritou.
Orka de repente amanheceu.
Ah! Espinha!
"Então Pimple, o que você está fazendo aqui?"
"Coloquei na minha calça", veio a resposta verdadeira.
Ronan torceu o nariz com nojo.
"Não, eu pergunto o que sua gangue de orcs está fazendo aqui!"
Os olhos de Pimple rapidamente se viraram, olhando ao redor da cena.
"A maioria das pessoas não tem cabeça aqui", ele murmurou.
Tarle tocou Ronan no ombro.
"Deixe-me tentar", disse ele confiante e virou-se para o orc assustado. Diga-me,
Espinha - continuou ele - por que você está aqui?
- Oh, tio, e não pergunte. A filosofia existencial para mim é apenas uma floresta sombria.
"Escute, seu dragão arrota", ele rosnou abafado. - Sua gangue de orcs teve um especial
razão para vir aqui. O que é isso, na floresta?
- Tem muitas árvores.
Os olhos de Ronan se arregalaram e Tarle se virou. A espinha, sentindo que não tinha dado a resposta esperada, começou a murmurar ainda mais.
- E se você quer saber sobre o motivo, e não sobre a floresta, é tudo porque essa pessoa no bar
nos pagou para vir aqui e te matar.
James Bibby, Ronan, o Bárbaro