▶关于做者:张帆(Zachary,我的微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描右侧的二维码~。
按期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。
若是这是第二次看到个人文章,欢迎右侧扫码订阅我哟~ 👉html
本文长度为4818字,建议阅读13分钟。程序员
坚持原创,每一篇都是用心之做~windows
这是一篇半娱乐性的吐槽文章,权当给广大技术人员解解闷:)。微信
哈哈哈,而后我要开始讲一个常常在发生的事实了。(程序员们可能会感到一些不适)网络
99.999999999%作技术的都会被问到或者被吐槽到:“你的程序怎么又出bug了!”架构
▲图片来源于网络,版权归原做者全部框架
反正,我做为程序员的心里世界是:如同一万只草泥马飞奔而过,难以压抑心里的激动,每次都差点忍不住想说“你写篇几百字的做文还有错别字呢,我码个几万行的代码还不容许出错了?“elasticsearch
可能一样是作技术的你此时在不断点头,哈哈。分布式
可是这么讲毕竟也缓解不了矛盾,咱们仍是得摆事实讲道理不是?工具
啥都不怕,就怕程序员有文化!
因此,Z哥想来带你好好分析一下这个事情,当你再遇到这个状况的时候,能够拿这些观点来反驳(不是作技术的也能够了解下程序员的难处,谁没个难处呢,多多包容)
任何一个「问题」的产生,自己是没有好坏之分的,可是为何会有的就不被care,甚至还会很喜欢,而有的会被吐槽呢?根本缘由是由于产生了利益损失。
好比年前拼多多出问题送了不少无门槛券。
做为一个用户,天然很喜欢,夸你夸到飞起,怎么会吐槽你呢。可是做为利益损失方,必然破口大骂,害我倾家荡产!
因此,若是没有产生利益损失,我想其余人也不会来找你吐槽。
可是「问题」就等于「bug」吗?我认为并非,「问题」不等于「 bug」。
由于程序员的职责是什么?拿造房子来比喻的话,我认为最核心的工做真的和“搬砖”(非贬义词)无异,就是根据设计师(产品经理)设计好的设计图砌砖(编码),建成和设计图纸上如出一辙的建筑。
因此,若是一个东西造出来与设计不符,那么它能够说是bug或者缺陷(缺斤少两不完整)。不然,并非bug,但能够被称之为「漏洞」(彻底没考虑到的),表示不在预料以内的状况。
以前看到过一个形象的比喻:你家里的窗能够从外面打开,那叫漏洞。你家里的窗打不开,那叫bug。
可是要认可,bug是必然存在的。为何?它是如何出现的呢?
正如前面所说,程序员作的是“造房子”的事情。这件事完整的步骤分为3步。
与产品经理讨论并肯定功能(肯定一个能够实现的设计图纸)
将每一个单独的元件抽象出来(肯定施工方案)
将相关的元件实现并进行组合,完成建设(带上材料开始施工)
第一步,“与产品经理讨论并肯定功能”主要是沟通,靠“看”和“理解”。
可是沟通自己是一个有损耗的过程,特别是在职责很是明确的组织中,产品经理啪啦啪啦讲了不少,到实际作的时候你必然仍是会去翻阅需求原型、需求文档之类的从新理解一下。这个时候就是一个很是危险的时期。
好比像下面这个的答案是什么?
▲图片来源于网络,版权归原做者全部
答案是17?不对。
我猜你可能没注意到这些地方。
▲图片来源于网络,版权归原做者全部
为了让你有深入的印象,这个举例可能比较刻意和夸张一些,可是我想在你的身边,因为没注意到或者理解有误的现象确定很常见。
沟通是相互的,这锅只让程序员背的话的确太委屈了点。
第二步,“将每一个单独的元件抽象出来”这主要是一我的抽象能力的体现。
可是抽象是啥?抽象是“透过现象看到本质”的能力,这个能力理论上是能够无限增加的。随着你对相关信息的掌握越多,这个能力会越强,会无限趋近于100%,但永远不会真正达到100%,由于没人知道怎么才算100%。
因此,当你具有的信息没那么多的时候,是否是就抽象的不是那么合理?不合理会致使什么?虽然不会直接产生bug,可是会更容易产生bug。可是人不都是须要经历这么一个成长的过程么?
能够说,精通一项能力的背后都是踩着无数的bug过来的。要么在来这个组织以前已经踩过了,要么在这个组织里踩。所以,前者的薪资也比后者高。
因此,若是过度苛求没有bug,等因而在扼杀每一个人成长的机会,而且在透支将来的可能性。人会变得很是保守、不敢尝试新事物。
可是外部环境在不断变化,新事物总会被动的须要去接纳(技术的更新愈来愈快,趋势不可逆),然而对新事物的接受能力又得不到锻炼,一旦遇到这种状况,在接触新事物的时候会产生更多的问题(欠下的债总要还的)。
第三步,“将相关的元件实现并进行组合,完成建设”这就是实际的coding过程,而coding是一个主观的,彻底由人主观掌控的事情。
人毕竟不是机器,不可能不犯错,就如前面提到的写文章的时候出现错别字同样。
可能你会说,有测试人员啊,测试的工做不就是经过逆向思惟来给程序员查缺补漏吗?
的确是的,但测试的介入只是下降错误率,只是让不出现bug的几率小数点后多几位
,期望发现100%的问题仍是不太现实的。至少在当下的条件下是这样,为何呢?由于代码的本质是各类逻辑的组合。
好比,一个完整的业务流程有10个环节,每一个环节有3种可能性,这是一个什么复杂度的系统?3 ^ 10 = 59049个分支(理论上存在的可能性数量),想要100%覆盖这些场景,付出的成本几乎是不可接受的。
然而咱们实际的系统中遇到的个别场景甚至还要复杂的多。
其实每一个正在运行的系统都有bug,包括咱们天天在使用一些热门系统(玩游戏的小伙伴们确定熟悉“卡bug”这个词)。只是这些bug有没有被执行到,有没有被发现,被多少人发现而已。
那么,咱们只能举手投降吗?那倒不至于,办法仍是有的。
首先最容易想到的一点是,增长测试人员。
这也是最容易看获得的“成本”一种方式,毕竟招一我的就得支出一份工资啊。因此,增长测试人员这个方案是最不容易被老板们采纳的方案。除非你能够说服这我的力成本的投入小于得到的价值。
另外,这个方案其实还增长了沟通成本,沟通的「隐性成本」其实很是大,可是每每容易被忽略。(关于沟通成本,感兴趣的能够看我以前写的《就简单聊聊沟通效率问题》)
其次会想到的就是程序员代码写的严谨一点,仔细一点啊。这也是一种缺啥补啥的惯性思惟。
先撇开到底能不能达到严谨一点,仔细一点的目的。那怕达到了,他会产生什么结果呢?多是下面3种。
更多的条件验证
更多的单元测试
更多的抽象提炼
能够肯定的是,这些工做会增长2样硬性的东西,投入的时间和总体的复杂度。时间很好理解,咱们就来聊聊复杂度。
一个常识是,越简单的东西越不容易产生bug。好比1+1=2,出现bug的可能性无非就是加号写成来减号,1写成了4之类。可是,1+1=2,而且1*1=1,而且1/1=1,。。。等等这些验证条件越多,那么因为验证条件自身的错误而产生问题的可能性反而更多。
因此,代码的复杂度和产生bug的几率是成正比的,而且具备「边际效用递减」的效果。这就意味着,作更多的验证带来的收益会愈来愈小。
所以,这个方案哪怕真能执行到位,也不是一个特别好的方案。
那有没有相对靠谱一些的办法呢?有,但须要咱们换一个角度来看待这个问题。
既然没法100%避免bug,那咱们能够换个角度考虑一下,如何让解决bug的过程更快,甚至快到你都没有察觉。
解决bug主要就是作2件事,找到bug的产生点,而后修复它。
天天都在解决bug的程序员们应该知道,这事最费时间的是“找bug”的过程。
由于“修复bug”是一个技术性问题,这个对不一样人的差别实际上是很小的,由于程序员们天天在写的代码都是差很少的,很是同质化的,何况还有标准答案“文档”能够参考。好比,都知道string.concat()是拼接,string.split()是分割。该用分割的地方不当心用了拼接,那改掉就好。
可是“找bug”就不是这样了。好比,你刚刚改完一行代码后发布出现的问题,你不用找就知道问题出如今哪。可是让你排查一个刚接手没多久的系统确定是一脸懵逼。
根本缘由在于,这个过程不像技术性问题具备肯定性,它是充满不肯定性的,处在一个“混沌”的环境中。
因此,对待bug的重点就变成了:如何更快的发现和找到bug。
关于这点Z哥的建议是:
打好日志
学会利用工具
每次的迭代规模尽量的小
首先,打好日志。日志其实就是咱们在编码的时候安插在程序中“记录员”,它替咱们记录着咱们认为容易出现问题的地方所产生的信息。
可是系统无时无刻都在运行着,必然会产生大量的日志信息,如何从这些信息中快速的找到关键信息,就是须要考虑的问题。
另外,若是每一个人都随意的用本身喜欢的记录日志的方式,那么从风格迥异的日志中找你须要的信息就变得很头疼,时间不一致,格式不一致等等。
因此,要作好打日志这个事情,就须要定义一个标准,好比必需要有时间,包含当前上下文的参数等等。
咱们还能够给日志作一下归类,定义不一样的日志级别,在记录的时候带上前缀。好比【info】、【warning】、【error】之类。如此一来,平时更着重关注的就是error级别的信息,并且因为将其余级别的信息剥离了出去,使得这里的数据量大大减小,更便于查看。
不过,日志记录毕竟是一个在作“预判”,若是日志中没有记录到怎么办呢?这里提醒你们不要先想着怎么调试。
若是你面对的系统是一个单体应用倒还好。若是你面对的是一个大型的分布式系统,调试的效率低不说,这事你一我的可能还完不成。并且,若是你直接调试生产环境的话,说不许还会产生什么反作用,摊上新的问题。
找bug本质上是一个排除法的过程,设断点调试也是如此。可是从起点开始一步一步的作排除法效率过低了。应该先经过本身的经验、拥有的部分信息先逻辑推理一下,缩小排查的范围。哪怕你最终仍是须要调试的话,先作这个事情也会让后续的工做更高效一些。
第二点,利用工具。这里的“工具”不要简单的理解成利用“调试工具”。正如上面提到的,找bug的本质是一个排除法的过程,那么任何可以帮你更高效的作排除法的工具都是能够利用的。好比,
从系统的「事件查看器」中获取更多的环境信息。
利用windows平台的windbg、lunix平台的MAT之类的工具直接分析抓到的dump文件。
借助可视化工具更高效的发现问题,如FlameGraph等。
另外,若是能主动的告诉你哪里出现bug了,就更棒了。因此,咱们能够搭建一套查看方便,信息同步及时的日志框架,以便让有价值的信息第一时间呈如今你的面前。若是有高效的筛选功能就更好了。
不少日志框架Z哥没用过,就不发表什么言论了,可是elasticsearch + logstash + kibana这套用起来仍是很爽的,体系也比较成熟,部署起来也很简单,你们能够尝试一下。再配上ElastAlert或者Sentinl,能够把实时预警机制也包含了。
最后,每次的迭代规模尽量的小。这个提及来容易,作起来难,由于这是由整个团队的文化来决定的。这个点的内容彻底能够单独开一篇讲,这里就简要阐述下。
MVP(Minimum Viable Product)式的小步快跑,其实除了让系统或者产品的功能演进更科学以外,还可让每次迭代所面临的风险更小。正如前面提到的,你改一行代码发布上去,若是出问题,你说问题在哪?
相对的,再想象一下,一次性发布一个开发了半年的版本,前一晚能睡的安稳不?
好了,咱们总结一下。
这篇呢Z哥先阐述了我对“什么是bug”的理解,而后分析了bug是如何产生的,以及咱们可能会作的一些惯性选择。
最后给你的建议是,以如何更快的找到bug为出发点来考虑。经过「打好日志」、「学会利用工具」、「每次的迭代规模尽量的小」这3种方式来进行。
不过话说回来,虽然咱们没法避免出bug(一个项目开发完后没测出bug?你问任何一个技术人员都说“作梦呢”),可是争取让bug更少是咱们的本职工做。
由于对bug容忍度低的另外一层含义是,你们对系统的依赖愈来愈重,愈来愈多的事情在经过程序完成,而不是人力。
可是再有人咄咄逼人,就把这篇文章丢给他!
相关文章:
做者:Zachary
出处:https://zacharyfan.com/archives/657.html
若是你喜欢这篇文章,能够点一下右下角的「推荐」。
这样能够给我一点反馈。: )
谢谢你的举手之劳。
▶关于做者:张帆(Zachary,我的微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描右侧的二维码~。
按期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。