新手程序员的恶习:不了解自己调用的API

本文约 1100 字,阅读需 3 分钟。

新手程序员的恶习:不了解自己调用的API

记录了自己在第一个需求灰度后的一些感受。 在自己的第一个需求灰度后,发现Crash率严重超标,虽然排查之后发现主要是其他人合入的需求导致的,但也确实发现了两个自己导致的Bug,由于触发Bug的条件比较极端(见下文),所以测试并没有发现。

问题一:未Catch异常

第一个错误是在读取配置的时候如果没有配置会返回null,而自己的代码:

    ...Integer.valueOf(Settings.get(key))...

并没有处理这个NumberFormatException,导致出现了Crash。由于这个操作是在退出APP的时候执行的,而从后台拉取配置则是APP启动时执行,所以必须在启动之后(拉取到配置之前)立即退出APP,这种情况很难触发,但是客观存在。

问题二:胡乱设置参数

背景是需要通过Apk包名获取对应APP的名称和图标,当时参考了StackOverflow后通过如下代码实现:

        PackageManager pm = getPackageManager();
        try {
            PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
            if (packageInfo != null) {
                ...packageInfo.applicationInfo.loadIcon(pm)..
                ...packageInfo.applicationInfo.loadLabel(pm).toString()...
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

测试的时候也没有发现问题,结果灰度后发现一个TransactionTooLargeException,经过排查以后发现是因为PackageManager.GET_ACTIVITIES这个参数会导致大量数据(包名对应APP的全部Activity信息)返回,超过Binder的限制(1M左右)。一般的APP都不会(但QQ这种Activity较多的就有可能),所以灰度了几万用户后也只发现了一例,但这里其实反映了两个问题: 1、测试人员有义务对这种极端情况(边界)测试,但实际没有。 2、自己作为开发,并没有取仔细阅读这部分的文档,没有弄清楚getPackageInfo第二个参数(flag)的含义。 其实自己只是需要APP的名称和图标,使用pm.getApplicationInfo(packageName, 0)即可,而上面的实现虽然也能达到目的,但是参杂了大量冗余,增大了出Bug的风险。

总结

第一个问题是非常低级的错误,第二错误是因为自己只追求结果而忽略了过程。以前大学有门生产实习课我觉得很水,但有一句话我一直记着:(上下文是老师的一个同事因为Copy开源代码导致一个复杂的Bug,进而影响项目进度,带来经济损失)就算是Copy也要知道自己Copy的每一行代码是什么意思。学生时代,总是急于实现功能,一些极端情况往往没有场景来触发(因为没有大量用户),导致不够重视代码的鲁棒性;另一方面,浅尝辄止,没有全面深入了解自己使用的API、API背后的原理,导致一些奇怪的问题。 希望自己引以为戒。

总阅读量次。