作者 | 赵裕
悟已往之不谏,知来者之可追。
从初入职场到现在,已经两年有余,看起来还是前途有限、后患无穷。写罢此文,聊以自慰,勉过往而励将来。
长久以来,我一直在思考两件事情:怎么把过往的经历抽象成可复用的经验,以及怎么把已有的经验应用于将面临的问题。
本文算是对过去两年初入职场的一个总结吧,由于自己身处一个业务驱动的部门,所以“如何在业务开发中实现自我成长”就是过去一段时间最重要的缩影了。可能看问题还不够深刻,立意还不够高远,但是留下一份快照总是好的。
一、深刻理解业务开发的特点
对于没有进入这个行业的人来说,技术人员的工作可能就是每天坐在电脑前敲代码,但是对于每个业务向的开发来说,可能每天花在代码上的时间并不多,大量的时间被琐碎地分割了,于是我开始反思,必须要认识到业务开发的特点,才能高效地生存在这种环境中。
1. 兼顾协作与闭环
首先说协作,在真正进入工作之前,我们大部分时候都是在一个人写代码(比如刷算法题),但是在实际的业务开发中:我们的代码往往是为了实现产品/运营的需求,要与客户端/后台交互,并由测试同学进行验证。这种改变带来的一个重要认知就是要从不同角色的角度去思考问题,如此才能顺畅协作:
- 产品:重点应该是预期的效果、上线的时间、核心数据指标等最终输出物
- 后台:重点应该是协议的制定、方案的设计(扩展、复用、性能等)
- 测试:重点应该是用例的设计、Bug信息的描述(是否必现、设备信息、日志、录屏等)
总而言之,一定要跳出自己的技术栈,站在别人的角度,才能高效协作。再说闭环(以客户端为例),在工作的第一年,我会发现自己的联调效率很低,比如一个UI上有一个倒计时组件,后台下发了一个时间戳是昨天的,我的逻辑显示的是00:00:00,而产品预期可能是已结束。
后来我就开始意识到客户端自测的重要性,通过制造假数据把所有的边界问题(如倒计时时间戳远小于或者远大于当前时间、文案过长、图片比例不符合预期等)都自检,这样就可以在开发阶段,把一些产品遗漏的逻辑都覆盖到,大大降低了联调后返工的风险。
2. 复用而非创造
业务开发有一个特点是大部分功能都不是需要从0开始的,往往在项目代码已经有过类似的实现,复用并不仅仅是写一个方法,以供反复调用,方案、策略同样可以复用。
所以有一条很重要的经验就是需求确定后、启动前一定要召集相关人员评估方案,我自己就曾踩过这种坑:选择了一个行业通用的方案,最后要合流的时候却发现有更好的做法,不想违背原则(写烂代码)只好临时加班。
所以后来,每每有比较庞大或者自己没有十足把握的需求时,都会定位到相关开发,咨询清楚相关背景再敲定方案,虽然启动时间变长了,但保证了合流的代码质量和上线后的效果。简单来说,提前评估方案可以避免重复工作、降低返工风险、降低事故概率。
3. 尝试了解业务全景
大家常常会自嘲为一颗螺丝钉,大部分时候也确实如此,但这并不妨碍我们去跳出需求、跳出技术栈,一窥业务的全景。比如自己一开始来应用宝实习,感觉这个App就是一个下载应用的(大部分人的认知),但这只是一个客户端视角。
如果站在后台视角,应用宝是一个App的分发平台;如果站在商业化团队的视角,应用宝的首页、搜索页等可以带来广告收入,游戏的分发可带来收入分成;还有内容化、游戏运营以及和灰产的对抗等等。哪怕只是浅层的了解,多了一些视角,做业务、评需求的时候就会多一些维度的思考。
除了业务的全景,还有流程的全景,业务开发如果定义为完成一个功能就太狭隘了,自己目前体会到的流程如下:
- 评审:通过产品详细了解需求的背景、目标、价值等
- 方案:具体问题具体分析,但一定要在开发之前
- 开发:完成自己的逻辑,做好各种边界测试、异常测试
- 联调:自测完备,联调就轻松
- 测试:重点是除了问题能快速定位(制定好日志、调试工具等)
- 灰度:
- 上线:上线不是终点,涉及统计/结算的需求一定要持续关注,避免背锅;不管是版本发布还是动态发布都要观察Crash等技术质量指标(本来应该流程约束的,自己也要有这种习惯)
二、发现问题并解决优化
个人感受颇深的是:无论是初入职场还是工作三五年,都会有一些自己的习惯或者说局限性,有时候甚至自己都没有觉察。
1. 个人开发习惯
开发习惯养成的两个核心是:发现重复工作并自动化+通过加深理解寻找最佳实践。这里举一些自己经历过的例子:维护别名集合。
比如我会把自己常用的命令都封装成别名:
# 查看当前Activity
alias v_adb_current_activity="adb shell dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'"
# 查看Activity堆栈
alias v_adb_activity_stack="adb shell dumpsys activity activities | sed -En -e '/Stack #/p' -e '/Running activities/,/Run #0/p'"
# 触发一个uri
alias v_adb_deeplink="adb shell am start -a android.intent.action.VIEW -d"
# 录屏/截屏
alias v_adb_screen_record="adb shell screenrecord //mnt/sdcard/demo.mp4"
alias v_adb_pull_record="adb pull //mnt/sdcard/demo.mp4"
alias v_adb_screen_cap="adb shell /system/bin/screencap -p /sdcard/screenshot.png && adb pull /sdcard/screenshot.png"
其实大牛们就是这么做的,比如oh-my-zsh就提供了很多有用的别名,常用的git命令别名有:
gup -> git pull --rebase
gcmsg -> git commit -m
gst -> git status
等,完整版见:https://github.com/ohmyzsh/ohmyzsh/wiki/Cheatsheet
另外就是自动化一些工作,比如之前经常要做一个zip包发布,每次都需要先把xml文件里面对lua文件引用修改成对out文件(lua文件编译后的二进制文件)的引用,手工操作繁琐且容易出错,后来做成自动化脚本后颇受好评。
除此之外,对于常用工具也应该系统学习,比如Git、Proguard、Gradle的官方文档,自己接触过的几个项目,混淆脚本和构建脚本写的都比较混乱,本质原因就是并非每个开发都能够标准地使用这些工具。
比如有一段时间,我发现有人会把DEBUG=true提交到仓库,又或者把一些很劣质的代码带上去,分析之后发现他们每次git commit的粒度都很粗,导致提交前无法用git diff自己检查,其实完全可以把一次大修改拆分成多次commit,在合主干之前确认无误再合并自己分支的commit记录,既可以保持提交记录整洁,又可以在合流前的频繁修改阶段详细记录每次修改的原因,可惜很多人对Git的理解并不足以进行这种尝试。
2. 业务研发流程
对于具体业务要具体分析,但都应该做到以下几点:
- 对于核心业务要主动输出文档,不仅为他人方便,也可以节省为别人答疑的时间
- 对流程化的东西做好记录,比如常用的发布地址、容易忘记的配置项的含义(比如我们动态化页面的发布系统里面,灰度时要选定版本号、版本名、Build号、QUA等字段,很多字段相似难以区分,最好记录下来具体含义)
- 解决问题而不是达成任务。比如一开始的时候,不同的后台/产品在提供UI元素的协议字段的时候会有很多差异(比如应用名字段有的叫app_name,有的叫app_title),如果是达成任务,你可以照搬提供的字段;如果解决问题,你就会综合历史因素、合理性等制定一个规范,类似代码的变量命名规范。
三、坚持沉淀复盘输出
简单来说,沉淀、复盘是认知层面的,输出(分享、写作)是实践层面的,前者是必不可少,后者是锦上添花。但把沉淀复盘的东西以语言文字的方式输出,我认为有3个不可替代的好处:
- 更加深刻:如果沉淀翻盘仅仅停留在思考层面,往往是碎片的、狭隘的,输出可以接受他人的反馈(赞许或是挑战),有更加全面的思考。
- 更加容易感知:思考是虚无且抽象的,输出一篇文章、做一次分享是更加容易度量的目标,也更容易让自己感知到思考的收获。
- 更加有价值:沉淀复盘是个人成长,也是知识积累,输出给大家不仅可以持久化,还可以塑造长久的个人影响力。
无论是业务开发还是基础架构,我相信沉淀复盘都是可以最大化自身收益的,同时也能造福他人。在工作中,写过的文章/文档,都会冥冥中造福他人、宣传自己:
案例一:
案例二:
四、培养代码之外的能力
作为一个业务开发,代码之外的能力同样重要,这些能力实在太多了,我自己也一直在学习,下面分享一二。
1. 沟通协作
个人认为所谓的话术、措辞都只是沟通协作的“表面功夫”,高效沟通协作的本质在于:从全局出发,综合各方诉求,去解决问题,实现总体最优。
如果只考虑自身利益,工作往往最后变成了零和博弈,总有人会不爽(产品怪开发Delay、开发怪测试adb都用不熟练......等等)。我导师给我分享的一个技巧让我印象非常深刻:遇到自己不能解决的问题不要直接拒绝产品,应该把问题向上升级,周知到自己的导师/leader。因为拒绝解决不了这个问题本身!
明白了这个问题,工作中很多事情都会有了新的角度。比如产品的需求单里面经常对UI元素的命名不标准,你就不会去吐槽,而是会去制定规范、进行引导;测试描述Bug不够清楚,你就不会去抱怨,而是发现可以用adb connect + Vysor实现远程调试,完全接管测试机。
2. 时间管理
长久以来,困扰我的一个问题就是时间管理,尤其是做业务开发的时候,你要和不同工种打交道:需求要和产品对、UI要和设计对、联调要和后台对、验证要和测试对,再加上各种会议,一天有一大半的时间要依赖别人。时间管理真是一个太宏大的话题了,后面打算单独一篇来讲,这里先跳过。
(相关书籍截图)
3. 情绪控制
这可能是我做的比较差的一点了,还被我的导师委婉地指出过。以至于有一次我听说,某个曾经合作过的产品说我算是开发里面脾气好的,我就很惊讶,后来想想应该是当时和我合作的后台更加暴躁吧。
虽然只暴躁过几次(要么是出了些小问题没忍住当面吐槽、要么是过于生硬地拒绝),但每次都很后悔(毕竟都是打工的,也不想给别人带来不愉快),后来想了想这个问题的本质,大概是两个因素叠加的效果:情绪控制差+风险控制差。脾气好的人不会暴躁,能把工作处理得井井有条的人也不会。
要走出这种困境,除了磨练心性,就是要提供工作技巧,比如前面提到的问题升级、时间管理等。暴躁的本质还是无能狂怒。
五、与自己的焦虑共处
长久以来,我能感受到业务开发对自己的一些影响,可能每个开发都会有一些焦虑:
- 没有多余的精力学习新的技术
- 工作过于重复,缺乏不可替代性
- 业务驱动,缺乏深度,没有干货
- 等等
个人认为,首先可以明确自己的本心,如果实在不能接受业务驱动的开发就应该换个方向,但真正的纯技术岗又有多少呢?技术的直接作用本就是创造价值。
如果选择了业务开发,就应该既来之则安之,发现业务开发中可优化的点,去解决而非抱怨,通过沉淀复盘输出建立影响力,甚至可以提供自己的解决方案,进而变成一个不可替代的人、有干货的人。
六、结语
工作的一个比较好的状态应该是:个人成长进步与业务价值交付的有机统一、相辅相成。本文是对过去两年的一个总结,可惜很多事情都没做好记录,记忆总是零散而残缺的,而且局限于技术栈和业务领域,难免有局限性,但希望能引发一些有价值的思考。
本文中有很多自己的主观看法,但环境和心态总是在不断变化的,因此,引用列宁在《共产主义》中的话作为结尾:
他忽略了马克思主义的精髓,马克思主义活的灵魂:对具体情况作具体分析。