集成商眼中的面向调试的编程或悲伤

碰巧的是,在过去的几年中,我一直在缝制科学怪人,而不是雕刻可爱的牧羊犬和烟囱的陶瓷小雕像。 我基于Magento 2创建解决方案。这意味着我的原始资料是任何考古学家的梦想。 具有各种“时代”和“文明”痕迹的文化层。 它可以用来研究过去十年来PHP / JS社区中程序员思想的发展。


并且这仅仅是基础,并且外接程序是需要集成在其中的第三方模块。 在这里已经有可能遇到外星智能的表现。 有些模块是由发达的生物创建的,其思想与基础的创造者非常相似,但是您遇到了那些想要抓住作者的肩膀,深深地注视着他的眼睛,并以友好的方式问道:“ 您来自哪个星球,本机?


图片


调试器可帮助从此类材料中缝制科学怪人。 下面是我个人的顶级编码技术,它会使像我这样每天使用调试器的人的生活变得复杂。 它很小,有四个位置,但是每次调试时遇到这样的事情,我都会感到难过。 也许我的帖子会减少世界上的悲伤人数,或者也许不会。 我至少会尝试。


混淆和代码加密


这是出于竞争。 我遇到了几次需要ionCube才能工作的模块,我可以说我要做的最后一件事是在项目中放置一个类似的模块。 我完全支持JS代码的精简,尤其是当附近有普通的源代码时,但是混淆和加密却是一种浓缩的,浓缩的邪恶。 我是作为集成商告诉您的。


IV。 单行代码


保存代码行是我列表中最无害的:


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

在程序的逐步执行过程中(该条件的计算,执行truefalse分支)在该行上挂两步。 没关系,您只需要记住在此行执行了一次遍历的次数,并在变量列表中跟踪$cond的值。 随着时间的流逝,自动机得到发展。


更糟糕的是,您不能在truefalse分支上设置无条件断点。 无需在IDE中单击即可,您将不得不使用鼠标/键盘稍长一些,从而添加了条件断点。


理想的选择是每个可执行步骤(条件, true -light, false -light)位于自己的行上时:


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

三, 表达结果


在条件中使用表达式:


 if (exp()) ... 

周期:


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

作为参数:


 foo(exp(), ...) 

并返回结果:


 return exp(); 

不仅使代码更“密集”,更易于理解,而且使调试更加困难-您只是在调试器变量列表中看不到表达式的执行值。 我必须添加监视程序 (一个有趣的问题,如果您通过监视程序监视生成器,这会影响程序的执行吗? )。


理想的选择是一个临时变量:


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

二。 许多出口点


很多次我遇到建议,只有一个退出功能的地方,而很多次我违反了此建议(一个发明的例子,但是一个典型的例子):


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

这是一个更正确的选项:


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

就是这样,我不需要在每次return分散断点,也不需要从第一行跳出(如果调用代码使我有机会在单独的变量中查看结果)来了解执行是如何结束的。 想象一下一个包含120行和22个内部返回的函数? 我自己对此进行了辩论,我怀疑这不是极限。


一,级联方法调用


我最喜欢的是方法级联


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

如果我需要进入addApprovedStatusFilter()方法,该方法是接口并在几个不同的类中实现(在运行时确定特定的类),那么最简单的方法是在$collection上设置一个断点并依次检查所有内容( addFilterByProductaddShowInStoresFilteraddPublicFilter ),直到正确的位置。 如果使用参数中的表达式和返回的结果将其组合在一起,则路径将变得完全不闭合。 原始代码如下:


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

是的,通过级联方法,代码变得更具可读性,但是对它进行借记变得更加困难。 我对设置者的级联没有什么反对(通常,我不会登场的设置者):


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

但是包含可能需要借记甚至是我自己借记的逻辑的代码最好写“ 老派 ”(我自己做):


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

是否变得更加难以感知?


或者以下是关于良好编程风格的建议


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

从集成商的角度来看这个问题,他应该down第二个问题。


总结


我并不是说这些技术在“代码”中被“ 外星人 ”使用。 完全没有,相反,它们的主要目的是减少代码量。 但是这些技术使调试变得复杂。 一个人没有计算机的速度,并且为了获得问题代码,集成商必须首先在关键点扫描(不理解,即扫描)程序的进度。 以上所有这些,一方面具有提高对代码的理解的任务,实际上,在调试期间,这种理解受到阻碍。 它们不会干扰代码的位置,但会干扰到达问题区域,这通常需要真正的理解。


免责声明


以上是个人专业变形的结果,可能与基于其他专业变形的观点有所不同。

Source: https://habr.com/ru/post/zh-CN442892/


All Articles