"Fácil de raciocinar" - o que isso significa? [fechadas]

49

Ouvi muitas vezes quando outros desenvolvedores usam essa frase para "anunciar" alguns padrões ou desenvolver práticas recomendadas. Na maioria das vezes, essa frase é usada quando você está falando sobre os benefícios da programação funcional.

A frase "Fácil de raciocinar" foi usada como é, sem nenhuma explicação ou amostra de código. Então, para mim, torna-se a próxima palavra "buzz", que mais desenvolvedores "experientes" usam em suas conversas.

Pergunta: Você pode fornecer alguns exemplos de exemplos "Não é fácil de raciocinar", para que possa ser comparado com os exemplos de "Fácil raciocinar"?

Fabio
fonte
4
@ MartinMaat Uma frase mais precisa que é amplamente usada é o raciocínio equacional, eu sugeriria que isso pode ser o que Fabio está
buscando
3
Eu gosto de usar a frase "carga cognitiva" para esse tipo de coisa.
precisa
16
Você sabe o que significa raciocínio sobre programas ?
Bergi
5
No sentido não formal, eu uso isso para significar que uma solução é simples o suficiente para entender (geralmente) quais serão os resultados para qualquer entrada sem testá-la. Isso significa que, para qualquer conjunto de entradas, os resultados serão surpreendentes. Soluções que têm casos de canto não óbvios, por exemplo, são difíceis de raciocinar. Principalmente eu uso isso em referência à robustez.
JimmyJames
7
Sou muito culpado de usar "mais fácil de raciocinar" com frequência; Observo, no entanto, que tento tomar cuidado ao dizer o comparativo mais fácil do que o absoluto fácil . Houve um dia na minha vida em que eu não conseguia pensar em nenhum software, então não foi fácil naquele dia; tornou-se fácil apenas gastando muito tempo e esforço. Dizer que qualquer problema de programação é fácil é adotar uma postura pejorativa em relação a qualquer um que ainda não ache fácil. Dizer que um modelo é mais fácil que outro é dizer que há menos conceitos envolvidos, menos partes móveis e assim por diante.
precisa

Respostas:

58

A meu ver, a frase "fácil de raciocinar" refere-se a códigos fáceis de "executar na sua cabeça".

Ao olhar para um pedaço de código, se ele é curto, claramente escrito, com bons nomes e mutação mínima de valores, trabalhar mentalmente o que o código faz é uma tarefa (relativamente) fácil.

Um longo pedaço de código com nomes ruins, variáveis ​​que mudam constantemente de valor e ramificações complicadas normalmente exigem, por exemplo, uma caneta e um pedaço de papel para ajudar a acompanhar o estado atual. Portanto, esse código não pode ser facilmente trabalhado apenas na sua cabeça; portanto, não é fácil raciocinar sobre esse código.

David Arno
fonte
29
Com uma pequena ressalva de que não importa quão bem você nomeie suas variáveis, um programa que tenta refutar a conjectura de Goldbach é inerentemente difícil de "executar", na sua cabeça ou em outro lugar. Mas ele ainda pode ser fácil raciocinar sobre, no sentido de ser fácil de se convencer de que se afirma ter encontrado um contra-exemplo, então ele está dizendo a verdade ;-)
Steve Jessop
4
Eu nunca iria querer executar código na minha cabeça. Isso, para mim, seria o programa definitivo de "não é fácil argumentar". Eu gostaria de poder fazer declarações preditivas sobre o que o computador faria sem executá-lo. Código que é "fácil de raciocinar" é um código que não precisa ser executado em sua mente, mas pode ser fundamentado.
precisa
11
Como alguém pode responder a uma pergunta sobre raciocínio sobre código sem sequer mencionar a verificação formal ? Esta resposta sugere que o raciocínio sobre o código é informal e ad-hoc. não é, geralmente é feito com muito cuidado e abordagens matemáticas. Existem certas propriedades matemáticas que tornam o código "fácil de raciocinar" em um sentido objetivo (funções puras, para dar um exemplo muito fácil). nomes de variáveis não têm nada a ver com o quão fácil é "raciocinar" sobre o código, pelo menos não em nenhum sentido formal.
Polygnome
3
@ Polygnome O raciocínio sobre código geralmente não é feito com muito cuidado e abordagens matemáticas. Enquanto escrevo isso, as pessoas que raciocinam informalmente sobre o código estão superando em número os aproximadores matemáticos em milhões para um, pelo menos, pelo menos eu acho.
Kaz
2
@ Polygnome "Code easy to reason about" almost exclusively alludes to its mathematical properties and formal verification- que soa aproximadamente como uma resposta para a pergunta. Você pode postar isso como uma resposta, em vez de discordar sobre qual é a resposta (subjetiva) nos comentários.
Dukeling
47

É fácil raciocinar sobre um mecanismo ou parte do código quando você precisa levar em consideração algumas coisas para prever o que fará e as coisas que você precisa levar em consideração estão facilmente disponíveis.

Funções verdadeiras, sem efeitos colaterais e sem estado, são fáceis de raciocinar, porque a saída é completamente determinada pela entrada, que está exatamente nos parâmetros.

Por outro lado, é muito mais difícil argumentar sobre um objeto com estado, porque é necessário levar em consideração em que estado o objeto se encontra quando um método é chamado, o que significa que é necessário pensar em quais outras situações poderiam levar o objeto a estar em um estado. estado particular.

Piores ainda são as variáveis ​​globais: para raciocinar sobre o código que lê uma variável global, você precisa entender onde essa variável pode ser configurada e por que - e talvez nem seja fácil encontrar todos esses lugares.

A coisa mais difícil de se raciocinar é a programação multithread com estado compartilhado, porque não apenas você tem estado, mas vários threads alterando-o ao mesmo tempo, para raciocinar sobre o que um pedaço de código faz quando executado por um thread que você é preciso permitir a possibilidade de que, em cada ponto de execução, algum outro encadeamento (ou vários deles!) possa estar executando praticamente qualquer outra parte do código e altere os dados nos quais você está operando sob seus olhos. Em teoria, isso pode ser gerenciado com mutexes / monitores / seções críticas / o que você chamar, mas na prática nenhum humano é capaz de fazer isso de maneira confiável, a menos que confinem drasticamente o estado compartilhado e / ou o paralelismo a muito pequeno seções do código.

Michael Borgwardt
fonte
9
Eu concordo com esta resposta, mas mesmo com funções puras, abordagens declarativas (como CSS, XSLT ou makeespecialização de modelo C ++ e sobrecarga de função) podem colocá-lo de volta na posição de considerar todo o programa. Mesmo quando você acha que encontrou a definição de algo, o idioma permite que uma declaração mais específica em qualquer lugar do programa a substitua. Seu IDE pode ajudar com isso.
Steve Jessop
4
Eu acrescentaria que, no cenário multithread, você também precisa ter uma compreensão razoavelmente profunda de quais instruções de nível inferior seu código deseja: uma operação que parece atômica na fonte pode ter pontos de interrupção inesperados na execução real.
Jared Smith
6
@SteveJessop: De fato, esse ponto é frequentemente esquecido. Há uma razão pela qual o C # faz você dizer quando deseja que um método seja substituível em vez de silenciosamente, tornando a substituibilidade o padrão; queremos exibir uma bandeira dizendo "a correção do seu programa pode depender do código que você não consegue encontrar no momento da compilação" neste momento. (Dito isto, gostaria também que "selada" foi o padrão para as classes em C #.)
Eric Lippert
@EricLippert Quais foram os motivos finais para sealednão ser o padrão?
Zev Spitz
@ZevSpitz: Essa decisão foi tomada muito antes do meu tempo; Eu não sei.
precisa
9

No caso de programação funcional, o significado de "Fácil de raciocinar" é principalmente que é determinístico. Com isso, quis dizer que uma determinada entrada sempre levará à mesma saída. Você pode fazer o que quiser com o programa, desde que não toque nesse trecho de código, ele não será quebrado.

Por outro lado, o OO normalmente é mais difícil de raciocinar, porque a "saída" produzida depende do estado interno de cada objeto envolvido. A maneira típica de manifestar são efeitos colaterais inesperados : ao alterar uma parte do código, uma parte aparentemente não relacionada é interrompida.

... a desvantagem da programação funcional é que, na prática, muito do que você deseja fazer é IO e gerenciamento de estado.

No entanto, existem muitas outras coisas que são mais difíceis de raciocinar, e eu concordo com @Kilian que a simultaneidade é um excelente exemplo. Sistemas distribuídos também.

dagnelies
fonte
5

Evitando discussões mais amplas e abordando a questão específica:

Você pode fornecer alguns exemplos de exemplos de "Não é fácil de raciocinar", para que possa ser comparado com os exemplos de "Fácil de raciocinar"?

Refiro-lhe "A história de Mel, um verdadeiro programador" , um pedaço do folclore de programadores que data de 1983 e, portanto, conta como "lenda" para nossa profissão.

Ele conta a história de um programador escrevendo código que preferia técnicas misteriosas sempre que possível, incluindo código auto-referencial e auto-modificador e exploração deliberada de erros de máquina:

de fato, um loop infinito aparente fora codificado de maneira a tirar proveito de um erro de excesso de carga. A adição de 1 a uma instrução que decodificou como "Carregar do endereço x" normalmente produziu "Carregar do endereço x + 1". Mas quando x já era o endereço mais alto possível, o endereço não era apenas zerado, mas um 1 era carregado nos bits a partir dos quais o código operacional seria lido, alterando-o de "load from" para "jump to" para que a instrução completa mudou de "carregar do último endereço" para "pular para o endereço zero".

Este é um exemplo de código "difícil de raciocinar".

Claro, Mel discordaria ...

AakashM
fonte
11
+1 por referenciar a história de Mel, uma das minhas favoritas perenes.
John Bollinger
3
Leia A história de Mel aqui, já que o artigo da Wikipedia não tem links para ele.
TRiG 21/06
Nota de rodapé @TRiG 3 na página, não?
precisa saber é o seguinte
@AakashM De alguma forma conseguiu perder isso.
TRiG
5

Eu posso fornecer um exemplo, e muito comum.

Considere o seguinte código C #.

// items is List<Item>
var names = new List<string>();
for (var i = 0; i < items.Count; i++)
{
    var item = items[i];
    var mangled = MyMangleFunction(item.Name);
    if (mangled.StartsWith("foo"))
    {
        names.Add(mangled);
    }
}

Agora considere esta alternativa.

// items is List<Item>
var names = items
    .Select(item => MyMangleFunction(item.Name))
    .Where(s => s.StartsWith("foo"))
    .ToList();

No segundo exemplo, eu sei exatamente o que esse código está fazendo rapidamente. Quando vejo Select, sei que uma lista de itens está sendo convertida em uma lista de outra coisa. Quando vejo Where, sei que certos itens estão sendo filtrados. De relance, consigo entender o que namesé e fazer uso efetivo dele.

Quando vejo um forloop, não faço ideia do que está acontecendo até ler o código. E, às vezes, tenho que rastreá-lo para ter certeza de que sou responsável por todos os efeitos colaterais. Eu tenho que fazer um pouco de trabalho para entender o que são nomes (além da definição de tipo) e como usá-lo efetivamente. Assim, o primeiro exemplo é mais difícil de raciocinar do que o segundo.

Por fim, ser fácil raciocinar aqui também depende da compreensão dos métodos Selecte LINQ Where. Se você não os conhece, é mais difícil pensar no segundo código inicialmente. Mas você paga apenas o custo para entendê-los uma vez. Você paga o custo para entender um forloop toda vez que usa um e novamente toda vez que ele muda. Às vezes, vale a pena pagar o custo, mas geralmente ser "mais fácil de raciocinar" é muito mais importante.

Kasey Speakman
fonte
2

Uma frase relacionada é (paráfrase),

Não basta que o código não tenha " erros óbvios ": em vez disso, ele deve ter " obviamente nenhum erro ".

Um exemplo de relativamente "fácil de raciocinar" pode ser o RAII .

Outro exemplo pode ser evitar o abraço mortal : se você pode segurar uma fechadura e adquirir outra fechadura, e há muitas fechaduras, é difícil ter certeza de que não há cenário em que o abraço mortal possa ocorrer. A adição de uma regra como "existe apenas um bloqueio (global)" ou "você não tem permissão para adquirir um segundo bloqueio enquanto mantém um primeiro bloqueio" torna o sistema relativamente fácil de raciocinar.

ChrisW
fonte
11
Hmm. Não tenho certeza se RAII é tão fácil de raciocinar. Claro, é fácil entender conceitualmente , mas fica mais difícil realmente raciocinar sobre (ou seja, prever) o comportamento do código que faz uso extensivo do RAII. Quero dizer, são basicamente chamadas de função invisíveis no nível do escopo. O fato de muitas pessoas terem problemas para raciocinar sobre isso é muito claro se você já fez alguma programação COM .
Cody Grey
Eu quis dizer relativamente fácil (C ++ comparado com C): por exemplo, a existência de um meio construtor apoiada em língua que os programadores podem não criar / tem / usar um objeto que eles se esqueça de inicializar, etc.
ChrisW
Esse exemplo baseado em COM é problemático porque combina estilos, isto é, ponteiro inteligente em estilo C ++ ( CComPtr<>) com função em estilo C ( CoUninitialize()). Também acho um exemplo bizarro, desde que me lembro de você invocar CoInitialize / CoUninitialize no escopo do módulo e por toda a vida útil do módulo, por exemplo, dentro mainou dentro DllMain, e não em algum escopo de função local de vida curta, como mostrado no exemplo .
ChrisW
É um exemplo excessivamente simplificado para fins ilustrativos. Você está completamente certo de que COM foi inicializado no escopo do módulo, mas imagine o exemplo de Raymond (como o exemplo de Larry) como sendo a mainfunção de ponto de entrada ( ) para um aplicativo. Você inicializa o COM na inicialização e o inicializa logo antes de sair. Exceto que você possui objetos globais, como ponteiros inteligentes COM, usando o paradigma RAII. Em relação à mistura de estilos: um objeto global que inicializou o COM no seu ctor e não inicializou no seu dtor é viável, e o que Raymond sugere, mas é sutil e não é fácil de raciocinar.
Cody Grey
Eu diria que, de muitas maneiras, a programação COM é mais fácil de raciocinar em C, porque tudo é uma chamada de função explícita. Não há nada oculto ou invisível nas suas costas. É um pouco mais trabalhoso (ou seja, mais tedioso), porque você precisa escrever manualmente todas essas chamadas de funções e voltar e verificar seu trabalho para ver se fez isso corretamente, mas está tudo exposto, qual é a chave para facilitar o raciocínio . Em outras palavras, "algumas vezes indicadores inteligentes são inteligentes demais" .
Cody Grey
2

O cerne da programação é a análise de casos. Alan Perlis comentou isso no Epigram # 32: Os programadores não devem ser medidos por sua engenhosidade e lógica, mas pela integridade de sua análise de caso.

É fácil argumentar sobre uma situação se a análise de caso é fácil. Isso significa que existem poucos casos a serem considerados ou, na sua falta, poucos casos especiais - pode haver grandes espaços de casos, mas que colapsam devido a algumas regularidades ou sucumbem a uma técnica de raciocínio, como a indução.

Uma versão recursiva de um algoritmo, por exemplo, geralmente é mais fácil de raciocinar do que uma versão imperativa, porque não contribui com casos supérfluos que surgem pela mutação de variáveis ​​de estado de suporte que não aparecem na versão recursiva. Além disso, a estrutura da recursão é tal que se encaixa em um padrão matemático de prova por indução. Não precisamos considerar complexidades como variantes de loop e pré-condições estritas mais fracas e outros enfeites.

Outro aspecto disso é a estrutura do espaço do caso. É mais fácil argumentar sobre uma situação que possui uma divisão plana ou quase plana em casos, em comparação com uma situação hierárquica de caso: casos com sub e sub-casos e sub-casos e assim por diante.

Uma propriedade de sistemas que simplifica o raciocínio é a ortogonalidade : é a propriedade de que os casos que governam os subsistemas permanecem independentes quando esses subsistemas são combinados. Nenhuma combinação dá origem a "casos especiais". Se algo de quatro casos é combinado com algo de três casos ortogonalmente, há doze casos, mas idealmentecada caso é uma combinação de dois casos que permanecem independentes. Em certo sentido, não existem realmente doze casos; as combinações são apenas "fenômenos emergentes do tipo caso" com os quais não precisamos nos preocupar. O que isso significa é que ainda temos quatro casos em que podemos pensar sem considerar os outros três no outro subsistema e vice-versa. Se algumas das combinações precisam ser especialmente identificadas e dotadas de lógica adicional, o raciocínio é mais difícil. Na pior das hipóteses, todas as combinações têm um tratamento especial e, na verdade, existem doze novos casos, além dos quatro e três originais.

Kaz
fonte
0

Certo. Tome simultaneidade:

Seções críticas impostas por mutexes: fáceis de entender porque existe apenas um princípio (dois segmentos de execução não podem entrar na seção crítica simultaneamente), mas propensos a ineficiência e impasse.

Modelos alternativos, como programação ou atores sem bloqueios: potencialmente muito mais elegantes e poderosos, mas terrivelmente difíceis de entender, porque você não pode mais confiar em (aparentemente) conceitos fundamentais como "agora escreva esse valor nesse local".

Ser fácil de raciocinar é um aspecto de um método. Mas escolher qual método usar requer considerar todos os aspectos em combinação.

Kilian Foth
fonte
13
-1: exemplo muito, muito ruim, que me faz pensar que você não entende o que a frase significa. "Seções críticas impostas por mutexes" são de fato uma das coisas mais difíceis de se raciocinar por aí - praticamente todo mundo que as usa apresenta condições de corrida ou impasses. Vou lhe dar uma programação sem travas, mas o ponto principal do modelo de ator é que é muito, muito mais fácil argumentar.
precisa
11
O problema é que a simultaneidade é um tópico muito difícil de ser discutido pelos programadores, portanto não é um bom exemplo. Você está completamente correto de que as seções críticas impostas por mutexes são uma maneira relativamente simples de implementar a simultaneidade, em comparação com a programação sem bloqueio, mas a maioria dos programadores é como Michael, e seus olhos brilham quando você começa a falar sobre seções e mutexes críticos. certamente não parece uma coisa fácil de entender. Sem mencionar todos os erros.
Cody Grey
0

Vamos limitar a tarefa ao raciocínio formal. Porque o raciocínio humorístico, inventivo ou poético tem leis diferentes.

Mesmo assim, a expressão é pouco definida e não pode ser definida de maneira estrita. Mas isso não significa que deva permanecer tão obscuro para nós. Vamos imaginar que uma estrutura esteja passando em algum teste e recebendo notas para diferentes pontos. As boas notas para TODOS os pontos significam que a estrutura é conveniente em todos os aspectos e, portanto, "Fácil de raciocinar".

A estrutura "Fácil de raciocinar" deve receber boas notas para o seguinte:

  • Os termos internos têm nomes razoáveis, facilmente distinguíveis e definidos. Se os elementos tiverem alguma hierarquia, a diferença entre nomes de pai e filho deve ser diferente da diferença entre nomes de irmãos.
  • O número de tipos de elementos estruturais é baixo
  • Tipos usados ​​de elementos estruturais são coisas fáceis com as quais estamos acostumados.
  • Os elementos pouco compreensíveis (recursões, meta etapas, geometria dimensional 4+ ...) são isolados - não diretamente combinados entre si. (por exemplo, se você tentar pensar em alguma regra recursional alterando para cubos dimensionais de 1,2,3,4..n..será muito complicado. Mas se você transferir cada uma dessas regras para alguma fórmula dependendo de n, você terá separadamente uma fórmula para cada cubo n e separadamente uma regra de recursão para essa fórmula. E que duas estruturas separadamente podem ser facilmente pensadas)
  • Os tipos de elementos estruturais são obviamente diferentes (por exemplo, não usando matrizes mistas a partir de 0 e de 1)

O teste é subjetivo? Sim, naturalmente é. Mas a expressão em si também é subjetiva. O que é fácil para uma pessoa, não é fácil para outra. Portanto, os testes devem ser diferentes para os diferentes domínios.

Gangnus
fonte
0

A idéia de que as linguagens funcionais são possíveis de raciocinar vem de sua história, especificamente o ML, que foi desenvolvido como uma linguagem de programação análoga às construções que a lógica para funções computáveis usava para raciocinar. A maioria das linguagens funcionais está mais próxima dos cálculos formais de programação do que as imperativas; portanto, a tradução do código para a entrada de um sistema de sistema de raciocínio é menos onerosa.

Para um exemplo de um sistema de raciocínio, no cálculo pi, cada local de memória mutável em uma linguagem imperativa precisa ser representado como um processo paralelo separado, enquanto uma sequência de operações funcionais é um processo único. Quarenta anos depois do provador do teorema de LFC, estamos trabalhando com GB de RAM, portanto, ter centenas de processos é menos um problema - usei o pi-calculus para remover possíveis bloqueios de algumas centenas de linhas de C ++, apesar da representação ter centenas de processa o raciocínio esgotar o espaço de estado em cerca de 3 GB e curar um bug intermitente. Isso teria sido impossível nos anos 70 ou exigido um supercomputador no início dos anos 90, enquanto o espaço de estados de um programa de linguagem funcional de tamanho semelhante era pequeno o suficiente para se pensar naquela época.

A partir das outras respostas, a frase está se tornando uma frase de efeito, embora muitas das dificuldades que dificultam a argumentação sobre linguagens imperativas sejam corroídas pela lei de Moore.

Pete Kirkham
fonte
-2

Fácil de raciocinar é um termo culturalmente específico, e é por isso que é tão difícil apresentar exemplos concretos. É um termo ancorado às pessoas que devem raciocinar.

"Fácil de raciocinar" é na verdade uma frase muito auto-descritiva. Se alguém está olhando o código e quer raciocinar o que faz, é fácil =)

Ok, quebrando tudo. Se você está olhando para o código, geralmente deseja que ele faça alguma coisa. Você quer ter certeza de que faz o que acha que deve fazer. Então, você desenvolve teorias sobre o que o código deveria estar fazendo e, em seguida, argumenta sobre isso para tentar argumentar por que o código realmente funciona. Você tenta pensar no código como um ser humano (e não como um computador) e tenta racionalizar argumentos sobre o que o código pode fazer.

O pior caso para "fácil de raciocinar" é quando a única maneira de entender o que o código faz é passar linha por linha através do código como uma máquina de Turing para todas as entradas. Neste caso, a única maneira de razão qualquer coisa sobre o código é para se transformar em um computador e executá-lo em sua cabeça. Esses piores exemplos de casos são facilmente vistos em concursos de programação obsfucados, como essas 3 linhas de PERL que descriptografam o RSA:

#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)

Quanto a fácil raciocinar, novamente, o termo é altamente cultural. Você deve considerar:

  • Que habilidades possui o raciocínio? Quanta experiência?
  • Que tipo de perguntas o raciocínio pode ter sobre o código?
  • Quão certo o raciocinador precisa ser?

Cada um deles afeta "fácil de raciocinar" de maneira diferente. Tome as habilidades do raciocínio como exemplo. Quando comecei na minha empresa, foi recomendado que eu desenvolvesse meus scripts no MATLAB porque é "fácil de raciocinar". Por quê? Bem, todos na empresa conheciam o MATLAB. Se eu escolhesse um idioma diferente, seria mais difícil para alguém me entender. Não importa que a legibilidade do MATLAB seja atroz para algumas tarefas, simplesmente porque não foi projetada para elas. Mais tarde, à medida que minha carreira avançava, o Python se tornou cada vez mais popular. De repente, o código do MATLAB tornou-se "difícil de raciocinar" e o Python era a linguagem preferida para escrever código que era fácil de raciocinar.

Considere também quais idiomas o leitor pode ter. Se você pode confiar no seu leitor para reconhecer uma FFT em uma sintaxe específica, é "mais fácil raciocinar sobre" o código se você se ater a essa sintaxe. Ele permite que eles olhem o arquivo de texto como uma tela na qual você pintou uma FFT, em vez de ter que entrar nos mínimos detalhes. Se você estiver usando C ++, descubra o quanto seus leitores estão confortáveis ​​com a stdbiblioteca. Quanto eles gostam de programação funcional? Alguns dos idiomas que saem das bibliotecas de contêineres são muito dependentes de qual estilo idomatic você prefere.

Também é importante entender que tipos de perguntas o leitor pode estar interessado em responder. Seus leitores estão preocupados principalmente com a compreensão superficial do código ou estão procurando bugs nas entranhas?

O quão certo o leitor precisa ser é realmente interessante. Em muitos casos, o raciocínio nebuloso é realmente suficiente para levar o produto para fora da porta. Em outros casos, como o software de voo da FAA, o leitor desejará ter um raciocínio rígido. Encontrei um caso em que argumentei usar o RAII para uma tarefa específica, porque "Você pode simplesmente configurá-lo e esquecê-lo ... ele fará a coisa certa". Foi-me dito que eu estava errado sobre isso. Aqueles que pensariam nesse código não eram o tipo de pessoa que "apenas quer esquecer os detalhes". Para eles, o RAII era mais como um chad, forçando-os a pensar em todas as coisas que podem acontecer quando você sai do escopo.

Cort Ammon
fonte
12
O código Perl é difícil de ler ; não raciocinar sobre. Se eu tivesse algum interesse em precisar entendê-lo, eu desautorizaria o código. O código que é realmente difícil de raciocinar é o que ainda é difícil de raciocinar quando está bem formatado com identificadores claros para tudo, e sem truques de golfe de código.
Kaz