编写明显没有错误的代码

昨天公司的技术微信公众号贴了一篇关于怎么检索一天全部订单的SQL的写法问题。相似: SELECT order_no FROM orders WHERE create_time >= '2015-04-07 00:00:00' AND create_time <= '2015-04-07 23:59:59',文中提到这种写法是有问题的,可能有部分订单落在最后一秒(create_time是Timestamp类型),这样在进行对帐等环节可能带来很隐藏的bug,很难被发现。文中还给出了MySQL中的方案推荐这样写 SELECT order_no FROM orders WHERE create_time >= '2015-04-07 00:00:00' AND create_time < '2015-04-08 00:00:00'。数据库

就这么个问题在吃饭的时候和几个同事进行了热(面)情(红)洋(耳)溢(赤)的讨论。有同事说他会在传给SQL的参数的截至时间拼接上.999。也即把毫秒数给拼接到截至时间里,这样就能『正确地』查询当天全部订单了。看起来是正确的,由于就目前主流的MySQL版本(5.5, 5.6。5.5版本Timestamp精度支持到秒,5.6版本支持到毫秒)是能把一天的全部时间都包括。当时咱们表示拼接上.999难以理解,这就至关于咱们常说的magic number同样,会给维护代码带来障碍。你们以为使用create_time >= '2015-04-07 00:00:00' AND create_time < '2015-04-08 00:00:00'更无歧义一些。不过这位同事给了另一个理由:由于他在使用SQL定义时间范围的时候更习惯使用btween ... and ... 。好吧,若是这也算是一个理由的话。性能优化

不过这让我忽然感到有点羞愧:我竟然不知道between ... and ...表示的是开开,开闭,闭开仍是闭闭区间。在询问了几个同事,都吞吞吐吐表示是闭闭区间,甚至有位同事还去查了下MySQL官网以后,我以为SQL的btween ... and ...设计得真扯淡。使用between ... and ...比添加.999更恶劣,由于这让我这个不知道这个区间的人感到羞愧,最起码我还知道.999是毫秒。人在被人弄得羞愧后第一个反应就是义正词严的进行反驳,以隐藏这种羞愧感。在思考了几秒钟后我反驳道使用between ... and ...很差,不推荐使用。若是你想来描述一个区间范围的话用大于等于,小于等于这样的方式会让代码更让人容易理解(好比,create_time >= '2015-04-07 00:00:00.000' AND create_time <= '2015-04-08 00:00:00.999',虽然我不想认可加.999是对的),代码更易读,由于就算不知道between ... and ...实际区间含义的人都知道这是什么意思(说完这句话,个人羞愧感大大下降了,甚至有点骄傲的感受)。微信

可是,在我骄傲的时候,这位同事给我当头一棒:你不记得between ... and ...是你的事,可是我记得啊,我第一次看到between ... and ...的时候我就决定用她了,由于范围的意思就是between ... and ... 。言下之意就是between and就是范围,范围就是between and是多么【天然】的一件事情。其实我挺喜欢天然这个词的。在恼羞成怒的状态下,我抛出了杀手锏:你知道Junit的assert方法第一个参数是actual仍是第二个参数是actual么?(画外音:由于Junit的这些只有两个参数的assert方法,两个参数类型是同样的,我每次使用的时候都搞不清楚第一个是actual仍是expected,若是用错最后的错误提示也是反的,幸亏Junit如今提供了assertThat的方式)。可是他竟然记得,他果断地说第一个是expected,第二个参数是actual。看来记忆力很差是硬伤,世上总有些人比你记忆力好,他们记得全部东西,因此千万不要跟他们拼记忆。并发

那么说了这么多我想表达什么呢?我可不是为了吐槽我那可怜的记忆力的。其实上面两个例子只是想说,咱们在编写代码的时候,应该时刻记着如何编写明显没有错误的代码。在性能没有量级的不一样以前,咱们更应该编写明显没有错误的代码(好比刚才那个查找一天订单的问题我以为SELECT order_no FROM orders WHERE create_time like '2015-04-07%'是个更直观的写法,可是这种写法可能性能很差,因此只能做罢)。明显没有错误的代码就是即便别人来维护这个代码的时候缺乏一些上下文信息(好比当前数据库使用的是什么精度,或者某方面的知识)都能很容易判断这个代码表达的是什么意思,由于当前他所看到的代码就是全部的上下文,没有其余隐藏的。咱们在编写代码的时候必定要记着咱们不是一我的在战斗,你的代码除了机器执行外会有更多的人来阅读和修改。在我看来SQL的between ... and ...和Junit的assert序列方法都是反面教材,他要靠人们对某些知识的记忆才能理解,但人的记忆又每每很不靠谱,就这样bug就出现了。即便在有些地方咱们须要进行性能优化,可能把一些代码给弄得比较难以理解,那么咱们也应该将这样的代码范围控制好,局限在某个部分。好比咱们将这样的代码封装到一个类里,而不是分散到各个地方,而且咱们用类名,用方法名,再不济用一些注释向后来者述说着这里曾经的故事。高并发

后记

大部分开发人员(包括我本身),可能对性能优化更感兴趣。好比常见讨论方式是:这个地方我去掉了一个锁,那个地方我减小了多少内存,性能提升了多少多少。而不多见到这样的讨论:这个地方我修改了一个方法名那个地方我修改了一个变量名,如今个人代码更易懂,更【形象】起来了。其实在一个工程化的环境中,性能是否是重要呢?固然重要,但不是最重要的。而代码质量才是提升总体效率,下降故障率更有效的途径。并且更加讽刺的是,每每咱们的性能到了须要优化的时候了,可是由于代码实在太糟糕而不知道如何优化,由于看不懂,不敢改。各个地方各类隐藏的上下文,各类歧义代码让性能优化难于上青天。你以为修改这个地方好像没有问题,可是等你修改以后一个故障就开始了。性能

还有一些开发人员可能比较喜欢遵循本身固有的一些习惯。诚然,每一个人都有一些习惯,多是很早以前在某个角落看到一段什么话,而后就记下来了,后来一直遵循着这种习惯,可是又说不出真正什么理由(嗯,就是喜欢)。可是,咱们在遵循这个习惯的时候,也要想着这是个人习惯,不是别人的。这个代码有没有更好的写法呢?全部人一看就知道是这个意思的代码或许比习惯更重要。优化

因此对我来说,我虽然也很热衷性能优化,喜欢研究一些所谓的高并发高性能,可是我更想把个人代码写得【漂亮】,让别人维护起来的时候更容易看懂。编写明显没有错误的代码不是一件很LOW的事情,虽然逼格不高。设计

相关文章
相关标签/搜索