2015年,是移动领域新技术取得极大丰收的一年。
(一)Android篇
这里我不谈Google IO大会的各种新概念新思想,不谈Android 5.0和高逼格的Material Design,那些都是浮云,热闹过后,能沉淀下来用于App应用的干货并不多。我只谈这一年来,我认为Android技术界最激动人心的三件事。最后再聊一聊八卦。
首先是插件化技术的百家争鸣。在此之前,关于Android插件化的介绍凤毛麟角,Android程序员即使想去研究也无从下手。2015年,几家大的互联网公司陆续开放了自己的插件化编程的项目源码,值得注意的是,各家的实现思想还都不同,各有特色。
1)DL插件化体系
第一个要介绍的是DL插件化框架,GitHub地址为:https://github.com/singwhatiwanna/dynamic-load-apk。
这个框架早在2014年3月就在Github上了,直到2015年才基本稳定下来,开始有越来越多的Android开发人员关注这个项目。它是由“民间”三位Android开发者共同研发出来的,分别是任玉刚、田啸、宋思宇。
这个项目的特色是,通过宿主程序中一个叫做proxy的Activity,去调用插件中的Activity。
以下图片摘取自任玉刚的博客,形象的表达了DL的核心思想:
抄底好时机【这3股】可增持
牛人直播揭秘,送独家赚钱战法, 【免费加群】跟对牛人,l轻松盈利!
DL框架面临两个棘手的问题:
首先是通过proxy调用插件中的Activity,那么插件中的Activity就是一个普通的类了,不再具有原有的生命周期,为此需要重写插件中的Activity的所有生命周期方法,proxy手动去管理插件中每个Activity的onCreate、onResume这样的方法。
其次是插件中的资源,不能再通过R来访问,为此要重写Context中的getAssets方法和getResources方法。
DL框架最有名的发明创造。莫过于that语法了。在插件中,我们将尽量使用that关键字来替代this。
DL目前还有很多不完善的地方。但据我所知,已经有大型移动互联网公司的Android插件化体系就是基于DL的。
2)Fragment系
https://github.com/mmin18/AndroidDynamicLoader
早在2012年7月,就有大众点评的屠毅敏在Github上发布了一个名为AndroidDynamicLoader的开源项目,这应该是第一个Android插件化的项目,它的亮点在于大规模的使用Fragment来代替Activity。所有的Fragment都运行在一个Activity上,从而在Manifest文件中只事先声明这个Activity就够了,这样就避免了每次新增一个Activity都要修改Manifest文件的尴尬。
2015年也有类似的一款基于Fragment的插件化框架问世,详情请参见以下地址:
博文介绍:http://blog.csdn.net/sbsujjbcy/article/details/47060211
Github下载:https://github.com/lizhangqu/CorePage
3)阿里系插件化体系
阿里其实几年前就在搞插件化编程了,代号为Atlas,只是2015年才把这套技术公布于众。先是命名为OpenAtlas,然后改名为ACDD,最后不知道为什么又把GitHub的地址改为ACDDExtension——其实这3个项目是一回事,相关地址请参见:
OpenAtlas:http://blog.csdn.net/column/details/openatlas.html
ACDD:https://github.com/bunnyblue/ACDD
ACDDExtension:https://github.com/bunnyblue/ACDDExtension
Atlas的亮点在于对R进行分区,从而确保资源相互独立互不冲突。为此,把功夫做足在aapt这个命令层面,需要额外修改aapt中的逻辑,以确保资源分区没有问题。
4)携程
https://github.com/CtripMobile/DynamicAPK
携程的插件化思想和阿里的Atlas有很多相同的地方,由此可见这是一套通用的技术解决方案,所谓的“正统思想”,主要包括以下几点:
1.aapt上的改造
2.gradle上的改造
3.资源ID分区
4.修改Context的getAssets方法和getResources方法,解决R文件的读取问题。
5)对插件本身没有限制的新思路
https://github.com/houkx/android-pluginmgr
看惯了前面的各种插件化技术,细心的朋友是否发现,我们对插件做的太重了,比如说要遵守各种人为的规定,重写aapt指令,资源分区,that语法等等。
这个世界总是太浮躁,让我们静下心来做减法,闭上眼睛思考我们究竟想要什么,而不是各种跟风。是否可以搭建这样的一个Android宿主程序,它可以把任何未经安装、默默躺在SD卡上的apk程序都作为插件加载进来。这样就降低了插件编写的难度。
本篇要介绍的pluginmgr就是这样的思想,作者在试图搭建这样的一个万能的Android宿主程序。
pluginmgrd的核心思想有2点:
一是把插件中所有的Activity都动态生成一个相对应的PluginActivity。启动插件的某个Activity时,先找PluginActivity,再找对应的Activity——所谓的依赖反转的思想。这就不需要把插件中的Activity还要在宿主中的Manifest文件中注册。
二是在启动插件的Activity时,不是通过自己写程序手动去new一个Activity,而是由Android系统来new这个Activity。我们将宿主的ClassLoader替换为FrameworkClassLoader。
注意,所有的插件apk都是不需要安装的,只需要静静的躺在SD卡上即可。由万能的pluginmgrd在运行时将这些apk加载进来。
6)更优雅的修bug:AndFix
https://github.com/alibaba/AndFix
Android插件化是为了解决什么问题?
65536方法数爆棚。
减少apk体积。
不通过发版就能发布新功能
不通过发版就能修复线上bug和崩溃。
但我们经过实践发现,插件化更多的运用于修复线上bug和崩溃。这是一个很轻量的需求,却为此花费了大量的人力和财力去运行这样一套庞大的架构体系,是相当不划算的。为此,2015年github上出现了AndFix,这款Android轻量级线上bug修复工具。
AndFix的核心思想是,把app中的方法B替换为新的方法B ‘,为此,我们把新方法B’所在的代码进行重新打包,并和就的apk包进行差分比较,得到一个差分包,放到服务器提供旧版apk下载,那么apk在接收到差分包后,就会执行新的方法B’了,如下图所示:
这类似于iOS的JSPatch实现。只不过Objective-C是一门动态语言,天生就支持这样的特性。而在Android中,则需要修改Native底层了。
在Native底层,有一个dalvik_dispatcher方法负责最终执行哪个方法。就是在这里做一些手脚,把旧方法替换为新方法。
对于功能不是很多的App而言,AndFix是首选,可以快速修复线上bug而不用发新版,而实现成本也很低。对于规模不大的团队而言,相当划算。
这里不得不说到dexposed。dexposed和AndFix都是阿里推出的开源框架,用以解决Android热修复的两种实现,原理两者类似,都是在在Native底层的dalvik_dispatcher方法做文章。但是dexposed有一个硬伤,就是不支持art,这使得很多粉丝转而去投标AndFix阵营。dexposed的github地址为:
https://github.com/alibaba/dexposed
8)360系插件化
https://github.com/Qihoo360/DroidPlugin
纵览了前面的所有插件化技术,你会发现,它们都是基于单进程的。这就是说,插件更新只能等到App重新启动才能生效。
但是我们的用户大都是不懂得如何重启App的。这就导致了插件升级后的更新率并不高,两周时间也就50%的升级率,然后App就又发大版本了。
对于这个问题,360推出了DroidPlugin的插件化技术,它是基于多进程的思想。比如说一个App中有吃喝玩乐4个插件,如果“吃”这个插件有升级,DroidPlugin就可以把正在运行的“吃”的旧版本的这个进程杀掉,然后运行新的插件版本。
目前看起来,对于电商、O2O、OTA这样多业务线、并偏重于闭环的App而言,DroidPlugin是一个终极解决方案。
第二个激动人心的是Facebook开源的Fresco,这是一款强大的图片加载组件,github地址:https://github.com/facebook/fresco。
Android领域最让程序员苦恼的莫过于内存不足够导致的OOM异常了,这大都是由于加载大量图片而没有及时回收导致的。为了解决这个问题,Android有很多专门用于加载图片的组件,比较著名的有ImageLoader、Picaso等,它们只能在Android层面通过及时回收图片资源来缓解Android的内存使用,来减缓OOM的发生频率。
接下来我们说Fresco,它引进了三级缓存的概念(Bitmap缓存、内存缓存和硬盘缓存),它比其他图片下载组件消耗的内存小,就在于这个全新的缓存设计。三级缓存中,尤以Bitmap缓存最亮眼。在Android 4.x和更低的系统,Bitmap缓存位于ashmem中,而不是位于Java的堆(heap)中。这意味着图片的创建和回收不会引发过多的GC。
关于Fresco的更多介绍,请参见Fresco的官方文档:http://fresco-cn.org/docs/index.html
最后,是针对于Android的线上崩溃的收集整理和分析修复。其实收集整理这件事,要么是使用第三方平台的系统,要么是自己做,但是收集到数据并去重后,如果分析这些崩溃信息并修复,是件很棘手的事情。要针对于机型、使用场景,具体问题具体分析,社区上(比如CSDN或Stackflow)针对于每个崩溃信息的分析和修复方案,鱼目混杂,或只言片语,或空穴来风,要逐一订正是件很费神的事情。
我曾经试图来整理这些崩溃的原因和修复方案,耗费半年时间,也才完成84个(可以参见《App研发录》第6章)。就在我干这件事的同时,腾讯有一个团队Bugly也在做类似的事情,他们在11月搞了这样的一个活动“腾讯 Bugly Android 异常案例解决方案征集”(活动的详细地址参加http://www.oschina.net/news/67914/tencent-bugly-projects),试图通过社区的力量来建立一个Android的崩溃仓库。天地万物皆有时,崩溃仓库在2015年只是一个萌芽,能否做大做全,我们期待2016年。
前面说了Android太多普大喜奔的事情,接下来说一说Android在2015年遇到的一个安全问题。
我敢打赌说,大部分公司的Android项目,会为了方便,而把签名密钥放在了项目中,所有开发人员都可以看到。随着这几年开发人员的流动,密钥已不再是密钥了。
把密钥从项目中移除,保存在1-2个人手中,是个不错的办法。但是仍不能避免之前的同事手中握有这份密钥。密钥一旦被流传到市场上,就会有不怀好意的人在原先的App加一些恶意的功能,然后重新签名。
更换密钥吗?这是个馊主意,这会导致生成一个新的App,而不再是原先的那个App了。
其实这个问题早就存在,只是现在才摆上台面而已。目前还没有更好的解决办法,也只能缩小直到密钥的人员。
末了插播一条新闻。2015年6月,Google宣布将在年底前停止对Eclipse Android开发工具的一切支持,从此我们只能使用Android Studio开发Android。对于一个使用Eclipse3年的开发者而言,我感到非常不适应。相信和我有相同感受的朋友不在少数。从此,Gradle成为标配。
ADT的没落完全是咎由自取,自身的不努力,导致Google不再花费时间和精力去支持。这样也好,集中精力先把一个IDE做好,目前看起来,Android Studio比微软的Visual Studio还差很多很多。
(二)iOS篇
2015年,iOS有太多的事情发生,每一次事件都促进了iOS技术的一次飞跃。
首先是苹果宣布从2015年2月1日开始,所有上传至App Store官方商店的新iOS应用都必须支持64位。为此,所有的App在打包时要兼容32位和64位,虽然某些机型上速度快了不少,但是App的体积却大了不少。
2015年应该是iOS的“瘦身年”。各大公司在发现自己的iOS App超过了50M之后,纷纷开始组织iOS团队对App进行减肥,然后我们就会发现,体积变大,不光是兼容64位导致的,兼容64位只会导致.a文件的增加,而资源文件是导致体积变大的另一个因素。
先说资源文件,包括以下几点:
减少图片和音频文件的大小(这一点携程的App做的不错,每个图片都不超过100k,甚至50-100k之间的图片都很少,而很多App之所以体积大,是因为其中有很多1M以上的图片)。
对于PNG图片,由于它内部保存了额外的分层和透明通道信息,统称为EXIF,所以它会比JPG图片大一些。App开发推荐使用PNG图片是因为XCode会在打包时压缩PNG图片的大小。我们可以写一个脚本,在打包前,把PNG图片中这些多余的信息,删除掉。
单色图片使用使用字体文件。关于字体文件的技术,也就是IconFont,网上有很多例子,同时适用于Andorid和iOS,我这里就不多说了。
使用.9图。之所周知.9图是Android的技术,能极大减小图片的体积,殊不知,iOS也有类似的实现方式。
动态下载表情包。把聊天时用到的表情图片,做成从服务器下载zip包的方式,而不是打包在App中。
清除不再使用的图片。每次迭代做新需求,都会导致一些旧图片不再使用了。XCode不提供检查未使用图片的功能,那我们就需要自己写一个脚本,每次发版前,对整个工程检查一次。
再说.a文件。.a文件是编译文件,这个文件大,说明代码多。于是我们检查项目中的代码,真的要写那么多行吗?其实有很多优化的空间。
冗余的类和方法。这些冗余仍然是因为做新需求导致的,忘记删除不用的类和方法,需要写脚本查找,定期删除。
相似度极高的代码片段。初级程序员在写代码时,喜欢把一段代码从A类粘贴到B类中,然后修改其中的几个变量名称,这个功能就算做完了。于是两段相似度极高的代码就产生了。
稍微懂得些面向对象思想的人,都知道这时候需要把这样的代码抽象出来,比如说在Utils类中新建一个方法,然后要用到这段逻辑的人调用Utils类的这个方法即可。
但并不是所有的程序员都有这样的境界,即使是有几年经验的人,也会因为急着下班二人世界或者给孩子换尿布而采用复制粘贴大法敷衍了事。久而久之,冗余代码就多了,包的体积自然就大了。为此,我们需要有一个检查代码相似度的工具。在iOS领域,我推荐Simian这个工具。有兴趣的读者可以尝试一下,对你们的项目使用一下这个工具,看能找出来多少相似的代码来
使用代码生成UI,而不是使用Xib或Storyboard。经过测试,对于同一个页面,使用代码而导致的.a文件增加的体积,大于Xib的体积。是时候该返璞归真,考虑使用Xib来布局了。Xib之所以广受诟病,是因为XCode这个IDE工具很烂,另一个原因是我们使用的少,人总是会抵触陌生的事物,在使用Xib的过程中遇到障碍了,就又转到写代码的路线了。
使用Hybird方案来代替iOS原生代码。我做过尝试,一个功能模块,导致.a文件增加3M,但使用Hybird却只有1-2M的样子,而且这1-2M中有一部分打包放在App中,另一部分则做成增量下载,从而从整体上减少App包的大小。其中Hybird的增量包技术是关键。
编译选项的优化。比如说Strip Link Product设为Yes啊,Make Strings Read-Only设为Yes啊,去掉异常支持啊,都能减少包的大小。此外,经常检查LinkMap文件,也是控制瘦身的一个办法。
微信团队2015年9月中旬发布了iOS微信安装包的瘦身经验,其中有很多实际经验。文章地址如下:
http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207986417&idx=1&sn=77ea7d8e4f8ab7b59111e78c86ccfe66&3rd=MzA3MDU4NTYzMw==&scene=6#rd
其次是春节期间,某款知名App的后门泄露事件。所谓后门,就是App开发期间,方便开发人员和测试人员的一些功能,比如说:
开发人员和测试人员可以随意切换到任意服务器(线上环境、测试环境)进行开发测试工作。传统的做法,这些地址是写死的,每次打包出来的App只能在固定的一个环境下运行,我们迫切需要一个后门页面,能够灵活配置。当然,线上用户是不能看到这个后门的,必须做一个类似于彩蛋的功能,比如在设置页的某个位置连续点100次,才会弹出一个密码输入框,只有输入正确了,才能进入后门页面配置服务器地址。
考虑到发布到线上的App,存在这样的彩蛋是非常危险的。于是我们需要一个Flag标记,在发布App时要把这个值设置为false,从而关闭后门入口。但人总是会犯错误的,即使有测试团队把关也还是会有纰漏。于是,国内某款著名的App在春节期间就把这样的后门漏出来了,也许是开发或测试人员急着回家过年。这是这次无心之失,让我们领略了这款App强大的后门里隐藏的功能。比如说,
服务器切换功能(上午已经介绍过)。
记录App的崩溃信息。有这样一种场景,测试人员在测试过程中发现的一个崩溃,虽然也记录在Bug仓库中了,但是等开发人员去修复的时候,却难以再现这个崩溃了。如果能把崩溃记录到App本地,那么测试同学提bug的时候,就可以把崩溃信息一起贴出来。
提供一个后门页面供Html5团队进行调试,该页面内置一个WebView,加载Html5团队正在开发的Html页面,要支持调试。
对App进行流量测试,统计某个页面所花费的流量,包括调用MobileAPI、下载图片、上传文件、XMPP聊天等等。其中,从App启动到首页加载完成所花费的流量是我们关心的一个关键点,而手机待机时,App所花费的流量也是我们所关心的。我们需要这样一个后门页面,看到这些数据统计。
对App进行电池电量消耗测试。需要有个后门页面记录每次打开App和退出App的时间,以及这段时间内我们的App所消耗的电量。为了确保数据的准确性,需要确保手机上只安装了一个App,而且处于相同的网络环境下,比如3G。
测试某个页面请求了哪些MobileAPI接口,打印出调用这些接口时输入的参数和返回JSON数据。这样就能够在线上App发现某个页面有问题时,及时在App后门中检查数据是否正常,而不用App开发人员和MobileAPI开发人员坐在一起逐行联调代码,极大的节省了人力。
在窥探到后门中这许多先进技术之后,各家无线团队纷纷在自己的App中增加类似的功能,只是不知道最初把后门漏出来的那个哥们离职了没有?
2015年最犀利的技术首推JSPatch,使用这门技术,iOS可以快速修复线上bug而不需要重新提交AppStore审核。
这门技术最早起源于大众点评的屠毅敏的一个开源项目WaxPatch。它是通过重写runtime的class_replaceMethod方法,从而可以修改任何一个类的任何一个方法,该项目的GitHub地址为:https://github.com/mmin18/WaxPatch
WaxPatch上支持的语言为Lua,也就是说,建立了一套Objective C和Lua语言之间大部分语法的映射关系,我们只要熟记这些转换语法,就能快速把一个Objective C方法翻译为Lua方法。然后我们把需要修改的Lua方法所在的类文件打包成zip,由App在启动的时候下载zip包并解压到本地目录,于是我们会看到,当运行到旧的Objective C方法时,实际执行的是下载到的Lua方法。这一切都因为Objective是一门动态语言,我们可以基于此制造一些“黑魔法”。
但是WaxPatch从2013年10月起就不再更新了。当2015年2月苹果宣布所有上传至App Store官方商店的新iOS应用都必须支持64位,这时我们发现WaxPatch并不支持64位。这就间接导致了很多已经在项目中使用了WaxPatch的App,必须砍掉WaxPatch热修复功能,后来社区有人给出了WaxPatch的64位解决方案,才让热修复技术能继续向前发展,这个项目的的GitHub地址为:https://github.com/maxfong/WaxPatch_X64/commits/master
尽管如此,WaxPatch还是有很多局限性。比如说它不支持多线程、不支持Block,不支持结构体和结构体指针这两个类型,这就导致了当我们在程序中使用了这些语法时,是没有机会把这些语法转换为Lua代码的。
通过上文的分析,我们知道,只要重写runtime的class_replaceMethod方法,就可以热修复Objective C中的任何类的任何方法,WaxPatch只不过使用了Lua作为新方法的语言载体,我们完全可以使用Python、JavaScript这样的脚本再写出一个新的Patch。
这时终于轮到JSPatch登场了,它是由腾讯的陈振焯(英文名Bang)于2015年5月编写的开源项目,从名字就能猜出来,它使用的是JavaScript语言作为新方法的语言载体,GitHub地址为:https://github.com/bang590/JSPatch。这个项目解决了上述WaxPatch所不支持的那些语法。目前这个项目还在每周持续更新中。
JSPatch还有一个亮眼的功能,就是支持一键生成,把一个Objective C方法翻译为JavaScript的方法。按照这个思路再往前走一步,就是iOS的“插件化编程”。我们可以把一个模块所涉及的所有页面都使用Objective C先实现了,然后一键生成JavaScript方法代码,打包成一个zip包,这就是插件化编程。不得不说的是,对大量的代码执行反射操作,性能是一个问题,究竟能往前走多远,2016年,我们拭目以待。
2015年注定是iOS领域不平凡的一年,比如说,在9月份大规模爆发的XCodeGhost病毒。IDE也能携带病毒,这是我一个.NET出身、用惯了Visual Studio的程序员所不可理解的一件事。只要是非官方下载的XCode,都有可能通过CoreService库文件进行感染,使用有毒XCode开发的App,都会感染病毒。这就像给病人动手术,结果手术刀没消毒,病人就会有生命危险。
关键是AppStore还无法检测出病毒,传闻将近800款App感染了这一病毒。
尽管事后立即有人站出来,声明自己是XCodeGhost的作者,并宣称是个“苦X程序员的”、“无害的”、“实验”,同时承认自己出于私心,在代码里加入了广告功能,并说自己在10天前,已主动关闭服务器,并删除所有数据。
但很多证据表明,这是一个蓄谋已久的恶性事件。
当号称“封闭安全”的AppStore也不再安全,我们还能相信谁?
接下来介绍React Native。这是Facebook在React.js Conf 2015 大会上推出了基于JavaScript的开源框架。同时支持iOS和Android,Github地址为:
http://facebook.github.io/react-native/
首先,React Native不是依赖于WebView的,所以它不是Hybird。React Native是把js翻译为Objective-C,倒是与JSPatch有些渊源
我一直在关注着这门技术的发展。但目前看起来,还很不成熟。尽管在2015年的各种技术大会上,React Native出尽了风头,但据我所示,目前也就BAT这种公司愿意烧钱让团队去尝试使用。
有关React Native的更详细介绍,推荐大家看下面这两篇文章:
我对 React Native 的理解和看法:http://div.io/topic/851?utm_source=tuicool&utm_medium=referral
React Native概述:背景、规划和风险:https://github.com/tmallfe/tmallfe.github.io/issues/18
2015年iOS的最后一件“振奋人心”的事情是Swift的开源。
Swift从面世伊始,就号称要取代Obejctive C成为新的iOS开发语言,但是几年过后却还是一个很小众的语言。没听说有哪家大公司的代码全都切换到Swift了。也许是我孤陋寡闻了,至少在App应用领域是这样。
从2015年12月初Swift开源,截止到本文写作期间,这个项目的Watch(邮件提醒)为1484、Star为22569,Fork为2652,火得一塌糊涂。但是热闹过后,又会有多少人真正关注?苹果官方给出了开源后的诸多好处和美妙的前瞻,这不过是官方的PR稿子,这不由得让我想起了.NET当初开源,也是叫好声一片,但实际效果并不理想,参见以下报道:
作为有着十多年编程经验的码农,我不能泼太多冷水。我不想浇灭刚入行的小朋友的社区热情。究竟Swift开源后能产生什么惊天地泣鬼神的作用,2016年,请用事实验证吧。
(三)App项目管理
2015年,在App项目管理领域,仍没有太大的进展。我悲观的认为,App项目管理,已经到了糟糕透顶的地步。
从事传统项目管理的工作人员,并没有与时俱进,还在把旧的项目管理方式直接套用在App项目管理上。主要体现为传统项目管理只涉及到产品经理、开发和测试三个团队,开发完毕介入测试,测试完毕随时可以发布上线,如果一个团队延期,另一个团队可以做下一次迭代的工作。
但是App开发就不同了,涉及到产品经理、Android、iOS、服务器、测试共计5个团队的协作,有时还会牵扯进H5前端团队,那就更复杂了。
App区别于传统项目的另一点就在于它有发版时间限制。2周或4周的迭代时间,到了最后一天就必须要提交APpStore审核或发布到各大Android市场,一般不能延期,否则不光影响技术团队,市场推广团队也会受到影响。哪个做不完或者测不完,就只能等下次发版再上,那就是一个月之后了。
既然迭代周期是固定的,App项目管理所关心的,就在于如何能在有限的时间内完成尽可能多的需求,而不是每天纠结于“敏捷白板上的小纸条哪里格式不对了”这种形式主义的东西。
如果有可能,我真心想把每个公司所使用的项目管理工具(比如Wiki)废弃了,工程师们往往是在项目完成后才更新Wiki上的项目状态,而做不到即时更新。我只能在每次App发版后才看到大量项目的状态变更。那我还要这种工具干什么呢?而过度的要求工程师实时使用Wiki来更新项目状态,那无疑是重流程的软件公司的打法,不适用于互联网高速发展的文化。越是大公司,这种官僚文化越严重,迭代速度远低于创业公司。因为互联网公司现在钱很多,很多软件公司的项目管理人员都跳槽到了大型互联网公司,无形中就把这种文化也带过来了。
说真的,我不喜欢循规蹈矩。我喜欢时刻去改变去尝试,直到找到一条切实的解决方案,所以我经常会到一线去,和团队一起加班一起熬夜。在4年的App项目管理经验中,我观察到的是,对于10人左右的小团队,每天可以在晨会上把产品、Android、iOS、Server、QA的进度都过一遍,控制在10分钟以内。而对于40人左右的中型团队,这时一般会按照Android、iOS这样的技术工种细分为多个小团队,每天晨会问技术经理团队的项目进度,他一般不会知晓团队中每个成员的工作状态,所以这样的晨会是很没有效率的。这时需要把团队按照需求拆分为若干虚拟小团队,每个需求的虚拟团队都由产品经理、具体的iOS开发、Android开发、Server开发和测试人员组成,采取产品经理负责制,每天组织各自的晨会并发会议纪要。
项目管理人员手中应该有一份所有人的名单,减去产品经理日报中涉及的人力输出,那么剩下来的人力,要么是请假了,要么是在做技术需求,还剩下来的人,就是真的没事做了,浪费掉了。
这时团队每个人的工作状态就都一目了然了。我们不苛求每天都把人力充分使用,但至少要做到哑巴吃饺子——心里有数。
那种靠每周发周报的项目管理方式,属于事后补救,难道我们要在一周之后才知道人员利用率不高而导致的项目风险吗?这对于两周发一次版本的App而言,多少有些可笑了。
我们不可能安排一个开发人员一个迭代只做一个需求,也许这个需求两天就做完了,难道剩下的时间全都用于修bug吗?这种敷衍的说法,用于哄弄那些不懂技术的老板的。剩下的时间应该去做更多的需求,那么就会有人问什么时间修bug?两周的迭代周期要怎么安排比较合理?
下面我给出两周的迭代周期图,这在我所从事的一家大型互联网公司一直坚持到现在,两年多了一直风雨无阻:
由上图我们可以看出,
1)开发只有第1周周二到第2周周三共计7天时间。
2)测试团队要在开发人员提测后立即介入,而不是等到所有项目都完成后统一测试。
3)开发人力不足,一般是第1周加班;测试人力不足,一般是第2周加班,但没有定式。
4)第2周周三晚上为Code Complete,周五晚上为Code Freeze,这两个点很关键,直接决定了是否要加班以及是否会延期。
当一个Task的开发时间,从3天(粗略评估)被压缩到2天(精准评估)后,多出的1天时间做什么?
首先是看还能不能消化更多的需求。
其次,就是重构,做技术需求。App领域有太多的技术需要升级,我分析过100多款国内比较知名的App,发现各自的瑕疵都还是有很多的。Android的技术工作会更多,比如每次迭代要挤出1-2天时间来修复线上千奇百怪的崩溃。
最后,就是研究新技术。要时刻了解市面上的新思想和新技术。
上述这若干文字,都是在诠释一个词,节奏。
团队多了自然就会有沟通上的障碍,从而导致效率大幅下降。而我的观察是,只要让所有团队踩准了节奏,App和Server团队同一时间联调而不是互相等待,按时提测而不耽误测试人员的进度,提前介入测试而不是前松后紧,当所有的团队能够踩住这几个节奏,那么我们就能在有限的时间内按时完成足够多的需求。
2016年,我们应该重点关注App的项目管理,多开几次会各个公司分享一下经验,总结出一条好的方式来。
(四)综合篇
接下来的篇幅,不限于Android或iOS。
2015年,各大互联网公司开始经营自己技术团队的微信公众号。以下是我收集到的几个(排名不分先后哦),欢迎读者补充更多的技术团队公众号:
淘宝:TaobaoTech
天猫:tmalltech
手淘:AlibabaMTT
微信:WeMobileDev
QQ空间前端:QzoneWeb
Bugly:weixinBugly
京东:JDTechEd
美团:meituantech
携程:ctriptech
去哪儿:QunarTL
途牛:tuniutech
当当:当当Tech
此外还有技术社区的公众号(排名不分先后哦):
InfoQ:infoqchina
CSDN:mobilehub
OSChina 开源中国:gh_430521f7587e
51CTO技术博客:blog51cto
CocoaChina:cocoachinabbs
极客学院:jikexueyuan00
通过持续关注这些公众号,尤其是无线相关的内容,可以大致知道业界最新的技术趋势,比如Android插件化编程,比如iOS瘦身。
2015年,对无线领域的技术分析正式摆上了台面。之前肯定有公司也在小规模的做这个事情,只是不能多做宣传罢了。
竞品分析的手段一般分为几种:
1)iOS的代码是无法反编译的,但是Android却可以,大多数App做了代码混淆,但也有的App直接裸奔就发到了市场上。即使代码做了混淆,我们也能从关键片段中看出端倪来。关于这个技术我不能再讲下去了,否则就要教坏小朋友了。目前看起来,对Android进行加固是一个好的办法,也有一些公司从事这个领域,但还没有广泛应用起来,比如说爱加密和梆梆。
2)所有的apk或ipa文件,都是压缩包,我们将其后缀修改为zip格式,就可以解压并看到其中的文件了。通过分析这些文件,我们可以学习到优秀的公司是如何解决App体积大小、性能优化新技术,一般的话,一个新的思想或新的技术,都会伴随一个配置文件在App包中,比如ABTest。
此外,我们知道,Android App中的动画,会放在Apk包res/anim目录中,当我们喜欢某款App的动画效果时,按图索骥,直接可以在上述目录中找到相应的动画文件;但是,当我们在ipa包中也看到类似的动画文件时,那十有八九是这款App的iOS版本中,存在一个动画引擎,iOS程序员可以把Android团队的动画文件直接复制过来就可以使用了。
关于竞品分析的更多介绍,请参见我发表在CSDN上的系列文章:
http://blog.csdn.net/JspAndAsp/article/details/49339363
2015年,我终于看到美团在App中使用ABTest来做产品。产品经理可以根据线上A和B两种策略各自的转化率来迅速决策哪种策略更适合。
也许ABTest这门技术,其他公司早就开始在做了,只是没有声张而已,在此请不要笑话我的孤陋寡闻。我把自己在实施ABTest的一些经验分享出来,请参见下面这篇文章:http://blog.csdn.net/jspandasp/article/details/49339443
数据驱动产品——我认为这才是做产品的方式,而不是靠拍脑袋。稍微高级一点的产品经理,会收集有利的数据来支撑自己要做的需求,而有意识的忽略那些不利的数据。这多少有些偷奸耍滑,需求上线后的结果也是听天由命大都结局不好。
产品需求分为两个方向,一是刚需,二是交互和UI设计。
对于第一个方向,需要对这个领域浸染很多年,才能真正知道用户和供应链上的真正痛点,目前我见过这个方向最好的产品经理就是杨威。也许以后还能遇到更好的,但是目前就是他了。2015年我有幸见到了他是怎么在几个月内从谋划到调动整个部门完成了机票整个流程的改造,最后做出来一套逆向报价系统。
对于第二个方向,则多少有些自说自话了。一套好的UI设计怎么评定?首先是老板喜欢,这是因为一套设计不可能让所有人都满意,但只要老板满意,就是好的设计,搞定了老板,后面的都好谈;其次是风格要统一;再次是要时刻关注竞争对手的App改版。
对于好的交互设计又怎么评定?首先不能设计出“反人类”的交互;其次要看PV和UV数据,看哪里的转化率低;再次看用户反馈,广泛吸取各方意见;最后看竞品,取长补短。
无论哪个方向,都需要数据说话。运营才是王道,因为只有他们才能通过调整策略得到不同的数据,分析数据最终做出判断。运营人员欠缺的就是不知道如何把需求组织成文档给开发人员,这时候就轮到产品经理出场了。
产品经理应该学点数学,能根据运营妹纸提供的数据,总结成公式,才是好的产品经理。数据驱动产品,重要的事情说三遍,不写出来了,心中默念三遍即可。
接下来介绍一款由腾讯团队于2015年发布的App尾随测试的神器,GT(随身调)。
2015年的最后一门技术,那就是App缓存命中率。
从事App开发的同学可能不清楚缓存命中率的概念。这一般是做在数据库层面,对于频繁访问的数据,会放入缓存中,从而下次访问时不会再执行SQL语句,极大地节省了性能,但是也不能把所有的数据都放在缓存上哦,没有那么大的控件。对此,我们的妥协方案是,设置一个阈值,大于这个阈值,缓存的时间会长一些;否则,就只有3分钟后缓存就会失效。
其实这个思想也可以做在App层面,把相同的逻辑搬到App应用中,从而减少访问服务器的频率。有些公司已经在App所使用的服务器接口层面做了类似的缓存策略,但是还没有在App中尝试实施这种策略。
(五)结束语
本人从事App开发4年时间。当初比较贪心,iOS和Android是一起学的,这就导致了精力要一分为二,结果哪门技术都做不到非常精深,而我又额外花费了很多时间在项目管理上,这也是我所喜爱的一个领域。所以上述若干文字,盘点了2015年App领域的若干新技术和新思想,但难免挂一漏万,或文中观点有所偏颇,还请各位读者多多指教。
最后,再奉献给读者们一个建议。微信这个工具大家经常使用吧,我们经常收藏朋友圈中别人分享的一些好的技术文章,但当时看的并不是很仔细,是时候把2015年收藏的所有技术文章重新翻出来研读一遍了,我这几天就在干这个事情,收获还是很大的。