“照”出代码的美
“照”出代码的美
口述/吴亚伟 整理/李晓婷
加入终端,缘来如此美妙
2005年的一个夜晚,老爸因为工作需要买回了家里第一台电脑。初中生的我,第一次望着显示屏上的windows大草原,体验着鼠标在系统页面自由跳转的快感,被这个“价值不菲”的产品勾起了兴趣。这之后,我常常采用各种“游戏隐藏秘笈”跟老爸斗智斗勇,以此获得更多与电脑的“约会”时间。
步入高中,我的兴趣再次延伸,偶然间学习到通过U盘boot文件自启动批处理,反编译破解了网管软件,甚至成了黑客论坛版主。这一切引爆了我成为一名软件工程师的好奇心,于是高考报志愿时我毫不犹豫选择了计算机专业。
大学期间,正值Android崛起,我也随之开启了Android的探索之路。新奇于第一次在自己手机里安装了自己的应用,学着独立开发了一个游戏辅助工具,并添加广告盈利,亲身体验了一次移动互联网红利,还被导师推荐参加了一些和学校合作的有关Android的创新项目……
用编码改变世界,成了我最想实现的梦。
2015年7月,22岁的我顺利毕业,如愿加入正在智能手机领域开疆辟土的华为终端,期待再续Coding之缘,做自己喜欢的事,在技术领域探索更多的美妙。
萌新预研,提前熟悉相机基础框架
入职软件基础ROM部两周时,PL安排我去做预研(预备研发)工作,我成为预研团队唯一的新员工。PL鼓励我:“往上跳一跳,能‘够’到就大胆上!”这句话让我受用至今。
那时候,团队正在做下一代相机预研项目。新的相机应用要从功能较少的一代接口切换到能力和拓展性更强的二代接口,并最终落地到华为旗舰机的双摄产品中。这涉及40万行代码量和数百个功能的重新开发,而预研要做的是搭起新相机应用的基础插件化框架,将内部各个功能解耦成多个相互独立的插件,彼此能自由组合,想要哪个模式,把文件加进来就行,供后续功能业务的快速拓展。
这对萌新的我来说,无疑是一个挑战,当时插件化在业内还没有太成熟的方案,终端内部也没有做过。但我也知道,这更是一个机遇,职场起步就能接触和学习比较新的技术,还有什么比这更美好的事呢?
别看我现在说得好像很容易,当时特别艰难。我在大学期间的学习偏技术原理,原来做开发是用的“野路子”,写个几千行的代码做个小项目还凑合,而现在参与的是需要整个团队维护、数十万代码量级的大工程,预研更复杂的是,要搞清楚基础框架,“野路子”一下子暴露出短板,写出来的代码有各种毛病,比如只考虑功能的实现,从未考虑代码要分层分模块,没考虑代码的可读性。我不得不逼着自己从零开始理解新架构。
幸运的是,我抓住了当时的架构设计师陈国栋的“援手”。国栋哥当时在华为已十年,是相机的模块设计师,在相机领域造诣颇深。他给我推荐Java书籍,讲解新框架的设计思想,再手把手教我设计接口草稿,职场新人喝着前辈的这杯“咖啡”吸收宇宙的能量。
前辈的思考方式和工作习惯也深深影响了我,他会从全局考虑设计是否合理,是否适合后续业务演进,接口设计是否稳定,后续会不会频繁修改。他还有一个习惯,和别人沟通时,一边沟通一边写下设计好的接口代码,等沟通完,设计草稿已经出来了。“除了完成任务,更重要的是要想如何高效完成。”他常常对我这样说。
从前辈的身上,我学到了太多太多。我知道了什么是代码的好坏味道,代码要讲究可读性、可拓展性、可维护性,我知道了代码的设计原则是为了更快更好地业务交付,我知道了怎么写代码,相机业务是什么,更学习了什么是插件化的技术和解耦……就这样一边工作一边学习,做得多,学得也多,不仅帮助我提前熟悉了新架构,也为后面独立承担基础模块开发打好了基础。
毫不谦虚地说,我自此建立了一种在熟悉的领域不管多难都能搞定的自信。也正是这种自信,支撑我后来不管碰到什么难题,都会选择“跳一跳”,万一“够”到了呢!
落地双摄,我“够”到了
完成新相机基础插件化框架预研后,为赶上3个月后的旗舰机发布,预研组十余人展开了与时间赛跑的三个月封闭开发。
因为对基础框架非常熟悉,主管将相机应用的基础流程管理,这一最基础也最容易出现问题的部分交给了还是新员工的我,其他人负责人像、夜景、大光圈等各个模式的开发。基础流程管理涉及基础的相机启动模块,3A算法交互模块、插件管理模块、基础拍摄流程等,用作各个模式的实现基础。那时候,我每天都要面对任务板上几十个密密麻麻的问题单和需求,有的能复现还好,有的是小概率偶现,还有一些是历史遗留问题,问题的繁杂常常让我措手不及。
好在“敲代码”这件事让人受益又让人快乐。我在代码的海洋里奋力探索,从团队空间到公司论坛,再到外部开源社区、搜索引擎,想尽办法不断汲取知识,找到解题思路,把一个个问题作为练手的工具,每晚到深夜仍然乐此不疲。当时相机的启动涉及二代接口和第三方应用,能参考的资料非常少,我查阅各种文档、手册和网上的问答,几乎搜遍全网终于在公司Andriod源码里找到了参考工程,有全量几十万行的代码。我从中搜索与实现功能有关的代码,仔细分析研读,找到了解题的钥匙,并从此掌握了一套知识搜索和学习技巧,独立解决问题更游刃有余,问题单的闭环速度也越来越快,从一开始一天一两个到后来平均五六个,甚至在组内有了“解单高手”的称号,算是渐渐站稳了脚跟。
忙碌的日子总是过得飞快,搭载了全组人心血的全新相机应用火热出炉,我们成功按期交付版本,落地P9系列双摄产品中。
现在回想起来,当时的艰难困苦都烟消云散,留下的只有满满的收获与感激。每当遇到艰难的阶段,我就会想起这段经历,对自己说:不怕跳一跳,就怕不敢跳;每一次起跳,都是向下一次发起冲击。
优化十来天,相机启动性能达业界第一
2018年,离EMUI9.0版本拉出商用分支只有十几天,我们突然接到一个新的优化诉求——Connect老化性能评测,相机启动性能要从1.2秒优化至0.6秒。
这个突如其来的极端要求把我搞懵了,我非常排斥,心想怎么可能?往常这种需求要投入两三人用一个月的时间实现,是不是流程出了问题?一般一个指标提升10%已经是非常大的变化了,这次要提升100%,幅度这么大,合理吗?业界其他竞品当时最快就是0.6几秒,我们在十几天内能做到超越吗?
尽管带着诸多疑问,我还是一边和测试部确认需求,一边着手分析历史代码。三天时间,通过排查发现,原来是历史代码随意增加功能捣的鬼。我开始对代码大胆“开刀”,对“坏味道”的历史代码逐一优化,并且调整相机全局资源加载流程的优先级,想尽办法减少每一毫秒的开销,一下子优化到了0.9秒,但是离最终目标还有不小的差距。
之后,考虑多个线程相互等待问题,我把一些线程的串行改为并行,把首界面不会出现的东西晚一点加载,相机启动性能优化到0.7秒。我感觉自己已经绞尽脑汁,可离要求的还有0.1秒!
还能再优化吗?我想来想去,只能采用比较极端的办法了。相机启动涉及几十个类几百个变量的初始化,我会去抠每个变量的初始化时间消耗,有些不需要在相机启动时出现在界面的变量,要么挪到后面,要么放到比较靠后的时间段执行,这样一个一个细抠,终于达到了0.6秒。
最终,我们的相机启动性能实现了Connect老化海外评测业界第一的目标。
完成任务后,我对代码的理解更深了一层。随意添加功能导致性能恶化,这些就是我们开发人员自己挖的坑,而指标优化,不过是开发人员必要的自我填坑罢了。有的人会及时填坑,目的是解决短期矛盾;而更优者则是前期“不留坑”,和坏代码说“NO”,目的是解决长远问题。
2019年,做相机1+N 组件化方案时,在完成需求规定特性的基础上,我依然思考着如何避免以前的问题重犯。组件化后会带来加载的高负载,我想了一个办法,按需延迟加载各个拍摄模式组件,减少初始内存消耗20M,整体内存占用下降10%,高负载下性能优化15%以上。
有人说,你走过的路每一步都算数。其实你每改一次坏代码,积累的好代码就越多;你每一次写代码“不留坑”,持续用好代码要求自己,就是在构建好代码的万里长城。
主动重构界面,效率提升60%
相机作为新手机发布会卖点的“常客”,界面设计一直以来受到用户的广泛关注。
在我来公司的这几年,相机界面从4.1版本升级到10.0版本,存在多次大的用户界面调整。2017年,我和同事十余人日夜奋战3个月,修改了十万行代码,成功交付新版相机界面。但改完之后回过头看,我们发现人力投入还是比较大,我心里不断冒出另一个想法:能不能让相机应用的界面调整变得更简单?能不能做到在不影响功能逻辑的前提下调整界面?
当时相机应用的界面和功能耦合,界面就是用户看到的图标、按钮,功能是用户点击了图标或按钮后的响应。调整界面就会影响到功能,修改起来复杂,容易引入问题。
痛定思痛,我决定选择重构,也减少以后界面调整的工作量。把这个想法和团队一说,大家也非常支持。
然而,面对历史的功能接口设计易与界面耦合的问题,新接口不仅要解决历史痛点,又必须适配相机所有的功能特性,这意味着很多需求都要推倒重来。而要推倒重来的前提,是对原来的功能业务代码了解透彻,并有很好的重构思维。
比如,相机的美肤功能,重构时存在一代简单美肤、二代加了虚化效果,后来又加了光滑、美白、瘦脸等美肤能力,每一个功能对应不同的历史产品,由不同的人开发的不同版本,规格不一,重构后的代码必须能保证以往的功能规格都能使用,且不会遗漏。为了了解原来的代码,我找到当时做这些功能需求的人,一个一个去交流,但有些功能已经实现很久了,开发的人不一定记得自己写过的代码,也只能靠自己一行一行看代码,自己去理解掌握。
说实话,这期间,我曾经有过放弃的念头。团队并没有给我定重构的目标,能实现多少是自己拟定的,我曾考虑放弃比较复杂的模块,但一想到下一次交付还会产生问题,还不如一次就把事情搞定,只得硬着头皮咬牙坚持下来。
幸运的是,重构之后界面服务化管理模块成功上库,界面和功能在EMUI9.0版本中解耦成功,开发变得更简单,更稳定。紧接着在2019年最新的EMUI10.0相机界面中,我基于重构的代码,用了2个月便快速完成界面替换,效率提升60%。
这让我把余下的精力放到与界面设计师一起持续打磨极致体验上。原先相机在华为手机、平板、折叠屏的布局上并不统一,带来了界面适配和维护较大的工作量,我们一起优化了设备的差异性,进行了统一,在面向用户的EMUI10.0设计风格调研中,相机的整体满意度再上一个台阶,让我再次尝到重构的美妙。
不经意间,我养成了每次修改问题单主动识别坏代码、重构问题频发区的习惯。2019年,我重构的代码也惊喜获得了软件部首届鸿蒙金码奖。
重构应该是自我驱动的,每一位工程师都应该尝试着独立看护某些模块,发现代码坏味道,再大胆优化。在编程界,流传着一句话——10万行代码铸就编程高手,它也激励着我主动重构,写出更多好代码。这种量变到质变的过程,本身就是代码修炼之道。
年轻,就要一码当先
“杀”猿祭天、毕业2年拥有4年工作经验、全员格子衫……每当我看到网友们对程序员调侃时,也会会心一笑。慢慢地,我也会注意到这些标签背后增加了新内容,比如小学开通python课程,比如非计算机专业的大学生跨界编码,比如很多名人纷纷学习编程……这无一不在印证乔布斯“人人都应该学习编程”的话吗?而作为年轻一代的程序员,我们更要一码当先。
不管程序员的标签是什么,我们都需要用代码为自己代言。转眼进入华为已经4年有余,我很幸运,伴随着终端的每一步发展和崛起,我也从职场菜鸟成为能独当一面的模块设计师。工作之余,我很喜欢去视频网站看手机拆解视频、前沿科技评测视频,了解主流厂商摄像头规格及安装方式,了解未来趋势。我喜欢我正在做的事,我也庆幸我能一直做自己喜欢的事。未来面临全场景的应用设计的新挑战,这将又是新的学习之旅,但我始终相信,只要拼搏向前,再大的困难总会结束,我们终有所获。
作为26岁编码人,我常常会幻想这样一个场景:
夕阳西下,年迈古稀,家里的小辈问我最会什么,我能自豪地说:“我最会敲代码!“
本文为《华为人》版权所有,未经允许不得转载。如需转载请联系编辑部hwrb@huawei.com
本文来自“华为人”期刊
- 点赞
- 收藏
- 关注作者
评论(0)