Programação orientada a depuração ou tristeza aos olhos do integrador

Aconteceu que, nos últimos anos, costurei Frankenstein, e não esculpi estatuetas de porcelana fofas de pastoras e limpadores de chaminé. Crio soluções baseadas no Magento 2. Isso significa que o material de origem para mim é o sonho de qualquer arqueólogo. A camada cultural com traços de várias "eras" e "civilizações". Ele pode ser usado para estudar o desenvolvimento do pensamento do programador em comunidades PHP / JS na última década.


E essa é apenas a base, e o complemento são módulos de terceiros que precisam ser integrados. Aqui já é possível encontrar manifestações de inteligência extraterrestre. Alguns módulos são criados por criaturas desenvolvidas, com pensamento muito semelhante aos criadores da base, mas você encontra aqueles que deseja levar o autor pelo ombro, olha profundamente nos olhos dele e pergunta de maneira amigável: "De que planeta você é, nativo? "


imagem


O depurador ajuda a costurar Frankenstein a partir desse material. Abaixo está minha técnica pessoal de codificação superior, que pode complicar a vida de qualquer pessoa que, como eu, use o depurador diariamente em sua vida. É pequeno, com quatro posições, mas toda vez que encontro algo assim durante a depuração, fico triste. Talvez meu post reduza o número de tristezas no mundo, ou talvez não. Eu vou pelo menos tentar.


Ofuscação e criptografia de código


Isso está fora de competição. Me deparei algumas vezes com módulos que exigem que o ionCube funcione, e posso dizer que a última coisa que vou fazer é colocar um módulo semelhante no meu projeto. Apoio totalmente a minificação do código JS, especialmente quando a fonte usual está próxima, mas a ofuscação e a criptografia são um mal destilado e concentrado. Estou lhe dizendo como um integrador.


IV Código de linha única


Salvar em linhas de código é o mais inofensivo da minha lista:


if ($cond) aaa(); else bbb(); 

Desliga duas etapas nesta linha durante a execução passo a passo do programa (cálculo da condição, execução da ramificação true ou false ). Tudo bem, você só precisa ter em mente quantas vezes você executou uma etapa nesta linha e acompanhar o valor de $cond na lista de variáveis. Com o tempo, o automatismo se desenvolveu.


Um pouco pior é que você não pode definir um ponto de interrupção incondicional na ramificação true ou false . Em vez de um único clique no IDE, você precisará trabalhar um pouco mais com o mouse / teclado, adicionando um ponto de interrupção condicional.


A opção ideal é quando cada etapa executável (condição, luz true , luz false ) estiver em sua própria linha:


 if ($cond) aaa(); else bbb(); 

III Resultado da expressão


Usando expressões em condições:


 if (exp()) ... 

ciclos:


 foreach (exp() as $item) ... 

como parâmetros:


 foo(exp(), ...) 

e retornar resultado:


 return exp(); 

não apenas torna o código "mais denso", facilitando a compreensão, mas também torna a depuração mais difícil - você não vê os valores de execução das expressões na lista de variáveis ​​do depurador. Eu tenho que adicionar relógios (uma pergunta interessante, e se você monitorar os geradores através de relógios, isso afetará a execução do programa? ).


A opção ideal é uma variável temporária:


 $exp = exp(); if ($exp) ... 

II Muitos pontos de saída


Muitas vezes me deparei com a recomendação de ter apenas um ponto de saída da função e muitas vezes me deparei com uma violação dessa recomendação (um exemplo inventado, mas típico):


 public function onEvent($event) { if($event == 'entrance') { return 'entranceRoute'; } else if($event == 'exit') { return 'exitRoute'; } return 'defaultRoute'; } 

Aqui está uma opção mais correta:


 public function onEvent($event) { $result = 'defaultRoute'; if($event == 'entrance') { $result = 'entranceRoute'; } else if($event == 'exit') { $result = 'exitRoute'; } return $result; } 

É isso, não preciso dispersar pontos de interrupção em cada return ou fazer um passo a partir da primeira linha (se o código de chamada me der a oportunidade de ver o resultado em uma variável separada) para entender como a execução foi concluída. Imagine uma função com 120 linhas e 22 retornos dentro? E eu mesmo debati isso e suspeito que esse não seja o limite.


I. Chamadas de método em cascata


Meu favorito é o método em cascata :


 $collection ->addFilterByProduct(...) ->addShowInStoresFilter(...) ->addPublicFilter(...) ->addApprovedStatusFilter(...) ->addCreatedAtLessThanNowFilter(...); 

Se eu precisar entrar no método addApprovedStatusFilter() , que é interface e implementado em várias classes diferentes (uma classe específica é determinada em tempo de execução), a coisa mais simples é definir um ponto de interrupção em $collection e addFilterByProduct tudo por sua vez ( addFilterByProduct , addShowInStoresFilter , addPublicFilter ) até o lugar certo. Se você combinar isso usando expressões nos parâmetros e nos resultados retornados, o caminho ficará completamente fechado. No original, esse código fica assim:


 $collection ->addFilterByProduct($this->getProduct()) ->addShowInStoresFilter($this->_storeManager->getStore()->getId()) ->addPublicFilter() ->addApprovedStatusFilter() ->addCreatedAtLessThanNowFilter(); 

Sim, com métodos em cascata, o código se torna mais legível, mas o débito se torna mais difícil. Não tenho nada contra a cascata de set'er (como regra geral, não estrear setter):


 $answerModel ->setAuthorName(...) ->setStatus(...) ->setCreatedAt(...) ->setAuthorEmail(...) ->setCustomerId(...) ->setHelpfulness(...) 

Mas o código que contém a lógica que pode ter que ser debitada, ou talvez sozinho, é melhor escrever " old school " (eu mesmo faço isso):


 $collection->addFilterByProduct(...); $collection->addShowInStoresFilter(...); $collection->addPublicFilter(...); $collection->addApprovedStatusFilter(...); $collection->addCreatedAtLessThanNowFilter(...); 

Tornou-se muito mais difícil perceber?


Ou aqui estão as recomendações para um bom estilo de programação:


 ladder.up().up().down().up().down().showStep(); 

Veja isso do ponto de vista de um integrador, que deve entrar no segundo nível.


Sumário


Não quero dizer que essas técnicas sejam usadas em seu código por " alienígenas ". De modo algum, na maioria das vezes, eles visam reduzir a quantidade de código. Mas essas técnicas complicam a depuração. Uma pessoa não tem a velocidade de um computador e, para alcançar o código do problema, o integrador deve primeiro verificar (não entender, ou seja, verificar) o progresso do programa nos pontos principais. Tudo isso, tendo por um lado a tarefa de melhorar o entendimento do código, de fato, durante a depuração, esse entendimento é prejudicado. Eles interferem não no local do código, mas interferem no acesso à área do problema, que, em geral, precisa de um entendimento real.


Isenção de responsabilidade


O precedente é o resultado de deformação profissional pessoal e pode diferir das opiniões baseadas em outras deformações profissionais.

Source: https://habr.com/ru/post/pt442892/


All Articles