Bug描述

服务端返回的日期在某台测试机上总显示1970年1月1日。

Bug分析

这是一个非常典型的Bug,一方面这个Bug只在某台测试机出现,另一方面这个Bug算是“奇怪”代码的产物。

临近App版本发布,测试老师突然找到我说有一个诡异的Bug还没解决,如果我也解决不了就放弃了,毕竟只在某台手机上出现,而且是必现。我一听就知道这是一个非常典型的系统环境相关的Bug,我接触了太多这样的Bug了,第一反应先看看本机时间,时间是没问题的,然后又查了一下手机型号是港版,第二反应是不是时间格式化的问题,与 NSLocale有关,后来一看代码好像也不是。

但是看了一眼代码,我就发现这代码写的很“奇怪”,我心里就有数了,这个Bug又是一个非常典型的Bug了,一方面这个Bug只在某台测试机出现,另一方面这个Bug算是“奇怪”代码的产物。

来看一下具体代码:

这部分逻辑很简单,首先服务端返回的是YYYY-MM-dd HH:mm:ss格式的日期,而在客户端需要展示成YYYY/MM/dd,这里做了两个函数,一个负责将服务端返回的数据解析成时间戳,另一个又把这个时间戳格式成要展示的日期格式。就代码本身来说,完全是多余的,这部分代码很可能是从别处复制粘贴过来的,本身写作两个函数问题就很大,在这个场景下是没有意义的,然后参数传递的也有问题,即便是用时间戳来传递那也没有必要将时间戳转成NSString,然后再从NSString转回时间戳,这就是奇怪的地方。而且这里面根本没有时间戳什么事,直接传递NSDate即可。

因为问题必现,直接调试,运行到时间戳那一步就发现不对了,时间戳变成了负数,明显是溢出了,我的第一反应是时间戳太大了?然后再一看时间戳一个是long,另一个是longlong,这一层转换造成了精度丢失,再结合这台设备来看,就明白了。这台设备是32位的,在32位下long和longlong的精度不一样,但是在64位下精度一样,这就导致了数据溢出,时间变成了负数,格式化当然也就不对了。

总结

首先不要写奇怪的代码,如果直接用一个函数处理就不会出现这个问题了,另外不要做多余的工作,就算是写了两个函数,那也不必用字符串来传递时间戳,这里面额外做了两个多余的工作。最后,对于数据类型转换要慎重,这个问题抛掉不规范的地方,最终是因为数据类型转换过程中丢失了精度。归根到底是是对数据不太敏感,缺乏职业敏感。很多时候作为程序员都丢失了对数据的敏感,而程序的根本便是数据处理,如果对数据都不敏感了,又怎能写好程序?

Linus说过:

git的设计其实非常的简单,它的数据结构很稳定,并且有丰富的文档描述。事实上,我非常的赞同应该围绕我们的数据结构来 设计代码,而不是依据其它的,我认为这也是git之所以成功的原因之一。依我的观点,好程序员和烂程序员之间的差别就在于他们认为是代码更重要还 是数据结构更重要。