事情的来由还要从几十几亿年前的一次星球大爆炸提及,sorry,背错台词了,是从几天前讨论接口返回数据和几个月前讨论课件本地数据结构提及,简单的说,就是碰到约定好的内容出现异常,是咱们在程序中内部做兼容处理,仍是抛出去。前端
打个比方,咱们要解析一段json,约定这个json的格式,只能是正常格式,或者是空,那么一旦返回json的方法返回了一个『既不是正常格式,又不是空的异常值』,程序该如何处理呢?编程
小花:一旦碰到约定异常,程序必须兼容处理,必定不能让程序Crash
小Fa:一旦碰到约定异常,就必须抛出去,告知约定有误,找出具体错误缘由json
这个问题,相信只要是程序猿基本都遇到过,举个最多见的栗子,NullPointerException,假如咱们要从json中取一个字段,忽然发现发生了NullPointerException,一些开发者认为是数据问题,那么把json中的这个字段改正确就好了;还有一些开发者认为是程序问题,认为程序须要作非空判断,再去使用。我相信这两种程序猿都有本身的理由,第一种程序简洁明了,代码逻辑干净,但一旦出错,就会崩溃,第二种程序耐操,随你数据怎么错,我都能不Crash,但代码中处处存在非空判断,臃肿、重复。后端
生存仍是毁灭,这是一个问题!安全
就在咱们为了这个问题而争论的时候,忽然有一个姓康的同事,施法祭出了一块砖头(《代码大全2》,近900页,至关于3本《Android群英传》),我一度觉得他想砸在个人脸上,正当我准备闪避的时候,他翻到了这块砖头的第八章,几个大字赫然印入了个人视线——『防护式编程』。数据结构
果真是老司机,竟然能够从防护性驾驶中悟出防护性编程,说好的编程不开车,开车不编程呢?编程语言
这位做者编程厉不厉害我不知道,但我知道,论开车,必定没有何老师diao!ide
OK,《代码大全》给咱们提供了一个定义——『防护式编程』,说白了,就是『人类都是不安全、不值得信任的,全部的人,都会犯错误,而你写的代码,应该考虑到全部可能发生的错误,让你的程序不会由于他人的错误而发生错误』函数
在书中,做者告诉咱们,程序须要对可能的错误输入,作出兼容,例如一个除法的函数,你必须判断分母可能为0的状况,从而给调用者返回错误提示。另外,通常的高级编程语言,都提供了『断言』和『异常』两种方式来进行错误处理。编码
断言,是一种在开发阶段使用的,让程序在运行时进行自检的代码,断言为真,那么程序运行正常,断言为假,那么程序运行异常退出。等等,防护式编程不是说好的要兼容异常吗,为何会退出?实际上,做者的意思是,先断言、后处理错误,而断言是在开发环境中的,正式上线后是不会有断言的。
但实际上,这是一个悖论,开发阶段的错误处理代码在开发阶段被断言给拦截掉了,但错误处理代码也是人写的,那么如何去检测『错误处理代码可能发生的错误』呢?
当代码出现问题时,能够经过抛出异常来进行通知,若是你没法处理,则能够交给外界进行处理。这个很少说,毕竟大部分代码,若是有异常,最简单的就是try catch了,我甚至见过把因此代码直接try catch的,你是有多不相信人类。
因此我以为防护式编程用久了,会不会开始怀疑人生,果真,在日后翻几页,做者也给出了建议。
借用奇异博士的一句台词——『你TM竟然把警告写在咒语的下一页』!
简而言之,防护式编程,就是持怀疑态度审视全部的代码,但这个和咱们讨论的主题仍是略有不一样的,咱们讨论的主题是『已经有了约定,但返回了约定以外的内容』。
就在咱们讨论的时候,天空忽然飘来五个字——那都不是事,哦不对,是『契约式编程』。
这个好像有点像!咱们先来简单的看下什么是契约式编程,简单的说,契约做用于两方,每一方都会完成一些任务,从而促成契约的达成,但同时,每一方也会接受一些义务,做为制定契约的前提,有任意一方无视了必尽义的义务,则契约失败。
契约式编程要求咱们在『前提条件』、『后继条件』和『不变量条件』进行契约的检查。相似的,例如检查参数,一旦参数不对,立即撕毁契约。这一点,如今不少新的语言都支持了,例如Swift,就支持对参数进行约束检查,这就是一种类契约式编程。
契约所约束的,是『一个为了确保程序正常运行的条件』,一旦契约被损毁,只有一个缘由,那就是程序出了Bug,例如一个数据字段,在我处理的时候,必须保证是不为空的,那么谁来保证这一点呢,必定是个人调用方(或者说是其它模块),因此,一旦出现问题,应该有调用方来检查,确保调用的时候,必须是不为空的。
这让我想到了刚开始在面向日本人编程时期的一些事,日本人的作事风格是出了名的谨慎和详细,每个方法、函数,在详细设计的时候,就已经把参数、返回值,已经它们的类型和全部可能的值都设计好了,每一个方法之间有着明确的界限,若是你的方法由于传入的参数不在设计范围内而致使错误,你彻底能够去找调用方,要求他按照设计来进行调用。不得不说,这应该是契约编程的最佳实践。日企广泛使用这种方式其实还有一个缘由,那就是能够严格区分责任,让每一个人都没必要为了迁就他人的错误而进行『艰难的编码』。每一个人按照契约处理好本身的事情,让损毁契约的人承担责任。
再引伸一下,这和如今的『面向接口编程』也很是相似,两个模块之间,定义好调用、处理的接口,而具体的实现,对方都不用关心,只要安装协议的接口来进行开发就能够了,但光有接口也不够,还须要契约来作进一步的约束,例如参数、返回值的约束。
无独有偶,在《代码大全》中,做者也提出了『进攻式编程』,其实和契约编程,有殊途同归之妙。
OK,梦醒了,让阳光照进现实。以上两种编程方式,都是很是理想化的编程,但在通常的公司里面不管是防护仍是契约,实现起来都是比较困难的,例如前端与后端的接口、不一样部门同事的交流,按照契约式编程,没人Care你的契约,按照防护式编程,代码惨不忍睹,还容易漏掉防护。那么到底该怎么办呢,我认为,若是能在公司层面推广契约式编程,首先是对开发效率的提高,让每一个人都对本身写的代码负责,在开发者之间创建良好的信任关系,同时也能减小没必要要的沟通成本和精力。但同时,必要的防护式编程也是不能少的,这是保证程序健壮、稳定的前提。怎么说呢,中国人民秉承了千百年的传统——『中庸之道』,契约仍是防护,视状况而定,这是平衡的艺术。
本文请使用防护式阅读,每一个人都会犯错,欢迎留言交流。
此文一出,颇有可能引起双方混战,红与黑,天灾仍是近卫,联盟仍是部落,Choose your side。
欢迎关注个人公众号: