Programación orientada a la depuración o tristeza a los ojos del integrador

Dio la casualidad de que en los √ļltimos a√Īos he cosido Frankenstein y no esculpiendo lindas figuras de porcelana de pastoras y deshollinadores. Creo soluciones basadas en Magento 2. Esto significa que el material fuente para m√≠ es el sue√Īo de cualquier arque√≥logo. La capa cultural con rastros de varias "eras" y "civilizaciones". Se puede utilizar para estudiar el desarrollo del pensamiento del programador en comunidades PHP / JS durante la √ļltima d√©cada.


Y esto es solo la base, y el complemento son m√≥dulos de terceros que deben integrarse en su interior. Aqu√≠ ya es posible encontrar manifestaciones de inteligencia extraterrestre. Algunos m√≥dulos son creados por criaturas desarrolladas, muy similares en pensamiento a los creadores de la base, pero te encuentras con aquellos que quieres tomar al autor por el hombro, mirarlo profundamente a los ojos y preguntar de una manera amigable: " ¬Ņ De qu√© planeta eres, nativo? "


imagen


El depurador ayuda a coser Frankenstein de dicho material. A continuaci√≥n se muestra mi t√©cnica de codificaci√≥n superior personal, que puede complicar la vida de cualquiera que, como yo, use el depurador a diario en su vida. Es peque√Īo, con cuatro posiciones, pero cada vez que encuentro algo como esto al depurar, me entristece. Tal vez mi publicaci√≥n reducir√° la cantidad de penas en el mundo, o tal vez no. Al menos lo intentar√©.


Ofuscación y encriptación de código


Esto est√° fuera de competencia. Encontr√© un par de veces con m√≥dulos que requieren ionCube para funcionar, y puedo decir que lo √ļltimo que har√© es poner un m√≥dulo similar en mi proyecto. Apoyo totalmente la minificaci√≥n del c√≥digo JS, especialmente cuando la fuente habitual est√° cerca, pero la ofuscaci√≥n y el cifrado son un mal destilado y concentrado. Te lo digo como integrador.


IV. C√≥digo de l√≠nea √ļnica


Guardar en líneas de código es lo más inofensivo en mi lista:


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

Cuelga dos pasos en esta línea durante la ejecución paso a paso del programa (cálculo de la condición, ejecución de la rama true o false ). Está bien, solo debe tener en cuenta cuántas veces realizó un paso en esta línea y realizar un seguimiento del valor de $cond en la lista de variables. Con el tiempo, el automatismo se ha desarrollado.


Un poco peor es que no puede establecer un punto de interrupción incondicional en la rama true o false . En lugar de un solo clic en el IDE, tendrá que trabajar con el mouse / teclado un poco más, agregando un punto de interrupción condicional.


La opción ideal es cuando cada paso ejecutable (condición, luz true , luz false ) está en su propia línea:


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

III. Resultado de la expresión


Usando expresiones en condiciones:


 if (exp()) ... 

ciclos:


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

como par√°metros:


 foo(exp(), ...) 

y devolver el resultado:


 return exp(); 

no solo hace que el c√≥digo sea "m√°s denso", lo que facilita su comprensi√≥n, sino que tambi√©n hace que la depuraci√≥n sea m√°s dif√≠cil: simplemente no ve los valores de ejecuci√≥n de las expresiones en la lista de variables del depurador. Tengo que agregar relojes (una pregunta interesante, y si monitorea los generadores a trav√©s de los relojes, ¬Ņafectar√° esto la ejecuci√≥n del programa? ).


La opción ideal es una variable temporal:


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

II Muchos puntos de salida


Muchas veces me encontré con la recomendación de tener solo un punto de salida de la función y muchas veces me encontré con una violación de esta recomendación (un ejemplo inventado, pero típico):


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

Aquí hay una opción más correcta:


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

Eso es todo, no necesito dispersar puntos de interrupci√≥n en cada return o hacer un paso desde la primera l√≠nea (si el c√≥digo de llamada me da la oportunidad de ver el resultado en una variable separada) para comprender c√≥mo termin√≥ la ejecuci√≥n. ¬ŅImagina una funci√≥n con 120 l√≠neas y 22 retornos dentro? Y lo discut√≠ yo mismo y sospecho que este no es el l√≠mite.


I. Llamadas de método en cascada


Mi favorito es el método en cascada :


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

Si necesito ingresar al método addApprovedStatusFilter() , que se basa en la interfaz y se implementa en varias clases diferentes (una clase específica se determina en tiempo de ejecución), lo más simple es establecer un punto de interrupción en $collection y revisar todo a su vez ( addFilterByProduct , addShowInStoresFilter , addPublicFilter ) hasta el lugar correcto. Si combina esto usando expresiones en los parámetros y los resultados devueltos, entonces la ruta no se cierra por completo. En el original, este código se ve así:


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

Sí, con los métodos en cascada, el código se vuelve más legible, pero debitarlo se vuelve más difícil. No tengo nada en contra de la cascada de set'er (yo, por regla general, no presento setters):


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

Pero el código que contiene la lógica que puede ser debitada, o tal vez incluso yo mismo, es mejor escribir " old school " (lo hago yo mismo):


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

¬ŅSe ha vuelto mucho m√°s dif√≠cil de percibir?


O aquí están las recomendaciones para un buen estilo de programación:


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

Mire esto desde el punto de vista de un integrador, que debería entrar dentro del segundo down .


Resumen


No quiero decir que estas técnicas sean utilizadas en su código por " extraterrestres ". En absoluto, en su mayor parte, por el contrario, están destinados a reducir la cantidad de código. Pero estas técnicas complican la depuración. Una persona no tiene la velocidad de una computadora, y para alcanzar el código del problema, el integrador primero debe escanear (no entender, es decir, escanear) el progreso del programa en puntos clave. Todo lo anterior, teniendo por un lado la tarea de mejorar la comprensión del código, de hecho, durante la depuración, esta comprensión se ve obstaculizada. No interfieren en la ubicación del código, sino que interfieren con el acceso al área del problema, que, en general, necesita una comprensión real.


Descargo de responsabilidad


Lo anterior es el resultado de una deformación profesional personal y puede diferir de las opiniones basadas en otras deformaciones profesionales.

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


All Articles