本文思路较乱,大概是平时吃的太多了外加心烦意乱
实习概述
根据我校软件工程专业培养方案,学生需要通过实习提高自己对社会的认知能力,学以致用,更好地适应社会发展。依照学校的指导方针,本人在今年4月份参加了腾讯实习生招聘流程,并最终顺利通过终面,并在7月份来到深圳腾讯进行实习,目前已顺利完成六个月的实习并从腾讯公司离职。
我在腾讯公司的实习岗位是后台开发,归属于腾讯PCG事业部的微视后台开发团队。随着实习工作的逐步深入,我个人对公司技术开发和其他流程的观察与看法也逐渐深入,我将在其他章节中进行详细描述。我在团队中主要负责活动信息触达相关开发工作,用户在端外参与活动或在端内推广活动的活动弹窗均是由我控制的模块进行下发。为了提高用户的使用体验,我们说服产品经理仅在首屏或用户切换页面的情况下展示活动弹窗。我们需要在这有限的时机和固定的形式内将不同渠道的信息综合整理。按照一定的次序向用户下发我们的信息。用户信息触达承载了产品活动的大部分内容,是产品活动能否推动用户大盘上涨、提高业务转化率的关键工作。
工作内容
弹窗服务收归
在上一次的实习报告中,我已经提到需要将弹窗服务进行一次大的完整的收归,在十一节假日之后,这一议题正式被安排在计划表中。项目背景在于弹窗服务在之前是由不同的小组件所组成的,在每个服务与每个服务之间的信息是互相不连通的。因此产品在决定信息下发的过程中就遇到了困难,由于模块之间相互不连通,没有全局的优先级进行控制,所以经常出现多个弹窗之间的逻辑上是会相互冲突的。同时由于弹窗内容没有收归,大部分统一管理模式的想法也无法实现,例如弹窗内容需要根据用户群体进行分批投放的功能仅部分场景下支持,活动内容的自动上下限以及活动内容的紧急拦截,连续弹窗串联能力都不是全部模块所具备的。并且由于弹窗的样式在以前属于野生发展,并没有任何限制,导致在收归前弹窗样式有20余种,但是大部分可能因为活动的停止已经被废弃。因此对于产品来说,一个统一的弹窗服务管理是非常重要的。但是这次收归计划需要依赖客户端的发版一同发布。因此在时间上没能提供足够充裕的时间,让我们理清所有的逻辑以及理清所有未知的问题。不过即使项目有风险,我们也要一定推行,因为这是完成一次大规模的收拢计划。
在服务收归的前期,我不断地理清代码中现有的逻辑,并且与客户端开发的同学,进行不断的对接与测试。确定了现有服务所有的数据输入输出接口以及产生作用的时机与效果。仅仅是客户端何时会与后台进行通信的时机,我们就用了一个大白板来描述所有的情况。很难想象,客户端在过去一年的野蛮发展过程中,产生了大量无用的代码,加重了客户端与后台的共同负担。这些杂乱的代码如同雨林中倒塌腐败的树木,不成体系,杂乱无章,但是却充斥着整个空间。相关记录的缺失也让这次收归的行动变得异常困难。许多不清晰的代码逻辑无人维护,也无人知晓,这段代码是否可以被删除,成为了摸清情况最大的绊脚石。由于客户端的更新不像后台的更新如此频繁,因此对于客户端的同学来说,他们的开发将会变得更加谨慎,一旦出现意料之外的情况,便没有合适的手段进行弥补。后台开发的任务也不轻松。为了这次升级的服务不出错,我们要同时保证两套逻辑都能够在线上同时运行。待到时机完全成熟之时,才能将旧的代码逻辑从我们的代码库中移除。但是非常尴尬的是直到我实习结束,我们仍未实现真正理想上的弹窗收容,旧代码仍然没有从代码库中移除,而是直接转交给了另外一位同学。(我现在十分担心,我埋了一个大坑给他)
弹窗收归计划过程中,我们发现了一条从来没有料想到的长逻辑。可以说这段逻辑的复杂程度不亚于理解一个英文文章中的长难句。这一活动的处理流程是由一位同事的模块开始向客户端下发了一个神奇的参数,客户端在没有理解这个参数的情况下,就将参数直接向我的模块进行传递,在我的模块收到参数之后会理解参数的内容,并将其转化为需要调用模块的信息,再通过rpc调用其他服务来获取弹窗具体的内容。这一链路在起初貌似不长,但在后来我们发现。这一参数的下发和客户端的中转,并不像想象中的那么简单。一方面参数的下发,是后台模块根据不同的机型不同的ID进行过滤,只有一部分命中名单的用户会拿到这一个参数。同时客户端在转发时也不是完全的实时转发,是在特定的时机特定的场景下才会将参数转发给后台,但是在处理这一参数之后,客户端并不知道自己所处的状态,因此导致经常出现下发内容的丢失。同时后台在处理的过程中,由于不知不清楚客户端的场景,因此做了大量的验证逻辑来检测这个弹窗是否是用户应该出现的内容。在检查弹窗内容时,模块隐式调用了其他服务提供的接口,所以造成了调用链非常长,时间延迟非常高的情况。这一尴尬的调用链条在整个APP设计之初是完全没有想到的,在那个项目开发时也是没有预计到的长链路。可以说他几乎用到了弹窗收归后所有的功能点,但是仍然没有满足其原本的需求。更大的挑战在于我们将原本的重客户端轻后台的逻辑转化为重后台轻客户端的逻辑,原本客户端所做出的特殊逻辑在后台全部需要实现,显然这在短时间内是无法完全实现的。
我们想做出一个更简洁更轻量的后台服务,让所有的弹窗内容采用统一的方式进行下发,避免样式混乱或逻辑复杂的情况。这一重大的长链路即使到最后也没能完全解决,但在大家的共同研究之后,认为这个长链路本身存在的价值就不高,因此应该在后期的产品中逐渐废弃(解决提出问题的人)时间紧任务重,我们的收归项目在截止日期完到来时还没有完全完工。在风险评估上,这处于严重的延期问题,最终在后台客户端产品多方协调下,我们终于在赶在客户端正式发布版本之前,将这一服务在后台发布上线。期间涉及的字段调整与逻辑调整数不胜数,而这一项目也成为我实习过程中做过的最困难最复杂的项目。
弹窗服务优化
在完成了弹窗服务的收容计划之后故事并没有结束,弹窗服务在之后的运营中还出现了各种各样的问题。
在我们实际运行时,发现同一个活动需要在旧模式中与新模式中都能运行,就必须按照新旧方式全部都配置一遍。由于我们的项目过度抽象,大量的参数都可以在程序之外的配置平台上进行调节,一个活动上线往往需要设置五六个配置表,每章表之间的关联与正确性都需要人工自行保证。常常容易造成部分配置设置后忘记发布,导致整体链路不能完全实现。
更有些需求因为配置过于灵活就想通过配置玩些骚操作,将一些本来没有关联的模块通过参数传递的方式进行连接。例如前端页面在完成流量导入后,向后台携带了一个指向活动的链接,这个链接的信息将直接影响弹窗下发后用户看到的弹窗信息。这两个弹窗中的内容衔接就是通过动态参数填充的方式完成传递的。至于这个参数中包含了什么信息已经会产生什么影响,后台程序也是完全不知情的状态。还好前后端的沟通采用的是加密协议的方式,不然出现参数注入什么的就非常麻烦了。
在服务优化的过程中,我们还遇到过前辈曾经埋下的坑,直到我们开始使用时才发现完全不可用。例如有弹窗曝光次数判断的计数逻辑,取判断条件的补集时逻辑上出现了偏差。还有在弹窗下发时原计划是可以采用XML的富文本,但是在客户端实际检查代码后发现,这一功能实际上根本并未实现,当时定理的字段不了了之。更有趣的是,曾经有位产品提出,为了避免弹窗之间出现冲突,她管理的弹窗不在应用启动的首页出现,客户端为此做了特殊的处理逻辑,然而当春节项目上线时,却慌里慌张的要求她的弹窗也能在首屏曝光。这种前后矛盾或者顾头不顾尾的骚操作见的多了。
Tab与Banner
长时间专注于弹窗功能的开发使得我对其他模块的设计情况不是很了解,巧的是我在实习的最后一个月接手了一个新的服务进行维护。这个服务提供的能力是控制应用第二页面的大多数内容的下发,而我修改的内容主要是顶部Tab栏和进入页面后的Banner信息拉取。
在这个小小的需求改动中,我发现代码木块真的十分脆弱,一点点小小的波动都会致使服务功能上漏洞百出。一个小小的Tab内容,来源就有三种:固定内容,实验内容,调用内容。我的任务是需要让其实现部分的配置化,能够在不修改程序的情况下插入需要的Tab标签,以此置顶或发布活动页面内容。Banner的改造也基本相同,都是将原本固定内容获取逻辑修改为可配置的自适应逻辑。在这种配置化改造的过程中,我深刻认识到自适应代码的鲁棒性提高真的是一个非常麻烦的事情,各种意想不到的配置方式可能都在挑战代码的边界情况。一些本以为正确的写法在实际运行的过程中却可能会出现内存泄漏等不安全因素。外加对代码原本逻辑的不了解,可以说在改造过程中,处处如履薄冰。
编程上的难度与风险都是可以预计和解决的,但是埋在代码中的坑却是无人能知的,尤其是在自己不是开发者的时候。由于大哥们都太忙了,这个模块自从我做了一点点修改之后,只要有模块相关的疑似BUG都丢到了我这边,这可把我整晕了。一会儿是RPC调用失败,一会儿是实验数据失效,一会儿又是数据上报异常。各种各样的BUG单如雪花飘落,不期而遇。更加尴尬的是大哥给的前辈的交接文档对代码中的潜在逻辑与发展历史基本为零,只是简单的描述了每个功能的命令字与代码位置,对其内容的描写约等于零,这真的太令人失望了。在实习期最后,我干脆放弃了这个模块的维护,所有的问题能拖就拖,能演就演,完全没有梳理弹窗模块时那样充足的心力了。
技巧提炼
开发模式
在上一次的总结中,我提到了公司内部有一套十分完整的开发部署方案,对开发效率的提升有至关重要的作用。众所周知,一套友好的环境能够提升开发效率,增强开发之间的协作能力,但是当他变得不友好的时候,就会变成了我们升级服务和开发上的阻碍。从开发模式上来说,我们开发组从11月开始启动春节项目之后,开发模式就由原来的主干开发模式切换到了现在的个人仓库开发模式上。但是我认为比较尴尬的是,这一能力并不依赖于git自身的代码管理机制,而是依赖于Golang的这门语言自有的包管理机制。Golang在前几个版本中并没有像Java和Python那样丰富的包。别说丰富的包了,就连包管理机制都并不存在。
开源社区在自己实现了一套包管理机制之后,谷歌将其抄袭,并且一直在更新在新版本中,但是包版本的管理和依赖处理又辣鸡难用。个人认为谷歌在这门语言的开发过程中,有一些狂妄自大,导致其出现了一些难以被接受的使用方式,常用功能被砍、主观加入骚操作,现在又开始抄袭开源社区(还没抄好)。我们项目中的每一个模块都将转移到自己独立的仓库中成为一个包。每个包都需要封装接口供外部的其他模块使用。区别于原来的主仓库模式,所有人的代码,按照文件夹的方式进行分类管理。这一开发模式对开发人员的接口设计理念和代码编写习惯有着较高的要求,否则代码的引入和调用将变得非常困难。
然而特别尴尬的是,组内许多开发我认为是没有开源代码编写经验的,或者说没有开源包的编写经验。在函数的封装与暴露接口的方面,经常出现反复造轮子以及封装不具有通用性的功能。在接口维护的过程中,既没有文档说明,也没有Changelog。时常出现接口功能或参数改动导致函数编译或运行时报错的情况。我认为这一问题为我们的开发埋下了巨大的隐患。但是发展中的问题总是要在发展中解决的,如果小组的成员更多的了解一下开源软件是如何进行编写与维护的,可能对未来的开发有较大的帮助。(我之后也要努力维护我的开源软件包)
环境治理
开发环境是开发人员所依赖的最重要的一个基础能力,但是组内的开发环境治理则是我曾面对过的,让我最恼火的一件事情。在我刚刚来到公司接触开发时,我们有比较明确的环境区分。基本上较为清晰的分为开发环境与测试环境。即使后来服务在多个发布器上进行迁移,开发环境与测试环境的分割,这一点基本上没有变化。然而当我完成弹窗服务的改造之后,我们的平台治理同学提出了一个较为大胆的想法。全面抛弃测试环境,而使用流水线自动打包生成的程序在预发布环境进行测试。这意味着我每次完成修改的代码必须要经过十几分钟的流水线才在测试条件下进行联调与功能试验,一次简单的debug流程就有十几分钟,这是难以接受的。同时比这更难以接受的是我的服务要连接多个基础性业务,而这些基础性的业务并不全有环境的区分。有些服务经过改造,同时支持正式环境与发布环境,有些环境没有经过改造,仅支持正式环境,有些服务曾经经过改造,只支持测试环境。每次完成全电路调试,通常需要将服务在几个环境中经常切换,这是非常痛苦的事情,严重降低了故障排查的效率和,代码的安全性检查。
测试的环境并不是按照模块划分的,有一些公共组件的测试,通常需要在后台流量入口修改环境变量。当两个人同时在测试某一公共组件的联通性时,经常会出现变量的相互冲突。另外有时为了测试是否出现了异常情况,通常需要注入一些启动时的环境变量才能够实现环境的测试,但是我们的标准流水线中又不支持自定义变量,在每次代码提交之后都会重置这些变量的设置,导致开发人员需要自己在机器上多次设置该变量。
这些问题在经过多次吐槽和反馈后才有了一点点的缓解,在修复的过程中因为缺乏支持,经常出现遇见问题却午饭按时解决的问题,整体的升级过程让人厌烦,新的模式无法满足开发的需要,流程也不通畅,数据都未打通,但是却基于将旧的开发环境和模式全部移除,强迫开发者自己去踩坑,是在让人头疼。
理想中的测试环境应该是按照项目维度或开发者的维度相互隔离,但是又保证其联通的可选择信口或者叫可配置性,这样子的话能最大程度的提高大家的时间利用率。
质量提升
由于我们的研发流程处于不断变化,不断强调质量的过程。因此在我持续的后期,我们的流水线中引入了CodeCC的质量检查。在这一检查中将使用更严格的语法和编程习惯,对现有的代码进行全面的静态检测。对于这一点的改变,可以说又爱又恨。一方面这确实能够提高我们代码的实际质量,至少让代码变得更加好看。但也引入了一部分没有必要的优化,使得工作量有一定提高。可以说我们走出了一条先污染后治理的过程,而这治理的过程必然是痛苦的,必然是需要花费一定精力和时间的。
刚刚我提到我们的代码在重视代码的质量的提升,以此来减少bug的出现。但是仅仅有静态的检查是不够的,我们后期引入的单元测试来提升代码的质量,但是又有多大效果呢,这个我对此表示怀疑。单元检测与接口测试不同,单元检测是完全黑盒的,只关心核心代码的输入输出正确性,只关心每行代码是否真的有被覆盖到,不关心外部接口对接的正确性。而代码中对于外部的调用过程是完全匿名的状态,采用mock的方式屏蔽了rpc的外部调用。但其实在我的理解来看,每个模块中的逻辑内容并不复杂,只是将数据简单的打散与组装。真正经常出现问题的模块通常是模块之间的rpc调用,然而这一部分却被我们的测试代码给忽略掉了。多个微服务之间进行通信时的协议、字段和内容定义是影响程序能否正常运转的关键,这一部分也常常因为开发者之间对接的不够完整通畅导致歧义的出现。
测试代码通常认为外部调用的返回值都是正确的,都是我们期望中的值,然而没有考虑到所有的边界值情况,也不考虑协议中出现偏差的部分。可能两位开发的代码都是能通过测试的,但是根本无法连在一起使用。根据现有的情况来讲,我们的代码在经过流水线的测试之后。可以直接向外网环境中进行发布。去除了以前需要人工review的流程。这种完全依赖自动化测试的方式,虽然从目的上来讲是提高效率释放人力的好事情,但是我们的自动化测试好像做不到比人更好的代码逻辑覆盖,我认为这是给bug出现埋下了一些隐患,同时也为我们的工作效率的提升制造了阻碍。一旦错误的代码可以轻易通过我们的质量检测,也可以轻易达到流水线所要求的单元测试覆盖率。一个简单的逻辑bug可以轻易的就被发布到线上,因为他没有在任何样例中被检测出来,这种既当球员又当裁判的过程,仍然在我们的开发过程中存在。同时单元检测的工作量给整体工作量造成巨大的负担,一般来讲单元测试的书编写,可能是开发时间的1.5倍到一倍之间。有些简单的逻辑代码,可能它的测试代码会比正式代码还要更长。可以说最差的结果就是我们花费的时间,消耗了精力,投入了资源,但是却没有收获更少的bug。
工作体会
这段起完全是我个人对工作上的各种吐槽,没有太多认真的思考,如果思路上有偏差也是正常情况。6个月前对于刚来到腾讯的我,任何东西都是新鲜的,任何东西都妙不可言,然而6个月之后的我。对腾讯有了更多的认识,更多的了解,在其中也发现了一些,让人觉得不太舒服的事情想要吐槽。
产品体验
以我对国内视频软件市场的使用体验和观察来讲,我认为短视频类型的视频平台可能已经逐渐陷入增长困境。一方面发掘新用户的成本已经比早期时更加高昂,另一方面如何产出更优质的视频留住用户也是各个平台需要考虑的事情。然而让人最心痛的是,微视根本就不注意提高自己的视频质量,在首页推送的内容中,经常是毫无意义毫无营养的选秀内容。平台整体也缺少优质的视频制作者,普通用户在其中的参与度更是少之又少,基本约等于零。与哔哩哔哩等视频网站不同的是,微视基本上毫不在乎用户的习惯培养与用户的内容养成,只是一味地通过发红包和其他方式刺激用户进入微视来进行短期的用户数量提升,QQ和微信等流量平台已经在大量投放微视的广告了,但是我认为没有真正抓住机会。
讲道理公司层面上大老板们已经给了微视很多的资源了,但是微视缺一直没能走上正向循环的过程。我不相信相关的产品和老板看不出这一点问题,但是可能也是对此无能为力,产品的逻辑根本没有任何改变。如果在今年的春节活动中微视不能达到自己的里程碑,将有被公司直接放弃的风险。
技术积累
说完了大层面上的问题,我们再聊一聊小问题。各种人士的变化令产品的决策和长期的规划不明显,有可能前一段时间还是专注于好友的内容,但后一段时间却专注于平台的建设,不考虑综合能力的提升,而是在短期内单抓一点来解决。有一种令人抓大放小的感觉,同时在流程上经常急匆匆地切换平台或收紧各种规范,这也使得开发者将背负更多的开发成本。我们有一些产品同学在提出需求和分析用户时,过于注重数字上的变化,完全不考虑整个产品还缺少什么用户还需要什么
我原以为像腾讯这种常年积累的公司,应该有一套自己完整的业务流程,但是后来发现可能只是在不同的部门有不同的流程,部门之间隔着厚厚的交流壁垒,这可能也是公司整体提出开源协同的原因吧。但是真正搞过开源的大佬并不多,大部分都是毕业后在各个小公司工作了一段时间后就想办法跳入腾讯进行工作,完全没有机会真正的参与过开源代码的编写。都说小马哥是技术起家,但是资本化运作之后完全没有技术主导的感觉。不比阿里有整体的语言积淀和统一框架(听说的),腾讯内部对于代码风格,注释风格,基本语言都无法统一。
团队氛围
最让人郁闷的是,在人事上可能确实存在着站队的问题,不能整一些内部方向不正确的事情。通常产品考虑的不是用户喜欢什么,而是老板们喜欢什么。而开发经常急需解决的问题,也都是老板提出体验疑问。在团队中技术完全不能作为任何主导,什么事情都是由产品或老板的决策牵着鼻子走,很多时候为了利益的划分做出一些牺牲。
在春节项目的开发过程中,大家本可以不那么紧张,在工作之余可以保持之前的开发进度,偶尔还能稍作休息。但是为了不让项目内其他人看起来我们太清闲,大哥就接一些没有什么意义,但一定要做的需求。额外承包的工作就会导致新的工作量,对于开发人员来说就一定会导致加班。这种毫无意义的加班对于项目的进度基本是毫无意义的,只是能在报告时有更多的亮点可以谈。我认为这些多余的任务和时间是完全没有价值的,最大的价值就是仿佛在向别人说明我们真的很忙。但其实从另一个角度来看,这也可能说明我们的开发设计或者我们的决策根本不够高明。我讨厌毫无意义的加班,我讨厌毫无意义的工作,我希望做出真正让用户感觉舒适的产品,而不是让老板感觉满意的产品。
只追求短期内用户数量的提高与变化,完全不在乎用户使用的心理。可以说只是不断的捞新人进来,但是没有保住那些已经来过的用户。视频的内容天天也都是腿腿腿,活动的方式也都是天天钱钱钱。即使已经投出了上亿的资源,但是却没有任何用户领情。原本应该定位于用户创作内容共享的平台,却却变成了单向传播视频内容的营销傀儡。可以说一个普通用户,在微视中几乎毫无存在感,能有的交流也仅仅局限于朋友圈之间。这相当于停留在上一个大众传媒的时代。这与当前的自媒体理念,我认为是完全相反的。微视很有可能是历史中被淘汰的那一个,虽然发展前景不佳,但是工作还是要做的,其实体验不佳,但仍然要做,因为这就是大哥们的意思。(实际上也导致了许多同事的流失)