写这篇文章,是想和身边的同学谈一谈在阿里做业务开发的方法,这些总结可能来自某本书或者某条理论或者是生拉硬拽,但都是本人这些年摸爬滚打的经验。有时候摔倒爬起来,突然想到当初看的某句话,心有戚戚焉,默默记下,但并没有去深究背后的理论,所以喜欢规规矩矩、条条框框的可以忽略本文。俗话说“文无第一武无第二”,这些经验不是最优的,也不一定适合所有人,大家自由评判,如果有人看完会心一笑,我就很满足了。
开放
工作多年后感觉“诶,别人知道这个,我却不知道”的机会有点少了,可能有点焦虑,但是没关系,学习,闻道则喜,年轻的朋友们更应该努力,养成习惯终身受益。从别人那儿学到了,也要能教给别人,互相交流才能形成良性循环,现在是信息时代,没必要藏私。做到这两点足够应付日常工作,还能形成一些影响力。
合作
公司里做事,遇到对方推诿或争吵,有的人选择刚到底(比如我),但也有人选择统统接受,无论哪种,我们要学会合作和拒绝。吵架的能力后面讲“产品思维”时还会讨论,先讨论“拒绝”。我们有一些同学很谦虚,也非常努力,总是尽最大的努力满足需求,但也总是被伤害,996 都搞不完,这时候就要尝试拒绝。当然,有时拒绝的同时也要帮对方想一下,看看有没有其他的解决方案。尤其是当大家都为了同一个事业奋斗并且对方也有足够理由的时候,简单粗暴的拒绝,只能导致停滞不前,最终损失的是整体利益。
追求卓越
人类从共同组织到社会的发展过程需要集体道德,它是法律的基础。写代码也要讲道德:设计是否有缺陷?实现是否有漏洞?多思考,不要简单为了通过测试、交付差事来写代码。有追求才能有提高,保证代码整洁高效才能赢得他人的尊重,未来别人接手时才能少骂几句。
结构化思维
初高中数学需要掌握的一项重要技能是把论证分支条件都覆盖到,工作以后要做的是结构化思维,按照某个维度切分到完全覆盖,相互之间又没有交集,这就是 MECE。
有些同学在讨论问题时不容易被大家理解,那么就尝试一下:抓主线、核心,确定讨论问题的深层本质,可能一时半会想不到最根本,但是通过一层层问自己为什么,不断寻找答案,至少能找到一个比较深入的层级,然后在这个基础上把主线逐条拆分,不要着急,一二三四讲完,基本不会太偏。这大概是《思考的快与慢》中的慢思考。
产品化思维
开发同学需要培养自己的产品思维。
产品的价值是使用价值,关键是用户体验,用户体验是需要打磨的。代码写完、测完、发布完成,但是用户一定还有各种各样的意见,而且,在数据量增大的情况下是否能保证体验是个问题,在系统失败的情况下怎么保证用户体验也是一个问题,在面临高流量压力情况下的表现更是问题。我们时刻想着用户的操作,再加上一些“技术性需求”,做方案就会简单点,讨论问题也会“显得”高大上一点。
理解用户需求,管理用户期望:很多人相信“唯快不破”,快不是唯一的指标,至少我们还要保证成功率、数据准确性,以及用户的操作体验。ToB 的产品避不开大数据量的操作,我们要在保证数据准确、同时在不影响C端的情况下尽量做到快,做不到也没关系,可以和运营沟通好,说明系统为什么慢,有多慢,有什么影响,管理好用户的期望。对于 C 端,我个人遇到转圈圈的网页等待 10 秒就没有耐心了,当然等待不是不行,但最好要有个进度条之类的东西;对于电商抢购的核心场景,用户体验没有商量的余地,也很难“管理用户期望”,我们只能做到尽可能快,尽最大努力保证吞吐量。
做业务需求,跟产品打交道是最多的,我想聊聊与产品同学的合作。
用户是很懒惰的,能走直线不走弯路,能点一下不点两下(所以,要用户点两下的功能一定是有影响的功能),相信产品在设计时会有相关的考虑,我们可能因为实现难度的原因而有质疑,但是不能否认产品同学设计的初衷。当然,提高用户的体验有很多种,大家可以一起想办法,既然我们想吵架,那还是要拿出点硬实力的。
信息是有势能差的。当初通信业的祖师爷香农提出了信息论,从此信息有了度量。信息在传输中也会有衰减、噪声叠加,每个人得到的信息有差异。从做决策到 PRD 评审,如果我们没有足够的信息,不要简单直接地否定或质疑别人的业务方案,那样效果非常差,基本上等于指着别人鼻子开骂了。我们要做的是吸收信息,同时用自有信息和自己的理解来补充、修正相关方案。当然,也不排除产品同学在设计时没有做好调研的场景,如果方案与现状不符,那大家随意……
我们的产品同学都喜欢讲“这个功能现在是这样,不排除以后要变成xxx样的可能”,有些同学喜欢揪住这个可能性不放。我个人觉得,这些只是提醒我们注意设计系统时为变化预留空间、封装变化、保证扩展性, 而聚焦主流程才是在有限的 PRD 评审时间里最该做的。“我心不动,随机而动”,只要能想明白,没什么好担心的。
信任产品同学,但也要有自己的坚持。曾经我们有一个后台管理功能,需要直接展示大量数据,用户一次保存也可能要保存很多,PRD 评审时就讨论很久,但是没有找到比较好的方案。后来我们又调研了两种方案,还是要获取、保存大量数据,不断跟运营讨论使用方式,最终确定了一套“粗调+微调”的解决方案,顺利交付。整个过程体现的就是大家对体验、对稳定性的坚持,如果项目保密相关制度允许的话之后再另写短文分享。
与产品、运营紧密合作的意义,如果我们相互信任,那么信息传递就会很顺畅,在做决策时,会从各自的视角尝试给解法。在这种合作模式下,大家的合力更大。我们在开发中经常会想到很多的“小场景”、“小概率”,解决他们需要花费的时间和精力很大,如果能从运营、产品层面解决,那么效果一定是事半功倍。当然,运营 SOP 也是要管控的,否则也会付出代价。
跟产品、运营沟通要学会讲“人话”, 我们做开发久了,对技术名词信手拈来,但是运营同学一脸懵,我建议多用类比的方案,这三年我们已经把跟我们对接的运营同学培养成了“半个开发”(运营小姐姐的原话), 说明大家的科普能力不错。
与产品运营的合作我讲的有点多,看来产品和技术的矛盾确实是永恒的话题。
计算机思维
相对于产品思维,我们开发同学还需具备计算机思维。只按照产品思维或者说“产品同学的理解”来设计我们的系统是很危险的,产品的要求绝对不应该直接映射成我们的实现,开发需要在开发框架内来做设计。
计算机思维可以帮助我们评估方案,在有多种选择的情况下与产品共同产出最优解。作为产品、安全对接的接口人,好多时候都需要现场评估方案的复杂度、可行性,对系统不了解,对编程能力、技术细节不了解肯定是不行的。尤其是“细节决定一切”,多想多思考,免得踩坑。
计算机思维偏硬核技能,我们需要不断学习,知识面要保证“宽+深”。“宽”是指与当前工作不相关的内容也要多了解,遇到问题时知道怎么用。“深”则是对于当前工作所需的技能要足够了解,了解最佳实践,追求卓越。
向上思考
如果一直都囿于自己的小圈子不考虑更高更远大的目标,那我们根本不可能达到那些目标,还在躺平的同学还是起来吧。
举个现实中的例子。作为技术人,设计方案时处处都要做决策做取舍,当我们要向上汇报或者大家一起评审决策时怎么办?首先需要明确一点,如果我们负责调研,那这个事情里边我们相比领导有很多关于细节的信息,领导可能会有其他的来自客户或者运营的信息,大家聚集一堂开会决策,要的是效率,那在开会前,负责调研的我们自己需要先有倾向,这是每个人都可以做的,因为我们已经有了相关的信息,我们可以做取舍、做决策,这是免费的锻炼机会,不要因为“让领导想去吧”而错过。
设计位面
各种方案设计,自底向上和自顶向下的设计是相辅相成的,自底向上的设计可以帮助我们了解当前的状况,比如有哪些接口可用、还需要增加哪些接口;自顶向下的设计能帮我们更好的理解需求,厘清系统之间的边界,在满足业务需求的前提下设计合理的架构。
自顶向下怎么设计?一个复杂的系统应该怎么描述?架构师在英文中也是建筑师,这说明设计系统和建筑是有相似点的。当我们把系统想象成一个立体的物体,肉眼看到的只是一个投影,这就是设计位面。
在开发设计系统时要考虑的位面包括但不限于:
各种方案设计,自底向上和自顶向下的设计是相辅相成的,自底向上的设计可以帮助我们了解当前的状况,比如有哪些接口可用、还需要增加哪些接口;自顶向下的设计能帮我们更好地理解需求,厘清系统之间的边界,在满足业务需求的前提下设计合理的架构。
1. 业务需求
我们现在做的业务特殊,好几个甲方提需求,一个业务要讨论很久。作为开发同学, 在过程中要拿捏到位,要不断确定优先级,探求用户的需求底线,了解需求的内涵、外延。比如,甲方希望做分批多次履约,甲方还希望支付前配座, 甲方可能还有各种各样的想法但又都不确定,那我们怎么办?
渐进迭代。先按照简单的方案做,先保证可用,保留扩展性。举个例子,我们做抽签时只是确定了算法,具体的业务玩法都还没确定,我们就开工了(实在是因为甲方太慢),先确定流程分,然后确定哪些地方还不确定,需要简单做保持扩展,然后我们就开始做了。后来加上了数据回流、库存兜底释放,后来为了解决支付前配座又在抽数字库存的基础上加了抽座位库存的逻辑。整体流程框架没有太大变化,我们在各种流程确定后也没推倒重来。
作为开发,我们要有“不怕需求”的气魄,敢于迎接挑战,不断探索更优的解法。不要习惯于说“不”、“做不了”,简单的拒绝会让人上瘾,同时也会让我们丧失一次深入思考业务和锻炼自己能力的机会。
坚守底线。有些原则是技术方案的重要假设,比如库存扣减指定渠道。这些“假设”对我们的方案至关重要,打破后会产生颠覆性的影响。我们要有意识地跟产品和运营达成共识,让产品和运营知道如果推翻这些假设要付出多少代价,这样他们跟甲方沟通时可以尽量避坑,大家讨论也节省唇舌。
2. 技术需求
可扩展,易维护,可测试。
3. 高可用
面向失败设计、性能、容量、预热、预案、限流、一致性、资损、容灾、监控报警、安全防护。很多词汇都和高可用相关,相互之间也有很多重叠,找到合适的子集坚决执行,日常常练常新,常怀敬畏之心,才能把稳定性做好。
4. 安全合规
我们奥运票务系统设计之初是面向全球的购票网站,所以安全合规更复杂。我经历过内外部 10 次的安全测试,参加过数次法务的讨论,光 Cookie 协议就改了很多版本。总之,对外开放的业务必须关注安全,关注各种越权、数据合规。
5. 成本考量(ROI)
运营或者产品提出的绝大多数问题,技术上都“能”做,主要是看人力投入、时间成本以及价值,投入产出比是任何时刻都可以拿来衡量的标准。
有时候,我们会被质疑为什么不能再增加点功能,比如说当前的方案还有变化的可能性,但是现在的方案已经有倾向性,那么是否要沿着这条路走很深就需要做好权衡,如果有一天要调头换方向,那么就要付出很高的代价。这时候我们要提前把风险跟业务需求方说清楚:要么少做简单做,要么让需求方保证不要调头。“不调头”的内容就是我们与业务方达成共识的底线,大家应该把这种底线牢记于心,防止哪天翻车。
常识与基本规律
空间换时间(或资源置换)
什么是空间?缓冲区、缓存、本地缓存、文件分发,都可以达到空间换时间的效果。
假如是 CS 或者 BS 的架构,有些工作在 Client 端或者 Browser 端做也未尝不是好方法,这样可以减少服务端的压力和交互。但要谨记:不要相信外界的输入,服务端要校验,不然容易产生安全漏洞。
数据结构与算法
计算机程序是算法加数据结构,做程序员要具备相关基础,不仅是为了面试,也是为了欣赏算法和数据结构的美妙之处,当有一天遇到类似的问题,至少有个思考的方向。
最短路径猜测
如果我们的系统在压测中报线程池满了,你是猜 tomcat 的线程池设置过小,还是我们的请求处理太慢?我可能会猜请求处理慢,因为 tomcat 的线程池大小使用的是集团推荐的设置,之前也没问题,而且,多数的线程池满都是因为任务执行太耗时,所以我选择相信我们内部某处处理有问题。当然 tomcat 线程池也可能有问题,怎么证明谁对谁错呢?那就看请求 trace 里的 RT,系统的负载吧,如果都没问题,那可能就是 tomcat 线程池不足,那怎么证明是真的不足呢,改一下线程池大小看看是否有效。
程序员很多时候都是在解决各种问题(bug、性能、安全) ,解决问题不是靠争吵动嘴的,“Talk is cheap, show me the code'才是王道,推理、验证、尝试修改,不断缩短处理问题的路径很重要。
奥卡姆剃刀原理:有时候我们的产品同学、开发同学在讨论到情绪高涨的时候会有各种各样的想法,这时候请大家还是坚持实用主义,坚持 “KISS” (Keep it simple stupid),坚持“如无必要,勿增实体”。
有时候我们需要一些理论来让我们讲的话听起来高大上,但有时候我们真的需要一些深信不移的理论,比如 SOLID、KISS、DRY。在开发过程中,我们要不断用各种假设结合这些原则来证明我们的设计,如果觉得之前的设计不好,不一定要改,但是要想、要思考,这会使我们有更深的体会。“知行合一”,既要知道理论,也要在实际中运用,慢慢形成自己的风格,形成对技术对行业的理解, 这就是每个人自己的“道”。
“求知欲、好奇心、理解力” 是 2020 年一位诺贝尔奖获得者说的三个词。我们没有机会接近诺奖,但这不妨碍我们去追求知识、艺术、爱情,去探索这个世界或者社会的奥秘,保持一颗年轻、求索的心。(正文完)
有话要说...