SegmentFault 前端早早聊最新的文章
2020-04-30T23:00:00+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
今天聊:你晋升失败的原因是什么
https://segmentfault.com/a/1190000022430769
2020-04-30T23:00:00+08:00
2020-04-30T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>又到了一年一度的阿里晋升季,按照过去几年的经验,应该还会有一波熟悉的和不太熟悉的同学在未获得提名,或者答辩失败后,来找我咨询如下两个问题:<br></p>
<ul>
<li>为什么我做这么好不能获得提名或不能晋升成功</li>
<li>现在外面还有哪些 Scott 大大认为不错的公司机会可以考虑</li>
</ul>
<p><br>前面一个问题 ,其实是情绪的延续,可能也确实经历了一些不公平或者不客观的流程,后一个问题则是问题的逃避,内心窝着一团气,很容易冲动行事。<br><br><br>但幸好之前几次,当时的你来找了我,我会用掏心窝的话,把你冷静下来,于是你重新站起。<br><br><br>今年为了不再微信或者线下一对一的疗伤,我打算把这些想法稍微汇总一下,不一定能让你冷静,但可以帮你降温,也或许能在晋升之前,帮你理清晋升的主轴,从而更顺利的答辩。<br><br><br>首先,我们来尝试回答两个问题:<br></p>
<ul>
<li>公司的晋升,目的是为了什么</li>
<li>在你大脑中理解的,应该靠什么说服评委</li>
</ul>
<p><br>这两个问题很关键,不清楚公司晋升的出发点,就失去了基准线,而不拿捏好后者的答案,就失去了谈判条件。<br><br><br>关于这两个问题,我从前写过一篇晋升的逻辑,今天看来还有一定参考性:<br><br><br><br><br>简而言之,公司晋升是组织视角,关于人才选拔,本质是一个组织生长和补充优质血液的通道,再说白点,就是让有能力的人上,去承担更难做的事情,所谓能力越大层级越高责任越大,而在你脑海中所驻留的观念是什么呢?<br><br><br>我们接着聊,抛开关系和运气,被提名和通过晋升一定要满足如下两个条件:<br></p>
<ul>
<li>有出色的业务结果,业绩之前几个 S 的绩效要 B+ 到 A</li>
<li>有显著的能力变化,过去一年,大量的表现出超出自己当前层级的能力,无论是技术还是合作</li>
</ul>
<p><br>业绩是反应的你的贡献和价值,技术成果是反应你的沉淀和能力,这两个基础条件需要满足,如果不满足也不是不可以,比如你是在部门呆了 4 年没有晋升的老人,刚好手头也在长期在负责比较重要的项目,团队离不开你,这次不晋升你就要离职了,此时门票可能会分配到你这里。<br><br><br>接下来聊你的老板,他内心是有一个 Pool 的,也就是晋升的队列,今年推谁上去,明年推谁上去,这样讲并不是说,这件事好像是很有操作性,有那种技术人员不以为然的政治考虑,而是作为老板,维持团队稳定性是他天然的职责(如果你参与过招人,你会明白从社区招优秀的前端有多难),而为了保持稳定性的同时再保证战斗力,他就要有他的一个晋升策略,业绩最好的未必会被晋升(当然能力也不一定到了下个层级),能力到了也不一定会被提名(当然业绩可能还不够亮眼),业绩和能力到了也不一定有机会(心胸和格局可能还没充分撑开),他会综合评定,推选最有把握的人选,争取不浪费一个名额,每一个被提名的是最有把握晋升的。<br><br><br>所以你看,这件事情,虽然老板是按照公司的制度走的,实际执行起来,就很难中立客观,何况有些时候对事情的价值判断,对人能力的判断,对人潜力的判断本身就仁者见仁。<br><br><br>晋升是为了给公司选拔人才,成就更大的事业,提名是为了赋予团队空间,注入更有活力的动力源,这两关是公司制度和你的老板把控,接下来的一关是你面对的评委。<br><br><br>如果草草准备靠流水账搞定,那么你就太小看评委了,评委个个火眼金睛,他们看你晋升不晋升,在投票的时候,决策依据是什么呢?<br><br><br>除了在高层级评委团的利益分配侧的默契外(这点你无需关心),评委被你搞定一定是看三个东西:<br></p>
<ul>
<li>你的 PPT 所展示的内容,或者叫论据</li>
<li>你的述职演讲所传达的观点,或者叫逻辑</li>
<li>你的回复所表现的潜力,或者叫格局</li>
</ul>
<p><br>PPT 是死的,要把它做活才能加分,这个做活就是对你过往业绩的整理、思考与执行链路的严谨与完整性,如果这里失分,是很不应该的,因为这是送分题,不好好准备说明你还不够重视。你可以想象自己是面对三四个外部的客户,正在说服他们购买你的方案,那么 PPT 的重要性不言而喻了。<br><br><br>你的述职演讲是活的,这个话术可能是你练了很多次打的腹稿,也可能是你平时不断的积累不断的思考,已经形成固定回路的思维模型,无论是哪种,功夫不花在平时,也需要花在提名后的准备阶段,这里要花心思。<br><br><br>显然这两个都不足以让评委下决策,因为 PPT 可以被很详实的包装,你的陈述也是如此,能不能禁得起挑战,必须有第三个标准,就是通过跟你有几回合的问答,来更近距离感知你这个人身上的特征、品性、性格,或者我们管它叫格局,是不是在这个层级上足够打开了,甚至远远超过了当前层级,这里再结合之前的论据和逻辑,最终展示出来的就是你的气量和心胸、潜力和格局,所以才有看 8 升 7 ,看 7 升 6 的这个说法,我们把潜力再翻译一下,就是你的忠诚度和可培养价值,以及你未来在新层级对公司能做多大的贡献。<br><br><br>然后,聊了这么多,你会发现,这只是我 - Scott 个人的判断,对,那么下一个问题就来了,那么多评委,难不成他们都是如此想的么,答案显然不是,所以讨论到这里,你就明白了实际上你未能提名、未能答辩成功的背后,原因许多许多,运气成分的确在里面,其他的博弈关系也有,评委的背景也有...<br><br><br>所以此时,你最需要的是什么?<br><br><br>此时最需要的不是输赢,也不是情绪,更不是逃避,而是能静下来反思自己,跟老板对焦,跟同行交流之后,对自己当前能力与价值的重新认定,对晋升这件事情的重新认定,以及新一财年的重新规划。<br><br><br>这件事,才是你在晋升季受挫后,应该好好考虑的事情。<br></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,可以加入早早的社群来一起学习,我也会一对一的来贴身辅导你,可以加我的微信: codingdreamer 来咨询详情,也可以来<a href="https://link.segmentfault.com/?enc=5smEzWXZK4vGahMZy0PLtA%3D%3D.wcmhzlxEToQyEvBW8fYEaIFzvjSU0gWxJ7A5uYCbiac%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:你命运改变的起点就是认命
https://segmentfault.com/a/1190000022430731
2020-04-29T23:00:00+08:00
2020-04-29T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
1
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>认命,听上去很消极,但它可能是最有投入产出比的最划算的决策。</blockquote>
<p>人年轻的时候,是热血的,自比马云马斯克,自比乔布斯佐罗斯,幻想改变世界扭转人生,即便是一事无成的到了晚年,也依然认为自己胸怀天下叱咤风云,想必大家从上一辈人的口中,从出租车司机的口中,从很多路演中热血的创业者口中,可以感受到很多如此的激情。</p>
<p>这种激情是好的,我加以肯定且非常向往,但我不再信了。</p>
<p>我不再信它,是因为当我信它并践行的时候,我一路碰壁遭遇磨难,而我不再信的时候,我反而渐走渐稳惊喜不断。</p>
<p>之所以拿到一些惊喜,可以用早期磨难带来的成长或者运气二字一言盖之,但这个扭转的背后不仅仅是成长和运气。</p>
<p>我今天重新复盘,发现影响我行动决策的内核,是我的心态变了,这个心态来自于我的认命。</p>
<p>如果用去创业抢市场来类比形容自己,就是越来越明白自己的局限性,我根本到不了靠智商跟人拼市场拼输赢的阶段,因为你根本没那么大能力和格局去 Hold 一个更大的盘子,但是细分的领域中你可以随便做,几十万几百万到几千万的规模,也没啥人来跟你抢,抢也抢不走,因为平行空间还有无数这样的盘子,谁做不是做,但谁做也做不完。</p>
<p>所以我就认命了,别人能提前半年想清楚后面布局,我做不到,别人能洞察几年后的走向,我做不到,别人是别人,我是我,活出自己的模样,重点不在于我用什么方式去活着,而在于我希望活出怎样的价值。</p>
<p>当我认命后,就能诚实的面对自己,感知自己,并且基于这个判断来相信我一定能迭代出未来心中所想的样子,就算今天想不清楚某件事我会做成什么样,我也果断去做,既然更高阶的预知能力这件事在我身上不存在,我也就不再依赖,换言之,想不清楚我也照样动手,不管三七二十一,先做几个出来,错了就错了。</p>
<p>于是,我把希望寄托在两件事:</p>
<ul>
<li>自己强大的哪怕是死板的执行力,光靠这个就能赢</li>
<li>自己愿意复盘迭代的企图心,加上这个能赢得更快</li>
</ul>
<p>我把希望押注在未来的自己,做的过程中,你的感知越来越强,你也会经常跟自己复盘迭代,这时候方向和它可能会变成什么样子,就慢慢出现在脑海中了。</p>
<p>基于这个,我给自己定了 6 + 1 决策原则,也就是如果这个事情只有 7 天的周期,我最多给自己 1 天来思考,到了第二天无论想的如何,先动手做了再说,只有这样才能避免晚上想想千条路,早上起来走原路。</p>
<p>时间是线性的稳定的,而在这条线上奔跑的你,则是非线性的会剧变会质变,有高峰有低谷的,甚至会停滞不前。</p>
<p>所以,选择认命是选择了诚实,选择了认清现实和重新面对,也就选择了重新的评估,选择以一种新的投入产出评估方程来迭代自己的能力和期许自己的回报,也就选择了更加从容的心态和更加务实的行动准则来前行,你不再是站在起跑线看马拉松的终点,而是站在马拉松的终点,重新梳理下一段路的起点,这个起点,便是你的认命。</p>
<p>而无论选择是认命还是不认命,也并不影响把执行力和企图心作为自己做事的驱动引擎,也并不影响对于未来的期待,因为你本来也不抗拒更加宏大的理想,只不过此时,你终于啃低头把 “始于足下” 四个字重新捡起来罢了。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1584006756098-4766ba9a-c963-4085-a6a6-86d68dc3583e.png#align=left&display=inline&height=369&name=image.png&originHeight=944&originWidth=1910&size=4402061&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,可以加入早早的社群来一起学习,我也会一对一的来贴身辅导你,可以加我的微信: codingdreamer 来咨询详情,也可以来<a href="https://link.segmentfault.com/?enc=fx%2Bu5cVlEOWInVvqzb5nqQ%3D%3D.mM9wfYbGPSCEqmV37HmU0u85qR3VPVizD0fJU97a0M4%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:如何向大会提交分享议题
https://segmentfault.com/a/1190000022430707
2020-04-28T23:00:00+08:00
2020-04-28T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>参加技术大会分享,对于很多工程师,都是有点遥远的事情,好像必须是行业的绝对大佬才能够资格,在我的视角中不这么看,我向来认为讲师与听众的互动所带来的新的启发才是大会的根本目的,而为了促成这些启发,是不是大佬只是一个更容易说服你的光环,所谓的权威性,但真正重要的依然是议题本身在说什么,想要表达什么,对听众有多大的帮助。</p>
<p>这也是我今年打算举办前端早早料大会的初心,我认为大会一旦走上高大上,就容易脱离群众,在群众这一层,必须要有一些高频的易消化的小主题会议,来给到听众更实际的干货,我自己参加大会,也是秉持这样的初心。</p>
<p>如下两个便是我提交给大会的两个议题,也在等最终的审核结果,如果审核没通过的话,我打算拿来跟早早聊的同学精讲一下,其中某些内容正好我近期一直在思考,有一些不一样的认知。</p>
<p>那么大家如果要参加技术会议,早早聊一定会是一个舞台,这里你不用拘束,直接找我就行,我只看内容不看背景,另外大家准备的方式也可以参考如下我写的格式:</p>
<blockquote>讲师、公司、职位、话题名称、背景、大纲、听众受益及适合人群。</blockquote>
<p><a></a></p>
<p><a></a></p>
<h4>工程师成长主题</h4>
<p>讲师:Scott<br>公司:宋小菜<br>职位:大前端团队负责人</p>
<p>话题:中小型前端团队的技术成长指南<br>背景:截至 2020 年中国互联网已经产生了近百万家的中小微企业,也催生了数十万的(泛)前端岗位,而不足 20 年的前端职业发展并没有在线上线下形成成熟的培养模式,同时前端能力模型也随着技术变迁发生着高频的变化,这给大面积的前端个人和团队都带来了巨大的成长挑战。本次演讲将结合小菜前端团队最近 3 年 6~20 人的扩张中,内部晋升 4 名前端专家和 3 个资深前端背后的培养方式,同时结合 Scott 近 7 年来对超过 300 名前端深度 1v1 辅导的经历和行业观察,分享阻滞前端工程师成长的原因到底是什么,作为前端个人和带团队的主管,有哪些方法可以借鉴,以达到更好的成长结果。</p>
<p>内容大纲:</p>
<ol>
<li>
<p>技术成长缓慢是普遍现状</p>
<ol>
<li>500 个前端主管的烦恼</li>
<li>200 个前端成员的烦恼</li>
<li>小菜前端的 3 年成长路</li>
</ol>
</li>
<li>
<p>团队中如何促成个体成长</p>
<ol>
<li>谁可以影响到团队成长</li>
<li>业务与成长的权衡方式</li>
<li>作为主管你可以做什么</li>
</ol>
</li>
<li>
<p>前端个人如何自我成长</p>
<ol>
<li>谁可以影响到你的成长</li>
<li>成长的路径和方法是什么</li>
<li>10 个前端成长案例背后的故事</li>
</ol>
</li>
</ol>
<p>听众收益:<br>了解大前端生态下的工程师成长现状<br>了解团队和个人有哪些方法影响成长</p>
<p>适合人群:<br>前端开发工程师</p>
<p><a></a></p>
<h4>大前端大工程主题</h4>
<p>讲师:Scott<br>公司:宋小菜<br>职位:大前端团队负责人</p>
<p>话题:小菜跨端跨栈的工程化实践<br>背景:历经多年的发展,互联网产品形态的丰富也不断重构着创业公司的商业模式和研发方式,尤其对于要同时支撑 APP/PC/H5/小程序等多端的大前端团队,每天都面临效率与质量的挑战。本次演讲将结合小菜前端团队最近 3 年的工程化实践历程,分享如何进行工具化/工程化的技术设施与团队能力建设,来驱动少于 20 人的前端团队,并发支撑公司 APP/PC/H5/小程序 共计超过 30 个核心业务应用的项目开发与日常迭代,并基于此来分享在三缺(缺钱、缺人、缺资源)的中小型创业公司中,有哪些可复用的工程化的方法论来支撑快节奏的早期产品试错,进而实现业务目标。</p>
<p>内容大纲:</p>
<ol>
<li>
<p>公司的快与团队的慢</p>
<ol>
<li>生鲜 toB 业务的特征</li>
<li>前后端团队的研发现状</li>
<li>跨端开发下的前端瓶颈</li>
</ol>
</li>
<li>
<p>团队的 4 次生产力解放</p>
<ol>
<li>多款 RN APP 并行后的工程化实践</li>
<li>中后台 PC 需求井喷后的工程化实践</li>
<li>H5/小程序全面开花下的工程化实践</li>
<li>逆向/视频创意等泛前端下的工程化实践</li>
</ol>
</li>
<li>
<p>工程化的启动时机与推进策略</p>
<ol>
<li>业务/产品判断要先于技术判断</li>
<li>人员/组织好判断要先于技术判断</li>
<li>如何形成最优投产比的工程化思路</li>
<li>如何推动工程化立项落地与推广</li>
</ol>
</li>
</ol>
<p>听众收益:<br>了解中小型前端团队的跨端时的研发现状<br>了解人单力薄时实践工程化的思路与方法</p>
<p>适合人群:<br>前端开发工程师</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1582802852685-12885766-1755-40e6-8555-a53673eb87ea.png#align=left&display=inline&height=360&name=image.png&originHeight=918&originWidth=1900&size=5147018&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,可以加入早早的社群来一起学习,我也会一对一的来贴身辅导你,可以加我的微信: codingdreamer 来咨询详情,也可以来<a href="https://link.segmentfault.com/?enc=MuktTo42YQiq07vke34hgQ%3D%3D.fpOW%2BSVhiS4RXy3%2BHbLugWmfaR9ncmXe8llWCcJusmU%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:为什么编程大佬总看不上做课程的
https://segmentfault.com/a/1190000022430657
2020-04-26T23:00:00+08:00
2020-04-26T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
2
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>这个社会的阶层属性天然存在,不以你我的心智高低为转移。</blockquote>
<p>阶层属性在工程师行业中也存在,也就是鄙视链,一种编程语言鄙视另外一个,一种框架用户鄙视另一个,一种编程理念鄙视另一个,深钻编程的鄙视做培训课程的,科班出身的鄙视跟教程入门的...大到处事之道,小到变量声明...</p>
<p>仿佛身边到处环绕着这种声音,仿佛鄙视链无处不在,仿佛稍不努力稍不严谨就被人挑战。</p>
<p>具体数量很难测算,仅仅根据我从业十年周期来看,接触过有四五千前端工程师,有一定的深度了解一两千人,只有少部分人带有这样的有色眼镜(往往内心并无恶意),只有极少极少数人会有这样的处事价值。</p>
<p>那为什么这些观点的声量这么大呢,因为互联网的传播效应和沉默永远是大多数,所以极少数人的声音和观点可以穿透整个社区,何况整个前端社区也就那点大,加上很多活跃的同学并无意图的传播放大了这种观点的效果,所以看上去的主流观点并不符合事实样本,非黑即白的辩证伦理观同样是极少数比例。</p>
<p>让我们从事实视角来还原这个问题:</p>
<p>为什么公司写代码的工程师看不上做编程课程的工程师?这个问题实际跟公司负责招聘的看不上培训班出身的是类似的性质。</p>
<p>首先是供需大环境,2000 年后,线下是有一波波的各种编程培训班,历经 20 年,如果不是 2020 年这次疫情,我相信整个编程教育的线上化和高质量化还要多花几年,互联网的飞速发展带来巨大的就业机会,而前端作为新生职位,门槛低薪资高更是吸引更多教育机构入围,所以可以释放巨大的入门级前端工程师,但跟各公司更为严苛的招人标准之间,存在着天然 Gap。</p>
<p>其次是技术的发展节奏太快了,前两个月的讲师还在聚焦 jQuery 的组件化,社区已经拥抱 Vue/Angular/React 框架了,前两个月讲师刚刚拥抱了框架入门,社区已经走向跨端、智能、搭建包括服务化的尝试了,即便是顶级公司的资深前端,都很难及时跟上技术的变迁,更何况是纯做课程设计的教育机构讲师呢,自然所能教授给同学的一定是初级、中级为主的偏知识型内容。</p>
<p>再次是前端已经进入了深水区,知识的掌握只是基本功,往上更多的是解决问题的能力,比如业务理解、需求分析、项目管理、团队协同合作...这么多的软实力是很难通过学习几门课程可以解决的,因为课程约等于知识,而职场上是靠能力,知识是能力的底层,知识的变化是高频的容易过时的,能力的迭代是深刻的需要积累的。</p>
<p>从主观上看,大量涌入前端行业的童鞋,确实相当比例并不是科班出身(大专以上的计算机专业),所以整个编程的技术体系基础并不夯实,再加上不计其数的中小型公司(几口人到百来号人)中不规范不先进的研发模式,不合理不科学的管理模式,更难以让通过学习浅浅几门课程的同学获得真正的核心竞争力。</p>
<p>总而言之,供需关系催生的授课体系简易、技术变迁导致的讲师能力薄弱、前端发展带来的职场门槛升高,以及粗糙的专业背景和成长路径,导致了从一个大样本上,大概率是培训体系的讲师能力比不过在研发型团队写代码的工程师,而从编程课程中成长起来的同学大概率比不过科班出身一路竞赛和实习的同学,但这又能说明什么呢?</p>
<p>只能说明前端这个行业依然是朝阳的,整个环境背景决定了今日的现状,主客观上虽然有可提升之处,但如何评价候选人,或者评价一个做教育的讲师,或者是一个创业期的团队,这个所谓的出身背景它可以成为一个有权重的因子(毕竟公司的商业化的是追求效率的不可能完全一视同仁),但并不应该沦为评判一个人或者一个公司和团队的标签,这样的心智模型还不够客观冷静。</p>
<p>再来换一个视角,假如一个团队招聘了 12 个月,只完成 1/3 的招聘量(9 个人只招到 3 个),这样的结果对公司当然是不利的,但行业内流通的高素质人才是有限的,作为在研发部门的工程师,如果可以摒弃这样的视角,多考虑一些培训机构出来的同学,多给他们一些机会和建议(面试前中后),或者多走出来做技术分享甚至开放一些脱敏的编程课程,而少一些对于做培训教育(无论是线上还是线下无论是入门级还是高阶的)的排斥,我想这对于整个行业发展都是有益的事。</p>
<p>我也呼吁更多的工程师可以走出公司,多为行业输出常识、知识、经验、能力,也只有这样,才能真正的末尾淘汰掉跟不上形势的教育机构和讲师,否则鱼龙混杂的市场中,始终有人在高价低质的收取着学生们的钱,却始终教不出你要的人。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581919253178-67fda2a7-2713-4951-a1dd-cd626b8c19b2.png#align=left&display=inline&height=390&name=image.png&originHeight=414&originWidth=792&size=742615&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=WCmjV4dx8GrAn%2BJE93BbRQ%3D%3D.lVt2xfM1hI37Y4B2raoz6nCPj9vylz5K0J6xATCYmAc%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:4 年 7 门免费课程收入 5 万
https://segmentfault.com/a/1190000022430623
2020-04-25T23:00:00+08:00
2020-04-25T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>2012 年 7 月,收到一封邮件:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581678451106-ca2054a3-b2c9-4f5c-b55a-945982537a99.png#align=left&display=inline&height=139&name=image.png&originHeight=277&originWidth=484&size=31983&status=done&style=none&width=242" alt="image.png" title="image.png"></p>
<p>是一个加拿大华人想创业做在线编程教育网站,就联系我想让我帮搭建一个编程教育网站的前端页面,后面的几个月我陆续花了一些时间,最开始也是模仿其他的在线教育网站:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581678732081-53fd8f2f-f4bb-439f-8f0c-90a2810ac180.png#align=left&display=inline&height=427&name=image.png&originHeight=686&originWidth=1198&size=384134&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>技术栈就是 jQuery + Boostrap,后面也迭代了很多版本,直到这个项目未能成功融资而告一段落,但也因为这段历程而改变了我后面的职业路线,也与这个华人成为了朋友,这部分按下不表,提这件事是我第一次近距离接触到在线编程教育这件事情,无论是行业观察、需求分析还是产品设计,所有对它的理解都是从这时候开始。</p>
<p>基于这段历程,在 2013 年冬天,恰好同事的前同事在为慕课网找第一批讲师,就间接的联系上了我,之后就开始合作,自此之后就把录制编程课程作为了一项业余爱好,最早的记录都存在 QQ 里,如今都找不到了,只找到了打磨 2 个月课程内容后发出来的课程设计邮件,那时候工作刚好三四年,是最拼的时候,工作到两三点是家常便饭:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581679608668-89093146-9c50-4345-badd-88458bf12691.png#align=left&display=inline&height=332&name=image.png&originHeight=664&originWidth=1507&size=120737&status=done&style=none&width=753.5" alt="image.png" title="image.png"></p>
<p>第一门课程上线也是在 2014 年初,分了 2 期,累计有 14 多万人学习过,如今早已下架了:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581679809152-2ecfe863-e34f-4bcc-acd9-3301b54be063.png#align=left&display=inline&height=200&name=image.png&originHeight=313&originWidth=1168&size=177925&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581679951456-aea9f68c-a75a-401f-b116-12f267a82c15.png#align=left&display=inline&height=261&name=image.png&originHeight=408&originWidth=1164&size=202914&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>链接分别是 <a href="https://link.segmentfault.com/?enc=hZmt%2Fnl84ahu1B5GI14m%2Bg%3D%3D.6nJB%2F7Bz672j%2FJGKpgfPZhsahJccawZndsz3f6Xg2vc%3D" rel="nofollow">imooc.com/learn/75</a> 和 <a href="https://link.segmentfault.com/?enc=bY%2Bddvg9gLNju4gjjWbnPg%3D%3D.4Qoa96OOUCkiI%2BHIAzJlUjXBE2Ldnu%2ByKVla3zcW6k8%3D" rel="nofollow">imooc.com/learn/197</a>,非常原始和古董,不建议大家再去学习了。</p>
<p>之后是从阿里离职后,正好赶上世界杯,就做了一个世界杯主题的课程蹭热度,主要是 Canvas 的使用,事实证明这门课很失败,只有 2 万多人学习,评价也不好,链接是 <a href="https://link.segmentfault.com/?enc=1adF42gr2Mea%2B%2Bc%2FyGqDgA%3D%3D.m13npncM%2B37x3%2FmTmdSY%2BcjK99Xveyi4cMHNvscFSDI%3D" rel="nofollow">imooc.com/learn/134</a>,依然不建议大家学习:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581680508614-8d0ba0ea-47e9-48f9-8bd8-dd6ce3963ff7.png#align=left&display=inline&height=211&name=image.png&originHeight=330&originWidth=1165&size=192460&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>再后来,考虑到很多同学觉得用 Node.js 直接开发前后端还是太难,就先出了一个 Jade(后来改名叫 Pug) 模板引擎的课程,有 3 万多人学习过,链接是:<a href="https://link.segmentfault.com/?enc=mV%2FbOvI5GTHXXcrKgajYhA%3D%3D.%2FPMAhJSt8JBA5m90VqKX%2FJ%2BaOiNsprLBXpQTkbkPAoA%3D" rel="nofollow">imooc.com/learn/259</a></p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581680711035-2c9529b0-0cec-4ae2-ac0b-c5a8a723affd.png#align=left&display=inline&height=141&name=image.png&originHeight=220&originWidth=1162&size=129991&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>以及配套出了两个 Node.js 的基础课程,累计有 30 万人学习过,链接是:<a href="https://link.segmentfault.com/?enc=QewB5oo6tyrIgNbKyITJag%3D%3D.hCu4X%2Bo6eMFS%2BEOYkokqwWLH2K7k9eilxWEb3AmQEdo%3D" rel="nofollow">imooc.com/learn/348</a> 和 <a href="https://link.segmentfault.com/?enc=9Y20UxdosIwSU4JKREA0LQ%3D%3D.IiMEkZqRkk87L4t7o7wTR%2FGwacv%2BQYfu3IxrdQVBRaI%3D" rel="nofollow">imooc.com/learn/637</a>,这些基础课程也都过时下线了,基础课程这部分大家有兴趣还是可以用 2 倍速快速听听,对入门是有些帮助,当然如今市面上有更多更新的课程,依然不建议大家花太多时间学习:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581680648854-8a95ddea-79f8-42b8-8d8f-07e221540118.png#align=left&display=inline&height=239&name=image.png&originHeight=377&originWidth=1179&size=180276&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581680817332-50ad4c9f-2e61-4d96-9899-55005d6dee42.png#align=left&display=inline&height=177&name=image.png&originHeight=278&originWidth=1171&size=158039&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>再往后,是做过一次 Node.js 的分享,就把这个分享的视频发到了慕课网上,有 4 万多人看过,链接是<a href="https://link.segmentfault.com/?enc=Ali86I1RlaYFoO5fYcLWlA%3D%3D.W%2FlW82qfOyVhXd0sGMnVYH2Ss8pRI0FNDTrrpqPxR9M%3D" rel="nofollow">imooc.com/learn/728</a>:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581680995450-d11cb24c-e02b-437d-ad0b-7b8286bff7b3.png#align=left&display=inline&height=210&name=image.png&originHeight=331&originWidth=1178&size=159201&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>所有上面的课程加一起,总共有 50 多万的童鞋学习过,也算是一件很值得我骄傲的事情,当然也要提一下收入,这些课程都是免费对用户开放,讲师部分费用则是由慕课网承担,早期这 7 门课程也有收入,差不多 5 万的样子。</p>
<p>只不过,自此 2016 年到 2020 年,就再没有推出过免费课程了,感觉对于看过我课程依然对我有信任感的童鞋缺少一个交代,希望 2020 年,能重新再出发,输出这几年来更多新的思考回馈给社区,尤其是基础性的部分,可以考虑多一些免费的课程分享出来。</p>
<p>关于编程教育方面,感觉可以写一个系列出来,从用户需求挖掘、人群定位、讲师软硬件准备、话题准备、课题创作、代码实施方式、讲解策略...,今天时间有限,就聊到这儿吧。</p>
<p>如果你曾经看过 Scott 的课程,或者听说过,或者纯粹感兴趣,都可以加 Scott 的微信 codingdream,来围观我的朋友圈,顺便也给我提一些建议,比如你希望学习那些编程的内容,对哪些方面感兴趣,也许我会针对这些方面做一些更全面的学习和分享。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1581681642997-962c857e-8856-4b83-8c23-177338bf4bf1.png#align=left&display=inline&height=247&name=image.png&originHeight=479&originWidth=1445&size=1566747&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=PGb2yuYmY0wSPpLczYRJ5g%3D%3D.Kdy5rFqeU9yOrF%2B%2B2sqvvk4SnOWR3%2FP56u6OQw1G5JE%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:你的时间和想法不值钱
https://segmentfault.com/a/1190000022430590
2020-04-24T23:00:00+08:00
2020-04-24T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>你的什么最值钱?</blockquote>
<p><a></a></p>
<h2>你的身体最值钱</h2>
<p>对于一个普通人,最值钱首先是他的身体:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579597946363-7aab4982-92d4-47d0-8d3a-5d3cc63f5f0a.png#align=left&display=inline&height=782&name=image.png&originHeight=431&originWidth=411&size=104654&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>大部分普通人,穷尽一生也赚不到 3 亿人民币,但却用 酒精、烟土、暴饮暴食、颠倒黑白的作息来毁坏自己的身体,背后也确实有诸多现实的原因,比如养家糊口、事业有成,我也不例外。</p>
<p>抛开了你的身体和健康,你最值钱或许就是这百来年的生命之河,也就是一生的时间,以及这一生所做过的事儿。</p>
<p><a></a></p>
<h2>你的时间不值钱</h2>
<p>显然你的时间也是不值钱的,因为碌碌无为 30 年大有人在,回头看也没什么精彩的人生,往前看也没什么期待的奇迹,所以即便拥有这生命之河的时间之水,它也并不值钱。</p>
<p>真正让时间变得值钱,是你如何分配你的时间,也就是你的精力是如何分配的,是 8 小时睡觉, 6 小时工作,4 小时加班摸鱼,3 小时吃饭,2 小时刷视频,1 小时学习还是其他,让我们看一个早早聊童鞋的早上是如何过的:</p>
<blockquote>坚持 11 点睡觉,5 点起床,早上在家学习 4 个小时,补计算机基础知识的短板(数据结构,编译原理)</blockquote>
<p>时间一直在流动,而你如何干预自己的时间流向,支配时间的能力,分配时间的比重以及在单一时间内的投入,才最终让你的时间背后的自己更值钱,这个观点你认同的话,我们再往下看。</p>
<p>而如何分配自己的时间的背后是你有没有清晰的人生规划,人生规划里关于工作有没有清晰的职业规划,人生和职业规划的某个长周期内,有没有清晰的目标,在去目标的路上有没有清晰的方法,在落实方法的过程中,你有没有强大的执行力(心力、脑力、体力)保障你去实现目标。</p>
<p>这一条执行链路中任何一个出现短板,都让你的时间变得不那么值钱,所谓你的个人价值没有最大化,甚至次大化。</p>
<p><a></a></p>
<h2>你的想法不值钱</h2>
<blockquote>晚上想想千条路,早上起来走原路,千条路就是你的想法。</blockquote>
<p>穷其一生,我们脑海中曾经纵横过多少想法,我们也总是被人评价是一个有想法的人,这个有想法的评价不见得是绝对的褒义,为什么不去夸我是一个有做法,知行合一的人呢?</p>
<p>你的想法无论多新鲜多创意,在没有从大脑中走向现实落地前,都是空谈,甚至所谓别人剽窃了你的想法,很多时候只是帮你走完了后面一段你永远也不会走的路,但是别人走成功了,你心中就留有遗憾了。</p>
<p>你的想法不值钱,但你去践行它,并且是专注的落地它的时候,它就值钱了,我们通篇用值钱二字形容价值,并不是真的用纯物质的方式,来量化这个金钱的钱,只是值钱二字容易听懂。</p>
<p>我曾经想要办一场技术会议,一场别开生面的不同凡响的会议,成为会议届的一股清流,这个想法我想了 3 年了,从来没有去做,你说,我的这个想法值钱么?</p>
<p>就算是我把想法告诉我所有的同学和朋友,它也依然不值钱,或者说,它也依然没什么价值。</p>
<p>直到 2020 年 1.11 我发起并办了人生第一场自己主导的前端技术会议:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579599822807-f1aad4c0-0034-4e89-9b0a-d0fecced8f53.png#align=left&display=inline&height=229&name=image.png&originHeight=458&originWidth=1492&size=1960380&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>办场大会多少钱</h2>
<p>我发现,我的想法值钱了,虽然这个会议办下来我是亏钱的,但它的价值不再是空中楼阁而是踏踏实实的落地了:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579599752135-6bdbbc92-938d-40b7-8dcb-98ef446c896d.png#align=left&display=inline&height=516&name=image.png&originHeight=952&originWidth=1376&size=197087&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>我也不需要向别人推销安利和解释,我的想法是多么多么的好,当这张预算表出来,当 450 人报名,230 人来场地的时候,我明白了把一个想法做出来,会多么的有成就感,我终于可以专注在这个想法的打磨上面,研究到底设计怎样的话题,请什么样的讲师,沉淀什么样的内容可以更有价值,这时候我觉得我的时间终于值钱了,抛开物质层面,他让我收获了社区更多的认同,跟我的内心价值观越走越近,也让我有了继续把想法践行,去办第二届的动力。</p>
<p>所以,你的时间不值钱,你的想法不值钱,你的身体最值钱,你的观点影响到结果才值钱,你的时间消耗在落地想法的过程中才值钱,你决定如何支配你的时间持续做到什么程度,这种专注的投入才换来你的更值钱(更有意义)。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579600421629-4b240068-a2a7-4338-8d7d-81276d6c4b65.png#align=left&display=inline&height=428&name=image.png&originHeight=1096&originWidth=1912&size=3797109&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=LwxHt2sBqlbzISAJW%2Bqecg%3D%3D.Cqtw78HjRYr75lTE0VqeG%2BfEv3KCkV41ERJyyEdXXIg%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:前后端分界线与 GraphQL
https://segmentfault.com/a/1190000022430540
2020-04-23T23:00:00+08:00
2020-04-23T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
3
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>天下苦前后端协同久矣</blockquote>
<p>过去一年多太多同学问我对于 GraphQL 的态度,就小小作文一篇,瞎聊一下。</p>
<p>前后端,从十几年前开始明确的分化,无论前端后端,到现在都经历了太多次的技术变迁,多少程序员黑发到白发,长发到秃头沉沉浮浮,前后端如今的边界在哪里,我们大脑皮层遇到这个问题的第一个反应,往往就是,前端开发页面,服务端渲染页面或者与页面异步同步数据,剩下的事情就交给浏览器了,边界仿佛就在静态页面开发和数据渲染这里,那么它真的是在这个地方么?</p>
<p>要回答这个问题,先聊一聊我的职业生涯,我从事前端开发快 10 年了,算是一个老前端,在我的眼中,前端后端的边界越来越模糊了,而且这个边界也在不同的公司,不同的团队,甚至不同的业务模式下,不断的发生着变化,这不是废话么,那到底边界线哪里,是什么?</p>
<p>我个人觉得,就是数据的控制权和与视图所依赖的 API,这里就是目前前后端的边界,数据控制权属于后端,API 属于后端,把前后端简单看做是一个完整的系统,这个系统中<strong>自 API 向下自然是后端的,API 向上则慢慢属于前端</strong>,为什么是慢慢属于前端,前后端的职能变化,前后端的分工边界,前后端的角色变迁,都跟我们这一次以 GraphQL 为代表的数据方案有着密切的关系。</p>
<p>不过话说回来,虽然 Scott 从业已久,但这个问题依然是回答的战战兢兢,原因就在于对于技术方向的判断,大多数资深的工程师都会有相似的判断,但对于某一层或者某一块具体的技术实现方案,大家得出的结论会相差甚远,这个有一小部分是人的问题,比如技术视野,技术胸怀,技术背景,以及个人的职业规划,但大部分是客观环境的问题,我们总是站在自己熟悉的若干客观环境下,以此举例和类推,得出整个世界也基本上是类似的情况类似的运作模式这样的结论。</p>
<p>其实不同公司不同团队甚至不同风格的工程师组合在一起,是完全没办法通过理论推导来达成统一的,所以我需要再次重申一下,GraphQL 有可能是不能解决你当下甚至未来的团队合作效率、开发模式问题的,但是它一定会给你带来一些不同的视角来认识到两件事情:</p>
<ul>
<li>第一个,<strong>前后端的合作成本其实很高,源于语言栈源于主导权,也源于各自职能的不同</strong>,这个是必然的,即便是有了各种的 Mock 方案,团队规范,工具基建,都没办法大幅度的降低这个成本。</li>
<li>第二个,<strong>前后端的边界既不像我们认为的那么清晰,前后端的职能壁垒也不像我们认知中的那样不可逾越</strong>,他跟我们内心对自己的工程师身份认同有很大的关系。</li>
</ul>
<p>所以大家要问自己一个问题,为什么我一定是一个前端工程师,为什么我一定是一个后端工程师, 为什么我一定不想去关心任何系统底层或者上层 UI 的问题,为什么我觉得端上的体验和页面或者服务搭建,几乎是我工作的全部重心,为什么作为前端,往往会觉得上线那一刻起自己的工作就已结束。</p>
<p>这一二十年前后端技术演进的过程中,前后端各自的能力边界都得到了很大的扩展,互相合作才有了今天互联网的繁荣,我个人的角度是,前端后端的边界模糊也好,清晰也罢,本质上我们是一个系统的上下组合部分,通过各种咬合来保证产品正常上线运行为公司创造价值。</p>
<p>至于我们咬合的部分,是需要双方都有足够的勇气和胸怀,迈出一步甚至两步,以团队效率为根本出发点,而不是仅仅职能,前端工程师尽量不要限定自己的界限,可以放大自己的能力甚至是权利,主动承担灰色地带的事情,这些事情的承担看上去是苦活累活,但最终解放的依然是我们自己的价值枷锁。</p>
<p>说的有点玄乎,一句话收尾,<strong>前后端在变化,边界也在变化,无论前后端都应该开放心态,调研新工具,实践新方案,站在一起来让工程师的技术价值最大化</strong>,帮公司省更多钱,给公司赚更多钱,这个需要决策者的心胸格局和专业度。</p>
<p>这个边界到底如何变化呢,我认为截止到目前,GraphQL 是一个可小范围尝试的解决方案,它能解决问题也同时带来挑战,大家用的时候要小心慎重,而这两年大火的 Serverless,它也有它特殊的生存环境,我们依然可以用 open 的心态看待,小范围试用的尝鲜,但具体到生产环境,我们依然要小心慎重。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579431051183-9f2e3029-02c4-49d1-af5d-e04b47b3012e.png#align=left&display=inline&height=395&name=image.png&originHeight=677&originWidth=1280&size=2383117&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=gpbDzQjPbiWxFaR3pfOjYg%3D%3D.ETHy%2Fx4%2FQufglKCZ7DosYgIVPWyyuqZtMyJCCvorTxk%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:为什么你遇不到一个好主管
https://segmentfault.com/a/1190000022430474
2020-04-22T23:00:00+08:00
2020-04-22T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>前端组长是你的老板,技术总监是组长的跨级老板,CEO 是总监的老板,投资人是 CEO 的老板...</blockquote>
<p>所谓老板,通常就是<strong>能决定你的选(招聘)用(授权)育(培养)留(激励)开(转正/劝退/辞退),能大比例决定你绩效好坏的那个人</strong>,通常是你的直接上属老板,也就是主管,相信你身边很多同学甚至你自己,工作这些年以来,可能都没有遇到过多少好的前端主管。</p>
<p>如何定义好呢,可以用如下三个标准:</p>
<ul>
<li>
<strong>技术是大牛级</strong>的(至少是 P7 以上),架构编码、技术视野或社区人脉能拉开你很大距离</li>
<li>身怀<strong>成熟的培养方法论</strong>,善于借绩效/辅导强弱手段,工作和私下沟通中,督促你和启发你</li>
<li>人品过硬三观正同时<strong>有智慧处理公司与员工问题</strong>,愿意且敢为员工(你)争取合理的利益回报</li>
</ul>
<p>越趋近于上面三个标准的主管,越大概率是一个更好的主管,能遇到这样的老板是一件幸运的事情,第一个标准带给你的是前端职业上技能和视野的可能性,通过他你能看到、看懂、看透多少技术路线的长度,第二个标准带给你的是综合能力的提升,所谓心脑体(越来越成熟的自我价值评估、职场人格和社会性),第三个标准带给你的是真实的利益匹配(薪资、福利、年终、奖励、激励、授权...),是否让你的利益得到尽可能多的保障。</p>
<p>我过去 9 年一共经历过 6 任主管(2 个前端,3 个后端,1 个运营),那我是如何评价他们呢?我用这三个标准(不是严格意义的标准)来衡量下,分别用非常满足、一般满足、不太满足和不满足:</p>
<p>第一任主管(前端):</p>
<ul>
<li>技术大牛:一般满足</li>
<li>培养方法:不太满足</li>
<li>利益争取:一般满足</li>
</ul>
<p><strong>第二任主管(前端):</strong></p>
<ul>
<li><strong>技术大牛:非常满足</strong></li>
<li>培养方法:一般满足</li>
<li>利益争取:一般满足</li>
</ul>
<p>第三任主管(运营):</p>
<ul>
<li>技术大牛:不满足</li>
<li>培养方法:不满足</li>
<li>利益争取:不太满足</li>
</ul>
<p>第四任主管(后端):</p>
<ul>
<li>技术大牛:一般满足</li>
<li>培养方法:一般满足</li>
<li>利益争取:一般满足</li>
</ul>
<p><strong>第五任主管(后端):</strong></p>
<ul>
<li><strong>技术大牛:非常满足</strong></li>
<li><strong>培养方法:非常满足</strong></li>
<li><strong>利益争取:非常满足</strong></li>
</ul>
<p><br>第六任主管(后端):</p>
<ul>
<li>技术大牛:一般满足</li>
<li>培养方法:一般满足</li>
<li>利益争取:非常满足</li>
</ul>
<p>我成长最大最快的是第二任主管和第五任主管,第二任带给我巨大的技术成长,第五任带给我巨大的综合思维和做事能力成长,他们带我的时间都不算太长,每个人都只有一年左右,但都大幅度的影响了我的人生轨迹。</p>
<p>有些童鞋会秉持这样的观点:主管就是利用我做事帮他拿结果的,我跟他个人上没啥关系,他也影响不了我什么。</p>
<p>我的观点是:<strong>主管在你的前期职业生涯中扮演非常重要的角色,他甚至比你的薪资比你的镀金什么来的重要的多也深刻的多,尤其在工作初期,他几乎扮演者一个上帝和老师的角色,有可能种下你后面多年做人做事的种子,如果你的主管满足了技术大牛,那就是百里挑一了,如果还能满足培养方法,那就是千里挑一了,再满足最后一个,几乎是万里挑一了</strong>。</p>
<p>我们回到主题,为什么你总遇不到一个好主管,这个问题不是问为什么我现任的老板不满足好老板的标准,而是问<strong>为什么我自己总是遇不到</strong>,因为公司也是我自愿跳槽过来,团队也是我自己挑的啊,当然也有公司的组织架构调整等原因,我自己认为之所以遇不到原因可能有三个:</p>
<ul>
<li>你还不够努力,不足以让好老板看中自己(能力、意愿和潜力不够)</li>
<li>你人生阅历尚浅,不善于辨识谁是好老板(看人观人和预测人不强)</li>
<li>你的职业规划和执行还不够稳妥(在迷茫的时候过于浮躁和着急)</li>
</ul>
<p>其实即便是这三个问题你都解决掉,你依然可能遇不到好主管,是因为前端这个职业太新了,行业的人才沉淀也太少,还不足以成长出来大量的好主管,自然更难遇到。</p>
<p>我这几年转做主管,我给自己打个分的话,结果可能是这样:</p>
<ul>
<li><strong>技术大牛:一般满足</strong></li>
<li><strong>培养方法:非常满足</strong></li>
<li><strong>利益争取:一般满足</strong></li>
</ul>
<p><strong><br></strong>我自认为在培养方法这里是做的非常出色的,这 3 年左右时间,我团队内培养出来 5 个前端技术专家**,同时在社区,我也建了微信私群,对一些职业发展出问题的同学做职业辅导和培训,有蛮多同学都有很大的提升。</p>
<p>但是在技术和利益两块我认为自己也只是做到了六七十分,并不突出,可能技术这块是介于一般满足和非常满足之间吧,但利益争取这里我还没有太好的能力沉淀。</p>
<p>好,今天就聊到这里,<strong>大家只有让自己变得更优秀,才有挑好主管的资本,职业规划不清晰的时候,盲目跳槽和变动,可能会让自己在寻找好主管的路上,越走越迷失,要戒急求稳,多问问自己多问问他人,当遇到非常不满足 3 个标准的主管,也要果断给自己换老板</strong>。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579315647811-c40c6f24-48c9-4384-90fa-23e712bac34e.png#align=left&display=inline&height=1056&name=WX20200118-104655%402x.png&originHeight=1056&originWidth=1894&size=512170&status=done&style=none&width=1894" alt="WX20200118-104655@2x.png" title="WX20200118-104655@2x.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=R%2BIFCSNqJyfKt%2BdfRu%2B3ow%3D%3D.8ANdP2iONDXVAmG4Em0E7qCf7XxqSJ2W1X5XsiwabtA%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天晒:9 年前我述职的工作总结
https://segmentfault.com/a/1190000022430449
2020-04-21T23:00:00+08:00
2020-04-21T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
2
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>所谓成长,就是不断认为昨天自己是 SB 的过程。</blockquote>
<p><br>9 年前,我刚入行,从 9 月份开始工作到 过完年,刚好有半年,完成了职场新人礼。<br>那时候汇报自己的工作,我所在的团队还不流行做 PPT,通常是邮件或者是当面聊,我选用邮件做了如下的半年总结:<br></p>
<p><a></a></p>
<h4>一、钻石展位:日常功能维护与 2.0 新功能迁移</h4>
<p><br>1、计划消耗;<br>2、bannermaker 接入;<br>3、账户诊断;<br>4、群体投放;<br>5、定价投放;<br></p>
<p><a></a></p>
<h4>二、明星店铺:主站搜索与店铺搜索</h4>
<p><br>1、第一期改版上线主搜;<br>2、第二期改版上线主搜与店铺搜;<br></p>
<p><a></a></p>
<h4>三、MiniSite:</h4>
<p><br>1、万塘书院从 minisite 中独立出来,成为子站点;<br>2、超级麦霸,钻石展位,第三方服务平台;<br></p>
<p><a></a></p>
<h4>四、TMS:淘宝联盟、E淘、促销活动,频道页面制作;</h4>
<p><a></a></p>
<h4>五、BP 后台:后台邮件,站内信兼容版本开发;</h4>
<p><a></a></p>
<h4>六、直通车论坛:论坛帖子,活动页面制作;</h4>
<p><a></a></p>
<h4>七、Sinba 后台:拖曳模块,树形结构,以及整站改版;</h4>
<p><a></a></p>
<h4>八、外投广告牌:对北京外投广告牌的支持,多尺寸广告牌的制作修改(针对yahoo,优酷,搜狐等主要门户网站),特殊版本(</h4>
<p>凤凰网,新浪网投放要求)的开发;<br><a></a></p>
<h4>九、无线商搜的手机页面制作;</h4>
<p><a></a></p>
<p><a></a></p>
<h4>团队建设方面:</h4>
<p><br>公司的团队生活与建设方面:带领球队共16 位队友,进行了 25 场次的训练与比赛,包括杭州师范学院,杭网俱乐部,杭州尤文图斯,淘宝球队,淘宝商城球队等进行过多次的联谊球赛;<br><a></a></p>
<p><a></a></p>
<h5>半年出现的问题:</h5>
<p><br>一、项目进度的把握程度:作为前端UED,对项目的把控能力还不够强势;<br>二、与多部门协调的能力:协调力度不够,成熟度欠缺;<br>三、对产品诞生过程中的影响力:影响力范围及力度不够;<br>四、技术层面的成熟度(既定时长内,需求价值,应用场景,开发周长,技术实现,维护性与扩展性,以及上线反响所综合考虑的最优折衷度):特殊场景下的需求PK与处理娴熟度不够;<br></p>
<blockquote>今天的自己看那个时候的总结,显然是稚嫩的不值一提,毕竟是用今天的标准裁定。</blockquote>
<p><br>述职做汇报,本质是在做三件事情:<br></p>
<ol>
<li>让衡量你绩效的人(通常是主管,也可能跨级老板和 HR 参与),对你的工作付出和工作价值有一个更清晰的看见,与他脑子里的做对照,补全残缺和偏移。</li>
<li>在做的所有事情里面,以各种数字案例佐证自己综合能力有成长,尤其是逻辑能力,也就是自己的总结归纳所反映出来的结构化梳理、体系化思考和直击内心的表达能力</li>
<li>透过工作内容和自己的沉淀总结,以及自己的成长诉求,让老板更有弹性的来因应你的诉求,结合你的兴趣和特长,重新定位你在团队中的位置以及潜在的位置,在适当的时候将你放到更能让你历练和成长的一个场景下。</li>
</ol>
<p>述职总结很重要,是因为第一点影响到你的绩效裁定,是关于过去的你,第二点是影响你的能力衡定,是关于当下的你,第三点是影响你的潜力发掘,是关于将来的你,而最重要的是现在的你,尤其是将来的你,所以述职的重点不在于过去,而在于当下和未来,无论绩效结果如何,我们坦然接受,然后立足当下和聚焦未来。<br><br>但是如果遇到的老板是不靠谱的,也是灾难,可是如何知道老板是不靠谱的,或者如何知道自己认为老板是全不靠谱不公正的这个观点本身是不成立的呢,我们下次再聊,在车上手机码字好累..<br><br><br><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579310196778-f6a4d391-17ef-4d9d-b7c6-b6515b966061.png#align=left&display=inline&height=810&name=image.png&originHeight=810&originWidth=1080&size=1582418&status=done&style=none&width=1080" alt="image.png" title="image.png"><br></p>
<blockquote>上次去深圳,发现地铁有商务座,真是活久见...</blockquote>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=1H%2BEZWA1aZpnVR8z6QVgqg%3D%3D.0IaAOiSMWgtYkJN9h2Va9I0K2QjtcZbjubvbbLMlOPQ%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
今天聊:前端跳槽要不要找猎头
https://segmentfault.com/a/1190000022430412
2020-04-20T23:00:00+08:00
2020-04-20T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
4
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>本号常年不在状态,讲话无凭无据,你可不要太当真哦。</p>
</blockquote>
<p>工作没几年的时候,觉得猎头是一个可高级的岗位了,能被勾搭上都觉得自己身价陡增,倍儿有面子。</p>
<p>是的,我当年就是这么想的。</p>
<p>QQ 好友里躺了好几百个猎头,每次打开都一排排的粉色头像在晃动,仿佛在跟我说:Scott,快来快来,这里有一个 Offer 等着你,基于你现在 10k 的薪资,再涨 8 千...</p>
<p>直到我开始自己创业的时候,我才发觉自己多么单纯。</p>
<p>跟上百的猎头聊下来,他们也帮我推荐了工作,不可否认,有许多很专业的猎头(功课做得足,专业知识够,沟通技巧高...),是非常值得托付终(Jian)身(Li)的人。</p>
<p>但同时,市面上充斥这各种层次不齐的半路猎头,他们可能只是对你好奇,过来打击一下你,过来讥讽一下你,过来挑逗一下你,过来装模作样了解一下你,甚至过来只是例行公事的骚扰一下你,拿走你的简历转手送人,更有甚者,想要来跟你做一笔交易,你入职她会陪你吃花酒...(嘘!我不能透漏更多了)</p>
<p>基于这个现实,前端跳槽要不要找猎头呢?</p>
<p>我的答案是,当你在社区有影响力的时候,不要找,当你技术水平还不足的时候,不要找,当你不了解目标公司用人标准的时候,不要找。</p>
<p>为什么呢?</p>
<p>如果你影响力比较大,社区很多人都了解你的时候,你在很多公司都有人脉的时候,你想一下,自己内推自己过去入职率高,还是猎头推荐你过去入职率高?</p>
<p>答案显然是自己找朋友内推成功率高,因为没有谁比你朋友更了解你了。</p>
<p>如果你技术还不够好,或者对目标公司用人标准不够了解的时候,仓促找了猎头投了简历,可能会碰到这种结果:</p>
<ul><li>面试过关,但不发 Offer</li></ul>
<p>好诡异的结果,原因是你可能面试刚刚摸到了公司的用人标准线,公司咬咬牙是想把你招进来的,结果一想到要支付猎头一大笔介绍费,就退却了(毕竟对于很多公司,能省一点省一点,何况这笔费用还不菲)。</p>
<p>那什么时候找猎头呢?就是技术水平还不错(最好是已经到了技术专家,也就是 P7 的水平以上),在社区里比较沉默影响力不够,或者目标是去一家外企的时候,可以考虑猎头。</p>
<p>那怎么联系猎头呢?放心,只要你有一点点风声出去,猎头都会来找你的。</p>
<p>那如何甄别猎头呢?你只需要考一考他/她对前端职业的了解程度,听听他/她对这个职业的理解深度,以及他/她能如数家珍出多少个前端社区有影响力的人,并且知道他们分别在什么公司带什么团队大概什么层级,以及他/她能基本分得清 Java 和 Javascript,分得清 Vue/Angular/React,分得清前端和大前端,知道这一两年的前端风向是什么,是 BFF 还是 Serverless,如果他/她能大概说的清楚,那么这个猎头可以再深度对接对接了。</p>
<p>真正专业的猎头,不会打击你,而是会给你提供事实案例和有价值的建议,真正专业的猎头,更不会嘲讽你,而是会帮你理清楚目标职位跟你的实力有距离的时候,你所面临的利害关系(比如一旦被面试唰下来,在这家公司再被捞起来的概率可能是大幅降低的),真正专业的猎头,是会认真跟你交朋友的,因为当下的你可能还只是弱鸡,三年后可能就一鸣惊人了,至少我见过的好的猎头,会带候选人一起参加面试,会跟有交情的主面试官打个客套,甚至会给候选人带吃的喝的全程陪护(考虑到有的高级岗位会面试一个上午加半个下午的情况)。</p>
<p>本来只想发 500 字,一不小心说这么多,大家听听就好,千万别当真哦。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1579178669691-3b97de17-d9b4-419d-84ee-57366d957032.png#align=left&display=inline&height=315&name=image.png&originHeight=539&originWidth=1280&size=1569079&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=ppJvfaOQ8JPvKdVQJaOh8Q%3D%3D.dK2gvagsxh%2BUM24eRusEqpX2NxfjRQGgan3kMos5PFE%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
不可思议: 300 个主管招聘 1000 个前端的故事
https://segmentfault.com/a/1190000022295196
2020-04-18T23:00:00+08:00
2020-04-18T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
1
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>理论上,具备核心竞争力的团队,招聘不应该成为一件难事,具备核心竞争力的个人,求职也不应成为一件难事,然后往往事与愿违,本文旨在帮助所有的前端候选人了解到市场缺口的机会是存在的,也让所有主管了解到在有限的池子里要想抢占招聘制高点,你必须做哪些准备?</p>
</blockquote>
<p>我有一个前端主管群,里面有 340 多个带团队的前端主管(进群时全部验证过所在公司和身份),遍布大江南北,大到 BATMD,小到刚成立一年的创业公司,我在群里做了一个 2019 第四季度和 2020 第一季度的招聘统计,也就是大家常说的 HC 数(HeadCount),统计表的数据如下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1572934758665-1f8b72a5-e618-48c2-81ab-b4f2bd39e268.png#align=left&display=inline&height=471&name=image.png&originHeight=1412&originWidth=3270&search=&size=849435&status=done&width=1090#align=left&display=inline&height=1412&originHeight=1412&originWidth=3270&status=done&style=none&width=3270" alt="image.png" title="image.png"></p>
<p>340 多个主管,一共带了 2000 多个前端,主动提交 HC 统计表的一共有 176 个主管,刚好占一半,剩下的一半可能没有看到消息也可能不愿意提交,那么一半的主管,提交上来了 704 个坑位,也就是群里一半主管的团队缺口是 700 个前端,那么我们大胆推测,剩下未填写收集表的一半主管,最少最少应该也有 300 个坑位,所以就有了本文标题 - 300 个前端主管要招聘到 1000 个前端,招聘的需求是未来的两个 Q,也就是未来半年。</p>
<p>数字听上去非常庞大,但我们平均一下,一个主管其实未来要招聘 3~4 个前端,比如小菜未来半年,其实会放开的招聘坑位,应该也是在 3~6 个之间的样子,如果我们平均一下,也不过分了,只是 1000 个前端的数字就让我们感到震惊,这个市场缺口居然这么大。</p>
<p>之前我专门写过一篇文章 - <a href="https://link.segmentfault.com/?enc=WfAJ7evdCmBc%2F899AUxuEg%3D%3D.huR9oUAQuFsBuHdnh2rf9ih7HP49TwLeVWrvxnF6fbAs1USEg%2BwDDa1dHvaau6UX" rel="nofollow">《</a><a href="https://link.segmentfault.com/?enc=La%2BRmTX7sZ7aVsqqPkOv5w%3D%3D.QJd0I4lHE%2BePJKvRFkPHvT95IpBI32BV4KX6bBZuW6z9sVyrDiZiMn31EEmPMjKp" rel="nofollow">面试招聘:2 年招到 18 个前端教你怎么招人</a>[》](),从人才画像到候选人分析,到面试过程优化等等,以为可以给大部分的团队提供了招聘思路和方法论,但当我看到这个数字的时候,我觉得那一篇可能还远远不够,还是不能解决招聘难的现状,未来半年,你依然面临找不到合适前端的情况,所以这 300 个前端主管要招聘到 1000 人的故事,可能不会有一个 happyending,毕竟每一个主管背后的每一个团队都有截然不同的优势和劣势,那让我们先从这些主管的基本情况开始分析。</p>
<p><a></a></p>
<h2>群内主管的的基本情况</h2>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1572939072788-22d7d094-f11b-4702-b5b1-930e4e54af24.png#align=left&display=inline&height=300&name=image.png&originHeight=1296&originWidth=3224&search=&size=319548&status=done&width=746#align=left&display=inline&height=1296&originHeight=1296&originWidth=3224&status=done&style=none&width=3224" alt="image.png" title="image.png"></p>
<p>从上图,我们就能看到团队规模小于 20 人占比 90% 多,尤其是 5~10 人的团队,而这些主管,工作经验不超过 8 年,占比有 70% 多,管理的经验,不多于 3 年也有 60% 多,所以结论很明显,大部分都是年轻的技术从业者,也大多是新晋管理者,无论是技术的整体丰富度和管理经验,都远远不够老练,那么理所当然面对招人拿不出具体有效的办法,也在情理之中了。</p>
<p><a></a></p>
<h2>HC 在各城市分布情况</h2>
<p>先看不同城市的 HC 趋势图,再看具体数字:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1572940224339-9cdcffe4-a96f-4c65-9d84-86380c5a3d5f.png#align=left&display=inline&height=370&name=image.png&originHeight=980&originWidth=1976&search=&size=123602&status=done&width=746#align=left&display=inline&height=980&originHeight=980&originWidth=1976&status=done&style=none&width=1976" alt="image.png" title="image.png"></p>
<blockquote>这数字是仅仅这一个微信主管群统计上来的数字,既不反应市场真实的招聘缺口,也不反应该城市真正的主管数量,仅仅反应这个群里面主管面临的招聘形势,也是我的人脉圈趋势,大家不要被数字误导了。</blockquote>
<table>
<thead><tr>
<th align="center">城市</th>
<th align="center">主管数量</th>
<th align="center">专家 HC</th>
<th align="center">非专家 HC</th>
<th align="center">城市 HC 总数</th>
</tr></thead>
<tbody>
<tr>
<td align="center">北京</td>
<td align="center">43</td>
<td align="center">45</td>
<td align="center">128</td>
<td align="center">173</td>
</tr>
<tr>
<td align="center">杭州</td>
<td align="center">41</td>
<td align="center">46</td>
<td align="center">73</td>
<td align="center">119</td>
</tr>
<tr>
<td align="center">上海</td>
<td align="center">23</td>
<td align="center">32</td>
<td align="center">74</td>
<td align="center">106</td>
</tr>
<tr>
<td align="center">深圳</td>
<td align="center">17</td>
<td align="center">23</td>
<td align="center">112</td>
<td align="center">135</td>
</tr>
<tr>
<td align="center">苏州</td>
<td align="center">6</td>
<td align="center">18</td>
<td align="center">26</td>
<td align="center">44</td>
</tr>
<tr>
<td align="center">广州</td>
<td align="center">12</td>
<td align="center">11</td>
<td align="center">24</td>
<td align="center">35</td>
</tr>
<tr>
<td align="center">武汉</td>
<td align="center">4</td>
<td align="center">4</td>
<td align="center">10</td>
<td align="center">14</td>
</tr>
<tr>
<td align="center">郑州</td>
<td align="center">2</td>
<td align="center">4</td>
<td align="center">6</td>
<td align="center">10</td>
</tr>
<tr>
<td align="center">长沙</td>
<td align="center">5</td>
<td align="center">4</td>
<td align="center">4</td>
<td align="center">8</td>
</tr>
<tr>
<td align="center">山西</td>
<td align="center">3</td>
<td align="center">2</td>
<td align="center">8</td>
<td align="center">10</td>
</tr>
<tr>
<td align="center">成都</td>
<td align="center">7</td>
<td align="center">2</td>
<td align="center">7</td>
<td align="center">9</td>
</tr>
<tr>
<td align="center">宁波</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">5</td>
<td align="center">7</td>
</tr>
<tr>
<td align="center">珠海</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">2</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">烟台</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">0</td>
<td align="center">2</td>
</tr>
<tr>
<td align="center">重庆</td>
<td align="center">3</td>
<td align="center">1</td>
<td align="center">7</td>
<td align="center">8</td>
</tr>
<tr>
<td align="center">南京</td>
<td align="center">2</td>
<td align="center">1</td>
<td align="center">6</td>
<td align="center">7</td>
</tr>
<tr>
<td align="center">厦门</td>
<td align="center">3</td>
<td align="center">1</td>
<td align="center">3</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">西安</td>
<td align="center">1</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">3</td>
</tr>
<tr>
<td align="center">贵州</td>
<td align="center">1</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">3</td>
</tr>
<tr>
<td align="center">济南</td>
<td align="center">1</td>
<td align="center">1</td>
<td align="center">1</td>
<td align="center">2</td>
</tr>
<tr>
<td align="center">湖南</td>
<td align="center">1</td>
<td align="center">0</td>
<td align="center">1</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">共计</td>
<td align="center">176 位</td>
<td align="center">203 个 HC</td>
<td align="center">501 个 HC</td>
<td align="center">704 个 HC</td>
</tr>
</tbody>
</table>
<p>从上图的数字中,我们很明显发现,这些招聘的 HC 中,专家的比例相当高,拿杭州举例,整个市面上流通的前端技术专家数量本来就很稀少,而群里的 41 个主管,就要招聘到 46 个前端技术专家,平均一人一个,这谈何容易,反过来,也暗示着<strong>前端工程师的市场红利还大大的有,只要保持技术成长,尽快到技术专家的水平,市场上有大量的专家坑在等着你</strong>,嗷嗷待哺的等你。</p>
<p><a></a></p>
<h2>候选人为什么来你这里</h2>
<p>作为用人方,都希望来自己这儿的候选人都是优秀的候选人,然后再从优秀的候选人里面挑选合适的,反过来对于候选人也是一样,首先挑选优秀的公司和团队,再从这里面挑合适的,合适的标准有很多,这些标准符合候选人的越多,候选人中意你的概率越高,所以用人方只要把这些标准尽可能多的展示给候选人就可以了。</p>
<p>我们接下来就来捋一捋候选人心动的点,也就是来你这里的理由:</p>
<ol>
<li>
<strong>公司光环</strong>: 我来这里能镀好金,比如进阿里,腾讯等大厂,全国家喻户晓</li>
<li>
<strong>团队加成</strong>: 我来这里能大成长,比如进阿里的体验技术部(国内最顶尖的前端团队,一大堆技术专家在身边)</li>
<li>
<strong>薪资诱人</strong>: 我来这里能大回报,比如进头条系的技术团队,虽然大小周,但薪资属于行业翘楚</li>
<li>
<strong>技术厉害</strong>: 我来这里能大成长,比如进阿里的体验技术部,各种最酷的技术探索,大舞台让我充分挑战</li>
</ol>
<p>我们只看这 4 点,公司光环、团队加成、薪资给力、技术厉害,是不是你的公司一个都没占,甚至这些都不以你的意志为转移,你努力也没有太大的用,这就是除了大厂外,剩下成千上万的公司和团队的现状,没名气缺大牛没预算,但是公司也要发展啊,总不能等天上掉专家吧,我们接着往下看。</p>
<p>我近 1 年,收到了来自阿里体验技术部,至少 6 份简历,有的是还在职,有的已经离职出来了,按道理小菜前端是一个小公司的小团队啊,怎么可能会得到阿里这种顶尖部门员工青睐呢,那一定是这些部门做错了什么,而我们做对了什么,这就是我要分享给大家的答案:<strong>招人要有差异化优势</strong>,那这些优势是哪些呢?</p>
<p>先聊问题,大公司的问题常见的有这么几种:</p>
<ul>
<li>氛围:部门内外有政治斗争,排挤和暗箱操作,业务蛋糕的明争暗斗</li>
<li>通道:公司内人才济济,要想获得晋升机会,需要务实也务虚,向上管理和规划投的精力比重太高</li>
<li>成长:部门有一些第三方或非核心的业务,需要有人常年值守维护,沦为螺丝钉每天搬砖</li>
<li>氛围:公司会议多,流程长,协同成本高,出问题扯皮甩锅的多</li>
<li>地位:业务话语权大,为了求稳需要在老旧的技术栈上维护老系统,成长空间有限</li>
<li>加班:工作强度太高,996 严重,加班加到怀疑人生</li>
<li>回报:薪资虽然不错,新员工的期权极少甚至没有,看不到未来的回报空间</li>
</ul>
<p>也就是我们常说的一些大公司病,那么对于中小公司,不在这些问题上犯错就能凸显出竞争优势了,如果一个小公司,整体会议扯皮,晋升通道不通畅,成长受限,开发话语权小地位低,加班过于反人类,那么这些优势就迅速变成连大公司病都比不过的致命劣势。</p>
<p><a></a></p>
<h2>小菜招前端的两个抓手</h2>
<p>小菜前端招人的渠道跟所有公司没有太大差异,拉勾、Boss、猎头等,但能在杭州这么激烈的招人环境中脱颖而出,获得诸多候选人的青睐,我觉得最核心的一个原因是,能让整个社区的更多同学看到来小菜前端所能得到的收获,请大家加粗 <strong>”更多同学“ 和 ”收获“ 这两个词,前者就是曝光度,后者是匹配度</strong>。</p>
<p>所谓曝光度,就是对于 A 公司,社区只有 1000 个前端听到过他们,对于小菜,社区有 2 万个前端听到过他们,那么 A 公司和小菜,哪个会收到更多简历,答案显然易见。</p>
<p>如何曝光的等会聊,我们先谈收获,所谓收获包含了技术成长、薪资回报、经验能力等等,小菜前端能拿到结果,无非就这两个抓手,让更多童鞋看到我们,且证明给这些同学在小菜前端团队是可以有巨大收获的,无论这个收获是你扩展了更多新的技术栈,还是在小菜历练后,可以有更大的实力直接进入大厂(我还被阿里的朋友说,小菜是阿里的人才培养皿,从小菜历练后出去的前端,都有很强的实力,今年连续 2 个都进了阿里,当然作为管理者和团队教练,也是乐见其成)。</p>
<p><a></a></p>
<h2>用人方做哪些事提升优势</h2>
<p>既然我们知道了曝光度和匹配度是核心因子,那么就要在这两个上面做功课,并且做实实在在的功课,<strong>如果要曝光,就要肚子里有货,没有货直接曝光只会越曝越虚</strong>,要能匹配上候选人,就要在海量的候选人中命中更多他们在意的因素,比如技术成长、做事氛围、晋升通道等。</p>
<p>那么对于曝光度,有哪些性价比不错的渠道呢?</p>
<ul>
<li>各个技术社区和内容平台,比如掘金、知乎、微信公众号上面可以持续的发布技术文章,无论是团队的账号,还是投放第三方账号都没关系,只要文章中能曝光团队名称,并且能输出干货,大家可以数下这篇文章中,小菜前端出现的次数,这种方式非常轻量级,短时间内很难见效,需要坚持做,建议大家学习小菜或者政采云前端团队的技术文章产出套路</li>
<li>举办技术大会或者派讲师参加,比如 FCC/GMTC/NodeParty/D2 等等,大会是集中流量曝光的地方,短时间内会有效果,小菜前端组建之初就连续参加了四五场外部技术会议,关于办会议建议大家跟大搜车芋头大大学习 NodeParty 举办经验</li>
<li>出版物首选电子书、技术报告或者技术小菜,比如小菜前端今年出了 <a href="https://link.segmentfault.com/?enc=Snr8v5tJAyb7ZeghlNvNCQ%3D%3D.RbXAwdLoaPxJUpjzREh0B%2BaA6snQW%2BcWJQHA2%2FKihtOG9JyjB3SZD2nrOYokQUScwuoCPG8%2FPCpWMI%2BPfjjf0p0Xz65nTa6QKQcPmk4LxYq5orOAOuOxtl9KVJhPdywU" rel="nofollow">《优秀的前端团队是如何炼成的》</a>这本小册,销量是次要的(经费当然全部供团队吃喝玩乐),重要是让更多人了解到一个团队的全貌,当然 gitchat 等等无论是付费还是免费的编程教育社区都可以选择</li>
</ul>
<p>保持性价比,我其实就只推荐这三种,这三种任何一个做好了,都会大大减缓招聘的压力,如果三个都做好了,当然效果更明显,小菜前端恰好三个都做到了,没有想象中那么难。</p>
<p>曝光度是方法,背后要有内容承载,这个内容承载决定了匹配度,那么内容无非就这么几种:</p>
<ul>
<li>干货的技术输出,无论是方案、工具、思路哪怕仅仅是一个组件,<strong>让社区看到这个团队对技术是开放探索的态度</strong>,这个态度至关重要</li>
<li>通畅的晋升通道,通过输出不同的讲师,或者不同级别的作者贡献文章,让社区感受到这个团队有技术钻研深度的层次感,感受到技术只要够厉害,在团队里一定有更大的舞台可以玩</li>
<li>舒服的做事氛围,无论是团建 outing,还是技术分享,还是聚餐游戏,让社区感受到这个团队是活生生的一群人,能相处的来,气氛总体是融洽的不是死气沉沉的</li>
</ul>
<p>这里面每一个都很关键,是需要团队管理者用心经营的,一天一周是不能速成的,需要几个月到一两年的持续运行,非常考察管理者的心力脑力,最难的是晋升通道,这个需要公司层面来配合让机制变得成熟,其次是干货的基础储备,这个需要技术部门老大理解你并配合你,所幸小菜技术部整体比较开放,老大非常开明,给与各个团队充分的授权做技术探索,如果你作为管理者,搞不定部门层面给你空间,那么你就会卡在这里。</p>
<p><a></a></p>
<h2>团队一把手是小棉袄 HR</h2>
<p>这段话分享给独立带前端团队,且<strong>背招聘 KPI 的主管,除了管理团队外,具备招聘能力是你的一项基本技能</strong>,在公司名气大团队影响力大时候,这些都不用操心,但当你处在大公司外的中小型公司中,特别是创业团队中,要把人字每天放到心头念一遍,因为搞人会成为你最大的一个难关。</p>
<p>而你能做的,无非就是增加曝光度,提高匹配度,而背后就是在候选人在意的问题上,推动公司少犯错:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1573721507695-ea2fb672-946a-4edc-a8b7-065f91496da5.png#align=left&display=inline&height=190&name=image.png&originHeight=434&originWidth=1706&search=&size=615324&status=done&width=746#align=left&display=inline&height=434&originHeight=434&originWidth=1706&status=done&style=none&width=1706" alt="image.png" title="image.png"></p>
<p>成长、薪资、氛围、平等的管理和人际关系,这些现代年轻的候选人在意的点,你要驱动组织发生变化,才能一点点形成竞争力。</p>
<p>最后,再放下小菜前端两年跑下来,在组织能力和团队氛围上所沉淀的经验,大家可以从这些维度上来完善团队,这是被验证有效果的方法论,希望能对你有所启发:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1573721661165-acc49f5c-ad56-487a-80e1-cb2c975e2de6.png#align=left&display=inline&height=418&name=image.png&originHeight=1254&originWidth=2238&search=&size=1648427&status=done&width=746#align=left&display=inline&height=1254&originHeight=1254&originWidth=2238&status=done&style=none&width=2238" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=hSqDLgxNufIkR1KiN8K8OA%3D%3D.yQrPvb3OjywM8gWiwSp81WLpT%2BbsMZGORHFBVJt5%2Bfg%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术决策:自研和半自研数据报表与可视化大盘
https://segmentfault.com/a/1190000022295211
2020-04-18T23:00:00+08:00
2020-04-18T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
4
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>数据只有被看见,真相才浮出水面,数据跳动在大盘,洞察才形成预判。</blockquote>
<p>今天 2020/1/7,到小菜整整 2 年半,看到团队在数据报表量产和可视化上面有了新的成果,这些年来也了解到前端后端面对不计其数的数据报表和后台可视化大盘,真心苦不堪言,就趁这个节点,跟大家聊聊两年半来我们是如何从前端来驱动数据报表量产和可视化大盘的技术探索。</p>
<p>首先上结论:</p>
<ul>
<li>公司的数据仓库(简称数仓)要投人力持续建设,它是报表及可视化的基础</li>
<li>前端自研报表及可视化会有较高的成本,需要谨慎再谨慎,竞品调研再调研</li>
<li>魔改 <a href="https://link.segmentfault.com/?enc=kjJVQ39IsIZ2aNj%2B42DQew%3D%3D.57jIASU5s0naWLbztEVrKlhzCUESGgovyyJFwXsRQwhRngblptMk%2FBcREE%2BRlAfB" rel="nofollow">Metabase</a> 是一个不错的选择,需要前端学习 Clojure 和熟悉 React</li>
</ul>
<p>简而言之,<strong>先推动技术团队把数据仓库建设到基本成熟,再来基于 Metabase 魔改出自己的报表和可视化业务后台</strong>,这是一个可取的套路,得出这个结论,是因为两年半的探索我们有斩获也有疼痛的教训。</p>
<p>当然一路自研过来,我们也调研了很多方案,无论是商业付费还是开源,对第三方可替代竞品的选择标准如下:</p>
<ul>
<li>代码开源免费,有团队/人持续在维护</li>
<li>产品交互流程易用可定制,有设计感</li>
<li>技术栈对前端友好,学习上手成本低</li>
</ul>
<p>阅读两篇旧文,有助于大家理解下文:</p>
<ul>
<li><a href="https://link.segmentfault.com/?enc=mmqkNHCWABI%2BR7RPEWBYKQ%3D%3D.xKhhoFjjOnPqpr5Aw5PAB8lsMGfQO8h%2BxX4nnuFfm2PS6exwL1dUxu2Zck%2FrVuQD" rel="nofollow"><strong>技术驱动:量产数据报表的工具如何搭建</strong></a></li>
<li><a href="https://link.segmentfault.com/?enc=1RFlQ5fKeLuY4m5RGyk%2B2Q%3D%3D.86%2FGh0DT%2F3469KGPEcx2sAKhza9FgiJ4anQFW%2B1AOg0WX%2FnuZqa8mxUol40QqVr4" rel="nofollow"><strong>技术驱动:业务大盘数据可视化技术探索</strong></a></li>
</ul>
<p><a></a></p>
<h2>为什么数据报表是刚需</h2>
<p>不管是 toB 还是 toC 的公司,无论是 <strong>+互联网还是互联网+</strong>,都对数据报表有着近乎疯狂的依赖,这不仅仅是像马老师说的我们正在进入 DT 时代,数据运营甚至数据智能价值挖掘和应用越来越普及,而是<strong>对于任何一家高速迭代的互联网公司,在产业互联网的大背景下,在中早期各种红利逐渐消逝的前提下,基于数据的成本意识和精细化运营能力越来越考验一家公司在所谓寒冬活下去的实力</strong>。</p>
<p>业务现场无时无刻都在产生着数据,<strong>通过什么途径观测业财健康直接决定一个公司/一条业务线的顶层决策</strong>,顶层决策有何等重要,促成决策的数据报表就有多重要,所以一个公司只要上了信息化系统,数据报表都会成为绝对刚需。</p>
<p>基于这个刚需,有的公司招专门的 BI 工程师,组建算法团队甚至大数据团队,有的则是业务方直接把要看的字段丢给开发团队,让前后端工程师,一个写跨库跨表的 SQL API,一个写能筛选日期和排序的 DataTable 页面。</p>
<p>显然小菜早期,就是<strong>以 SQL -> API -> DataTable 的流程开发报表,效率极低,成就感极弱,前后端成长极慢</strong>,带来的影响有很多,比如工程师更不稳定,比如业务决策等待的周期更长,比如报表的零散维护出错率更高...</p>
<p><a></a></p>
<h2>第一波探索 - SQLEditor</h2>
<p>启动数据报表是在 2017 年 7 月份,届时市面上还没有较为成熟的开源方案可选,包括目前的 Metabase,调研无果后,我们选择了纯自研,<strong>目标是让产品经理/后端开发可以快速在线制作报表并渲染出来。</strong><br>**<br>方式是参考数据仓库业务表的文档,在系统上快速的定义报表列的中文名称以及对应的库表字段的查询(比如产品经理可以不借助开发资源,自行查询销售的周市调次数和周个人交易单量这样的简单报表),由于是取代运营本地人肉的 “搭表格”,因此这个系统取名叫做 “大表哥”,它的技术栈的进化如下:</p>
<p><a></a></p>
<h4>早期技术栈</h4>
<ul>
<li>前端:React + Ant</li>
<li>后端:Node.js/Koa2/MongoDB/RDS</li>
<li>服务器:1 台 2 核 4G Centos</li>
</ul>
<p>功能清单:</p>
<ul>
<li>报表需求提交(看某业务的哪些数据)</li>
<li>报表加工(在后台网页编辑 SQL)</li>
<li>过滤组件(基于某字段做数据筛选过来)</li>
<li>报表查看(按照一套模板渲染报表)</li>
<li>报表导出(Excel 格式导出)</li>
</ul>
<p>技术栈缺点:</p>
<ul><li>Koa2 是一个精巧精简的 Node.js 框架,不是一个企业级的框架,从 0 开始配置开发,成本还是比较高</li></ul>
<p>产品交互易用性:</p>
<ul><li>前端页面的交互未经过设计,前端自行设计,比较粗糙难用</li></ul>
<p><a></a></p>
<h4>中期技术栈</h4>
<ul>
<li>前端:React + Ant + Apollo + React Native</li>
<li>后端:Node.js/Egg/Python</li>
<li>服务器:1 台 2 核 4G Centos</li>
</ul>
<p>功能清单:</p>
<ul>
<li>报表需求提交/加工/查看/导出优化,及更多过滤组件</li>
<li>报表权限(谁能看哪些报表)</li>
<li>数据权限(谁能看哪些报表背后数据库的哪些表)</li>
<li>透出报表到 App 端(ReactNative 报表组件)</li>
</ul>
<p>技术栈缺点:</p>
<ul>
<li>低版本 RN 报表组件开发踩了不少坑</li>
<li>Python 加工数据性能压力比较大,且比较吃 CPU,无法高效的解析二进制类型的数据</li>
</ul>
<p>产品交互易用性:整体的产品设计较粗糙,菜单管理权限管理粗暴,维护成本较高,导出功能不稳定</p>
<p><a></a></p>
<h4>目前技术栈</h4>
<ul>
<li>现在:AntD + AntV + Apollo + Rxjs + React + Rematch + React Native</li>
<li>后端:Node.js/Egg/Envoy/Python/gRPC/Docker</li>
<li>服务器:1 台 4 核 8G Centos + 1 台 2 核 4G Centos</li>
</ul>
<p>功能清单:</p>
<ul>
<li>报表需求提交/加工/查看/导出优化(分布式 Docker 部署)</li>
<li>报表权限/数据权限接入权限中心</li>
<li>报表到 App 端的组件化丰富与开发</li>
</ul>
<p>技术栈缺点:</p>
<ul><li>大量的报表查询与导出,给 RDS 带来较大查询压力,同时超大报表的导出,服务器 I/O 压力大</li></ul>
<p>产品交互易用性:</p>
<ul><li>整体功能可用,但流程偏复杂,设计感不强</li></ul>
<p>报表制作后台,可以跨库跨表的查询数仓的数据,自由度很高:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1578476837819-b48cbd26-f6af-4555-b784-62d90ed06c93.png#align=left&display=inline&height=402&name=image.png&originHeight=804&originWidth=2412&size=173318&status=done&style=none&width=1206#align=left&display=inline&height=804&originHeight=804&originWidth=2412&status=done&style=none&width=2412" alt="image.png" title="image.png"></p>
<p>报表展示页面,自动关联各种筛选组件,增强报表的检索功能:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1578477057709-b1b301f2-5c1a-4788-b9fe-261a2cf1e11b.png#align=left&display=inline&height=432&name=image.png&originHeight=864&originWidth=2758&size=170775&status=done&style=none&width=1379#align=left&display=inline&height=864&originHeight=864&originWidth=2758&status=done&style=none&width=2758" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>第二波探索 - 可视化大盘</h2>
<p>启动可视化大盘是在 2019 年 1 月份,届时销售征战四海,业务遍布全国各地,需要有一些更宏观、更易于理解、更易于诊断和决策的视角来看时间线上的业务财务变化,以及跟进地面部队的 KPI 完成情况,就启动了数据大盘这个项目,因为它需要有很强的定制性(比如更改 KPI 和录入新指标等),而且比较紧急,除了付费用阿里云 DataV 做一些过渡外,就在大表哥的基础上启动了数据大盘的开发,让它可以直接长在数据报表之上,技术栈情况如下:</p>
<p><a></a></p>
<h4>当前技术栈</h4>
<ul>
<li>前端:React + Apollo + AntV</li>
<li>后端:Node.js/Egg/Python/C#</li>
<li>服务器:1 台 2 核 4G Centos</li>
</ul>
<p>功能清单:</p>
<ul>
<li>元数据过滤聚合</li>
<li>10 个图形组件可选择</li>
<li>自由挑选组件组成看板</li>
<li>自定义看板布局</li>
<li>Redis 缓存数据</li>
<li>看板查看权限</li>
<li>图表动态筛选组件</li>
</ul>
<p>技术栈缺点:</p>
<ul>
<li>明细数据数据量大,导致前端加载慢</li>
<li>GraphQL 无法 URL 缓存</li>
<li>C# 计算 Excel 方案吃 CPU,服务器压力太大</li>
<li>Python 计算性能差</li>
</ul>
<p>产品交互易用性:编排流程复盘,需要定时触发任务加工数据,编辑体验和调试体验不好,可视化的大盘性能不好</p>
<p>除了传统的饼图柱状图二维表等等,也有偏定制的跟踪 KPI 的录入式卡片集:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/87555/1578477580982-738a553f-c7b2-43d9-b4f1-e20eb51601fc.png#align=left&display=inline&height=144&name=image.png&originHeight=390&originWidth=2022&size=64844&status=done&style=none&width=746#align=left&display=inline&height=390&originHeight=390&originWidth=2022&status=done&style=none&width=2022" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>第三波探索 - Metabase</h2>
<p>启动 Metabase 是在 2019 年 7 月份,届时 Metabase 趋于稳定,公司的数据仓库建设也更加成熟稳定,可以面向 BI 团队接收需求来开发一张张业务宽表,具备了可快速查询的条件。</p>
<p>另外需求也有变化,更多端的报表及可视化的透出需求越来越多,比如透出到钉钉 H5 上,内部的 App webview 内,PC 中后台的系统中,甚至是客户的微信 H5 账户主页上,就启动了这一次的探索:基于 Metabase 来魔改报表及图表的拼装流程,公司自己登陆系统/权限系统的集成,与原来的大表哥做融合升级抽离微服务等等,基于这么多可视化大盘的需求,我们把这个经过魔改的 Metabase 改名叫 “大盘子”,它的技术栈情况如下:</p>
<p><a></a></p>
<h4>当前技术栈</h4>
<ul>
<li>前端:React + Redux + D3</li>
<li>后端:Clojure/Docker/RDS</li>
<li>服务器:1 台 2 核 4G Centos</li>
</ul>
<p>功能清单:</p>
<ul>
<li>创建需求</li>
<li>创建仪表盘(看板)</li>
<li>创建定时任务(发送需求至邮箱)</li>
<li>自动分析数据库数据</li>
<li>14 个可视化组件</li>
<li>自动分析生产仪表盘</li>
<li>下钻分析</li>
<li>支持多种数据源</li>
<li>权限管理</li>
</ul>
<p>技术栈缺点:</p>
<ul>
<li>前后端耦合</li>
<li>React 太低,只有 15,无法使用很多社区资源</li>
</ul>
<p>产品交互易用性:</p>
<ul><li>汉化的效果不佳,整体的设计稿偏朴素,流程上手有一定的理解成本</li></ul>
<p><a></a></p>
<h4>预期技术栈</h4>
<ul>
<li>前端:React + Redux + d3 + AntV + AntD + Storybook + gRPC</li>
<li>后端:Clojure/Node.js/Envoy/gRPC/Python/Docker/RDS/Druid</li>
<li>服务器:3 台 2 核 4G Centos</li>
</ul>
<p>功能清单:</p>
<ul>
<li>创建需求</li>
<li>创建仪表盘(看板)</li>
<li>创建定时任务(发送需求至邮箱/钉钉)</li>
<li>自动分析数据库数据</li>
<li>22+ 个可视化组件</li>
<li>自动分析生产仪表盘</li>
<li>下钻分析</li>
<li>支持多种数据源</li>
<li>数据权限管理</li>
<li>钉钉小程序组件</li>
<li>多种主题(目标替代已付费的 DataV)</li>
<li>模块组件</li>
<li>分布式服务</li>
</ul>
<p><a></a></p>
<h2>大表哥和大盘子生产链路</h2>
<p><a></a></p>
<h4>大表哥一句话</h4>
<p>网页版的报表编辑器和展示工具,具备量产数据报表和可视化搭建图表的能力。</p>
<p><a></a></p>
<h4>大盘子一句话</h4>
<p>基于 Metabase 魔改的系统,具备数据报表和图表搭建的全链路生产与应用能力。</p>
<p><a></a></p>
<h4>生产报表链路</h4>
<p>大表哥,更偏工具属性,它的生产链路是从一份报表的需求提交开始,比如想要一个报表,看所有门店昨日成交 总单数、GMV...假如门店业务的 10 个表头业务字段也定义好了,接下来 PD/开发 进场:</p>
<p><a></a></p>
<h6>一、 制作阶段:</h6>
<ul>
<li>从报表需求进入到网页后台的 SQL Panel 制作页面,引入各方数据表(跨库跨表)</li>
<li>对各种表进行 join,提炼业务字段并定义、过滤(数据内容、数据权限管理)、数据聚合、排序和分页规则</li>
<li>最终生成两套 SQL,一套是能查出这份报表的 SQL 本身,一个是对它的 count 操作</li>
<li>生成的 SQL 以元字段和特定规则持久化到 MongoDB,报表制作完毕</li>
</ul>
<p><a></a></p>
<h6>二、 渲染阶段:</h6>
<ul>
<li>从 MongoDB 中拿到特定报表的 SQL 规则</li>
<li>把规则转成 SQL,连接 RDS(MySQL) 进行 Query</li>
<li>查询后拿到的 Rows Data 返回,经由 GraphQL Query Endpoint 进一步筛选聚合</li>
<li>网页拿到二维数据及表头数据,开始渲染 Table 渲染及配套的过滤组件</li>
</ul>
<p><a></a></p>
<h6>三、导出阶段:</h6>
<ul><li>导出 Excel 依靠另外一台服务器,做 Excel 的流式存储</li></ul>
<p><a></a></p>
<h6>四、透出阶段:</h6>
<ul><li>透出到移动端,借助于额外开发的 RN 移动报表组件,来实现九宫格、卡片、列表、Tab、复合筛选等报表功能</li></ul>
<p><a></a></p>
<h6>五、图表制作:</h6>
<ul>
<li>在 1 基础上,定时更新,过滤、聚合(统计逻辑)、将大盘背后的数据,定时持久化到 Redis(单个宽表)</li>
<li>挑选 redis 报表数据源,二次加工数据,编排组合这些二维表和图表,生成特定业务域的可视化数据大盘</li>
</ul>
<p><a></a></p>
<h6>六、定制通知:</h6>
<ul><li>在 5 的基础上,可以以关注的形式跟进大盘的数据变化,获得实时的钉钉消息推送</li></ul>
<p>从制作到展示,到透出到移动端,整个报表链路是闭环的,但是也有不足和缺陷:</p>
<ul>
<li>移动端只能适配 APP,无法适配 H5,并且强依赖 APP 的热更新发布</li>
<li>移动端只建设了二维表组件,未建设可视化组件(这也不是 RN 强项)</li>
<li>产品的 SQL 能力有限,跨库跨表查询容易把数据库查挂,或者拖慢整体的性能</li>
<li>数据仓库的底层未建设,放开跨库跨表查询的权限有安全风险</li>
<li>编排可视化大盘与报表的绑定太过耦合,对其他数据源的兼容度不好</li>
<li>报表、可视化以及移动端的 RN 报表组件内,对于权限的管理不够体系化</li>
</ul>
<p>大盘子,虽然也是工具属性,但由于它是站在了数仓宽表基础设施完善的基础上,所以针对单表(可额外 Join 一张表)的数据聚合、组合和图表编排能力更完整,它的主流程如下:</p>
<p><a></a></p>
<h6>一、数据源创建阶段:</h6>
<ul>
<li>SQL Panel(单库单表,额外 Join 一张表),引入宽表数据源</li>
<li>字段定义、过滤、聚合、排序生成 SQL(可以预览 SQL)</li>
<li>SQL 规则持久化,数据源定义完成</li>
</ul>
<p><a></a></p>
<h6>二、图表/二维表制作阶段:</h6>
<ul>
<li>在 1 的基础上,透出二维表/图表类型的映射选择</li>
<li>针对表的字段再定义</li>
<li>渲染展示和导出 Excel(导出性能不好)</li>
<li>不断的重复 1 到 2 的图表/二维表选择,制作很多单图表组件</li>
<li>组合编排这些单图表组件,生成可视化数据大盘</li>
</ul>
<p><a></a></p>
<h6>三、透出阶段:</h6>
<ul><li>Webview url 内嵌或者组件引入,渲染特定的二维表/图表/综合大盘的 PC/H5 页面</li></ul>
<p>显然大盘子的链路更短,而且可以被 webview 嵌入,可以充分利用浏览器能力,它的发布效率更高,特别是 Bug 修复和大盘具备迭代的时候,但大盘子的报表导出性能不高,同时对于偏录入式的可视化组件支持不够,以及 webview 自身的加载性能问题。</p>
<p><a></a></p>
<h2>自研与半自研的价值比较</h2>
<p>大家如果对比上面三波探索的功能点,会发现这个公式:</p>
<blockquote>大表哥(自研) + 大表哥可视化(自研) ≈ 大盘子(半自研)</blockquote>
<p>也就是我们辛辛苦苦迭代了 2 年的的数据报表和可视化的成果,也就能顶上开发半年的 Metabase 的成果,WTF...</p>
<p>如果让我们重新回到 2017 年,我们一定会做如下的选择,来避开两段弯路:</p>
<ul>
<li>在数据仓库不 Ready 的前提下,我们不会启动数据报表平台的建设</li>
<li>在 Metabase 趋于成熟的时候,我们会选择用半自研替代全自研</li>
</ul>
<p>提到价值,就一定是这套技术解决方案给公司带来的价值,在对它门复盘时候我们是这样评估的:</p>
<ul>
<li>大表哥的价值:实现了公司数据报表量产的从 0 到 1,<strong>所谓量产,就是提效,提高数据报表从需求到上线的效率,进而提高业务方的决策效率</strong>,这个价值在过去的 2 年被充分证明了(有产品经理形容做报表比从起快了 8 倍,从起两三天,现在两三小时)</li>
<li>大盘子的价值:实现了公司报表及可视化的流程贯通,<strong>所谓贯通,就是降本,降低团队继续迭代报表和可视化的研发成本</strong>(基于原来的大表哥继续自研下去,研发成本会居高不下)</li>
</ul>
<p>所以这个价值是一个递进关系的价值,在不同的阶段发挥能力,但不可否认,我们整个报表体系化建设中,的的确确走了弯路,多浪费了几个月的时间,半自研的启动其实可以更早更果断一些。</p>
<p>最后大家如果要做独立的报表系统,或者长出大盘可视化的能力,我们的建议依然是:</p>
<ul>
<li>先驱动公司技术团队,建设好数仓,来接管复杂报表和大盘的多表计算需求,实时更新宽表</li>
<li>前端自研报表及可视化会有较高的成本,竞品调研再调研,能承担付费就用第三方过渡</li>
<li>魔改 <a href="https://link.segmentfault.com/?enc=Em8BgBO2bNTDM%2BUNfENdFQ%3D%3D.d1qUlf76ZiDF%2FVlZ7G%2B7tMZMYTXWKzsI3sHhZYjFaZD%2BUQWb2lBs1qRH2%2BA0tkql" rel="nofollow">Metabase</a> 是一个不错的选择,前端至少要学习 Clojure,需要跨栈能力</li>
</ul>
<p>基于前面的三波探索,我们目前明确的方向是,把大盘子和大表哥做融合,制作二维表/图表/编排大盘的能力都给到大盘子,数仓未建设到位的零碎报表展示由大表哥接管(会被逐步弱化但难以替代,因为高频的小报表需求是层出不穷的),同时 PC 端的大盘展示一律接入大表哥做展示,在大盘子和大表哥的背后,抽离连接数仓和其他 API 的能力,封装成微服务,同时供给大表哥和大盘子使用,以及将大表哥的导出服务也贡献给大盘子用,简而言之,大盘子上面制作,大表哥上面看,要透出到多端的时候,一律来嵌大盘子的大盘 URL 或者组件 SDK。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=P%2BAw6Het4WksRs3YYlv7RA%3D%3D.fTUOa3qfwqqTRXraFSJQpYV%2F%2FZ3i8SmDyXtp0asckyQ%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
职业路线:前端工程师的晋升逻辑到底是什么
https://segmentfault.com/a/1190000022295143
2020-04-17T23:00:00+08:00
2020-04-17T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
7
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>小菜前端,历经 2 年,6 到 20 人,从 2018 年 4 月份,1 个 P5 成功晋升 P6;2018 年 10 月,1 个 P7 破格晋升 P8,2 个 P5 破格晋升 P6;2019 年 4 月,1 个 P5 成功晋升 P6,2 个 P6 成功晋升 P7,2 年不到,共成功晋升 7 次,换来的是 7 次的薪资大幅上调及期权发放,晋升通过率 100%,预计到 2020 年 4 月,至少还能有 3 名童鞋得到晋升,这在一个从 6~20 人的前端团队中,2 年能有趋于或者大于 10 次的晋升结果会是非常难得的成绩,那晋升的内部逻辑到底是什么呢?应该以怎样的心态看待它呢?</p>
</blockquote>
<p>专门做了一个小菜前端近 2 年晋升结果表,给大家分享小菜前端团队成长的数据:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567747847944-4e17c10d-dbec-46c9-9764-ca7e3abef5a4.png#align=left&display=inline&height=357&name=image.png&originHeight=1072&originWidth=2370&size=684492&status=done&style=none&width=790" alt="image.png" title="image.png"></p>
<p>一年有两个晋升窗口(跟阿里类似),一个是例行的普通晋升窗口,每年 4 月份,挑选上一财年绩效最好、成长最大的部分同学(有一定的比例限制,比如 10%)进行提名晋升,参加晋升述职评审,闯关成功才算是晋升通过;另外一种是破格晋升窗口,通常在 10 月份,每一年不一定有,是挑选当年度有重大突出贡献的同学进行提名,没有比例和名额限制,因为本身数量就较少甚至没有合适人选导致轮空。</p>
<p>另外就是参加晋升的同学,一定是入职工作满一年以上的同学,其实大家想想就能理解,如果一个同学刚进公司 5 个月就晋升,说明当初面试时候的定级定低了(这种情况会发生,但比例极低),属于是招聘事故,所以符合晋升门槛的对象通常是符合特定要求的员工。</p>
<p>而晋升的模型,无非就是从中高级到资深,资深到专家,专家到高级专家再到资深专家,在你的公司可能是另一套职称体系,但层级晋升的概念应该是一样的。</p>
<p>通过上图我们了解到小菜前端过去 2 年,每年都有 4 个上下的同学晋升成功,其实在 7~11 人的晋升池子中,占比非常高,这说明小菜前端的成长速度非常快,才得到了公司的充分认可,否则一定会有名额缩减,更不可能出现这样的 100% 的晋升成功率,另外就是看破格晋升,能发现每年都能斩获一定的名额,说明前端团队在整个公司的贡献是相当大的,<strong>破格晋升的窗口是以贡献论机会的,不断能获得这样的机会,说明团队有持续性的人才迸发出来,并且能持续性的拿到漂亮甚至卓越的业务结果,虽然这样讲有点不够谦虚,可我还是很开心能看到小菜前端团队不断有童鞋有勇气站出来,有担当敢拿结果,打一场场漂亮仗,也给团队注入了更大的活力和斗志,这是作为管理者乐见的也是创业公司乐见的</strong>。</p>
<p><a></a></p>
<h2>晋升是一个敏感的话题么</h2>
<p>晋升在你的团队也许不是个敏感的话题,但它一定是一个重要的话题,既重要又敏感,大家很难在桌面上讨论它,更多是私底下聚会时的窃窃私语或者是呛声抱怨,这当然不是健康的现象,但它是小范围安全的,毕竟这在职场就等于升职加薪,只差白富美,而薪资在几乎所有公司都是高压线,所以导致升职也经常是少有人公开提及。</p>
<p>在讨论要如何看待它之前,要先讨论为什么好多同学无法正确或者客观淡定看待它。</p>
<blockquote>什么,你让我淡定的看待它?震惊脸.jpg。还要客观? 这不都是潜规则好的咩.gif?</blockquote>
<p>首先声明一下:本人工作 9 年只经历了阿里、创业的公司和宋小菜这三家公司,只有在阿里和小菜里切身经历过晋升和参与过整个晋升体制的搭建和完善,另外小菜的晋升体系跟阿里非常接近,<strong>所以我整篇论点的建构基础,大家都可以理解为阿里系的晋升或者类阿里系的晋升</strong>,其他公司是否有晋升体系、如何晋升、晋升的标准和规则我自认为没有足够素材,就尽量不谈没有事实的观点,希望大家可以理解。</p>
<p>在一个小职场和公司大环境里面,人事的变动是最常见的事情,人事的任用升迁和惩罚也是常见的事情,只不过从公司头部的战略制定到基层员工的执行,是一个信息流的传导,这个传导为了能有更大的穿透效率和更小的路径失焦,就必然要赋予所有的管理层一定的权利,这个权利就包含了最无敌最击中人内心的绩效评定包括劝退辞退。</p>
<p>在这个岗位,你做的好与坏,首先就要获得老板这一层的认可,以及关联部门的认可,而你表现好坏最终会影响到你的收入和未来的空间,这是所有职场人最为关心的,自然而然就让管理形成了约束力,也就有了明确的上下级关系。<strong>而上下级关系或者约束关系的确定,就必然对人的内心产生一定的威慑,不用判定这种威慑是好的还是不好的,它只是客观存在,并且维持整个人类社会不断有效运行而已,同时管理一定是反人性的。</strong>因为它就是要求你什么要做什么不要做,当这个约束关系和反人性的控管模式存在的时候,无论在你什么公司什么团队,都一定处在某个特定管理象限,自然会对权力有所畏惧,至少是谨慎对待,需要执行的当然要执行,不喜欢执行的也要去执行,这未必是一个开心的职场,但他就是一个成年人特定游戏规则内做事的成熟的职场,这个职场里面,安全感是很重要的,而反人性的管理和约束模式的存在,就更加剧对这种安全感的追求,必然让你谨言慎行,谨言慎行没什么对错,但只要有了谨言慎行的行为模式,加薪这种高压线又不得触碰的时候,而恰恰升职加薪又总是不分家的时候,就导致我们每次看待它,都会夹杂很多复杂的情绪和理解在里面,最终很难正确的看待它,至少是很难客观的看待它和评估它。</p>
<p>上面这一大段只为了引出我这样一个观点:<strong>薪资福利既然是大部分公司的高压线,一碰就死,那我们就应该严格遵守,但是升职往往并不是高压线,我们应该把这两个脱钩,拆开看升职的时候,眼睛里就会清楚看到升职这一部分,它的因果逻辑是在哪里,它与成长的关系是什么,与我的关系是什么</strong>,这个时候我们就可以从更具体的视角去分析升职的好处和挑战,心态也就容易放平,自然有了心理基础去评估、看待和实施计划。</p>
<p><a></a></p>
<h2>晋升成败关于成长而非公平</h2>
<p>我们很容易觉得一个人晋升,是因为他熬了这儿多年应该有这个资历,这就相当于是把人进行了排队,越早的人越早获得机会,按照时间轴排排站感觉能体现公平,或者我们会觉得一个工程师晋升,就一定是他的技术实力到了一个层次,那么理所当然要升,不然技术弱的人升了就失去了公平性,实际并不是,<strong>在晋升大盘的评委眼中,晋升的本质是为公司选拔更有担当力更能拿到结果并且主观意愿度也高的优秀人才,此时既是能力成长技术实力的 PK,也是业务结果的 PK,更是一个人综合能力成熟度的 PK</strong>,这样的话,就没有了时间轴所谓的公平性,也没有了所谓能力高低排名的公平性,只不过综合实力需要更多的数字来佐证,无论是业务拿到了什么结果,成就团队成员获得了哪些荣誉还是思维格局到了哪个层次。</p>
<p>那会不会晋升本身就是不公平的呢,就是对某一些同学出现不合理的结果呢,我相信一定会有,至少我接触了阿里好几十个要好的或者是关系一般的技术/产品/运营/设计的朋友和同事下来,从他们的吐槽中,能深深感受到他们的不满和怨气,那我举一些案例大家感受一下(每一个都有具体的人物对应,绝不是想象出来的):</p>
<blockquote>会不会一个前端,辛辛苦苦兢兢业业的在阿里奉献了 9 年的青春,只获得 1 次晋升机会?答案是会。<br>会不会一个后端,拼搏了 2 年把所有的脏活累活全干完还出了成绩,结果被别人强行拿走?答案是会。<br>会不会一个后端,比较内向到了晋升阶段遇到业务表达型评委,被另一个外向型技术取缔掉?答案是会。<br>会不会一个前端,本来说好的要提名晋升结果另一个同事闹离职,老板无奈把机会给了他人?答案是会。<br>会不会一个前端,成长本来很顺利,结果遇到组织架构频繁调整,换了 5 个老板导致良机尽失?答案是会。<br>会不会一个运营,她老板只论关系远近不论能力结果,对她强行边缘化,只提拔他人晋升?答案是会。<br>会不会一个产品,披荆斩棘把产品从 0 到 1 做出来,却被其他部门老板抢走导致晋升无望?答案是会。<br>会不会一个前端,3 个季度绩效一直处在头部,结果年底老板强行给 C,为了让渡名额给他人?答案是会。<br>会不会一个运营,连续 6 年都受到组织架构调整导致被转岗 3 次,能力好但毫无晋升可能?答案是会。<br>会不会一个前端,他的老板是任人唯亲结帮结派,靠承诺笼络众人,却因不会巴结一路不顺?答案是会。<br>会不会一个前端,老板不关心他如何成长,脏活累活不应该接的活统统给他,导致晋升无望?答案是会。<p>还有太多的会会会会会会....这仅仅是我接触到的一个小小样本而已...</p>
</blockquote>
<p>为什么会这样?为什么不能让每一个 case 都变得公平合理,让每一个不应该被耽误的人才都有机会施展,让每一个蒙混画饼的人都早早淘汰...显然用一句不中听的话形容就是:林子大了什么鸟都有,用一句标签化的话形容就是:大公司病而已,规则下自然无法公允公平。</p>
<p>但是否我们会因为这么这么多的负面的不公平的不合理的 Case 来否定阿里这家 11 万员工的晋升体制,包括这一二十年的人才选拔结果,以及这种选拔机制中涌现的人才所带来的整个经济体的飞速成长么?同样是否上面那么多案例的职场不顺晋升失败都要归结给其他人或者其他客观因素么?</p>
<p>显然我们不会去得出这样武断的结论,因为规则是保障体制的延续,而体制是有自己独立的价值观判断,规则是在人手中掌握,再公平的规则也无法在应用的时候,让每一个案例都充分公平,无论参与决策的人主观意愿多么尽心公允,何况参与决策的人本身就一定会存在一定比例的能力和心态缺陷包括信息不透明 - 导致无法做出公平的决断。</p>
<p>但就整个晋升大盘而言,除非你所在公司的整个晋升体系就是形容虚设,规则的具体执行是崩塌状态,那么单从大盘上看,它一定是趋于公平,并且一定是技术能力的梯度结合业务结果的佐证,以及外在评委团和部门间竞争关系的综合值所推向的一个结果,当我们认识到这一层之后,就知道晋升有成有败,成败皆有因,这个因虽然有环境和他人成分,但这个成分不是大概率也不是最核心的成分,最核心的依然是自身,<strong>无论成败,只是一次经历,接下来的新一段历程要重新审视和调整自我,来修正规划获得下一个阶段的成长和再一次的机会。</strong><br>**<br>很多时候不是思维能力的差别,只是心态的不同,心态只要端正了,上面的很多现象我们就不会形成太偏激的认知,我确实了解到一些前端同学,历经 2 ~ 4 次的晋升挫折以后,整个人生观确实发生了一定的扭曲,心态也不再健康,甚至影响到他的工作开展和家庭稳定,这些挫折背后有他人的因素,也有自身的因素,但在他心目中是放大了他人的因素而无限缩小了自身的因素,落差感越来越强,对抗心也越来越强,反而对他的职业状态产生了更大的影响,非常可惜。</p>
<p>这也在一定程度上反应出,工程师这个与机器打交道多过于人的职业,刚毕业的大学生到工作四五年的历程中,整个社会人格和成熟心智的塑造上,确实比一般的社会人会差之蛮多,在这样的背景下,程序员虽然技术造诣很深竞争力很强收入很高,但心智成熟度的欠缺会导致看问题总不能理性客观的同时还缺少烟火气。</p>
<p><a></a></p>
<h2>晋升逻辑的背后是职级体系</h2>
<p>以上给大家灌了 2 口鸡汤:</p>
<ol>
<li><strong>将晋升和薪资两个话题脱钩,单独看晋升,它没有我们想象的那么敏感,可以用更开放的心态讨论它</strong></li>
<li><strong>只要晋升体系相对完善能够运行,不需妖魔化它,我们应该把它看过是检验自己成长的一个绝佳机会</strong></li>
</ol>
<p>只要有鸡汤铺底,我就能展开给大家聊聊晋升体系的内在逻辑和运行机制了,算是给大家解密。</p>
<p>大部分公司都有自己的职级体系,所谓的岗位层级,甚至会区分技术岗还是管理岗,比如在小菜(现在有些不同,但大逻辑类似)和阿里,都是区分 P 和 M 的,P 就是技术岗,M 就是管理岗,对于前端:</p>
<ul>
<li>P4 (初级)前端工程师,通常是校招实习生</li>
<li>P5 (中级)前端工程师,通常是毕业后工作一两年内</li>
<li>P6 (高级/资深) 前端工程师,通常是工作三五年之后</li>
<li>P7 前端技术专家,通常是工作五七年之后</li>
<li>P8 高级前端技术专家,通常是工作七/十之后</li>
<li>P9 资深前端技术专家,通常是十年靠上</li>
<li>P10 研究员</li>
</ul>
<p>目前整个前端行业内,在纯技术造诣和价值实现上,基本上 P10 是目前已知的天花板,也就是说一个前端,能做到 P10,放在整个全中国是极为稀少的,稀少到比如在阿里,晋升到 P10 的前端连 5 个都不到。</p>
<p>走向管理岗的是少部分人,通常做管理,它的起点就是 P6,P6 相当于 M1,P7 相当于 M2,以此类推,在管理岗上有前端走到了更高的层级,比如业界有些前端,自己开公司并且把公司规模做很大的,是自己当了 CEO。</p>
<p>我们讨论的范围会锁定一下,锁在 P 系列,也就是纯技术路线,放眼整个中国的前端行业,放眼看过去的 20 年,能一路晋升到 P7 的人其实相当少,也就是说,对于前端,成为专家(P7) 就是第一道天花板,很多前端写代码十多年,依然停留在 P6 的水平,十分可惜。其实对于所有前端,只要沉下心一直自我驱动学习提升,所有前端都能走到 P7 这一层级,不需要很高的智商只要是个正常前端就能走到这里,只有走的快和慢的区别而已,快则两三年内慢则十来年。</p>
<p>既然到 P7 这么难,自然再往上的 8/9/10 更难,我们把范围在锁定一下,锁定在 P4/5/6/7 这个层级上,因为到了 P7 及以上,实际上就不需要借助这篇文章的帮助了,完全有自己独立客观的判断了,但在 7 以下,对本文探讨的很多话题,很容易认知不全或者不准,那么 P4/5/6/7 这个群体,通常就是工作 10 年之内,并且从分布上看,大概率是工作在 5 年以内的居最多,那么这个群体在公司的人才结构中,处于是生长层,也就是弱管理和偏执行层居多,权限也有限,舞台也有限,但它却是公司极为重要的组成部分,因为这个群体就是任何一家公司的腿部力量,公司走的快一定是靠腿快。</p>
<p><a></a></p>
<h2>职级体系不仅仅靠技术高低</h2>
<p>那么职级体系是如何搭建起来的呢,这里面是有很大很大的学问,甚至需要借助于第三方专业的公司进驻公司帮忙搭建,我只说最简单的逻辑,任何技术团队(只要稍微大一些)都有技术排名,也就是强行排名一定排的出来谁技术好综合能力优,谁技术一般综合能力薄弱,如果把它们进行适当分层,就会形成最原始的层级梯度,比如我们如果用行业一些通用的术语来描述的话,可以这样理解,比如:</p>
<ul>
<li>有效执行:在别人一定的辅导下,被拆解的任务点可以完成</li>
<li>独立完成:在别人较少的辅导下,可以独立完成更大更独立的功能</li>
<li>独当一面:在不需要别人辅导下,能对立应对一个完整的有复杂度的项目或产品线</li>
<li>自有一套:面对更复杂的问题,可以有效识别并借助各种资源和路径将之解决</li>
<li>创造性解决:面对部门及以上更大范围内,更具挑战性的复杂问题可以创造性的解决</li>
</ul>
<p>简单根据这 5 个层次,来对应下工程师,就能分别对应到 P4/5/6/7/8,内部略模糊的层级界定后,可以跟整个业界的大参考对象对标,比如跟阿里或者腾讯对比,看有多大的差距,比如拿小菜的 P6 跟阿里的 P6 做对比,无论是招聘阿里的同学过来了小菜,还是小菜的同学跳槽去了阿里,还是借助朋友同事的关系了解更细,还是借助第三方介入,总能找到一个大致的对应关系,没有完全对应上没有关系,只要有较高的区分度就行,这个区分度是对于评委而言,让评委有区分的维度去界定。</p>
<p>如果公司要做的再细致一点,也可以把能力进行适当的分类和量化,比如分为: 技术能力、通用能力和管理能力,每个能力下还可以继续拆分,比如通用能力还可以拆为:沟通能力、客户导向、判断决策等等,在这些维度上把童鞋们对号入座,按照一定的打分规则进行量化,那么量化后再经由一定的公式(往往是业界专业公司有这套公式)进行权重分布和职级初始化,基本上就形成了实际的职级高低关系,这个关系图放到整个团队同学面前或者管理者看,跟心理的预期都不会差多少(差的特别多的个体需要进行重新调整计算),这样的话<strong>整个职级关系再应用个一两年就跑成熟了,所有的评委团专家团包括管理者都对他有更深刻的认知了,这套认知就逐步形成了这家公司相对固化下来的晋升标准</strong>。</p>
<p>当有了晋升标准后(每年也会跟进行业现状调整),晋升就成了一个工具,这个工具是为公司选拔人才,站在个人角度,是获得一个更大的授权和舞台,当然有物质的回报和精神的收获。再回到公司的视角,不让任何一个人才埋没就会成为这个工具的宿命,而定义人才,即便是在技术部,都不仅仅是纯靠技术实力高低,都是综合看的,只不过技术实力是一个很硬很硬的门槛,这个门槛不太到的话,就很难挤进去,就算到了的话,如果其他的短板太明显或者业务的结果很不好,也是很难挤进去,就算是技术和结果到了,如果这个童鞋的主观意愿度特别消极抵抗,同样很难挤进去,就算上面都满足,在评审的时候的思考层次/策略建构路径/分析解决技巧这些方面的表现不尽如人意,同样晋升会失败,所以选拔人才的初心和目标是好的,但一定会特定比例的淘汰率或者失败概率,<strong>针对没拿到机会或者闯关失败这一点大家一定要秉承健康的心态,不以一次论成败,本身公司看待员工也不会以一次论成败的,而是经历了这次失败后,要思考到底我是哪些方面还有短板,需要提升,接下来我如何提升这些选项</strong>。</p>
<p><a></a></p>
<h2>我如何提高自己的晋升概率</h2>
<p>前面写了很多过程性的思考(其实还有很多内容),我想大家最关心的还是方法论,所以我就不展开了,直接来聊作为一个 P4/5/6/7 的前端工程师,工作三五年居多的,到底如何争取提名机会,如何准备,以及执行实施,以及最终如何说服评委,本文重点聊一下如何获提名。</p>
<p>提名往往来自于主管,也就是主管顶你,那么首先也是最重要的一点,要跟主管保持一个良性的互动关系,如果你忙了 1 年,只让他了解到你做了什么,而不了解你做到了什么,怎么做的,怎么想的,解决了哪些问题,个人心态、能力有什么明显的变化等等这些,在观感上不成立的话,提名的时候自然你就不够突出。</p>
<p>但是,还有一个最基础的前提,那就是你的技术一定是有大幅度的提升,并且业务上也要有所成就(不一定要很大,但至少不能是失败),技术大幅度提升的背后不仅仅指前端技术你掌握的溜不溜,深不深,更是要看你对于技术的看法,比如它的风险、受益、给团队带来的冲击、维护的成本、社区的风向、对业务的驱动、学习的门坎等等这些,你都要有自己独立的判断,所以单纯跟主管保持良好的互动关系很重要,但如果忽略了技术成长,那一定是得不到机会。</p>
<p>再来,撇开主管的观感和你的技术成就,你的影响力是决定晋升成败的关键因素,再一次重申:<strong>千万不要以为自己技术厉害了,就一定被晋升,一旦不被晋升就骂老板和公司 SB,这种思想对个人一点帮助都没有,看到晋升二字,就一定要看到:技术实力、业务成就和个人影响力</strong>,他们三个缺一不可,技术实力只是晋升达成的必要但不充分条件,这也是为什么我认识的一些阿里童鞋一直没有想透彻的事,自以为技术牛逼走天下,却忽略了其他关键因素。</p>
<p>针对如何争取提名我们来总结一下:</p>
<ul>
<li>技术实力有大幅度的跃进(不是某个框架掌握的熟练,而是有体系化的认知和综合能力提升)</li>
<li>业务结果有长期性的产出,至少不能是过去 1 年参与的业务全部不能善终</li>
<li>个人要在团队有影响力</li>
</ul>
<p>技术和业务大家很容易懂,但影响力很容易想歪,我给大家引导一下:</p>
<p><strong>影响力有个人有集体,内部与外部,技术的和业务的,越高的层级越要有更全面的影响力,但最内核的影响力一定是包含这两个:技术的影响力和做事合作的影响力。</strong></p>
<p>技术的影响力是指你在公司的大团队内,在你这个小团队内,你利用自己的技术能力,可以驱动团队更成功,驱动别人成长更快,它的形式是各种各样的,不仅仅是分享、技术方案输出、技术思想布道、技术资源整合、技术成果应用和推广等等,如果你在这个团队里,一年到头,上面的分享/输出/推广/应用极为稀少,并且从团队所有人看过去,你并没有帮助所在技术团队走的更快更好,你关心并且只在做自己的事情,团队的事情你参与的极少(甚至团建都很少参与),那么此时你的影响力就是缺失的,是否被提名就要被打很大的问号,因为公司选拔人才一定是从组织角度出发,所谓组织就是你要跟公司尽可能多的人产生足够的关系,去影响他们,进而去影响公司的决策。</p>
<p>做事合作的影响力,更多是体现在跟业务部门等关联关系部门,合作研发时你所扮演的角色,是情绪化的对抗式的,还是有担当的主动的,是以我主导的还是以服务对象(客户)为主导的,是推动联合型的还是自我实现型的,一个个业务做下来,一个个部门合作下来,一个个人合作下来,你留给别人的印象是什么,你在这么多项目中影响到整个项目组的部分是什么,总是那个 trouble maker,还是总是那个 problem resolver,你如何定位自己,所有人都看在眼里记在心里,这个就是你在这个组织里面所能产生的影响力。</p>
<p>所以当你的技术实力到了某个层级甚至超过了一段距离,不要着急,再静心看看自己参与的业务对团队的贡献是不是也有持续性的结果达成,再看看自己的技术影响力和做事合作的影响力,帮助团队帮助他人更成功的部分,是不是还非常欠缺,如果非常欠缺可以开始动起来,因为你距离晋升并不遥远了。</p>
<p>关于技术和综合实力提升,之前写过一篇 <a href="https://link.segmentfault.com/?enc=iYR0r7mqJ26gfuh75ji0Og%3D%3D.gOGcFtEatfEPMCUSvU48V33528uGRGvnQpA%2F%2FZYSPqXEnHNzBnA5HalD1oHq7rsh" rel="nofollow">前端开发已经进入深水区</a>,里面会有更多软硬实力的讲述,大家有兴趣可以去了解下,本文限于篇幅不再讨论,只贴下硬软实力的截图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567752752293-08919d5b-7f65-43fa-af3d-137b68b1dbc3.png#align=left&display=inline&height=421&name=image.png&originHeight=1032&originWidth=1828&size=619426&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567752779755-7e4a16c9-68b1-4970-8c2c-44f07a5b53df.png#align=left&display=inline&height=420&name=image.png&originHeight=1032&originWidth=1832&size=653133&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>关于晋升逻辑的一点点总结</h2>
<p>当我们是一名骄傲的工程师的时候,我们同时是一个成熟的社会人,不同的工种有不同的上升通道,而工程师的通道里,除了管理、转行、自由职业和创业等,就剩下技术成长和自我成就这一条路,这条路通常是在某几家公司的某几个团队里,走过了技术储备早期的四五年,这条路坎坷但也足够透明,坎坷是因为技术路漫漫要坐冷板凳,软实力短板还得不到晋升,透明是因为打怪升级就这么几个档位,路径和方法都很成熟,我们只需要自律并且热情的执行下去。</p>
<p>当我们越来越心智成熟,就会了解到技术的魅力,并不会随着岁月和生活的打击而变得暗淡,同样职业的精彩,也确确实实需要我们保持内心的修炼和与他人合作共赢的一路同行,一行行代码写过去,一个个项目做出来,一年年岁月流逝掉,我们所收获的一定有内心对技术的热忱和深刻的认识,但除此之外,我们还可以有更多其他方位的尝试和突破,而晋升,就是这样横躺在职业生涯路上的,一个个检验你阶段性能力和成果的机会,心态上不需要每天都把它挂在嘴上,但也不要一直不放心上,而是大大方方的看到它的背后,其实是一场成长的考试,这次考试可以帮我更认清自己,更知道接下来如何提升,对它既不看轻也不看重,毕竟核心功夫在平时,而答卷只在交卷后。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=RqaO7V40c6bfS35g3FRoLQ%3D%3D.baWaKGSym%2FQlFcthjEVLL7rMqOQJyvk6MxHwCvO8%2FTY%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术探索:60 天急速自研-搭建前端埋点监控系统
https://segmentfault.com/a/1190000022295168
2020-04-17T23:00:00+08:00
2020-04-17T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
12
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>决策源于数据,而数据源于采集,采集源于规则梳理,让这一切发生源于工程师的创造力和执行力,本文 5000 字,偏科普向,技术深度一般,阅读约 10 分钟,可以先 Mark 后看,文章架构细节图(含最新备注)可以找 Scott 索取(微信: codingdream)。</p>
</blockquote>
<p>背景:小菜从 2014 年第一款 APP 上线,到如今将近 5 年,5 年风雨 5 年征程,虽然技术部有 80 人,前端有 20 人,我们依然对自己所研发的 8 款 APP、4 款小程序、6 款 H5 商城系统、10+ 个 PC CRM/IM/ERP/TMS 中台运营系统的用户使用情况、线上异常情况、设备分布情况、营销活动的 PV/UV 转化情况统统一无所知,<strong>因为看不见就不清楚现场,这种做法显然很不互联网,也很不符合小菜前端 “工具为王效率至上” 的技术价值观</strong>。</p>
<p>历史问题和痛点:</p>
<blockquote><ol>
<li>
<p>toB 产品的多端数据未搜集,toC 的产品亦然</p>
<ul><li>如同一个业务的 RN APP/PC Web(React 单页/多页应用)/H5/小程序跨端产品</li></ul>
</li>
<li>
<p>数据埋点散落未做定义及归类</p>
<ul><li>如阿里有位置跟踪 SPM、资源位跟踪 SCM、曝光和交互的黄金令牌,我们统统没有</li></ul>
</li>
<li>
<p>用户的线上访问异常(B 端用户,可用性稳定性是刚需)无从跟踪</p>
<ul><li>如整个质量体系监控没有抓手,前端报错后端报错,全靠经验、人肉日志和用户主动反馈</li></ul>
</li>
<li>
<p>用户的访问行为/设备特征/应用性能信息完全无感知</p>
<ul><li>如活跃时间点(避开做发布),软硬件系统和设备比例(做兼容),慢页面优化等无从做起</li></ul>
</li>
<li>
<p>业务数据的效果无从跟踪</p>
<ul><li>如营销活动转化效果、支付链路的耗时等都很难服务业务决策</li></ul>
</li>
</ol></blockquote>
<p>其实痛点还太多太多,为了不让自己变成瞎子,我们决定无论是借助社区方案,还是付费,还是自研,一定要做出一套前端产品埋点监控的工具产品出来,这几年,我们也做过一点尝试,总共走过了 3 段历程:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569404609561-f03f5f63-a9e5-49f9-8a2e-d949f278d99a.png#align=left&display=inline&height=313&name=image.png&originHeight=938&originWidth=2690&search=&size=469561&status=done&width=896.6666666666666#align=left&display=inline&height=938&originHeight=938&originWidth=2690&status=done&style=none&width=2690" alt="image.png" title="image.png"></p>
<p>直到今年,我们最终选择社区开源方案 + 完全自研,也就是阶段三,几乎不再用任何付费产品,投入了 1 个前端全力攻坚,整个项目从立项到落地,差不多用了 60 人日。</p>
<p>另外,本文所介绍的整个监控系统属于小菜前端质量评估与跟踪体系中的一环,至于端质量体系策划了两篇,还没动笔写:</p>
<ul>
<li>上篇 - 如何从 0 到 1 搭建前端质量跟踪平台(上)</li>
<li>下篇 - 如何从 0 到 1 搭建前端质量跟踪平台(下)</li>
</ul>
<p>大家可以 <strong><a href="https://link.segmentfault.com/?enc=3yUcEBloo09u3%2BQVymVW5Q%3D%3D.dDqAdeWKIsUPwDVmCU%2BtMZIx6Gh4zemwc23E6WB2Wpg%3D" rel="nofollow">关注我的语雀账号</a> </strong>来跟进这两篇的写作动态,本文我们不做质量体系的探讨,只聚焦在监控跟踪实现。</p>
<p><a></a></p>
<h2>监控系统肚子里有哪些东东</h2>
<p>为了让大家更直观的感受到底我们做了什么,做了多少,也便于大家理解后面更技术性的一些选型判断,先放我们的数据流向图、产品功能图和系统架构图出来,形成第一观感及疑问。</p>
<p>数据从用户访问页面那一刻开始,到基于这些数据做出必要的决策结束,整个数据流进来一步步处理掉,可以分为 采集、转发、解密、持久化和处理这几个核心流程:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569228028634-d2e63139-99ef-4a56-b142-d318862d2648.png#align=left&display=inline&height=285&name=image.png&originHeight=854&originWidth=2840&search=&size=211943&status=done&width=946.6666666666666#align=left&display=inline&height=854&originHeight=854&originWidth=2840&status=done&style=none&width=2840" alt="image.png" title="image.png"></p>
<p>而整个监控跟踪,从采集到跟踪,从产品的视角,可以拆分出来如下几个功能模块:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569229698638-b1469108-1387-4c6a-9cac-c796c6f5c76e.png#align=left&display=inline&height=340&name=image.png&originHeight=1020&originWidth=3186&search=&size=301855&status=done&width=1062#align=left&display=inline&height=1020&originHeight=1020&originWidth=3186&status=done&style=none&width=3186" alt="image.png" title="image.png"></p>
<p>从实现层面,数据一层层进来,每一层的任务都有对应系统接管处理,整个监控跟踪的技术架构图如下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569397719356-61d5feee-a63b-490e-a5ac-6bf875a0e07e.png#align=left&display=inline&height=399&name=image.png&originHeight=1198&originWidth=2860&search=&size=477192&status=done&width=953.3333333333334#align=left&display=inline&height=1198&originHeight=1198&originWidth=2860&status=done&style=none&width=2860" alt="image.png" title="image.png"></p>
<p>从核心系统/模块组成上,可以简单分如下几个:</p>
<ul>
<li>采集 SDK 的设计与实现(PC/H5/小程序/RN/NodeJs)</li>
<li>数据转发器 DataTransfer 设计实现</li>
<li>监控后台 Dashboard 前后端设计实现</li>
<li>任务控制器 Controller 设计实现</li>
<li>任务执行器 Instpector 设计实现</li>
</ul>
<p>限于篇幅,我们只针对每个系统的设计做介绍,不涉及技术细节,大家想要了解更详细的信息,或者要更详细的高清架构图,<strong>可以加我微信索取: codingdream</strong>。</p>
<p>图上用到了很多名词,大家可以搜索下做些越热,我先尝试用大白话简述下它们关系,然后我们就开始进入系统介绍,内部的关系是:</p>
<ol>
<li><strong>数据流:数据从页面上搜集上来后,经由 Nginx 给到了一个数据转发服务器,它无脑的把一行行访问日志丢给 Kafka 这个消息转发中心,经由它交给专门处理日志的 ELK 套件,然后 ELK 这个套件提供了很多查询日志的能力,这些能力进一步按照规则被下沉到数据仓库,数据仓库再经由 SQL-Table-Charts 的报表生产和展现工具,通过报表平台给到产品业务同学使用。</strong></li>
<li>数据管理:除此之外,面向开发者应该有一个监控管理后台,实时从 ES 查数据展现数据,以及基于异常数据做一些任务的生成,而这些业务逻辑都是管理后台,透过 Kafka 来通知到任务控制器完成的,任务控制器做一些更纯粹的任务管理,它把一些更细节的执行透过 Kafka 来通知到执行器干活,任务的回写之类的事情自己做掉。</li>
<li>数据持久化:所有的日志都存在 ES 里面,所有的 issue 都存在 MySQL 里面,而对 issue 的跟踪管理则以任务栈的形式存在了 Redis 里面,同时所有的按照规则梳理的数据,都下沉到了数据仓库最后透出到报表平台。</li>
</ol>
<p><a></a></p>
<h2>客户端 SDK</h2>
<p>数据源于采集,而采集源于需求梳理和规则梳理,也就是为了达到某某某的目的,而必须采集到端上什么样的数据,以 PC/H5 为例,希望采集的数据有如下几大类:</p>
<ul>
<li>
<p>用户数据</p>
<ul><li>如匿名/非匿名的用户 ID、IP 等基本信息</li></ul>
</li>
<li>
<p>设备信息</p>
<ul>
<li>如操作系统类型和版本</li>
<li>如浏览器类型和版本</li>
<li>如 App 版本号等</li>
</ul>
</li>
<li>
<p>行为数据</p>
<ul>
<li>如用户访问来源</li>
<li>如用户访问路径</li>
<li>用户点击滑动区域等</li>
</ul>
</li>
<li>
<p>性能数据</p>
<ul><li>如脚本加载时间、接口响应时间等</li></ul>
</li>
<li>
<p>异常数据</p>
<ul>
<li>如前端脚本加载错误、脚本运行错误</li>
<li>如后端 API 请求超时、返回数据异常、参数交互错误等</li>
</ul>
</li>
<li>
<p>定制数据</p>
<ul><li>如活动页面特殊区块访问数据、表单提交数据、邀请来源等</li></ul>
</li>
</ul>
<p>对这些数据需求做整理,映射到浏览器宿主环境下,就需要实现如下一些功能:</p>
<ul>
<li>API 请求监控</li>
<li>Log 面包屑</li>
<li>性能上报</li>
<li>自定义事件上报</li>
<li>SPA/MPA 路由/页面切换记录数据上报</li>
<li>Error 监控(onerror/onunhandledrejection)</li>
<li>UI 事件上报(可手动开启,用于错误回溯以及页面热力图)</li>
</ul>
<p>技术没什么难点,主要是对浏览器的特定事件( onerror 、onunhandledrejection、onpopstate 等)进行监听以及以 AOP 的方式进行包装一些全局对象的某些特定函数(如 XHR 的 <code>send</code> ),在不影响开发者的情况下采集必要的数据。</p>
<p>这个过程中我们应该注意的是,在对函数或对象进行 wrap 的时候,一定要避免重复包装,真正花时间的是兼容性的调试,特别是在移动端会遇到一些难点,比如 iOS 设备频繁发生的 <code>script error</code> 、指纹丢失、iOS 的 <code>sendBeacon</code> 上报到达率低一些问题。</p>
<p>因为要集中管理多个端的 SDK,我们在搭建这个 SDK 工程时,使用了 monorepo 的方式,TypeScript 实现代码,部分 SDK 使用 rollup + tsc 打包。</p>
<p><a></a></p>
<h2>数据转发器 DataTransfer</h2>
<p><a></a></p>
<h4>模块关系图</h4>
<p>数据从客户端采集到后,按照一定的策略上报到服务器,先经由 Nginx 拿到 IP 等信息后,直接交由 Transfer,然后将数据发送给 Kafka,让 Kafka 把数据同步给 ELK。下图是 DataTransfer 在整个架构中与其他组件的关系:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569399308125-81a1589f-f332-42ab-a6bb-eab3849242a4.png#align=left&display=inline&height=207&name=image.png&originHeight=622&originWidth=2184&search=&size=214665&status=done&width=728#align=left&display=inline&height=622&originHeight=622&originWidth=2184&status=done&style=none&width=2184" alt="image.png" title="image.png"><br><a></a></p>
<h4>模块的作用</h4>
<p>这里的数据转发器,就是一个 Node 服务,它扮演数据搬运工的角色,将数据转发给 Kafka 集群,同时它也做了一些额外的事情,比如数据的解密和验证,添加额外的必要字段等。</p>
<p><a></a></p>
<h4>模块实现方式</h4>
<p>针对 Kafka 我们做了降级方案,当转发到 Kafka 失败的时候,就将数据写到本地的日志,然后用 Filebeat 发送给 Logstash,为什么做降级呢,因为我们自建的 ES 和 Kakfa 正在经历阿里云 VPS 从经典到私有网络的切换,过渡期的几个月不稳定,我们这里就用了两条腿,优先发送给 Kafka,当 Kafka 不稳定的时候,就由 Filebeat 接管,再推送给 Logstash,每一台 transfer 上都对应一个 Filebeat 备胎,属于是过渡性方案。</p>
<p>其实这里的 Nginx + Transfer 用 Openresty 会更合适,性能也不错,我们之所以没采用,是因为整套设施是前端自行搭建和维护的,用 Eggjs 搭建的 Transfer 服务,不想引入额外的语言栈加大后期的维护成本,就用了 Nginx + Node Transfer(Filebeat)。</p>
<p>至于工程的实现,我们依然使用了 TS,服务框架用的是 Eggjs,针对 Eggjs 写了一个 egg-kafka 插件用于 kafka 的消息收发,该插件也算是此次项目的收获之一。</p>
<p><a></a></p>
<h2>监控后台 Dashboard 前后端</h2>
<p><a></a></p>
<h4>模块关系图</h4>
<p>数据如果没有介入到团队的决策,那就失去了搜集的价值,既然是决策,无非就是信息的聚合展示以及各种任务的增删改查,而这个角色就有监控后台 Dashboard 承担。</p>
<p>Dashboard 在整体架构中与其他模块的关系如图所示:<br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569400766935-c5ac9fe1-74c2-4ad9-a67b-b1299f9412e7.png#align=left&display=inline&height=239&name=image.png&originHeight=718&originWidth=1608&search=&size=125122&status=done&width=536#align=left&display=inline&height=718&originHeight=718&originWidth=1608&status=done&style=none&width=1608" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h4>为什么不用 Kibana</h4>
<p>ELK 三大件中最好用的莫过于是 Kibana,为什么我们不用呢,其实我们也不是不用,而是给到部分小场景去灵活使用,之所以没有完全使用,是因为我们希望跟前端团队有更强的关联性,比如用户身份、issue 的推进、任务的跟踪、未来代码仓库分支的异常关联、质量报告的评估等等,这些业务属性太强,而 Kibana 显然不便于我们做很灵活的扩展,所以就没有以它作为 Dashboard。</p>
<p><a></a></p>
<h4>Dashborad 的数据来源</h4>
<p>Dashboard 的数据来源主要有两个,ES 和 阿里云的 RDS(MySQL)。</p>
<p><a></a></p>
<h4>Elasticsearch 日志查询</h4>
<p>ES 扮演的就是日志数据库的角色,他提供查询的能力,而 Dashboard 就是无脑的从 ES 获取实时数据,比如刚刚 15 分钟的异常数量,或者今天到目前为止某个应用的 PU/V ,访问的设备类型分布等等,如下图,某个应用大盘的数据:<br><img src="https://cdn.nlark.com/yuque/0/2019/png/88660/1569502733300-509a45a9-04e9-43b4-92c0-336fef67175b.png#align=left&display=inline&height=459&name=68DE6BAF-7385-4B31-B20B-86515181C3A5.png&originHeight=459&originWidth=1348&search=&size=190912&status=done&width=1348#align=left&display=inline&height=459&originHeight=459&originWidth=1348&status=done&style=none&width=1348" alt="68DE6BAF-7385-4B31-B20B-86515181C3A5.png" title="68DE6BAF-7385-4B31-B20B-86515181C3A5.png"></p>
<p>或者该应用异常发生情况:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569381925879-ebc3f1a0-44d9-40b0-aec6-77aade268315.png#align=left&display=inline&height=311&name=image.png&originHeight=934&originWidth=3208&search=&size=211204&status=done&width=1069.3333333333333#align=left&display=inline&height=934&originHeight=934&originWidth=3208&status=done&style=none&width=3208" alt="image.png" title="image.png"></p>
<blockquote>每一个特定的异常,我们可以点击详情查看相应的异常详情,跟踪到用户的 ID、设备及厂商、浏览器版本、页面、发生时间、IP、地理位置甚至角色身份等更细节的数据信息,再结合异常的回溯重放和 Sourcemap,便于我们第一时间跟进了解和修复。</blockquote>
<p>甚至 API 请求出错的情况也能查看:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569382291658-21bdda5f-432e-44e5-a521-f3a1504782ee.png#align=left&display=inline&height=301&name=image.png&originHeight=904&originWidth=3206&search=&size=216253&status=done&width=1068.6666666666667#align=left&display=inline&height=904&originHeight=904&originWidth=3206&status=done&style=none&width=3206" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h4>MySQL 持久化业务数据</h4>
<blockquote>MySQL 中存储的数据是我们通过下节会讲到的 Controller 对存储在 ES 中的错误原始数据进行分类和抽象而得到 issue 信息、以及开发者为了监控某个特殊 issue 而制定的规则和相应的任务信息,</blockquote>
<p><a></a></p>
<h5>下图便是我们抽象出来的 issue :</h5>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569383143024-84e89364-6552-4831-898e-a04619e33726.png#align=left&display=inline&height=375&name=image.png&originHeight=1124&originWidth=3292&search=&size=279996&status=done&width=1097.3333333333333#align=left&display=inline&height=1124&originHeight=1124&originWidth=3292&status=done&style=none&width=3292" alt="image.png" title="image.png"></p>
<p>针对每个 issue ,无论是前端还是后端,到底哪些被跟进修复了,修复情况如何,都可以跟踪到:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/88660/1569510182132-e0d0a7d2-417d-45ea-bd3e-02997c76cc51.png#align=left&display=inline&height=1674&name=7B50AFD8-0166-4D90-9E6B-817BC7D5454E.png&originHeight=1674&originWidth=2814&search=&size=622939&status=done&width=2814#align=left&display=inline&height=1674&originHeight=1674&originWidth=2814&status=done&style=none&width=2814" alt="7B50AFD8-0166-4D90-9E6B-817BC7D5454E.png" title="7B50AFD8-0166-4D90-9E6B-817BC7D5454E.png"></p>
<p>同时,针对用户的某一次的一系列动作我们会有一个 session 的概念,上报数据时会生成一个 sessionId 然后透出到 issue 详情中,便于开发者在解决错误时查看用户具体操作了什么,然后能更好地解决问题:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/88660/1569510604745-9e58c34e-bbd6-4530-8c1c-9397d00af9e5.png#align=left&display=inline&height=313&name=B51E9943-CB45-4D52-B684-96F0484229BB.png&originHeight=1252&originWidth=928&search=&size=191153&status=done&width=232#align=left&display=inline&height=1252&originHeight=1252&originWidth=928&status=done&style=none&width=928" alt="B51E9943-CB45-4D52-B684-96F0484229BB.png" title="B51E9943-CB45-4D52-B684-96F0484229BB.png"></p>
<blockquote>目前这个页面还做得比较粗糙,毕竟没有专门设计师</blockquote>
<p>issue 的大致生命周期如下,其中大多数状态变更的操作是开发者在 dashboard 上实现的:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569403158964-359ce1ec-09f3-476d-b832-a673955fd5b5.png#align=left&display=inline&height=189&name=image.png&originHeight=568&originWidth=2112&search=&size=93060&status=done&width=704#align=left&display=inline&height=568&originHeight=568&originWidth=2112&status=done&style=none&width=2112" alt="image.png" title="image.png"></p>
<p>前端和后端结合起来联动查看,可以更快速的解决问题,再配合上异常的识别和判定机制,可以更主动的把异常推到前端和后端的钉钉群里,甚至复发的问题会 @ 当事人,关于 issue 的判定我们放到后面再来讲:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569382874278-3051f138-3646-44b1-8f39-9a6a42b77139.png#align=left&display=inline&height=477&name=image.png&originHeight=1536&originWidth=1112&search=&size=773694&status=done&width=345#align=left&display=inline&height=1536&originHeight=1536&originWidth=1112&status=done&style=none&width=1112" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h4>报警任务信息的生成</h4>
<p>当开发者需要对某个 issue 特别 "关照" 时,可以针对该 issue 设置相应的报警规则,下文提到的 controller 会根据报警规则生成报警任务,下图就是一个简单的报警任务:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/88660/1569487275346-658c5fda-1934-4d8f-87b6-996be4c88af0.png#align=left&display=inline&height=309&name=B91E0611-05DC-4E33-ABD4-DEC212BB976B.png&originHeight=1234&originWidth=2724&search=&size=279747&status=done&width=681#align=left&display=inline&height=1234&originHeight=1234&originWidth=2724&status=done&style=none&width=2724" alt="B91E0611-05DC-4E33-ABD4-DEC212BB976B.png" title="B91E0611-05DC-4E33-ABD4-DEC212BB976B.png"></p>
<p>我们还能看到该任务的执行情况:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/88660/1569487503652-a7938a0c-37f3-4ba2-8cc8-c63efa00545f.png#align=left&display=inline&height=132&name=0170EB90-CFD6-4F77-B6F9-7EC5D45BDA4D.png&originHeight=132&originWidth=2826&search=&size=125519&status=done&width=2826#align=left&display=inline&height=132&originHeight=132&originWidth=2826&status=done&style=none&width=2826" alt="0170EB90-CFD6-4F77-B6F9-7EC5D45BDA4D.png" title="0170EB90-CFD6-4F77-B6F9-7EC5D45BDA4D.png"></p>
<p>后台还有很多其他实用的功能,比如 issue 查看分配指派与分类、更新流水、报警任务查看编辑、错误信息回溯、各种质量周报的生成推送等,更多截图在文后。</p>
<p><a></a></p>
<h4>DashBoard 的技术实现</h4>
<p>技术实现上,后端我们使用的是基于 Eggjs 封装的 Cross 搭建的工程,集成了 Kafka 和钉钉等,其中 kafka 用于和其他模块交流;前端则使用了 AntDesign Pro(umijs/dva/bizcharts),这次考虑到是功能多变且业务性强,就没有使用 TS。</p>
<p><a></a></p>
<h2>控制器 Controller</h2>
<p><a></a></p>
<h4>模块关系图</h4>
<p>前面提到的 Dashboard 最大的作用是消费、修改以及管理 issue 数据,而从原始数据中抽象出 issue 数据给 dashboard 消费的则是 controller,当然,controller 的作用不止于此,我们会在下面展开来说,这里先贴出其在整个架构中的与其他模块的关系图,让大家对其在整个架构中的角色有一个大致的认识:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569402119241-532d1ce4-5402-414d-a0aa-c6c664a59e4b.png#align=left&display=inline&height=195&name=image.png&originHeight=586&originWidth=1862&search=&size=153099&status=done&width=620.6666666666666#align=left&display=inline&height=586&originHeight=586&originWidth=1862&status=done&style=none&width=1862" alt="image.png" title="image.png"><br><a></a></p>
<h4>控制器的作用</h4>
<p>Controller 在整个架构中的作用至关重要,主要体现在以下几个方面:</p>
<ul>
<li>线上 bug 发现,新 issue 的生成、分类和发送警告</li>
<li>某一个 bug 在某个时间段内发生次数过多(如 100次/1m )的警告</li>
<li>某一个已经标记为已解决的 issue 又再次发生,需要通知到相关 issue 的负责人</li>
<li>bug 报告生成,这样就能让开发负责人们对端质量上有一个更量化认识</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569391123322-b9bb3970-768e-424b-9658-2159732d49d7.png#align=left&display=inline&height=384&name=image.png&originHeight=1152&originWidth=3280&search=&size=259944&status=done&width=1093.3333333333333#align=left&display=inline&height=1152&originHeight=1152&originWidth=3280&status=done&style=none&width=3280" alt="image.png" title="image.png"></p>
<ul><li>用户针对特殊 issue 设置的报警任务的分配,以及报警任务执行完成后的结果分析等,但是 controller 并不会执行任务,它只负责通过 Kafka 发送消息分配任务给下面将要提到的任务执行器 inspector(s) 们</li></ul>
<p><a></a></p>
<h4>控制器的技术实现</h4>
<p>任务控制器是一个纯后端项目,它依然通过 kafka 与其他模块进行交流,因为其功能比较明确所以我们采用 TypeScript 编写,后端框架依然是我们团队基于 Eggjs 自研的 Cross。而报警任务队列是通过 redis 实现的。</p>
<p><a></a></p>
<h2>任务执行器 Instpector</h2>
<p><a></a></p>
<h4>执行器的作用</h4>
<p>作为任务控制器的小弟,任务执行器 Instpector 做的事情就很纯粹,就是解析从 controller 发送过来的任务,然后对原始进行查询最后返回结果,但是考虑到任务可能会比较多,我们在设计时是将其设计为多点的,利用 kafka 的消息单播的特点,尽可能让任务尽快地执行。</p>
<p><a></a></p>
<h4>执行器的实现</h4>
<p>实现执行器也是用 TS 开发,框架为 Eggjs, 比较简单。</p>
<p><a></a></p>
<h2>梭哈监控后的心得</h2>
<p>这个系统的建设并不是一蹴而就的,我们在过去两年使用过不少社区现有的产品,也自研过不完善的方案,从中积累了不少经验,没有这些沉淀,我们也没办法做出现在的这个系统。</p>
<p>整个系统麻烦在于设计而不是实现,大家动手之前,可以先考虑清楚自己的应用场景,期望解决的问题是什么,也就是弄清楚 What 和 Why,之后再考虑是否投入人力进行设计和实现,毕竟整个系统建设下来,还是需要一定的技术实力和不少人力的。</p>
<p>截至目前,这个系统并非达到最理想的状态:</p>
<ul>
<li>比如 Dashboard 和 Controller 中都会对 MySQL 和 ES 做相似的某些操作,其实是可以将其抽象成两个特定的服务</li>
<li>比如我们目前还没做到针对页面加载时间过长的报警</li>
<li>比如我们还没有做到将所有问题分类型的解决方案汇聚成 "bug 解决方式百科全书",也就是异常 Wiki 化</li>
<li>比如我们还没有做到将平台的 issue 与我们的代码仓库绑定,然后解决 issue 实现自动化关闭等等,也就是异常与仓库代码分支的联动,自然也就做不到更有参考价值的工程师代码质量的评估</li>
</ul>
<p>但即便如此,上线这 3 个月以来,我们能看到端产品上的行为数据和异常情况了,对产品体验的提升或者下降更有感知,对问题的跟踪修复也更有效率了,用户对于产品的负面反馈也在一天天的减少,我想,这也算是一个不错的开始吧。</p>
<p>再补两张 DashBoard 截图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569404248758-f00dc6f4-9f34-4811-9d3d-c08238573253.png#align=left&display=inline&height=307&name=image.png&originHeight=920&originWidth=3042&search=&size=309095&status=done&width=1014#align=left&display=inline&height=920&originHeight=920&originWidth=3042&status=done&style=none&width=3042" alt="image.png" title="image.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1569555088674-fadf0134-1777-40ea-8b0e-dc8fd87ab088.png#align=left&display=inline&height=314&name=image.png&originHeight=942&originWidth=2714&size=445343&status=done&style=none&width=904.6666666666666" alt="image.png" title="image.png"></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=V%2BVEkpn6rBCPhZQ5a2nHLQ%3D%3D.VGZDb8JtOXalV8nLi%2BRDDSTHva3ad57vxMbrKZYR8rU%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
职业思考:技术人需要突破的 10 个困局
https://segmentfault.com/a/1190000022295021
2020-04-16T23:00:00+08:00
2020-04-16T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>为什么社交有时候那么累,是因为每个人都试图施展自己并不具备的能力,为什么你对他人有时候期望很少要求很低,是因为潜在深处你也希望别人对自己也要求低一些,以妥协换满足。</p>
</blockquote>
<p>2010 年工作,2013 年初涉创业,至今 9 年,无论是创业还是在职场都趟了不少弯路,前两周对团队做技术管理者套路内训时,把过去的收获整理成这 10 句话,放到了 PPT 最后一页作为结语,感觉过于简练了,打算再做一个更准确的阐述。</p>
<p>这些观点就是下面图上的几句话,分别是:</p>
<ul>
<li>正视自己内心,对应困局是在工作和人生历程中,总是初心不见,迷茫踌躇,找不到努力的方向</li>
<li>接受人无完人,对应困局是看自己看他人看他事总是不尽如人意,总被不满意不满足的情绪掌控</li>
<li>对抗框式思维,对应困境是分析问题总偏离本源,评估问题过于机械过于直觉,缺少换位和结构化思考</li>
<li>理解人性复杂,对应困局是不懂人间冷暖炎凉与险恶,期望总面临失望,因果关系看不懂看不清</li>
<li>明白商业多变,对应困局是对于既有组织关系和业务模式的变化很难理解,推导链很难建立,不愿执行</li>
<li>逼自己拼大盘,对应困局是对复杂问题如业务盘子缺少感知,无法准确定位自己的角色和未来价值</li>
<li>敢对抗不合理,对应困局是缺少勇气挑战权威,遇到问题总是找借口妥协,慢慢激情消逝,趋于麻木</li>
<li>去创造危机感,对应困局是安适惬意对当下的一切没有太多不满意,对可预见的变化也缺少期待</li>
<li>画大饼算大帐,对应困局是定目标和宣导目标对自己及身边团队影响力有限,无法说服更多人认同并加入</li>
<li>布局未来十年,对应困局是时间过得搜搜快,行业洗牌一波波,自己辛辛苦苦忙忙碌碌却鲜有收获</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563872511339-6e8936b2-0402-4a6e-b0d3-3140c5e03f80.png#align=left&display=inline&height=296&name=image.png&originHeight=764&originWidth=1314&size=317163&status=done&style=none&width=509" alt="image.png" title="image.png"></p>
<p>环境对一个人的塑造是无比深刻的,环境不同塑造的结果差异很大,而组成环境的一个重要因素便是人,你身边的人对你的影响千丝万缕,我们必须看到总是有极少数的人,完全可以独立的思考,可以长远的思考,对环境有很强的把控力,对当下环境的审时度势和自我规划是超强的,这些人往往是我们可望不可及的榜样,而我们大部分人都是蛮普通的,我们努力很久只是让自己变得更加优秀,却很难卓越。</p>
<p>我们先不谈卓越,单从普通到优秀,也有很长的一段路走,在这段路上,我的个人经验是,如果有高人指点、前人指导甚至是贵人指点,都能对你的人生路产生非常深刻的影响,甚至直接切换到一个新的路线上,我在工作的头两年确确实实经历过贵人的指点,其实前后也不过 3 次,但每一次都对我的思考方式是一次完全的刷新,每次都对我重新规划未来起了关键性的作用,自此之后的 6 年之久,我再没有遇到这样的高人,全靠自己摸索,摸了这些年,也算是有一些经验性的方法,这些方法我自认为对于工程师是比较适用的,尤其对于技术管理者是适用的,那接下来我会结合自己的案例,来跟大家做一个更深度的探讨:</p>
<p><a></a></p>
<h2>正视自己内心</h2>
<p>与自己对话是一种能力,你可以问下自己:我有多久没有静静的坐下来,花上 2 个小时,跟自己好好对话了,问问自己最近过的怎么样,距离目标还有多远,过的开心么,有什么收获么,目前的工作和生活是我想要的么,如果不是想要的为什么我没有做出改变,如果是暂时性妥协我想要妥协多久,如果设定个倒计时我会具体到多久,从倒计时倒退到现在我必须要做什么,假如届时我都做到了也改变了,改变后的生活和工作我会怎么过,那样过了是不是我内心就是开心的了....</p>
<p>:::info<br>我工作的第三年,因为薪资和晋升的原因,内心每天非常煎熬,在工作上虽然踏实沉稳全力以赴,但我的意志却被极度的压抑,那时候一年过半时间都在失眠,每天跟自己的负面声音做战斗:既然 hr 卡你,团队也没有给你争取,不如一走了事,既然做这些重复性工作没什么成长,不如一走了事,既然每天这么不开心,不如一走了事,既然业务方和产品经常瞎搞,不如应付了事....<br>:::</p>
<p>我自己的前途,被押注在了我懊恼的情绪上了,而我情绪的产生,是因为我不能正确的认识到自己,也无法正面正视自己内心,单纯从处境上得结论,而得出的结论对前途的进程没有丝毫的正面作用。我从来没有想过为什么我会不开心,真正的原因是回报和付出不成正比么,其实并不是,而是我的焦躁感,焦躁感来源于哪里呢,是我忘记了自己真正想要什么,我以为我要的是晋升是回报,不否认这是我想要的,但我更想要的其实是技术的精进和能力的提升,以及对于产品更强的认知,而技术的精进、能力的提升和产品更强的认知这三样,并不是工作中不能获得的啊,无论我是否在工作中,无论工作是怎样的形态,当我的注意力放到了这三件事上,我照样可以不断自驱来提高技术,来锻炼能力和学习产品啊,而我如果继续扎实内心在这三件事上,晋升和回报也就自然距离不远了啊,就算晚能晚多少呢,一年两年最多了,但是我眼光放不长远了,内心深处也迷失了,于是越陷越深,最终还是从阿里离职出来创业。</p>
<p>在今天往回看,创业这个路始终是我想要的,对创业我懊恼但不曾后悔过,但技术有成、能力成熟和产品观变强这本就是我当初训练自己为创业做的准备啊,可是我被当时的环境羁绊了,导致并没有把这三个能力打磨的像个样子,就过早的离职出来创业,也草草的堵上后面的三四年,最终以另外一种悲壮的方式收场,用新的一种弯路,来对抗当初的不甘,这就是典型的不清楚自己几斤几两,也不敢正面面对内心的期望,只能以逃避换自安自得,不可取,如果自己不够强大,再怎么挪窝也很难有质的改变。</p>
<p>而很多时候,看不到内心是因为不敢正面内心,不敢正面内心是不愿意正视真相,因为真相太残酷:你现在太不上进,太懒惰,太拖延,太看重一时回报而看不远,被现实浮华糊住了双眼,你甚至不敢主动迈出脚步争取改变,去好好沉淀。可是又有谁愿意主动承认这些呢,于是选择视而不见甚至听而不闻,继续在弯路上走一遭又一遭。</p>
<p><a></a></p>
<h2>接受人无完人</h2>
<p>我们通常不容易跟完全对立的人达成和解,我们跟自己也同样很难达成和解,很多时候只是达到了和平状态而已,而和平只是一种利我利他的状态,它的底下可能是压抑和对抗,可能依然波涛汹涌。</p>
<p>身处一个团队中,上下左右都是同事,工作配合上不可能像是流水线的机器一样,没有丝毫出错,而我们又是一个个的人组成了公司这部复杂庞大的机器,任何螺丝都会松动出现纰漏,纰漏的背后不排除别有用心,但更多是疏忽不小心或者能力不够,这时候我们是严苛一个人的前提是,要知道他本不完美,满足期望和超出期望都是比较美好的结果,不尽如人意的状况反而会时有发生,这就需要从内心中接纳这种现实,同时从组织手段、考核方式、流程规范和沟通中去避免下一次的问题重犯。</p>
<p>这件事情看上去很容易,实际上蛮难,因为我们都假设了自己的立场,以为对方会全力配合,对方完全可以领悟到且有足够能力,最终以失望收场,比如团队里师兄带新人,新人一而再再而三的让师兄失望,师兄一气之下就对他恶言相向,或者对他冷处理不那么热心的帮忙,对新人的成长和团队融入都是未必有利的。再或者对于一个纯实力派的管理者,对于团队成员的期望是很高的,稍有差池就恨不得自己动手去做,这样长久看是不利于团队的健康成长,也不利于帮带环境的逐渐形成。</p>
<p>聊了团队,我想再聊聊对自己的包容,我们对自己苛刻都是个人选择,但苛刻的背后是需要具体行动的,通过行动和行动后的复盘思考来不断优化下一次行动,可有时候我们会在行动结果上一再的纠结,却忽略掉真正需要花精力的地方,而此时我们没有意识到是自己的能力和状态都不够 Ready,自己所经历的这些只是过程,而过程中自己是一次次变得更好但不可能至善至美,尤其我们在做重要的事情的时候,一定要在事后给与自己合理的谅解,不然这份执念会一直干扰将来的行动。</p>
<p>:::info<br>我在创业的中期,是犯了这样一个错误,招了一个还不错的前端,但我对他的期望与他的表现是有一定差距,可是这个差距我无法接受,于是一开始总是忍不住自己动手去做,到后来会对他非常严厉的指责,而不是通过观察和提醒来对他的实力有更量化的认知后,去辅导帮带他,最终再放手授权,这个接受他的过程我没有意识也没有去做,而是简单通过看结果下结论,最终也导致了他的黯然离职,也导致了我相当长一段时间不开心和不理解,为什么我对你这么负责你还认为我有其他用意,时至今日发现是当初自己心理的宽容度和用人的弹性都有很大的问题。<br>:::</p>
<p><a></a></p>
<h2>对抗框式思维</h2>
<p>所谓框式思维,是我自己发明的词,形容是在一个竹筐内青蛙观天,会被自己的思维框架直接框住,无法跳脱出来。</p>
<p>它的解法其实也很简单,就是换位思考,一旦当我们跟任何一方的意见相左,或者一个明显不符合我们认知的讲法冒出来的时候,我们就换位过去,尝试去理解声音发出者他背后的思考逻辑,而不要本能的用自己的既有观念尝试去打败或者推翻它,通过换位,也许可以发现当事人他逻辑链路中的局限性,也可能会重塑我们自己原本的认知,但不换位过去,不仅对抗的过程很辛苦,结果可能是双方都不受益。</p>
<p>当然也不是说,任何事情都要换位,过度的换位也会成为找理由的土壤,比如下属员工合错分支发布,导致线上故障,这时候不能拿项目紧张啊什么为他开脱,过错就是过错,但当时慌张合并的原因还是值得问一问,是粗心大意,还是工具上面有很多不友好的交互等等,目的是避免再犯。</p>
<p>换位思考只是一种手段,本质上,对抗框式思维,我们是在跟自己的意识框架对抗,这个世界足够的复杂,我们掌握在手中的技能寥寥无几,长在我们脑海中意识层次也非常单薄,特别对于程序员这个群体,对于物理世界的认识与虚拟社会的认识完全是两个极端。</p>
<p>:::info<br>讲一个我的案例,工作的头几年,我非常瞧不起做影响力的同学,觉得非常务虚,非常 KPI,非常不切实际,非常不硬核,总之就是既不理解也不认同更不愿意去做,别提出书著作,就连技术分享甚至写个博客都极为吝啬,我当时其实接触过很多内容创业者和站长,他们也告诉过我影响力的重要性,但都没听进我的心里,我自然也没从影响力中有过任何受益,直到 2013 年冬天当时应慕课网邀请,带着帮助他人更好学习的初心录制了一些 Nodejs 视频,影响力才悄无声息的建立,而我自己对此浑然不知,直到我 2016 年招聘的时候,面试进我公司的居然都是慕课上学习过视频的同学,当时对我整个人的冲击是非常大的,我一直不怎么看在眼里的影响力,居然因为我的无心之作在关键的时候为我带来的巨大的帮助,也是从那时候起我开始不抵触影响力这件事,开始转换观念,去慢慢寻思它的好处,直到 2017 年加入小菜,开始带着前端团队东奔西跑,真正意义的对外输出了一些影响力,才有了今天小菜前端 20 人的完整团队,以及这些优秀同学所承担起来的业务大盘和逐步健全的技术体系,没有影响力的建设,就一定没有小菜前端的现在,而这个建设,恰恰是我过去不曾认同的一环,工作 6 年才开始不抵触它,工作 7 年才开始刻意去建设它,这样的本能意识框架就轻松把我框住 7 年之久。<br>:::</p>
<p>简而言之,我们总以为的对和错、好与坏、是与非,放在多年的职业生涯中,都会慢慢磨去它原有的颜色,而褪去颜色后的才是真我,而加速对自己的探索,最有效的手段之一便是剥夺自己坐拥已有的意识框架并以为会躺赢的权利,让自己尝试去理解曾经的不理解,去认同原来的不认同,在辩证的选择中揣摩两级之久的可能性,一旦开窍,最终换来的是更加深度的思考力,并以此来引申,才能不断升级自己结构化的立体思考框架。</p>
<p><a></a></p>
<h2>理解人性复杂</h2>
<p>所谓人性复杂,其实是一个太复杂的话题,我自认为是没有能力讲出一二三,只是觉得这个话题值得大家重视它,并且应该花一定的长周期刻意训练自己,训练自己什么呢,其实就是看人观人能力。</p>
<p>生活和工作在这个社会,你身边环绕了太多的人,每个人都跟你有一定面积的接触,而每个人背后都有庞大的家族关系、复杂的人际网络和迥异的社会背景,仅凭一言一行是很难对人有合理判断的,这在招聘的时候尤为突出,如果你是招聘主管,你要决定一个候选人来不来团队跟你合作,其实是很难很难的一个决定。</p>
<p>所以很多时候我们采用做朋友的方式来对身边的人排序,以及基于此对他人进行定义,比如一个候选人我聊下来很投机,很愿意跟他交朋友,直觉告诉我们此人靠谱,可以合作,进了团队后相处一段时间,会不会在出现一些印象上的偏离,偏离的幅度有多大也是很难预估的,举这个例子是为了说看人观人这个能力是没有量化指标的,全靠心里的一把秤。</p>
<p>我自知是工作 9 年,看过不少人性的恶,也见过不少人性的善,但让我再去分辨,我依然是不具备这个能力,我唯一的经验就是:听其言、观其行。</p>
<p>言行一致的人靠谱的概率高,言行不一致的人靠谱概率低,但是否一致其实往往跟人性复杂有关,而跟人性善恶往往无关,我们不能把复杂和善恶混在一起,那样子的判断最终只会一叶障目,误自己前程。</p>
<p>:::info<br>举一个例子:还是我创业的时候,只不过是中后期,公司要被另外一家公司并购,大部分人都很雀跃欣喜,我内心很忐忑,因为看到对方过程上提出了一些反常识的要求,与当初讲的不同,担心被另外一家公司坑骗,但老板被对方老板喂了定心丸,完全放下成见不设防,一五一十完全照做,此时我和其他有同样想法的小伙伴,提醒和建议都无济于事,老板把并购理解为了纯合作利益,而忽略背后人性和利益的复杂,最终不出意料,被对方做局坑骗了整整一年,但此时已付出太多太多沉没成本无法挽回,造成了惨痛的失败:团队 2017 年资金链断裂而倒闭,当然所有人都付出了代价,代价因人而异,至于我,我直到 2019 年 7 月,还在偿还公司续命时借投资人养活团队的钱,人性判断出错后,痛不痛只有自己知道。<br>:::</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564563296526-a77967fc-2a84-4acc-9026-883df68b8dea.png#align=left&display=inline&height=449&name=image.png&originHeight=1602&originWidth=1640&size=182193&status=done&style=none&width=460" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>明白商业多变</h2>
<p>对于商业的理解我也非常浅薄,自知没能力去讨论商业因果,但关注商业这件事是值得我们工程师花精力的,至少要对自己所参与的业务和背后的商业逻辑有一定的认知,并且有自己独立的判断,这种判断能力要不断的历练和修正。</p>
<p>如果不能明白商业的变化性,就很难理解公司为什么每年每季度的战略和打法要常常变化,自然也很难认同背后在产品和技术上的不断迭代升级,也就看不到一次次的变化背后,从技术到产品再到用户,从行业服务和被服务的关系上,到底公司活下来的核心能力是什么,盈利的关键点是什么,越是是资深的工程师越要练习,因为越资深,被授权的范围越大,做出的决策影响面也就越大,所谓授权越大,风险越大。</p>
<p>关于这一点我就不造次了,大家可以多看一些投融资相关咨询,以及一些针对失败倒闭的公司的分析还有不同行业的观察白皮书等等,来训练自己对于生意这两个字的认知深度,从而在上升到商业的高度,当商业敏感度越来越高的时候,不仅对于公司的战略逻辑能更快捕捉到,甚至可以从技术面来发现更多机会点,来驱动和引领业务走出新的可能性,我自己也经历了这样的案例,但目前讲太敏感,就不给大家分享了。</p>
<p><a></a></p>
<h2>逼自己拼大盘</h2>
<p>所谓拼大盘,其实是一种归纳总结的能力,或者说是拆和装的能力,把问题拆解开,把答案装上去,比如我问你要把你这个团队的整体能力提上去,你打算从哪些方面着手?</p>
<p>那我自己从前有尝试回答过这个问题,也给出了自己的答案,今天看还是挺稚嫩的,但可以给大家带来一些启发性,我把图贴一下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563947341387-36a4603f-7b01-46ea-a3e5-09a5d42f424b.png#align=left&display=inline&height=403&name=image.png&originHeight=1008&originWidth=1876&size=958312&status=done&width=750.4#align=left&display=inline&height=1008&originHeight=1008&originWidth=1876&status=done&style=none&width=1876" alt="image.png" title="image.png"></p>
<p>任何一个复杂问题都可以用这种方式来训练,训练的久了,你的结构化能力就会变强,除了团队你还可以针对技术栈,针对系统,针对框架甚至针对技术和业务的结合等任意场景进行拼大盘的思考。</p>
<p><a></a></p>
<h2>敢对抗不合理</h2>
<p>关于这一点很好理解,就是工作中的不合理,是忍受还是反击,我的认识是,反击可能不一定有好的结果,但一定比忍受好,至于不合理的界定,我的看法是,自上向下大家达成共识的部分,就尽量不要挑战它的合理性,未达成共识的部分可以充分挑战,如果这个共识是很久前达成的,时过境迁与当下不适宜,此时要挑战。</p>
<p>所有的挑战出发点,不能只站在个人立场,要站在公司视角看待,我挑战后,能不能让公司变得更好,让团队变得更好,如果能那么就可以尝试做,如果挑战后只有我个人变得更好的,公司和团队不会受益,那么要三思后行可以先小范围论证下。</p>
<p>:::info<br>举一个我的例子吧,依然是创业时,2015 年冬天为了赶项目,我出差到美国加州居住了 2 个月,跟那里的同事汇合开发产品,在我回国前,老板让我在国内的分公司场地安装摄像头,摄像头要对着工程师座位的地方,我首先问了他的初衷,他初衷是担心公司出了什么事(打砸抢之类),好有一个记录,我认为这是不合理的,因为直接侵犯到了隐私,更重要的是,这让工程师感受到了不信任感,有一种被监控的感觉,在这件事情上我跟老板争论了很久,脸红脖子粗,我说就算装也是对着门口走廊就行,如果真要看上下班也可以装个打卡机,摄像头太夸张了,当然最后我说服了公司没做出这个决定。<br>:::</p>
<p><a></a></p>
<h2>去创造危机感</h2>
<p>当周边环境或者他人带给你危机感的时候,你可能真的危机了。</p>
<p>大家可以把危机感理解为未雨绸缪,把自己代入进去的不同的场景中,就会有危机感,也算是一种主动获取焦虑的方式,通常适用于我们工作一个周期后,驾轻就熟,没什么操心事的阶段,因为通常这个阶段我们会停滞成长限于安逸。</p>
<p>在慕课网有一个跟着我学习 Nodejs/小程序 开发的童鞋,非常有想法也非常上进,他的单位工作不算忙,业余时间全部用来学习技术和充电,做自己感兴趣的事业,比如借助小程序销售老家特产甚至是尝试珠宝生意,而这些都通过他自己用技术的方式把想法实现,不光技术有很大的成长,一年下来的销售流水也有几百万,当我问他精力分配的时候,他提到了他的危机感:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564566750456-6aae6918-fcde-4828-b278-e9cc111fbdff.png#align=left&display=inline&height=792&name=image.png&originHeight=1584&originWidth=1726&size=392193&status=done&style=none&width=863" alt="image.png" title="image.png"></p>
<p>反之,这一年多有上百个童鞋加我聊他们在团队迷茫的情况,不知道何去何从怎么发力,其实我认为有不少童鞋是缺少危机感,空有担忧,更缺少规划,假如这个同学意识到如果是下个月失业会饿肚子,不掌握 React/Vue 全家桶和基本原理一定找不到工作,倒计时开始只有 30 天,我相信每个夜晚每个周末一定会被他充分利用,去尽可能吧填充内心的不充实,但因为明天总是一个可被消费的资产,危机感就没有那么强烈,焦虑反而更强烈,于是一晃一年就过去了。</p>
<p>大家想一下,如果有一天 AI 突然爆发,UI 部分代码只要不是太复杂全部不用写了,简单的流程逻辑也不用写了,甚至跟用户的交互和交易方式也变了,还停留在 UI 实现和简单功能实现的前端工程师,该怎么办,在之前可以做哪些准备,或者说脱离了工程师这个职业,还能靠什么生存,模拟出更多危机感,会利于我们做出应变,也利于我们长出新能力从而发现新机会。</p>
<p><a></a></p>
<h2>画大饼算大帐</h2>
<p>所谓画大饼是基于合理推导,给自己和团队绘画蓝图,所谓算大帐,是根据自己团队的兴趣和特长,将精力放几块可以将大图拼起来,在拼起来的过程中,成本和受益是什么有多少。</p>
<p>比如,我在 2017 年的时候,给架构组的同学梳理了长远建设的课题方向,属于是画大饼:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564643474319-5e144106-d8fb-4260-ba6b-a49efca049d2.png#align=left&display=inline&height=734&name=image.png&originHeight=1614&originWidth=2728&size=660062&status=done&style=none&width=1239.9999731237244" alt="image.png" title="image.png"></p>
<p>在之后结合业务和团队的能力现状,阶段性的立项建设,把项目的价值盘点清楚,从研发到排期到最终上线运营以及后续的技术沉淀这一套闭环评估后,要投几个人,预计做多久,预计分几期,这些就算是算大帐了,至于大账是多大,大家自己界定就行,没有标准,小项目也可以很闭环的。</p>
<p><a></a></p>
<h2>布局未来十年</h2>
<p>其实这一点是我最想说的,我们都知道职业规划很重要,但我们中的大部分都做不好,尤其是工作的头几年,根本无从规划,因为对行业的认知,对技术的掌握,甚至对自己的认知都很浅,担心所做的规划有很强的不确定性,比如我在 2011 年年度述职的时候,总监问我的职业规划,我说我希望自己可以独当一面,成为一个前端架构师,而当时我其实对架构师一无所知,只是觉得名字贼酷也看上去是一个技术终点,而我给自己设定的 deadline 是 2 年内,那么显然我没完成自己的规划,不仅如此,我还步入了完全另外一种创业的旅程。</p>
<p>那我当时的规划是不是瞎想的用来凑数呢,其实也不是,我当时也是非常仔细的思考了,也仔细的规划了,大家可以看下我在 2011 年初,还没有述职之前,对自己的半年总结:</p>
<blockquote>半年总结:<p><a></a></p>
</blockquote>
<h4>业务方面:</h4>
<blockquote>一、钻石展位:日常功能维护与 2.0 新功能迁移;<br>1、计划消耗;<p>2、bannermaker 接入;</p>
<p>3、账户诊断;</p>
<p>4、群体投放;</p>
<p>5、定价投放;</p>
<p>二、明星店铺:主站搜索与店铺搜索;</p>
<p>1、第一期改版上线主搜;</p>
<p>2、第二期改版上线主搜与店铺搜;</p>
<p>三、MiniSite:</p>
<p> 1、万塘书院从 Minisite 中独立出来,成为子站点;</p>
<p>2、超级麦霸,钻石展位,第三方服务平台;</p>
<p>四、TMS:淘宝联盟、E淘、促销活动,频道页面制作;</p>
<p>五、BP 后台:后台邮件,站内信兼容版本开发;</p>
<p>六、直通车论坛:论坛帖子,活动页面制作;</p>
<p>七、Sinba 后台:拖曳模块,树形结构,以及整站改版;</p>
<p>八、外投广告牌:对北京外投广告牌的支持,多尺寸广告牌的制作修改(针对 Yahoo,优酷,搜狐等主要门户网站),特殊版本(凤凰网,新浪网投放要求)的开发;</p>
<p>九、无线商搜的手机页面制作;</p>
<p><a></a></p>
</blockquote>
<h4>团队建设方面:</h4>
<blockquote>公司的团队生活与建设方面:带领球队共 16 位队友,进行了 25 场次的训练与比赛,包括杭州师范学院,杭网俱乐部,杭州尤文图斯,淘宝球队,淘宝商城球队等进行过多次的联谊球赛;<p><a></a></p>
</blockquote>
<h4>半年出现的问题</h4>
<blockquote>一、项目进度的把握程度:作为前端 UED,对项目的把控能力还不够强势;<p>二、与多部门协调的能力:协调力度不够,成熟度欠缺;</p>
<p>三、对产品诞生过程中的影响力:影响力范围及力度不够;</p>
<p>四、技术层面的成熟度(既定时长内,需求价值,应用场景,开发周长,技术实现,维护性与扩展性,以及上线反响所综合考虑的最优折衷度):特殊场景下的需求PK与处理娴熟度不够;</p>
</blockquote>
<p>其实可以看到,我那时也算是一个很勤奋(无数加班狂做很多项目,半年的经验可能顶的上别人一年半的简历),也很会主动思考的童鞋,再对比我自此后带过的很多毕业生,在半年内能做这么多,并且具备我这样的总结能力的其实是不多见的,勤奋如我主动思考如我,为什么还做不好自己的职业规划呢?</p>
<p>其实就是对自己的认识还不够深刻,只停留在技术的层面,并且对于这个行业的积累还太少,也不知道前端会变成什么样,除了架构师还有什么可能,就算是架构师,架构师需要什么技能,这些技能分别是什么,代码能力占了多少比重,统统这些是我当时还不擅长思考的,我想的都是如何把项目做快做好,如何多学一些编程技能。</p>
<p>那规划都做不好,怎么布局职业十年呢,我的看法是,在工作的头 3 年,就拼命逼自己的技术成长,在这中间历练沟通能力、协作能力和项目综合把控能力,这个阶段的确是很难做中长期规划的,在这三年中让自己变得技术足够硬足够强,然后从第三年开始,去刻意训练更多的软实力,也更多的向内去挖掘自己的潜能,看自己适合什么,擅长什么,想干什么,然后再基于此做自己未来 10 年的长期规划,一旦有了这个长度,眼前的这两年三载你都不会很纠结,因为方向清楚了,只是不同阶段你要关注什么的问题。</p>
<p>而我自己开始有意识的布局未来 10 年长度的职业方向,是从 2017 年开始,也就是我工作了整整 7 年,我才把自己看清楚,我才有把握对自己做一份能履行有价值可量化的规划,我相信大家如果经过这篇文章的点醒,一定可以比我醒悟的更早,也规划的更早更好,规划不仅仅是那个未来的结果,其实更是这个路上自己如何成长,左右摇摆都没关系,只要那个方向依然明确,脚步依然超前,那么目标势必会越来越清晰可见。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=BHiNobC8ikj4IoFfwhpmSA%3D%3D.3YyA02FqW%2F33T8K7xEOMyq%2BS41WJ%2FnqaJEfOx%2BJxXdc%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
面试招聘:2 年招到 18 个前端教你怎么招人
https://segmentfault.com/a/1190000022295038
2020-04-16T23:00:00+08:00
2020-04-16T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
4
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>小菜前端从 2017 年 7 月到 2019 年 7 月,历经 2 年,一共招聘到 18 位前端,3 个技术专家,5 个资深,7 个中高级和 3 个校招,成果上看还算不错,但过程无比艰辛,今天就尝试从用人单位和面试官的视角,来给大家一些启发,也给找工作的童鞋更多视角来观察跳槽这件事。</p>
</blockquote>
<p>进入正文前,我需要跟大家解释下为什么这篇文章具有一定的参考价值,也就是怎么保证文中观点是经过验证有参考性的,主要的理由有如下几个:</p>
<ol>
<li>我从 2013 年开始招聘前端/NodeJS 工程师,到今天招了有 6 年多,有 6 年的招聘经验</li>
<li>这 6 年与候选人正式面试/面谈/电话/视频/文字/邮件等各种形式沟通至少 1000 人,样本规模有一定说服力</li>
<li>2 年内成功招到 18 个前端,劝退 2 个,流失 3 个,关于人才选用育留开,我熟知人才与用人单位的匹配模型</li>
</ol>
<p>这是工作内验证的部分,这些年在工作外业余时间通过分享或者线下社交,加了上百个微信群,朋友圈也多了上千个前端朋友,我自己也建了 5 个成长群,分别是:未毕业(大一二三四)、初级(工作约 0~2 年)、中高级(工作约 2~4 年)、资深(工作约 3~5 年以上)以及专门的前端管理群(带团队大于等于 3 人),与群里的部分同学也有很多深度的沟通 (想进群童鞋加我微信 codingdream,私聊我注明自己工作年限)。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567481611924-a6fb026e-c841-45df-9e82-4fa703be5003.png#align=left&display=inline&height=351&name=image.png&originHeight=1080&originWidth=1120&size=622461&status=done&width=364" alt="image.png" title="image.png"><br></p>
<p><a></a></p>
<h2>为什么前端那么难招聘</h2>
<p><br>我把上面的群定位成了严肃的技术和职业成长群(严格控制不允许吹水),所以可以从群里看到很多真实有价值的想法和观点,自然看的越多,也就越了解不同能力层级/不同技术栈背景/不同工作年限/不同行业属性/不同团队规模和组织架构下大家的工作和生活状态,以及处在不同的阶段,看待技术、团队、公司和个人职业发展的视角,就会了解到,虽然大量的公司都在疯狂的招聘前端,也有足够多的前端想要换一个更好的公司和团队,那为什么前端总是遇团队不淑,总是进不到好的团队,而公司总是招人总是很难匹配到合适的人,越招越难?其实答案很简单,就两句话:<br></p>
<ol>
<li>我们不知道自己团队需要什么样的人</li>
<li>我们不知道如何影响到候选人来加入</li>
</ol>
<p>对于第一个问题,我们很多时候是以为自己知道,其实并不知道,对第二个问题,我们总是觉得钱给够了就能来人,其实也把真正厉害的候选人看的太轻了,第二点是今天重点要谈的,就是让大家了解影响到候选人决策的一些因素和流程体验,这些我们作为招聘方和面试官,都可以去发力的地方。</p>
<p><a></a></p>
<h2>四张大图确定人才画像</h2>
<p>而对于第一点,我们要放到大环境中来谈,也就是自己公司在整个行业中的位置,未来发展阶段中所需要的梯队能力等等这些要全部综合起来看,我们才能更精准的预判出自己需要什么样的员工,那就需要对团队进行能力盘点,我通常盘点团队的办法就是四张图,第一张是团队每半年的员工新增情况和能力层级分布:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567494471720-986fa3ec-2c40-4a68-a259-0fc3c5ff2ff0.png#align=left&display=inline&height=369&name=image.png&originHeight=922&originWidth=2304&size=453431&status=done&width=921.6" alt="image.png" title="image.png"></p>
<p>通过这样的盘点,我明确知道团队是偏执行的中高级比较缺乏,还是承担攻坚力量的资深比较紧缺,还是能带领小组的管理型和专家人才比较紧缺,目标就是不断调整整个团队的形状不至于太畸形,头大脚小或者腰太细,而在某个特定阶段内出现畸形是没关系的,比如大家看这张图的 2018 年 12 月前,在资深和专家这一档特别紧缺,也就是说比较缺少能带你成长的师兄,所以 2019 年进行了招聘调整,增补了很多资深的同学和专家,这样大家就能得到较好的成长。</p>
<p>那么配合第一张图,还需要有一张能力图,也就是第二张大盘图,看整个团队的细分能力长短板的,比如我上次盘点的能力分布图如下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567495860799-3bdc133f-2b79-47f6-a7da-cd1bd7668729.png#align=left&display=inline&height=531&name=image.png&originHeight=1328&originWidth=2372&size=793495&status=done&width=948.8" alt="image.png" title="image.png"></p>
<p>有了上面两张图,你对于团队的现在一目了然,但这些评估还是偏主观,还必须结合公司的战略大盘来做第三张业务大盘图,把团队童鞋放到公司业务大盘里看他的发展路迹,从而预判是否每个人所在领域都能有一个合理健康的成长路线,以及在此领域内是否有人手的冗余或者欠缺,这一张大家自己做,我这里就不涉及公司敏感信息了,再上第四张图,就是一个行业人才机会图,比如我要招聘前端技术专家,也就是 P7,我就必须了解这个岗位在市场上的情况,就做了下面这张图,对于大团队 TL,这些信息你是需要掌握的,而对于小组长,这张图有没有关系不大:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567494865128-b89e18a5-fe94-40a5-908f-6746b80684b4.png#align=left&display=inline&height=681&name=image.png&originHeight=1702&originWidth=3326&size=5244420&status=done&width=1330.4" alt="image.png" title="image.png"></p>
<p>这张图很久了,放到今天是过时的,但对于我几个月之前的招聘是起到了作用,它可帮助你更清楚的了解专家在行业的紧俏情况,特别是管理型的高级专家人才,那么这时候就需要看自己团队有哪些方面是能匹配到他的,如果这些都不了解,甚至这些常见行业的商业模式都不了解的话,你跟他不仅连话题都没有,更重要的是自己与其他公司的区别之处,哪些可能是他在意的,你也讲不出来。</p>
<p>希望这两张图背后的逻辑能帮助到大家,接下来我们针对如何感召候选人这一点,来对候选人在多一些感性上和理性上的认识,同时看如何基于他们的关注点和期望值,以服务他们的心态,来改善自己的招聘策略。</p>
<p>另外技术这块,其实还有一个路线图大家可以做下,团队统一的技术栈演进和解决方案探索上,也要根据需要储备和引入人才,比如这张图是我一年多前就规划的,基本上变化不大,仍然在各个环节上不断的补人来进行长期建设:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567565051280-b5784fbf-ec99-46ad-ba0f-93d056f7ae90.png#align=left&display=inline&height=674&name=image.png&originHeight=1686&originWidth=3780&size=757995&status=done&width=1512" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>影响候选人入职的因素</h2>
<p>在我们接下来讨论更多的变量之前,先把 2017~2020 年间大环境下,我通过接触了这么多候选人后,所总结的会影响到候选人决策的要点,也就是软硬实力的决策因子比重,给大家分享下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567492373419-92c8904e-ea1c-4762-a22e-9cb05c44f950.png#align=left&display=inline&height=529&name=image.png&originHeight=1322&originWidth=2784&size=1020646&status=done&width=1113.6" alt="image.png" title="image.png"></p>
<p>上图的所有维度都是大家关心的,但对于不同层级(初级、中高级、资深、专家)不同背景(大公司、创业公司、海外归来)的候选人,他们由于职业的历练和个人技术路线的规划,对于不同维度上面的想法会有一些差异性,从大样本上看有这样的趋势:越靠近专家(工作通常有七八年靠上)的童鞋,对于公司未来回报、职业匹配度和前景有更高的要求,而越是工作经验较短的同学,对于公司的薪资福利、技术成长空间、团队氛围更加敏感,所有人都关心成长和回报,但成长的内容和回报的类型则有较大的不同。</p>
<p>大家如果发现自己跟图上的情况不符合,也不必纠结,图上的并不是标准答案,因为根本不存在标准答案,每个人的成长情况和路线都不同,没有对错甚至没有优劣之分的,只不过我们站在前端行业的时间轴上,会认为越资深的人自然看的越长远,并且期待接受更大的挑战,越年轻的童鞋会越在意氛围和成长,因为他尚需要持续的积累,从而将来能有更大的舞台。</p>
<p>那么抛开薪资待遇的部分,作为一个团队的管理者,天然都对员工的成长负责,我想起来我从前讲过这样一句话:</p>
<blockquote>在你的团队里,不论男女、不论层级、不论能力,只要在你的麾下,你就要对他的成长天然负责,妄图逃避规避找理由,都是不敢正视自己管理职责的闪烁其词,没有这样成就他人的心态,你可能仅仅做到了管理及格。</blockquote>
<p>无论你是只带 2 个前端,还是带 40 个前端,其实都可以从团队文化、组织架构、能力层级、人才梯队、新人融入、团队氛围、培训体系和内外部影响力上发力,来不断把团队带领的越来越强,下图是之前整理的,分享给大家:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567495270486-988b1a64-01d4-4516-9008-6055674cf0cf.png#align=left&display=inline&height=532&name=image.png&originHeight=1330&originWidth=2374&size=1361533&status=done&width=949.6" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>面试官可在体验上发力</h2>
<p>对于上图影响候人的因素,如果你有很独立客观的判断,了解自己团队和公司的长短板,也能推动这些因素朝着更成熟的方向进行的时候,就要来考虑第二个问题,如何让对你有意向的候选人,更倾向于来选择你的公司,此时作为招聘方,假如你要招的是专家,如果你不能给他更好的职业岗位匹配,也不能给他未来更大的回报,那么招聘一定是困难重重,如果你要招的是资深,他要的成长空间、团队氛围和薪资福利你都很难提供,那么结果也是一样。</p>
<p>会有同学说,我只是一个小小的团队 TL,我尚且人微言轻,不足以影响上面那么多团队状态发生改善,那么针对这种情况,我们可以把上图这些因素暂且抛开,来看看还有哪些发力点,可以降低候选人入职的门槛,比如下图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567493103060-cdd75f05-8041-40ea-84b1-30b7dba43419.png#align=left&display=inline&height=477&name=image.png&originHeight=1192&originWidth=2588&size=1191741&status=done&width=1035.2" alt="image.png" title="image.png"></p>
<p>我将招聘分了这些环节:前期的影响力传播、意向候选人的面试前的沟通、面试阶段对候选人做的功课、面试阶段可以为候选人描绘的他的成长路线、面试后的问题跟进和待遇进一步争取,以及整个过程中对候选人的招待、沟通等全流程所表现的专业程度、细心和专业程度,这些都可以给候选人留下较好的印象。</p>
<p>我想大家不管命中了其中哪个环节,那么在这个环节上你都可以给自己提更高的要求,接下来,针对候选人和面试官这两种看似对立的角色,我想额外给大家再输入一些观点,帮助大家,特别是帮助候选人也更中立客观理性的看待用人单位和候选人之间的关系。<br></p>
<p><a></a></p>
<h2>企业的性格与你的性格</h2>
<p>用人单位不是冰冷的一个组织,而是围在一起做事的一群人,既然是一群人,就自然有这群人凝聚出来的性格,这个性格决定了他们喜欢什么样的人,愿意接纳什么样的人,愿意培养什么样的人以及会淘汰什么样的人,比如不合群的人容易被淘汰,因为他容易与团队之间产生对立甚至内耗,降低团队的战斗力,这是站在用人单位的视角评估潜在的合作成本和磨合成本,以及可能的破坏力。</p>
<p>而具体到个人,虽然不合群的人可能是你,但不合群和道德品性,包括跟能力意识也完全不画等号,也就是说不合群就是不合群而已,你是完全没问题的,企业可能也一样,只是双方不合适,就像谈恋爱一样,相亲的时候就知道彼此不合适,所以万一发生,千万不要因为这一次不合适就否定自己,或者用人方否定自己的用人标准,这都正常。</p>
<p>这个所谓的性格匹配,在有的公司叫气味相投,或者说价值观匹配和味道一样,比较务虚,但它事实存在且至关重要,毕竟在任何团队中,都不是孤立的个体,而是一群人,需要更多的默契更少的对抗,至少不能是人和人之间的对抗。</p>
<p>那么对于面试官而言,当你感觉彼此性格/味道/价值观等这些并不合拢的话,是需要有决断力,学会拒绝,因为一旦发生了候选人进入后与团队磨合出现重大问题,不仅仅是伤害到这家公司,其实也更是伤害到了这位候选人,他的整个职业生涯也在这一段历程中受到了影响,而他本人无论技术还是人品都是没问题的,只是跟你的团队不搭配而已,可是你却没有识别出来,或者识别到了但无所作为。</p>
<p>那么如何识别呢,首先面试官自己不能是一个特别偏执、二元论或者极端的人,必须要正直善良利他,然后来把自己铺开放在团队里,看看跟候选人聊下来,你内心深处,会愿意跟他做朋友么,如果很愿意,那么就可以大胆招,如果完全不认同,那么就不要将就,那么去了解的方式很多,开放性的话题都可以聊,我会大家分享一个自己考察候选人的图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1567564199871-d424613c-bf68-4ff2-acf1-bed50a3b5819.png#align=left&display=inline&height=343&name=image.png&originHeight=802&originWidth=1742&size=594835&status=done&width=746" alt="image.png" title="image.png"></p>
<p>这些都是一个主客观的维度,随便挑几个听他的看法,他的经历,他的思考和最后的收获,停下来后相信你会有自己的判断。</p>
<p><a></a></p>
<h2>相对阶段的招聘要求会变</h2>
<p>一个公司处在 ABCDE 融资的阶段,一个公司的部门处在新成立、快速测试、稳定运行的阶段,一个部门的老板处在空降过来、提拔上来、转岗过来的阶段,一个开放的具体职位处在长期没有招聘到、临时的坑需要快速接手、长期建设的阶段...如此分下去,大家就明白某家公司这段时间放开的某个职位,虽然招聘的岗位可能都叫前端工程师,但背后的要求都会因循着特定的阶段、组织的形态、业务的背景发生很大的变化,并不会一成不变。</p>
<p>如果阶段背后的要求不是恒定的常量,那么必然存在某个阶段你与该岗位是匹配的,而过了一段时间又不匹配了,换句话说,某段时间你面试通过可以入职,再过段时间可能你就进不去了,再过段时间可能又能进去了,所以当初把你拒掉的公司不代表你没有机会再进去了,同样某段时间被你拒掉的候选人可能过段时间可以再捞起来聊聊。</p>
<p>那么对于面试官而言,不能拿从前的旧标准来约束新的候选人,要用发展的眼光看待每一个想要切换新舞台的候选人,他们都是一个个梦想者,心怀希望身批技能,要结合当下该岗位的特征,去跟每一候选人进行应用,无论是之前被你拒绝过的,还是拒绝过你的,大家都有互相再次了解的机会,我还记得之前杭州的一个前端被我拒了后,又接连至少给我发了 2 次简历,每一次匹配都没有匹配上直到最近的一次,我们也开放了中高级的岗位,同时对于学习能力、适应能力和思考主动性有更强的要求,于是就通过面试考核后,给他下发了 Offer,最终成为了同事。</p>
<p><a></a></p>
<h2>写给前端面试官的寄语</h2>
<p>招聘是一件很有挑战性也有复杂度的事情,但他的本质并不会变化,吸引优秀的人进入团队,成就他也成就公司彼此更成功,作为面试官,要时刻把候选人当做是你服务的客户,虽然是你在考察他的过往经验和能力,但本质上也是传递你的团队性格和优势信息,在这个过程中,无论结果如何,双方都能得到一个深度交流的机会,透过这个机会既能帮助候选人更了解你的公司文化和氛围,也能让你更了解一届届的毕业生和新人,在市场大环境的洗礼下他们的关注点到底是什么。</p>
<p>基于这些了解,可以帮助你调整接下来的招聘策略,从而塑造团队成为大家更愿意来之奋斗的团队,即便大家暂时未能合作,将来某天可能还会再见,就比如我跟 2010 年时面阿里时拒绝我的面试官成为了很好的哥们,一起玩服务器一起玩域名,后来又从阿里前后出来一起进了创业圈,在前端这个小圈子中,每次相见都是缘分,希望每次相见,都能给彼此一个大大的惊喜,保持一份相信,新的合作机会在未来还会出现,我们彼此还会遇见。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=zV6r8%2B%2Bw1cDUvXm%2BI8DG5g%3D%3D.KsM8zWWgqTchACIC2P7OXWfxSA0JyqhSjB1emYrzCFM%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
团队建设:创业公司技术团队的文化氛围如何打造
https://segmentfault.com/a/1190000022294969
2020-04-15T23:00:00+08:00
2020-04-15T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>团队文化是对企业文化的继承和引申,公司文化更兼容通用,而团队文化更有导向性和职业特征,假如公司文化有一条叫有激情,那么销售团队可以激励 + 口号点燃激情,而工程师只能代码成就感点爆激情,内核类似,表述方式和落地手段截然不同。</blockquote>
<p>关于技术团队的文化和氛围,这是让 Scott 最难下笔的一篇,自认为没有太多的经验和套路,但它又是一个无法回避的课题,Scott 斗胆写下近两年小菜前端团队(对技术团队亦通用)在这上面的思考与尝试,目前的结果也仅仅是做到 0 到 1,收获也只是可圈可点。</p>
<p><a></a></p>
<h2>为什么要建设文化与氛围</h2>
<p>任何举措都有它实际的目的,对于需要长期性持续性不断升级的文化与氛围的建设更是如此,这件事情做与不做,到底区别在哪里,不做可以么?团队一个同学给出了自己的理解:</p>
<p>团队一,每个团队成员之间只是冰冷的同事关系,每天只是各顾各的完成上级分配的任务。能力强者只会抱怨能力弱者拖累了进度,能力弱者每天混混度日。团队二,每个团队成员大到朝着一个目标,小到解决一个问题,都能够互相帮助,互相鼓励,互相信任,先行者帮助后行者,后行者紧步跟上,无论遇到怎样的问题都不会轻易放弃。</p>
<blockquote>后者与前者之差,就差在后者有属于团队自己的文化导向,对一个团队而言,只要这个文化持续的感染着每一个人,所有人是文化的受益者也是建设者,更好的工作氛围也随之而来。</blockquote>
<p>正如这位同学所言,文化是团队如何做事及性格形成的向导,是氛围形成和持续变好的驱动者,倡导什么文化就会衍生出什么样的氛围,所以市面上有文艺气质的团队,有所谓狼性文化和执行力的团队,也有务实与结果为王的团队,无论哪一种,作为工程师都希望自己的团队是简单的纯粹的,没有勾心斗角没有人前人后的算计,而是有更多的尊重和理解,有更多的激励和回馈,有更多的轻松时刻和荣誉时刻,有更多的沟通交流和互帮互助。这种感觉没有了,人之间就逐渐冷漠了,合作基础慢慢松散了,凝心力和荣誉感也逐渐消失,最后导致人才储备和沉淀会沦为一句空谈。</p>
<p>这就是为什么需要持续性的文化宣导和氛围建设,因为一旦失去了文化的土壤,也就没有了氛围发酵的容器,所以这是一个团队必须面对的非常核心的课题,逃避只会让情况变得更糟。</p>
<p><a></a></p>
<h2>如何去定义技术团队文化</h2>
<p>在文化的层面,实际上没有高下优劣之分,文化落地和氛围打造的过程结果之所以会事与愿违,原因就在于这一群人是否是文化的笃信者和践行者。倘若没有拿到好结果,要么是文化水土不服定偏了,要么招聘进来的人不认同也不执行更别提推动,文化遇到极大阻力了,要么是没有更多的方法方式来保证文化的落地。</p>
<p>所以文化不匹配,人不合适,执行过程缺失,往往是一个团队文化最终无法落地的三个关键因素,那么首先来解决如何定好文化这个问题。</p>
<p>宋小菜走过 4 年,技术部从一开始的七八个人到现在的六七十人再到未来的成百上千人,团队一些早期加入的程序员老人,就有这种感悟:</p>
<blockquote>当团队人数越来越多时,如何让整个团队朝着一个方向走,如何让更多的人在日常工作中实现自己的价值,仅仅通过公司大的战略目标和逐年不变的文化口号是很难实现的,这个时候就需要考虑塑造技术团队自己的团队文化。</blockquote>
<p>技术团队的文化属于技术团队的每一个人,因此也应该由团队的每一个人一起参与制定。小菜技术团队是按照这样的次序做的:</p>
<ul>
<li>分组共创,每个小组各自内部讨论产出该小组希望文化长成的样子;</li>
<li>TL 共创,将所有小组产出的文化汇总一起,由技术组长进一步共创讨论;</li>
<li>文化聚焦,针对 TL 共同共创后的文化进行归纳整理和去重,形成最终版本;</li>
<li>文化公示,将整个技术部两次共创后的文化公示给大家听取反馈;</li>
<li>解读文化,由技术部负责人将公示后的文化,结合员工案例解读给大家形成初步印象。</li>
</ul>
<p>这里面的思考路径有很多,比如结合工程师的职业特征,性格爱好,结合公司近一两年的战略方向和业务重点,结合团队既有的做事方式和短板劣势,大家在自己团队做一遍后,就会有更深的感悟了。经过这样的流程后,所有的文化既有来自一线同学的感性思考,也有来自上层归纳抽象后的引申,小菜技术部秉承着文化是服务于组织,而不是组织服务于文化这一个基线,以及文化是要简单的可传承的可让工程师持续成长的宗旨,最终锁定小菜技术部的文化是非常简练的三句话:有担当、敢冒险、拥抱业务。简单解释如下:</p>
<ul>
<li>有担当,遇事不推诿,敢背锅,责任心驱动,主人翁意识,使命必达,为结果负责,过程中影响团队</li>
<li>敢冒险,不惧挑战,大胆创新,敢挑战不可能的项目,通过技术创造更多可能性,驱动业务拿到更大价值</li>
<li>拥抱业务,深入业务现场,感知预测业务,理解业务的变与不变,主动与业务保持同步,与业务方同患难共荣辱</li>
</ul>
<p>对于我们这种 toBtoC 业务形态的创业公司,处在链路长规则复杂变化频繁,未知因素多技术挑战大的研发环境中,有担当、敢冒险和拥抱业务这就是我们在一两年内在技术部推崇和反复倡导的文化,这是我们的一个上墙海报的 Demo 版本:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563946715120-d380fe24-169a-4a32-9859-152d7ee3f32f.png#align=left&display=inline&height=862&originHeight=862&originWidth=1932&size=0&status=done&style=none&width=1932" alt="" title=""></p>
<p><a></a></p>
<h2>如何让文化在团队落地</h2>
<p>如果定出了文化而不执行,那么这个就是一个空虚的标语,不会为团队带来实际的收益,在技术团队虽然是靠实力说话,但是人心也都是肉长的,不同脾气不同性格不同价值观的人一起合作,就需要在整个虚拟框架里的团队中去主推集中价值观,这种价值观可以让大部分同学在特定的事情上更容易达成共识形成合力更能创造价值,说洗脑和灌输并不合适,说是共识的承认和达成更合适,既然我们希望达成这个结果,就要在各种手法上来辅助它的缓缓落地,有这三个虚一点的基础点的套路:</p>
<ul>
<li>宣导:首先就是虚一点的做法,就是跟大家不断的宣导,利用言语的鼓励和肯定来让大家对文化建立印象。</li>
<li>标杆:其次就是树立标杆和榜样,在团队中挑选与文化最契合的同学,让所有人都知道具备这样特质的同学是整个团队更肯定,那么标杆自然也成为了一种衡量的尺度</li>
<li>奖惩:再次就是奖惩分明,针对符合文化的和违背文化的要有一定的奖惩措施,它的方式和程度可以由团队自行斟酌,比如小尺度的就是奖励小玩具发奖金,大尺度的可以是增加晋升权重和年终绩效成绩,最终可以反映在奖金上等等。</li>
</ul>
<p>除了这些常规的虚一些的做法,还有很多可以尝试的方式,比如想让团队的 Geek 文化更浓郁,可以</p>
<ul>
<li>组建小规模的 12 小时编程大赛,快速做出利于团队和业务的 Demo 工具;</li>
<li>组建硬件兴趣小组,基于 IOT 来与线上的服务结合,做一些报警监控的小玩具;</li>
<li>利用团队 outing 机会,利用无人机和便携相机来为团队制作航拍的旅游大片;</li>
<li>在办公室区增设内部开源贡献墙,来突出钻研技术所带来的一系列效率和基建价值;</li>
<li>组织同学每双周推出一些业界与公司技术栈相关的重要技术新闻周刊。</li>
</ul>
<p>如果想让团队更接地气更接近业务和用户的话,可以:</p>
<ul>
<li>定期组织同学去业务现场去做用户调研回来做现场问题分享;</li>
<li>针对用户的访问行为数据做一些深度的过程分析,输出一些监控维度的看板来观测业务现场的用户特征;</li>
<li>与业务方做一些共创性的方案推研,从更宽的视角看待在做事情的价值;</li>
<li>模拟一些创业茶话会,让有想法的同学把他的工具做成 PPT 向大家宣讲融资(吸纳成员)接受挑战。</li>
</ul>
<p>其实只要打开脑洞,利用现在的社群和这么多娱乐 APP 可以玩出很多花样,只要用心去坚持去做去总结,都能让团队宣导的很多价值观也好、文化也好,能慢慢植入到同学的脑海中,而所有人因为文化价值的聚合也会从中受益。</p>
<p><a></a></p>
<h2>搭建健康的梯队模型</h2>
<p>在文化落地我们前面提到了很多方法,所有的方法都需要有人去执行才可以,如果这所有的事情都让团队一把手去做,他要累死也未必做得完,所以这里就必须有合理的团队梯队来逐步落实,比如有每个业务小团队前端负责人,那么这些负责人就可以成为推广文化的最佳旗手,从这个角度必须要搞定这些小组长,动之以情晓之以理,如果非常努力与之沟通都发现他完全没意愿执行,有可能这个小组长不是你的最佳培养对象,因为这个文化他也是当初参与共创出来的,可能需要切换一个人,也可以轮空这个人,其他小组做起来后再尝试给他最后一次机会。</p>
<p>这里我们聊的其实是团队的腰部力量,头脑里规划的路线再好,也需要大腿来跑,而能跑多远撑多久核心力量就在腰腹这里,所以如果腰腹这里你都无法搞定来落地文化,那么再往下一定出问题,这时候需要把这个梯队结构再优化调整一下,团队里能者上愿者上,关键位置不可以出现有能力却无意愿的人。</p>
<p>梯队模型搭建的健康程度,会影响文化的落地速度和程度,如果配合一些必要的管理手段,往往这一层的问题不会太严重,最难搞的依然是基层一线偏执行的同学。</p>
<p><a></a></p>
<h2>如何提高基层的意愿度</h2>
<p>文化是很虚的东西,不仅对于一线同学,对于管理者依然如此,这么虚的东西要逐渐做实,是要耗费一些心理的,怎么调动大家的意愿度呢,我建议的做法首先要从大家的利益和兴趣出发,以最轻松可接受的方式来逐步渗透文化想要表达的颜色,在这个执行过程中要确保争取大多数,等待极少数,一定要一对一搞定大多数同学支持文化落实的各种实操方案,有了这样的一个绝对数量,就可以开展活动了。</p>
<p>开展中随时欢迎原本无意愿的人,千万不要调戏或者冷淡处理这些同学,因为每一个人组合在一起才是这个文化落地的真实意义,如果说长期性的连续的活动依然有极个别同学抵制,那么这个同学未必跟你的团队文化匹配,走到这一步往往会很残酷,使劲全力再次尝试依然无效的话,要么劝退要么开除。</p>
<p>可是不就是一个小小的文化活动形式,为什么要上纲上线,原因很简单,在一个既定的玩法规则里,所有人都共同打造这样一个氛围的时候,个别同学的抵制等同于是否决了这个文化的合理性,既然否决了合理性,就说明彼此的匹配有问题,未来再招聘新员工一定要仔细甄选。</p>
<p>然后再反思管理者的问题,任何一个同学的离开,无论是否劝退开除都是你的管理事故,在整个过程中,不可否认有一些公司大环境的不完美甚至不合理,但作为管理者也一定逃不开责任,你是否站在了一线员工的利益和期望处,为他们的成长设身处地去思考,并定制和升级越来越有效的帮带手段,如果这些都没有,最终导致了员工的离开,必须给自己的管理记上失败的一票,要从中吸取经验。</p>
<p><a></a></p>
<h2>营造参与感共做一件事</h2>
<p>如果我们的亲朋好友中有人参军,特别是上一代,我们经常听到 “战友” 这个称呼,他们之间的感情是非常非常深厚的,甚至有的是过命的交情,一辈子的信任甚至强于亲兄亲弟,为什么会这样?是因为他们共同经历了太多的考验,共同经历了荣誉与耻辱,一起战斗成功过也失败过,而感情就是在这样的战斗中一场场磨炼出来的,这种感情关于信任也高于信任。</p>
<p>那么在一个公司实体里面,如果所有的同学都有极低的参与度极弱的荣誉感,特别在技术团队,大家都对着机器交流,而日常只仅仅是工作合作关系的话,这在创业公司就是一场灾难,大公司里面可以不讲究这个但小公司就是以快打快,彼此都是背靠背的兄弟,需要有极强的信任感才能合作中去执行更多错误的而又不可避免的决策,一次次掉进到坑里,共同经历失败再爬出来共同经历欣喜。</p>
<p>那这种荣誉感怎么营造呢,小菜这边我们的办法是除了工作以外,建立了很多虚线小组:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563947477292-c197df45-75b7-4729-8f0e-0552530ab23c.png#align=left&display=inline&height=331&name=image.png&originHeight=792&originWidth=1784&size=586644&status=done&style=none&width=746" alt="image.png" title="image.png"></p>
<p>如上图所示,有自告奋勇的组长,有热心入团的组员,每个小组自行定规矩、做计划、要预算、做执行,再形成沉淀,那么这些小组基本上就能把一个团队的绝大多数人凝聚在一个个的场景中共同经历一个事情,共同推进一个目标,目前跑下来,我们的效果还是不错的。</p>
<p><a></a></p>
<h2>总结</h2>
<p>当我们把文化落到团队的时候,往往氛围也随之而来,同样当我们把氛围逐渐培养起来的时候,来宣导文化会更加可落地,所以它俩其实是相辅相成的关系,理想情况是两者可以结合来做,既轻松又有激励的作用,而且要适当伴随一些管理的技巧和力度,也只有这样,团队才会朝着你期待的方向走去。除了上面所讲的这些,大家一定要知道团建不是单一的手段,而是综合性组合拳抓手来推进,而且往往是不能量化,更是一种感觉,有的跟工作有关系,有的毫不相关,我梳理出一些利于组织发展的方向,把他们交叉起来同步推进,实线虚线结合最好:</p>
<ul>
<li>团队文化建设</li>
<li>组织架构设计</li>
<li>能力层级共识</li>
<li>人才结构升级</li>
<li>新人融入保障</li>
<li>团队氛围促进</li>
<li>培训体系完善</li>
<li>团队影响力建设</li>
</ul>
<p>我也把它汇总到一张图上,来表达他们对于组织发展的关系,其实说白了就是人的选用育留,供大家参考:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563947341387-36a4603f-7b01-46ea-a3e5-09a5d42f424b.png#align=left&display=inline&height=403&name=image.png&originHeight=1008&originWidth=1876&size=958312&status=done&style=none&width=750.4" alt="image.png" title="image.png"></p>
<p>最最后,作为一个普通的工程师个体,可以放下个人立场,先不去抵制这个文化本身,而是去透过文化看团队出了问题,针对这些问题我自己可以为团队做些什么,站在一个团队的视角来思考这些问题,会帮你更快更好的梳理出健康的职业路线,也帮你更好的理解工程师群体的信仰和特征,它是很虚的同时也是很实的东西。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=Dzhq2iQhKrkg6QIOtoBrVA%3D%3D.6wrmkQsrIn9sdcPHn0Q6RysYnf2SC5fuxtRRl1axPAo%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术路线:前端开发已进入深水区
https://segmentfault.com/a/1190000022294997
2020-04-15T23:00:00+08:00
2020-04-15T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
5
<blockquote>
<p>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</p>
<p>对于普通人,最大潜水深度一般不超过水下 30 米,极限为水下 40 米,超过 40 米就进入到技术潜水的范畴,就会面临各种复杂的危险状况,需要各种装备的集成和系统化的训练才能保证一定的安全性。</p>
<ul>
<li>为什么技术晋升越来越难了</li>
<li>为什么高薪资的岗位 Offer 越来越难拿了</li>
<li>为什么公司总是说做技术也要懂业务</li>
<li>为什么很多团队主管总把价值挂在嘴边</li>
<li>为什么 What/How/Why 必须要搞清楚</li>
<li>为什么单纯技术硬很难向前突破了</li>
<li>为什么前端开发往上走比之前更难了</li>
<li>为什么我想发力却总是懒于动手</li>
<li>为什么我趴键盘上看不到明天看不到希望</li>
<li>...</li>
</ul>
</blockquote>
<p>红利已逝,今非昔比。对比 2010 年,整个前端生态已经翻新了好几遍,直到近几年的 Node BFF、IDE Cloud,抑或是客户端 AI,还是 Serverless 的建设,前端想要深度参与的话,单纯依靠原来的 HTML/CSS/JS 三件套技能也远远不够了,再抛开技术,整个互联网创业生态也重构了好几遍,生意的本质没变,但做生意的理念和方法论以及辅助的工具都发生了巨大的变化。</p>
<p>新的商业环境下就有新的公司组织架构形态,以及新的产品研发流程和合作模式,这些也对今日的前端开发工程师提出更新更高的要求,无论是技术层面还是意识层面,如今的前端开发已经进入深水区,要在深水区中生存以及捕捞猎物,就需要有深水区所需要的系统化的技能体系以及配套的软硬件能力,以及从浅水区进往深水区所需要的进阶方法论,本文试图向大家传达这样一种观点,希望带给大家一些启示,无论是新人老人都要居安思危,提前做出储备,以应对新的职场挑战,更灵活的延展自己的职业路线。</p>
<p>本文是小菜前端 TL 内训课程中, 《上手技术管理的初级套路》 这一节里面,关于前端已迎来深水区这个观点的展开陈述,文中会截取几页 PPT 来辅助叙述帮大家理解:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562663531223-c21f1167-d054-4be1-bbd1-676ccadd58e0.png#align=left&display=inline&height=425&name=image.png&originHeight=730&originWidth=1280&size=485729&status=done&width=746" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>浅水区需要哪些技能</h2>
<p>站在 2019 年,通常一个工程师履历中体现的是跳槽历史、参与项目的难度、React/Vue/Angular 等框架底层熟悉度、编程方法论的掌握程度以及职位的变迁等,而在工作中的确与编程强相关的技能有很多(该图是我多年前整理修改而来,有同学知道出处可以告知我):</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562638872275-f21ac36b-593b-4822-b342-0743e73500b0.png#align=left&display=inline&height=469&name=image.png&originHeight=1032&originWidth=1828&size=619426&status=done&width=830.9090728996217#align=left&display=inline&height=1032&originHeight=1032&originWidth=1828&status=done&style=none&width=1828" alt="image.png" title="image.png"></p>
<p>抛开 BATMD 这种大体量的公司,放在市面上任意一个 50 人规模以下技术团队的公司里面,大概率掌握最好的是 IDE/框架/API 这一层,至于代码实现的足够优雅很难保障,更不要提程序设计的娴熟套路、项目背后沉淀的方法论等等,单纯在这张图上打怪升级花个 5 年 10 年丝毫不为怪,而对于前端工程师,这张图的技能点花个 7 年 10 年全部打满打透,此时也差不多三十而立了,而立之年也就是摸到了技术路线的第一个天花板,这个天花板就是技术专家,即便如此,用 10 年时间碰到这个天花板的人依然是极少数,大部分人需要花费更久甚至一直到不了这个高度,而所有这张图上我把它定义成浅水区技能,是肉眼可见的,是可以量化的,是最容易产生共鸣而形成学习动力的,但是放在如今的新商业环境中就显得很单薄了。</p>
<p>为什么单薄呢?我们把图上的能力和知识体系打碎重组,提炼后就是三个关键字:架构、编程、运维,一个是意识和逻辑层面,一个是过程实现层面,一个是环境保障层面,这些能力依然是落纯技术体系内,并没有跟外部的商业和职场环境发生多少交集。</p>
<p><a></a></p>
<h2>深水区需要哪些技能</h2>
<p>在深水区,脑海中如果只有编程二字是不够的,就算带一些沟通合作也还是远远不够,但是不是一定需要深水区技能才能把工作做好,答案也并不是,深水区技能是更长期性更深刻的,从长期看具备这些特质可以更快更好的跨过技术专家的这个天花板,走到更高的一个 Level,但不具备这些特质也未必会严重影响浅水区的表现。不过当更多同龄人具备深水区能力的时候,只具备浅水区能力的你慢慢就变成了裸泳,而更多更多的新人跳入到浅水区和你一起竞争,此时你跟深水区已经是隔绝的两个世界,看到的和收获也截然不同了。</p>
<p>我把深水区的技能,更口语化的总结为: 技术创新、流程优化、团队合作、影响大盘、驱动业务、商业决策和团队管理,如下图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562639725095-da5f6ec7-cb39-4013-b52c-c9166bfd4147.png#align=left&display=inline&height=469&name=image.png&originHeight=1032&originWidth=1832&size=653133&status=done&width=832.7272546783955#align=left&display=inline&height=1032&originHeight=1032&originWidth=1832&status=done&style=none&width=1832" alt="image.png" title="image.png"></p>
<p>每一个能力的解释我也标注在了图上,再通俗的解释一下:</p>
<ul>
<li>技术创新,从技术面、业务和产品面出发,以技术作为突破点,取得技术上的突破,比如兼容多端的框架研发、客户端浅层次 AI 的实现</li>
<li>流程优化,更多是从产品研发流程上发力,借助向上向下的管理,推动流程变得更高效,比如前后端的接口联调方式、比如产品 PRD 到测试流程的介入更敏捷的迭代方式,可能是规范可能是工具层面</li>
<li>团队合作,这个最好理解也最难做好,同样是从管理和业务的视角切过去,促成团队成员之间有更高层面的共识达成,有更信任的纽带关系,以及有更匹配的使命目标驱动,比如与业务同学一起出差拜访客户,并在过程中发现更多共鸣点,从而驱动彼此更快调整协作方式,最终为客户解决问题</li>
<li>影响大盘,所谓大盘就是公司或者部门的业务大盘,这个一定需要对业务的前景有较为客观深刻的认识,并且形成自己的独立判断和决策,去发现业务缺失哪些核心的因素点,并去补全这个遗漏甚至是发现一个机会点,去发掘实现一个新的业务可能性,比如公司的内容生产是一个核心业务,去发现它未来规模化生产会遇到人力瓶颈,有没有可能通过产品化背后的技术能力提供生产力,让业务看到一个新的可能性从而修正整个内容的规划方向</li>
<li>驱动业务,与影响大盘不同,驱动业务更多是有实质性的推进而不仅仅是想法,比如通过配套的埋点监控工具,来捕捉用户一些有意义的行为,从而不断从中发现问题并推动业务去优化解决,或者发现有价值的方向,从而开放这些价值点背后的技术能力给到业务和产品,赋能他们更好的迭代业务流程</li>
<li>商业决策,这一点更多是从数据价值层面,比如可视化很多时候是从前端来主导研发和推进,从各种展现模型中为业务提供更好的决策视角,但在它之前一定是对业务和产品有足够深的理解才会形成有效的决策路径和模型</li>
<li>团队管理,这个则是一个很大的话题了,站在组织的视角把团队从弱带到强,从小带到大,从层次不齐带到规矩有章法能冲能创,成为公司具备核心影响力的团队</li>
</ul>
<p>经过我们再次简单分析后,可以发现这些技能背后,是四个核心能力,分别是:技术、产品、业务和管理能力,把它们再拆到每个能力上,按照影响的权重,是这样的对应关系:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562640905313-dfefb33e-e46a-4241-b729-caa33fddbfd0.png#align=left&display=inline&height=461&name=image.png&originHeight=1014&originWidth=1864&size=808842&status=done&width=847.2727089085859#align=left&display=inline&height=1014&originHeight=1014&originWidth=1864&status=done&width=1864" alt="image.png" title="image.png"></p>
<p>大部分仅仅是靠技术都不可能去推进了,甚至技术都未必是它的重要影响权重,比如团队合作、影响大盘、商业决策等,统统这些能力的集合就是一个足够资深的工程师,他能在深水区存活,并且靠此打出一片天所需要的软实力了。</p>
<p><a></a></p>
<h2>怎么修炼深水区能力</h2>
<p>聊清楚深水区对于工程师的 What 和 Why 以后,我们来聊一聊 How。开始之前我们必须认识到这些能力不是一蹴而就的,无论是你已经具备了部分能力,还是丝毫不具备,我们都要认识到它的习得需要一个过程,这个过程通常就分为这三个阶段:初级练习阶段、渐变娴熟的阶段、质变内化为能力的阶段,在初级练习阶段没有足够的沉淀前,直接跳往后两个阶段都是不切实际的。</p>
<p>首先是初级阶段怎么练习,我把 PDCA 修改后形成这一个做事套路,大家可以参考:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562641870792-9cc3eb77-f373-4688-8491-d4e78b729c3c.png#align=left&display=inline&height=294&name=image.png&originHeight=646&originWidth=1768&size=206707&status=done&width=803.636346218015#align=left&display=inline&height=646&originHeight=646&originWidth=1768&status=done&style=none&width=1768" alt="image.png" title="image.png"></p>
<p>工作中的每一项具体的任务,都可以按照这个路子走一遍,一开始的时候会不适应,甚至有点僵硬的硬套模仿,多来几次慢慢就会成为一种习惯,举个例子:</p>
<p>团队里有很多表单开发的场景,大家的效率都很低,开发很痛苦,我看到这个问题后,就想要做一个复杂表单组件,我首先就是研究各种市面方案,研究公司的业务场景,研究已有的端产品上业务表达的交互表达方式,团队有没有人研究过表单的方案,我去收集相关的信息,并且我也弄明白为什么要开发这个表单组件,它能为业务带来实际的价值么,这个表单应该承载什么核心功能呢,做完能推动落地么,我本人能推得动么.... 这个环节就是形成判断决策的时候,也就是捉摸。</p>
<p>捉摸明白后,我开始制定目标,这个要符合 SMART 法则,尽量的可量化,比如:我要用 2 周时间开发一个表单组件,这个组件要可以被兼容替换到 AB 两个业务的 DEF 三个产品的 10 个页面的交互中,然后开始制定具体的开发计划,哪个时间点找老板征得同意,开始定出分几个版本来迭代,每个版本的周期是几天,每个版本完成的具体功能是什么,在这个过程中需要哪些资源,比如架构组同学的支持,业务组同学的反馈,交互组同学的设计配合,产品经理同学的理解和认同,然后把整个开发过程以可被感知的方式量化出来,透明化出来,这就是规划的阶段。</p>
<p>规划后开始进行技术方案的设计,模块的设计,三方库等等直到编码完成,开始推动组件在匹配的业务线和产品中使用,推动并帮助其他同学使用该组件,跟踪组件使用的效果并及时的修理 Bug 优化交互等,这个就是执行阶段。</p>
<p>在业务线用了一段时间后,组织一个小小复盘,针对实际应用中的问题做个收集整理,并且把过程中自己的不足也做一个检视,比如经常忘记跟老板同步进度,经常疏忽其他同学的吐槽建议等等,另外根据复盘和反馈来确保这个组件的确有提效的价值。</p>
<p>最后是沉淀开发组件的方法论,相应的技术文档(这个往往在开发过程中就沉淀下来了),以及组件化立项开发的套路,自己个人能力有什么成长,这种能力如何快速复制给其他新手同学...也就是沉淀 Share 的阶段。</p>
<p>实际工作中的问题,往往比一个组件要复杂的多的多,这就需要我们更加谨慎的对待每个阶段,把它们灵活应用并保障每次都比上一次拿到更好的结果,个人每次都比上一次方法论用的更纯熟。</p>
<p>上面抛砖引玉介绍了单纯实现层面可以训练的方法论,这种方法论同样适用了任何能力的练习,但方法论毕竟是方法论,真正决定它们训练结果其实还有一个前置条件,就是你的做事驱动力,也就是能力和意愿的情况。</p>
<p><a></a></p>
<h2>能力意愿是前置条件</h2>
<p>我们先讲了方法论,让大家更明确的感受到一些可执行的套路,然后再来看能力和意愿的重要性,所谓能力就是你判定问题和分析解决问题的能力,所谓意愿就是你面对任何一个突入飞来的难题或者任务,内心是抵触、认同还是兴奋这样的一种情绪。</p>
<p>首先,我们分析下一个员工的做事动机,通常有这几类:</p>
<ul>
<li>不知道不关心,对这个任务不清楚 what/how/why,也不关心它做不做的价值有多大</li>
<li>这么做是因为必须这么做,依然不理解它的价值,但知道这样做是因为我是前端工程师,这是我分内事</li>
<li>不这么做会有罪疚感,老板对我有信任,我如果不做好会觉得不好意思,心理过不去</li>
<li>这么做对我很重要,我认同这件事交给我做的原因和意义,这件事对我的成长及未来晋升都有意义,我很重视</li>
<li>喜欢并专注去做,这件事是我一直以来期待的机会,我很喜欢很想去实现它,我很理解它做好的意义</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562662079208-68c652dd-979a-4600-9f87-5b342c9caac9.png#align=left&display=inline&height=503&name=image.png&originHeight=1006&originWidth=1864&size=465804&status=done&width=932" alt="image.png" title="image.png"></p>
<p>所以一个同学有可能做不同的项目会有不同的动机,即便做同一个项目的不同阶段也会有不同的动机,这是一个完全主观的事情,但是它很重要,因为不同的动机会带来三个结果:老板及周围同事通过你做这件事所看出的你的做事态度,这件事你做完达成的结果,以及你由此而获得的成就感或者成长,当然所有的团队都希望你无论喜欢与否,都至少是理解并执行这个任务:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562662354056-6f1bdd7e-4657-4ac5-8045-241a877dc9ec.png#align=left&display=inline&height=493&name=image.png&originHeight=986&originWidth=1836&size=563606&status=done&style=none&width=918" alt="image.png" title="image.png"></p>
<p>最怕的是理解不执行和不理解和不执行,最终反映在能力和意愿上,在一个团队的分布中,你就有了不同的象限,是能力好意愿度高的,还是能力高意愿度低的,只有意愿高能力高的人才能获得最大程度的授权和自由空间,反之不仅获得授权会缩水,甚至必须听从具体的拆解后的任务去做执行的角色,所以如何让自己无论能力高低,先让自己具备一个高意愿度都是一个明智的选项。</p>
<p>那么存不存在一些事情是无意义的,做了也是白做呢,一定存在,现在这样高节奏的创业环境中,试错始终是一种常态,做一件事而拿不到结果也是常有的事,但是不是因此就否定了组织的动机,从而把自己束缚的越来越紧,正面看过去好像自己不再亏什么了,反过来看自己却失去了进入深水区而该有的历练,这个历练中一定有汗水也有委屈。</p>
<p><a></a></p>
<h2>面对深水压力不需紧张</h2>
<p>其实何止前端开发,整个技术行业都已步入深水区,只是前端工程师的感知来的晚一些而已。只要把眼光投向深水区,问题就会一个接一个的浮上来,当越来越多问题浮起来的时候,就是你慢慢沉向深水区的时候,这时候不需要太过紧张,此时的发生正在见证者你的成长,欢迎大家文后提问更多问题,我们可以再换一期来针对性讨论,本文主要帮大家引导到深水区已然到来,在它之上需要储备技能的必要性和重要性,目的就达到了。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=g6VMdkEwdTgsOxve53EDxw%3D%3D.yiPjFBBOkZ0eQ9jFxXgEJXS5NgtzyAh3xxO8RMWkhwY%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"><br></p>
框架设计:小程序框架与组件化如何选型定制
https://segmentfault.com/a/1190000022294925
2020-04-14T23:00:00+08:00
2020-04-14T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
1
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>蚂蚁雄兵的年代,人人皆可为王。</p>
<p>如今早已是全民联网年代,可以发现自己的父母大姑大姨等亲戚甚至爷爷奶奶,只要他们在使用千元智能机了,无论是看头条还是微信还是抖音,都在参与整个互联网的流量和内容的产生,他/她们通过手机消费了自己的时间,同时为所有的产品提供了更多人物画像的行为数据,无论是上翻下翻还是留言点赞,每一个 APP 都是一个独立的平台,而在这两年,冉冉升起的区别于 APP 的新应用平台,非小程序莫属:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564468241133-734aa6af-b89e-489c-88bc-7170fbdcb011.png#align=left&display=inline&height=1044&originHeight=1044&originWidth=1884&size=0&status=done&width=1884" alt="" title=""></p>
<p>上图是从阿拉丁公布的数据报告中截取引用过来的,整个 2018 年,基于小程序生态的融资规模是 80 亿,是 2017 年的整整 8 倍,小程序几乎扎根了所有领域的所有层面,而且除了微信小程序,其他小程序小应用也都在布局:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564468241116-fbe087ba-444d-4658-a968-e352bfb7c289.png#align=left&display=inline&height=1054&originHeight=1054&originWidth=1898&size=0&status=done&style=none&width=1898" alt="" title=""></p>
<p>在整个泛小程序生态崛起的过程中,许多创业公司都主动登船,小菜也不例外,我们是在 2018 年 3 月份开始技术预研和拥抱小程序生态,至此 1 年我们业务上收获颇丰,而技术这里,也略有积淀,就跟大家分享小程序这块我们的思考和沉淀。</p>
<p><a></a></p>
<h2>用原生还是用框架</h2>
<p>小菜前端的个别同学,包括我都有过一些开发小程序的经验,没使用任何框架就用小程序原生语法来实现,但小程序的功能都比较简单,所以也自然没遇到太大的工程挑战,而我们 2018 年要启动的小程序产品具有两个特征:第一个是功能和交互足够的复杂,第二是迭代速度要非常快,两周就要首版上线,之后每周至少发一到两个版本,基于这样的业务背景,我们也就毅然的选择使用框架而非原生,但这个决策带来的后期风险也的确超出了我们的预期。</p>
<p>如果我们再回到一年前做选型,估计还是会选择框架,但至少不会那么乐观的 All in 其中,而是择时机尽早切回原生(虽然我们目前已是半原生)。所以给大家的建议是:如果产品功能相对简单,一二十个页面也没有太奇怪的交互和太大的列表数据量,用框架用原生都可以,开发周期短的话就用框架,实际上市面上看到的绝大多数小程序都不属于是复杂应用,用框架都能很好很快的 hold 住,但反过来假如你要实现的产品交互和前端列表数据量较大,图片图表视频多媒体复杂搜索应有尽有,那么能用原生就用原生。</p>
<p><a></a></p>
<h2>如何选择框架</h2>
<p>框架的核心价值就是效率,一旦我们决定使用框架,那么就要把当下及未来市面上可用的小程序框架,做一个必要的比较和选择,这个过程通常会比较纠结。因为截止到 2019 年,还并没有一个小程序框架足够足够的好,大家都在六七十分上下,那我们可以从哪些方面来考虑呢?</p>
<p>小菜前端最初选型框架主要考虑如下几个方面(都很必要但优先级程度自上向下依次降低):</p>
<ul>
<li>框架的成熟程度与开发效率 - 是否满足产品迭代需求</li>
<li>多端(H5/小程序)的兼容程度 - 是否满足产品的端覆盖需求</li>
<li>配置成本/易用性/拓展性 - 是否满足工程师的工程架构需求</li>
<li>整体性能的表现 - 是否能顶得住复杂交互和大数据列表</li>
<li>团队成员的学习成本 - 是否有必要的人员和技术栈储备</li>
<li>框架背后的团队实力 - 是否有足够好的工程实践和开发支持</li>
<li>框架在社区的沉淀和生态 - 是否有群众基础和社区方案</li>
<li>框架是否是 KPI 产品 - 是否会慢慢 Bug 不修弃坑跑路</li>
</ul>
<p>总体做选型的路子是优先保产品,再看工程质量及合理性,最后看社区及开发者生态健康程度。</p>
<p>很可惜,即便我们考虑了这么多,限于当时(2018 年 3~5 月)的小程序框架生态太过早期也太单薄,我们最终选择了美团的 MPVue(实际上没得选),但上面的参考项今天看来对大家依然是通用的,当时的比对过程我再给大家呈现下,帮大家加深下这个选型运用的过程:</p>
<p>首先针对能否优先保产品,也就是框架成熟程度和开发效率,多端兼容程度这块,我们实际上只有 wepy,MPVue,Taro 可选,针对他们三个,我们是这样比对的:</p>
<ul>
<li>社区生态是否足够活跃</li>
<li>跨端迁移成本</li>
<li>框架核心团队是否背靠大厂,是否是 KPI 产物</li>
<li>开发效率问题,更多是踩坑时间问题</li>
</ul>
<p>其次,针对工程质量与合理性,也就是框架的配置成本/易用性/拓展性,整体性能这块,我们是这样评估的:</p>
<ul>
<li>框架上手成本</li>
<li>底层工程架构基建是否支持到位</li>
<li>性能问题: 先上再说,过得去就好,剩下的就慢慢优化</li>
</ul>
<p>最后,针对社区/开发者生态,也就是团队成员既有技术栈、社区反馈和生态这块,我们是这样评估的:</p>
<ul>
<li>团队成员中是否有人具备相应的技术栈能力</li>
<li>框架是否支持已有的库快速接入</li>
<li>社区对于该框架的反应如何,是否还属于半成品或者存在 Bug 很多的问题</li>
</ul>
<p><a></a></p>
<h2>如何做组件化</h2>
<p>小菜最初的产品端载体主要是 APP 和 PC Web,尤其是 APP,有 7 个之多,所以 RN 的组件化在 2018 年是有过两个大版本的累计了好几十个,但这个对于小程序来讲远水解不了近渴,而小程序的页面数目越来越多,组件复用变成了刚需,所以我们开始了小程序的组件建设之旅。</p>
<p>基于 MPVue 在小程序里写组件,也是比较神伤。因为小程序端代码是静态的(即提前编译好的模版), 所以像 HOC 就没办法用了(还有很多其他一些 Vue 语法糖编译不了), 我们这里用的都是 mixins,基础的 mixins 有很多:</p>
<ul>
<li>函数调用相关(去抖/节流)</li>
<li>列表加载相关</li>
<li>用户基础信息/微信信息</li>
<li>数据初始化相关</li>
<li>分享调用相关</li>
<li>页面下拉/滚动相关</li>
<li>收集 Form Id</li>
<li>授权处理相关</li>
</ul>
<p>基于 mixins 就可以来设计组件了,一旦决定要抽象出一个组件,我们主要考虑如下因素:</p>
<ul>
<li>UI/功能的耦合程度</li>
<li>内外部调用的耦合程度</li>
<li>组合组件(组件间的通信层)</li>
<li>组件性质(基础/业务)</li>
<li>兼容问题</li>
<li>后期扩展能力</li>
</ul>
<p>我们已经沉淀的组件有:</p>
<ul>
<li>上传组件(Upload)</li>
<li>Tabbar</li>
<li>Spinner</li>
<li>Radio/Radio Group</li>
<li>Video</li>
<li>Cell</li>
<li>Input/Textarea</li>
<li>SearchBar</li>
<li>授权/登录弹窗 组件</li>
<li>保存/预览图片 组件</li>
<li>图片懒加载/占位 组件</li>
<li>语音录制/播放 组件(Record-bubble/Record-button)</li>
<li>页面异常状态组件 (102/404)</li>
<li>其他业务组件......</li>
</ul>
<p>这些组件里面:</p>
<p>比如 Input/Textarea 组件,它需要重点考虑 UI/功能的耦合,要如何设计?</p>
<ul><li>组件复杂度高的话,可以切分数据服务层与 UI 层,采用 Mixin 混合抽象方法到 UI 层里。</li></ul>
<p>比如授权/登录弹窗组件,它需要重点考虑内外部调用的耦合,要如何设计?</p>
<ul>
<li>组件需要具备单一职责,不能图方便把很多东西都耦合进去</li>
<li>如何和其他组件配合使用</li>
</ul>
<p>比如 Upload Group 组件,它属于是组合组件,要如何设计?</p>
<ul>
<li>上传发生异常的处理与上抛。</li>
<li>组合层之间调用的 Hook。</li>
<li>注意 Props 的透传与值的双向绑定。</li>
</ul>
<p>比如语音录制/播放组件,它需要组件性质,要如何设计?</p>
<ul>
<li>业务级别的组件,在复杂度高的情况下,也可以考虑切分 UI/数据服务层。</li>
<li>如果通信层较复杂的话,可以考虑类似 redux 的设计,下层组件 dispatch action 到上层,上层统一管理 action 并 分发数据/事件 给下层组件。</li>
</ul>
<p>除此以外,组件设计的时候还要兼顾小程序端上与 Vue 的差异性。比如生命周期(组件与页面),在 MPVue 编译完后, Vue 组件生命周期并不会编译成小程序组件的生命周期,说白了就是需要你熟悉两套生命周期: Vue 组件生命周期与小程序组件/页面生命周期。</p>
<ol>
<li>MPVue 编译完的 Vue 组件生命周期并不会和 小程序组件生命周期的调用一致,比如<strong>第二次</strong>点开同一个页面,非页面级别的组件 <code>mounted</code> 永远只会调用一次(除非你在组件或者组件上层挂了 <code>v-if</code> ),而实际上这个组件在小程序里被调用了两次 <code>attached</code> 小程序组件生命周期。</li>
<li>更不用说 <code>beforeMount/onUnload</code> 的问题了。</li>
<li>页面数据缓存问题,小程序本身会缓存打开过的页面数据,常见场景就是商品详情页面,第二次打开的时候,在进行页面数据更新之前,页面并不是空状态,而是上一次详情的数据。处理的话就有很多种方法了,可以在 <code>beforeMount/onUnload/其他生命周期</code> 里初始化页面数据及置空所有状态,具体就看你怎么设计和抽象了,最主要的目的还是让开发者尽可能少的感知/手动调用。</li>
</ol>
<p>除了要考虑以上这些问题之外,我们还需要去解决端上的兼容问题以及框架带来的问题。</p>
<p>微信端的兼容问题简直是层出不穷,不仅和机型、系统版本有关,甚至还和微信版本有关。所以当遇到这一类问题的时候,我们只能求助于 <a href="https://link.segmentfault.com/?enc=bxJNejYkewlnLWCkOQa16A%3D%3D.sDkZYVTRvKiwqg7m2o7fTKlIZy2HPaoW2BUq2NnCD5NWEynSOZshSbDvX7ZPY1cP" rel="nofollow">微信开发者社区</a>,期待有相应的解决方案。</p>
<p>框架带来的问题有时候就有点恶心了。比如说 MPVue 并不支持动态的传入 <code>input</code> 的 <code>type</code> 属性,这就导致如果我们需要文本键盘、数字键盘、带小数点数字键盘等等这一类的 <code>input</code> 时,我们需要每种类型都写一个 <code>input</code> 组件,平白增加了代码量,并且定位到问题也不方便。</p>
<p><a></a></p>
<h2>逃不过的原生能力</h2>
<p>以上我们探讨了框架选型和组件化设计,最后再回归到我们认为非常核心的一个能力,就是小程序的原生开发和优化能力,MPVue 编译完的代码运行时的性能在很多场景里并不达到你的要求,比如输入组件的双向绑定之光标闪烁/内容回退,,大数据量之操作延迟等等...... (没遇到过的同学<a href="https://link.segmentfault.com/?enc=qujFdyRfLd3p%2Fvywl1v0xA%3D%3D.OPl6fts%2Fdl6by9OPNabez1vcYf7%2FL3fJzlwxUlmDqc1QqhBgg26JWzYjqkpJVPzevU5AZ9LYNYiZlPDz%2Fwl47A%3D%3D" rel="nofollow">自行搜索</a>)。总的来说就是 MPVue 底层对于数据的操作实现的很稀烂,这个问题也只有当我们将项目做大了才遇到。</p>
<p>当遇到类似上面这种性能问题的时候,就避免不了去寻找解决方案。但所谓的解决方案很有限,要么换框架,这时候已经上车,全量换框架工程太过浩大不敢想。要么写原生,写原生不仅工程量也浩大,而且原生代码的复用成本也难度不小,这就是框架选型带来的后续维护成本和风险了。</p>
<p>但问题是躲不过去的,终究要解决。除了上面这几点需要去衡量的之外, 还要衡量一些非技术因素:</p>
<ul>
<li>产品发展形态/可预见的趋势:随着业务的发展以及小程序的权限收缩,为了继续扩大产品的可触达范围,势必会新增更多的端。</li>
<li>用户群体:需要去收集用户的地理信息、手机型号、网络环境等等,综合这些数据去优化相应的点,做到有的放矢。</li>
</ul>
<p>我们最终还是决定当部分组件替换为原生组件,比如:</p>
<ul>
<li>MPVue 写的 <code>input/textarea</code> 在输入的时候就会出现光标闪烁/内容回滚的异常(原因就不赘述了),所以使用小程序原生语法重写了 <code>input/textarea</code> 组件,主要目的就是让组件的输入能够脱离 MPVue 的更新,直接组件内部走小程序的 <code>setData</code> ,因为当时 MPVue 还没有对数据更新做 <code>diff</code> 操作,目前据说做了一层 <code>diff</code> (实际效果大家自己去测评吧)</li>
<li>产品中的文章详情需要 Markdown 渲染,因为文章内容相对来说都是数据量比较大的,使用 MPVue 去对这部分数据进行解析的话性能会相对来说较差。因此我们也使用了原生去实现了一个 Markdown 渲染的组件。</li>
</ul>
<p>其实除了将组件替换为原生组件之外,我们还可以去优化原生的 <code>setData</code> 方法,具体内容可以阅读 <a href="https://link.segmentfault.com/?enc=YXnz%2FxgK%2F2zE2Z2nYPJnGg%3D%3D.pnkvY9UxQSMoq5tCaeUQiukINrjY6Xq%2Fgllq3otnpvVA3k%2FH8eTj3ELy0qyhc87u" rel="nofollow">westore</a> 这个库,进一步提升性能。</p>
<p>最终,我们的架构慢慢就会变成了这样:Vue 会慢慢成为一个数据注入/数据分析/事件分发三者集合的中心枢纽一样的存在,底层是由各种高性能的原生组件,上层是由 Vue 来分发事件给不同组件,注入数据到不同组件里,收集埋点行为/事件。</p>
<p>这样一个现状依然有它新的问题,首先是多端复用成本低,现在还无法一套代码在 H5/小程序里全部通用,其次是小程序原生学习成本还是比框架要高,这对于不熟悉原生的同学都是一个不小的技术学习成本。</p>
<p><a></a></p>
<h2>当下的困境</h2>
<p>当下来看,我们之前选择的 MPVue 已经不能很好地支撑业务需求了。其一是因为 Vue 与我们的主体技术栈的分割,二来 MPVue 并不能支持跨多个平台开发。</p>
<p>跨多平台开发已经是当下的一个迫切需求。假如一个需求需要维护多端的代码,那么势必会需要更多的前端资源投入,这个成本是难以接受的。因此我们也开始考虑到底是使用市面上类似 Taro 这样的框架还是选择自研,两者的选择都有各自的好处。选择 Taro 这样的框架能够让我们迅速进入开发,但是长远来看免不了可能会出现 MPVue 类似的维护问题;选择自研的话虽然不会存在维护上的问题,但是会短期内需要投入更多的前端资源。</p>
<p>以上这些问题就是我们当下遇到的一个困境,选择任何一个方案都可能对将来造成巨大的问题,就比如当初我们选择 MPVue 那样。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=YcFHvMrabnbPGXN4TzUUJQ%3D%3D.HIzbGYCoIccku5SRX%2B2UxACb0nByaBCIxwpaAtIanSA%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
团队建设:创业公司技术团队的影响力如何打造
https://segmentfault.com/a/1190000022294946
2020-04-14T23:00:00+08:00
2020-04-14T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
0
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>互联网区别于传统行业的最大优势之一,是知识传播媒介的变化与成本大幅降低,进而带来认知更新速度的升级。</p>
</blockquote>
<p>本文写在 2019 年初,有当时的局限性(团队规模小,只有 12 个人),依然是偏管理的视角,与大家聊聊 Scott 心目中的技术影响力是什么,为什么要做这件事以及如何来做。</p>
<p><a></a></p>
<h2>小菜在影响力上面的尝试</h2>
<p>Scott 第一次登上讲台做分享,是 2013 年小飞(现: 魔筷科技 CEO)组织的阿里内部前端分享会,关于广告豆腐块的模板化制作里面数据接口加工的封装,第二次是 2016 年去大搜车做 <a href="https://link.segmentfault.com/?enc=IJdcQ31E3DwbUiSZwFBCiA%3D%3D.jk5TnmPqZBiZ7mxBterG4IkEHqoz0jN3fXLoBeQTpiV8zrN6IgSq2fOyVevWX0E9" rel="nofollow">NodeJS 方面的分享</a>,一次对内一次对外,工作的头 6 年极少抛头露面。我非常不喜欢做这种事情,一个是因为我认为技术分享是一件很虚很虚的事情,从来都不屑于去做,一个原因也确实是担心万一讲的不够干货,被人拍砖吐槽名誉扫地。</p>
<p>那为什么从 2017 年 7 月进小菜之后,尤其在 2018 年,Scott 露面这么多次呢(光 18 年就出去分享了 5 次)。真正的原因是,当我在阿里的时候,技术影响力有人在做也不需要我关心,我那时候也不是管理者,自然是屁股决定脑袋不以为然。而当我带团队之后,发现全中国甚至在江浙沪都极少有人知道宋小菜,更是几乎没人知道宋小菜的前端团队。这种情况就导致了招牛人难度很大,团队士气自信心也都不振作,这时候我才意识到技术影响力的重要性。</p>
<p>先来看结果,这是我带团队后,组织的内部外部的分享列表:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563357120641-40a1026a-9441-4941-b153-b4867dddce41.png#align=left&display=inline&height=975&originHeight=975&originWidth=939&size=0&status=done&style=none&width=939" alt="" title=""></p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563357120659-f7085204-2a62-4f40-8f56-959219fa7163.png#align=left&display=inline&height=449&originHeight=449&originWidth=939&size=0&status=done&style=none&width=939" alt="" title=""></p>
<p>互通有无是内部技术分享的直接收益,同时对内可以建立良好的讲师氛围,对外我们把公司团队的影响力在不断做大。2019 年春节后投递的简历中,也有相当一部分童鞋是通过我们的影响力触达后,他才去了解我们团队大概的技术栈、成长环境和研发实力这些因素。我个人是喜欢有目的性求职的同学,通过各种手段去了解一家公司及他的团队,然后再针对性的求职,锁定若干家公司,这样双方互选的成功率会高很多。</p>
<p>以上的我是 Scott,大家发现没,特意在文中重复一个词汇,可以强化记忆力,换言之你的团队曝光度也取决于团队名称在社区的出现和重复次数,如果把这个我换做是你,影响力与你会有什么关系呢?可以给你和你的团队带来什么好处呢?要正确的探讨这两个问题,我们需要先了解下团队的影响力到底指什么?</p>
<p><a></a></p>
<h2>技术团队的影响力是什么</h2>
<p>什么是影响力?一句话形容它大家就有感知了:你可以影响到你老板的决策的能力就是影响力。当然影响力的对象不限于你的老板,也可以分为对内和对外:</p>
<p>对内,是工作上有影响力,比如一个技术方案,你凭借自己的观点可以左右或者影响到他人的决策,这个他人可以是你的下属,可以是你的同事,可以是你的老板,可以是公司的决策层,这个是对内的影响力。而你的团队由于在公司历年来足够的专业性,对某些领域(如算法、可视化、爬虫)非常擅长,那么整个公司在去往某个领域时,脑海中第一个复现的理想顾问一定就是你的团队。</p>
<p>对外你可以让更多人从你的观点中有所收获甚至付诸行动,比如你团队写了一篇技术博客,一个远在三亚的前端同学在看了你的文章后,若有所思,对某个技术观点比较认同,对你的团队的技术研究领域有所印象或者有兴趣,甚至他第二年再次求职时会把你的公司放到择选名单里,那这就是实实在在的影响力。</p>
<p>影响力是一个虚到不能再虚却又实到不能再实的东西,虚是因为它很难量化很难放之四海而皆准,实是因为它存在工作生活行业社区的方方面面,时时刻刻在影响你,比如提到宋小菜前端,很多人就没听过更别提了解了,而我们提到 AntDesign,就能想到是蚂蚁金服的前端很厉害,提到 Facebook,就能想到他们的 React 框架对我工作的重要性,这就是很实在的影响力。</p>
<p><a></a></p>
<h2>影响力与我是什么关系</h2>
<p>影响力是职场必选项么?答案一定是 Yes。那为什么 “我” 没有怎么经营影响力,也没感觉缺啥少啥啊?答案是只有你用心经营了,你才会知道自己本来可以得到更多。</p>
<p>对于影响力的理解,我们脑海中很容易联想到参加技术大会做分享、写书出版这些事,把它具象化,于是就望而却步,觉得距离很远。我没有什么太亮眼的开源项目甚至也没非常体系化的知识结构,去大会分享是不可能的,写书出版更是不可能的,所以影响力与我而言无法落地。</p>
<p>这种不可能的心理预设,让“我”跟影响力之间始终保持着间距,未必讨厌它但至少没办法太去喜欢它,更别提拥抱它了,也就越来越看不清它跟“我”的真正关系。</p>
<p>影响力跟“我”的真正关系是,可以让”我“的能力得到更好的曝光和传播,让别人从我这里得到一定的收获,甚至促成别人跟“我”合作的可能。这种合作的结果可以让我的影响力进一步放大和加强,形成正反馈,即便是你不再持续去经营影响力了,影响力本身也会继续持续相当长一段时间。</p>
<p>既然影响力可以更好的成就你,我也想做了,可是我不善表达怎么办呢,终究是要跟人打交道的,那在我们开始谈如何建设影响力之前,先聊聊影响力与表达的关系。</p>
<p><a></a></p>
<h2>影响力需要强表达么</h2>
<p>我们先回到工程师的个人本身,无论职场内职场外,我们可以把技术这个工种从业者分为几大种:</p>
<ul>
<li>能力型(脑子灵手快活好)</li>
<li>表达型(口才棒会交际话术感人)</li>
<li>思考型(心思缜密默默无闻与世无争)</li>
</ul>
<p>同时具备能力/表达/思考的人是稀缺人才,职场中有但通常比例不高,能力型加思考型在编程的这个行业里比例较高,所谓靠 Coding 吃饭不靠颜值,但通常这个群体是偏弱表达型的。</p>
<p>而事实上,表达型的程序员是更容易在管理岗上大有斩获,因为物以稀为贵,人亦如此,在不善言谈的技术群体里,相对表达不错的人就很容易冒尖被发现了,而思考型的人才更容易走上架构专家岗,走研发路线。表达在职业早期的作用容易被弱化也确实起效甚微(因为还没有靠技术实力足够证明自己),但随着职级变高表达又变得越来越重要,为什么?</p>
<p>因为表达可以让技术影响力快速准确的放大辐射,形成能力的闭环:我知道自己技术好,我能让别人知道我技术好,我能让别人因为我的技术好而愿意跟我合作共事,共事共赢从而进一步佐证我的能力是真的好,于是大家都觉得你很棒的这种印象分便是你的影响力了。</p>
<p>在没有闭环之前,影响力也可以靠技术产出量(常年又快又好)证明出来的,当然靠长期的技术深度和架构(极富难度的技术挑战)一样可以,只不过表达的能力可以加速这一过程。</p>
<p>本文的命题是:创业公司的技术团队影响力如何打造?聊团队之前,我们先把人的影响力聊透。</p>
<p><a></a></p>
<h2>个人的影响力怎么打造</h2>
<p>前面大篇幅我们探讨了表达对于影响力的重要性,但对于个人影响力的形成,表达并不是唯一甚至不是最重要的一项,我们接下来列举几种典型的提升个人影响力,从是否靠谱(以这种方式做出来是否真有价值)、难度指数(实现和执行难度)、影响力(对于个人影响力的提升)这三个维度罗列下,看看各自优劣。</p>
<p><a></a></p>
<h3>1. 做出个惊天地泣鬼神的项目并商业化</h3>
<ul>
<li>靠谱指数:※※※※※</li>
<li>难度指数:※※※※※</li>
<li>影响力指数:※※※※※</li>
</ul>
<p>用事实说话,如果这个事实是可以用金钱衡量的,那么金钱越多,事实越成立。如果你靠自己的技术实施了一个项目,把它商业化了,卖了出去,那么毋庸置疑,你的技术价值最大化的影响力一下子就建立了,简单直接粗暴。</p>
<p>事实是,无论你的项目是卖 100 块,还卖 100 万,只要商业化成立,那么这个结果对于影响力的形成都是正向的,所以大家培养自己产品/商业/业务/设计的 Sense,始终都是个好习惯。至于说商业化的是你的代码方案,还是你的工具系统,还是把技术的专利卖掉,还是被很多公司邀请付费做技术培训,还是写一个小册或者课程在网上售卖,亦或是别人请你写一个网站,可能是硬资产可能是软技能,只要这个广义的项目能被金钱的数字衡量,那么影响力通过商业化变强都是成立的。</p>
<p><a></a></p>
<h3>2. 参与开发一个项目并开源</h3>
<ul>
<li>靠谱指数:※※※※</li>
<li>难度指数:※※※※</li>
<li>影响力指数:※※※※</li>
</ul>
<p>有机会参与一个开源项目并不一定让影响力变强,除非你是主导的角色,或者核心骨干的角色,甚至是核心推广和运营的角色,这个项目的开源因为你的参与而变得更有价值这一点只要成立,你的影响力自然就建立了。</p>
<p>事实是,往往早期的工程师并没有足够的实力去设计一个优秀的项目并开源,可以选择的做法是平时多收集工程与业界的痛点,然后把基于痛点思考后的想法,把它进行提炼不断缩小他的边界,然后从很小很小的工具开始做,比如一个自动下载 Youtube 视频的命令行工具,诸如此类的小项目,从项目的功能设计,API 设计,用户研究甚至是 UI 设计以及代码的规范程度,来不断的练习自己开源的能力,直到某天一个崭新的项目冉冉升起。</p>
<p><a></a></p>
<h3>3. 在行业中布道分享</h3>
<ul>
<li>靠谱指数:※※※※</li>
<li>难度指数:※※※</li>
<li>影响力指数:※※※</li>
</ul>
<p>把自己技术上沉淀的思想或者方案,通过技术大会、线上线下的沙龙讨论、甚至是小圈子的技术交流等等方式,输出给在场的人,再由在场的人把你的影响力间接的辐射给他的社交圈里面,以此不断的在行业发声,从而塑造出特定人设的个人影响力。</p>
<p>事实上,我们最乐于做的就是去大会做个分享,因为它看上去更直观更容易实施,但往往结果只能跟与会童鞋有一些简单的交流沟通,很多时候只是混个脸熟无法进行深入的技术观点碰撞,更多是直接了当的以技术成果作为载体,向业界输出自己的影响力,也是比较简单粗暴,越大型的会议,影响力的传导越强。</p>
<p><a></a></p>
<h3>4. 著书立作开门开派</h3>
<ul>
<li>靠谱指数:※※※</li>
<li>难度指数:※※※※</li>
<li>影响力指数:※※※</li>
</ul>
<p>按道理讲,写书会被技术分享更能站得住脚,但由于技术迭代的周期越来越短,加上写书的时间成本与难度较高,导致比起技术分享,它的影响力辐射速度和效果还要稍弱一些。</p>
<p>但是越慢的事情越扎实,你可能不记得某年某月某某某做的一场技术分享,但你会记得这个家伙写过 5 本技术书籍,这是货真价实的影响力,虽然有一些书籍比较水难入法眼,但不影响他有特定的用户市场,有特定的用户价值,因为技术人也拥有文人的气质,而文人总是相轻。</p>
<p>我们从商业化到开源,从技术布道分享到著书开派讨论了个人技术影响力的塑造可行性,还有太多太多的方式,大到去往一个到公司带领一个部门通过技术驱动竞争格局变化,小到一个微信群里对某个技术发表思考后的观点,都可以不断的加强自己的影响力。</p>
<p>而我想给大家分享的是,抛开这些术,影响力修炼的道就是:把自己脑海里技术深思熟虑之后,通过各种载体传达给业界,前者靠实力,后者靠技巧,在实力和技巧之外,要靠自己的一点点厚脸皮和持续练习。</p>
<p>打开了个人影响力的脑洞后,我们再来看团队影响力,答案就呼之欲出了。</p>
<p><a></a></p>
<h2>团队的影响力怎么打造</h2>
<p>创业公司的技术团队,通常的特征是没人、没钱、没资源、没沉淀,甚至没时间没精力没意愿。这可能是一段非常恐怖的起步时期,流失率/成长空间/团队综合效率最大化都是 TL 面临的棘手问题,而破除这些困难的其中一条路就是:在工作技术中积极充分思考与建设,形成技术成果,再反馈给业界,最后从社区收获认同,同时收获更多将来可能来公司应聘的种子粉丝,这个正向影响力的建设与收获是互为促进,互相成就,同时也离不开公司层面的高度支持。</p>
<p>团队的影响力衡量单位通常是:xx 公司 xx 团队的某某某,以及 xx 公司 xx 团队的某某方案,所以团队影响力包含两个重要的组成部分:技术明星及技术成果。</p>
<p>要打造有影响力的团队,这两条线可以并行,也可以有先后也可以只有一条线,首先靠技术明星的打造。</p>
<p>方法一就是招聘,把业界已经知名的有影响力的技术明星招聘过来,这样整个团队会跟着闪闪发亮,另一种方式就是从团队内部走出来若干个技术明星,他可以是讲师,可以是某本书作者,可以是某个技术方案的设计者,甚至可以是非常擅长组织大会的筹办者,通过他的能力,把更多团队内的技术财富与观点,不断的传递给外界,这个过程中,他的个人影响力会迅速形成,而形成的过程中,团队的影响力也就水到渠成了。</p>
<p>方法二就是技术成果,比如 AntDesign/MPVue/Taro 等背后都是一个技术团队的成员在开发维护,它的背后可能有很多技术明星,也可能一个没有,但这个项目本身就足够璀璨,这个团队的整体观感就变虚为实,从远及近了。</p>
<p>而小菜前端在 2017/2018 年尝试了招聘技术明星和培养技术明星,以及更高频的自己举办大会和参与大会技术分享外,从 2019 年,我们来尝试一个更高难度的事情,就是以团队的名义来把非敏感的技术总结商业化,在掘金上写了一本小册,通过这本小册为团队赚取的团建基金其实是额外收益,更多的出发点是让整个业界更了解宋小菜,以及更了解宋小菜的前端团队,知道我们这个团队,大家的做事方式,看待业务和技术的态度,对待技术人成长的考量,以及我们在团队整体技术上的探索和沉淀,为所有处在早期尚未规模化的团队,提供一个团队的组建原型与趟坑实践。</p>
<p>以此,我们会收到业界更多的反馈,这个反馈就是我们团队影响力的佐证,如果我们这个模式探索成功,大家也可以尝试把自己团队的技术总结小册化,系统化回馈给社区,我相信这是一种投入产出比很高的影响力塑造方式。</p>
<p>以上,就是我对于创业公司技术团队与影响力打造的思考,希望能帮到大家拨开困惑,不再摇摆,想做就动手去做。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=Km30XRnJRjkX2bjWDyjwSA%3D%3D.rgHCXbt8SheXQLRJk52OzWgWbkCitfGzvhfDxjmt0aw%3D" rel="nofollow">关注 Scott 跟进我的动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
框架设计:PC 端单页多页框架如何设计与落地
https://segmentfault.com/a/1190000022294910
2020-04-13T23:00:00+08:00
2020-04-13T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
4
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>框架的价值更多体现在应用层次上面,是一种整合作用,通常框架是一套大而全的特定问题域的解决方案,它与库的主要区别无外乎控制反转、可扩展性和不可修改,尤其控制反转是框架具备的典型特征:在框架里面,程序的控制流程不由调用者决定,而由框架决定,而对于若干相似的库,调用者可以自由切换库和选择性调用库 API,再直白一些,框架是一套规范而库是一堆砌方法。</p>
</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564992932525-60af0eab-2700-4544-b721-7400720ed3b7.png#align=left&display=inline&height=1082&originHeight=1082&originWidth=2824&size=0&status=done&style=none&width=2824" alt="" title=""></p>
<p>每个团队都有一个框架梦,我们也不例外,只要遇到的足够复杂的问题,对团队的整体效率与稳定不断造成冲击的时候,往往就是去做问题归纳和推出框架的时候,这次我们聊一聊关于 PC 网站的网页前端开发方案,我们遇到的问题和对于框架的初步尝试,为保持给大家轻松的阅读体验和更宽的视角,本文不会深入代码细节,至于源码将来我们某天开源后大家便可一睹芳容。</p>
<p><a></a></p>
<h2>启动框架的初心</h2>
<p>一切技术决策皆有特定业务背景,我们在日常的开发中,主要面临如下三类场景:</p>
<ul>
<li>中后台的单页 PC ERP/CRM 等系统,上百种权限的十几个角色在后台各自的工作界面,每个角色都有十几个到几十个独立页面的业务流程,比如物流专员的发车调度、销售助理的加价推新等等,对于这些系统有可能是一个独立入口的 SPA,也有可能是多个独立入口的多 SPA 集合,在同一个仓库内维护</li>
<li>前台的 PC 网站,几十个关联性不强的页面,没有太复杂的逻辑,主要做展示,比如公司官网</li>
<li>在手机浏览器上的 H5 网站,几十上百个有强业务逻辑的页面,也有角色的区分,比如有交易业务的移动版商城</li>
</ul>
<p>在小菜前期三四年的创业历程中,我们扎根在销地做撮合型的 toB 交易,所有的协同流程都移动化,交易也依托于独立的 APP,彼时也正是移动互联网崛起的时候,我们对于 PC 系统的建设和沉淀比较简单粗暴,公司中台只有一个囊括了几乎所有角色的 ERP(含 CRM 部分功能)后台,上百个页面,jQuery 与 React 共存, 通过 webpack 设计了多入口的打包方案,每一个独立的子系统(面向某类角色的业务流程页面)都独立打包,但随着我们的业务规模攀升和生鲜供应链的上下游打通,业务场景越来越多,特定层面的业务越来越垂直细分,包括中台和工具层面的建设,整个大中台开始有了雏形,十几个后台 PC 系统像雨后春笋一样快速启动,仓促上线,同时数量上也丝毫没有没看到减速的态势,我们必须有一套标准方案在做到快速的复制来降低重复开发与维护的成本,不为炫技只为解决问题就是我们的初心。</p>
<p><a></a></p>
<h2>遇到了那些挑战</h2>
<p>在这样的业务背景下,我们遇到了巨大的挑战,主要是如下几方面:</p>
<p><a></a></p>
<h3>生态丰富却失去约束</h3>
<p>我们知道 React 自身单薄,但是周边生态异常丰富,每有一个新特性出来就会多出非常多的轮子,在眼花缭乱的周边中,我们早期也迷失其中:</p>
<ul>
<li>在跨组价通信和状态管理上,我们用过 context、event-emiiter、redux、mobx 还有基于 redux 包装的 rematch等,比如 16 年起 redux 异步解决方案就有非常多的轮子:thunk、saga、redux-observable 等,而在中后台项目,尤其是 CMS 类型项目,几乎不会涉及竞态的问题,有些方案实现的有点牛刀杀鸡</li>
<li>在 css in js 方案上,有原始的 sass/less scope 方案、css modules 、 style-components 、jss 等同样让人眼花缭乱,很容易选择新的和舍弃旧的</li>
<li>在路由上,有 react-router 、reach-router、react-navigation 等。我们虽然沿用了 react-router, 但也不舒适,在路由权限这里我们自己完全去定制开发</li>
</ul>
<p>整个过程趟过来,我们会发现 react 周边工具都能衍生出自己的生态,这样的裂变组合,导致我们前期的前端工程千奇百怪,交叉开发时,进入的新同学理解成本很大。</p>
<p><a></a></p>
<h3>基础环境升级困难</h3>
<p>当我们想要享受到基础工具升级带来的好处,比如早前 webpack2 的 tree shaking,webpack3 的 common chunks 策略更改,那么每个项目都需要升级一遍,就会陷入重复开发的泥淖中,而这些对于业务的同学最好是弱感知的,可以获得更好的开发体验,效率和开发幸福感自然会提升。</p>
<p><a></a></p>
<h3>代码无分层,测试难</h3>
<p>早期的代码是一个巨大的 class,数据请求对象也揉在 class 内,这个 class 会变得非常大,不可维护。按照关注点分离的原则,UI 层和数据层应当分离,只有这样,UI 测试和数据层的测试才能独立,多人开发才能成为可能。</p>
<p><a></a></p>
<h3>工具函数散落 没有版本管理</h3>
<p>前端和后端基于网关通信,我们会封装调用网关的请求工具,而各个项目都有自己的实现,一旦出问题,不仅排查起来没有规律,也无法集中解决,维护性很差。</p>
<p><a></a></p>
<h3>开发环境差异化</h3>
<p>当出现很多内部子系统时,每个系统启动命令和打包命令都不一致,让我们的心智成本非常的高,这个在我们开发了前端发布系统后暴露的尤其严重,我们取消了本地发包发布,都转移给运维发布平台去做执行,但在迁入发布平台时,每个项目的发布命令不同,就需要写出不同的运维脚本,完全是差异化的规则,并且一旦遇到紧急线上重启项目,还需要逐个分清楚它的命令参数,效率很低。</p>
<p><a></a></p>
<h3>新启项目慢 响应业务的速度慢</h3>
<p>那么多内部系统,每新启动一个 PC 系统,从登录到本地用户态与网关的保持,与权限系统的对接(限制页面的路由访问层级),整个系统的工程目录重新梳理等等各方面重新来一遍,整个配置过程弄下来一天就过去了,偶尔还碰到 webpack 和 babel 的bug,让新项目的搭建非常的耗时。</p>
<p>问题多多,全部总结下来就是随着系统的变多,没有框架约束的项目会面临三个问题:维护性差、效率低、扩展性差。</p>
<p><a></a></p>
<h2>如何给框架定位</h2>
<p>针对上述问题,我们希望在复用性、规范性、可维护性上产出一套方案,重点不是做出一个什么框架,而是系统解决掉前端工程上的这些问题,所以我们并不纠结这个框架的自研程度或者概念上的正确性,它一定是逐年逐季度迭代的,也一定会随着业务不断受到巨大挑战甚至某一天会夭折,但在特定的连续时间段内,能解放我们的成产效率,为业务带来更好的支持,它的目的就达到了。</p>
<p>因此结合我们业务多变,系统繁多,中后台居多的特征,我们把这个框架定义成:轻量级框架 + 自助餐搭配,具体的意思如下:</p>
<blockquote>轻量框架 = (工程化工具包 + 模板市场) * 可升级<br>工具包 = 开发工具 + 上线工具 + 监控工具<br>模板市场 = 中后台项目 + 轻量工程(例如官网首页)+ H5 工程</blockquote>
<p>它可以兼容到我们的中后台项目以及 H5 工程,同时能搭建轻量级的非 SPA 工程,不能囊括进来的项目就不用该框架搭建,同时它对新人同学足够的友好。<br>模板市场会承载一部分无法纳入框架管理的定制需求,满足解决不同场景的需要,例如 H5 和 PC 的模板不同,最典型的便是兼容性要求不一样。</p>
<p>具体程序载入的策略和执行的策略则交给框架去约束,简单说就是业务代码按照框架的约定(实现框架的接口),就能让你的业务代码程序跑起来,不按我的约定,就不能跑起来,更别提上线了。</p>
<p>我们想要达到的效果是:业务开发不用关心基础环境的任何问题,基础环境有 bug,只要提出 issue,解决后直接升级基础框架即可。提高开发效率,减少解决重复 bug 的情况,最终提高业务响应速度。</p>
<p><a></a></p>
<h2>如何设计工具包</h2>
<p>上面的工具包载体就是 cli (command line tool), cli 的功能块如下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564992932545-401e80d9-3092-4e0a-b0c3-85bf5f389747.png#align=left&display=inline&height=990&originHeight=990&originWidth=1448&size=0&status=done&style=none&width=1448" alt="" title=""></p>
<p>这里简单地介绍下 cli 相关的命令,cli 的交互式命令行依赖了 2 个核心的三方包,分别是:</p>
<ul>
<li>commander: 用于处理命令行内的参数</li>
<li>inquier: 处理交互式命令行的问答</li>
</ul>
<p><a></a></p>
<h3>init</h3>
<p>在 init 阶段选择需要初始化的模板(模板来自模板市场,现在可以简单认为模板市场就是一个代码仓库)根据选择的类型去仓库内拉取相应的代码,然后安装 node_modules 包,整个工程就搭建起来了。</p>
<p><a></a></p>
<h3>dev</h3>
<p>dev 则是启动本地开发环境,有时我们需要本地启动不同的环境查看效果。在命令行设计时,我们可以针对常见的三个环境做不同的启动命令。如启动测试环境 dev:test, 就会依赖项目中针对不同环境配置的参数做整体替换。</p>
<p><a></a></p>
<h3>build</h3>
<p>build 则是打包本地的项目,也同样可以根据不同环境做不同的打包策略。</p>
<p><a></a></p>
<h3>deploy</h3>
<p>可能大多数公司也会从这个阶段过渡过来,所以提一下。在早前没有接入发布平台前,我们是本地发布的,html scp 到应用服务,静态资源走CDN,此时的 deploy 也需要针对不同环境做不同的打包策略。接入发布平台后,这个命令就应当被废弃了。本地打包带来的问题非常多,服务器权限、lock问题、协作效率等等。</p>
<p><a></a></p>
<h3>test</h3>
<p>依托 jest 对项目进行关键点的测试。测试固然非常重要,想做到100%覆盖率则会耗费非常多的时间,我们不强求100%覆盖,只要求对工具函数和业务组件做到覆盖。</p>
<p><a></a></p>
<h2>对 webpack 的思考</h2>
<p>前面我们简单介绍了几个常用命令,dev、build、deploy 都和 webpack 强相关。我们常常会将 webpack 相关的命令都放在 package.json 内,webpack 也同样存在于项目内。但这样就会出现之前所说两个问题,分别是<strong>基础环境重复配置</strong>和<strong>暴露基础环境配置容易被修改</strong>,最终业务项目各自为政,难以维护。</p>
<p>所以,我们需要对业务开发者屏蔽 webpack 配置,将 webpack 的配置放入 cli 的工程内,当在业务项目中调用全局的命令时则根据响应的对应的子命令参数,获取对应的 webpack 配置。</p>
<p>将 webpack 的配置收敛在全局则会出现无法扩展的问题,为了满足不同业务项目的需求,我们约定在业务项目的根目录内存放一份配置文件,在调用命令时会先读取响应的配置合并到内存中,这里会涉及 webpack 配置合并的问题, 可使用 webpack-merge 或者 webpack-chain 这样的工具进行合并。</p>
<p><a></a></p>
<h2>工具链辅助</h2>
<p>框架周边一定是围绕着各种工具链,并且它的重要性不亚于框架本身:</p>
<p><a></a></p>
<h3>关于效率</h3>
<ul>
<li>数据 mock mocks.js 定制</li>
<li>简化路由配置 glob 读取文件夹作为路由</li>
<li>所改即所见 webpack-dev-server 的 hotreload(H5 营销活动系统)与保持状态的 react-hot-reload(长业务流程需要保留state)</li>
<li>代码生成器 定制生成 pageFile、service、model 文件的命令</li>
</ul>
<p><a></a></p>
<h3>关于质量</h3>
<ul>
<li>code lint 基于 eslint 定制,配合 husky 做到开发时、提交时、上线时的校验</li>
<li>提交规范 commit-lint</li>
<li>指定代码规约做 code review</li>
</ul>
<p><a></a></p>
<h3>发布</h3>
<ul>
<li>
<p>缓存策略</p>
<ul>
<li>动态资源 html 放应用服务器,走协商缓存</li>
<li>静态资源 hash化,放入 CDN,走强缓存</li>
</ul>
</li>
<li>
<p>发布策略</p>
<ul>
<li>html scp 上传到应用服务器,这件事前期是项目负责人本地发布,后期是发布平台操作</li>
<li>cdn 资源 hash 化,永久缓存</li>
</ul>
</li>
</ul>
<p><a></a></p>
<h2>如何做到可升级</h2>
<ul>
<li>基础配置收敛进全局</li>
<li>通用组件、工具函数用 npm 包管理</li>
</ul>
<p>cli 遵循语义化,升级与否由开发者自己决定。为了及时通知到开发者,我们可以在 npm run dev 脚本里加入一段脚本用于 check 本地 cli 的版本和最新的cli版本是否一致,如果不一致则吐出 CHANGELOG 的链接,然后由业务开发同学阅读后选择是否升级。</p>
<p>光是解决基础环境的升级还不够,在业务系统中我们将通用的请求函数、异常处理、通用的组件也统统抽成 npm 包,各个业务团队利用 npm 语义特性可以进行无痛的升级。所以,鼓励将业务中搜集到的问题和好的解决方案抽出并发布 npm 包。</p>
<p><a></a></p>
<h2>关于模板市场</h2>
<p>利用 yeoman 定制相关的 templates,而各个模板需要各条线的业务同学贡献过来,目前使用最多的是中后台的项目,因此质量最好的中后台相关的。</p>
<p><a></a></p>
<h3>React 的工程化</h3>
<p>前面所讲的是工具包相关的,这部分讲讲业务代码部分的工程化,工具是开发效率的利器,虽然开发环境问题已经被 cli 解决,工程化规范是保证业务项目牢靠的关键,需要一套规约。</p>
<p><a></a></p>
<h3>自助餐清单</h3>
<ul>
<li>css in js: jss 搭配 less/sass</li>
<li>状态管理: rematch</li>
<li>路由:react-router</li>
<li>ui 库: ant-design</li>
<li>测试框架:jest</li>
<li>mock 工具:mock.js</li>
</ul>
<p><a></a></p>
<h3>简版工程结构</h3>
<pre><code class="bash">.
├── assets // 全局的静态资源
│ ├── icon
│ └── index.js
├── components // 全局的components
│ ├── index.js
│ ├── menu
│ │ ├── index.js
│ │ └── index.less
│ └── slider
│ ├── index.js
│ └── index.less
├── pages // 页面,约定每一个页面都是一个路由
│ ├── 404
│ │ └── index.js
│ └── user
│ | ├── service.js // 存放本页面需要的数据请求对象和业务逻辑
| | ├── models
| | | └── index.js //存放本页面自己的 rematch model 文件
| | └── index.js
| └── login
│ └── index.js
├── routes // 自动路由配置
│ └── index.js
├── services // 存放数据请求对象
│ ├── index.js
│ └── user
│ └── index.js
├── store // 状态管理
│ ├── index.js
│ └── models
│ └── user.js
└── utils // 工具函数</code></pre>
<p>工程结构按照功能结构划分,没有将所有的分层文件提升到最顶层,减少来回切换的心智成本,并且明确了服务层,既解耦界面和逻辑,又方便测试。</p>
<p><a></a></p>
<h3>路由权限</h3>
<p>路由权限上,我们会从后端拉取当前用户拥有的路由表,在 react-router 加入 component 处加入路由级权限校验的逻辑。</p>
<p><a></a></p>
<h3>状态管理</h3>
<p>关于状态管理,我们选择了 rematch,简单易用,也刚好够用,适合的就是最好的。状态管理可以让数据和逻辑抽离 UI 层,可以做到更高的测试也降低了巨型 class 组件的维护成本。</p>
<p><a></a></p>
<h3>服务层</h3>
<p>服务层存放数据请求对象,即请求接口。除此以外,一些较重的业务逻辑也会放入 service 内管理,我们希望状态管理竟可能轻量,将其中较重的逻辑收敛入 service 中管理。这么做的目的:</p>
<ul>
<li>复用一些 comb 的接口</li>
<li>态管理层的心智负担,例如一些字段的default</li>
<li>方便测试一些关键业务点</li>
</ul>
<p><a></a></p>
<h3>与后端交互</h3>
<p>RESTFul 部分抽出公用的网关工具函数并放入私有的 npm 包进行版本管理,GraphQL 部分抽出 pc 版的 gpm 包对接 GQServer。</p>
<p><a></a></p>
<h3>单页和多页</h3>
<p>从 webpack 配置上看,除了入口配置有点不同,其他部分几乎是一样的。单页通常适用于业务之间联系较为紧密的整体应用,例如CRM系统。多页则适用于页面非常多,并且彼此之间没有太多关系的应用,例如营销 H5 系统。</p>
<p>中后台系统中我们应该按照业务域划分出各自的子系统,不应该将全部的页面都放入同一个工程。起初内部的 ERP 系统从 Java VM 模板中迁移出来,不得以用多页形式进行过渡。现在切出业务子系统,各个小系统由各个小团队自己维护,解耦且拥有单页良好的体验,越来越多的业务子系统的启动,也是我们做框架的必要性之一。</p>
<p><a></a></p>
<h2>总结</h2>
<p>实现框架的全链路建设是一个长周期的事情,需要持续不断的投人力进去,虽然听上去很高大上,但执行起来还是相对琐碎,尤其是框架推出阶段和升级阶段,基本上框架的实现者就是在当客服,当然相对优质的升级文档或者版本间的兼容程度会降低这种工作量,无论怎样,对于团队来说,有大量业务场景支持的框架会迸发它更大的价值,对于个人来说,参与框架的建设是一个很考核全方位能力的过程,而对于所有使用框架的同学来说,则多了一个顺手的工具同时也多了一个可以学习的封装范例,也正因为如此我们对于这件事情持 open 的态度,目前我们只是实现了它的从 0 到 1,还有监控集成、单元测试覆盖、发布系统接入、差异化打包方案、系统模板平台等等很多有意思的方向还没有更多的同学加入去共创去建设,还有相当长一段路要走。</p>
<p>:::info<br>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=ZT%2FtIRi1eTjjesIlZ7quXg%3D%3D.8elsGR185NjMBlC8L10hiChsExHtq5SkwmV6ZaD6ezk%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。<br>:::</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
框架设计:RN 端的框架如何设计与落地
https://segmentfault.com/a/1190000022294766
2020-04-13T23:00:00+08:00
2020-04-13T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
9
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>线下越重,线上需要越轻,这个轻指的是轻便轻巧和简洁易用,B2B2C 生鲜领域在线下是如此之重,那么在交易场景线上化的过程中,端的移动化就势在必行,试想一下,让菜市场摊位老板人手一台笔记本点开网页选购支付,让采购销售抱着电脑去拜访客户,一边聊蔬菜行情,一边打开笔记本进行记录,有没有一种回到世纪初的感觉。</p>
</blockquote>
<p>产品的移动化,这将是我们展开这篇文章的背景,我们会先了解小菜的产品托管在哪些端上,然后感受这些端带来的挑战,最后是我们聚焦如何做移动端的框架封装,包括必要的基建部分。</p>
<p><a></a></p>
<h2>小菜大前端的端有哪些</h2>
<p>小菜早期围绕着蔬菜销地以客户集单批发的模式摸爬滚打几年,从上游的蔬菜供应商到下游批发市场的摊位老板,在这个长长的链路中,我们诞生了这样几款线上产品来服务于不同的人群和场景,之前文章中也有介绍,这里再汇总一下,共 9 款 App:</p>
<ul>
<li>宋小菜 服务于销地批发老板的下单工具</li>
<li>宋小福 服务于小菜内部销售团队的 CRM 销售管理与客户管理工具</li>
<li>宋小仓 连接司机-物流-采购-销售的蔬菜在途位置监控工具</li>
<li>采秘 服务于小菜内部采购团队的蔬菜品类采购工具</li>
<li>麦大蔬 服务于上游蔬菜供应商的大宗农产品交易平台</li>
<li>宋大仓 服务于上游囤货配资的进出库管理平台</li>
<li>云掌柜 服务于产区加工厂进销存的移动 Saas</li>
<li>卖大蔬 服务于产销行情与货源泛用户的内容小程序</li>
<li>行情宝 服务于产销两地的内部行情采集和预测工具</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564651585718-f1d0eee6-75be-4ea0-bd52-731d183c3e03.png#align=left&display=inline&height=1194&originHeight=1194&originWidth=2144&size=0&status=done&style=none&width=2144" alt="" title=""></p>
<p>前 7 款 App 都是基于 ReactNative 开发的 iOS/Android App,最后两个是微信小程序,它们涵盖了公司几乎所有的协同场景和工作流。</p>
<p><a></a></p>
<h2>多端带来的技术挑战</h2>
<p><a></a></p>
<h3>1. 【物理现状】移动端的碎片化</h3>
<p>古典互联网时代,因为要兼容 IE678 而痛苦不堪,Hack 黑魔法经验基本代表前端水平,如今互联网早已移动化,我们理想中的移动端开发,看上去是可以大胆使用新语法特性,只需要做好尺寸兼容就好了,但事实并非如此,不仅在移动端的浏览器不是如此,在移动端开发 RN App 也是如此,这是我们某一款 App 一段时间内,所收集上来的手机厂商分布:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1564651585717-8c62b596-ea6b-47db-8c9a-f01773fa4de0.png#align=left&display=inline&height=996&originHeight=996&originWidth=1508&size=0&status=done&style=none&width=1508" alt="" title=""></p>
<p>可以发现 Android 的碎片化非常严重,每一个厂商下面有不同时期推出的不同型号的手机,这些手机有着不同版本的操作系统,不同的分辨率和用电策略,不同的后台进程管理方式和用户权限,要让一款 App 在哪怕头部 40% 的手机上兼容,都是一件艰难的事情,这个客观物理现状叠加下面的社区现状,App 质量保证这件事情会变得雪上加霜。</p>
<p><a></a></p>
<h3>2. 【社区现状】技术框架的不稳定性</h3>
<p>回到本文的开头,我们在长链路的 B2B 生鲜场景中,为了更快更轻,开发出了 7 款 App,而且将来随着业务场景的拓展会诞生更多独立 App 甚至是集大成的 App,所以技术选型不太可能选择原生的 Java/Object-C 开发,尤其对于创业公司,7 款 App 得需要多少名原生开发工程师才能搞定,高频繁重的业务变化又怎样靠堆人来保证?</p>
<p>想清楚这些,一开始我们就调研 ReactNative,并最终全部从原生切换到了 RN。通过跑过来的这 4 年来看,使用 RN 为公司节约了大量的人力成本同时,也尽可能的满足到了几乎所有的需要快速迭代的业务场景,又快又轻,成为宋小菜大前端团队做事的一个典型特征。</p>
<p>但换一个角度看,就是带来的问题。又快又轻的背后是 RN 版本的飞速迭代,截止到目前,也就是 2019 年 4 月份,RN 还没有推出一个官方的正式的长期维护的稳定版本,什么意思?就是 RN 目前依然处在不稳定的研发周期内,我们依然站在刀尖上起舞,用不稳定的 RN 版本试图开发稳定的应用。四年走来,我们在 RN 的框架里,多少次面对旧版本局限性和新版本不稳定性都进退不得,旧版本的 Bug 可能会在新版本中修复,新版本引进则会带来新版本自己的问题。</p>
<p>除了 RN 自身版本,还有第二个问题,围绕着 RN 有很多业界优秀的组件,但这些社区组件甚至官方组件,都不一定能及时跟进最新的 RN 版本,同时还能兼容到较老的 RN 版本,所以 RN 升级导致的组件不兼容性,会引发你 Fork 修改组件的冲动,但这样会带来额外的开发成本和版本维护成本,取舍会成为版本升降的终极问题。</p>
<p>在国内开发,还有第三个问题,就是中文文档缺乏,社区资源匮乏,参考文献陈旧,可拿来主义的开源工程方案甚至社区线上线下会议分享都很缺乏,一个不小心就会踩坑,这就是 RN 社区的现状,我们在刀尖浪花上独步,App 选型背后的技术栈稳定性则成为悬在头上的一把铡刀,你不知道什么时候会咔嚓一声。</p>
<p><a></a></p>
<h3>3. 【人才现状】人员能力的长短不齐</h3>
<p>我们知道有一个词叫做主观能动性,表示没有条件创造条件也可以上。这个词的主体就是人,聊完移动端设备现状和社区现状后,我们来聊聊人的问题。RN 在国内真正开始普及使用,是从 2015 年开始,也就意味着,到 2019 年,一个 RN 工程师最多也就只有 4 年的工作经验,而 RN 的 “Learn once, write anywhere” 也刺激着一切 Care 人员开支, Care 产品研发投入性价比的公司纷纷跳水研究 RN,争抢 RN 人才,RN 是前端中的移动前端,前端有多抢手,那么 RN 工程师就比它还要抢手。</p>
<p>这就导致基本上 RN 工程师很难靠外部招聘,只能靠内部培养。这也是小菜前端的成长历程,我们有 2 名资深 RN 工程师,一个是从服务端 Java,一个是从原生 Android 开发转过来的。如果 RN 人手不足,产品支持的力度和速度就一定会遇到瓶颈,这就是我们曾经面临的问题,就是人才现状,外招数量不足,内培速度有限,RN 工程师的数量和能力就时不时成为公司业务扩张的瓶颈。</p>
<p><a></a></p>
<h3>4. 【公司现状】高密集业务的交付质量</h3>
<p>作为工程师,我们有很强的自尊心和不容挑战的代码洁癖,但在一个创业公司里面,甚至大公司的一个创业团队里面,我们需要对接一些关键的业务节点,冲刺一些特定的时间窗口,并且要及时响应多变的业务,和业务背后多变的产品形态,这都会带来非常密集的需求队列。</p>
<p>这些密集的需求队列对我们的代码质量有非常高的挑战,一个组件用 5 分钟思考如何抽象和用 50 分钟思考,实现后的稳定性、兼容性都是不同的。如何保证产品按期交付上线,会是摆在我们面前一个非常关键的命题,而这个难题之外,还有一个更难的命题等着我们,那就是如何保证交付不延期的同时,还能保证交付质量。</p>
<p>要知道,如果一个项目代码赶的太毛糙,后期维护起来的成本会是巨大的,甚至只能用更高的成本重构重写。本质上,再次重构就一定是公司在为早期的猛冲买单,为这些技术债买单,如何不去买单或者如何用最小的成本买单,这跟我们早期的业务密集程度,交付周期,质量把控有很大的关系。</p>
<p>综上,移动端碎片化所带来的兼容难度,RN 框架的局限性,版本间差异带来的不稳定性,技术社区资源的匮乏和前端团队技术能力掣肘,再叠加上高密度的业务排期,让前端开发这个本来很酷的事情,变得晴雨不定。</p>
<p>这些避不开的现实,是绕不过去的坎儿,必须通过人才储备和技术基建来缓解,接下来我们进入到本文的重点 - RN 框架的封装。</p>
<p><a></a></p>
<h2>RN 的 App 工程如何架构</h2>
<p>RN 的 App 工程骨架,全部抽象完毕,再搭配上组件化,就可以称为一个基于 ReactNative 定制的 App 框架了,而 RN 涉及到原生层面的技术细节太多,我们暂不做讨论,只专注在工程与业务的封装上。</p>
<p>我们在构建 RN App 工程时需要关注这几个关键要素:</p>
<ul>
<li>配置管理</li>
<li>静态文件管理</li>
<li>网络请求</li>
<li>组件管理</li>
<li>路由管理</li>
<li>数据缓存</li>
<li>App 的热更新</li>
<li>数据搜集</li>
<li>应用状态管理</li>
</ul>
<p><a></a></p>
<h3>1. 配置管理</h3>
<p><strong>配置管理</strong>是指可以灵活合理的管理 App 的内部环境,主要包括:</p>
<ul>
<li>App 本身的一些配置</li>
<li>所使用三方插件的配置</li>
</ul>
<p>我们在构建工程时尽量将所有的配置抽象统一放置在一个地方,这样便于查找和修改。但是由于大多数配置都统一放在同一个地方,那么就难免有部分文件要使用某个配置时其引用路径比较长,比如:</p>
<pre><code class="javascript">import { pluginAConfig } from '../../../../../config'</code></pre>
<p>这样就造成了阅读性很差且代码不美观,因此我们可以使用 Facebook 的 <code>fbjs</code> 模块提供的一个功能 <code>providesModule</code> :</p>
<pre><code class="javascript">//config.js
/**
* config for all
* @providesModule config
* 使用 providesModule 将 config 暴露出去
**/
import pluginAConfig from './plugin_a_config'
export default {
pluginAConfig
}
// 然后在其他文件中调用
// A.js
import { pluginAConfig } from 'config'</code></pre>
<p>这样就能很方便地在 App 的任意一处使用 config 了,但是我们要避免滥用 <code>providesMoudle</code> ,因为使用了 <code>providesMoudle</code> 进行声明的模块的源码,想要在编辑器中使用跳转到定义的方式去查看比较困难,不利于团队多人合作。</p>
<p><a></a></p>
<h3>2. 静态资源</h3>
<p><strong>静态资源</strong>泛指会被多次调用的图片或 icon,我们一般在 RN 使用图片时是直接引用的:</p>
<pre><code class="javascript">import { Image } from 'react-native'
render(){
return (
<Image source={{uri: './logo.png'}} />
)
}</code></pre>
<p>当图片需要在多处使用时,我们可能会将这些可能会被反复使用的图片统一管理到 <code>assets</code> 文件夹中,统一管理和使用,但是当需要使用图片资源的文件嵌套较深时,引用图片就变得麻烦:</p>
<pre><code class="javascript">render(){
return (
<Image source={{uri: '../../../../assets/logo.png'}} />
)
}</code></pre>
<p>这个问题与配置管理的问题一样,可以首先将图片资源按照类型进行分类,比如 assets 文件夹下有 button/icon/img/splash/svg 等,每一个类型的结构如下:</p>
<pre><code class="javascript">- icon/
- asset/
- index.js</code></pre>
<p>其中 <code>asset</code> 文件夹保存我们的图片资源,在 <code>index.js</code> 中对图片进行引用并暴露为模块:</p>
<pre><code class="javascript">// index.js
export default {
IconAlarmClockOrange: require('./asset/icon_alarm_clock_orange.png'),
IconAvatarBlue: require('./asset/icon_avatar_blue.png'),
IconArrowLeftBlue: require('./asset/icon_arrow_left_blue.png'),
IconArrowUpGreen: require('./asset/icon_arrow_up_green.png')
}</code></pre>
<p>然后再在 <code>assets</code> 文件夹下编辑 <code>index.js</code> ,将所有的图片资源作为 <code>assets</code> 模块暴露出去,为了避免和其他模块冲突你可以修改模块名为 <code>xxAssets</code></p>
<pre><code class="javascript">// assets/index.js
/**
* @providesModule myAssets
**/
import Splash from './splash'
import Icon from './icon'
import Img from './img'
import Btn from './button'
import Svg from './svg'
export {
Splash,
Icon,
Img,
Btn,
Svg
}
// A.js
import { Icon } from 'myAssets'
render(){
return (
<Image source={Icon.IconAlarmClockOrange} />
)
}</code></pre>
<p>这样,我们就能很方便地将分散在项目各处的图片资源统一到一个地方进行管理了,使用起来也非常方便。</p>
<p><a></a></p>
<h3>3. 网络请求</h3>
<p><strong>网络请求</strong>这块,react-native 使用 <a href="https://link.segmentfault.com/?enc=JL4YMYWSX4KhUDfaarSEHg%3D%3D.4Em72MtI00uQPJOzLPlqATN981CWbk6Tj2yMu9CSmnOk%2FZmojrGNKLHF3g0RzOC34bRSzNanFoWihnPZjjnLD6iOMOl7hUwEHHPk6tT8X84%3D" rel="nofollow">whatwg-fetch</a>,我们也可以选择其他的三方包如 <a href="https://link.segmentfault.com/?enc=8hfj9RrmFy8iJrH%2Bh1kimg%3D%3D.45YsH%2Bduo%2FaF5eLXOehvVo%2FbfmgOwwMdiNLlrlGPlKc%3D" rel="nofollow">axios</a> 来做网络请求。但有时候我们会在开发中遇到一个问题,那就是我们明明已经在代码里已经修改了 cookie, 但是每次请求可能还是会带上之前的 cookie 从而造成一些困扰,所以这里推荐一个实用的组件 <code>Networking</code> :</p>
<pre><code class="javascript">import { NativeModules } from 'react-native'
const { Networking } = NativeModules
// 手动清除已缓存 Cookie,这样就能解决上述的问题了
Networking.clearCookies(callBack)</code></pre>
<p>当然,<code>Networking</code> 的功能不止于此,还有很多其他有趣的功能可以发掘,可以直接用它来包装自己的网络请求工具,还支持 <code>abort</code> ,可以参考 <a href="https://link.segmentfault.com/?enc=cyC3zbRX0OgN7NaYIA6q1w%3D%3D.iASAHygFzklB5jwK8NAnCOZY%2F1K436BU8mh79%2FMmvuVHpbVNMQvA4uSOIGhrXfAO%2FVPpllzujYBpn%2FCyAWcuo1Cw3QrRsUKESK64u2l64qVbhAayQrBqZlLZHioXpknR" rel="nofollow">源码</a> 来具体把玩。</p>
<p><a></a></p>
<h3>4. 组件化</h3>
<p>使用 RN 开发 App 本身效率就比较高,如果想要继续进阶就要考虑组件化开发,一旦涉及到组件化开发,就不可避免地会涉及到组件管理的问题,这里的<strong>组件管理</strong>比较宽泛,它实际上应该指的是:</p>
<ul>
<li>组件规范</li>
<li>组件类型划分</li>
<li>组件开发标准</li>
</ul>
<p>组件规范指的是 UI 设计规范,我们可以与设计同学交流规定好一套特定的规范,然后将通用的样式属性(如主题颜色,按钮轮廓,返回按键,Tab 基础样式等)定义出来,便于所有的组件让开发者在开发时使用,而不是开发者各自为政在开发时重复写样式文件,这里推荐一个比较好用的用于样式定义的三方插件 <a href="https://link.segmentfault.com/?enc=5QH9C9Eq8RoJT22jc21JmA%3D%3D.WN6WoC3UgWF6bMvsYj6HmMOC2fBDL8KDhMzr55qs6eHb1eMpyOFVxjUomdriv4cD3eUl9HH%2B5mNxIwaK%2B4ZTSg%3D%3D" rel="nofollow">react-native-extended-stylesheet</a> ,我们可以使用这个插件定义我们的通用属性:</p>
<pre><code class="javascript">// mystyle
import { PixelRatio, Dimensions } from 'react-native'
import EStyleSheet from 'react-native-extended-stylesheet'
const { width, height } = Dimensions.get('window')
const globals = {
/** build color **/
$Primary: '#aa66ff',
$Secondary: '#77aa33',
$slimLine: 1 / PixelRatio.get(),
/** dimensions **/
$windowWidth: width,
$windowHeight: height
}
EStyleSheet.build(globals)
module.exports = {
...EStyleSheet,
create: styleObject => EStyleSheet.create(styleObject),
build: (obj) => {
if (!obj) {
return
}
EStyleSheet.build(_.assign(obj, globals))
}
}
// view.js
import MyStyleSheet from 'mystyle'
const s = MyStyleSheet.create({
container: {
backgroundColor: '$Secondary',
width: '$windowWidth'
}
})
render....</code></pre>
<p>这样,我们就能在开发的任意插件或者 App 中直接使用这些基础属性,当某些属性需要修改时只需要更新 <code>mystyle</code> 组件即可,另外还可以衍生出主题切换等功能,使得开发更加灵活。</p>
<p>关于组件类型我们会抛开三方组件以及原生组件,因为一旦涉及到这两者,需要写的东西就太多了,我们将组件按使用范围分为通用组件和业务组件两大类。</p>
<p>首先什么是业务组件?即我们在开发某个业务产品常用到的组件,这个组件绑定了与业务相关的一些特殊属性,除了这个业务开发以外,其他地方都不适用,但是在开发这个业务时多个页面会频繁地使用到,所以我们有必要将其抽象出来,方便使用。</p>
<p>什么是通用组件?即可以在 App 范围内使用甚至于跨 App 使用的组件,这里可以对这个类别进行细分,我们将能跨 App 使用的组件上传到了自己的搭建的私有 npm 仓库,方便我们的 App 开发者使用,同时,具有 App 自己特色的组件则放到工程中统一管理,同样适用 <code>providesModules</code> 暴露出去。</p>
<p>制定一整套组件开发标准的是很重要的,因为很多组件开发可能是多人维护的,有一套既定的规范就可以降低维护成本,组件使用的说明文档的完善也同样重要。</p>
<p><a></a></p>
<h3>5. 路由管理</h3>
<p>开发 App 就不可避免地会遇到如何管理页面以及处理页面跳转等问题,也就是<strong>路由管理</strong>问题,自从 Facebook 取消了 RN 本身自带的 Navigator 以后,许多依赖于这个组件的开发者不得不将目光投向百花齐放的社区三方组件,FB 随后推荐大家使用的是 <a href="https://link.segmentfault.com/?enc=%2Bec1pxnZm%2B8kcUihJch5Aw%3D%3D.6FHLtI36cZSBbjzIfJTiiIbPWTrTyF8wx1z1sKXgmPfae5Fssjl9GYHH62onR6Bi" rel="nofollow">react-community</a> 推出的 <a href="https://link.segmentfault.com/?enc=ky8TzknAYwoK2LwWzFVwCg%3D%3D.LADtvDVI1rCVub4sjXUTrg2X%2BX7G3oUoj8mJbw3a9ofE2lA3Aou6iBeBkZS69FC8" rel="nofollow">react-navigation</a> ,现在这个路由组件已经独立出来了。我们在开发时就是使用的这个组件作为路由管理组件,只不过是在其基础上做了一些定制 ,使得使用更加简单,部分跳转动作更加符合我们的产品场景,推荐大家使用这个组件。当然,除去这个组件还有很多其他的组件可供选择:</p>
<ul>
<li>基于 <code>react-navigation</code> 进行深度定制的 <a href="https://link.segmentfault.com/?enc=aZZsiWK35XcBAk8%2Fnpq0xg%3D%3D.DKq32OjGTD4Wnk0pZ4tzXDlO1kGkaojxzgDR5HblTT0zeOMMtsFEbP23nocRdLjJReWKzLeFSr8kEh31P12lMQ%3D%3D" rel="nofollow">react-native-router-flux</a>
</li>
<li>基于原生解决方案的 <a href="https://link.segmentfault.com/?enc=CzAcl7UwFW2Nsomse2fNHA%3D%3D.Aw%2FOuYC5P7btnNM%2BS0aC7HWiNu%2BaXjf7Boa84XVmGghHhqfcnlQf5DMWSoaS4AuK" rel="nofollow">react-native-navigation</a>
</li>
<li>airbnb 的 <a href="https://link.segmentfault.com/?enc=QaA1UiyuSO0YpgfBYFvd6Q%3D%3D.PgU2lIKNXcUkzUwOwONjscXtzt9md6fVpOblgAYD2OPYIjGebErUzB0o8fA6C1b6" rel="nofollow">native-navigation</a>
</li>
</ul>
<p>路由管理作为整个 App 的骨架,它是这几个部分中最重要的一部分,合理地定制和使用路由管理可以极大地简化我们的开发复杂度。</p>
<p><a></a></p>
<h3>6. 数据缓存</h3>
<p>一般情况下需要缓存的数据基本上就可能是我们会在 App 很多地方都会使用到的全局数据,如用户信息,App 设置(非应用层面的设置)等,RN 提供一个 <a href="https://link.segmentfault.com/?enc=QX41W1dr3ZDUVbER%2FUi1IQ%3D%3D.ciSgCSDBze3hygNrHeL1Jr%2BHMdiS%2BB8usDit2lEENkIlL2WXzufc0qdpjQaf1LVLKlYB6Bi%2FsUPSYYeWmIcsnOvrAVGxYzx7UdQTlD8OHCJn1nQJ1eVQZaDfSSJA5Nx3" rel="nofollow">AsyncStorage</a> 存储引擎,通常的使用方式是对这个数据引擎进行包装后暴露出符合我们要求的读写接口。这里推荐另外一种使用方式:</p>
<p>既然需要缓存的数据可能是会在 App 很多地方使用到的全局数据,那么我们可以将这些全局数据使用 <a href="https://link.segmentfault.com/?enc=uC9ex1rtNHs5my60KLvX3Q%3D%3D.YqqSlYofNE1rMGnXxDwnrMFm3wT%2B6Ee%2Boe%2BLkDZRNYdRVPZl3ZRxdia5XEeulzEI" rel="nofollow">redux</a> 来进行管理,而利器 <a href="https://link.segmentfault.com/?enc=zmukEPbcsiyDT%2BW16a0fSg%3D%3D.LWrbhytUvkyTJAUsKKYw5yi%2BYhzylvsKPFVA36hWI6%2FrRlZPQ6hKPI0sSRZSBoJj" rel="nofollow">redux-persist</a> 则能让我们很优雅地读写我们的缓存数据。</p>
<p>同时,如果对 <code>react-navigation</code> 进行合理的定制,接管其路由管理,那么我们还能实现保存用户退出 App 之前最后浏览的页面的状态,用户在下次打开 App 依然可以从之前浏览的地方继续使用 App,当然,这个功能要谨慎使用!</p>
<p><a></a></p>
<h3>7. 热更新</h3>
<p><strong>App 的版本更新</strong>,RN 除了传统的 App 更新外还有一个热更新的可选项(传统 App 更新也有热更新,其原理就不太一样了),社区大多数人都推荐使用 <a href="https://link.segmentfault.com/?enc=dpdGCzhRu6d80k3XlLWeFA%3D%3D.2RBecp%2BZY2V2Tzq3aTuGvlPAc4VYo52SWoOBdG1NUNim%2BZzwzuqhGNJprTqoKI7YY%2FMUfFnfRAQBmBRE0NJyNg%3D%3D" rel="nofollow">codepush</a> 来进行热更新,至于其后端解决方案 貌似已经有了一个 <a href="https://link.segmentfault.com/?enc=JQZNKNg69S%2BQFsD6l7nKeA%3D%3D.JD%2BQ3Slc7JZuYwCbvu8RAJ67fgmmEU9YfpG5Z0WgYURrLjF4Za0nFJKjS7bhT0iF" rel="nofollow">code-push-server</a> ,我们是使用自己的热更新方案,其原理就是在不更新原生代码的基础上更新 JS 代码和静态资源文件。</p>
<p><a></a></p>
<h3>8. 数据搜集</h3>
<p><strong>搜集的 App 使用数据</strong>(包括异常数据)并对此分析,根据分析来定位问题是保证 App 质量的有效手段之一。你可以选择自己搭建一套数据搜集服务,包括客户端 SDK 和服务端搜集服务,或者选择市场上已有的工具,目前较为成熟的收据搜集工具比较多,如友盟,mixpanel, <a href="https://link.segmentfault.com/?enc=9ZaC8IGq3M0deST54jhFtg%3D%3D.Q%2FsApP6moRZklkhiat%2FkjJylQ%2BsZAMJ4JK%2Bs6HuWmoo%3D" rel="nofollow">countly</a> 等等,在此不作赘述。</p>
<p><a></a></p>
<h3>9. 应用状态管理</h3>
<p>React只是视图层的解决方案,对于复杂应用,需要涉及状态之间的共享、各层级组件之间的通信、多接口之间调用的同步等等,就需要进行应用状态管理,Facebook最早提出了Flux架构思想,后来社区又涌现了Redux、Mobx等很多种模式。经过调研比较,我们选择了Redux进行应用状态管理,Redux的核心概念主要是通过Store、Action、Reducer、Dispatch实现单向数据流动,具体概念请参考官方文档。Redux通过middleware机制,可以对Redux进行各种能力增强,这个增强其实是在action分发至任务处理reducer之前做一些额外的工作,dispatch发布的action先依次传递给中间件,然后最终到达reducer,所以使用middleware机制我们可以拓展很多能力,例如我们使用了状态持久化插件redux-persist,状态记录和重播插件redux-logger,而异步操作插件我们经历了两轮技术选型redux-thunk和redux-saga。</p>
<p>支持函数action的redux-thunk通过简单的几行代码使得只处理plain object的action支持异步操作。</p>
<pre><code class="javascript">if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);</code></pre>
<p>Redux-thunk的实现非常简单,使用也非常灵活。我们可以在action中处理各种异步操作,也可以做任何事情,但是它的缺点是它缺乏对异步的直接处理,异步操作分散在各个action 中,而同步接口等操作依赖使用者自己的实现。</p>
<p>于是我们进而选择了支持generator的redux-saga。Redux-saga通过一个类似于独立线程的方式管理你的应用程序中的副作用,这意味着你可以通过普通的redux action开始、暂停或者取消saga线程。Redux-saga使用ES6的generator来管理异步流,使得业务逻辑的读写和测试变得更简单。在我们最新的架构中,我们其实使用的是蚂蚁金服开源的dva-core。之所以选用dva-core,主要是因为dva-core整合了redux和redux-saga,并且使开发者可以通过一个命名的model文件集中管理一个业务逻辑的state,通过定义的effects管理副作用操作,通过定义reducers管理其他处理函数。一个完整的model大概是这样的:</p>
<pre><code class="javascript">export default {
namespace: 'order',
effects: {...},
reducers: {...},
subscription: {...}
}</code></pre>
<p>最后,关于应用状态管理,还有一个话题可以讨论,就是状态的不可变性immutable。在redux中状态是不可变的,每个reducer都会产生新的不可变状态。那么这个不可变性是否需要不可变js库(比如immutable.js)的支持呢?简单来说,immutable.js可以带来计算效率和存储效率的提升,但是它需要使用库支持的数据类型,所以如果从头构建一个应用,可以选择。如果是对于一个已有的复杂应用进行重构,那就需要综合考虑一下了。</p>
<p><a></a></p>
<h2>小结</h2>
<p>总结一下,一个 RN App 架构应该要保证 App 的运行稳定以及开发的便捷。运行稳定这一方面,除了从 JS 层面(如单元测试,JS 错误上报等)保证之外,很大程度上还要依赖于原生层面的处理,所以团队里面要有同学的精力可以投在原生研究上面,至于开发便捷,我们尽量将复杂重要或者简单繁琐的操作在构建工程时就做掉,这样也可以大幅度提高我们的开发效率,降低开发者之间的合作沟通成本。</p>
<p>:::info<br>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: <strong>codingdream</strong>,也可以来 <a href="https://link.segmentfault.com/?enc=wz9x9UHOYdWsbw5STPbl%2FQ%3D%3D.k8x7oXOn1uiEN26DcBJoA3QyAvDVsA%2FzyYpv77eo6s4%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。<br>:::</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术驱动:业务大盘数据可视化技术探索
https://segmentfault.com/a/1190000022294570
2020-04-12T23:00:00+08:00
2020-04-12T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
5
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>数据的理解成本和决策价值会经历结果可见、趋势可见、过程可见,实际就是不断把真相显露水面的过程,越友好的数据展示方式,越低的决策成本越短的决策周期,这就是数据可视化的价值。</p>
</blockquote>
<p>在小菜,可视化的命题不仅仅是把数据图表化,而是实现很多数据的批量图表化,或者说是业务数据可视化的量产,不是三五个而是几十个,如果我们用传统的服务端 API 来对接几十个大盘里面共几百个图表的特定格式数据,那么前后端基本上可以锁定好几个工程师长期 base 在上面了,任何图表展示维度或者格式发生改变,API 要随之而变,这对于一个崇尚效率的技术团队无异于一场灾难。</p>
<p><a></a></p>
<h2>量产数据可视化的背景</h2>
<p>下图是一个 Demo 阶段的大盘需求汇总,这还是非常粗颗粒度的目标,它们的每一个底下都有更精细化的业务大盘,以及伴随大盘的年月周日这种时间线上的过程叠加,这是一个既有跳转深度也有丰富维度和数量的可视化产品。</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555412561547-c9073744-790b-46d9-b9e0-75f5909342a8.png#align=left&display=inline&height=366&name=image.png&originHeight=732&originWidth=2720&size=649335&status=done&width=1360#align=left&display=inline&height=732&originHeight=732&originWidth=2720&status=done&style=none&width=2720" alt="image.png" title="image.png"></p>
<p>我们再回到上一篇,温习下数据的几个阶段(阶段间并非线性先后顺序,往往是并行不断迭代),当几百张报表都可以批量生产后,从管理和决策的视角就要关注更多变化性的趋势而不仅仅是变动的数字,这个阶段也就是数据聚合和数据大盘趋势可视化的这两个阶段之和,前者关注结果后者关注过程。</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1554184533089-5ba572c6-8bd4-40a2-a669-2ead1e5d5754.png#align=left&display=inline&height=456&name=image.png&originHeight=912&originWidth=1714&size=206815&status=done&width=857#align=left&display=inline&height=397&originHeight=912&originWidth=1714&status=done&width=746#align=left&display=inline&height=912&originHeight=912&originWidth=1714&status=done&style=none&width=1714" alt="image.png" title="image.png"></p>
<p>上文的报表量产我们解决了,接下来就是可视化的量产,这两个刚好是底层和上层堆叠的关系,本文我们探讨下如何实现基于量产化后报表的可视化的量产。</p>
<p>再开始聊技术实现之前,先看下我们的一些可视化的编辑界面和一些展示形式,编辑过程通过在线切换 Tab 的 Excel 快速输出计算规则和公式,可以定制展示形式和展示顺序:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555472817445-a4923797-d0aa-4124-9a9d-d8a3662bb9a3.png#align=left&display=inline&height=710&name=image.png&originHeight=1420&originWidth=2592&size=306616&status=done&width=1296#align=left&display=inline&height=1420&originHeight=1420&originWidth=2592&status=done&style=none&width=2592" alt="image.png" title="image.png"></p>
<p>以及一些数据查询条件,包括 Excel 模板的导入等等:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555472898152-3a8897e6-89bc-4086-9333-0f35d27c4711.png#align=left&display=inline&height=381&name=image.png&originHeight=762&originWidth=2214&size=82200&status=done&width=1107#align=left&display=inline&height=762&originHeight=762&originWidth=2214&status=done&style=none&width=2214" alt="image.png" title="image.png"></p>
<p>在这些界面上,结合 Excel 模板,就可以快速把一些数据格式化出来作展示,比如一些和完成指标挂钩(可以运营手动录入)完成进度按照一定维度聚合配置的卡片图:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555472321592-81e1bf8e-2ee3-4504-9310-4e3bea435cbb.png#align=left&display=inline&height=564&name=image.png&originHeight=1128&originWidth=2702&size=215985&status=done&width=1351#align=left&display=inline&height=1128&originHeight=1128&originWidth=2702&status=done&style=none&width=2702" alt="image.png" title="image.png"></p>
<p>这些卡片就是结果可见,还有曲线图饼状图之类的趋势、过程和组成可见:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555472060313-41febd38-4400-42e9-b775-66a11e1769cd.png#align=left&display=inline&height=313&name=image.png&originHeight=626&originWidth=2574&size=204899&status=done&width=1287#align=left&display=inline&height=626&originHeight=626&originWidth=2574&status=done&style=none&width=2574" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>技术实现原理简介</h2>
<p>我们已知,目前小菜的报表系统是用 Node + GraphQL + SQL 拼装出来的一个工具界面输出 SQL,SQL 到数据库再到 Table 的配置与渲染工具,而报表系统之上的可视化,目前是借助 Excel 完成数据统计与数据存储的一个实验性系统(未来不排除摒弃 Excel 文件),整个可视化依然是跑在整个报表项目中,除了 Node 处理业务逻辑外(提供给客户端 GraphQL 接口),服务端还涉及 C#(Excel 数据的重算)的使用、Python(数据的获取、过滤、分组等预处理工作),在客户端则是使用 Antd Design 的 Charts 组件与 Bizchart(未来可能会换成 D3)。</p>
<p>整个技术方案中,可视化的制作流程可以分为下面几步:</p>
<ul>
<li>管理员制作 Excel 模版和配置脚本</li>
<li>定时任务执行脚本,更新缓存数据</li>
<li>前端获取数据用以图表展示</li>
</ul>
<p>流程非常简单,从数据库到数据再到展示,他们背后的技术栈如下图,其中 grpc 则是在 Egg 与 Python 预处理任务之间的数据流通信:<br><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1554649093467-c7cc58fa-698a-4123-b458-83eb5f8fb28d.png#align=left&display=inline&height=515&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-04-07%20%E4%B8%8B%E5%8D%8810.58.02.png&originHeight=515&originWidth=670&size=56104&status=done&width=670#align=left&display=inline&height=573&originHeight=515&originWidth=670&status=done&width=746#align=left&display=inline&height=515&originHeight=515&originWidth=670&status=done&style=none&width=670" alt="屏幕快照 2019-04-07 下午10.58.02.png" title="屏幕快照 2019-04-07 下午10.58.02.png"><br>接下来我们把技术栈上的单点概念和实现原理来捋一下。</p>
<p><a></a></p>
<h2>数据可视化实现过程</h2>
<p><a></a></p>
<h3>Excel 模版</h3>
<p>这里主要说明一下为什么使用 Excel,以及遇到的一些问题,现在有一个场景,一个运营需要统计每日各个城市的 GMV,而目前有这么一张全国 GMV 的明细表,以及一张城市分组的表,那么这个运营只要做好一张 Excel 的统计模版(通过 Excel 公式统计各个城市的 GMV),每天这个运营都需要将新的 GMV 数据以及城市的数据复制在模版之中,那么 Excel 会自动计算新的统计数据。可视化系统最初的构思就是将这个过程脚本化。所以先使用 Excel 作为底层的数据处理的方式作为实验方式,先跑跑看。另外当初在设计这个系统的时候是希望这是一个通用的解决方案(这里的通用是指可以应用在之前做的一个量产表报表系统的任意一张或者多张报表上面,再解释一下就是之前做了一个报表系统可以生产很多报表,现在做一个系统可以让里面所有的报表都可以变成可视化报表)。</p>
<p><a></a></p>
<h3>业务数据的定制</h3>
<p>由于设计通用解决方案,让人头疼的自然就是很多报表的统计逻辑都有着自己的业务逻辑在里面。举例就是业务上有可能今天的目标值是1000,明天可能要改成了800,这样经常变动的数据,又或者一些来源与第三方的统计数据且暂时没有进公司的系统之中但是统计时却又要用得到的。</p>
<p>像这样需要变动并且数据源不明确的数据我称为业务定制数据,为了减少开发量,这样的数据源的被划进 Excel 模版数据源里面,再通过提供一个 Web 版 Excel,让管理员(一般都是BI 或者运营)来随时更新数据到 Excel 模版之中。</p>
<p><a></a></p>
<h3>数据量增大问题</h3>
<p>显而易见,随着数据量的增大,Excel 文件也会越来越大,脚本的执行速度也会越来越慢,模版以 Excel 文件的形式物理保存在服务器上也不安全,容易会出现被删除等情况。</p>
<p><a></a></p>
<h3>数据的预处理</h3>
<p>主要使用 Python 中的 Pandas 以及 NumPy 来获取、处理数据,最后写入对应的 Excel 工作表之中。数据预处理目前只有数据分组以及数据过滤,以及一些特定图表需要的数据的计算(如和弦图),选用 Python 是考虑到更快实现,也就是前文技术栈落地的文章中我们秉承的观点 - 最小成本预研落地,这里用 python 开发成本更低(实际是把 python 当作 matlab 来用)。</p>
<p><a></a></p>
<h3>数据分组</h3>
<p>在这个可视化系统中,我们把报表的数据做了一个分类,分为了</p>
<ul>
<li>索引(一般为日期)</li>
<li>分类数据(城市,品类等)</li>
<li>其他(把索引看做自变量的时候,这些一般看做因变量)</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555069774741-fbb05588-290d-4f53-add4-61dce995402a.png#align=left&display=inline&height=385&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-04-12%20%E4%B8%8B%E5%8D%887.24.39.png&originHeight=496&originWidth=960&size=347138&status=done&width=746#align=left&display=inline&height=385&originHeight=496&originWidth=960&status=done&width=746#align=left&display=inline&height=496&originHeight=496&originWidth=960&status=done&style=none&width=960" alt="屏幕快照 2019-04-12 下午7.24.39.png" title="屏幕快照 2019-04-12 下午7.24.39.png"></p>
<p>一般情况下,图上的销售日期为索引,销售地区、销售人员和品名为分类数据数量、单价和销售金额为因变量,较多的时候需要统计的都是因变量,每日的<strong>数量</strong>、<strong>单价</strong>、<strong>销售金额</strong>等。</p>
<p>所以当我们接到需求要看<strong>销售</strong>维度或<strong>销售</strong>城市维度销售金额的总额以及整体总额的时候,只需要在 Excel 中新建一张透视图就可以完成任务,然后再通过设置日期索引,拉取对应日期范围的数据写入 Excel,最后让这个 Excel 重算一下读取新的数据就可以了。</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555069781148-21095e17-ad66-4086-a63a-0abbdcd7a126.png#align=left&display=inline&height=214&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-04-12%20%E4%B8%8B%E5%8D%887.43.35.png&originHeight=238&originWidth=830&size=113846&status=done&width=746#align=left&display=inline&height=214&originHeight=238&originWidth=830&status=done&width=746#align=left&display=inline&height=238&originHeight=238&originWidth=830&status=done&style=none&width=830" alt="屏幕快照 2019-04-12 下午7.43.35.png" title="屏幕快照 2019-04-12 下午7.43.35.png"></p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555069787584-3736f6a9-dcb6-4897-94b4-748256b3b5fb.png#align=left&display=inline&height=308&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-04-12%20%E4%B8%8B%E5%8D%887.49.08.png&originHeight=396&originWidth=958&size=178645&status=done&width=746#align=left&display=inline&height=308&originHeight=396&originWidth=958&status=done&width=746#align=left&display=inline&height=396&originHeight=396&originWidth=958&status=done&style=none&width=958" alt="屏幕快照 2019-04-12 下午7.49.08.png" title="屏幕快照 2019-04-12 下午7.49.08.png"></p>
<p>为了完成这个任务,我们需要</p>
<ul>
<li>Web 提供配置输入(索引列选择等)</li>
<li>Python 拉去数据写入 Excel</li>
<li>C# 重算 Excel,返回新的数据</li>
</ul>
<p><a></a></p>
<h3>Web 配置</h3>
<p>由于我们一般都是拉取某个日期范围的数据,所以首要的需要配置的是数据源的索引列,再提供一个系统预设的日期选项可以抽象为这样</p>
<pre><code>sysDateRange<近|本, N, DateUnit>
DateRange<sysDateRange<近,1,月>></code></pre>
<p>表现出来这样<br><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555136607303-6ff38451-8821-465e-81e7-0482cc723a3f.png#align=left&display=inline&height=231&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-04-13%20%E4%B8%8B%E5%8D%882.22.47.png&originHeight=280&originWidth=646&size=28006&status=done&width=533#align=left&display=inline&height=280&originHeight=280&originWidth=646&status=done&width=646#align=left&display=inline&height=280&originHeight=280&originWidth=646&status=done&style=none&width=646" alt="屏幕快照 2019-04-13 下午2.22.47.png" title="屏幕快照 2019-04-13 下午2.22.47.png"></p>
<p>根据这个预设每次拉取对应的数据再写入对应的源表之中就可以了,如果需要复制的需求的时候,如需要对数据去重等 Excel 公式很难完成的任务时,就要提到 Pandas 了。Pandas 是 Python 上的一个开源的数据分析包,专门做各种数据分析与预处理。平常很难的算法,用 Pandas 几行就可以实现。这里列举几个常用的操作:</p>
<p>比如需要过滤出指定日期范围的数据的话,那么用 Pandas 一行就可以了:</p>
<pre><code class="python">(df['销售日期'] > start_date) & (df['销售日期'] <= end_date)</code></pre>
<p>或者对上述表格需要对品类去重,统计品类数,可以这样做:</p>
<pre><code class="python">new_source = source.drop_duplicates(subset='品名')</code></pre>
<p>假如是再复杂点对多个条件进行去重,比如需要每日的品类数,也是一行代码搞定:</p>
<pre><code class="python">new_source = source.drop_duplicates(subset=['品名', '销售日期'])</code></pre>
<p>再回到 Web 端,只要提供对应的配置表单即可。如前面提到的日期过滤条件表单,并且把这样的配置应用到每个工作表之中去,就可以在一个工作簿里面写入各种不同维度的工作表明细了,这样整个数据预处理过程就搞定了。</p>
<p><a></a></p>
<h2>重算 Excel</h2>
<p>所谓的重算 Excel,就是读取预处理之后的 Excel,并且计算里面 Excel 公式,得到新的公式结果。这里我们主要是用 C# 里面的 EEPlus 来完成,可能大家会疑问,为什么需要用一个新的语言来做这件事?</p>
<p>Python 或者 Node 不行吗?这是因为我们的服务器系统是 linux 系统,假如是 Window Server 的话,Python 或者 Node 也确实可以找到可重算 Excel 的库,我们还尝试过 Java 的 POI,虽然可用,但是跑不了太大的数据,并且还很慢,所以就 ban 了,剩下的就只有 C# 了,毕竟都是微软自家的,支持程度比其他的好很多。</p>
<p><a href="https://link.segmentfault.com/?enc=yxE0YGajNcYeInRBcatb6A%3D%3D.11fQk7vbu8%2FZT0rjGncCYLZRTMBggusM4GTvc%2BDxmJZNZaGeGVei7qVNwP25Ifsp" rel="nofollow">Nuget</a> 上可以实现重算的库又很多,<a href="https://link.segmentfault.com/?enc=bSHPUgM1TQuYLCEgAnhDPQ%3D%3D.9ZI8LjjjK3h9yR%2FwCY%2BFrotQPI%2FpXBQXUXibVTdBIV12SD1YgRwEEmIHXAWhiKt0" rel="nofollow">NPOI</a> 、<a href="https://link.segmentfault.com/?enc=8ytOKKJxXVDhWy06y6HEfg%3D%3D.gO5NUDB%2Fhms58rzeH%2BN3n1DI2KKOVrefCpyDVtrDGiFga7QqzYeWUwQz1JiUiDvmGWch4FJz4A%2By5nq04qdYpg%3D%3D" rel="nofollow">Microsoft.Office.Interop.Excel</a> 、和 <a href="https://link.segmentfault.com/?enc=KcLgTzb7gllHRnanVPJuhQ%3D%3D.qL%2FzkPUtRO8KKQQBw8rlxzA8Zp7daXDnmGKkkbNIbKPFqQP4WNQNtCiTsuepdm1o" rel="nofollow">EPPlus</a> 等。试用下来都有一些 Bug,如 NPOI 对 SUMIFS 公式的支持就不是很好。这三者的速度比较的话,我们小小测试了一下,结果是 <a href="https://link.segmentfault.com/?enc=AOQrO4SpXsOAzSUP1uEGKw%3D%3D.%2BrGHUUqP5rFiGhpyp8GTdEUkJysTlIGhQ9VZTsYDFwnEGqExgTd5qydgR73FonXD" rel="nofollow">NPOI</a> > <a href="https://link.segmentfault.com/?enc=%2F%2FKHvU7greh7vOrrYlKGwg%3D%3D.1vnDjPjtpqinVVRqpPsST5k4cELa3%2BjgNgBagjL4YEG1xTUSjVZgyWiuMPdhbeGx%2F9tEDWYmueOb8sCYOheB3g%3D%3D" rel="nofollow">Microsoft.Office.Interop.Excel</a> > <a href="https://link.segmentfault.com/?enc=Ejqw4rA32BTTr2QVqhYc%2FA%3D%3D.G5Yr6xcYdxqmIxRV8EfBU4P9grK7PcPyN5SyNDNJc4KMBDhH8s%2FMmmkgjO4%2BZB6g" rel="nofollow">EPPlus</a> ,但是最后选的是 EEPlus,因为看中的就是他提供了自定义函数的这个 API,可以定制自己的 Excel 公式函数,如在 Excel 2019 实验的 Filter 函数,并且还能让我在发现其他函数的时候临时复写(不用 PR 到 git 上)。</p>
<p>再回到前面的重算,用 C# 也是只要一行就好:</p>
<pre><code class="csharp">package.Workbook.Calculate();</code></pre>
<p>是不是非常的简单!完成接口的代码差不多也就这么几十行:</p>
<pre><code class="csharp">String[] arguments = GetCommandLineArgs();
string filePath = args[0];
string outputPath = args[1];
FileInfo src = new FileInfo(filePath);
FileInfo dest = new FileInfo(outputPath);
if (dest.Exists)
{
dest.Delete();
}
File.Copy(src.FullName, dest.FullName);
ExcelPackage package = new ExcelPackage(new FileInfo(dest.FullName));
if (package != null)
{
package.Workbook.FormulaParserManager.AddOrReplaceFunction("sumifs", new MySumIfs());
package.Workbook.Calculate();
package.SaveAs(dest);
}</code></pre>
<p>重算之后把工作簿里面每张工作表里面的数据缓存为各个 LowDB 的 DB,Egg 通知每个 Worker 去缓存新的数据。</p>
<p><a></a></p>
<h2>前端组件</h2>
<p><a></a></p>
<h3>Antd Pro 组件</h3>
<p>Ant Design Pro 给我们提供很好的开箱即用的可视化模版组件,如图:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555052099810-5a42b310-4981-4500-9915-44be7942d9f4.png#align=left&display=inline&height=204&name=image.png&originHeight=204&originWidth=280&size=9344&status=done&width=280#align=left&display=inline&height=321&originHeight=204&originWidth=280&status=done&width=440#align=left&display=inline&height=204&originHeight=204&originWidth=280&status=done&style=none&width=280" alt="image.png" title="image.png"></p>
<p>像这样的卡片组件,即可以一眼看到统计数据,又可以大致的看出数据的增长趋势,通用性很强。要做的只是提供一个对应的后台配置,去对应的 LowDB 缓存里面的对于的数据就行了。</p>
<p><a></a></p>
<h3>复杂图表</h3>
<p>为了很好的暂时页面的数据埋点数据以及 PV 流量的流向,需要用到和弦图,这种复杂的图表需要把明细数据集转化成一个 n * n 的二维数据表:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555140830544-4126e931-bfc8-4ddf-9dca-e3f55d4fb43e.png#align=left&display=inline&height=540&name=image.png&originHeight=540&originWidth=350&size=39530&status=done&width=350#align=left&display=inline&height=705&originHeight=540&originWidth=350&status=done&width=457#align=left&display=inline&height=540&originHeight=540&originWidth=350&status=done&style=none&width=350" alt="image.png" title="image.png"><br>一开始我们尝试把这样的算法放到前端,后来随着数据量的增大,发现 JS 很难完成需求了(虽然可以分批计算,增量统计,不过实现起来繁琐一些),所以就把这样的图表定制算法切到 Python 服务那边去。</p>
<p><a></a></p>
<h2>订阅服务</h2>
<p>这个功能就是钉钉推送,主要是提供一个订阅功能,让用户可以订阅对应的统计卡片数据(图表在开发中),每天特定的时间通过钉钉,对该用户推送卡片数据,属于是爱心关怀的贴心功能,实现很简单,服务端使用的是 Egg,安装 <a href="https://link.segmentfault.com/?enc=u3uIilwdND6Fs3Mlr3aH7w%3D%3D.EoygG3%2Bf8yrhzc2V3R9tJKsERH1nHQK1xkKzYH76%2B%2FEfwDN4eZXwvF7wXoGPZ%2Bql" rel="nofollow">egg-dingtalk</a> 插件,按照文档配置:</p>
<pre><code class="javascript">exports.dingtalk = {
corpid: '',
corpsecret: '',
host: '',
enableContextLogger: '',
};</code></pre>
<p>再按照 <a href="https://link.segmentfault.com/?enc=PHyJ4LprNMnugaAUXqvlKQ%3D%3D.x2Egu6KPWsOPvlV%2FoDZkyvT8MphnwDFDPSKq5S8yyfrWAThEQ9Y04VDI15FJJt3G" rel="nofollow">node-dingtalk</a> 调用就可以了:</p>
<pre><code class="javascript">message.send({ touser, toparty, msgtype, ... })</code></pre>
<p>关于图表图片,我们目前的想法是借用 <a href="https://link.segmentfault.com/?enc=NkSUlh%2B91hEobsbh6e3rHw%3D%3D.9mKKZLUH%2FfZieUKqfiIpZglT6getqny2KMu2hJ%2BVhiWu3%2BUunLPwDHGPZQaSceMi" rel="nofollow">quickchart</a> 来实现。</p>
<p><a></a></p>
<h2>跨语言微服务</h2>
<p>我们使用了 Python 和 C# 来提供微服务,那么 Egg 和这两个微服务之间的通信就是要解决的问题,这里选用的是 gRPC</p>
<blockquote>gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。</blockquote>
<p>gRPC 对比其他 RPC 系统最大的优势就是他是跨语言的,基本我们需要的它都覆盖了:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/88663/1555143245999-07d81e33-0b9c-4389-9fd1-392c96130331.png#align=left&display=inline&height=300&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-04-13%20%E4%B8%8B%E5%8D%884.04.54.png&originHeight=490&originWidth=1218&size=72949&status=done&width=746#align=left&display=inline&height=300&originHeight=490&originWidth=1218&status=done&width=746#align=left&display=inline&height=490&originHeight=490&originWidth=1218&status=done&style=none&width=1218" alt="屏幕快照 2019-04-13 下午4.04.54.png" title="屏幕快照 2019-04-13 下午4.04.54.png"></p>
<p>通过一个 .proto 文件,描述出每个服务的下可调用的 API 以及该 API 的入参类型以及响应数据类型,再根据每个语言不同的工具把这个 .proto,文件转化成对应语言所需的文件,这里用一个简单的 .proto 为例</p>
<pre><code class="protobuf">syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// SayHello 方法的入参类型, 这里的意思就是入参数的字段名为 name, 类型为 string,这个字段的标识符为 1
message HelloRequest {
string name = 1;
}
// 和入参的逻辑一样
message HelloReply {
string message = 1;
}
// 服务描述,声明又一个类名为 greeter 的服务,该类提供 SayHello 与 SayHelloAgain 两个方法
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc SayHelloAgain(HelloRequest) returns (HelloReply) {}
}</code></pre>
<p>Egg 以及提供可 egg-grpc 插件,我们只要把对应的 proto 文件放如指定的文件夹之中就可以了。比较需要注意的是该插件的默认配置会把类名以及方法换成首字母小写:</p>
<pre><code class="javascript">const { ctx } = this;
const client = ctx.grpc.helloworld.greeter;
const result = await client.sayHello({ name: 'Gamelife' });</code></pre>
<p>Python 需要使用命令行来生成对应的服务文件:</p>
<pre><code class="bash">python -m grpc_tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/helloworld.proto</code></pre>
<p>C# 需要在工程描述文件 .csproj 里面加入 .proto 文件的路径:</p>
<pre><code><ItemGroup>
<Protobuf Include="../../../app/proto/helloworld.proto" Link="helloworld.proto" />
</ItemGroup></code></pre>
<p>然后在代码中就可以直接作为 nameplace 来使用了:</p>
<pre><code class="csharp">using System;
using System.Threading.Tasks;
using Grpc.Core;
using Helloworld;
namespace GreeterServer
{
class GreeterImpl : Greeter.GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
class Program
{
const int Port = 50052;
public static void Main(string[] args)
{
Server server = new Server
{
Services = { Greeter.BindService(new GreeterImpl()) },
Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
};
server.Start();
Console.WriteLine("Greeter server listening on port " + Port);
Console.WriteLine("Press any key to stop the server...");
Console.ReadKey();
server.ShutdownAsync().Wait();
}
}
}</code></pre>
<p><a></a></p>
<h2>总结</h2>
<p>结合上一姐报表量化的技术方案,我们可以把流程整理如下,首先是普通报表展示流程图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/jpeg/366288/1561706521305-145ba813-eca0-4af2-83bf-53488116f3f6.jpeg#align=left&display=inline&height=1080&name=d1.jpg&originHeight=1080&originWidth=1956&size=280687&status=done&width=1956#align=left&display=inline&height=1080&originHeight=1080&originWidth=1956&status=done&width=1956#align=left&display=inline&height=1080&originHeight=1080&originWidth=1956&status=done&style=none&width=1956" alt="d1.jpg" title="d1.jpg"><br>其次是可视化报表展示流程:<br><img src="https://cdn.nlark.com/yuque/0/2019/jpeg/366288/1561706806933-0d483dbf-e823-47dd-8f32-73da900f7f79.jpeg#align=left&display=inline&height=1104&name=d2.jpg&originHeight=1104&originWidth=1940&size=289707&status=done&width=1940#align=left&display=inline&height=1104&originHeight=1104&originWidth=1940&status=done&width=1940#align=left&display=inline&height=1104&originHeight=1104&originWidth=1940&status=done&style=none&width=1940" alt="d2.jpg" title="d2.jpg"></p>
<p>它的缺点很明显,node,python,c# 这几个服务都耦合在一块,python 在处理数据时候容易暂用大量内存,使整个服务挂掉,目前进一步用 gRpc 协议将不同的服务拆分开来, python 也部署到另外一台机器上,但仍需要一个更大的优化重构才能 handle 更多的应用场景和需求。</p>
<p>我们稍微总结下,目前实现的方案是在大表哥这个量产报表的系统上,再额外提供 Web 配置,利用 Pandas 来预处理数据, EEPlus 重算公式(解决定制需求),然后缓存数据展示到前端,整个底层实现后,只要会 Excel 计算公式的运营,就可以根据一些宽表来定制自己业务线的数据看板了,尤其是 BI 的同学,在我们的规划里,会让这里的制作成本越来越低,同时后期当预处理模块的功能逐渐完善之后,我们会希望替换掉 Excel 公式的作用,换一种更轻量级的方案来做。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=vpKBTIZ%2BVVRVsXm6gqevwA%3D%3D.if68CXUYfZ1vHk2%2F%2F3AfrJanwneJg3Vv7E%2B5yw9xUTw%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
框架设计:如何基于 Egg 设计 Node 的服务框架
https://segmentfault.com/a/1190000022294602
2020-04-12T23:00:00+08:00
2020-04-12T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
9
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>Node 的工具化价值自不多言,而服务化价值需要长期探索,小菜前端在服务化路上依然是小学生,目前的尝试是是 Cross 框架,尝到了一些甜头。</p>
</blockquote>
<p>我想,几乎没有前端工程师会对 Node 不感兴趣,但用它适合干哪些事情,每个人的答案都不同了,比如小菜前端,我们对于 Node 的深度尝试,可以在这里找到答案:<a href="https://link.segmentfault.com/?enc=PlpASwYofx4zf27kSnjs3Q%3D%3D.rmkdzs7fruOh5W%2FB8Me6bw6v75kLKoKfyUObFdZERFwZg3tl0nGrYLdQUUN7qVlt" rel="nofollow">《技术栈:为什么 Node 是前端团队的核心技术栈》</a>,但关于让 Node 做服务端的事情,却只有少数团队有这样的勇气。</p>
<p>之所以缺乏自信和勇气,本质的原因在于 Node 还没有一个足够顺手的框架来让你快速证明驱动业务的价值,也在于对 Node 缺乏足够的了解和信心,以及相对于服务端的强势,往往前端在侵蚀服务端领域的时候,会受到这般那样的挑战甚至刁难,这也成为了在团队推广 Node 常遇到的阻力,希望大家从小菜团队身上可以找到一些答案,其中答案的一部分就是要对 Node 要有足够的了解和认知,才可以为通用问题抽象出通用的方案去实施,在小菜,就是对于 Node 框架的封装,这个框架尚未开源,名叫 Cross,寓意没有迈不过的技术门槛。</p>
<p><a></a></p>
<h2>分清楚 Node 的边界</h2>
<p>前后端的团队本身是相爱相杀的关系,是左右手的双十合十,既有接口联调上的上下游数据立场,也有必须与对方精诚合作才能一次次拿下项目的战役,而在服务这件事情,前端就直接介入到了服务端的领域,而且从整个行业来看,这种介入在大中型公司已成为不可阻挡的趋势,无论是淘宝、天猫、支付宝、腾讯、网易、百度,包括创业独角兽大搜车、贝贝网、Rokid,海内外不分国籍不分领域的众多公司都有一个个团队在深度耕耘,所以这里的第一个边界是前后端的边界。</p>
<p>一千家公司可能就有一千种商业模式,一千种用户画像,一千种业务特征,既有高依赖算法的高实时计算的井喷式访问场景,也有日均几十 UV 几百 PV 的 toB 大客户产品,什么场景用 Node 合适,什么不合适,这第二个边界就是 Node 在业务领域里的服务边界。</p>
<p>只有弄清楚这两个边界,才有 Node 的生存土壤,脱离了这两个边界,就难免处处碰壁无法落地,针对前后端边界,我从前写过这样一段话:</p>
<blockquote>数据的控制权和与视图所依赖的 API,这里就是目前前后端的边界,数据控制权属于后端,API 属于后端,把前后端简单看做是一个完整的系统,这个系统中自 API 向下自然是后端的,API 向上则属于前端。</blockquote>
<p>在 API 下面,对于数据的业务流转流转逻辑,在上面对于数据的调用和组装,这就是数据层面的天然分界点,而 Node 植入进去,也必须在 API 这一层与 Java 保持规范的统一和兼容,通过 RPC 无缝的调用才能来谈边界,而这个边界我的理解它可以是非强业务耦合的,比如独立的内部协同系统,也可以是非高计算型的,可以是相对独立的异步的高并发的模块,比如消息堆栈的频繁拉取推送,比如日志的收集整理等等,总结起来就是非复杂业务流程的,非高计算型的这个地方可以作为 Node 进入的边界。</p>
<p>而对于业务的服务边界,只要的小而美的相对独立的系统,只要不是核心业务,都可以用 Node 快速开发,比如小菜这里就有报表系统、打包系统、发布系统、市调系统、日志系统、可视化平台、招聘面试系统、Bug 跟踪系统等等。</p>
<p>以上的两个边界,大家在仔细评估的时候,一定不要忘了自己团队人员的能力配置,能不能 Hold 住 Node,有没有 Node 技术专家坐镇,不然仓促使用可能还适得其反。</p>
<p><a></a></p>
<h2>为什么要封装 Cross</h2>
<p>在弄清楚上述的边界后,小菜前端在 1 年多的时间里,对 Node 进行深度的使用,从基建系统到相对独立的业务系统,整个走下来,团队更多同学掌握了 Node 的使用,同时每个系统之间的差异性也越来越大,有的用的是 Koa 有的是 Koa2,有的是 Thinkjs 有的是 Express,还有的是原生 NodeJS。</p>
<p>显然每个人的偏好都不同,代码质量也不同,工程架构方式也不同,这为后期的维护带来巨大的麻烦,尤其是做 Node 监控时候,发现没法用一套方案做批量的部署,也同样不能做水平的快速扩展,需要挑选一个框架基于它做统一的封装,从而把前端参与的所有服务端建设可以统一起来,而且现实是我们的前端和 Node 应用由于整个工程的构建与服务部署方式的不同,已经散落到各个服务器上,导致维护成为了瓶颈,也必须到做出改变的时候了,这是当时的部分零散的应用图:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555320016031-dd4d09ed-d982-4371-9506-5ca4169f5878.png#align=left&display=inline&height=779&name=image.png&originHeight=1558&originWidth=2306&size=360933&status=done&width=1153#align=left&display=inline&height=1558&originHeight=1558&originWidth=2306&status=done&style=none&width=2306" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>为什么选择 Eggjs</h2>
<p>小菜前端在使用 Eggjs 作为 Nodejs 的基础服务框架之前使用过诸如 Koa、Express、Koa2、Thinkjs 等框架,其中与 Eggjs 最接近的当属奇舞团开源的 <a href="https://link.segmentfault.com/?enc=3MgiS90axt1vI905Oj0ZUQ%3D%3D.J%2BJzVOA%2FFqEwz8kfVwV4y6OUqnGzyknYeSARxDc9QkM%3D" rel="nofollow">Thinkjs</a> , 同样的约定大于配置,同样的基于 Koa2 进行包装完善,同样的采用多级分层的设计方式(Controller, Service 等等),让应用开发变得更加清晰明了,然而有趣的是, Thinkjs 的开源时间(2013)早于 Eggjs 的开源时间,其在 github 上的 star 的增长速度却是远远落后于 Eggjs,NPM 下载数亦然,虽然 thinkjs 开发体验也不错,小菜最后会选定 Eggjs 作为 Nodejs 服务框架的原因,除了上述提到的优点之外,还有如下几点 :</p>
<ul>
<li>高度可扩展的插件机制</li>
<li>方便定制上层框架</li>
<li>丰富且活跃的社区生态</li>
<li>渐进式开发</li>
<li>多进程管理</li>
</ul>
<p>小菜前端从 18 年年初就开始使用 Eggjs 了,我们的很多项目都是基于 Eggjs 搭建的,其中包括我们的报表系统、GraphQL 网关、小程序后台服务等。在使用 Eggjs 开发这些项目的过程中我们逐渐形成了自己的一套适用于宋小菜的基于 Eggjs 的上层框架,基于小菜特定业务场景长出来的 Framework,它的定制程度很高,大家可以参考我们实现这套框架时用到的技巧与方法,这些套路应该是通用的。</p>
<p><a></a></p>
<h2>秉承怎样的设计理念</h2>
<p>考虑授人以鱼不如授人以渔嘛,我们先分享下我们的设计理念,这是最简单却也最重要的开始部分,我们的目标是风格统一、上手容易、维护方便:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555332236027-0a15ce02-76c2-4412-9e67-8984a4e6ba71.png#align=left&display=inline&height=351&name=image.png&originHeight=702&originWidth=2618&size=456165&status=done&width=1309#align=left&display=inline&height=702&originHeight=702&originWidth=2618&status=done&style=none&width=2618" alt="image.png" title="image.png"></p>
<p>然后就是整体需求的整理和开发集成,在开发集成个过程中不断调优:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555332351600-1c22d68b-4ad4-46a8-abab-9d7de1e5f80e.png#align=left&display=inline&height=452&name=image.png&originHeight=904&originWidth=2188&size=507261&status=done&width=1094#align=left&display=inline&height=904&originHeight=904&originWidth=2188&status=done&style=none&width=2188" alt="image.png" title="image.png"></p>
<p>定完目标,设计好流程,就要准备具体的实施了,我们实施涉及到过程,主要从下面四个方面着手:</p>
<ul>
<li>框架关系</li>
<li>通用 API</li>
<li>插件定制</li>
<li>工程管理</li>
</ul>
<p><a></a></p>
<h2>如何设计 Framework</h2>
<p><a></a></p>
<h3>框架关系</h3>
<p>我们将所有通用的 API 和常用工具函数以及常用的插件(redis、gateway)等统一集成在基础框架 baseFramework 中,由于 Egg 支持多级框架继承,所以我们可以根据基础框架 baseFramework 衍生出其他框架如 GraphQL 相关的框架、微服务相关的框架,它相当于是一颗框架种子,可以往不同的方向定制:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555332576919-a5d7b1f4-d598-4197-bda6-d71811ffdc58.png#align=left&display=inline&height=488&name=image.png&originHeight=976&originWidth=2464&size=526539&status=done&width=1232#align=left&display=inline&height=976&originHeight=976&originWidth=2464&status=done&style=none&width=2464" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h3>通用 API</h3>
<p><a></a></p>
<h6>1. 请求参数统一获取</h6>
<p>假定某个 HomeController 有成员函数 <code>testAction</code> 既要处理 post 请求又要处理 get 请求,就有可能出现以下情况:</p>
<pre><code class="javascript">const { Controller } = require('egg');
module.exports = class HomeController extends Controller {
testAction(){
const { ctx } = this;
const { method } = ctx.request;
const id = method === 'GET'? ctx.request.query.id : ctx.request.body.id;
...
}
}</code></pre>
<p>我们可以将其优化为:</p>
<pre><code class="javascript">/* yourapp/app/controller/home.js */
const { BaseController } = require('egg');
// 或者
const { BaseController } = require('your-egg-framework');
module.exports = class HomeController extends BaseController {
testAction(){
const id = this.getParam('id');//
...
}
}
/* egg-baseframework/core/base_controller.js */
const { Controller } = require('egg')
module.exports = class BaseController extends Controller {
getParam(key) {
const { ctx } = this;
const { method } = ctx.request;
if (method === 'GET') {
if(key) {
...
} else {
...
}
} else {
...
}
}
}
/* your-egg-baseframework/lib/index.js */
const { BaseController } = require('../core/base_controller');
module.exports = {
BaseController,
...
}
/* your-egg-framework/app.js */
module.exports = (app) => {
require('egg').BaseController = BaseController
}</code></pre>
<p><a></a></p>
<h6>2. 返回数据格式化</h6>
<p>方法同上,我们可以在 <code>BaseController</code> 中定义统一的调用成功和调用失败返回函数,并在函数中处理返回数据从而避免返回数据不规范的问题</p>
<p><a></a></p>
<h6>3. 通用工具函数</h6>
<p>我们可以将平时业务开发中可能会用到的工具函数统一通过框架扩展的额形式定义到内置对象 <code>helper</code> 上,这些都可以以框架扩展(extend)的方式集成进来,比如参数转化啊,错误信息格式化等等。</p>
<p><a></a></p>
<h6>4. 增加参数校验层</h6>
<p>我们可以将参数校验这一步抽离出来成为 <code>logic</code> 层。有两种方式可以做到:</p>
<ul>
<li>在框架加载时调用 <code>app.loader.loadToContext</code> 将所有 controller 对应的参数校验函数挂载到 <code>context</code> 上,在 <code>controller</code> 执行相应的处理函数时调用</li>
<li>在你的框架继承的 <code>appWorkerLoader</code> 中覆写 eggjs 的 <code>loadController</code> , 对每一个 controller 的处理函数都使用对应的 <code>logic</code> 进行代理</li>
</ul>
<p><a></a></p>
<h3>插件定制</h3>
<p>Egg 的拥有着丰富的插件生态,然而总有些我们需要用到的插件不太符合我们的要求,比如:</p>
<ul>
<li>egg-redis 长久不支持哨兵模式</li>
<li>egg-graphql 不支持连接其他 graphql 服务</li>
<li>egg-kafka 长久没有维护</li>
</ul>
<p>这个时候就需要我们自己动手编写或修改相应的插件了,而有些在公司层面上通用的功能如:Java 服务端网关请求(egg-gateway)、用户鉴权(egg-auth)等我们也将其封装为插件集成到基础框架中,讲实话,整个框架开发中,让人最开心最后成就感的部分就是写插件的时候:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555332665108-88ad2ebe-e082-48ec-96d0-c9be26c8979b.png#align=left&display=inline&height=488&name=image.png&originHeight=976&originWidth=2764&size=500433&status=done&width=1382#align=left&display=inline&height=976&originHeight=976&originWidth=2764&status=done&style=none&width=2764" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h3>工程管理</h3>
<p>由于插件和插件之间,插件和框架之间,框架和框架之间存在相互依赖的关系,代码管理就成为了比较头疼的问题,推荐使用目前比较火的 monorepo 来进行管理。规范版本发布流程,避免出现不兼容问题。</p>
<p><a></a></p>
<h2>总结</h2>
<p>关于 Cross 的建设我们差不多投入了一个多月的周期,从投入产出比来看还是很划算的一次尝试,但是在落地时候也会遇到不少问题,从人和团队的角度来看,这样的一套 Framework 需要有一定的 Node 编程能力的同学才能较好的用起来,对于所有人依然有一定的心智成本,有没有可能把这个成本继续降低呢,走向 Pass 跟高阶的只关心业务逻辑不关心背后实现的阶段呢,这是一个很值得研究的课题,另外就是从事情的角度,如果业务中没有那么多的场景来承载这个框架,事实上它是很难继续进阶的,因为没有足够的应用和测试场景来暴露问题,这也是我们当下遇到的一个实际困难,缺少 Node 好手掣肘了我们前进的步子,不过好消息是接下来的业务场景已经铺开了,团队也刚刚进了一个 Node 选手,接下来看看应用后发力效果如何。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=NdIKwC54uDCIZDU0Ejgrzw%3D%3D.z%2BCNzK3AVqsJJumaidvTnvKFIuWTvzBi7XL29Z61%2F7w%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术驱动:如何让工程师的技术价值最大化
https://segmentfault.com/a/1190000022294476
2020-04-11T23:00:00+08:00
2020-04-11T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
6
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<blockquote>如何让工程师的技术价值最大化,职业空间最大化,就一定要让工程师手中的技术闪闪发光,有效的做法就是为新技术找应用场景,或者换个说法,也就是如何通过技术为业务找突破口,这也是除了技术架构和技术响应速度外,不制约业务甚至驱动业务的必走之路。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555331832301-5159411d-7e6a-4059-a5d9-0ac8a1119029.png#align=left&display=inline&height=305&name=image.png&originHeight=610&originWidth=2300&size=236142&status=done&width=1150#align=left&display=inline&height=610&originHeight=610&originWidth=2300&status=done&style=none&width=2300" alt="image.png" title="image.png"></p>
<p>要通过技术为业务找突破口,我们就要从业务上找可能性找痛点,同时要对技术有足够的感知,答案摆在这里很简单,但是究竟如何才能训练出这种能力呢?</p>
<p><a></a></p>
<h2>需求挖掘与主观能动是第一生产力</h2>
<p>首先,让我们小菜前端尝试过的案例枚举一些出来,我们从思路和角度上观察下,有没有可以复制过来的办法:</p>
<ul>
<li>销售团队运营团队看数据慢看数据难,我们研发了大表哥数据报表系统,解锁报表产出效率</li>
<li>销售团队想针对不同生鲜品与客户快速做市场调研,我们研发大瓜子表单系统快速支持差异化市调模板配置</li>
<li>技术团队没有测试想要有更稳定更高效的打包与发版流程,我们研发了大伯伯自动发包与推包系统</li>
<li>产品团队希望用最小的人力成本,搭建多个 APP 服务不同的人群,我们用 ReactNative 解锁开发效率</li>
<li>采配销团队协同的需求变动需要快速体现在 APP 上,我们研发大表哥热更新发布系统,解锁发版节奏</li>
<li>客户千元机多机型 APP 异常希望快速反查到特定 Commit 代码,我们开发了大表姐热更新系统全流程分发代码</li>
<li>人事部门想要系统化管理所有候选人的简历与安排面试,我们开发大才子实现简历管理与面试工单系统</li>
<li>行政部门想要集中管理公司图书和大量的纪念品文化衫,我们开发牛犊子系统统一管理行政物料</li>
<li>技术部发周报走邮件零零碎碎不好整理不好统计,我们开发堂哥报表系统,解锁周报收集与统计效率</li>
<li>销售团队想要推行用户自主下单而非销售代为下单,我们研发了 RN SDK/RGB 来分析下单主体是否本人</li>
<li>技术部的前后端数据接口频繁改动与对接成本高,我们研发了大舅子来解锁数据接口对接聚合的协同效率</li>
<li>技术部的多个 APP 在几十种低端机型的闪退异常无从跟踪,我们研发了姑奶奶做端异常的收集与跟踪系统</li>
<li>运营部门希望可以有更直观的监控交易市场的动销与行情,我们就研发了创意中心做视频切片与字幕音效合成</li>
<li>城市销售想要对特定市场招聘社会兼职收集竞手卖货行情,我们迅速扩展了 Vue 技术栈开发小程序来管理兼职</li>
<li>...</li>
</ul>
<p>还有很多,不再一一列举,这里面大大小小,每一个展开都是一个故事,所有的故事串在一起,就是今日的小菜前端生机面貌,要做到这些需要背后有一个神秘的能量,就是对于需求挖掘的能力和主观能动性的内驱力,前者会带来无数的机会,后者会让这么多飘在空气中的想法逐个落地。</p>
<p>主观能动性很容易理解,就是主动去跟进问题,主动去解决问题,主动去把解决方案落地的责任心和主动性,而需求挖掘的能力,要如何培养呢?</p>
<p>如果没有这样的能力,就自然看不到满地沙子中的黄金,自然也失去了很多获得财富的机会。即便是满腔热血也没用,要培养这样的能力,实际上比我们想象的要容易的多,具体到执行上则是有难度的,大家可以按照如下几个步骤来训练自己:</p>
<p><a></a></p>
<h2>一、走进业务现场</h2>
<blockquote>不要讨厌你在做的业务,就是它在养活着这家公司,不要轻视你的客户,正是他们对你尚存信任。</blockquote>
<p>事实是就算你不喜欢当下的业务,也应该到业务现场走一走看一看,为什么进业务现场如此重要要排在第一位,因为所有的事情,要想超越它 Get 到新的感悟,一定要尽量亲身经历一番,至少也要真实看见。</p>
<p>通过逼自己进入到业务现场,你会看到用户是怎么看待你做的业务,怎么使用你做的产品,以及他们在使用产品过程中会遇到哪些问题。更重要的是,你会观察到这个业务在用户群体中所真实发挥的价值,是提高了效率,还是节约了成本,还是优化了协作的方式。这样的改变是如何一点点的重塑着整个行业,公司又是因为这样的业务建立起了怎样的竞争壁垒,如何从用户的口袋里赚到了自己的一份钱。这所有的问题只坐在办公室的电脑前,是很难在脑海中形成画面建立观感的,必须亲自去走走看看听听用用,它会在无形之中让你对于业务的理解更加的扎实接地气。</p>
<blockquote>案例匹配: “销售团队想针对不同生鲜品与客户快速做市场调研,我们研发大瓜子表单系统快速支持差异化市调模板配置”,我们的同学跟随销售到现场做调查,发现他们用钉钉逐个逐个录入蔬菜老板的每日交易品类,货源信息,进货出货频率,以及他获知行情和货源的渠道,个人的电话地址家庭状况等等零碎几十个信息,换一个城市换一个老板,要调研的内容就会因为经营品类的不同而发生一些结构性的变化,这些变化给销售同学带来极大的困扰,而每次开发 H5 网页又会给工程师带来很多重复性的工作,所以我们在想搭建一个给销售助理和销售运营使用的表单配置系统,让他们十分钟就能快速配置出多种结构化信息后的表单页面,然后投放给一线的销售同学使用。</blockquote>
<p>如果我们没有去现场观看,压根也不觉得用钉钉记录数据再回流有什么问题,也不觉得市场调查是一个多么消耗人力的事情,更不会认知到市场调研这么多维度的数据对于整个业务能有序的运行,对于新市场的开拓和老市场交易动态的理解有多么重要的意义。</p>
<p><a></a></p>
<h2>二、培养产品感知认知</h2>
<blockquote>如果有人总是告诉你不可能,那他一定是见过太少的奇迹,经历太少的可能。</blockquote>
<p>每个工程师都有一个产品梦,我想你也不会例外。自己独立做一款 APP,几十万安装使用就已经是一件非常值得自豪的事情,但是用代码做出一个 APP 真心不是难事,难的是如何吸引用户来安装这个 APP。</p>
<p>如果你是一个 APP 工程师,你手机桌面上有没有曾安装过超过 100 款 APP,并且逐个注册和试用他们;如果你是一个 PC Web 工程师,有没有把 toC 和 toB 的系统使用超过 100 个,从它们里面找共性,找它们各自的定位和交互优缺点,看他们的设计元素;如果你是一个工具型工程师,有没有研究过超过 100 款工具,看他们解决的痛点和如何提高效率,他们设计和实现的方式。</p>
<p>做这么多看起来无用枯燥的尝试的目的是什么呢?其实是为了倒逼自己思考为什么这么多成熟的产品竟然都有生存的空间吗,都有对应的受众。那么好奇心就会驱动你也去研究,在我的身边有没有类似的场景和机会,去为特定的用户群体解决一些问题。如果是我来设计这款产品,我会从过往看过的上百个产品中吸取什么元素来组装出来一个产品蓝图,这个蓝图要如何切入到这个用户群体,到底能不能命中需求解决问题,它有没有市场的竞争者,竞争者又是怎么做的,带着这样的问题不断的训练自己,会让自己对产品越来越敏感。</p>
<p>一旦自己的敏感度建立起来后,事实上就可以把这种思想应用在工作之内和之外。之内是手头的业务,之外是和别人合作中遇到的一切问题。所有的问题能不能用代码解决,能解决到什么程度,这种反应能力会每天伴随着你,每一天都比前一天要成熟,慢慢的对于产品的感知力就培养起来了。</p>
<blockquote>案例匹配:“人事部门想要系统化管理所有候选人的简历与安排面试,我们开发大才子实现简历管理与面试工单系统”,人事的同学对于产品和研发流程是不了解的,所以整个候选人从简历收集管理到最后面试结果的同步,都非常人肉非常辛苦,但又没有相应的产品经理来跟进这件事情,因为它往往比业务优先级要低,于是前端工程师凭借自己对于产品的理解,就搭建了简历与面试系统,从简历入库、简历筛选指派、面试转交、面试评价、钉钉提醒等等方面都做到了最初的 0 到 1,界面与功能并不闭环,但是能极大的提升候选人的整个面试进程效率。</blockquote>
<p>除了大才子,还有大表哥他们都是前端工程师驱动的产品,如果没有敏感的产品感知能力,前端工程师自然没有勇气和信心来启动这样的一个可能失败的实验性产品,也自然不能再扩充一个技术场景来让自己的技术再次闪光。</p>
<p><a></a></p>
<h2>三、训练数字化成本与效率思维</h2>
<blockquote>如果有一样东西不会撒谎,那它就是真实的数据,数据不说话,真相静悄悄。</blockquote>
<p>提到数据我们通常会想到算法、大数据、机器学习这些领域,对于前端工程师,我们虽然日常都在对接数据接口,却更多对交互和工程化敏感,而对于数字背后的含义不太关注。关注了和不关注的区别在哪里呢,我们来看下这个案例:</p>
<blockquote>案例匹配:“技术团队没有测试想要有更稳定更高效的打包与发版流程,我们研发了大伯伯自动发包与推包系统”,如何打包和如何解决打包问题我们非常熟练,但对于它的成本一直缺少一个量化的数字概念,后来我们把整个流程全部观测了一遍后,获得数据如下:5 个 APP,每个 APP 背后有至少 2 个打包人,每次打包的环境有至少 6 种选择(正式环境热更新包、正式环境非热更新版、测试环境热更新版、测试环境非热更新版),同时有 2 种类型选择(企业版和公开上架版),已经两个平台的支持(iOS/Android),抛开这些之外,每个同学本地的 XCode/Gradle/Node 的环境版本也会有差异性,会有上百种可能性在过程中出错,这个在之前文章有提到,也就是下图:</blockquote>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555050058188-9f9bc2ae-d3fb-4fd2-850e-ae0294e4e80f.png#align=left&display=inline&height=523&name=image.png&originHeight=577&originWidth=805&size=167561&status=done&width=729#align=left&display=inline&height=577&originHeight=577&originWidth=805&status=done&style=none&width=805" alt="image.png" title="image.png"></p>
<p>当你把所有这些数字写下来的时候,你就会对成本产生更直观的认识。一旦量化后,我们就从直接感受到了这个形势的紧迫性,于是首先是从流程上形成规范,下图是最早的第一版全发布流程纪念图:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555069846371-f798fca4-4ef9-49c4-845f-f817897cf9b1.png#align=left&display=inline&height=413&name=image.png&originHeight=395&originWidth=713&size=41984&status=done&width=746#align=left&display=inline&height=395&originHeight=395&originWidth=713&status=done&style=none&width=713" alt="image.png" title="image.png"></p>
<p>并且定义了它的一个热更新策略:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555069803364-60542e15-e883-4f8f-a4ad-ef48d8d19a4f.png#align=left&display=inline&height=545&name=image.png&originHeight=525&originWidth=719&size=71673&status=done&width=746#align=left&display=inline&height=525&originHeight=525&originWidth=719&status=done&style=none&width=719" alt="image.png" title="image.png"><br>然后就着手启动了打包平台的开发,从此本地(开发) - 大伯伯(打包测试与正式打包推包) - 大表姐(热更新分发) 全流程就闭环了,完成这次自我革命的秘诀就在于把付出的成本与耽误的人力全部数字化,去惊醒脑海意识里面再忍忍没多大事的这种想法。</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555402854809-a9f4fb1d-20ec-4c53-ac90-7f5493fd97f3.png#align=left&display=inline&height=74&name=image.png&originHeight=148&originWidth=1502&size=24872&status=done&width=751#align=left&display=inline&height=148&originHeight=148&originWidth=1502&status=done&style=none&width=1502" alt="image.png" title="image.png"></p>
<p>这是打包平台上线后一年多的数据,我们总共打了 3000 多个包,其中光用来平时开发和测试过程的包就有 1500 多个,节省了大量的人力也提供了足够高的包质量,有了这样的数字支撑,我们也对投入产出比有了更量化的评估,再去解决任何其他问题,包括我们自己产品和用户的一些问题,都能从数据上看出一些需要坚持和适当妥协甚至放弃的做法。</p>
<p><a></a></p>
<h2>四、锻炼团队合作协同能力</h2>
<blockquote>把你杀死的往往不是合作方的撕逼,而是你的 ”我以为“,任何观点传播都会不断的衰减扭曲,协同的意义在于合力时候可以步调一致。</blockquote>
<p>合作是我们从小学教育就开始培养的能力,但真正到了工作环境,依然会发现之前的能力非常单薄,原因就在于决定合作能否成功,还取决于协同时候的说服和推动,说服靠沟通,而推动靠执行,单纯沟通和执行这两点,相信所有职场的工程师都自认为还不错,但两者结合起来时候就发现很吃力了,你讲的话没人听,你推的事没人做,你以为十万火急的事情别人轻轻带过。</p>
<p>造成这种现状的原因很多,沟通技巧缺乏,执行力度不够,推动面积过小,职能部门之间利益的纷争甚至同事之间的猜忌和不认同,每一个的解法都不同,我会重点聊聊沟通和执行力这两个比较核心的主观因素。</p>
<p>沟通至少需要做到这三点才算是有效的沟通:</p>
<ul>
<li>有原因有过程有结论有可量化的目标的去沟通,理性为主</li>
<li>有共同的大利益框架捆绑的沟通,你荣我荣共赢才算赢</li>
<li>多次的重复的有二次确认的沟通,防止声音衰减</li>
</ul>
<p>然后才是个人魅力,部门影响力和手中的权利大小等等,如果再直白一些,把事情前因后果想清楚最好带着几个预设的结论去沟通,并且多去沟通,多反复讨论去拿捏双方合作中彼此的临界点和 care 的点,达到结果一定是双赢的价值更大化的,而不是单方面收益。</p>
<p>而执行力这块,更多的不是做的有多对,而是做的有多主动多热心,你希望合作对象可以给你想要的,那么就要多去了解对方的进度和困难,无论当面/电话/钉钉,要多去问勤联系主动向对方同步自己做的进度,太花哨的套路不太推荐。</p>
<p>这一个是所有工程师走向资深后,无论是做业务还是做架构还是做管理,都必然面临的课题,可能连续几年都解决的不好,但只有让自己勤快的想,勤快的讲,将心比心的沟通,主动向他人同步才能让自己处在一个相对好合作的环境中,也才能获得更多别人的支持。</p>
<p><a></a></p>
<h2>五、保持对技术与商业化的好奇心</h2>
<blockquote>看书万卷不如编码实战,编码实战不如出去看看,出去看看不如动手练练。</blockquote>
<p>很多时候我们不知所措不是因为看的太多,而是做的太少,比如你所在的团队氛围低沉业务繁重技术陈旧,每天脑海中都是在想怎么逃离这里,总是觉得成长一定是技术成长,这种想法在编程的早两三年都是 ok 的,但真正让你愈加值钱的,是技术背后的商业化思路,技术深度和广度可以一直扩展下去,但背后的商业化思考能力和价值应用能力,反而是一个需要长期建设的软能力,这种能力越往后越重要。</p>
<p>比如你是一个团队的前端架构师,或者某个业务线的前端负责人,你会怎么定位自己又会怎么去思考手上的事情,这件事情对于团队对于公司甚至对于行业有什么样的革新,对于用户有什么内在的需求满足和变现内核,这些都是非常值得去思考的事情,因为正是站在你的技术方案之上,这些工程化的产品最终发挥了价值,这个过程中技术是最下沉的运行底层,这个底层如果换一个商业逻辑,换一个场景能不能兼容,其实就取决于你怎么对商业的本质有基于技术的抽象和封装。</p>
<p>不同的业务长在不同的互联网软硬件集成设施上,所有的业务都有它的运作逻辑,所有的底层系统也有它特定的运行领域,下层的领域和上层的逻辑之间永远处在动态升级的关系,时快时慢,它们之间的关系对于我们工程师来说,是最值得投入时间去研究的领域,这会不断重塑我们脑海中那个技术价值树,什么技术长什么业务,什么业务用什么技术,这课树越来越粗壮,我们自身的铁打竞争力也越来越强。</p>
<p><a></a></p>
<h2>总结</h2>
<p>工程师的价值最小的时候,可能只是一个团队角落的螺丝钉,最大的时候可以是上市大公司的 CTO 甚至是 CEO,每个人也都有自己职业天花板,越往上冲刺越靠近商业,越往上冲刺也越难,无论我们当下处在哪个阶段,脑海中都应该有一个看得见的远处,在那里,你身上会散发技术的光芒,所有与你临近的商业星系都会受益,它们受益越多,机的工程师价值也就越大。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=8hiNBDrfuD8zaFU72DICZQ%3D%3D.3kj7tMjcYSBvwfs7xfKqxAI4iY8sqOlU6w8O2Jx05mA%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术驱动:量产数据报表的工具服务如何搭建
https://segmentfault.com/a/1190000022294509
2020-04-11T23:00:00+08:00
2020-04-11T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
1
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>数据只有被看见,真相才有机会浮出水面。</p>
</blockquote>
<p>对于任何一家公司,数据未必是充分条件,但一定是必要条件,如果连数据都看不到,做任何决策都只能基于经验算命,风险极高。</p>
<p>数据如此重要,但数据往往不容易被看到,更别提更及时的看到,现在也的确很多公司成立所谓大数据团队,在业务场景中没有找到有价值的发力点之前,很多大数据团队也会沦落为公司的报表取数器,这一方面反映出数据价值透出的紧迫性,也一方面看出公司为了快速获取数据而不惜动用大数据团队的窘迫局面。</p>
<p>而这个问题的本质特别简单:如何让数据库里的 dbs/tables 的成千上万个字段,快速的呈现在 HTML 的网页上?本文写于 2019 年初,介绍的是项目中前期的技术架构方式,希望能给大家一些启发。</p>
<p><a></a></p>
<h2>数据价值逐步呈现的链路</h2>
<p>但呈现只是一个小小的环节,在它的前后有更多可以做的事情,在我的视角里,数据从冰冷的库表到最终对公司有更大决策价值,可以分为这几个大的阶段:</p>
<ul>
<li>
<strong>收集阶段:</strong> 依赖各种业务场景的端载体和基建支撑来把数据回流汇总到线上数据库;</li>
<li>
<strong>加工阶段:</strong> 把业务数据库/表同步到一个独立的数据仓库;</li>
<li>
<strong>制作阶段:</strong> 从 SQL 到 HTML 展示报表的整个制作上线过程;</li>
<li>
<strong>整理阶段:</strong> 基于公司的业务域和行业特征梳理更严谨的数据定义;</li>
<li>
<strong>聚合阶段:</strong> 针对公司/事业部/部门/产品线来把数据结果聚合成看板和大盘反映业务健康;</li>
<li>
<strong>趋势阶段:</strong> 在大盘基础上增加时间和更细化的业务观测维度来把周期内数据趋势呈现出来;</li>
<li>
<strong>分析阶段:</strong> 从产品上线/技术优化/运营玩法/业务打法等节点上把关键事件集成到趋势中给出变化原因;</li>
<li>
<strong>决策阶段:</strong> 更自动化智能化的依托于算法和规则来做业务预警/目标管理来直接驱动业务。</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368198-58352b2e-cbb5-478d-96ba-2e413e3b9fad.png#align=left&display=inline&height=912&originHeight=912&originWidth=1714&size=0&status=done&style=none&width=1714" alt="" title=""></p>
<p>每一个阶段都更进一步,更深一层,一二三阶段是很多公司都做了的,是数据价值更大化的基础,没有一二三的基建准备,再往后会很艰难,我们今天要关注的是第三个阶段,也就是制作,这一道坎儿已经成为很多公司的痛点,而解决这个痛点就要深入到过程中分析。</p>
<p><a></a></p>
<h2>传统数据报表的开发流程</h2>
<p>在给出我们的解决方案之前,我们先看下传统方式让数据可见的两个步骤,这也是小菜早些年的做法:</p>
<p><a></a></p>
<h3>所有数据从各个端/源流入数据库持久化成一张张表</h3>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368197-3ef6acec-6b90-4dda-ae49-ae9e62bfbdf1.png#align=left&display=inline&height=544&originHeight=544&originWidth=1736&size=0&status=done&style=none&width=1736" alt="" title=""></p>
<p>这时候我们往往可以从数据库的管理界面,或者命令行来用 SQL 命令筛选一些数据,也可以导出成 Excel 做一些数据分析,这是最原始的阶段,优点是一句 SQL 就能搞定一张报表,快速导出分析,缺点是必须懂 SQL 语法,还得理解所有字段的具体业务含义,同时本地要维护几十上百个 SQL 语句,来随时登上去执行,并且数据库和数据库表的权限管理会逐渐放开,最终变成运营和产品经理都上来人肉执行 SQL 的混乱局面。</p>
<p><a></a></p>
<h3>后端的 API 与前端 HTML 结合</h3>
<p>SQL 线上直接查太过于暴力,而且无非很好的维护,所以往往需要动用前端工程师和后端工程师,来共同实现一个报表,让销售/运营/产品经理等各个角色都可以打开网页看数据,既然是前后端合作,就必然存在接口约定,字段约定,筛选条件约定,翻页数量约定配置,各自开发,前端写静态页面、接口调用和占位符填充,后端工程里写 SQL,包装专门一个接口注册到网关上,前端后端联调测试后,最终各自发布上线。无论报表是简单还是复杂,几乎都要遵循这样的一个流程,最终展示这样的一个报表页面:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368199-1d155fac-aa2f-4c4d-8342-5e559f61e5e9.png#align=left&display=inline&height=800&originHeight=800&originWidth=2692&size=0&status=done&style=none&width=2692" alt="" title=""></p>
<p>在这个基础之上,才有可能基于 Excel 或者接口数据做一些简单的可视化的过程展示,比如:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368178-04c84004-7375-40d2-9c2d-b10b101f2afe.png#align=left&display=inline&height=776&originHeight=776&originWidth=1720&size=0&status=done&style=none&width=1720" alt="" title=""></p>
<p>现实是,很多人对上面流程是无感的,取数据不就应该这样么,无论是一二十个页面的一二十个报表,还是三四百个页面的三四百个报表,自然不会有人对参与这个过程的工程师投以关注,而这样的一个 SQL 转接口的后端工程师和一个接口转 Table 的前端工程师的职业成长却会收到很大影响,一年要花好多时间来机械式的做数据报表,更要命的是,由于开发资源和工期的紧张,往往数据报表的优先级会低于业务需求,这意味着业务上线后还需要等一段时间的开发排期才能看到业务数据,这对于快速迭代的业务是非常致命的,无法敏捷的根据数据做及时调整,后知后觉。</p>
<p>要打破这样的一个魔咒,工程师可以有真正的成长,看数据的童鞋可以更快更舒服的看到数据,就必须从技术上找到突破点,拿到对所有人都友好的结果,就必须通过技术的升级来驱动业务,让决策更高效。</p>
<p><a></a></p>
<h2>数据仓库是报表量产的必要基础</h2>
<p>所有的数据都有它的决策时效性和整理周期,比如当我们看过往周维度的数据,这些数据可以是昨日之前甚至是本周之前的数据,如果我们想要看实时成交大盘,那么可能就要有小时表或者分钟表,能实时有数据获取,无论是实时数据还是非实时数据,我们都希望不要连接线上的生产数据库,而是一个更稳定又不那么敏感的数据库,这个角色往往是数据仓库。</p>
<p>要建设一个存储历史数据的数据仓库,唯一要做的事情,就是从生产数据库按照分钟,小时,天的规则往数据库搬砖,搬的时候也可以有一些简单的必要计算规则或者收敛规则,比如把一些用户表进行合并处理等等,而搬的动作,往往用 Python 脚本搬砖就行。</p>
<p>而对应到上图,就是第二个步骤,小菜经过几年的迭代,刚好也沉淀了一个可用的数据仓库,我们从这里开始出发。</p>
<p><a></a></p>
<h2>数据报表的 SQL 拼接工具开发</h2>
<p>既然 SQL 到 HTML 展示是痛点,需要多人参与,那么如果开发一款工具,通过它可以把 SQL 自动执行,然后自动渲染为 HTML 页面,痛点不就解决了么。</p>
<p>我们最初也是有这种思路,但后来发现,除展示,还有一个更大的痛点,那就是 SQL 里面大量的字段英文名,实际上它要对应到一个具体的业务中文名,而这个字段有可能是经过 SQL 的多个字段计算而来,它实际的中文名只存在于运营的脑海中,开发并不清楚,所以只是丢一个 SQL 不能解决问题,另外就是有很多字段的中文名其实是可以复用的,但每次都重新去找人问效率很低,最好是有一个中英文的字段名称池,每张报表都沉淀一些字段下来,下次再制作进去挑就好了。</p>
<p>所以我们让设计师设计了一个版本,长这样子:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368180-e845b16d-3c78-4106-9bee-92e30b6fed86.png#align=left&display=inline&height=658&originHeight=658&originWidth=2096&size=0&status=done&style=none&width=2096" alt="" title=""></p>
<p>显然这完全是无法满足报表的制作和量产的,原因是设计师是很难很难理解 SQL 这样一个查询语言打散再组装在一个工具里面应该是怎样的流程,所以我们就完全摒弃了设计稿,完全由前端工程师来驱动,边学习 SQL 边开发持续迭代。</p>
<p>具体实现的时候,我们把思路倒换过来,在 SQL 执行之前,还应该有一个 SQL 拼接的过程,或者说制作 SQL 的过程,这个工具就是让后端工程师和懂 SQL 语法的产品经理,直接在工具的可视化界面中跨库跨表拼 SQL,同时把英文字段名和中文名称对应起来,然后执行制作后的 SQL 就可以了。</p>
<p>先看拼接后的 SQL 长的样子:</p>
<pre><code class="sql">SELECT
a.city_name as `城市`,
a.cat_name as `品类`,
sum( a.sku_num ) as `订单件数`,
sum( a.sku_weight ) as `订单重量`,
( sum(a.total_fee)/100 ) as `订单收入`,
( sum(a.order_cost)/100 ) as `订单成本`,
( sum(a.order_first_freight)/100 ) as `一段物流费用`,
( sum(a.first_gross_income)/100 ) as `一毛额`,
( ifnull(sum(a.first_gross_income) / sum(a.total_fee), 0) ) as `一毛率`,
( ifnull(sum(a.discount - a.coupons_discount_fee), sum(a.discount))/100 ) as `立减`,
( ifnull(sum(a.first_gross_income - a.discount + a.coupons_discount_fee),sum(a.first_gross_income - a.discount))/100 ) as `一毛净额`,
( ifnull(sum(a.first_gross_income - a.discount + a.coupons_discount_fee) / sum(a.total_fee),sum(a.first_gross_income - a.discount) / sum(a.total_fee)) ) as `一毛净率`,
( sum(a.coupons_discount_fee)/100 ) as `优惠券`,
( sum(a.first_gross_income - a.discount)/100 ) as `二毛毛利额`,
( ifnull(sum(a.first_gross_income - a.discount) / sum(a.total_fee), 0) ) as `二毛毛利率`,
( sum(a.subsidy_fee)/100 ) as `红包消耗`,
( sum(a.second_gross_income)/100 ) as `二毛额`,
( ifnull(sum(a.second_gross_income) / sum(a.total_fee), 0) ) as `二毛率`,
( sum(a.pickhouse_taking_wastage)/100 ) as `周转仓盘点报损额`,
( sum(a.allhouse_taking_wastage)/100 ) as `综合仓损耗额`,
( sum(a.indemnity_fee)/100 ) as `赔款额`,
( sum(a.third_gross_income)/100 ) as `三毛额`,
( ifnull(sum(a.third_gross_income) / sum(a.total_fee), 0) ) as `三毛率`,
( sum(a.second_freight)/100 ) as `二段物流运费`,
( sum(a.forth_gross_income)/100 ) as `四毛额`,
( ifnull(sum(a.forth_gross_income) / sum(a.total_fee), 0) ) as `四毛率`
FROM db1.tables1 a
GROUP BY a.city_name, a.cat_name
LIMIT 50</code></pre>
<p>而 SQL 的拼接重点是两个:</p>
<ul>
<li>字段中文名的映射,无论是具体的字段还是公式计算后的值</li>
<li>SQL 计算符和条件的支持,比如 sum/ifnul/Group By/OrderBy/HAVING 等等</li>
</ul>
<p>字段名映射和计算符的支持,这个过程的编辑是在这样的界面上完成的:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368249-9c41bdbb-1111-4354-8018-5510f8cd716a.png#align=left&display=inline&height=1240&originHeight=1240&originWidth=2452&size=0&status=done&style=none&width=2452" alt="" title=""></p>
<p>除此以外,还有各种查询条件的支持,比如小于等于大于等于等等:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368218-f06e1888-dab9-4c39-b888-d50bbdfa755d.png#align=left&display=inline&height=1140&originHeight=1140&originWidth=2252&size=0&status=done&style=none&width=2252" alt="" title=""></p>
<p>有了 SQL 就等于有了数据获取能力了,就可以通过 NodeJS 去链接数据仓库查询到响应的数据了,接下来要解决的问题是如何展示。</p>
<p><a></a></p>
<h2>数据报表在页面的自动展示</h2>
<p>在解释页面展示之前需要先了解一下这个服务中 Graphql 的 Schema 里面和这个页面有关的 Type 结构关系:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368187-a79ff0c9-8b1d-449e-915f-9cc9a94e23e7.png#align=left&display=inline&height=1082&originHeight=1082&originWidth=468&size=0&status=done&style=none&width=468" alt="" title=""></p>
<p>user 挂在根请求下面,report 挂在 User Type 下面,表头和数据还有数据统计的都挂在 Report Type 下面,展示页的页面大致是长这样的</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368231-eb0efbd5-db9b-4b36-86b2-d81f02ace7ae.png#align=left&display=inline&height=1664&originHeight=1664&originWidth=2834&size=0&status=done&style=none&width=2834" alt="" title=""></p>
<p>整个加载分为三部分</p>
<ul>
<li>user 请求加载地址菜单</li>
<li>报表页加载报表基本信息(表名,表头等)</li>
<li>报表页面加载数据(tbody 和 pagination)</li>
</ul>
<p>第一步在刚进入任何页面时已经加载了,这里就不提了。下面这图主要概述进入一个报表页面的加载逻辑,与服务端的 Resolver 的执行顺序。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368255-ed8382b8-b2ed-446e-b0ee-557ecfa72c36.png#align=left&display=inline&height=2118&originHeight=2118&originWidth=3792&size=0&status=done&style=none&width=3792" alt="" title=""></p>
<p>可能你会发现在请求页面 pagination 和 tbody 的时候依旧会经过 Query.user -> User.report 这两个 resolver,为什么不直接把 report 的 resolver 挂到 Query 下面呢?这么做的原因很简单,为了有效的控制权限,并且不需要写太多额外的代码。也就是说和用户权限相关的东西直接挂到 User 这个 Type 下面,那么下面的的 resolver 的 parent 就是 user,方便获取 user 权限的信息。</p>
<p>另外,我们希望报表可以适配到多端,这里我们也花费了大量的心力,封装了很多种比较复杂的移动端报表组件,比如下面几个图是数移动端的尝试</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368257-1af7af05-b5dd-4265-aa24-aca45e3ed50e.png#align=left&display=inline&height=1156&originHeight=1156&originWidth=2056&size=0&status=done&style=none&width=2056" alt="" title=""></p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368215-c471193d-3931-45af-b6c0-c3c9e6481da3.png#align=left&display=inline&height=1152&originHeight=1152&originWidth=2052&size=0&status=done&style=none&width=2052" alt="" title=""></p>
<p><a></a></p>
<h2>数据权限的处理</h2>
<p>数据是一家公司最隐私的资产,那么作为一个数据产品,权限必然是一个需要建设的领域,我们目前的权限是这样的流程:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368228-d118f3f7-a447-4fc7-a6e5-0fa36eb091fa.png#align=left&display=inline&height=800&originHeight=800&originWidth=653&size=0&status=done&style=none&width=653" alt="" title=""></p>
<p>这里权限分为了两类,菜单权限以及数据权限。所谓的菜单权限就是最通俗的该账号是否有权限访问这个页面,而数据权限则是该账号访问这个页面之后可以查看的数据维度。举例就是现在有一张运营效果的全数据表,那么首先只有能看这张报表的运营账号才能查看,其次就是假如这个运营账号是北京的,那么他便不该看到上海的运营数据。</p>
<p>要实现这个,需要一个基本的用户权限中心,通过报表的 ID 以及账号 ID 校验该账号是否可以进入该页面,比较复杂就是用户数据维度的权限控制,但是实际实现只需要在最终的 SQL 中加入一条 WHERE 条件,通过结果反推,那么只要一个动态的 WHERE 条件生成模块,该模块需要关联用户或角色,利用传入的用户或角色信息,生成对应的条件(请求其他权限或者通过数据库查询或直接返回等)。</p>
<p>如上述的运营例子,那么先通过 userId,查询该用户 ID 下的运营账号管理的城市 ID,返回生成一条类似</p>
<pre><code class="sql">a.cityCode in (3,2,1)</code></pre>
<p>这样的 SQL,替换或插入到最终查询的 SQL 之中去就可以了。</p>
<p><a></a></p>
<h2>量产后的报表价值</h2>
<p>在我们实现这个报表系统后,短短一年多,几百张报表迅猛上线,成为了整个公司非常核心的一个产品</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368223-91920323-fa33-40d9-a450-68c90ee04798.png#align=left&display=inline&height=876&originHeight=876&originWidth=2364&size=0&status=done&style=none&width=2364" alt="" title=""></p>
<p>同时我们也遇到了一些报表查询相关的一些性能瓶颈和挑战,关于这一块我们后面会推出一篇文章来详谈,先看下一个一些比较慢的查询监控:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563444368297-ced8c848-190b-4f60-b582-7bdec17366f3.png#align=left&display=inline&height=1184&originHeight=1184&originWidth=2596&size=0&status=done&style=none&width=2596" alt="" title=""></p>
<p>如果查询这么慢到了好几秒甚至十几秒的时候,我们想要在上面做进一步的可视化展示,就会遇到更大的技术挑战,这个挑战我们下一篇来谈谈如何对数据做计算方案的技术选型。</p>
<p><a></a></p>
<h2>总结</h2>
<p>这一篇我们花费了大量笔墨讨论了数据报表工程化和规模化量产的必要性,是为了向大家展示一种纯技术驱动的理念,就是没有什么繁重的开发模式是天经地义的,一定有可以突破它量产它的办法,只不过需要在技术实现和产品路子上打开想象力,那么通过这样的建设,我们也拿到了非常漂亮的业务结果,也在技术上找到了很大的成就感。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=NKTVdty2cXRSi5QYQXFJfw%3D%3D.THNsssvNP0uMlMxyrlzfi7UHFWHekBF4vaDxLXfGUek%3D" rel="nofollow">关注 Scott 跟进我的动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
新人成长:新人在前端团队如何快速成长为技术骨干
https://segmentfault.com/a/1190000022294415
2020-04-10T23:00:00+08:00
2020-04-10T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
9
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>不想当将军的兵不是一个好兵,不想成为技术骨干的技术人不是一名好技术。小菜的一个妹子如是说。</p>
</blockquote>
<p>本文写于 2019 年初,写这篇文章之前,团队每个小伙伴都给出了自己的答案,我挑几个给大家曝光下:</p>
<ul>
<li>观点 1:有明确的职业规划、持续学习和总结输出;</li>
<li>观点 2:独立思考、消化吸收、深度钻研、心态好、沟通好、会合作、有团队精神;</li>
<li>观点 3:技术难题攻坚、技术方案比对、学会管理资源项目与情绪、会沟通、有感染力;</li>
<li>观点 4:做好视觉、把握视觉细节、拥抱业务、有担当、敢冒险、心态好;</li>
<li>观点 5:明确目标、心态开放、主动承担责任、跳出舒适区、持续积累;</li>
<li>观点 6:基础夯实、经验积累、学习能力、沟通协作、职业化、多看书。</li>
</ul>
<p>不知道大家看完这些关键词作何感想,随便挑出几个词,大家可以摸着胸口问自己,做的足够好么?是不是在很多方面自己都有坚持去做了,很多方面执行的也还不错,比如多看书,比如主动承担责任,没有 10 分也有 7 分 8 分,但好像自己没有成为心目中那个朦朦胧胧的技术骨干呢?</p>
<p>我曾经在 2018 年 7 月份把团队的整体能力做了一次盘点,将它对比 2017 年 7 月份,一年前后团队成员的成长速度,大家也可以参考制作这张图(如果你是管理者建议每季度做一次),列出团队所需要的技术栈等能力,然后逐项标记,星星越多代表能力越好,红色的星星代表自己在 1 年内新 Get 到的和继续沉淀的技能,整体排下来,不仅对自己的了解更直观,对于自己在整个团队中的位置也更了解:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563236344155-d6312203-0073-4f60-822f-21e0cd507c34.png#align=left&display=inline&height=918&originHeight=918&originWidth=1850&size=0&status=done&style=none&width=1850" alt="" title=""></p>
<p>而图中,像小 ABCD 属于是有一定工作经验的员工,但 AD 也是团队新人,为什么能成长这么快,每年会多出十几颗星星,以及像小 EFHI 则是属于职场新人,也能在一年时间内增长这么多技能点,我对所有人复盘后,发现所有人的成长路径是不同的,但成长内核是类似的,我想这个内核是大家关心的,那我们就往下看吧。</p>
<p><a></a></p>
<h2>技术骨干不会凭空产生</h2>
<p>技术骨干的定义是相对的,这个相对的参考系横轴是与同团队同学比较,纵轴是基于当前公司业务的研发难度而言,前者与人的比较很残酷也很主观,工作年限的长短并不能决定一人是否是团队的核心骨干。一个工作 6 年的人不一定是团队的核心骨干,而一个工作 3 年的人有可能成为团队技术的顶梁柱,而公司业务的研发难度则是一块试金石,团队有人搞不定但也有人总是能攻坚下来。</p>
<p>我们探讨这个话题的背景是几乎所有同学都希望自己成为技术骨干,而结果往往是只有部分人会在当下成为公司的技术骨干。事实上公司里是没有技术骨干这么一个岗位职称的,他往往存在于团队 Leader 的心目中,也能间接通过职级反映。在大家的眼中,往往是那个冲刺在一线攻坚最难项目的人,我们既希望自己成为这个他,又畏惧自己承担不起,自己也可能确实搞不定。这是一种变相的职场碾压,话很糙,但在哪里不是如此这般呢?</p>
<p>高考的班级里,长跑的赛道上,甚至是同行业处于竞争状态的几家公司,大家的视线都是随着领先者而移动,而领先者对于落后者的碾压始终是一种现象。</p>
<p>对于现象,我们要中立观察:领先就是领先,而碾压无处不在。碾压也一定会给自己带来无形的压力,也可能产生负面情绪。碾压这个词是非褒义甚至非中性的描述,我们应该关注的是领先的意义,碾压的本质不在于它的含义,而是领先的意义,领先是任何一家公司,任何一个团队,任何一个个体都希望发生的事情,如果把它定义成一段周期内的领先,这段领先就是我们所期待的奇迹。</p>
<p>而我们希望这个奇迹可以快速发生,持续发生,最好是发生在我所在的公司里,我所在的团队里,或者发生在我自己身上。</p>
<p>再回到技术骨干这个词,我们就清楚的看到,它是一段周期内一个人处于领先时的状态,这个状态是一种人设,有可能不会一直持续,也会被他人超越,但这个状态一定不会凭空产生,因为领先的前提是,自己积累越来越多傲人的成绩,而傲人的成绩一定不是等出来而是拼出来的。</p>
<p><a></a></p>
<h2>技术骨干身上的几个特征</h2>
<p>前面我们对技术骨干的存在合理性建立了一个认识,我们接下来看看在他/她身上会存在的几个明显特征:</p>
<p><a></a></p>
<h3>技术底子扎实</h3>
<blockquote>万丈高楼平地起,靠的就是深厚的地基,团队楠哥语录。</blockquote>
<p>技术底子是工程师能力的核心基础,技术栈语言栈的广度深度,工程框架设计、原理的理解和运用的程度,这些方面不够扎实基本上与技术骨干无缘了。</p>
<p>至于说广度要多广,深度要多深反而没有一些清晰的指标。现在前端技术栈本身就是上下越来越厚,左右越来越宽,在 PC Web 的 Javascript 的单一技术栈上,如果积淀够深也足以支撑一个骨干的长成,同样在 ReactNative/Node 方面都如此,并不是前端的主要技术栈每一样都逐一掌握的足够好才能成为技术骨干,反倒是只要满足一专多长,这一专成立甚至是多个擅长项成立,那么就具备成为技术骨干的实力硬件基础了,接下来就要看软件实力了。</p>
<blockquote>小案例:团队有个小伙伴 A,喜欢思考,关于 React 全家桶的知识储备非常扎实,从框架设计到内部运行原理以及同类型数据流方案的优缺点,所有人与他交谈都能有所收获,甚至醍醐灌顶。</blockquote>
<p><a></a></p>
<h3>善于独立解决难题</h3>
<p>无论是在业务的技术架构中,还是纯技术性的攻坚中,我们知道工程实现会遇到五花八门各种各样的问题和难点,这些问题的解决和难点的突破,有许许多多可以尝试的办法,其中一个快捷键就是去请教团队里更资深的人,也就是场外求助迅速解决,但一个技术骨干在这方面往往能独立性的快速推进。</p>
<p>这里强调独立性并不是说他也不去咨询团队内外的人,而是说他不依赖团队内外的人,通过咨询是给他提供更多分析问题的视角,最终的解决依然是靠他个人。</p>
<p>问题解决的过程也因人而异,有的会快速的 Github/StackOverflow/Google 甚至百度/搜狗微信参考和 review 各种开源实现,有人会直接进入框架代码的阅读和逐行 Debug,有人会拿一支笔在画板上反复勾勒推理,无论哪一种,最终都是靠个人的能力解决问题,而每次解决问题后,能看到他征服困难后的成就感,用各种表情写到了脸上,身边的人也会受他感染共享征服感,大家可以设想下如果身边好多个技术骨干,每天都连续上演征服成功的案例,这对于团队士气提升是非常有益的。</p>
<blockquote>小案例:团队有个小伙伴 B,喜欢独辟蹊径,无论多难受的问题到了他这里,总能独立以异于常人的方式把问题解决掉,这种问题解决的越来越多,功力也日渐增长,每次解决完都要在团队里炫耀吹嘘一下自己多牛逼,所有人都跟着开心片刻,这种氛围最终会影响到身边人。</blockquote>
<p><a></a></p>
<p><a></a></p>
<h3>不畏惧陌生领域的挑战</h3>
<p>在一家增长型的公司,除了能感受到组织架构和业务上每个季度的变化外,还有一块技术人最看重的东西,那就是业务进程内外潜在的巨大技术机会与挑战,所谓技术成长空间。</p>
<p>这种机会通常是伴随业务的快速发展和大胆试错而来的,它有可能是业务驱动、运营驱动或者产品驱动,也有可能是技术驱动,无论哪种都可能会在原有的团队技术栈里面炸开一个口子,这个口子可能就是所有团队的工程师都不熟悉的领域,大家都不熟悉怎么办,除了快速招人外,就必须有技术骨干顶上去硬啃,至少能支撑项目的 1.0 粗糙版跑出来。</p>
<p>那么这时候技术骨干身上的不畏惧等于什么?怎么才叫不畏惧?一句 “都闪开,老子来” 口号算不算,我觉得只能算一半,前一半是刚开始时的勇气,另外一半是持续去挑战所带来的征服欲,征服欲越强或者兴趣越浓,越有驱动力去想法设法钻研,征服欲越弱,眼前的问题就会变成枯燥的任务,就算解决了,带来的征服快感也随之变弱。</p>
<blockquote>小案例:团队有个小伙伴 C,遇到的一个技术领域上黑盒,在我们团队决定花精力去钻研个初步方案后,小伙伴自费搞了必要的设备,甚至整个过年期间都在强攻技术难点,终于春节后,带着可行性的方案来公司,为业务带来了极大的想象空间,驱动他的不仅仅是任务,更是征服欲所带来的满足感。</blockquote>
<p><a></a></p>
<h3>极少让别人失望</h3>
<p>这个更多是在说结果,这个别人可能是合作方,可能是你的主管。为什么把这个单独拎出来,是因为不是所有技术好的同学都具备这样一个使命必达的执行力,只要允诺下来的事情,无论多难无论成败,都能拿出一定的成果来让等待的一方有所收获,这是一个技术好的同学走向技术骨干最重要的一个特征之一。</p>
<p>技术骨干的同学技术一定好,但技术好的同学未必是技术骨干,这一点往往被忽视,也是童鞋们在工作中最容易想当然的一件事情,如果你让别人失望的次数到了一定数量,那么距离技术骨干也还有一段距离了,因为骨干脱离了公司脱离了团队就会失去实际意义。而一个团队一定有它特定的定位和目标,目标的达成是衡量这个团队战斗力非常核心的标杆,也是主管脑海中的骨干的画像特征,定义骨干与非骨干的分水岭就在于此了。</p>
<p><a></a></p>
<h2>如何快速成长为技术骨干</h2>
<p>上面我们聊了技术骨干存在于我们大脑中的投影,也知道了他身上具备的显著特征,那怎么成为技术骨干呢?可以从下面几种路径入手:</p>
<p><a></a></p>
<h3>1. 弄清楚任务的 what 和 why</h3>
<p>任何一个任务都有特定的背景和目的,比如老板让你去预研下 Electron 开发客户端软件的可行性,这是一定要问清楚这个可行性的软件客户端开发方案是为了承载什么场景的需求?为什么要用客户端而不是网页的方式来实现?</p>
<p>这就是任务的 what 和 why,需要你跟老板明确对焦,有可能他需要的仅仅是一个可以收发消息的聊天功能实现方案,这时候一个 socket 的聊天室网页版可能就能满足需求,应该是去调研 socket 更有价值而非是 Electron。一旦真的是去调研了,即便调研过程很漂亮,但对于最终问题的解决不是最优解,损失的不仅仅是老板对你的信任,更是失去了一次独立最优解拿下问题的机会。</p>
<p>有了这样的一个任务的对焦过程,我们会更了解到自己做这件事情的价值,对于结果也会更有期待,原始的驱动力天然就存在了。</p>
<p><a></a></p>
<h3>2. 从过程中而不是从结果中学习</h3>
<p>在微信群和社区经常看到提问的同学,非常焦急的等待一个问题的答案,或者是自己独立解决问题的过程中各种快捷方式求结果,拿到结果或答案后便迅速用到项目中,之后便丢到脑后,这是非常不可取的学习方式,每一次丢弃都丧失了一次成长的机会,要知道结果的价值是相对于业务和项目而言,而过程的价值才是相对于自己而言。</p>
<p>每一次拿到结果后,可以写一篇博客记录,也可以记个笔记,也可以弄张纸 review 一下,也可以讲给别人听,本质上是让自己重新播放刚才解决问题的过程,从中观察是什么样有意无意的动作和思考方式,启发了自己最终找到关键线索和路径,这样的一个思考过程反复锤炼会形成一个解决问题的套路库,比如什么问题直接 Google 就可以,什么问题要深入到代码中去深究,什么症状大概率是人为使用错误而非程序设计 Bug,从外向内再从内向外,让自己不仅仅对于技术框架或方案的细节更了解,也对于它们宏观上的特征更了解,最终让自己的问题解决能力越来越高效。</p>
<p><a></a></p>
<h3>3. 以开放的视角看待一切技术存在</h3>
<p>如今互联网所有上层的繁荣集市都是建立在各色各样的技术底层之上,无论是从 ASP 到 Go 这样的语言层面,还是 jQuery 到 React 这样的框架层面,从硬件到软件的方方面面杂糅在一个无限复杂的网络中执行着自己 0 和 1 的信号逻辑,任何一只能抓老鼠的猫都是一只有用的猫,技术同样如此,合理存在必然有特定场景下的价值,我们可以打开胸怀去观察甚至去接纳。</p>
<p>但开放到什么程度呢,是无限开放么?答案肯定不是。我们凡胎肉身不可能把目前极度细分的技术领域都摸过来,只能在特定的工程背景下做必要的心态开放,在未见到一个技术的真正价值之前不轻易否定它,在未评估好在自己项目中落地可能性之前不轻易使用它,这是两个层面的接收和拒绝,前者是价值与合理性的接收,后者是可行性落地与成本评估的拒绝。</p>
<p>聊这么多,跟技术骨干有什么关系呢?是因为技术骨干永远不知道自己接下来会面临一个来自什么领域的挑战,而保持视界的开阔和心态开放会给自己注入足够多的信息线索,有选择性的尝鲜,保持试错的好奇心,总是尝试去琢磨一个技术方案的核心价值点和设计策略,这样即便面临陌生领域的挑战,也可以用各种参照比对的方法为自己快速构建一个解决问题的路径坐标系,在这个坐标系里面,上下左右延展总会碰到之前大脑中索引的一些信息线索,从而触发一些灵感的产生,这些灵感的产生可能就是问题得到有效解决的关键。</p>
<p><a></a></p>
<h3>4. 坚持高强度的学习和持续性的总结</h3>
<p>当我们可以正确的认知一个任务的特征,也能有一个开放的心态和开阔的视野观察问题,也能从问题解决过程中回收套路进行索引的时候,我们距离一个技术骨干就差一个习惯了,这个习惯就是高强度的学习和持续性总结的习惯,为什么学习要高强度,而总结要持续性呢?</p>
<p>学习是为了输入,知识体系变得有力量一定需要足够的输入,而输入从哪里来,连续做两年 React 框架内的业务代码可以带来沉淀么?其实也未必,如果常年做业务但没有深入框架内部学习,也没有对框架之内的设计(如数据、状态、交互、异步、更新等等实现原理)更没有对框架之外的意义(组件、API、工具链、维护与封装等成本与效率)有足够的认识,那么所谓的内修基本功是站不住脚的。</p>
<p>至于说高强度,是因为低烈度的输入会伴随着遗忘,更会导致整个学习周期过长,更容易看不到质变而感觉枯燥无味甚至弃坑而去,这尤其在新人身上容易发生。如果让我建议一个学习的周期,我觉得 1~2 个月的高强度学习,分成 2 ~ 4 个小阶段是可取的,如果 2 个月没有明显进阶,那么需要推倒重来从 0 开始,而不是续命。</p>
<p>伴随着学习的一定是总结,所有的美食入口到胃,长长的肠道蠕动很久后,营养成分才能被机体充分吸收,最终再合成为新的动力之源要么燃烧要么存储备用,这时候的摄入才转成自己身体的一部分。无论是项目开发还是单纯的学习,都要给自己建立一套 review 机制,通过 review 把自己摄入的零碎的知识点进行重组串联,反反复复的理解消化,并重新输入一套新的知识蓝图把它刻到自己的记忆硬盘中,通过这样的持续性的总结归纳,自己的记忆硬盘会的不断的升级调整,最终对于所有知识的理解会越来越立体。</p>
<p><a></a></p>
<h2>小结</h2>
<p>以上从准备、过程、心态和习惯上为新人设定了一个骨干长成的路径,但真实的技术开发远远比这个复杂,需要再投入更多的心力精力帮自己迈过去一个个的天花板,所谓打怪升级再升级打怪,对于一个前端新人来说,在 2 ~ 4 年的工作过程中,最容易成长为技术骨干,而这段周期最好也有稳定的职场环境和社交环境,避免频繁跳槽,避免受到太大干扰,把握住这段黄金期,随后的技能大树、职场之路会越长越健壮越走越宽阔。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=iY%2Fgi9Mjc29%2BPy7EopqCLA%3D%3D.JcMEZL9CGIVL1h66kYzgRSMCUqGZy41vKSpzhVl2ycM%3D" rel="nofollow">关注 Scott 跟进我的动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术管理:如何带领管理少于 10 人的前端小团队
https://segmentfault.com/a/1190000022294438
2020-04-10T23:00:00+08:00
2020-04-10T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
15
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream。</p>
<blockquote>近期面试了一个工作 10 年的前端主管,带领了一个 9 人的前端团队,从他身上明显发现了两个致命的问题:一、他没有意识到成员拥有成长空间的重要性,二、他没有以培养接班人的心态打造团队腰部力量,最终事无巨细亲力亲为但整个团队并没有持续发生更快更好的变化,总结出一句话就是带领不是领导,而是领着冲刺成绩,管理不是权力,而是激励授权培养更多骨干。</blockquote>
<p>抛开场景谈管理,跟抛开场景谈技术一样,很容易沦为干巴巴的教条,我这一篇会以小菜前端为样板,结合实际的案例,给大家引入我的管理思路,以及通用的方法论和观察视角,只要能给大家带来一点点启发,最终带团队少走了那么一点点弯路,本文的价值就足够大了,因为带团队本身就是一项因人而异的艺术,而艺术很难加上刻度进行量化。</p>
<p>另外,我会换用问答的形式,来跟各位对话,在每次往下看我的观点之前,请先在内心酝酿你的答案,酝酿成熟后,再往下浏览,这样可以保留属于你自己的思辨,避免被我先入为主,因为管理本身并非是寻求答案,更多是训练如何寻求答案形成落地 Action 的思考习惯,那我们先思考第一个问题:前端工程师这个群体身上有什么特质?</p>
<p><a></a></p>
<h2>重新认识前端工程师</h2>
<p>前端工程师虽是工程师,却与主流技术从业者有诸多不同,最大不同就是想象力创造力爆棚,浑身散发纯真的文艺气息,天真美好浪漫但是一放到荒漠沙洲却常常不堪一击,这是我两年前带团队时分享的一页 PPT:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1555923159802-9f2b8216-2469-42df-a39d-ecfe6826f76c.png#align=left&display=inline&height=311&name=image.png&originHeight=746&originWidth=1792&size=2147746&status=done&width=746#align=left&display=inline&height=746&originHeight=746&originWidth=1792&status=done&style=none&width=1792" alt="image.png" title="image.png"></p>
<p>以及关于前端主要工作场景的一页 PPT:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1557227959671-f402a5f8-f389-42bd-87fe-cb6f14f65a40.png#align=left&display=inline&height=478&name=image.png&originHeight=1052&originWidth=1862&size=411099&status=done&width=846.363618019199#align=left&display=inline&height=1052&originHeight=1052&originWidth=1862&status=done&style=none&width=1862" alt="image.png" title="image.png"></p>
<p>一群人会塑造和改善环境,而环境反过来也会重塑它之中的人,这也是为什么程序员在人群中很容易被一眼识别的原因,那就是特定的工种塑造出我们特定的性格、喜好、气质、观人看事的角度,这样的塑造在前端的行业中更加的深刻更加的剧烈,因此一个前端团队往往比想象中好带,也可能比想象中难带的多,这一群人真的可能会千人千面,与众不同,拢在一起别说团结一致,有时能否听从指挥都是问题,彼此的感情连接紧密程度可弱可强,前端的技术面积宽深度浅,这都是客观存在的事实,并且这个群体可千万不可小觑,如果不用心带不仅会让你目标错失,API 无法完成,甚至整个团队会分崩离散,那接下来让我们来面对这个课题吧,小型的前端团队到底应该怎么带?</p>
<p>要讨论怎么带,我们还要看看一个前端团队在不断成长的过程中,从 1 个人到 5 个人,到 10 个人,到 30 个人,到 80 个人,到 100 个人,你认为这个团队会经历哪些阶段,会有什么样的能力结构,也就是你现在 10 人团队的当下如何,未来怎样?大家对这个充分思考后再看下文。</p>
<p><a></a></p>
<h2>小菜前端的几个时代</h2>
<p>上文聊了前端的个性化特质,再来看下 10 人团队可能处于哪个阶段,2 年前看到蚂蚁金服的玉伯分享了前端的几个时代,非常认同,我把它进行了调整进一步转化到小菜的业务和组织架构上,最后草拟了这样的一张规划图:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1557228972563-20ded2b2-68fa-456f-94f8-a103b95a957f.png#align=left&display=inline&height=691&name=image.png&originHeight=1520&originWidth=2780&size=404541&status=done&width=1263.6363362477837#align=left&display=inline&height=1520&originHeight=1520&originWidth=2780&status=done&style=none&width=2780" alt="image.png" title="image.png"></p>
<p>这几个时代词如其意:</p>
<ul>
<li>人工时代偏人肉,工具设施薄弱,业务繁重,资源紧张</li>
<li>工具时代偏效率,各种轮子往上凑,不太成体系还忙中带乱,业务支撑可圈可点</li>
<li>工程时代偏规模,规模化的用户和业务背后可复用的工程化体系与方案,业务支撑稳定有序</li>
<li>智能时代偏算法,通过对业务深刻的理解和运用来打造出非常好用的产品和服务,极大的解放人力</li>
</ul>
<p>那我们带的团队在 10 人以内,如果不是在 BAT 这种大厂,往往处于工具和工程能力偏弱的阶段,也就是人工时代,业务越重基建容易越薄弱,如果是有很好的团队规划意识以及公司的资源支撑,那么 10 人团队往往会处在人工时代往工具时代的转型期,此时基建往往与业务并进,彼此互相影响,但总体依然会偏向人工,而人工时代的团队特征是什么,这是我们需要思考的问题。人工时代或者说人肉时代,我们对于人的依赖程度很高,这时候如果是纯资源管理的视角,那先思考下你最多能直接管理多少人,你觉得 10 人团队应该管理什么?好管理么?</p>
<p><a></a></p>
<h2>管理半径与团队阶段</h2>
<p>一周五天,一天重点照顾两个人,10 人的团队可以勉强覆盖,根据我的过往经验,一个管理者如果要对每一个成员都负责,都能拿到结果,基本上 10 个人就是一道坎,在 10 人以内,是有机会也有能力对每一个成员负责的,但高度负责后的团队主管会很累很忙,也就是人越少越依赖主管帮带和规划的个人能力,带小团队往往是这样的背景。</p>
<p>还是以小菜为例,我按照阿里的 P 系列来对团队能力层次的几个阶段做了整理,这些不是严格意义上的小菜前端层级分布,只做示意,供大家观察趋势和问题(18 人是当下,25 人是未来小半年后),看完后请思考每个阶段都有什么问题?</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1557299043505-2bc25592-efcd-44a7-9e6f-32eca3bc7cb6.png#align=left&display=inline&height=397&name=image.png&originHeight=874&originWidth=1906&size=398984&status=done&width=866.3636175857107#align=left&display=inline&height=874&originHeight=874&originWidth=1906&status=done&style=none&width=1906" alt="image.png" title="image.png"></p>
<p>第一个阶段,7 人左右,整体工程师能力偏弱,极少数的技术熟练工,资深前端会成为团队的能力天花板,这样的状态如果没有新变化会磨削掉所有人的成长空间,逐渐沦为纯粹做事的工具或者资源,新同学没成长,老同学到天花板,离职率就会变高;<br>第二个阶段,10 人左右,有了带队的专家,但有大量的初级前端,而资深前端数量偏少,这样在腰部的传承这块就会断层,所以此时专家就必须对很多具体的事项负责,也需要对人才的成长和资源的解放负责,带队专家会成为团队瓶颈,如果不得到进一步的团队能力提高和解放,专家的综合能力也会遇到天花板;<br>第三个阶段,13 人左右,补充了更多的资深前端,整体分布看上去趋于健康,但专家变得紧缺,因为有更多的资深前端嗷嗷待哺,依然是在腰部短板,此时会有个别有管理能力的同学涌现,但管理意识和方式都很初级,需要有一些制度性培训性的流程来保障他们融入组织成长;<br>第四个阶段,18 人左右,有了更高层级的专家,专家整体数量变多,但初级前端也变得更多,此时需要有更多具备管理能力的腰部主管出现,这一层职责就落到了专家层,需要专家成为教练,来主导自己的小组方向,将更好的方法论实施起来,帮助同学更快成长,所以这个阶段对于资深前端和专家的需求依然旺盛;<br>第五个阶段,25 人左右,有了更多具备管理能力的资深前端和专家,整个团队的能力传递形成了梯度,整体分布趋于健康,但在初级前端和资深前端交接的这一层 P5+/P6- 成为了能力洼地,需要更多同学被发掘和帮带上来,通常这个时期会有大量意识好主动强有担当,并且能扛风险拿业务结果的同学快速晋升,这个阶段是一个团队真正意义的黄金成长期;</p>
<p>这里提供给大家一种从能力来看团队健康度的视角,实际上的团队所处环境会比图上复杂很多,比如有掉队同学的劝退,优秀同学的离职,有新同学的加入冲击,再加上各种不同的业务交叉时资源的冲突,技术栈的发展畸形,公司大组织架构的变化等等,每个阶段的侧重点都不同, 所有这些都考察者团队管理者的反应速度和决断能力,而正向的业务会带来人员数量的快速增长,因此管理能力与增长的动态变化,会变成团队能力的核心坐标,稍有不慎就会出现管理故障。</p>
<p>虽然每个阶段都不同,但每个阶段都是承接与上一个阶段的成果之上的,越早期时候的方向修正的正确,越后期的扩展和成长才会更顺利,否则团队整体的心智在这些阶段中历经冲击,反而会伤害到整体的团队心理状态和能力梯度,我们切回去到 10 人之前的团队状态,这个时期是整个团队最早期也是最最重要的原子阶段,这个时期所奠定的研发底蕴、工程师文化、分享与影响力、看待业务与技术的态度、自我认识与工程师价值判断等等都是在这个时期慢慢形成雏形,所以千万不要小看人数不足 10 人的时期,这个底子没打好,后面会变灾难。</p>
<p>对于小菜来说,10 人时期主要的管理工作,除了业务,就是技术栈的提前规划预研、工程师的稳定性、团队内技术资产的透明化、一定程度的效率与质量基建,包括工程师的成就感培养和有潜力员工的刻意栽培,这就是此时管理二字此时的含义。</p>
<p>我们花了大量篇幅讨论前端的职业特征、团队的发展阶段,你作为事实上的管理者,或者未来潜在的管理者,要拥有哪些能力,以及从哪些方面来带领这个团队快速成长,奠定必要(至少是不差)的早期基础呢?大家思考一下先。</p>
<p><a></a></p>
<h2>技术 TL 必备能力清单</h2>
<p>管理是一门很复杂的学问,团队越大越依赖管理手段,人越少越依赖带领能力,我们把 10 人团队的管理弱化,同时把此时主管需要的能力简化为带领能力,那么这样的能力如何训练呢?让他成为你技术管理生涯中的雏形能力,为未来你带领 20 人、 50 人团队做好铺垫。</p>
<p>大家可以先思考下,思考后再看下面这几张图,图上是 Scott 刚接手 7 人团队后半年多主要关注的事情(图是半年汇报 PPT 的截图),那时对于管理和带领的认识是没有今天深刻的,后面我会把当时半年多的过程整理成观点:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1557386580243-e68533b6-2f3c-403c-aa24-a092f8964f71.png#align=left&display=inline&height=376&name=image.png&originHeight=828&originWidth=1844&size=2028737&status=done&width=838.1818000147169#align=left&display=inline&height=828&originHeight=828&originWidth=1844&status=done&style=none&width=1844" alt="image.png" title="image.png"><br><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1557386636539-cea205c6-9298-44af-9ea4-b5e7ab9eee69.png#align=left&display=inline&height=250&name=image.png&originHeight=550&originWidth=1798&size=1346204&status=done&width=817.2727095588184#align=left&display=inline&height=550&originHeight=550&originWidth=1798&status=done&style=none&width=1798" alt="image.png" title="image.png"></p>
<p>来到今天,我回头去看过往走过的路,把 10 人团队内需要训练的几个核心能力总结为:敢于担当、建立信任、善于规划、探索创新、培养成就感、扩大影响力。</p>
<p>为什么是这几个,做不做又有什么区别呢?对于我做管理意味着什么?大家可以先思考下,然后我们再针对每一个适当展开一些讨论。</p>
<p><a></a></p>
<h2>担当是拥抱组织的前提条件</h2>
<p>一个团队的管理者,如果没有担当,那就是一场巨大的灾难,这是对管理者最基本的要求。而担当讲着容易,做起来却很难,一旦你带领一个团队的时候,你就需要拥抱这个团队,无论他做的多好的地方还是多烂的地方,无论团队的能力和业绩是出众的,还是扶不上墙的,当你的屁股坐在这里的时候,当组织把你放到这个位置的时候,你对上级主管和组织就是背负着他们的信任和期待,对下面的员工则背负着责任与担当,除非你永远也不坐到具有管理职能的位置上,否则担当是你永远也无法回避的管理门槛。</p>
<p><a></a></p>
<h2>信任是做好管理的黄金基石</h2>
<p>当你要带领一个团队时,你的任何决定都是需要团队的大多数人支持和推进的,那么你就需要争取到绝大多数人的信任,即便一个事情他认为是百分百错的,但是你这里必须紧急执行,那么基于信任他也会尽心执行,否则就容易产生对抗或者过程偏离,而对抗和未尽心尽力伤害的不仅仅是管理者和当事员工,也最终会伤害到公司既定目标的实现,反之,员工需要获得你的信任,你也要获得你老板的信任,这样一层层的双向信任,才有可能在整体推进时候遇到最小的阻力。</p>
<p><a></a></p>
<h2>规划是带领团队的必备素质</h2>
<p>对于管理者来说,要把全团队人的时间用出相对较高的价值,就必须有规划能力,所谓规划,就是把想做的事情坐标化和里程碑化,坐标里的 x 轴是基于时间尺度的团队不同阶段,纵轴是不同阶段需要重点做的事情,而里程碑就是每个特定阶段每个重点事情,它在特定时间点需要达成的目标,这个能力是最容易被技术管理者忽略的技能,大家往往觉得脑海里有个模糊的概念和方向就行了,剩下所有的事情就靠 Coding,一直 Coding,这对于团队是很大的伤害,其实就算不是作为管理者,越是技术走向资深,越是承担更大的挑战,规划能力就越刚需。</p>
<p><a></a></p>
<h2>探索是驱动组织的不二法宝</h2>
<p>技术往往是有趣的,而技术做的事情往往是无趣的,在无趣中找有趣是一个永恒的课题,摆在管理者的面前。如果你是一个喜欢求稳的墨守成规的管理者,那么所有跟着你的同学,他们的成长空间就会受限,反之如果你是一个非常激进敢于冒险的管理者,所有跟着你的同学空间就会快速放大,但同时也会伴随较大的技术冒进风险,所以探索的速度和深度需要结合严禁的规划来实现,一定是基于深思熟虑的有实际价值的规划路径来做探索,而既然要探索,就要解放思想,放开手脚,不要犹犹豫豫左右徘徊。</p>
<p><a></a></p>
<h2>成就是选拔人才的通关门卡</h2>
<p>虽然工作只是混口饭(PS: 惨兮兮的说法而已..),但对于现代的年轻人,表里一致兴趣契合以及技术开发所能带来的成就感,这一点必须单独拎出来说,这里的成就感不仅仅指技术上实现所带来的成就感,更是他职业生涯上有所突破,做的事情能看到实际价值,包括技术深度广度上真真实实的收获,这些收获是个人努力得到的,但这些机会和道路是你为组员设定规划或者是指引的,因此这时候成就他人就是你必须培养的一种能力,也只有通过成就他人才能最终成就业务,成就团队,从而也成就自己。</p>
<p><a></a></p>
<h2>影响是培育文化的终极魔法</h2>
<p>我们通常讲影响力,都很容易联想到技术分享带来的影响力,所谓技术网红的样子,这一点没错,我们在前面专门有一篇文章探讨过影响力的意义和如何做影响力,那放到管理的视角来看,如果团队整体是一个社会化的人,那么影响力就是它的综合口碑,它的外部形象,它给外界所传达的人设,这些虚的东西往往发挥着着非常实的作用,比如对于你的招人,比如对于你团队内文化的促进,比如对于你团队与其他团队的合作关系等等,扩大影响力并且不断的塑造正向的影响力,也是一个技术 TL 不能回避的课题。</p>
<p>这几项能力在职业生涯中不断历练,一个 10 人的前端团队就能带的越来也有章法,但知易行难,在大家当下实际的环境中也一定会遇到种种的困难,我的建议是,选择一到两个作为主线,在特定的时期内重点推动,同时尽可能兼顾其他,通过周期性的轮转,来让团队不断的磨合前进,形成的合力越来越强,就像小菜前端 2019 年的主轴就是认知升级:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1559031527826-bcaa09a5-6d7f-4b2a-a750-1e123600d700.png#align=left&display=inline&height=234&name=image.png&originHeight=424&originWidth=1352&size=111402&status=done&width=746#align=left&display=inline&height=424&originHeight=424&originWidth=1352&status=done&style=none&width=1352" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h2>从问题抽象到行动聚焦</h2>
<p>一旦我们对团队梳理后,脑海中有了明确的主线,那么就可以把团队现存的所有问题进行分类,分类是为了聚焦,在特定时间周期内聚焦到特定问题,投入主要精力进行改善解决,就比如前文提到的,小菜在初期也会有下面的 8 大类问题,此时的小菜刚好是在 10 人规模之内:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1559031647617-71d57a29-0ddc-4598-88f2-d2f639ca2177.png#align=left&display=inline&height=324&name=image.png&originHeight=712&originWidth=1912&size=228140&status=done&width=869.0908902538713#align=left&display=inline&height=712&originHeight=712&originWidth=1912&status=done&style=none&width=1912" alt="image.png" title="image.png"><br>针对这些问题分别聚焦后,以半月到单月的长度,进行了持续半年的推进解决,有的是靠口头,有的靠文档,有的靠工具,有的靠分享,有的靠影响力,有的靠业务赋能,所以小菜才这样一步步克服过来:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1559032038498-555fdd96-4d9b-413e-a656-41be6195b78f.png#align=left&display=inline&height=415&name=image.png&originHeight=912&originWidth=1884&size=603657&status=done&width=856.3636178024548#align=left&display=inline&height=912&originHeight=912&originWidth=1884&status=done&style=none&width=1884" alt="image.png" title="image.png"></p>
<p>当问题都陆续解决的时候,实际上就是管理更上一个台阶的时候,也是团队基础打好,准备打下一场大战役的时候,在这样的一个套路上,我们一直这样操作,2019 年的认知升级,也是为了 2020 年能更好的能力升级,只不过此时面临的挑战是人数超过 20 人的团队它的境况,而它的基础是当初 10 人规模的阶段。</p>
<p>最最后,大家在带这样规模团队时候,需要真的把心放进去,刻意练习担当、信任、规划、探索、成就感、影响力这几个关键词背后的能力,同时把眼光往后面多展望半年,聚焦当下的问题,形成具体的计划逐步推动,相信这个团队在你的带领下,一定会每一周都有一个新面貌。</p>
<blockquote>近两年 Scott 观察到前端行业已经完全进入竞争的深水区,各大小公司的前端 TL 刚刚上任,初带团队,针对前端工程师这个群体,应该怎么管人理事,搭台拿结果,帮带有成长,就成立了这个全国的前端技术主管学习交流群,在人的选用育留上互相学习成长,入群的门坎是你有实线或者虚线在带团队,请加 Scott 微信: codingdream 邀请入群,二维码见下方:</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
职业思考:技术和管理路线之间如何取舍
https://segmentfault.com/a/1190000022294339
2020-04-09T23:00:00+08:00
2020-04-09T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
6
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>程序员的青春饭,有人说是 30 岁,有人说是 35 岁,现实是这样么?真写不动的时候,要不要转,什么时候转,怎么转?</p>
</blockquote>
<p>2018 年,刚好工作 8 年,也是我而立之年,在 30 岁这一年我从技术研发全面的转向了技术管理,经历了一个夜夜深思夜夜失眠的阶段,今天把我的思考结果分享给大家,包括身边的一些人一些事也会贯穿在本文之中,尝试给大家梳理一些选择之前需要考量的因素。</p>
<p>在开始之前,先送大家四句大白话:</p>
<ul>
<li>了解了解不停去了解</li>
<li>规划规划不断做规划</li>
<li>执行执行绝对要执行</li>
<li>回馈回馈坚持做回馈</li>
</ul>
<p>其实按照池老师的处事三原则就是:闭环、谁难受谁推进、Think Bigger,换做是我自己的方式,总结一下,就是不断去了解自己,不断去修正规划,不断的推动执行,不断上下左右回馈,如此反复再无它。</p>
<p><a></a></p>
<h2>做技术到底是做什么</h2>
<p>未来机器会取代我们,就像年轻的工程师会取代我们一样,凭借更佳的脑力运算凭借更低的应用成本,那我们当下做技术到底是做什么?</p>
<p>工程师赖以生存的技术,是驱动这个世界发生质变的核心推力引擎,它的本质是创新也就是再造,通过消耗我们的脑力去更好的消耗计算机的算力,脑力换算力成立的前提是脑力可以做更多意识层面逻辑性的情感性的决策,可以通过强大的抽象能力分析事物的本质,而算力目前还很难做到,等到机器可以做深度抽象做自主决策的时候,就是脑力编程下岗的时候,那时候就要依靠我们人类无穷无尽的想象力与创造力来输出规则给机器,机器帮我们做最优决策和过程实现。</p>
<p>回到当下,最优决策和过程实现还必须靠我们这一代人,而做技术就是在做决策和付诸实现,只不过我们凭借特定的语法规则给机器编写特定的执行任务,而语法掌握的熟悉度、技术运用的熟练度以及对机器和规则运行作用过程的理解程度决定了我们的技术实力是处在哪个段位哪个 Level。</p>
<p>Java 的语法有它特定的结构,PHP/Python/Javascript 统统不例外,这些特定的语法规则和结构我们都可以通过记忆烂熟于心,而它们背后的技术思想,基于它们衍生的特定框架,结合它们所形成的特定语言工具生态,对于这些的熟悉程度又进一步决定了我们运用技术的灵活程度,至于对机器和规则的理解则取决于我们训练大脑的深度和广度。</p>
<p>看到这里,我们再来看技术二字,就很容易明白它无非就是一些技巧规则的运用,而我们常年累月所浸泡的技术体系里面,经常面对的恰恰就是这些技巧和规则,编程经历越久,对于技巧掌握的越多,对于规则理解的越深刻,基于技巧和规则我们能衍生出的再造能力也更强,而通向更强再造能力的过程中,我们做技术的本质就是不断训练自己的大脑熟悉这些技术体系,建立新的认知体系,再创造出新的解决思路和应用方法论,所以到最底层的时候,比拼的还是想象力和创造力,只是很多时候我们空有想象力和创造力,却缺少让想法落地的技巧和规则运用能力,原因在于我们训练的还不够深刻,还不够丰富,也就是量变不够充分,质变也就很难发生,做技术本质就是 架构、编程和运维保障,架构就是训练出来的脑力逻辑性,编程就是规则和技巧,而运维保障则是规则应用的土壤,把它们拆解一下,就是下图上的一些技能点:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562240083739-29028fbe-ecca-4c57-8d10-f9af430fee85.png#align=left&display=inline&height=598&name=image.png&originHeight=1316&originWidth=2324&size=834794&status=done&width=1056.3636134675717#align=left&display=inline&height=1316&originHeight=1316&originWidth=2324&status=done&style=none&width=2324" alt="image.png" title="image.png"></p>
<p>至于如何通过技术训练我们的大脑,实际上就是如何保持技术的快速成长和持续成长,我们前文有过相关的讨论,在这里我强调一点,技术需要持续性的时间投入来训练才能保持一定速度的成长,一旦投入中断,或者投入强度变小,很快技术成长就会降速,甚至没踩上行业趋势的话,会被同行甩在后面,作为这个小话题的结尾,我举一个身边的案例:</p>
<blockquote>有一个同学 13 年毕业,进入大公司历练 2 年,技术趋于资深,后来高薪跳槽到一家创业公司成为核心骨干,创业公司发展迅速,1 年内就有了将近 10 人的前端团队,就任命这个同学成为技术 TL 带领团队,但快速膨胀的业务线迅速吃满了该同学的编程和架构时间,业务越来越多团队越来越大,他也就半推白就的走向了管理岗位,2015~2016 年起 React 进入蓬勃发展的时期,也是 Node 开始大规模应用的时期,他身不由己的松懈了对于技术深度的精进,到 2018 年时虽然薪资拿的较高,但原有的技术体系与当下的技术栈已不合时宜,编程的综合能力也快速下降,更重要的是,他内心依然向往编程,对于技术管理并没有建立太浓厚的兴趣也没有积淀太多成熟的管理方法论,后来痛定思痛,跳槽出来,降薪 30% 进入了一家公司做基础架构,技术重新捡起,降薪是因为他的技术能力已经低于市面行情所需求的实力,从 18 年到 19 年,他越来越开心,虽然薪资还没当年拿的多,但技术总算慢慢追赶上来了,所以,技术的精进需要持续的投入,如果中断就很快掉队,在切向管理的时候,一定要深思熟虑三思后行。</blockquote>
<p><a></a></p>
<h2>做管理到底是做什么</h2>
<p>技术是以熟练的技巧和规则为基础,靠兴趣、想象力和创造力驱动,那技术管理是做什么呢,把管理丢开只做技术可不可以?答案是可以,答案同时也是不可以,可以还是不可以要分阶段来看,在职业的早期阶段是可以的,在走向资深的阶段后就不可以,因为管理不仅仅是以人为对象,包括自己包括组织,包括一件件复杂的事情和合作关系,都需要具备管理能力,为什么需要管理能力,是因为技术编程现在已经进入了深水区,光具备 编程、架构和运维实际上只是具备了基础能力而已:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562240269043-867c545d-f5ff-4251-920a-0cb334967e23.png#align=left&display=inline&height=592&name=image.png&originHeight=1302&originWidth=2264&size=881779&status=done&width=1029.0908867859648#align=left&display=inline&height=1302&originHeight=1302&originWidth=2264&status=done&style=none&width=2264" alt="image.png" title="image.png"></p>
<p>抛开基础技能还需要更多其他的综合能力,假如业务走在最正确的方向,确定最合理正确的指标,运营收集到最客观真实的客户反馈,产品规划出最直击用户心灵最命中业务痛点的产品路线,产出最完整最闭环最精准的 PRD 文档,UED 同学设计出最符合用户需求最契合 PRD 文档的设计稿,服务端提供最稳定最明确的接口稳定和接口联调环境,项目经理把握最稳妥最可控的迭代节奏...在这样的环境下,有可能你能专心的写代码不需要跟各方有太多纠缠,可是试问下:这个 “最” 字有几个人可以做到,你经历过这样超高命中率超强配合能力的团队么?任何一个环节出岔子,就可能代码编程实现中的重大干扰因素,这还仅仅是对于一个人是如此,如果 10 个人前端团队,每个人都处在这种不稳定的状况下呢?</p>
<p>其实我们都处在一个个不完美的公司,一个个不完美的团队中,即便如 BAT AMD,又何尝没有道不完的心酸,团队越大问题越复杂,而作为技术管理者,职责就是解决团队中出现一切问题,并能促使团队不断的变得更优秀,前文我们讨论如何带领小团队时有张截图,这是小菜前端早期的一个阶段:</p>
<p><img src="https://cdn.nlark.com/yuque/86/2019/png/87556/1559640524341-ec2752e2-eaf0-41d8-8899-a9f4ddd58c36.png#align=left&display=inline&height=294&name=image.png&originHeight=647&originWidth=1738&size=248115&status=done&width=789.9999828772116#align=left&display=inline&height=647&originHeight=647&originWidth=1738&status=done&style=none&width=1738" alt="image.png" title="image.png"></p>
<p>其实一个团队出问题的时候,是远不止上面这些问题的,当这些同时出现交叉出现的时候,团队的技术管理者应该做什么呢?答案就是发现问题、定义问题、制定方案、解决问题、复盘总结,发现问题是最容易做的事情,团队中大家的吐槽随时都是发现了问题,但定义问题则是一个更重要的能力,如何准确的定义问题直接决定了能否制定出正确的应对方案。</p>
<p>我们再把上面的其他综合能力做个分类归纳,会发现如下特征:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562240374049-cf823727-d948-43d2-90a6-e16372a84182.png#align=left&display=inline&height=591&name=image.png&originHeight=1300&originWidth=2348&size=1093023&status=done&width=1067.2727041402145#align=left&display=inline&height=1300&originHeight=1300&originWidth=2348&status=done&style=none&width=2348" alt="image.png" title="image.png"></p>
<p>所有的这些能力集合,都可以成为管理岗需要的能力,只不过我们所认为是管理是比较狭义的管理能力而已,它的对象更多在于组织内部的向上向下和向左向右。</p>
<p>这时候我们也就意识到,管理所涵盖的的确不仅是事情,而是将所有能力综合后完整的推进路径,简言之就是驱动团队的方法论,方法论是可以训练的,但这些方法论往往跟编程本身没有关系,方法论投入精力越多,编程参与就越少,这就是技术向和管理向的天然矛盾,但方法论的背后反而有很多通用套路是对编程也是有益的,比如 PDCA 这样的做事规划模型,我对它做了改进,加入了意愿和能力的维度:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562240549287-c77a3a25-3300-41de-a8ec-9e9e4a6c0729.png#align=left&display=inline&height=370&name=image.png&originHeight=814&originWidth=2210&size=285199&status=done&width=1004.5454327725187#align=left&display=inline&height=814&originHeight=814&originWidth=2210&status=done&style=none&width=2210" alt="image.png" title="image.png"></p>
<p>尽然技术路线与管理路线有矛盾也有统一,但最终它们通往的方向不同,我们在做职业转型的时候,就必然要取舍,就必然会经历内心的煎熬,就必然在某条路上愈行愈远。</p>
<p><a></a></p>
<h2>管理能力一定是加分项</h2>
<p>看完前面两个论述,我们会觉得管理好像不是一件很容易做的事,也不太像是一个对很工程师生涯很友好的选型,事实上,在整个市场的技术岗位稀缺度上,技术管理者与技术专家是同样的稀缺,无论这个同学技术是一般般还是非常好,身上具备管理能力一定是加分项。</p>
<p>因为技术团队是最好带也是最难带的,好带是因为技术同学的单纯与淳朴,难带是技术同学的天真和不成熟,一个好的技术管理者可以把团队打理的井井有条,发挥更大的效能,让业务方爽的不要不要的,团队成员也都能不断的获得成长,而一个不合格的管理者则会把团队搞的乌烟瘴气、怨声载道,甚至跟业务方无法建立信任关系,这对于一家企业是灾难性的后果。</p>
<p>因此用人方任命技术管理者,宁肯不求有多完美的果,却希望不要有太多的过,因为一旦技术团队与公司之间撕裂或者内部撕裂,整个公司将付出更巨大的资本和时间成本,来再次把团队校正到正确轨道,而由于技术团队是公司最贵重的资源,这个技术管理岗就至关重要,这就解释了为什么它是加分项。</p>
<p>最后一个观点,技术管理一定离不开技术二字,一个管理者可以不再精通技术,但要对技术有充分的经验积累和敏感度,要具备比较成熟的技术评估和技术人才运用的方法论,一定不可以抛开技术,纯粹从业务和人的视角做管理,比如用强 KPI 强指标的考核,或者只追求短期业务实现而不顾及长期基础设施建设和技术栈的迭代升级,那样对于技术团队的长期人才体系会有很大的伤害。</p>
<p><a></a></p>
<h2>技术生涯跟天赋强相关</h2>
<p>技术天赋越好的人,技术价值最大化的成功率越高,在技术的圈子里,技术成就能有多大,的确是因人而异,是有天赋因素加成的。</p>
<p>其实十几年看下来,真正在纯技术领域走向成功的人并不少,但前端这个领域却凤毛麟角,通常达到阿里的标准 P7 专家水平,就已经是大部分人的职业天花板了,还有少部分人能继续攀登到 P8 高级技术专家的高度,再往上走,就往往跟技术编程本身关系不大了,这也是为什么大部分人到了 P7,年龄也大都接近 30 岁上下,会慢慢转向管理,一个是市场需求大,一个是自己的职业天花板在这时候就遇到了,毕竟背后付出的心血都是脑力和身体。</p>
<p>所以,如果我们发现自己的技术天赋很高,那么可以尽量迟一点考虑管理,如果技术天赋一般,那么可以早一点理解管理的意义,并做一些必要的准备,将来迎接这个转型。</p>
<p><a></a></p>
<h2>什么时候该考虑做管理</h2>
<p>往往你做管理的时候,会源于一些外力,比如你跳槽去了一家新公司,刚好有这个管理岗坑位,比如你在本岗位干的风生水起,老板比较挺你让你带俩人试试,比如公司组织架构调整,你是被动任命,比如你所在团队老板离职,你临危受命等等,很多时候你从技术开始转向管理,都有一些机缘巧合,不知不觉就半只脚迈进了管理的池子中。</p>
<p>而你身上一定有了管理的标签,你就不再是一个人走,而是带着一群人走,你不再是对自己负责,而是对大家负责,你不再是仅仅面对业务,更是面向组织,可能就是这一夜之间,你的使命已经发生了根本性的跃迁,可是往往你要过很久才能慢慢明白过来。</p>
<p>这样的管理,其实是大部分人遇到的,也就是被动式的考虑,被动式的征召,而转向了管理,其实最好的管理路线,其实也是最好的技术路线,都跟我们前面提到的能力和意愿强相关,我们意愿上愿意转管理喜欢做管理,那么可以切换,如果意愿上极度排斥,那么就要深思而行,那怎么判断自己是喜欢还是排斥呢,我拿几张表格给大家测试下,看你喜不喜欢做这样的事情?</p>
<p>是否喜欢推导人的做事动机,是否愿意用这样的图来复盘自己和他人的项目过程,看所有人的能力和意愿处在哪个区间:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562241030431-f96ffd98-ae3c-4bd7-a9e6-a01506316d42.png#align=left&display=inline&height=584&name=image.png&originHeight=1284&originWidth=2368&size=647121&status=done&width=1076.3636130340833#align=left&display=inline&height=1284&originHeight=1284&originWidth=2368&status=done&style=none&width=2368" alt="image.png" title="image.png"></p>
<p>是否对商业模式感兴趣,愿意花时间研究不同行业不同公司不同团队,他们的成长情况,包括自己团队的成长阶段:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562241083285-dde4c2d5-0211-410d-8cf2-68a30cc64243.png#align=left&display=inline&height=556&name=image.png&originHeight=1224&originWidth=2342&size=597292&status=done&width=1064.5454314720537#align=left&display=inline&height=1224&originHeight=1224&originWidth=2342&status=done&style=none&width=2342" alt="image.png" title="image.png"></p>
<p>是否喜欢对问题进行分析归类,从人、事、组织等多个角度来抽象问题本质,并且有足够的热情去推动解决:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562241130889-72bd781e-8e3b-47c9-a32a-d7beb18f2a5f.png#align=left&display=inline&height=505&name=image.png&originHeight=1110&originWidth=2272&size=1088403&status=done&width=1032.7272503435124#align=left&display=inline&height=1110&originHeight=1110&originWidth=2272&status=done&style=none&width=2272" alt="image.png" title="image.png"></p>
<p>是否对于管理的手段,管理者的定位,以及所有公司决策层下发流程的执行力度有自己的分析,有更客观的评估:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562241206540-f94df1e3-d0fb-49cb-816b-98fa88d92454.png#align=left&display=inline&height=489&name=image.png&originHeight=1076&originWidth=2358&size=909569&status=done&width=1071.818158587149#align=left&display=inline&height=1076&originHeight=1076&originWidth=2358&status=done&style=none&width=2358" alt="image.png" title="image.png"></p>
<p>是否真的愿意花时间去理解使命愿景价值观,人的道德品质和内心价值取向这些务虚的东西,是否认同人的驱动和需求层次与管理者胸怀及成就他人的关系:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1562241288588-3d63d051-3401-4a2c-8a8c-0e20490e6fb9.png#align=left&display=inline&height=417&name=image.png&originHeight=918&originWidth=2282&size=428000&status=done&width=1037.2727047904468#align=left&display=inline&height=918&originHeight=918&originWidth=2282&status=done&style=none&width=2282" alt="image.png" title="image.png"></p>
<p>以上这些事情与编程几乎无关,大家如果毫不排斥甚至喜欢,那么我认为当你的技术到达了技术专家的时候,或者再晚一点,都是可以考虑转管理的时候了,如果继续走技术路线,那么相信这些感兴趣的分析也会帮你更好更客观的分析所处的环境与所能发挥的价值。</p>
<p><a></a></p>
<h2>小结</h2>
<p>技术研发和技术管理有很多不同,但并不冲突,甚至在一个人的职业生涯中,二者的定位和比重也会来回切换,那是因为技术总是在急速的变革之中,只有积极的跟进技术浪潮,对技术保持较高的好奇心和敏感度,才能更好地做技术管理,同理在一直追求技术造诣和工程师价值的路上,也要时不时培养训练一些基础性的管理能力,至少是管理意识,这些软实力可以成为你当前岗位内推进各种疑难事项的润滑剂,同时也为将来的另一个职业路线打下一些基础,总之,技术路线与工程师创新价值的长远实现是贴合的,而技术管理与商业、团队和组织能力成长更贴合,两者在少数人身上可以很好的整合,形成软硬兼具能虚能实的综合竞争力,而我们大多数人,可以让自己在两个方面都不要有明显短板,才能在长期的职业生涯中,总能收获期许的回报。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=9EtkrXCvPg2Rfi2akn0X3g%3D%3D.lsmvUmvHJqHfZDKX7TL2x2IKv2549buep%2B75cVUhRAg%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
职场瓶颈:2~4 年前端走出离职困境与舒适区
https://segmentfault.com/a/1190000022294371
2020-04-09T23:00:00+08:00
2020-04-09T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
10
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream。</p>
<blockquote>
<a href="https://link.segmentfault.com/?enc=tTfOk1sRdKA6%2Fi1Fi1OVvg%3D%3D.Fq5fF8F9bsJIVS51yrt4hhW97jIOzJ%2B%2FVasQRPhhAioZJ9jupKQg250GD7fJzQtxiNPpVYXFu8lJ%2B%2BuZwbVuwkPesbWGUwQo%2F8tBapSQCZuBXVilnEMDtW1eozPfnH80" rel="nofollow">1 万个小时</a>和 3 万行代码,会成为工作前 4 年非常核心的量化指标,把握住这段周期,可以在职场建立非常有竞争力的择业优势,更关键的是自己真正的潜能会被挖掘出来,继而有机会成为那个心目中的大牛,而把握二字,知易行难,背后的逻辑就是不断的走出舒适区不断的突破困境区。</blockquote>
<p>我们不必纠结前几年的工作,是花了 8000 个小时,还是手写了 2 万行代码,如果是重复性的劳动就算是 4 万个小时 8 万行代码也没有太多意义,而 1 万个小时和 3 万行代码是我本人比较认同的一个经验值,在前几年沉浸式的花费上万个小时在技术的思考和实践上,无论是什么框架什么业务都能用更高的标准要求自己最终沉淀几万行代码的编程经验,那么大概率你的技术能力会处在中上游,所以我往往给新人的建议就是找活儿干,抢活儿干。</p>
<p>上一篇文章,我们讨论了工作内外的技术成长,针对的受众也是工作 2~4 年的前端,这个群体最容易出心理问题,很大一部分原因就在于还没有建立更成熟的自我认知,也没有完成从学生到社会人的身份转变,就像与 Scott 有深度私聊的这些同学也多在工作的头几年:</p>
<ul>
<li>聊聊 1 - 3 年前端走出成长的焦虑</li>
<li>聊聊 2 - 1 年前端小生之跳槽困惑</li>
<li>聊聊 3 - 4 年高级前端如何走出舒适区</li>
<li>...</li>
<li>聊聊 8 - 2 年前端频繁跳槽怎么破</li>
<li>聊聊 9 - 2 年前端面对职业危险期</li>
<li>...</li>
</ul>
<p>在认知不够成熟的时候,很容易陷入所谓的困境,或者顺风顺水的停滞搁浅在舒适区,这就是我们这一篇想要重点探讨的,跟上一篇的技术成长有所不同,这一篇我们更关注自我认知(心理建设、价值设定)和困境突围,首先我们从困境的定义开始,舒适区则放到最后。</p>
<p><a></a></p>
<h2>困境与困难到底是什么</h2>
<p>很多时候,我们对于困境的描述,往往像下面这些:</p>
<ul>
<li>计算机基础不扎实甚至是完全没有,比如算法、数据结构、网络相关理论等等</li>
<li>JS 基础能力不行,心里没底又觉得没有力气和方向迈出去</li>
<li>一年经验用三年,对于工作中用到的技术没有去了解内部机制</li>
<li>没有考虑如何把代码写的更好,业务中到处是胶水代码</li>
<li>工作环境导致的身边没有大牛,没有样板可以模仿、学习</li>
<li>空有想法没有行动,导致收集一堆资料却从未去看过</li>
<li>我们内部用的工具总是很老套。没有人想改变什么,没有野心,没有梦想,像一架老马车,大家都在凑合</li>
</ul>
<p>等等不计其数的早年职业困惑,碎片化的焦虑让我们彻夜难眠,这些本质上是困难而非困境,我们定义为困境后,再从社区从他人这里获得的,也经常是相对碎片化的建议,比如:</p>
<ul>
<li>前端虽然工作中用不了数据结构算法等等这些基础知识,但是这些知识决定了一个人的天花板高度,并且也是大厂常常考察的一点。当然学习这些基础并不能一蹴而就,只能在平时业余时间有意识的去补齐这部分的短板。</li>
<li>前端知识点确实很多很杂,因为并没有很好地阅读一些基础书籍,高程、你不知道的 JS、 JS 精粹这些书籍读完一定能打好一个不错的 JS 基础。</li>
<li>工作年限越长,公司对于开发者的要求就会越高。这时候公司需求的员工是一个能写代码、能解决团队成员遇到的问题、能带人的这样一个工程师。了解技术的内部机制才能让自己不被淘汰。</li>
<li>平时要有意识的去重构自己的代码,抽离可以复用的功能,这样做通常都能提高之后的开发效率。但是大家可能并不知道如何去优化自己的代码,一是可以学习团队中大牛的代码,看他是如何实现的;二是学习业内顶尖库的代码,看看人家是如何设计的。</li>
<li>收集了一堆资料就当看过了,对于存在这样情况的前端工程师,可以选择想学什么再去收集相关资料,然后立马设定 TodoList 督促自己学习。</li>
</ul>
<p>看过听过之后,可能有一两条我们坚持下去了,而其他都慢慢丢在了脑后,这背后的一个很大的原因在于,我们往往不是缺少目标,甚至也不缺驱动的原动力,我们缺乏的是对自己职业属性以及困境区分于困难的正确认知,所以认知一旦出了问题,困境就随之而来,无论它是事实上的外界物理环境造成的,还是自己内心期望与惨淡现实的落差造成,这都会持续的伤害着我们的职业成长路线,而此时困境就是我们认知的边界尚未突破的尴尬局面,在这个局面下,一切皆困境。</p>
<p><a></a></p>
<h2>哪些关键认知需要建立</h2>
<p>一个人立足于世,不论男女,都有这几个问题需要自我思辨最终弄清楚:</p>
<ul>
<li>社会属性,也即我的社会价值,我在中国(海外),当前阶段(留学/实习/刚工作),我存在社会的价值是什么?无论从事哪个行业,无论内心是多懒散,我想我们都向往积极的活着,不成为社会的蛀虫,活着社会上,就一定有所劳动,这些劳动就是我可以为社会提供的价值,也即我存在的意义,这也是我当前从属行业它的价值。</li>
<li>家庭属性,也即我的家庭角色,无论我是孑然一身,还是生活在完整完美的家族关系中,无论我是一穷二白,还是家产非常殷实,我的多重身份(孙子、儿女、父母、哥哥姐姐弟弟妹妹...)就决定了,要为家人带去保障,为家人带来幸福与安稳,所有这一切都是我奋斗的原动力,这一切的奋斗一定不是通过躺着实现,一定需要我的大脑和双手来让血脉的存续,来让亲人的期待都不落空。</li>
<li>群体属性,也即我的社会关系,无论多宅,我们都是社会化的群居动物,团队合作和群体沟通始终贯穿我们终生,通过合作和沟通,我们具备了生存的外在能力,也具备了通过他人观察自己的机会,而所有的合作和沟通都是建立在资源的前提上,也就是你本身具备社交价值,无论是作为主导关系的强势主宰,还是仅仅作为倾听他人负能量的收集桶,这些价值每一年都会被不同的群体反复检验,这种检验会让我们明确知道身边聚拢越来越多优秀的人,还是寥寥无几的平层社交,通过这种比较让我们最终对自己的价值有更清楚的判定。</li>
<li>自我属性,也即我的内心所向,是当个出家人,是当个坦克兵,是当个店老板,还是工程师,这一切社会化的工种行当,都取决于我的价值选择,我定义自己成为什么样的人,内心深处的价值是导向哪里,在不完美的世界中有那么一些美好,它们浮现到我的心中分别是哪些坚守与放弃,这都影响到我的自我定位。</li>
</ul>
<p>从社会、家庭、群体到自己,每个人的情况都不尽相同,大白话就是我们的三观不同,不同的三观驱动下,我们去往的方向和路径就可能截然不同,回归到工程师,我复述下我过往 8 年的认知过程,给大家一点点参考:</p>
<p><a></a></p>
<h4>生存阶段</h4>
<p>关键词是危机感,发生我工作的前 2 年,怎么夯实自己的技术,让自己在团队有立足之地,这花费了我大量的精力也给我带来了无尽的深夜烦恼,我当时的做法是疯狂的写代码,业务时间疯狂的接单做网站,也由于各种自卑不敢到社区大大方方的社交,大大方方的找前辈请教,没有任何指导的前提下,我凭着一股子热情,通过压榨自己的时间来慢慢积累代码时间和代码量,逐步克服了技术的生存危机。</p>
<p>如果让我重新来过,我依然会这般如此的压榨时间,但我不会再疯狂的用满业务时间做外包,而是用来看书学习,总结和整理,同时多留一些时间跟行业的前辈交流,提前做第三第四年的职业规划。</p>
<p><a></a></p>
<h4>诱惑阶段</h4>
<p>关键词是满足感,发生在我工作的第 3 年,工作轻车熟路的我开始飘飘然,总是沉不下心,很容易受外界干扰,同行的薪资待遇,同行做的事情,其他公司在做的业务,所有这些都像雨水一样不断的弄湿我的脸庞,我需要不断的用衣袖擦干它们,我渴望做更有成就感的事情,我渴望拿到更高的待遇,每一天的我都度日如年,针对这种情况我当时是找了前辈沟通,借助他们对我技术和职场成熟度的打击,我逐渐冷静下来,继续沉淀自己的技术深度。</p>
<p>如果让我重新来过,我会更理性的看待手头的工作和外面的机会,更深刻的认识薪资-能力-职业发展它们的长短期关系,更早的找更多技术前辈看他们的成长经历,帮自己仔仔细细规划技术体系的成长路线,而不是乱花迷人眼,荒废了大量时光在诱惑的对抗上。</p>
<p><a></a></p>
<h4>证明阶段</h4>
<p>关键词是饥饿感,经过第 3 年神魂颠倒和冷静后,我自我感觉良好,有更大的野心和成功的渴望,第 4 ~ 6 年我进入到证明自我价值的阶段中,这个阶段持续比较久,虽然中间有离职创业,但内核没变,我在找寻能让自己人生价值最大化的赛道,我试图着去证明一些我当时说不太清楚的东西,虽然对于短期薪资福利我看的更为平淡了,对于非技术的观察力和决断力我更为看重,对于更长远的技术投资和回报变现我更为看重,但依然没经历住时间的考验,对于创业的舍近求远和急于求成,而让自己饥不择食。</p>
<p>如果让我重新来做,我依然会选择离职创业,但我不会那么冲动的来做这件事,我会跟我的主管及主管的主管好好聊聊我的职业困惑,我会和社会上的创业团队多多接触,正负面我都会关注,不仅要看事情,更要观人心,人事双修,而不是一腔热血抱着技术二字去改变世界。</p>
<p><a></a></p>
<h4>实现阶段</h4>
<p>关键词是成就感,经历过创业的挫败,我对于自己的能力和理想有了更准确的判断,我开始从带创业公司的第一个团队到带小菜的第二个团队,从带 6 个人到现在快 20 个人,依然在创业依然在带团队,但初心和驱动力已完全不同,我更希望和一群人(更大的一群人)拿到一次次的成功,也是在这个阶段,我找到了答案。</p>
<p>所谓这个答案,是我某一天顿悟,驱动我做几乎所有事情的原动力是:独特、利他、团队和成就感,这就是我工作 8 年才第一次正确的挖出来,也是第一次的认识到自己内心深处的价值取向:</p>
<ul>
<li>我希望自己自内向外所参与的事情,所打造的产品,所创造的价值,所塑造的形象都是独特的与众不同的充满创意的,一切平庸的重复的机械的守旧的一切不 Cool 的我都很难去喜欢,我都想打破而重立,我都想打破陈规推陈出新,我都想去挑战一下,这就是独特与我的意义。</li>
<li>我希望自己所做的事情都是对家庭他人对社会有正向的价值的,就像这本小册一样,我以分享的形式想要把整个团队的想法和沉淀给到各位,来帮各位早日走到正确的赛道上,一切对他人不利的,造成伤害的,让人无法健康成长的,不管是规矩还是制度还是潜规则,都违背我的内心,这就是利他与我的意义。</li>
<li>我希望自己不再是单枪匹马,不再是英雄主义,我应该有一群人一起开心一起哭,我的成功不再是靠自己,而是让团队的每一个人都能因我更开心更成功,团队不再局限是公司我带的团队,也泛指社会上我参于的任何一个聚会任何一次群体活动,都能因为我的参与变得更融洽更团结更有正能量,这就是团队在我内心深处的意义。</li>
<li>我希望所做的事情都能有好的结果,都能是影响到其他人影响到更大范围,这会让我收获一种愉悦的感觉,那就是成就感,这种成就感是我通过前面的独特、利他和团队都能实现进而升华后的一个新的层次,这种对成就感的渴望会成为我非常核心的驱动力。</li>
</ul>
<p>上面谈了我的认知历程,我相信看到此处一定有同学受到启发,也会顿悟自己的使命和内心所向,如果这个实现阶段让我重新来过,我会希望自己可以再早一些再早一些好好认识下自己,好好了解下自己,这 8 年的职业经历带给我的这么多感受,而我总是忽略它们,总以为答案在外面,其实答案始终在内心深处,只是自己从未站在认知的高度,一次次的剖析自己拷问自己,一定要靠这么多年的折腾才能某一天醒悟,我不后悔这一路历程,我只是可惜这来的晚了一些,更早一点越早一些,我想我会收获更多的朋友,更多的成长和成就感。</p>
<p>下一个阶段是哪里,我还不清楚,但下一个阶段的关键词,我想基本不会变了,那就是:独特、利他、团队、成就感,这是我的内心价值,对于认知建立这样的里程碑,你准备好拷问自己了么?经过拷问后获得对自己最真实的了解、理解和认同后,再来还原到下面具体困境解法里,你的答案才会坚实很多,也会更容易做出对的抉择。</p>
<p><a></a></p>
<h2>脱离困境并非只有离职</h2>
<p>当认知都清晰之后,再来看这个命题,会发现似乎所有的困境不再是困境,仅仅是生活和工作的一个状态,而困扰我们往往只是困难,比如不知道怎么夯实技术基础,不是科班选手不知道怎么学习,团队没有学习氛围怎么破...而困境是什么,困境是我们尽所有能力去克服困难后,依然陷在泥淖中无法挣脱,而如果我们并没有倾尽全力去克服所有的困难之前,怎么可以把困难视为是困境呢?</p>
<p>我们重点聊聊一个常见的困境,就是择业切换之前,渴望离职的时候渴望摆脱的时候,这对于超过 10 年长度的职业生涯来说,要不要走,去哪里,它是事实存在的困境。</p>
<p>“做事不开心、钱给的不够” 这是行业里最流行的对于离职的原因分析,也的确是大实话,因为我这三四年线上线下面试以及聊过的几百个童鞋里面,是要有一小半把离职原因归咎于公司的变态制度、不人性化、没有弹性、没有技术成长空间以及薪资过低等等原因,在这样的环境里面的确是做事很不开心,回报也远远不够,我会鼓励他们早日脱离苦海,切换一家更适合成长的公司。</p>
<p>离职一定是一条最快路径的可选项,因为整个从行业、公司文化、业务方向、职能要求、团队配置以及老板方方面面都经历一次刷新,从前的困境烟消云散。但是脱离了苦海,再入的一定大大好过从前么?答案也是未必,离职是一把双刃剑,我身边好多个朋友当初忍受不了阿里内部大公司的一些毛病,会议多乱甩锅工程师氛围政治化等等,出来干了几年,好多个最后又回去了,因为发现外面溜了一圈,每个公司都有它的问题,有的问题比阿里更严重,有的则是前景非常灰暗,当然也有一些同学跳槽的很成功,只是比例确实非常非常小,这就是择业择公司的智慧和运气了,我们前面有一篇专门讨论如何挑选到成长空间更好的公司,大家可以回头去看。</p>
<p>每个公司都充满了委屈、不平、揪心甚至困惑,做这样的选择一定要慎之又慎,最佳的离职状态是职业到了天花板,公司已经不能再给你更大的舞台和空间,技术上管理上不能再上一台阶,此时需要切换一个新赛道从 0 开始,最差的离职状态就是不满意组织内的人和事,比较情绪化的不开心一走了之。</p>
<p>放弃是最容易做出的决定,而坚持无论在哪儿都是最难的选择,这也是我对一个在吉利车企做事的前端提出的建议:这个组织让你不开心,那么你可以用尽各种办法,线上线下的制度性的社交性的策略和办法,找各种人找各种资源来推动组织发生更好的变化,而不是静等着组织自我优化来满足你的心境,组织不是组织,公司亦不是公司,里面的每一个人所形成的整个整体才是你不开心的,但你也是参与者之一,有权利去优化它,通过这个过程你也能练就一身为人处世以及组织成长和管理的本领,这样的本领到哪里都适用。</p>
<p>而对于另外一个同学,我则是完全不同的建议,她说:今年刚刚 25 岁,女生,工作不到 3 年,自己内心想在技术上在好好深造锤炼,对前端工程化的构建,还有对技术的锤炼的深度及广度,很想去突破一下,目前的整个团队氛围不错,领导很好,但是整个研发团队以后端为主,部门前端只有 2 个,技术老板也不懂前端,框架一团糟,前端也没有经验特别丰富的人,大家也没有对技术的深度拓展及创新,很多技术都是我在推进,个人技术上得不到很好的成长,落地比较难,要不要换一个更成熟的前端团队来丰富自己的技术能力。我则是建议她可以大胆切换去更成熟有架构能力的团队,去迎接技术的下一个成长期,最后送她一句话:一切正向变化都始于知行合一的 All in,认定既坚定,坚定才能坚持,加油!</p>
<p>关于离职聊得比较多,主要是确实接触了好多好多离职中的同学,几乎都处于所谓困境中,但原因各不相同,并且大部分同学其实没有想清楚这个问题,更多面临的是困难,眼前的切换属于是冲动决定,甚至有的跳槽频率很高很高,后期严重伤害了职业生涯,而成功切换的总是很少数,非常可惜。</p>
<p><a></a></p>
<h2>舒适区才是最大的困境</h2>
<p>我们看抖音,会发现有些人的技术特别娴熟,比如切菜的,比如为快递打包的,工程师的编程技能也一样,如果长时间在某一块重复性训练的话,也会唯手熟尔,比如一个常年做活动页面的同学,比如一个常年做后台表单页面的同学,这些容易重复性的领域很容易造成一种错觉,那就是这块我熟能生巧总是很快搞定,然而却不知不觉的进入到了一个舒适区,有时候会自己意识到,有时候意识不到,带来的后果是往往技术的成长停滞不前,更可怕的是在不知情的情况下度过了多年时光,</p>
<p>1 个月前我遇到了两个工作都超过 3 年的前端同学,他们的薪资是 5k,他们都在做移动端推广的活动页面,非常熟练,其中一个意识到严重性另外一个只是觉得工资低,但工作很悠闲反而觉得很舒服,最后对他们的建议是,立刻马上切换工作内容,并且赌上自己所有的时间来学习前端知识,包括框架的使用,如果有可能再从团队中找一些可以写脚手架可以做组件可以开发工具的场景,让自己的重复性工作得到解放,或者干脆建议公司招人来取代自己做这些简单的工作,逼自己走出舒适区尽快追赶更行业优秀前端的巨大差距。</p>
<p>除了写代码,做管理也会遇到舒适区,同样一个带团队的前端同学工作 4 年,他毕业后就顺风顺水,自驱意识也很强,很快成为团队的技术骨干,并且带起来一个 10 人的前端团队,但整个公司的业务模式决定了所有项目的复杂度都不是很高,所以即便进行深度的工具基建,实际上缺少应用的场景,对业务产生的价值也不大,加上业务挑战也不高,同时公司付给他非常高的薪水,他就被动主动的进入到舒适区,出来去一些公司面试拿到 Offer 后,几乎所有公司都给不到他目前的薪水,还会打折很多,我对他的建议是:考虑跳槽去一家更有挑战性的公司,哪怕是比当前薪资低出一个数量级也可以,因为他已经成为团队甚至公司的天花板,公司用高薪不仅购买了他的时间,也购买了他的成长空间,虽然当下他公司很器重他,但一旦未来出来公司,能力却再次会落后于行业平均水平,这对于这样一位高潜力本可以成为大牛的同学是非常危险的阶段,除了切换,也可以选择留下,跟公司好好谈谈,从产品、技术、业务角度看有没有可能从技术侧驱动更多的创新,从而为自己团队带来更大的挑战,也就是主动求变,也可以为自己招前端老板来带领自己和团队走出舒适地带,不能因为眼前的利益而牺牲了未来更大的回报。</p>
<p>所以面对困境未必要离开,处于舒适区也未必要留下,每一个人处于这种状态下,都是很痛苦,如何把痛苦周期缩短,如果找到突破点求变或者坚持,其实都取决于我们对于自己的判断,以及对行业的判断,所有的判断加在一起,再来对每一个问题标注上优先等级,注释上自己力所能及的事项,再列出来推进解决它的详细计划,最终能否迈出去到一个更好的阶段,就取决于执行力了,说到执行力,再送给各位几个关键词来面对所有的人生困境:脑力、体力、心力、执行力,脑力是分析是智慧是取舍是规划,体力是坚持是强度是执行力度,心力是耐力是决断力是忍受向前的抗击打能力,执行力是使命必达说到做到破釜沉舟的落地程度,这一切都需要你足够主动,足够负责,才能点爆奇迹。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=JecuHbchhQMG80VbqLMrFw%3D%3D.yoqqzcNKL51s2FzWVgIjBfmx%2FbXrwwlOv8mhYHtPP6g%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术栈:如何让团队规划技术栈得到有效落地
https://segmentfault.com/a/1190000022294308
2020-04-08T23:00:00+08:00
2020-04-08T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
3
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>所有事情都可分三个版本:正在进行中的 v1.0,已规划且正在预研和调整的 v2.0,正在设想并形成粗规划的 v3.0,每次完成之后都可以看做沉淀下稳定的技术栈。所有的任务都可以分为主线和支线:主线打绩效,支线玩惊喜,技术栈规划与执行亦不例外。</p>
</blockquote>
<p>本文写于 2019 年 3 月份,尝试帮大家梳理下团队技术栈演进的一些做法,先来看下小菜前端团队,关于技术栈语言栈(包含框架)的演进结论,帮大家把时间线上的规划串起来:</p>
<p>2017 年 7 月:</p>
<ul>
<li>进行中:RN / React(PC)</li>
<li>预研中:NodeJS(Express / Koa / ThinkJS / Egg) / RN 骨架</li>
<li>设想中:GraphQL / RN 组件化 / 脚手架 / 自动化测试</li>
</ul>
<p>2018 年 7 月:</p>
<ul>
<li>已沉淀:RN / React(PC) / NodeJS(EggJS)</li>
<li>进行中:RN 骨架 / 脚手架 / GraphQL</li>
<li>预研中:PC 框架 / Node Framework / MPVue / RN 组件化</li>
<li>设想中:Python / Rust / Go / RN 框架 / Rust / 多端采集埋点 / 自动化部署 / 视频流加工 / Docker</li>
</ul>
<p>2019 年 3 月(当下):</p>
<ul>
<li>已沉淀:RN / React(PC) / NodeJS(EggJS) / GraphQL / RN 组件化 / RN 骨架 / 视频流加工</li>
<li>进行中:Node Framework / PC 框架(兼容 H5) / MPVue / 可视化 / 自动化部署</li>
<li>预研中:Python / Go/多端采集埋点 / Docker</li>
<li>设想中:Rust / Android SDK / 小程序-H5 统一框架 / 全链路服务化监控 / 直播推流转发</li>
</ul>
<p>再来直观的解释下:</p>
<ul>
<li>已沉淀:团队有一定数量的同学掌握了该技能或者这个方案成熟了进入维护期;</li>
<li>进行中:团队没掌握好,方案不稳定不完善还需要大量迭代,需要持续推进的;</li>
<li>预研中:本地测试和尝鲜,主要跑原型测试和接入小型项目,未正式立项开发;</li>
<li>设想中:结合业务和技术痛点,跑 Demo,看文档,以脑洞想法和 YY 为主。</li>
</ul>
<p>所以对于小菜前端团队来说,我们的方法论就是从设想到预研,从预研到进行,最后落地沉淀。有时候设想中的会泡汤或者遥遥无期,比如 Rust 的落地;有时候设想中的会迅速落地,甚至跳过预研,比如可视化与 GraphQL;也有时候已经落地的并没有带来太大价值反而是白白投入,比如我们早期的自动化测试,但大体上是按照这样的一套流程来推进整个技术栈的演进的。</p>
<p>接下来我们来结合这几个阶段,来看看如何提前量的做技术栈规划和调整。</p>
<p><a></a></p>
<h2>技术认知与业务理解是前提</h2>
<p>设想中的,通常是基于技术的更新周期,要有一定的工具链或者语言栈升级。除此以外,更多的是基于业务发展所带来的新的与用户对话的场景和方式,预判业务将来可能需要的技术储备。但这块需要深扎业务,基于对于业务的长远理解,才能做出准确率更高的预测。</p>
<p>除了业务,那就是要对技术更加敏感。这个敏感其实有很多简单的套路去做,比如去调研业务类型类似且规模比自己大的公司,看他们的技术栈现状,他们要偿还的技术债,他们对某个技术的应用程度,以及他们比较领先的技术解决方案。这些讯息可以靠参加技术大会或者当面沟通来获取,获取后当然不能硬抄,需要结合自己的团队和业务状况看看是否匹配,成本多高价值多大,小菜早期包括现在,从其他公司中学习到了很多。比如从大搜车的前端和无线架构组这里学习到了 Node 基建和 ReactNative 组件化带来的价值,所以也就把 Node 作为核心技术栈来推进,最终拿到了不错的结果。</p>
<p>除了调研这种很实用的参考手段之外,其实就是去关注社区开源方案的动向。特别是大公司大项目的大改版背景,看看社区反馈的风向,基于这些官方的小道消息,可以引发很多基于猜测的思考,比如 Flutter 的野心,ReactNative 的设计终局,这些关注会让自己对技术的判断更加敏感。</p>
<p>总结来说,本着不以捕风捉影的心态去尽可能多的定期关注技术动态,对技术方案有更强的敏感度和成本感知,找更多参考样板公司做差距比对,以及进入自己公司业务中参与更多讨论,从中形成自己对于业务走向和规模化程度的判断,并基于此来畅想团队未来一年左右的技术前景,有了这个前提,就可以做预研了。</p>
<p><a></a></p>
<h2>技术预研要最小成本实践</h2>
<p>当对于所设想的技术有一定的判断后,就可以在适当的时候,比如刚好有同学资源闲置,比如刚好有个项目是小型项目可以用来试错,就可以做预研了。</p>
<p>在挑选人预研时,要谨记两点:</p>
<ol>
<li>要找学习速度最快的技术尖子来做预研</li>
<li>要用最小的项目原型来做尝试</li>
<li>可以借助第三方(付费)来替代需要自研的部分</li>
</ol>
<p>这三点非常关键,前者不仅可以最快最容易拿到预研结果,还可以从过程中来观测尖兵上手的速度从而评估他对于普通工程师的上手成本,后者则是要最小程度的侵入到现有的产品体系中,保证最小的副作用和成本,最小的成本不意味着最少的思考,反而是要充分考虑清楚才可以动手,最后还有一点需要额外留意的,就是在动手之前,一定要把真实的流程和问题进来透明化出来,而不仅仅是存放到脑海里面。</p>
<p>2017 年底我们想要启动一个对 RN APP 自动化测试的方案,集成到我们的打包系统中,这样测试或者 PM 可以发起一个测试流程,把关键的测试流程定制后,就可以让机器去自动化打包及模拟测试流程,最终输送一份测试报告出来,我们就把一些过程性的角色和问题点透视出来:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563939517511-e190c06a-89ba-4889-9091-4165a2638cb0.png#align=left&display=inline&height=479&originHeight=479&originWidth=695&size=0&status=done&style=none&width=695" alt="" title=""></p>
<p>同时把角色之间的合作关系也透视出来:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563939517330-d28dca0e-2b67-465b-a8c6-61458cd4dacf.png#align=left&display=inline&height=619&originHeight=619&originWidth=1047&size=0&status=done&style=none&width=1047" alt="" title=""></p>
<p>然后才是付诸实施,实施的时候,能接力就借力,我们就借助了阿里的 MQC 来做模拟和输出报告的过程,最初的流程与技术栈图如下:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563939518177-615617c1-f4d3-4c42-ae1b-1b3cee4a0eaf.png#align=left&display=inline&height=1362&originHeight=1362&originWidth=1478&size=0&status=done&style=none&width=1478" alt="" title=""></p>
<p>可以发现我们把需要第三方的成本也列入进去,这样我们就可以快速的把流程跑通,就算预研失败也影响不大,如果预研成功,就可以选择在适当的时候立项攻坚开发了。</p>
<p>上面提到的这个项目,其实我们诉诸了很大的想象力,也取得了一些初步的成果,但是做的太过于激进(后端稳定的日常环境还没准备好),导致项目最后被搁置,但这样一个最小成本实践的方法论大家是可以借鉴的,我们其他的项目都遵循这样的方式来做前期准备。</p>
<p><a></a></p>
<h2>落地过程要坚决笃定</h2>
<p>决定一个技术规划能否落地,除了预判的准确率外,还有一个非常关键的因素就是这项技术或者方案推进的坚决程度。因为有时候一个方案看着美好,真正实施会遇到很多障碍甚至会走很多弯路。这个过程中会产生很多负面的声音包括压力,一不小心就放弃了导致前功尽弃,所以一旦立项开搞,就坚决不能回头一条道儿走到黑,无论是否成功。</p>
<p>最大的忌讳是:进行立项的过程中受到阻力就开始摇摆,于是放缓推进的速度和力度,这样对整个团队是不负责任的。不仅会影响参与项目同学的工作激情,还会让方案的可行性和成功率大打折扣,最重要的是,可能由于摇摆而让周期很长,从而失去最黄金的技术应用窗口期,从而失去了为业务创造更大价值的机会。</p>
<p>举一个例子,我们当时做小程序时团队是零经验,在经过设想和预研后就坚决把 MPVue 结合测试项目,在两周就做了出来,从而为业务的打法测试打下了基础。这个过程我们顶着巨大的压力,但最终证明这样的坚持是非常正确的,整个公司的业务生态因此而受益。</p>
<p><a></a></p>
<h2>历史包袱一定要择机重构</h2>
<p>技术栈更新一定会带来旧系统的不兼容,比如你有一个 jQuery 的旧系统,过了三四年如果不把它重构掉,后面再招聘新同学进来,就会受到旧技术栈的干扰,如果只会 Vue/React,还要现学 jQuery,并且要慢慢非常熟悉 jQuery,才能对原来基于 jQuery 开发的比较复杂的页面和组件进行维护。如果是团队老同学去维护旧系统,那么自然会占用老的资深同学的宝贵时间去做这些相对挑战度不高的项目,成就感也会大大减弱,所以技术栈更换的周期可以拉长一些,但当整个团队的技术栈都更新上来的时候,旧系统就一定要花人手去把他强行重构掉,除非这个系统非常非常稳定,几乎不再基于它做任何额外开发,那么可以多拖一些年月。</p>
<p><a></a></p>
<h2>小结</h2>
<p>2019 ~ 2020 年的技术栈规划,相信大家已经从前面的时间线上看到了,秘诀就是:技术感知/业务深扎/最小成本预研,以及尽可能打开脑洞。而我们对于未来 1 年所押注的技术栈是:Python/Go/多端采集埋点/Docker/Rust/Android SDK/小程序-H5 统一框架/全链路服务化监控/直播推流转发,也就是这张图上的具体体现:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563939517439-f09e78da-7068-4a27-bafa-9ccb562f6c18.png#align=left&display=inline&height=1137&originHeight=1137&originWidth=2280&size=0&status=done&style=none&width=2280" alt="" title=""></p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=XpC3pAA3HCtEzLTFL4Jvkg%3D%3D.MNfcjCT2eZo6H8IV5DtPGn4Z2A%2F%2BAw2XhdUWZXxkHXA%3D" rel="nofollow">关注 Scott 语雀跟进最新动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术栈:2015~2019 小菜 4 年技术栈进化回顾
https://segmentfault.com/a/1190000022294237
2020-04-08T23:00:00+08:00
2020-04-08T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
3
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。<p>早期汽车诞生取代马夫的时候,政府颁布命令让汽车限速在 4 英里,要有三个人驾驶,其中要有一个人专门摇摆小红旗给汽车开道,而随着特斯拉电动汽车诞生后,对于汽车的共识,就变成了 “4 个轮子 + 1 块电池 + 1 台电脑”,甚至无人驾驶,这就是技术进步的力量。</p>
</blockquote>
<p>2014 年,互联网已整体进入移动化进程,各种创业 App 满天飞,小菜的前端团队也是在这样的一个时代背景下开始组建,而小菜的业务团队需要多地联合移动办公,对敏捷和效率有更高的要求,从 2015 年开始,内外部的产品和协同工具也都选择了 App 这种载体,直到今天协同工具全部移动化,主阵营也从 App 扩展到了小程序、H5、公众号,甚至涵盖 PC 网站等配套基建基础,这几年技术栈发生了巨大变化,可以参考下面这张刻度比较粗的时间轴:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563236864134-88afcb6e-7b97-4358-af4e-9a01d7b4b134.png#align=left&display=inline&height=1348&originHeight=1348&originWidth=2406&size=0&status=done&style=none&width=2406" alt="" title=""></p>
<p>本文写于 2018 年底,发表于掘金小册中,作为开篇,可以跟随小菜前端的视角,快速回顾下促成这些变化的背景,以及不同的技术栈带来的优势和挑战,也了解下这个团队这几年技术上的变化。</p>
<p><a></a></p>
<h2>蛮荒时代 · jQuery + 原生</h2>
<blockquote>[从无到有]创业初期,无前端工程师,服务端 + 外包</blockquote>
<p>公司最初的业务试点是从城市的一批蔬菜市场以场内采买的方式,把蔬菜售卖给二批的商户,需要大量的地推销售,采购和物流人员,而售卖必然需要一个交易平台,于是 宋小菜 这个 App 就呼之欲出,蛮荒创业的时候自然没有太多技术积累也没有足够的时间准备,于是就上了一个网页版的混合 App,也就是原生壳里面嵌了一个浏览器,浏览器的网页选择 <a href="https://link.segmentfault.com/?enc=yxGeMiK%2BzLAeE64D2ti87A%3D%3D.TtLoYRFSsFB8X8netIQNGSyPHLHsdw2n2y6x9xuY1Uo%3D" rel="nofollow">jQuery</a> 作为 DOM 和事件库,为用户的下单购买提供交互能力,这当然是一个过渡方案,因为内嵌网页的性能在几百块的安卓机器上表现很不理想,体验很差,对于业务来说就是勉强能用。</p>
<p>除了一个支持交易的移动 App 外,需要对采购、订单、物流做精细化管理,那么自然需要一个 PC 版的 ERP 系统,这个系统最初也是找外包公司开发的,后端是 Java + VM,前端是绘制页面,JS 库依然是 jQuery,无论前后端,代码质量到系统架构都非常粗糙原始,随着公司整体技术升级,最初的架构也从历史小包袱变成了历史大包袱,甚至出现过一些重大的安全漏洞,幸运的是,蒸汽时代很快到来。</p>
<p><a></a></p>
<h2>冷兵器时代 · jQuery + 原生 + RN</h2>
<blockquote>[形成战斗力]创业早期,客户端工程师 + 前端工程师 <= 3 名</blockquote>
<p>随着公司业务规模扩和模式的升级,一个体验差的 App 显然不能很好的支撑业务了,此时依然是 2015 年,我们看到了 Facebook 开源的 <a href="https://link.segmentfault.com/?enc=IV0eBa0F2AV4F3Nb3klKlQ%3D%3D.j1eWvIMezCeLJj67vO44SaLtqBOpAlcPsfWFUiK81wrbSniO%2BW8OQ35k3PSyJbDs" rel="nofollow">ReactNative</a>,也就是 RN - 全套 JS + 部分原生组件就可以快速搭建出一个移动 App,于是苹果版本的 App 我们就用 RN 实现了,而 Android 就没这么幸运,因为早期 RN 的 Android 从不支持到支持也经历了一段时间,并且支持的很不完善,于是 Android 的宋小菜用原生也就是 Java 重写了,而 iOS 的宋小菜用 RN 重写了。</p>
<p>除了交易的 App,采购,销售团队与客户关系的管理也成为了刚需,不然完全靠线下的 Excel 和 ERP 根本无法响应 toB 业务中的时效性,于是第二款和第三款 App 诞生了,服务于采购的采秘与服务于销售体系的 CRM App - 宋小福,这两款 App 都是用 RN 开发的。</p>
<p>在这个时代,线上的 App 前后端已经完全分离,但后台的接口设计还很青涩,同样前端的 RN 框架应用也非常暴力,大量的全局变量注入与引用,大量的三方包直接魔改丢到 node_modules 随 git 仓库一起走,大量的 UI 组件在多个 App 里面拷贝来拷贝去,虽然 JS 的语言语法栈我们用的是 RN,都是最新的语法特性,但在整个工程层面就像浆糊一样混在一起很难维护,这就是这个时期的特色,既超前又混乱,多种前端技术方案混用,编程思想和工程组织混乱。达摩之剑虽然手,从内功心法到招数却无法合二为一,就像谢逊拿着屠龙刀,勇猛但不得真谛。</p>
<p><a></a></p>
<h2>蒸汽时代 · jQuery + React + RN + 原生</h2>
<blockquote>[初步解放生产力]创业前期,客户端工程师 + 前端工程师 <= 6 名</blockquote>
<p>随着 RN 的持续应用,App 端的开发效率得到了量级的提升,乌烟瘴气的冷兵器时代很快结束,进入了挑战更高的蒸汽时代,这时候已经是 2016 年了,采配销中的采和销有了,CRM 客户工具也有了,还没有配送工具及服务供应商的工具,于是新增两款 App - 服务于物流配送司机的宋小仓和服务于供应商的卖大蔬,这些新的 App 都使用 RN 开发,从架构体系上基本统一了,ERP 后台也从 jQuery 逐步切换到了 Webpack + ReactJS。</p>
<p>技术栈逐步统一后带来的好处很明显,可以用很少的人持续的快速支撑业务的调整,这一点对于 toB 这样对效率和成本非常敏感的创业团队来说非常关键。无论是新开 App,还是已有的 App 上面增加业务模块,后端给接口,前端拼页面,业务节奏和开发节奏从此进入双快时期。</p>
<p>在没有基建基础和规范保障的时候,伴随快而来的就是无序和风险,这就是这个时期的特点,所有的 App 虽然有独立的仓库,但仓库之间的组件代码并没有实现真正意义的共享,而是通过拷贝的方式来复用代码,而且路由、定位、页面容器甚至工程结构都差异很大,RN 框架的主版本也相差甚远,这个给新人带来巨大的学习成本,也给团队自己带来了巨大的维护成本,一旦业务进入稳定器,对性能、稳定性和可维护性有了更高的需求,这些暴露的问题就变得致命。</p>
<p><a></a></p>
<h2>电气时代 · React + RN + Node + GraphQL</h2>
<blockquote>[进一步解放生产力]创业中期,前端工程师 <= 9 名</blockquote>
<p>人类有了电以后,文明进化的速度瞬间开挂,而小菜前端的电就来自于 NodeJS,我们使用 RN 来搭建 App,是因为它从开发成本到打包构建都非常敏捷,更重要的是它可以支持热更新,在不向苹果商店及 Android 渠道提交版本的前提下,就能实现 App 内的功能更新,也即发布不发版,这一点对于业务以周为单位发生变化的创业团队简直是救命药,所以 2017 年,我们用 NodeJS 搭建了自己的 RN 热更新平台,这是第一次近距离尝到甜头,但尝到甜头的同时也带来了很多问题,尤其是在蒸汽时代的很多问题纯靠人肉都是无法解决的。</p>
<p>盘点创业到 2017 年,几乎所有的前端基建都是 0 的状态,此时有点像是权力的游戏中的多斯拉克部落,作战英勇兵力也充沛,但配套的攻城设备、高阶攻略与工具都没有,同时大家都比较心高气傲,这也是多斯拉克被无垢者整齐划一的军团打败的一个关键原因,下图是 2017 年下半年梳理的,从工具、规范到业务基建的问题截图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563236864169-b2f1eccc-cf40-49e9-b6ce-c006f52fe7a5.png#align=left&display=inline&height=1263&originHeight=1263&originWidth=771&size=0&status=done&style=none&width=771" alt="" title=""></p>
<p>来举一个例子,比如业务基建的报表场景,是需要前后端配合的,后端写各种 SQL,然后输出接口给前端,前后端要在几十个字段的命名、意义、单位上完全达成共识,然后才能在前端的 table 里输出无误的报表,这个报表可能还得支持日期时间段的检索和排序,这时候接口上就需要增加上多个参数来向服务端传递用户的操作动作,这样一个报表通常开发周期是 1 到 3 天,每次需要前后端团队各自排期,进入评审,再开发测试和最终发布,以及后期的维护升级,对于 [数据即真相,决策即生死] 的业务决策层来说,公司跑了 3 年,才开发了50 多张报表,决策时间永远都是滞后的,这样的问题显然是致命的。</p>
<p>针对这个问题,前端工程师把这样的报表做成了可 SQL 正反拼装,结合 GraphQL 实现自动展示的系统后,报表在之后 1 年就快速产出了 200 多张,所有的业务方都竖起了大拇指,每一个工程师都自豪感满满,从内心深处我们都深深明白一件事,基建基础即核心能力前提,基建核心能力即 NodeJS 开发能力,而只要碰到 NodeJS,便会带来无数的技术挑战,这些挑战会随着基建体系的进一步搭建,随着业务规模的铺张越来越多越来越紧迫。</p>
<p><a></a></p>
<h2>电网时代 · React + RN + Node + GraphQL + C# + Python</h2>
<blockquote>[生产工具全面升级]创业中期,前端工程师 <= 12 名,前端技术专家 1 名</blockquote>
<p>在电气时代,我们从两个宝物中受益,一个是 NodeJS,一个是 GraphQL,从前的能力都是点状、线状的,而把 NodeJS 融入到前端团队工程化的方方面面以后,再把 GraphQL 这种聚合数据的中间层结合起来,前端的能力就可以组成一张网了,这张网的正中心是人,最好的变化一定是首先从人开始的,我们盘点了 2017 年到 2018 年使用 RN 或者依赖客户端的几个不同时期的创业公司人员与工程师比例,如下图:</p>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563236864136-4e0ae161-be81-4c5c-91c3-81ad21d46ed1.png#align=left&display=inline&height=1028&originHeight=1028&originWidth=1694&size=0&status=done&style=none&width=1694" alt="" title=""></p>
<p>发现我们团队依然是处在较为早期的规模,但整体技术进度已经走向到了一个新的阶段,新的阶段不是靠等出来的,而是靠疯狂的基建把效率压榨出来的,所以电网时代,我们受限于人力,就 push 团队的核心成员,技术栈的深度和广度发生更多质变,从而能空出来一定是资源来持续支撑基建,而基建的成果一定能吸引更多优秀的工程师进来团队,这样就能形成一个健康的基建生态,这样基建、业务支撑、人才成长之间就互相反哺,整个团队才正式走向正规。</p>
<p>判断团队是否走向正规,可以从业务的支撑程度以及技术沉淀物来评估,下图是我们 2018 年 10 月份盘的前端支撑情况,其中有如下几个重要的技术沉淀:</p>
<ul>
<li>Node 服务框架 Cross,2019 年将支撑十几个线上系统</li>
<li>前端 PC 框架(支持 H5) Highway,2019 年将支持十几个线上平台</li>
<li>RN 的统一路由/组件框架 Brick(图上未体现),2019 年将继续 9 个 App</li>
<li>可视化数据报表系统,技术栈 Node + GraphQL + C# + Python,2019 年将支撑全公司业务数据透视</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1563236864178-9fc8bb2a-9174-42c1-8424-65c30f158643.png#align=left&display=inline&height=1104&originHeight=1104&originWidth=1972&size=0&status=done&style=none&width=1972" alt="" title=""></p>
<p>在上图,我们特意标出了 人工时代 - 工具时代 - 工程时代 - 智能时代,来对应到之前玉伯提到的前端团队路线,发展轨迹确实与小菜前端特别吻合,所以我们前面几年的技术栈是处在人工时代和工具时代,而现在我们正在从工具时代跨向工程时代,而工程时代的思维方式跟之前会有很大的不同,这个课题就将伴随我们团队未来至少 2 年,我们也会把未来 2 年在工程时代的思考,以及部分智能时代的尝试,在后面不断的更新进来与大家一同进步。</p>
<p><a></a></p>
<h2>小结</h2>
<p>本篇带大家快速的 review 了团队的技术栈发展史,大家脑海中可能已经有了无数的问题想要问,比如 NodeJS 在团队中具体做了哪些事,基建与业务到底如何平衡,业务与个人成长到底如何结合等等,这些问题我们全部打散成了一个一个的小课题,在后面的章节中与大家逐个探讨,建议大家在阅读的时候,结合自己所在的团队,结合自己的职业规划,结合自己假如作为管理者会如何选择,用这种代入感发问更多问题,并最终从我们的总结中受到启发,有所收获。</p>
<blockquote>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=dW4YRsBRlBj4GkJhZb%2Fdow%3D%3D.rVrmN%2BnBNB%2FbNam%2BRnh5wyPzECu40HrR%2FojuGfUkB3U%3D" rel="nofollow">关注 Scott 跟进我的动态</a>,本文未经许可不许转载,获得许可请联系 Scott,否则在公众号上直接转载,尤其是裁剪内容后转载,我都会直接进行投诉处理。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
生鲜 B2B 技术平台的前端团队该如何搭建
https://segmentfault.com/a/1190000022294016
2020-04-07T23:00:00+08:00
2020-04-07T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
7
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>线下越重,线上需要越轻,这个轻指的是轻便轻巧和简洁易用,通过前面几章小菜技术与产品历史介绍,我们了解到 B2B 生鲜领域在线下是如此之重,那么在交易场景线上化的过程中,端的移动化就势在必行,试想一下,让菜市场摊位老板人手一台笔记本点开网页选购支付,让采购销售抱着电脑去拜访客户,一边聊蔬菜行情,一边打开笔记本进行记录,有没有一种回到世纪初的感觉。</p>
<p>产品的移动化,这将是我们展开这篇文章的背景,我们会先了解小菜的产品托管在哪些端上,然后感受这些端带来的挑战,最后是我们面对这些挑战所采取的策略,以及整个小菜前端团队历练后的技术成长和沉淀,和我们对于自己的一个评估和对未来的展望,本文将采用最通俗易懂的方式陈述,会略有繁琐,但力求对技术新人也足够友好。</p>
<p><a></a></p>
<h3>一、小菜大前端的端有哪些</h3>
<p>小菜早期围绕着蔬菜销地以客户集单批发的模式摸爬滚打几年,从上游的蔬菜供应商到下游批发市场的摊位老板,在这个长长的链路中,我们诞生了这样几款线上产品来服务于不同的人群和场景,之前文章中也有介绍,这里再汇总一下,共 7 款 App:</p>
<ul>
<li>宋小菜 服务于销地批发老板的下单工具</li>
<li>宋小福 服务于小菜内部销售团队的 CRM 销售管理与客户管理工具</li>
<li>宋小仓 连接司机-物流-采购-销售的蔬菜在途位置监控工具</li>
<li>采秘 服务于小菜内部采购团队的蔬菜品类采购工具</li>
<li>麦大蔬 服务于上游蔬菜供应商的大宗农产品交易平台</li>
<li>宋大仓 服务于上游囤货配资的进出库管理平台</li>
<li>行情宝 服务于产销两地的行情采集和预测工具</li>
</ul>
<p>前 6 款 App 都是基于 ReactNative 开发的 iOS/Android App,最后一个是微信小程序,它们涵盖了公司几乎所有的协同场景和工作流,其他涉及审核、数据观测和过程管理的部分,则会进入到我们 PC 端产品中,也就是:</p>
<ul><li>ERP 后台管理系统</li></ul>
<p>生鲜的 toB 场景,角色众多,链路冗长,这种延伸到产地农民,延伸到小 B 交易的管理系统一定会角色杂,权限多,操作重,业务复杂度所带来的页面复杂度不是一般的小系统可比拟。</p>
<p>到目前为止,我们已经看到小菜的 7 个移动端 App,以及一个复杂的后台管理系统,这些都跟前端工程师息息相关,除了这些,还有 2 个重要的内部产品,就是:</p>
<ul>
<li>大表哥 数据报表系统</li>
<li>大瓜子 市调模板配置系统</li>
</ul>
<p>其中大表哥(谐音:搭 Excel 表格)由前端工程师独立研发和维护的数据报表系统,单拎出来这个系统,是因为在 B2B 公司,尤其涉及到供应链的长链路场景中,真实业务数据的及时反馈对于每一个执行团队都至关重要,没有这些数据抓手,就失去了多维度数据观测,都很难快速的做出正确的运营决策和业务调整,甚至很难发现业务中出现的漏洞和问题,比如不正常的非自助下单(也就是销售帮忙下单)的比例。</p>
<p>关于报表系统后文还有介绍,我们再为前端增加一个服务的产品场景,就是微信生态内产品,比如公众号或者小程序,它的技术栈和运行环境跟原生 App 和 PC 都不同,虽然小程序可以带来更多的业务可能性,也会对前端带来更大的挑战。</p>
<p>我们把这些端合并一下,小菜前端要服务的端或场景:</p>
<ul>
<li>移动端(iOS/Android App/小程序)</li>
<li>PC 端(ERP)</li>
<li>工具端(大表哥数据报表)</li>
</ul>
<p>端上全部开花,这也应了我之前在掘金 JTalk 上小菜对于长链路流通交易分享的一个观点:<a href="https://link.segmentfault.com/?enc=W5NLPYIIOARvz3e4vsfvXQ%3D%3D.xG5%2BYZoZGwVUZf0LePo63jkFJKeFoBuuHUs4hsJDzqrwDalAYow218DerwQmNFg8" rel="nofollow">链路足够长,每个节点上都可以长出产品</a>。那这些端产品都是与业务有强关联的,还有更多技术基建的和服务于团队内的产品,比如:</p>
<ul>
<li>大伯伯(谐音打包包) 实现 App 选仓库选分支选环境配置的自主打包与推包系统</li>
<li>大表姐(来自饥饿游戏,寓意开工没有回头箭) 实现 6 款 App 解包差分后下发热更新包的发布系统</li>
<li>姑奶奶 线上异常汇集分析与与 Bug 定级指派系统</li>
<li>大舅子 向下调用微服务接口向上提供 GraphQL 查询能力的数据聚合服务</li>
<li>RGB 用户使用 App 的 PV/UV,以及业务数据监控相关的可视化平台</li>
<li>110 解决端异常收集与报警需求</li>
<li>堂哥工作台 团队记录资源分配与 redmine 同步的自动化周报系统</li>
<li>ITms 解决内部 App 安装测试的配置生成和预装服务</li>
<li>...</li>
</ul>
<p>这些是服务于团队内部的工具链,全部由小菜前端自行维护。到这里我们发现,在小菜这样一家创业公司内,前端要服务的端和场景的确较多,但这些产品和工具的背后,整个前端组也就 10 个人而已(我们当然也求才若渴),但是人虽少,效率不能自我妥协,所以我们能服务到这些端,也正是基于端的多样性和数量,我们称自己:宋小菜大前端。</p>
<p>先上小菜端上若干产品和工具的技术栈图,帮助大家理解我们的技术理念:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1525686896336-0af87fa7-b4e7-4c43-ae22-80a5a86c7746.png#align=left&display=inline&height=545&originHeight=990&originWidth=1358&status=done&style=none&width=747" alt="" title=""></p>
<p><a></a></p>
<h3>二、多端带来的挑战</h3>
<p><a></a></p>
<h5>1. 【物理现状】移动端的碎片化</h5>
<p>古典互联网时代,因为要兼容 IE678 而痛苦不堪,Hack 黑魔法经验基本代表前端水平,如今互联网早已移动化,我们理想中的移动端开发,看上去是可以大胆使用新语法特性,只需要做好尺寸兼容就好了,但事实并非如此,不仅在移动端的浏览器不是如此,在移动端开发 RN App 也是如此,这是我们某一款 App 一段时间内,所收集上来的手机厂商分布:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1525342888541-27451bb8-8278-4ba1-9554-f36b79da48f0.png#align=left&display=inline&height=493&originHeight=996&originWidth=1508&status=done&style=none&width=747" alt="" title=""></p>
<p>可以发现 Android 的碎片化非常严重,每一个厂商下面有不同时期推出的不同型号的手机,这些手机有着不同版本的操作系统,不同的分辨率和用电策略,不同的后台进程管理方式和用户权限,要让一款 App 在哪怕头部 40% 的手机上兼容,都是一件艰难的事情,这个客观物理现状叠加下面的社区现状,App 质量保证这件事情会变得雪上加霜。</p>
<p><a></a></p>
<h5>2. 【社区现状】技术框架的不稳定性</h5>
<p>回到本文的开头,我们在长链路的 B2B 生鲜场景中,为了更快更轻,开发出 7 款 App,而且将来随着业务场景的拓展会诞生更多独立 App 甚至是集大成的 App,所以技术选型不太可能选择原生的 Java/Object-C 开发,尤其对于创业公司,6 款 App 得需要多少名原生开发工程师才能搞定,高频繁重的业务变化又怎样靠堆人来保证?</p>
<p>想清楚这些,一开始我们就调研 ReactNative,并最终全部从原生切换到了 RN,通过跑过来的这 3 年来看,使用 RN 为公司节约了大量的人力成本同时,也尽可能的满足到几乎所有的需要快速迭代的业务场景,又快又轻,成为宋小菜大前端团队做事的一个典型特征。</p>
<p>但换一个角度看,就是带来的问题,又快又轻的背后是 RN 版本的飞速迭代,截止到目前,也就是 2018 年 6 月份,RN 还没有推出一个官方的正式的长期维护的稳定版本,什么意思?就是 RN 目前依然处在不稳定的研发周期内,我们依然站在刀尖起舞,用不稳定的 RN 版本试图开发稳定的应用,三年走过来,我们在 RN 的框架里,多少次面对旧版本局限性和新版本不稳定性都进退不得,旧版本的 Bug 可能会在新版本中修复,新版本引进则会来新版本自己的问题。</p>
<p>除了 RN 自身版本,还有第二个问题,围绕着 RN 有很多业界优秀的组件,但这些社区组件甚至官方组件,都不一定能及时跟进最新的 RN 版本,同时还能兼容到较老的 RN 版本,所以 RN 升级导致的组件不兼容性,会引发你 Fork 修改组件的冲动,但这样会带来额外的开发成本和版本维护成本,取舍会成为版本升降的终极问题。</p>
<p>在国内开发,还有第三个问题,就是中文文档缺乏,社区资源匮乏,参考文献陈旧,可拿来主义的开源工程方案甚至社区线上线下会议分享都很缺乏,一个不小心就会踩坑,这就是 RN 社区的现状,我们在刀尖浪花上独步,App 选型背后的技术栈稳定性则成为悬在头上的一把铡刀,你不知道什么时候会咔嚓一声。</p>
<p><a></a></p>
<h5>3. 【人才现状】人员能力的长短不齐</h5>
<p>我们知道有一个词叫做主观能动性,表示没有条件创造条件也可以上,这个词的主体就是人,聊完移动端设备现状和社区现状后,我们来聊聊人的问题。RN 在国内真正开始普及使用,是从 2015 年开始,也就意味着,到 2018 年,一个 RN 工程师也就只有 3 年的工作经验,而 RN 的 “Learn once, write anywhere” 也刺激着一切 Care 人员开支, Care 产品研发投入性价比的公司纷纷跳水研究 RN,争抢 RN 人才,RN 是前端中的移动前端,前端有多抢手,那么 RN 工程师就比它还要抢手。</p>
<p>这导致基本上 RN 工程师,很难靠外部招聘,只能靠内部培养,这也是小菜前端的成长历程,我们有 2 名资深 RN 工程师,一个是从服务端 Java,一个是从原生 Android 开发转过来的。如果 RN 人手不足,产品支持的力度和速度就一定会遇到瓶颈,这就是我们曾经面临的问题,就是人才现状,外招数量不足,内培速度有限,RN 工程师的数量和能力就时不时成为公司业务扩张的瓶颈。</p>
<p><a></a></p>
<h5>4. 【公司现状】高密集业务的交付质量</h5>
<p>作为工程师,我们有很强的自尊心和不容挑战的代码洁癖,但在一个创业公司里面,甚至大公司的一个创业团队里面,我们需要对接一些关键的业务节点,冲刺一些特定的时间窗口,并且要及时响应多变的业务,和业务背后多变的产品形态,这都会带来非常密集的需求队列。</p>
<p>这些密集的需求队列对我们的代码实现质量有非常高的挑战,一个组件用 5 分钟思考如何抽象和用 50 分钟思考,实现后的稳定性、兼容性都是不同的,如何保证产品按期交付上线,会是摆在我们面前一个非常关键的命题,而这个难题之外,还有一个更难的命题等着我们,那就是如何保证交付不延期的同时,还能保证交付质量。</p>
<p>要知道,如果一个项目代码赶的太毛糙,后期维护起来的成本会是巨大的,甚至只能用更高的成本重构重写。本质上,再次重构就一定是公司在为早期的猛冲买单,为这些技术债买单,如何不去买单或者如何用最小的成本买单,这跟我们早期的业务密集程度,交付周期,质量把控有很大的关系。</p>
<p>综上,移动端碎片化所带来的兼容难度,RN 框架的局限性,版本间差异带来的不稳定性,技术社区资源的匮乏和前端团队技术能力掣肘,再叠加上高密度的业务排期,让前端开发这个本来很酷的事情,变得晴雨不定。</p>
<p>这些避不开的现实,是绕不过去的坎儿,是搭建团队必须搞定的基础,我们想要把 B2B 生鲜的线上线下场景通过端产品关联起来,想要通过前端团队的用户侧输出从而让这些产品落地,就必须面对这些现实挑战,而应对这些挑战,首先必须搞清楚有哪些挑战,搞清楚挑战以后,我们就会认识到,首当其冲的事情,是去搭建 B2B 生鲜公司的前端技术栈和人才梯队,现在我们进入到本文的重点。</p>
<p><a></a></p>
<h3>三、如何应对井喷的挑战</h3>
<p><a></a></p>
<h5>1. 前端梯队如何搭建</h5>
<p>创业公司的技术团队,本质上就是人和事,用合适的人搞定特定的事,人才的瓶颈就是这家公司产品落地速度和上线质量的瓶颈,因此人是第一位的,对于前端团队来说,如何一步步形成有综合战斗力的团队,取决于搭建什么层次的前端梯队,如果所有人一视同仁,培养同样的能力栈,发挥同样的兴趣向,跟进同样的业务线,那么这个梯队的扁平就会带来致命的团队瓶颈:能力可复制但不能互补,能力可递进但很难跨越,不能互补和很难跨越会导致团队内的技术路线过于单一,技术思维趋于固化,至于技术储备的丰富性和技术沟通带来的碰撞就更有限,最终导致人做事越来越机械化,甚至失去最初的技术初心。</p>
<p>那么小菜前端到底如何搭建,还是要从公司的人员、业务和技术现状出发,由于端的碎片化和技术框架的不稳定性,就必须在质量保障上投入巨大的人力保证产品可用,而人才能力局限性和数量的匮乏,就跟产品的质量保证成为了天然的矛盾,不可协调,代码撺太快,线上天天都是 Bug,代码撺太慢,产品节奏跟不上,至于跟工程师天天宣讲要小心小心再小心,能起到的作用也不大,因为工程师本身的能力也是参差不齐的,所以就必须把团队先拆成两部分,一部分做基建支持,一部分做业务支持,基建支持的同学研发整个团队的工具脚手架、抽象和打磨团队的基础通用组件、长期维护项目的通用架构,这些投入都会反哺到业务支持的同学,业务的同学可以放心大胆的基于基建的成果做上层业务开发,稳定的工程基础有了保障,上层的业务代码做质量保障难度就大大降低了。</p>
<p>除了分出来人做基建,做业务,还需要有核心的技术骨干,做技术前瞻性的研究,为团队 3 个月后,半年后,甚至 1 年后的技术方向,做必要的调研、测试和实验性开发,因为对于刀耕火种的早期技术团队,从原始人到迈向外太空跨空间作战,这中间还差着很多个关键的技术迭代节点,这些关键的技术迭代节点,一部分是靠外招技术专家和资深的工程师来输血发力,还有一大部分是需要靠团队内部长期的积累沉淀,也就是人才内部培养。</p>
<p>我们总结一下:</p>
<ul>
<li>基建的同学负责输出工具系统、基础组件、流程规范,保证内部效率最大化和质量的有效保障</li>
<li>架构的同学负责攻克技术底层难点,调研先进技术,升级团队技术架构,沉淀技术方案,锁定和推进团队未来技术方向</li>
<li>业务的同学负责产品跟进,高频使用基建产品,并通过反馈来优化团队的技术基础设施,同时基于业务来抽象更多的基建需求</li>
</ul>
<p>基建、架构、业务这三个角色并不是相互独立,而是互有重合各有侧重,一个业务的同学,可能也同时在负责基建的事情,一个基建的同学,可能也同时在参与架构的设计,在小菜就有同学以架构和基建为主,业务也时不时的参与开发,架构和基建必须依托于业务场景来做,不能脱离了场景,不然会输出畸形的难以落地的技术方案。</p>
<p>上面是人员的分工,还有三个重要的保障,这里不做引申,只列举一下:</p>
<ul>
<li>团队人员的兴趣栈、能力栈和业务要尽量匹配</li>
<li>团队人员的阶段性目标、长期规划要跟进公司的职业晋升路线和能力模型</li>
<li>团队要有持续性的内部技术互动分享和对外的技术理念、方法方案分享</li>
</ul>
<p>小菜的前端是大前端,对人的要求是:一专多精多能,至少在某个领域内朝着专家方向走,同时要慢慢精通多项技能,最后是具备多个特定技术栈的开发能力,比如 ReactNative,在小菜就是一个必须具备的开发能力,不要求每一个同学都成为 RN 专家或者精通,但要具备业务开发的能力,通俗点描述,就是能用 RN 开发业务产品。</p>
<p>最后一点,就是资源流转,架构的同学,基建的同学和业务的同学的梯次关系是从下到上,越下越接近技术本质,越上越接近业务结果,越向下需要越好的技术实力,越向上需要越好的业务理解能力,这两个能力都是核心能力,需要让团队成员沿着梯队关系慢慢流动起来,业务中技术能力好的同学可以有机会沉下来做做基建,长期埋头基建的同学可以有机会上去做做业务,业务理解不错技术沉淀又好的同学可以继续沉下去参与架构,这样团队内部的同学都可以有多样性的技术场景和业务场景,一旦有同学请假、陷在别的业务不能抽调,马上就有同学可以补位进来开发,不会影响到产品上线节点。</p>
<p>关于团队如何搭建,目前小菜是走到了这个算是 v1.0 的阶段,未来还有更多挑战,也会带来更多的基于公司现状的新调整,无论如何变迁,方法论我们先沉下来:</p>
<ul>
<li>人才梯队要有层次:基础架构、基建和业务上层等</li>
<li>人才成长要有规划:兴趣栈、能力栈和公司关系</li>
<li>人才能力要有扩展:单人能力和互补后的团队能力</li>
</ul>
<p>以人为过程,以事为结果,人事之间要有动态的机制形成互惠互补的关系,只有这样,团队才会初心不变,激情常在。</p>
<p><a></a></p>
<h5>2. 如何做技术选型</h5>
<p>技术选型是一个行业老话题了,方法论也有很多,在小菜我们遵循的是:技术方向性预研大踏步,业务基建型开发小碎步,前者尽可能激进,后者尽可能保守,比如 数据报表系统,我们激进的采用 GraphQL 来解决 SQL => 页面 Dom 的链路问题,在宋小福 App 上面,我们就求稳的采用 v0.48 的 ReactNative 版本,而不是用当时较新的 v50+ 版本。</p>
<p>在做技术选型之前,还有一些比较重要的基础性问题需要搞定,那就是团队技术动作的一致性,这个一致主要包含两点:</p>
<ul>
<li>代码规范共用一套</li>
<li>仓库合作方式共用一套</li>
</ul>
<p>这两点如果不一致,会给技术选型后的落地带来内耗成本,千万不可大意。</p>
<p>再回到技术选型本身,抛开激进保守的大踏步和小碎步,我们需要回到技术本质和工程师的本质来看待如何选的命题,技术的本质是效率,工程师的本质是兴趣,如果这一套技术选型不能带来效率,如果工程师普遍不感兴趣,那么通常这一个选型我们不会采纳,我觉得这一个主观一些的标准,大家可以参考,但这里面也要权衡好历史包袱、维护成本,上手难度等这些客观现实,如果一个新技术会带来革命性的效率提升,那么即使有上手难度和维护成本,我们也会果断入坑,比如 GraphQL 对于数据报表对于解放前后端有大幅度的提升,我们会果断入坑大力推行,如果一个技术对于团队是锦上添花,那么我们会慎重选用,比如 TypeScript,可以给工程稳定性带来了较大的保障,但我们只选择在热更新这种 RN SDK 和 Server 端的去集成,而不是一下子推广到整个团队项目中铺开用,这里面就会考虑到实际得到的好处,以及历史包袱和上手难度,反复权衡后并没有带来更大的价值,所以这两类场景的推行和不大力推行,就又不会太依赖于工程师的喜好兴趣。</p>
<p>那么我们技术选型后的结果是如何呢?</p>
<p>文章最开始的那张图,里面就是我们的技术栈,这里再做一下总结:</p>
<ul>
<li>工具类:强依赖 Node,多而杂的其他技术,如:MongoDB/Redis/MySQL/Shell/Python</li>
<li>业务类:强依赖 React/ReactNative,适度集成其他技术,如: Redux/GraphQL/Apollo</li>
<li>框架类:除了 React 全家桶会谨慎选择,Node 端框架则相对宽松:Koa/Thinkjs/Eggjs</li>
</ul>
<p>这些相对求稳,不求稳的部分,如小程序开发,我们会使用 mpvue,也会用原生,还会集成进去 GraphQL,同时一些涉及到数据爬取和视频图像识别,我们也会集成 Python/C++/TenserFLow 等等,不过这些往往是前瞻性的技术尝试,会让团队的同学适当分配精力持续研究。</p>
<p><a></a></p>
<h5>3. RN 的 App 工程如何架构</h5>
<p>小菜的主要产品类型,尤其是对外的产品,主要是 RN App,而且数量较多,那么 RN 项目的合理架构就变得尤其重要,我们这里探讨下小菜前端在 RN App 上面的沉淀,涉及到原生层面的技术细节太多,这里暂不做讨论。</p>
<p>首先,我们在构建 RN App 工程时需要关注这几个关键要素:</p>
<ul>
<li>配置管理</li>
<li>静态文件管理</li>
<li>网络请求</li>
<li>组件管理</li>
<li>路由管理</li>
<li>数据缓存</li>
<li>App 的热更新</li>
<li>数据搜集</li>
</ul>
<p><strong>配置管理</strong>是指可以灵活合理的管理 App 的内部环境,主要包括:</p>
<ul>
<li>App 本身的一些配置</li>
<li>所使用三方插件的配置</li>
</ul>
<p>我们在构建工程时尽量将所有的配置抽象统一放置在一个地方,这样便于查找和修改,但是由于大多数配置都统一放在同一个地方,那么就难免有部分文件要使用某个配置时其引用路径比较长,比如:</p>
<pre><code class="javascript">import { pluginAConfig } from '../../../../../config'</code></pre>
<p>这样就造成了阅读性很差且代码不美观,因此我们可以使用 Facebook 的 <code>fbjs</code> 模块提供的一个功能<code>providesModule</code> :</p>
<pre><code class="javascript">//config.js
/**
* config for all
* @providesModule config
* 使用 providesModule 将 config 暴露出去
**/
import pluginAConfig from './plugin_a_config'
export default {
pluginAConfig
}
// 然后在其他文件中调用
// A.js
import { pluginAConfig } from 'config'</code></pre>
<p>这样就能很方便地在 App 的任意一处使用 config 了,但是我们要避免滥用 <code>providesMoudle</code> ,因为使用了 <code>providesMoudle</code> 进行声明的模块的源码,想要在编辑器中使用跳转到定义的方式去查看比较困难,不利于团队多人合作。</p>
<p><strong>静态资源</strong>泛指会被多次调用的图片或 icon,我们一般在 RN 使用图片时是直接引用的:</p>
<pre><code class="javascript">import { Image } from 'react-native'
render(){
return (
<Image source={{uri: './logo.png'}} />
)
}</code></pre>
<p>当图片需要在多处使用时,我们可能会将这些可能会被反复使用的图片统一管理到 <code>assets</code> 文件夹中,统一管理和使用,但是当需要使用图片资源的文件嵌套较深时,引用图片就变得麻烦:</p>
<pre><code class="javascript">render(){
return (
<Image source={{uri: '../../../../assets/logo.png'}} />
)
}</code></pre>
<p>这个问题与配置管理的问题一样,可以首先将图片资源按照类型进行分类,比如 assets 文件夹下有 button/icon/img/splash/svg 等,每一个类型的结构如下:</p>
<pre><code class="javascript">- icon/
- asset/
- index.js</code></pre>
<p>其中 <code>asset</code> 文件夹保存我们的图片资源,在 <code>index.js</code> 中对图片进行引用并暴露为模块:</p>
<pre><code class="javascript">// index.js
export default {
IconAlarmClockOrange: require('./asset/icon_alarm_clock_orange.png'),
IconAvatarBlue: require('./asset/icon_avatar_blue.png'),
IconArrowLeftBlue: require('./asset/icon_arrow_left_blue.png'),
IconArrowUpGreen: require('./asset/icon_arrow_up_green.png')
}</code></pre>
<p>然后再在 <code>assets</code> 文件夹下编辑 <code>index.js</code> ,将所有的图片资源作为 <code>assets</code> 模块暴露出去,为了避免和其他模块冲突你可以修改模块名为 <code>xxAssets</code></p>
<pre><code class="javascript">// assets/index.js
/**
* @providesModule myAssets
**/
import Splash from './splash'
import Icon from './icon'
import Img from './img'
import Btn from './button'
import Svg from './svg'
export {
Splash,
Icon,
Img,
Btn,
Svg
}
// A.js
import { Icon } from 'myAssets'
render(){
return (
<Image source={Icon.IconAlarmClockOrange} />
)
}</code></pre>
<p>这样,我们就能很方便地将分散在项目各处的图片资源统一到一个地方进行管理了,使用起来也非常方便。</p>
<p><strong>网络请求</strong>这块,react-native 使用 <a href="https://link.segmentfault.com/?enc=Ih8F%2FExG%2F5qcOeVhHfhNWg%3D%3D.Tnz7%2Fb49P7PYgMmYxgEPl%2B80NX%2BITZVJKIjsIKcvXAYBDxIaYXyUshTineOUme0n6n%2F%2Fu5kpDx9g84ScfBu1VPzonToeN8Y5X691u0Q%2FnC4%3D" rel="nofollow">whatwg-fetch</a>,我们也可以选在其他的三方包如 <a href="https://link.segmentfault.com/?enc=GvOFUmi05SX2%2F2nWf6ZE2A%3D%3D.uFIdAp9%2BSbza4i1bYzMdAWs%2FSgw4cAuLiKmUBlI6kfo%3D" rel="nofollow">axios</a> 来做网络请求,但有我们在开发中遇到过一个问题,那就是我们明明已经在代码里已经修改了 cookie, 但是每次请求可能还是会带上之前的 cookie 从而造成一些困扰,所以这里推荐一个实用的组件 <code>Networking</code> :</p>
<pre><code class="javascript">import { NativeModules } from 'react-native'
const { Networking } = NativeModules
// 手动清除已缓存 Cookie,这样就能解决上述的问题了
Networking.clearCookies(callBack)</code></pre>
<p>当然,<code>Networking</code> 的功能不止于此,还有很多其他有趣的功能可以发掘,可以直接用它来包装自己的网络请求工具,还支持 <code>abort</code> ,可以参考 <a href="https://link.segmentfault.com/?enc=Lef6SFiIF8bEMoa3egxqvw%3D%3D.c%2FssgKhSCWQ7SvzBlxoq96K6nkemduFQRXQ55ftOm3G%2By%2FGlQRNnslE4FUezyeESFtdzRlM4p%2Ft5K%2B69%2B60GzDPWUI5GANFeBBgXZAbLnL7hvAVUSo4H7VqJjh6sbSFq" rel="nofollow">源码</a> 来具体把玩。</p>
<p>使用 RN 开发 App 本身效率就比较高,如果想要继续进阶就要考虑组件化开发,一旦涉及到组件化开发,就不可避免地会涉及到组件管理的问题,这里的<strong>组件管理</strong>比较宽泛,它实际上应该指的是:</p>
<ul>
<li>组件规范</li>
<li>组件类型划分</li>
<li>组件开发标准</li>
</ul>
<p>组件规范指的是 UI 设计规范,我们可以与设计同学交流规定好一套特定的规范,然后将通用的样式属性(如主题颜色,按钮轮廓,返回按键,Tab 基础样式等)定义出来,便于所有的组件开发者在开发时使用,而不是开发者各自为政在开发时重复写样式文件,这里推荐一个比较好用的用于样式定义的三方插件 <a href="https://link.segmentfault.com/?enc=wfBgEmMMikxhpzozV%2FM40Q%3D%3D.N%2BxibRL7S%2F8rgpPF%2B%2Fetnv7sVVZC%2F2yRQN2zwsnk5j0EDVO7VE%2Bc0eyofGsEh7G%2BPLSeiYJcZ3VDejtpyVI43A%3D%3D" rel="nofollow">react-native-extended-stylesheet</a> ,我们可以使用这个插件定义我们的通用属性:</p>
<pre><code class="javascript">// mystyle
import { PixelRatio, Dimensions } from 'react-native'
import EStyleSheet from 'react-native-extended-stylesheet'
const { width, height } = Dimensions.get('window')
const globals = {
/** build color **/
$Primary: '#aa66ff',
$Secondary: '#77aa33',
$slimLine: 1 / PixelRatio.get(),
/** dimensions **/
$windowWidth: width,
$windowHeight: height
}
EStyleSheet.build(globals)
module.exports = {
...EStyleSheet,
create: styleObject => EStyleSheet.create(styleObject),
build: (obj) => {
if (!obj) {
return
}
EStyleSheet.build(_.assign(obj, globals))
}
}
// view.js
import MyStyleSheet from 'mystyle'
const s = MyStyleSheet.create({
container: {
backgroundColor: '$Secondary',
width: '$windowWidth'
}
})
render....</code></pre>
<p>这样,我们就能在开发的任意插件或者 App 中直接使用这些基础属性,当某些属性需要修改时只需要更新 <code>mystyle</code> 组件即可,还可以衍生出主题切换等功能,使得开发更加灵活。</p>
<p>关于组件类型我们会抛开三方组件以及原生组件,因为一旦涉及到这两者,需要写的东西就太多了,我们将组件按使用范围分为通用组件和业务组件两大类。</p>
<p>首先什么是业务组件?即我们在开发某个业务产品常用到的组件,这个组件绑定了与业务相关的一些特殊属性,除了这个业务开发以外,其他地方都不适用,但是在开发这个业务时多个页面会频繁地使用到,所以我们有必要将其抽象出来,方便使用。</p>
<p>什么是通用组件?即可以在 App 范围内使用甚至于跨 App 使用的组件,这里可以对这个类别进行细分,我们将能跨 App 使用的组件上传到了自己的搭建的私有 npm 仓库,方便我们的 App 开发者使用,同时,具有 App 自己特色的组件则放到工程中统一管理,同样适用 <code>providesModules</code> 暴露出去。</p>
<p>制定一整套组件开发标准的是很重要的,因为很多组件开发可能是多人维护的,有一套既定的规范就可以降低维护成本,组件使用的说明文档的完善也同样重要。</p>
<p>开发 App 就不可避免地会遇到如何管理页面以及处理页面跳转等问题,也就是<strong>路由管理</strong>问题,自从 Facebook 取消了 RN 本身自带的 Navigator 以后,许多依赖于这个组件的开发者不得不将目光投向百花齐放的社区三方组件,FB 随后推荐大家使用的是 <a href="https://link.segmentfault.com/?enc=iQqC7i6vXu4KcK4KqFXiMA%3D%3D.vGNNxugLxf%2FosWvYCHgbu6LxwYSFXKfMIUFX0CWps82%2FH2jPBvxJUxnolOdXhzxz" rel="nofollow">react-community</a> 推出的 <a href="https://link.segmentfault.com/?enc=%2B8uYcMpv7aIfTLM9%2FWORXQ%3D%3D.3TJfI3oMLGiUDZiJWo6a2Mlv%2FOd0yE4KEG3V0oJjddbDqZVMrjix85zox%2FL5qQIT" rel="nofollow">react-navigation</a> ,现在这个路由组件已经独立出来了。我们在开发时就是使用的这个组件作为路由管理组件,只不过是在其基础上做了一些定制 ,使得使用更加简单,部分跳转动作更加符合我们的产品场景,推荐大家使用这个组件。当然,除去这个组件还有很多其他的组件可供选择:</p>
<ul>
<li>基于 <code>react-navigation</code> 进行深度定制的 <a href="https://link.segmentfault.com/?enc=vbzRH%2BMQ9nhDyURLOqHYtg%3D%3D.dmGHqP7EQOMJJGGMWSRNxRXPMFVklhYM9OxTHK6b9IXrXe42V%2BrWRt9xPyp%2BKGMZ08ji723byFVokEO1PTxt8Q%3D%3D" rel="nofollow">react-native-router-flux</a>
</li>
<li>基于原生解决方案的 <a href="https://link.segmentfault.com/?enc=9nMbbYcx%2FpJkkmQsQaiJ%2BA%3D%3D.9jRWm4134Nw7VeiH3VXnHKXuiZ%2FVY4hXEpCUu%2BJUEj5kGjPXCodLBLsyiebvbCNN" rel="nofollow">react-native-navigation</a>
</li>
<li>airbnb 的 <a href="https://link.segmentfault.com/?enc=%2BTiP%2FHhZZTlpbKhHXQqc%2BQ%3D%3D.SnoYwQnvC9etPA7mdtG7ZD9GV9dKeCbEBMkely1gboqvkYgITimMx%2B2BttsAH1ZJ" rel="nofollow">native-navigation</a>
</li>
</ul>
<p>路由管理作为整个 App 的骨架,它是这几个部分中最重要的一部分,合理地定制和使用路由管理可以极大地简化我们的开发复杂度。</p>
<p>一般情况下需要缓存的数据基本上就可能是我们会在 App 很多地方都会使用到的全局数据,如用户信息,App 设置(非应用层面的设置)等,RN 提供一个 <a href="https://link.segmentfault.com/?enc=dXFgiIrBz0emlhe9YC0Khg%3D%3D.BAi2Soi1v1Pyp1PB2Sj1N9hfoFRaeVBUrNAVCvmdgEzIBtvDbszqb2TzL41LbwkTzoMwKzHTw3OOFln332aXPDb3V6oohBWQCn7tScqNLPbxspk0MzcRNwYB%2FWaJJKoJ" rel="nofollow">AsyncStorage</a> 存储引擎,通常的使用方式是对这个数据引擎进行包装后暴露出符合我们要求的读写接口。这里推荐另外一种使用方式:</p>
<p>既然需要缓存的数据可能是会在 App 很多地方使用到的全局数据,那么我们可以将这些全局数据使用 <a href="https://link.segmentfault.com/?enc=2knmT7AjfMPTqPp3IEi3UQ%3D%3D.L36PmwaOuWsBhjVuEe5yLWWni5Z0edHZjUQm5KPQzznb3yDtNupHtlIpeZ1yiIuL" rel="nofollow">redux</a> 来进行管理,而利器 <a href="https://link.segmentfault.com/?enc=X8URYEK62icni699EKqtcQ%3D%3D.NEMiq2PTQzg%2FQCo1EQO3kgn9H3lBL00lOs7gSI8t6Izxe%2Fvl8ULrW7fjMBuAKx96" rel="nofollow">redux-persist</a> 则能让我们很优雅地读写我们的缓存数据。</p>
<p>同时,如果对 <code>react-navigation</code> 进行合理的定制,接管其路由管理,那么我们还能实现保存用户退出 App 之前最后浏览的页面的状态,用户在下次打开 App 依然可以从之前浏览的地方继续使用 App,当然,这个功能要谨慎使用!</p>
<p><strong>App 的版本更新</strong>,RN 除了传统的 App 更新外还有一个热更新的可选项(传统 App 更新也有热更新,其原理就不太一样了),社区大多数人都推荐使用 <a href="https://link.segmentfault.com/?enc=CVMN3A076Zagk0CaG55pwQ%3D%3D.%2Fb8v3FKTCDahZqx0sX2ccLJJEBlANj62oynZfTjipDHtUm6ygvt%2BnItchfYNfZtaklgUHQ3BLkpt%2FWMjII6YvQ%3D%3D" rel="nofollow">codepush</a> 来进行热更新,至于其后端解决方案 貌似已经有了一个 <a href="https://link.segmentfault.com/?enc=gy8aSaE3pvspz1HIWvf8Dw%3D%3D.V5yzEJwfomEIdOf2ZrkPWrSlUvOipFn8P2koj8zaSvfHHp0HlBCsNpI0p705kNO%2F" rel="nofollow">code-push-server</a> ,我们是使用自己的热更新方案,其原理就是在不更新原生代码的基础上更新 JS 代码和静态资源文件。</p>
<p><strong>搜集的 App 使用数据</strong>(包括异常数据)并对此分析,根据分析来定位问题是保证 App 质量的有效手段之一。你可以选择自己搭建一套数据搜集服务,包括客户端 SDK 和服务端搜集服务,或者选择市场上已有的工具,目前较为成熟的收据搜集工具比较多,如友盟,mixpanel, <a href="https://link.segmentfault.com/?enc=btk9vyl4SguoYeV%2Bz98RQQ%3D%3D.9vPTBVjyuoEJyDPHlGkLfDO8IgoVIKtqCCcMOJlTUdk%3D" rel="nofollow">countly</a> 等等,在此不作赘述。</p>
<p>总结一下,一个 RN App 架构应该要保证 App 的运行稳定以及开发的便捷。运行稳定这一方面,除了从 JS 层面(如单元测试,JS 错误上报等)保证之外,很大程度上还要依赖于原生层面的处理,所以团队里面要有同学的精力可以投在原生研究上面,至于开发便捷,我们尽量将复杂重要或者简单繁琐的操作在构建工程时就做掉,这样也可以大幅度提高我们的开发效率,降低开发者之间的合作沟通成本。</p>
<p><a></a></p>
<h5>4. 效率协同工具如何打造</h5>
<p>效率协同往往不分家,效率宽泛一点,就是又快又好,协同宽泛一点,就是顺滑无内耗,而且效率协同在不同的场景下,一定有不同的表现,所以效率协同一定要具体到某一个场景才有意义,比如:</p>
<p>我们要发布 6 款 RN App 中的若干款,在一周内的若干天发布,由若干人自行打包测试自行发布,那么这里面就有巨大的协同问题,同时还有一些效率问题,如果一个同学进来改了 3 行接口调用代码,他至少要有这几个阶段:</p>
<ul>
<li>开发阶段本机切新分支调试</li>
<li>测试阶段打一个连接测试环境的包测试有效性</li>
<li>测试完再打一个连接正式环境的本地包测正确性</li>
<li>最后再打一个连接正式环境的用来热更新的包进行发布</li>
</ul>
<p>那么多人之间都各自来做这个发布,就会出现一些发布冲突的协同问题,如果把发布权限全回收到某一个人,协同貌似能解决,但是会带来效率问题,大家要让这个发布人频繁打包,或者打好的包,反复传给发布人,发布人的时间线就被他人的开发进程给打断了,变成了一个打包员,关于这个我专门做了一张图:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1525411608024-527ad7a0-2767-4132-91ac-5da2cec086ae.png#align=left&display=inline&height=523&originHeight=1160&originWidth=1658&status=done&style=none&width=747" alt="" title=""></p>
<p>这里面的一个圆点,就代表一个编译后的包,比如 A 打出来的不需要 Debug 的连接正式环境的需要热更新的 iOS 的 ipa 包,那么 A 的这个包,跟 B 打出来的不需要 Debug 的连接正式环境的需要热更新的 iOS 的 ipa 包,即便是在同一个仓库的同一个分支,也不能保证 100% 一模一样的包,原因在于,这些本地打的包,还会受到 Node/NPM 版本(语义化),XCode 版本,原生热更新版本控制等等因素影响,导致这个包自身很容易出问题,甚至是一些人肉引发的分支和人工上传等等的影响,也会导致这个包发布出问题,举一个我们真实发生过的故障,A 打完包,把包文件钉钉传给 B,B 在发布的时候,选择本地文件时候选错了一个老版本直接发布上线,导致线上部分用户直接版本回退,我们后来不得已采用紧急回滚,才把影响范围控制住。</p>
<p>上面大篇幅的介绍打包的这个场景,是小菜前端早期非常痛苦的一个场景,协同方式和规范无论我们如何三令五申总是避免不了人肉的问题,一旦出问题,就是大问题大故障,那么这时候,就必须投入基建的力量来打造一款或者一套流程工具,通过工具一劳永逸的解决这些主要的协同问题,把琐碎人肉的事情交给机器去做,机器比人做的快,也比人做的好。</p>
<p>我们来总结一下,团队跑一段时间,一定会挤压一些问题,这些问题不可以视而不见,也不可以拿业务支持第一这样的借口来无限期推迟解决问题,而是时不时评估一下,有没有可能通过系统和工具,来约束一些行为,来取代一些人肉工作,进而可以一劳永逸的解决掉一些问题,一旦决定去解决了,那么如何打造协同工具就变得顺水推舟了,因为工程师最擅长的干的事情之一,就是造轮子造工具。</p>
<p>小菜前端造了哪些轮子哪些工具呢,文章最开始就已经列出来了,这里再陈述和解释一下:</p>
<ul>
<li>大伯伯(谐音打包包) 解决人肉打包带来的协同问题</li>
<li>大表姐(代号 Laurence - 来自饥饿游戏) 解决人肉发布、人工维护版本,问题追溯定位的效率问题</li>
<li>姑奶奶 解决去多个三方平台查看异常日志和 Bug 反馈指派的人肉效率问题</li>
<li>大舅子 解决前后端耦合在 Restful/Mock/冗余的接口 的合作效率问题</li>
<li>RGB 解决纯数字报表分析页面访问数据和用户行为的效率问题</li>
<li>堂哥工作台 解决组员与 Leader 日报周报难回忆带来的书写效率和后期回顾问题</li>
<li>小菜图书馆 解决小菜书架上面借书还书靠人肉记录维护的效率问题</li>
<li>...</li>
</ul>
<p>其中的大舅子这个单独拿出来说一下,现在前后端常见的合作方式是基于 restful API 的接口合作,前后端经过一轮接口评审,后端再为前端写 Mock 数据,可能还会加上一个 Proxy 服务,最终前端本地的页面上,做 Mock 环境、测试环境和正式环境的切换,这种方式最大的问题有 2 个:</p>
<ul>
<li>前端比较依赖于后端的接口定义,后端为前端 Mock 做完后,前端才方便的进行页面中的数据替换和逻辑判断,有等待成本</li>
<li>前端复杂多变的页面会影响到后端的接口复杂度和体积,页面上的字段增减,都会反映到接口的字段增减,接口本身变得不稳定,会带来很多隐患点,比如接口体积越来越臃肿,或者接口有多个版本,一旦接口文档更新没跟上,会导致后期的同一个接口的不同版本之间,增加调用出错概率等等</li>
</ul>
<p>当然业界也有各种各样规避这些问题的策略,可能是文档建设,可能是流程约束,小菜早期,哪怕到现在,也是在使用这种方式合作的,直到现在我们有了大舅子,前后端合作的方式开始进化,大舅子系统架构图如下:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1527817993898-647eb047-03cf-4747-99b4-f31eb6bf2b00.png#align=left&display=inline&height=429&originHeight=927&originWidth=1616&status=done&style=none&width=747" alt="" title=""></p>
<p>大舅子目前的架构是放到网关下面,网关层做一些鉴权和安全的处理,向下把一个 GraphQL 的请求转发给大舅子,大舅子上面根据这个 Query Type 对应的 Resolver 去调用下层的服务接口,下层可能是另外一个 GraphQL 服务,也可能是微服务,也可能是数据库,兼容度很高,无论是哪一种,大舅子的角色扮演就是配置和聚合:配置客户端上页面对应的数据类型,嵌套关系和数据结构,向下连接和聚合不同的数据源。</p>
<p>内部的开发正式环境关系图如下:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1527818051969-24d27b30-4b7f-4221-a436-9a47a0bc171d.png#align=left&display=inline&height=636&originHeight=1080&originWidth=1268&status=done&style=none&width=747" alt="" title=""></p>
<p>这个事情并不新鲜,多年前,Nodejs 就在扮演数据聚合层的角色,把多个 API 聚合成一个 API,或者打散一些 API,聚合成新的 API,但本质上依然是向客户端提供 API,这种 API 依然是面向页面,可以看做是页面驱动的 API,大舅子因为整个建模基础是 GraphQL,所以页面和数据结合的权利,交给了客户端自己去做,它需要什么数据,就在客户端声明什么数据结构,带来的好处很多,这里列举两条我认为有价值的:</p>
<ul>
<li>前端可以不再局限于接口评审阶段,可以继续往前提到数据库/表结构评审阶段进入开发流程,在表结构评审期就能拿到字段定义与含义,从而再大舅子上提前定义前端自己的 Type 和 Resolver</li>
<li>后端不再耽误自己的时间为前端提供 Mock,也不再受页面 API 的约束,可以下沉精力专心做下层业务领域能努力的建设,下沉的领域能力多大,那么端上可使用和组合的能力就有多大</li>
</ul>
<p>从此,尘归尘,土归土,前后因为页面数据控制权的分离而解耦,也因为数据能力的回收而同时贴近业务,前端也被倒逼去了解业务,不再仅仅是界面和产品交互驱动,现在大舅子还在早期的迭代阶段,关于它的好处和优化的空间还非常非常大,今天不做深入讨论,我们来总结一下:</p>
<p>小菜前端已经从工具基建中受益,因为工具带来了协同和效率的优化只是结果之一,最重要的收获还有两个:</p>
<ul>
<li>解放了小菜前端团队以及技术团队的人肉时间,可以有精力做其他事情</li>
<li>通过基建工具研发培养了小菜前端分析问题和解决问题的能力,同时沉淀了一些不错的技术方案</li>
</ul>
<p>那么小菜的成长和沉淀,我们接下来就可以来总结一下了。</p>
<p><a></a></p>
<h3>四、技术成长和沉淀</h3>
<p>技术成长就是工程师的能力变化,我在 4 月份给大家做了一个 10 个月前后的能力评估,这 10 个月,是小菜前端 3 年来基建密度和团队内调整最大的几个月,也是团队整体战斗力提升最大的几个月,本文的所有分析、策略和实际的解决办法,也都是在这几个月里面进行实施的,挑了几个同学,挑了几个主要的能力维度,我们感受下他们的技术成长,白色的 * 代表 10 个月之前的能力值,2 颗星代表可以熟练的开发,三颗星代表基本精通或擅长,四颗星是比较精通。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1525415185719-d923f471-39a7-4f7c-9970-d76e8b3a3886.png#align=left&display=inline&height=343&originHeight=832&originWidth=1814&status=done&style=none&width=747" alt="" title=""></p>
<p>可以看到每个人都有不同程度不同层面的成长,有的全面开花,有的某些领域内快速积累,也要同学技术成长不多,但是协作能力工程能力有很大提升,其实还少了一个维度,就是参与业务拿到的结果或者说业务能力,图上放不下了,稍后会做分析和补充,我们再来看下这些同学做的事情:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1525415536480-e57c2ab2-4c21-47f5-8bd5-15723be9270d.png#align=left&display=inline&height=420&originHeight=998&originWidth=1776&status=done&style=none&width=747" alt="" title=""></p>
<p>如果仔细比照一下,我们很容易得出三个结论:</p>
<ul>
<li>整个技术团队综合技术能力有大幅度的提升</li>
<li>承担职责越多的同学能力成长越多越快(如组员 A)</li>
<li>承担繁重基建和工具开发的同学比承担业务开发的同学技术成长更多(如组员 E)</li>
</ul>
<p>业务能力没有放到图上,这是要补充的第四个结论</p>
<ul><li>承担业务越多的同学,项目管理能力/沟通能力/业务理解能力也越好</li></ul>
<p>以上是人才成长,那么沉淀下来的内容一共是三部分:</p>
<ul>
<li>通用的工具技术解决方案</li>
<li>通用的技术模块和业务组件库</li>
<li>团队整体的问题解决套路(分析解决问题的思维方式)</li>
</ul>
<p>通用的技术解决方案可以不断的快速复用,比如我们宋小福用新架构前后调整优化有 1 个月,把这同一套架构放到麦大蔬上 2 周就够了,再次迁移到新项目宋大仓里面只需要 1 周就搞定了。</p>
<p>通用的技术模块和业务组件库,则是我们的组件三步走策略,首先是某个业务产品线下面的组件模板,比如 筛选组件或者列表组件,能在这个业务场景下的产品形态中通用,如果它可以跨产品线,那么就会跃升为 App 内通用组件,如果它还能继续抽象具有可重用性,那么就可以跃升为跨 App 的通用业务组件,比如热更新组件,地理位置定位组件,登录组件,异常提示弹窗组件等等。</p>
<p>团队整体的问题解决套路,这个是我们最大的收获,再直白一点,就是如何更快更好更有创造性的做事,这种思维方式,解决问题的套路,本质上是可以在团队内不断传承的,无论我们后面遇到什么样的业务和团队问题,我们用这一套场景-技术-长短期投入产出比评估的路子,都能用较轻的方式把问题解决掉,这个对于我们培养新人有很大的帮助。</p>
<p><a></a></p>
<h3>五、对未来的展望</h3>
<p>小菜三年走过来,前端团队从早期的技术和人员不稳定,到现在趋于稳定,站在公司的角度,最大的收获就是培养和磨炼了一批有创业热情,有担当勇气,有技术底蕴的一群人,这一群人抱团在一起,可以在所谓大前端这个框框内玩出更多的花样,支持到更多的业务场景。</p>
<p>站在今天看明天,虽然有很多东西对我们来说依然是未知的,但我们不再像过去一样临场发怯,手忙脚乱,取而代之的是无论多大多难的业务类型,我们都可以坐下来利用这帮人的智慧汇聚出一个最优选择,胸有成竹的去做技术探索和工程尝试,在跟公司一起成长变大的过程中,站在今天看明天,虽然有很多东西对我们来说依然是未知的,但我们不再像过去一样临场发怯,手忙脚乱,取而代之的是无论多大多难的业务类型,我们都可以坐下来利用这帮人的智慧汇聚出一个最优选择,胸有成竹的去做技术探索和工程尝试,在跟公司一起成长变大的过程中,小菜前端也一定会沉淀出来更有实践价值,更有效率的技术方案,而这些就是我们将来可推广复用的宝贵技术资产,当然除了宝贵的技术资产,最最最重要的还有我们这群人,可以开心有趣有挑战性的 Coding,想进一步了解我们团队的可以<a href="https://link.segmentfault.com/?enc=gr7gcsq3KpVWOtAz3OeTzw%3D%3D.P9m6KmIWNoi28zxghZU3WZgomrFq8h51kbbk2S1PajVGLg7PTRhIFRjRV3D6AwR8%2FS5JteIVd7QUwB5FbWMuIg%3D%3D" rel="nofollow">移步这里</a>。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=3jE9gdSHAmN%2FflooE7258Q%3D%3D.NmwrtpmkoroiQCGinbUE3qlKKwiGrbKvm2TQD8dNY2k%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
第一届 GraphQLParty 首场工程实践图文版
https://segmentfault.com/a/1190000022294052
2020-04-07T23:00:00+08:00
2020-04-07T23:00:00+08:00
Scott
https://segmentfault.com/u/codingdream
6
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott:各位大牛,大神,大咖大家下午好,我是 Scott,也是这次杭州第一届 GraphQLParty 的发起人。先回到会议的主题,为什么会开这么一个会议?原本这个会议报名的时候希望可以控制到 100 人之内,不要超过 120 人,结果报到 250 人还爆满了。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033138192-92245f29-0087-444c-bdf5-4943c9970677.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033083069-66f9d2fd-01c5-46d3-a3d5-7180a66a2713.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>后来没有办法,我们只能从工作经验来筛选,选择工作经验在三年以上的比较资深的工程师,和一部分 2 年经验工作经验的,还有 5 年的,10 年甚至更久的从业者。</p>
<p>那现场我调查一下哈,大家有了解过领域驱动的同学请举一下手好么(观众互动),不到十个人,那大家在工作中使用 GraphQL 的同学举一下手好么(观众互动),也是十个人不到的样子,这就是为什么要办这个会议(观众大笑)。</p>
<p>起因是这样的,我们当时想要去尝试 GraphQL 的时候,发现国内的文档,社区,会议等等关于 GraphQL 的资源都特别少,很匮乏,没有地方可以去沟通,可以去交流,后来我们只能找自己同行业的朋友去沟通发现大家其实都感觉交流匮乏,我们最后把这条路的坑都踩过了之后,觉得是不是可以自己总结的一些东西,可以单独拿出来跟大家分享。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033206830-bc29c004-3dc3-4a74-b29f-b2e5d649cf4d.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>在过去不到一年,大概十个月左右的时间里我们团队用 GraphQL 实践了一些产品,发现自己确实从中受益了,觉得说这个经验的确是可以拿出来跟大家来探讨的。</p>
<p>再回到大会的主题,有这么几个关键词,一个是协同,一个是效率,领域驱动是单独的 1 Part,然后还有前后端职能变化。其实这也是我自己感受最深几个词,一个技术带来的价值不仅仅是开发效率本身的提升,可能还会带来额外的价值,这些额外的价值可能是协同或者是前后端职能的变化。这也是为什么会去举办 GraphQLParty,以及定这个主题的原因,因为无论是 GraphQL 还是领域驱动,包括他们结合后的价值,这个话题在国内目前没有一家公司真正拿出来去讲,我们觉得自己可以第一个来吃这个螃蟹,然后和大家一起去推动这个事情。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033179059-3a3fa659-14b3-4268-bdc3-6ac2222908ae.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>今天下午一共有五场分享,有前端后端的分享,也有比较方法论的,当然会有干货湿货,我们能对讲师的要求呢,就是不要讲太高大上的东西,尽量讲比较接地气的东西。同时我们不知道行业水准怎么样,我们会先把自己做的东西,无论水平如何,都拿出来给大家看看。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033318836-4ab293a0-96b2-4181-8d72-377a60acd6a6.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>然后我们这里有一些问题列了出来,这个在我们开始报名活动开放时候就已经公布出来了。今天下午大家可能会对讲师的演讲内容产生不同的疑问,你的问题可能是这里面某一个,也可能不在这个里面,但没有关系,如果你想了解 GraphQL,了解领域驱动,可能这里面都会有一些问题是你躲不过的。</p>
<p>大家可以带着问题听今天下午的五场分享,但能否拿到答案现在也不好说,但最终大家一定会有自己的判断。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033304325-9ff48292-553e-481e-a6ff-0db917dca307.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>当所有问题全部解决掉之后,对我们在场的资深从业者来说可能还会面临一个终极问题,那就是假如说今天,你们讲师们啊,都讲的都有道理,我想去用打算去推动,那么会给我的团队带来哪些收益,又会遇到哪些技术上的挑战,遇到哪些坑。技术挑战和遇到的坑一会儿由我的搭档来为大家介绍,我先为大家讲一下宋小菜自己有了多大的收益,来举一些案例。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033293775-9b6a9705-9f0a-4ad3-a9f0-30fd37a139ef.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>关于案例呢,先来了解一下我们的产品背景,毕竟技术不能脱离场景,宋小菜 10 个前端工程师,其实不到 10 个,大概是 7 个,是最近几个月才招到了几个,我们一共开发和维护了 6 款 APP,1 款小程序,1 个复杂的 ERP 系统,市 调系统,报表系统等等。这看起来像是一个大团队做的事情,但其实我们最多只有十个前端来负责。那这里面就会有很多问题,比如说 APP 与 APP 之间,人与人之间的合作,我们之前使用版本不稳定的 RN,踩了很多坑,这个开发和协作成本太高,必须造轮子,或者用轮子优化开发效率,所以针对前端团队内部做了很多事情,就像 PC 端一样需要解决资源上线、打包问题、编译、版本、缓存等很多问题,我们也不例外,差不多这些就是 7 个人陆陆续续开发的内部工具,所解决的特定的问题。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033347158-72bfea59-5a1f-4146-8483-38d92a1df78e.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>举个例子:大伯伯推包系统,所解决的问题是在我们需要发布 APP 包的时候,如果一个人打的包,钉钉上传给那个小伙伴,他去上传的包有可能就会出错,而且这种故障有发生过,这种场景可能靠人肉是解决不掉的,所以我们开发大伯伯推包系统,让机器对接机器,通过机器去做这件事情,这里面有大伯伯,大表姐,大瓜子,为什么取这个名字,是因为我们希望产品能尽量接地气,再加上谐音,比如打包叫做大(打)伯(包)伯(包)。</p>
<p>刚才这么多问题解决掉以后,我们发现还是不行,前端团队内部效率啊,配合成本确实降下来了,但是发现团队之间的成本还降不下来,比如有这三个比较典型的问题是我们逃不过去的,并且跟前后端关系都很大。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033383671-f1ec3af2-77fa-44ff-9c80-e8a900fbe648.png#align=left&display=inline&height=1080&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>第一个是多端之间的类报表同步,大家现在开发前端,可能开发小程序,APP,PC,会有多端,对我们公司场景来说我们这个端比较杂,可能要在 ERP 要透出报表,在 App 上透出报表,在小程序上透出报表,但是面对不同权限的人报表透出的维度不一样,但本质上下面的数据源是同一份,那我们就可能开发很多个接口去对应不同的 APP,那这个问题靠前端是解决不了的。</p>
<p>第二个是多端之间多模块共享,这个模块不太准确,我解释一下,意思大概是比如有一个用户模块,一个订单模块、一个物流模块,每个模块里面可能会有一两个组件来组成,不一定是什么组件,但向下所需要的基本数据可能还是同一份或者同两份,只是在不同端上的 UI 呈现不一样。那我们想要让这些模块之间去共享数据很难,我们在不同端上开发一个组件就绑定一个接口,这个组件拿到另外一个里面去,套到那个模块去用的时候发现行不通了,这也是一个很大的成本。</p>
<p>第三个是业务变化快,产品总要升级迭代,难免 UI 设计师要找活给你干,要改版的时候,加一个字段,减一个字段,或者叠加几个字段,那么接口又要升级,或者加一个新接口,这个同样导致合作成本很高。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033404080-63565166-f05f-428d-8220-db447658a418.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>为什么会这样?是因为我们都知道啊,基本上行业内通用一个开发流程是这样的,可能大家的团队比我图示上显示的长一些,短一些都没有关系,但大家跳不过的是这几个环节,来看红色的几个,系统设计,里面涉及到 Java 服务端工程怎么搭建、骨架怎么搭建、服务怎么拆分,最后具象的时候,是服务端同学设计这个数据库和表结构,这几张表上面的字段有哪些。然后接口设计,服务端同学会给出接口的文档,比如说会给你提供五个接口,每个接口 15 个字段,才会进入到前后端对接完之后,再帮你去做一份 Mock 数据,然后前端在页面上把页面样式重构之后,再去调假的 Mock 数据,然后页面交互流程调通之后再切到正式接口,大概是这个套路。这里面有很多工具栈,很多第三方开源的工具可以用,那我们发现这里面前后端堵塞在这个点,而且堵塞很多年也解决不掉,因为接口设计控制权在服务端手里,前端不知道会给到多少接口,然后在接口评审时候,15 分钟或者一个小时,前端基本上很难理解哪个字段背后的业务含义,过后还要和服务同学反复再沟通确认,就因为在这个点的堵塞导致上面三个问题不是很好解决。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033414481-a2a3f15d-a24a-410a-bff7-5039398e7a05.png#align=left&display=inline&height=1080&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>把三个问题再抽象一下,其实就是这三个:第一个是 API 的设计,服务端同学有的时候会被迫也好,被 “强奸” 也好,我必须要面向你多变的 UI 去做 API 的设计,面向这些页面服务,页面变化的时候,API 可能也要升级。第二个是 Mock 职责重合,之前也知道业界很多公司自己做了 Mock 工具和平台,我们一直也是在使用第三方的,有时候是前后端共同维护同一份 Mock 接口,有的时候是服务端去维护,但是总之要存在一个协作成本,到底谁来对它负责,这件事情,到现在也说不清楚。服务端同学给你做完 Mock 之后终于可以沉下心来做底层的业务开发,但发现临时需要调整一个字段,就把接口调整了,但是忘记去更新 Mock 文档,前端不知道这个事情,到后面俩人一对接发现字段对不上,这就是一个典型的工作流协作问题。还有一个问题,这个对于 toB 公司,或者 toC 也有这样的场景,就是报表,报表可能是一个刚需,对于管理层其实需要看到过去一周一个月公司交易的整个规模、吨位、物流情况、库存情况,不同维度的数据观测。业务打法一变报表的维度也要变,传统的报表开发就前后端各一个,服务端搞定数据库,跨表跨库查询,给出标准的字段结构,前端就是把它套到 Table 表格里面去,这个事情很简单,但是可能要排期,一天两天三天,可能产出报表的速度就很有限了。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033442693-d5ebd8a1-e88d-44b2-8010-d324e55b5964.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>针对刚才的问题,我们先把宋小菜在自己的业务场景下,技术的解决方案拿出来给大家看一下。我们现在解决方案是在网关这一层,集成 GraphQL 的一个聚合服务,第二场架构师会来讲具体架构图,这边单独讲这一个点。我们理想中的 GraphQL 接入方式,是跟网关同层嵌入在里面做一个管道,但是现在我们的实现方式呢,考虑到快速跑通,暂时把它放在网关的下面,是为它的鉴权跟安全不想占太多开发成本,把它交给网关去做了,所以它就只做数据聚合这么一件事情。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033454126-adc0bb5f-8a9e-43cc-9fd2-a960d20223a3.png#align=left&display=inline&height=1080&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>那么通过系统改造,我们开始回答之前的问题,那就是收益有什么?2016 年 2017 年差不多 2 年多时间为了整个公司开发的报表一共 50 张报表,总的开发时间没有详细计算,但是这并不代表说整个公司只需要看这 50 张就够了,而是因为我们只有这么多人力开发这 50 张,报表开发成为一个瓶颈,当我们通过 GraphQL 在端上透出以后,包括服务端去一些拼装的动作,现在提供了可视化报表编辑的系统,这个系统面向产品经理和运营,面向服务端工程师,他们通过可视化的界面配置一下,报表就生成了。</p>
<p>这个系统上线以后四个月就产出 200 多张报表,把整个公司报表需求全部消化掉了。现在的情况是,产品经理跟业务方开会,业务方说:我需要看一下某个服务站一周的报表数据,我要提需求,我需要这个指标这个指标。然后会还没开完,产品经理就把报表做完直接上线了,现在报表产出就是这么一个节奏。通过做这个系统我们发现 GraphQL 可以给我们带来很大方便,我们就继续往下挖,把 GraphQL 它的价值从 APP 端继续往下沉,沉到服务端,我们就做了大舅子,前面的报表系统是大(搭)表(表)哥(格),是搭 Excel 表格的一个谐音,这边是大舅子,公司的产品啊,他们都是亲戚。</p>
<p>大舅子是我们今天分享的主题,刚才那个 GraphQL 的聚合服务叫大舅子,这个到现在为止实践不到 3 个月时间,跑了一些项目,目前评测下来可以节约的人力是这样,如果一个小日常小项目需要前端后端共同开发 4 天,我们可以把成本降到 3 天,那这是单个人的状况,如果人更多的时候,多人对接成本的提升通过这个系统的表现会更加的明显。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033497883-d7c336bb-d214-484d-8a21-3c9a032a7db6.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>上面是从业务结果拿到的收益,除了这个收益之外还有别的收益。就会涉及到今天另外一个关键词 - 前后端的职能变化。大家心目中的前端跟服务端我不知道是怎么样的,我就说下我们现在朝着一个方向走是这样子的,前端对于页面上的数据有一定的控制权,我需要什么样的数据只有我自己知道,因为我需要对数据有控制权,要更快去输出页面,包括去走通一些业务流程,点了什么按纽,触发什么事件,就必须去理解每一个字段背后的业务含义,我要去理解每个字段背后的业务含义,就必须去理解业务。以前会说我只需要 UI,理解交互,理解产品就好了,业务我不管,反正给我们什么字段就用什么字段,我们去消费数据。现在对前端的挑战在这里,我要负责的事情有一些变化。对于服务端来说,反而很爽,因为我终于不用再面向多变的页面去设计 API,我从里面解放出来了。</p>
<p>那么解放出来之后会带来两个问题:</p>
<p>第一个问题是解放出来的时间用来做什么?<br>第二个问题是如果前端介入到这一层,你们还会对我(服务端)提什么要求?</p>
<p>对于第一个问题,既然有精力时间,我可以把胶水代码都拿掉,把 Mock 的时间,粘合数据的时间省下来去做底层的服务设计,提供更稳定的数据服务,反过来前端也会希望说服务端同学提供的接口也好,不同的领域设计也好,给我趋于稳定的设计,而不要给我多变的设计,不要因为每一次前端页面改版研发而引发后端服务改动的大地震,这是前后端的一个变化。</p>
<p>那我们到底怎么通过代码通过工程的方式拿到这个收益呢,接下来由我的同事陈锦辉跟大家去做具体的工程上的分享,掌声欢迎陈锦辉。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033546970-d586ef7e-656c-4567-87b0-0aea24272049.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>陈锦辉:大家好,我是宋小菜的前端工程师陈锦辉,刚刚 Scott 给大家讲了一下宋小菜在一段时间内实践了 GraphQL 的结果以及我们搭建基于 GraphQL 的数据聚合系统——大舅子,这是 Scott 的七大姑八大舅系统里的一个成员。这里简单介绍一下我要讲的主要内容,关于什么是 GraphQL,我会开始先做一个科普,后面演示一下现在正在试用这么一个系统,最后有哪些坑需要去踩,最后再针对 GraphQL 开开脑洞。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033638566-f3086d87-b34a-413b-8ea9-d329978c08ad.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>最开始先看一下大舅子的这个数据聚合系统,在我们整个系统架构里面到底处于哪一个位置。从图示中可以看出它处于我们的网关和后端数据服务的中间,刚刚 Scott 也解释过,我们网关本身已经存在了,所以它已经把如鉴权和安全一类的事情做掉了,所以我们在做数据聚合服务的时候,将这个服务放到网关后面。为什么取名叫 GPM,它全称叫 GraphQL Pipe Manager,这是对一个对后端服务提供的数据提供数据拼装的这么一个系统。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033688584-b331c0e8-2f95-43e7-905f-4210419800a6.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>这是我们整个 GPM 内部架构大概一个结构图,分成两部分:一部分是正式的服务,可以看到正式的服务比较简单,因为要保证提供正式数据服务稳定,所以我们尽量简化它。另一部分稍微复杂一些的,是开发服务,在开发服务里面我们可以对类型进行编辑管理,然后在开发服务上进行测试,最后应用到我们的正式数据服务上。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033706006-849247e3-27a1-4d7c-981a-6ee8d70d0333.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>介绍完我们使用 GraphQL 的大致情况后,鉴于在场的部分同学之前可能没有接触过 GraphQL,所以我先来介绍一下什么是 GraphQL,GraphQL 全称叫 Graph Query Language,官方宣传语是“为你的 API 量身定制的查询语言”,用传统的方式来解释就是:相当于将你所有后端 API 组成的集合看成一个数据库,用户终端发送一个查询语句,你的 GraphQL 服务解析这条语句并通过一系列规则从你的“ API 数据库”里面将查询的数据结果返回给终端,而 GraphQL 就相当于这个系统的一个查询语言,像 SQL 之于 MySQL 一样。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033725334-d450a247-354f-4815-938f-29e9a312367f.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>宋小菜经过一个时间不是很长的实践,发现使用 GraphQL 给我们带来五点的比较方便的地方:一个是单一入口,第二个是文档的展示和编写,第三个也是比较有特色一点,就是数据冗余可以使用 GraphQL 来避免,第四点数据聚合是这一个系统本身最主要的职能,还有最后一点就是数据 Mock,Mock 相当于比较棒的附加值。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033752813-ec43a1e2-f1d9-41da-be4d-bbd722408546.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033793895-d0bd1b14-d5b4-4edc-babf-51fa52151375.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>首先说一下单一的入口这一点。传统的 RESTful API 里,不管前端还是后端都要对 API 做管理,一是版本管理,二是路径管理,非常麻烦,增加了工程管理的复杂度。但是如果使用 GraphQL,只需要一个入口就可以了。刚刚也说到 GraphQL 相当于一个数据库,它的入口只有一个,我们只需要访问这个入口,将我们要查询的语句发送给这个入口,就可以拿到相应的数据,所以说它是一个单端点+多样化查询方式的这么一个结构。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033832467-c16f4647-05d8-4804-a996-08758b675dcf.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529033996370-b7477ca1-ab18-4bdd-bf46-a9671c586afd.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>第二点是文档,这里文档虽然不能完全替代传统的文档,但是它能在一定程度上方便我们。传统的 RESTful API 文档管理,市面上有很多工具,像 Swagger、阿里开源的 RAP 以及 showdoc 等。但使用这些 API 文档管理工具的时候其实是有一定的学习成本的。像 Swagger, 可能对于老手来说使用起来不是很复杂,但是对于刚上手的开发者来说上手还是需要一点时间的。然后还有在使用这些平台的时候都会遇到让人头痛的“ API 和文档同步”的问题,很多时候需要自己去做 API 和文档同步的插件来解决。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034022605-f7e47d72-b26d-4602-a2c6-aa3f6fc5f47d.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>如果使用 GraphQL 就可以在一定程度上解决 API 文档的一些问题:在做 GraphQL 类型定义的时候我们可以对类型以及类型的属性增加描述 (description) , 这相当于是对类型做注释,当类型被编译以后就可以在相应的工具上面看到我们编辑的类型详情了,像示例的这一个类型 Article,它的描述是 “文章” ,它的属性有哪些,有什么含义,都会展示在大家面前,只要我们在开发的时候规范编写类型,整个文档的展示就比较规范了。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034037288-00127119-e862-4b95-aac8-3c75c8d897dd.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>使用 GraphQL 还有一个比较棒的功能,就是每一个 GraphQL 类型 其实相当于 mongo 里面的一个 collection,或者 mongoose 里面的 Model, 而每一个类型之间关系也可以用工具很形象的表现出来。像系统上用到这么一个模型,它对应到哪些和它有关系的模型都高亮出来了。</p>
<p>链接: <a href="https://link.segmentfault.com/?enc=tl%2F9TP6piT83ehOyLPcL6w%3D%3D.UFJ1F9vew0XVjNusmmdSyFx7lca92GI8CVo4EPldzhUCdodzBlDu5HJ4Cf%2FKY9qF" rel="nofollow">https://apis.guru/graphql-voyager/</a></p>
<p>这里演示一下,可以传送看一下,在 Github API 4.0 开放出的 GraphQL API,它将 Github 所有的对外类型都暴露出来了。可以看到每一个类型对应的定义和解释都在左面有显示出来。每一个类型都有对应的 UML 图展示,这是一个比较大并且比较复杂的 UML 关系图。我们主要平时用到一个核心的类型其实就是仓库 (repository) 类型,我们可以看到这个类型比较复杂,同时它也是比较核心的,和它有所关联的类型就非常的多,仓库类型下还有 issue 这个属性。如果我们参考 Github 开放的 API 4.0,就可以做到在 Github上面开发相关的插件。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034091702-18a5d434-5902-4916-9bf2-7321d9d3bee6.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034102950-d1da3e8a-0a90-42c2-8fc3-cdf75c598839.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>使用 GraphQL 的第三点好处就是可以避免数据冗余。我们在传统的 RESTful 处理冗余的数据字段大约有这么三种处理方式:</p>
<ul>
<li>一是前端选择要不要展示这些字段;</li>
<li>二是要么做一个中间层(BFF)去筛选这些字段,然后再返回终端来展示出来;</li>
<li>三则比较传统也比较麻烦,还不一定能生效,就是前端和后端去做约定,如果说这一个接口这一个字段已经不要,可以和后端商量一下把这个删掉,但是有一种情况可能造成冗余字段删不掉的,那就是后端的同学做这个接口可能是“万能接口”,也就是说这个接口在这个页面会用,在另外一个页面也能用,在这个应用会用,在另外一个应用也可能会用,多端之间存在部分数据共享,后端同学为了方便可能会写这么一个“万能”的接口来应付这种情况,久而久之,发现字段冗余到很多了,但是随便删除又可能会影响到很多地方,导致这个接口大而不能动,所以前后端都不得不忍受它。</li>
</ul>
<p>但如果使用 GraphQL,就可以避免接口字段冗余这个问题,使用 GraphQL 的话,前端可以自己决定自己想要的返回的数据结构。刚刚我也解释过,GraphQL 实际上是一种查询语言,我们在使用时就像是在数据库里面查询数据一样,查询的某一个数据要哪些字段可以在查询语句里写好,要哪些字段就返回给我们哪些字段。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034144084-4d86b4ef-7f52-4878-8e6f-c498d3f3552b.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>拿 PPT 上这个作为示例:我们要去拿 id 为 1 的文章,如果我只要 id 和 content,我在 query 里面指定这两个字段,那么返回的就是 id 和 content,如果除了 id 和 content 之外,我还要拿需要作者信息的时候,我只需要在 query 里面指定 author , GraphQL 就将作者的信息给返回回来。这样就能做到前端决定自己想要什么结构的数据返回的就是什么样的数据。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034155400-685f74d2-6cf1-4ec8-9398-118d808534f5.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034165254-4aa6f89e-09e5-4077-a8a8-91a523740e05.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>最重要一点当然是数据聚合,数据聚合在使用传统的 RESTful 的方式时有多种解决方案:</p>
<p>一种前端发针对这个页面上的多数据源单独发起数据请求,然后一一展示出来,这样可能会出现页面数据加载不同步的情况。<br>第二种就是开发做数据拼装的中间层(BFF),用于拼装后端提供的数据,然后返回给前端。<br>还有一种是宋小菜在最前期的使用一种方案,那就是后端同学编写针对页面的 API,即所谓胶水代码,来拼接各个服务的数据,返回给前端。</p>
<p>如果是第三种情况的话,就会有大量的工程需要我们去维护,大量的 API 需要我们去维护。但如果使用 GraphQL 的话,这些问题都不会存在,因为它是天生支持数据拼装的。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034193039-fef22b4e-66c7-4977-92ea-e6ff78a4cea4.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&style=none&width=747" alt="" title=""></p>
<p>为什么它是天生支持数据拼装的呢?我来尝试着从 GraphQL 执行的原理上大概解释一下。这是个GraphQL 执行的大致流程,第一步我们去验证需要去执行 GraphQL 的标准,同时去验证将要去查询语句的合法性,第二步生成执行的上下文,关键点在第三步和第四步,第三步是获取查询语句所需要查询的字段,这里叫 fields,所有需要查询的字段可以在查询语句里通过算法拿到,这里可以解释刚刚提到的 GraphQL 怎么做到避免返回数据的冗余的。拿到所有需要查询的字段后,第四步针对每一个字段去执行它的 resolver,可以从 resolver 返回数据里面拿到字段对应的数据,最后是格式化结果并返回。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034209699-2ac66e2e-fff8-4464-bf06-c4566b76ef43.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034222290-f5e7b617-9095-4949-8d28-80a29ea90445.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>第四步我解释一下,在GraphQL里面有一个类型的概念叫类型 (type),每一个类型下面对应的是一个或多个字段,每一个字段绑定了一个 resolver,这个 resolver 的作用就是获取字段对应的数据。对应到刚刚举的例子,比如 article 这个类型,它有四个字段: id,author,content,comment。每一个字段都对应的一个 resolver。而这个 resolver 其实是可以被开发者重新定义的,如果说没有定义的话 GraphQL 会给一个默认的 resolver,像Article 的 author 字段类型是 User , User 可以从用户服务里面去获取,所以我们可以将 author 这个字段 resolver 重新定义一下,通过 UserService 获取用户信息。下面的评论(comment)也一样,我们可以通过 CommentService 获取评论数据,这样可以做到在查询这个文章的时候既获取了文章本身的数据,也通过 UserService 和 CommentService 获取到了作者信息和评论信息,然后经过拼装返回给客户端,这样就达到了使用 GraphQL 进行数据拼接的目的。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034243823-5c822b90-2ccc-4373-8d64-2106f7e5c9d1.png#align=left&display=inline&height=1080&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>第五点是附加的一点,我们可以适当地利用 GraphQL 做数据 mock。那么使用 GraphQL 怎么去做到 mock 呢?</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034267938-3c25eae6-c6cc-4ee3-81a9-891a43b95654.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>GraphQL 的类型大致可以分为两种类型:</p>
<p>一种标量类型,像普通的开发语言一样,提供 Int,Float,String 这种标量类型,这种类型在 GraphQL 中也对用着一个 resolver,我们可以通过重新定义其 resolver 来做到对标量类型的 mock, 像 Int 返回的范围是什么,Float返回的范围是什么?String 返回的格式是什么样的?等。同时我们在开发中常用到的一些简单但是有一定规则的数据类型像手机号码、图片地址、身份证号码、身份证号码这样的数据我们也可以通过自定义标量类型来做到数据 mock。<br>第二种是普通类型,像刚刚示例中的文章(Article)类型,普通类型下面可能会有多个字段,每个字段对应的数据类型可能是普通类型也可能是标量类型,这种类型也可以做 mock,如果我们对标量类型做了适当的 mock 以后,像 Article 的 mock 数据就会自动生成。</p>
<p>使用 GraphQL 做数据 mock 还有一个方便之处在于经典 mock 数据可以被很方便地复用。如刚刚示例中查询 Article 下面类型为 User 的 字段 author 的时候可以利用这个特性,因为用户信息(User)这个类型不仅仅会用于文章的作者也可能会用于评论的作者,所以我们针对User 类型做一个 mock 数据,这个 mock 数据可以会在查询文章作者和查询评论作者中同时用到,同时我们也可以在返回 mock 数据时耍一些小花招,例如从几个用户数据中随机返回一个用户信息,或者根据查询条件返回对应的假数据等。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034298344-c462983c-e98a-47c9-b431-1832268a7501.png#align=left&display=inline&height=1080&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>使用 GraphQL 做数据 mock 有多方面的好处:</p>
<ul>
<li>好处之一就是 mock 数据随着类型 (type) 走,当我们修改类型以后,它的 mock 数据也是会被同步修改,不会出现 mock 数据和类型不同步的情况;</li>
<li>好处之二就是能很容易地实现 mock 数据的细粒度,原理刚刚也解释过了,这样能够很大提高我们的开发效率。</li>
<li>好处之三是 mock 数据可以复用,节约开发时间。</li>
<li>最后一点,那就是 mock 数据的职责可以由前后端共同承担。或者说由前端自己来做,因为通常情况下 mock 数据的消费者都是前端自己,为何不自产自销呢,省去大量的交流成本。</li>
</ul>
<p>这里简单做一个演示(现场是联网操作后台,这里仅插入部分截图示意),展示一下我们开发出来的还在试用期的一个 BFF 服务—— GPM,目前它的页面还比较简陋,还在还在试用阶段。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034411593-08d66ed2-fe48-45c6-a453-a89aa2776476.png#align=left&display=inline&height=399&originHeight=1510&originWidth=2824&status=done&style=none&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034486655-94b29d83-e055-49d5-a372-60970858f510.png#align=left&display=inline&height=448&originHeight=1420&originWidth=2368&status=done&style=none&width=747" alt="" title=""></p>
<p>在 GPM 中每一个生成类型都会以表单的形式展现出来,当然代码的形式也会有特定的地方呈现,我们只是对每一个类型都进行可视化,如果作为一个新人来使用,只需要点击按纽添加类型,指定类型名字,填写类型描述,根据类型的实际情况设置缓存有效时间,绑定到宋小菜的哪些 APP。然后针对已经添加好的类型可以对它做字段的添加的操作,指定字段的名字、类型、描述、缓存有效时间,以及 mock 数据。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034599736-0be76f54-ba33-4028-955c-71cce4fc1056.png#align=left&display=inline&height=418&originHeight=1596&originWidth=2854&status=done&style=none&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034782808-4d47a56d-0b07-423d-ad86-a062dd740556.png#align=left&display=inline&height=415&originHeight=792&originWidth=1427&status=done&style=none&width=747" alt="" title=""></p>
<p>同时这一个系统可以直接在线上测试并发布类型的:我们在编辑好一个类型以后,可以部署到开发环境上,然后在 IDE 里面做调试提前查看返回数据是否正确。像刚刚说到的处理数据字段冗余是怎么做的,这里可以演示一下,在前端不想要这一个字段时,直接在查询语句里面删掉然后执行查询就能拿到不包含这个字段的数据了。我们也可以通过 IDE 获取这个查询语句结果的 mock 数据。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034845341-dd42f8f0-5889-4900-87bb-d8cda30835a7.png#align=left&display=inline&height=414&originHeight=1584&originWidth=2856&status=done&width=747" alt="" title=""></p>
<p>在写查询语句的时候这个 IDE 根据我们已经生产的 schema 自动帮我们提示,就像使用普通的桌面 IDE 一样,而每一个类型的文档可以从右边的弹窗里面看到。GPM 将 IDE 分为了正式服务和测试服务的 IDE, 正式 IDE 时针对线上数据做查询的。我们在测试好了新增或者修改的类型以后就可以部署正式环境上了,不用重新发布 GPM 就可以做到。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034896013-8374e6a2-d1a8-41a8-8bf3-77ed4fb3d3bd.png#align=left&display=inline&height=416&originHeight=1590&originWidth=2852&status=done&width=747" alt="" title=""></p>
<p>这是刚刚提到文档展示,GPM 也集成进来了,可以看到这些类型有哪些,然后这些类型到底有什么含义,类型和类型之间的关系是什么样的,都可以在这里很方便的去查看。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529034949711-089f6ea1-a4d1-4517-a7bc-d8f1b0bca70e.png#align=left&display=inline&height=405&originHeight=1216&originWidth=2242&status=done&style=none&width=747" alt="" title=""></p>
<p>在 GPM 上我们还做了一些附加的功能,因为我们后端提供的微服务大多数是用使用 RSETful 的方式去调用的,所以我们特意做了一个针对 RSETful 请求的追踪,这里可以看到每一个 RSETful 访问的情况。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035007232-0d24e709-3005-4ed1-9eae-9cd0a1eb68cb.png#align=left&display=inline&height=381&originHeight=720&originWidth=1413&status=done&width=747" alt="" title=""></p>
<p>最重要的其实是对每一次 GraphQL 查询语句的追踪。可以看到,像我们执行这么一个查询语句,拿到的数据结果,执行时间,这一个查询语句的详情都能看到,同时还可以看到每一个字段查询速度如何。又比如说,像这一个接口,它绑定两个服务,一个服务是囤货单的服务,还有一个服务是供应商信息服务,这样子可以看到每一个查询字段它追踪到这种执行效率怎么样的,可以根据这个查询结果来告知后端同学做优化。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035059449-8f240f7e-2f49-4c21-a6ad-64f67dc97ec9.png#align=left&display=inline&height=380&originHeight=998&originWidth=1962&status=done&width=747" alt="" title=""></p>
<p>还有我们的部分自定义 Mock,这就是整个 GPM 大概的样子。因为时间的关系,我就只稍微说一下我们是怎么去实现在线编辑部署 GraphQL 的。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035155698-ef152150-6529-4429-8788-6f8f571914ab.png#align=left&display=inline&height=1080&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>GPM 是使用 nodejs 搭建的,所以这个方案是针对 nodejs 的,其他语言的解决方案需要大家自己去探索了。实现这个功能有以下几个关键点。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035166706-2d1525c0-1372-4bd3-93df-eb05573f3233.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>关键点之一是替换 schema,实际上 schema 可以被修改的,只要我们使用特定的方式将每次执行的 schema 修改掉,那就做到了每次执行 graphql 时都会使用到最新的 schema 了。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035176188-6302444c-deeb-4485-a4a7-707877f0d45e.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>关键点之二怎么做到修改已经在使用中的 schema:我们将 GraphQL 的 schema 分为两部分:一部分是类型定义,另一部分是 resolver。前面也提到过,每个类型下面有字段,每个字段下面绑定了 resolver,我们其实可以把类型定义和 resolver 分开来,同时对 resolver 进行适当的分层。GPM 的分层结构是这样子,但这是我们自己的这种分层,其实还有其他方案,后面的讲师会讲到。 然后我们将 resolver 和 type 定义做好以后,将它使用一些开发工具将它绑定起来,就生成了这么 GraphQL 的 schema 。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035210418-2f077186-740b-4eb4-83e0-7644cac8d4c7.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>在做查询时候就参考 schema 来做,type 定义本质上是 string,关键的一点就是怎么去动态生成 resolver,也就是第三个关键点,这里稍微简单讲一下。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035222309-d9bf11cb-7556-4fa5-9149-2fb1c6843273.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035237763-8f5691e0-5f17-4162-a229-b1d09b47026d.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>我们首先需要去简化 resolver,resolver 本身它的形式是固定的,函数签名其实就是这样,类型下面字段名字,字段名字下面有四个参数,然后返回结果。第一个参数是父类型的查询结果,我们有可能会使用到它类型下面的一些查询的数据;第二个是指定的查询参数;第三个最就是我们刚刚提到的执行上下文(Context),我们可以在执行上下文 (Context) 里面去调用绑定的各种服务。这就是是 GPM 中 resolver 大致形式,第一步拼装参数,第二步使用执行上下文调用服务,就可以动态拿到数据,这样就可以做到动态生成 resolver。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035250557-a5b5f68d-5804-432c-81cb-5f43603c7d6f.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035265743-2dd6c7c7-51f0-4ffd-bc44-6d2b0729b87b.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>我们在使用 GraphQL 的时候有一些无法避免的问题是需要去解决的,这里有两个绕不开的问题:</p>
<ul>
<li>第一是安全问题</li>
<li>第二是慢查询的问题</li>
</ul>
<p>当然还有其他需要解决的问题,关于安全的问题后面的讲师也会讲,时间的关系,这里就不细讲了。</p>
<p>慢查询在终端已经有很多用缓存去解决这个问题的方案了,像 apollo、relay。还有就是在 GraphQL 服务里面去做缓存,apollo 提供的 apollo-engine 就是这种方式,但这个要翻墙才能用,所以只能用来它作为参考。还有一种方案是宋小菜在 GPM 里面用到的:合理地利用 GraphQL 提供的指令 (directives) ,去置换 resolver,这样做到 GQ 服务数据的缓存。还有使用 dataloader 来批量处理多次重复查询,后面的讲师也会提到。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035318584-c431683b-90a0-4215-98ce-afa50ef14420.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035329164-f4148e8b-1805-454e-a096-08427fa41396.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>最后有一个加分项,就在做 GraphQL 的时候有一个数据收集,在 GQ生态里面有 GraphQL-extension,用起来非常好用,我们可以参考它来做一个自己的 extension 追踪 GraphQL 查询语句的执行情况,我们也可以使用第三方工具来做,如 apollo 的 trace。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035338212-cb10058f-34d2-4c29-9da8-0a8a76b1a753.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>最后来一起开个脑洞。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035365997-4250949d-94b6-44b5-8702-4b350f5793df.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>GraphQL 本身其实是一个标准,我们没有必要一定要使用官方 提供的 GraphQL 引擎,我们可以根据自己的实际情况去实现自己的GraphQL。</p>
<p>重新回到 GraphQL 的执行的一个流程,我们在实现自己的 GraphQL 引擎时可以做到以下优化:</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035415776-9cba1acc-a1d2-4165-a2fa-67709d65921a.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>相同的查询语句其实没必要每次都去做验证,这里可以节约一点点查询时间。既然是相同的查询语句它的这种字段收集其实没有必要再去做收集,可以用一些比较简单的方式去避免重复 collect fields。还有比较提升性能一点,官方的 graphql-js 去执行每一个字段的 resolver 时是循环串行执行的,有没有可能做到针对实际情况适当地并行执行 resolver。</p>
<p><img src="https://cdn.yuque.com/yuque/86/2018/png/87556/1529035444420-b528e3d9-6729-46d3-99d6-9e72ab1383dd.png#align=left&display=inline&height=420&originHeight=1080&originWidth=1920&status=done&width=747" alt="" title=""></p>
<p>最后做一个总结,当宋小菜在使用 GraphQL 的时候,概括起来有以下六个特点:</p>
<ol>
<li>单一入口,单端的入口方便前端做工程管理,避免后端做烦琐的API 版本管理。</li>
<li>文档,这个文档可能在一定程度上能够解决文档同步的问题和前端开发阅读的问题。</li>
<li>数据冗余比较方便,减少前后端交流成本。</li>
<li>数据聚合。GraphQL 天生支持数据聚合。因为每一个类型绑定resolver,所以定义不同的 resolver,就可以拿到不同服务上的数据,可以做到不同类型数据源的数据拼装。</li>
<li>MOCK,适当将 MOCK 的职责交到前端,或者前后端一起维护,而且维护起来比较简单。所以说 MOCK 方便我们开发。</li>
<li>动态编辑做到实时部署,敏捷开发。实时部署很快做到线上数据的响应。</li>
</ol>
<p>Scott:回答观众的问题(重新总结的版本)</p>
<p>对于宋小菜的前后端合作工作流,直观上可以看到这几个变化:</p>
<ol>
<li>前端从接口设计环节,向前介入到服务端的系统设计中的库表结构评审环节,此时不仅能了解到库表的字段分布和业务含义,也能在库表设计上就提出一些建议,帮助服务端输出更友好的字段类型和结构给前端,比如 精度和维度,这两个是分开存,还是用逗号隔开,存一个 String,是有分别的;</li>
<li>服务端省去 Mock,省去胶水 API 的设计和维护,省去 Mock,节约的时间可以专心做底层基于业务的系统拆分,提供更稳定的数据服务,构建更健壮兼容的底层架构;</li>
<li>前端在接口评审之前,就可以在 GraphQL 的自定义类型 Mock 上抽象大部分的字段出来(服务端一但确定库表结构,后续改动的可能性就会很小了),此时就可以把 DOM 页面实现后,把占位符的字段就填进去了大部分,最终结构上在接口评审环节双方针对接口特殊性,再核对调整一遍就好了;</li>
<li>前端由于有服务端领域边界的支撑,可以针对特定领域及领域的组合,来封装更有弹性的组件,组件的扩展性可以由配置决定,而不是某一个 API 决定,这个配置向下就是 GraphQL 的聚合能力。</li>
</ol>
<p>关于第 3 点,是需要前后端不断磨合的,关于第 4 点,我们仍然在探索尝试,最终想要表达下我们前端团队的做事的一些理念,我个人认为这一点很重要,尤其对于初创团队。团队里面,无论事情看上去是属于谁的,最终事情一定是公司的,无论一个技术推广影响到谁或者撼动了谁的所谓原来立场所代表的利益,只要对公司研发团队效率有利,有利于技术演进,有利于推动业务更快的走,那么就要果断尝试。最终,为我们所有人的行动买单的是公司,但最最终,依然是我们自己。</p>
<blockquote>Scott 近年面试或线下线上技术分享,遇到太多前端同学,由于团队原因/个人原因/职业成长/技术与管理通道,甚至家庭城市等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命和价值有更多的看见与了解,Scott 微信: codingdream,也可以来<a href="https://link.segmentfault.com/?enc=PCsGYLuuVt996wEp8sUgEw%3D%3D.J42LuhnGhB9J8pXSVHKHrq6fP3U%2BkT6lC%2FglJ2Gqlzw%3D" rel="nofollow">关注 Scott 跟进我的动态</a>。</blockquote>
<p><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882754189-781488ce-b345-45cf-a3b7-cb5309e9caa6.png#align=left&display=inline&height=399&name=2.png&originHeight=600&originWidth=600&size=158647&status=done&style=none&width=399" alt="2.png" title="2.png"><br><img src="https://cdn.nlark.com/yuque/0/2019/png/87555/1575882773713-309efa88-e1fc-481f-865b-3c0cb0d3ec43.png#align=left&display=inline&height=398&name=1.png&originHeight=600&originWidth=600&size=134434&status=done&style=none&width=398" alt="1.png" title="1.png"></p>
技术驱动:前后端的协同效率从哪些方面发力推进
https://segmentfault.com/a/1190000018997619
2019-04-26T14:29:26+08:00
2019-04-26T14:29:26+08:00
Scott
https://segmentfault.com/u/codingdream
21
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream。<br>本系列共 18+ 篇(最开始 15+ 篇,未来会扩充到 30 篇),此为第六篇预热[对旧文章进行了更多观点的更新和补充],大家感兴趣后面文章可以点下关注,再转发下朋友圈我就心满意足了。</p>
<h2>正文开始</h2>
<blockquote>中国铁路大提速是指由 1997 年至 2007 年期间,中国铁路一共进行了六次大面积的提速,提速前的 1993 年,全国列车平均旅行速度仅有 48.1 公里/小时,到今天,中国着眼于建设高速客运专线,使其最高速度达到 350 公里,如今庞大的高铁协调系统复杂程度远超过往,而调度运输效率同样翻天地覆。</blockquote>
<p>技术革命会促使组织结构发生巨大的变化,也会给组织间的协调方式带来新机遇和新挑战,这一点在互联网公司同样成立。我们提到互联网公司,总能联想到敏捷、快、轻、颠覆这些字眼,而事实上除了头部巨头公司的部分部门和部分小而美的中小创业团队,真正能做到敏捷的公司并不如想象中的多,这些公司不仅缺乏敏捷和效率才能持续优化组织升级的思维和意识,更多是缺少自我革命推倒重来的勇气,所以 996 横行,只能靠人力和时间来弥补效率和能力的不足,来实现所谓产品上的快速迭代。</p>
<p>实际上产品上能实现连续正确的快速迭代,影响它的因素是有很多的,比如:业务团队的决策和执行、产品经理的行业功底、项目经理的管理能力、工程师的项目经验、前后端之间的协同等等。从顶层的战略设计,到管理层的理解与推动,到一线的过程设计和执行,任意一个环节掉链子,都会导致产品的迭代出现方向上或者速度上的问题,而工程师的视角容易自前向后自左向右自内向外,往往缺少自上向下的透视,我们重点看前后端协同这块的优化路径。</p>
<p><a></a></p>
<h2>研发流程的核心人物是 PM</h2>
<p>这是小菜技术部我们所遵守大项目研发流程,它往往是线性的:</p>
<p><img src="/img/remote/1460000018997622" alt="image.png" title="image.png"></p>
<p>其中在开发阶段,也是跟前后端工程师密切相关的就是在数据对接这一层有较大的合作成本,我们把这个线性的过程再绘制如下:</p>
<p><img src="/img/remote/1460000018997623" alt="" title=""></p>
<p>来看红色的几个,系统设计,里面涉及到 Java 服务端工程怎么搭建、骨架怎么搭建、服务怎么拆分,最后具象的时候,是服务端同学设计这个数据库和表结构,这几张表上面的字段有哪些。然后接口设计,服务端同学会给出接口的文档,比如说会给你提供五个接口,每个接口 15 个字段,才会进入到前后端对接完之后,再帮你去做一份 Mock 数据,然后前端在页面上把页面样式重构之后,再去调假的 Mock 数据,然后页面交互流程调通之后再切到正式接口,大概是这个套路。这里面有很多工具栈,很多第三方开源的工具可以用,那我们发现这里面前后端堵塞在这个点,而且堵塞很多年也解决不掉,因为接口设计控制权在服务端手里,前端不知道会给到多少接口,然后在接口评审时候,15 分钟或者一个小时,前端基本上很难理解哪个字段背后的业务含义,过后还要和服务同学反复再沟通确认,就因为在这个点的堵塞导致上面三个问题不是很好解决。</p>
<p>往往产品迭代出了问题,就有可能就是上图中某个环节出了问题,所以我们会需要强势的靠谱的 PM 做更严谨的项目管理,同时从技术团队也要给产品经理和运营施加压力,来挤压出最真实的需求,这里对项目经理业务能力和项目能力是重度依赖的,越靠谱的项目经理,这里就有越高效合理的项目迭代,反之可能就坑坑无数。</p>
<p>通过这里引入更靠谱的项目经理,我们可以大大降低前后端以及研发前置和后置流程中的风险点,迭代也会更有节奏感,再往下到数据接口层面的对接和 UI 上的透出效率,项目经理就爱莫能助了。</p>
<p><a></a></p>
<h2>展示层协同与效率的成本</h2>
<p>结合多端展示多样化报表的场景,最初研发成本居高不下,从前端的视角看过去是这样的:</p>
<p><img src="/img/remote/1460000018997624" alt="image.png" title="image.png"></p>
<p>第一个是多端之间的类报表同步,大家现在开发前端,可能开发小程序,APP,PC,会有多端,对我们公司场景来说我们这个端比较杂,可能要在 ERP 要透出报表,在 App 上透出报表,在小程序上透出报表,但是面对不同权限的人报表透出的维度不一样,但本质上下面的数据源是同一份,那我们就可能开发很多个接口去对应不同的 APP,那这个纯靠前端做数据切片组装不太现实。</p>
<p>第二个是多端之间多模块共享,这个模块还不是组件,比如有一个用户模块,一个订单模块、一个物流模块,每个模块里面可能会有一两个组件来组成,但向下所需要的基本数据可能还是同一份或者同两份,只是在不同端上的 UI 呈现不一样。那我们想要让这些模块之间去共享数据很难,我们在不同端上开发一个组件就绑定一个接口,这个组件拿到另外一个里面去,套到那个模块去用的时候发现行不通了,这也是一个很大的成本。</p>
<p>第三个是业务变化快,产品总要升级迭代,UI 重构或者交互改版的时候,加一个字段,减一个字段,或者叠加几个字段合并后的状态值,那么接口又要升级,或者加一个新接口,这个同样导致合作成本很高。</p>
<p><img src="/img/remote/1460000018997625" alt="image.png" title="image.png"></p>
<p>把三个问题再抽象一下,其实就是这三个:</p>
<p>第一个是 API 的设计,服务端同学有的时候会被迫也好,被 “强奸” 也好,我必须要面向你多变的 UI 去做 API 的设计,面向这些页面服务,页面变化的时候,API 可能也要升级。</p>
<p>第二个是 Mock 职责重合,之前也知道业界很多公司自己做了 Mock 工具和平台,我们一直也是在使用第三方的,有时候是前后端共同维护同一份 Mock 接口,有的时候是服务端去维护,但是总之要存在一个协作成本,到底谁来对它负责,这件事情,到现在也说不清楚。服务端同学给你做完 Mock 之后终于可以沉下心来做底层的业务开发,但发现临时需要调整一个字段,就把接口调整了,但是忘记去更新 Mock 文档,前端不知道这个事情,到后面俩人一对接发现字段对不上,这就是一个典型的工作流协作问题。</p>
<p>最后一个问题,这个对于 toB 公司,或者 toC 也有这样的场景,就是报表,报表可能是一个刚需,对于管理层其实需要看到过去一周一个月公司交易的整个规模、吨位、物流情况、库存情况,不同维度的数据观测。业务打法一变报表的维度也要变,传统的报表开发就前后端各一个,服务端搞定数据库,跨表跨库查询,给出标准的字段结构,前端就是把它套到 Table 表格里面去,这个事情很简单,但是可能要排期,一天两天三天,可能产出报表的速度就很有限了。</p>
<p><a></a></p>
<h2>GraphQL 作为解法是否可行</h2>
<p>我们在协同和效率上,最初尝试的解法就是通过 GraphQL,从 2017 年开始小型测试到 2018 年上半年一定规模的推行使用,在这个过程中也跟业界的童鞋有过不少交流,当时收集了如下这些问题:</p>
<p><img src="/img/remote/1460000018997626" alt="" title=""></p>
<p>针对这些问题,我们结合后端 DDD 的设计,尝试在内部前后接口的协同上找突破点,后来在网关这一层,集成 GraphQL 的一个聚合服务,我们理想中的 GraphQL 接入方式,是跟网关同层嵌入在里面做一个管道,但是最终实现的时候,暂时把它放在网关的下面,主要考虑到跟网关的兼容开发成本,比如鉴权安全这些事情都交给网关去做了,它纯粹的做数据聚合,见下图:</p>
<p><img src="/img/remote/1460000018997627" alt="" title=""></p>
<p>针对刚才的问题,我们先把宋小菜在自己的业务场景下,技术的解决方案拿出来给大家看一下。我们现在解决方案是在网关这一层,集成 GraphQL 的一个聚合服务,第二场架构师会来讲具体架构图,这边单独讲这一个点。我们理想中的 GraphQL 接入方式,是跟网关同层嵌入在里面做一个管道,但是现在我们的实现方式呢,考虑到快速跑通,暂时把它放在网关的下面,是为它的鉴权跟安全不想占太多开发成本,把它交给网关去做了,所以它就只做数据聚合这么一件事情,通过系统改造,我们也获得了一些收益:</p>
<p><img src="/img/remote/1460000018997628" alt="image.png" title="image.png"></p>
<p>那么 2016 年 2017 年差不多 2 年多时间整个公司开发的报表一共才 50 张报表,报表开发速度成为一个瓶颈,当我们通过 GraphQL 在端上透出以后,包括服务端去一些拼装的动作,现在提供了可视化报表编辑的系统,这个系统面向产品经理和运营,面向服务端工程师,他们通过可视化的界面配置一下,报表就生成了,报表开发效率直接解锁,这个系统上线以后四个月就产出 200 多张报表,把整个公司报表需求全部消化掉了。</p>
<blockquote>有一个有意思的案例,产品经理跟业务方开会,业务方说:我需要看一下某个服务站一周的报表数据,我要提需求,我需要这个指标这个指标。然后会还没开完,产品经理就把报表做完直接上线了,现在报表产出就是这么一个节奏。通过做这个系统我们发现 GraphQL 可以给我们带来很大方便,我们就继续往下挖,把 GraphQL 它的价值从 APP 端继续往下沉,沉到服务端,我们就做了大舅子,前面的报表系统是大(搭)表(表)哥(格),是搭 Excel 表格的一个谐音,这边是大舅子,公司的产品啊,他们都是亲戚。</blockquote>
<p>大舅子作为今天我们讨论的一个前后端数据组装方案,通过它一个通常需要 4 天的单人小日常小项目,现在可以缩短到 3 天,参与的前后端人越多,多人对接成本降低就越多,通过这个解法,前后端各自的职能也发生了一些演变,同时对于两个工种都有正面的一些影响:<br><br><img src="/img/remote/1460000018997629" alt="image.png" title="image.png"></p>
<p>那关子卖完了,我们聊聊如何搭建这样的一个系统,也会简单给大家科普下 GraphQL 的知识:<br><br><img src="/img/remote/1460000018997630" alt="image.png" title="image.png"></p>
<p>最开始先看一下大舅子的这个数据聚合系统,在我们整个系统架构里面到底处于哪一个位置。从图示中可以看出它处于我们的网关和后端数据服务的中间,刚刚 Scott 也解释过,我们网关本身已经存在了,所以它已经把如鉴权和安全一类的事情做掉了,所以我们在做数据聚合服务的时候,将这个服务放到网关后面。为什么取名叫 GPM,它全称叫 GraphQL Pipe Manager,这是对一个对后端服务提供的数据提供数据拼装的这么一个系统。</p>
<p><img src="/img/remote/1460000018997631" alt="" title=""></p>
<p>这是我们整个 GPM 内部架构大概一个结构图,分成两部分:一部分是正式的服务,可以看到正式的服务比较简单,因为要保证提供正式数据服务稳定,所以我们尽量简化它。另一部分稍微复杂一些的,是开发服务,在开发服务里面我们可以对类型进行编辑管理,然后在开发服务上进行测试,最后应用到我们的正式数据服务上。<br><br><img src="/img/remote/1460000018997632" alt="image.png" title="image.png"></p>
<p>介绍完我们使用 GraphQL 的大致情况后,鉴于在场的部分同学之前可能没有接触过 GraphQL,所以我先来介绍一下什么是 GraphQL,GraphQL 全称叫 Graph Query Language,官方宣传语是“为你的 API 量身定制的查询语言”,用传统的方式来解释就是:相当于将你所有后端 API 组成的集合看成一个数据库,用户终端发送一个查询语句,你的 GraphQL 服务解析这条语句并通过一系列规则从你的“ API 数据库”里面将查询的数据结果返回给终端,而 GraphQL 就相当于这个系统的一个查询语言,像 SQL 之于 MySQL 一样。</p>
<p><a></a></p>
<h2>使用 GraphQL 能带来哪些便捷</h2>
<p><img src="/img/remote/1460000018997633" alt="image.png" title="image.png"></p>
<p>宋小菜经过一个时间不是很长的实践,发现使用 GraphQL 给我们带来五点的比较方便的地方:一个是单一入口,第二个是文档的展示和编写,第三个也是比较有特色一点,就是数据冗余可以使用 GraphQL 来避免,第四点数据聚合是这一个系统本身最主要的职能,还有最后一点就是数据 Mock,Mock 相当于比较棒的附加值。</p>
<p><a></a></p>
<h3>单一入口</h3>
<p><img src="/img/remote/1460000018997634" alt="" title=""></p>
<p>首先说一下单一的入口这一点。传统的 RESTful API 里,不管前端还是后端都要对 API 做管理,一是版本管理,二是路径管理,非常麻烦,增加了工程管理的复杂度。但是如果使用 GraphQL,只需要一个入口就可以了。刚刚也说到 GraphQL 相当于一个数据库,它的入口只有一个,我们只需要访问这个入口,将我们要查询的语句发送给这个入口,就可以拿到相应的数据,所以说它是一个单端点+多样化查询方式的这么一个结构。</p>
<p><a></a></p>
<h3>文档化</h3>
<p><img src="/img/remote/1460000018997635" alt="" title=""></p>
<p>第二点是文档,这里文档虽然不能完全替代传统的文档,但是它能在一定程度上方便我们。传统的 RESTful API 文档管理,市面上有很多工具,像 Swagger、阿里开源的 RAP 以及 showdoc 等。但使用这些 API 文档管理工具的时候其实是有一定的学习成本的。像 Swagger, 可能对于老手来说使用起来不是很复杂,但是对于刚上手的开发者来说上手还是需要一点时间的。然后还有在使用这些平台的时候都会遇到让人头痛的“ API 和文档同步”的问题,很多时候需要自己去做 API 和文档同步的插件来解决。</p>
<p><img src="/img/remote/1460000018997636" alt="" title=""></p>
<p>如果使用 GraphQL 就可以在一定程度上解决 API 文档的一些问题:在做 GraphQL 类型定义的时候我们可以对类型以及类型的属性增加描述 (description) , 这相当于是对类型做注释,当类型被编译以后就可以在相应的工具上面看到我们编辑的类型详情了,像示例的这一个类型 Article,它的描述是 “文章” ,它的属性有哪些,有什么含义,都会展示在大家面前,只要我们在开发的时候规范编写类型,整个文档的展示就比较规范了。</p>
<p><img src="/img/remote/1460000018997637" alt="" title=""></p>
<p>使用 GraphQL 还有一个比较棒的功能,就是每一个 GraphQL 类型 其实相当于 mongo 里面的一个 collection,或者 mongoose 里面的 Model, 而每一个类型之间关系也可以用工具很形象的表现出来。像系统上用到这么一个模型,它对应到哪些和它有关系的模型都高亮出来了。</p>
<p>链接: <a href="https://link.segmentfault.com/?enc=v7tuBVgX9E8ARPF8v8oKPQ%3D%3D.qVTdOs6RQCKTcG2xq2Ed65N2O6aAvuNtYy6sWiZEWzEGF9nZfo3IFLPF%2B5FjQJ6D" rel="nofollow">https://apis.guru/graphql-voyager/</a></p>
<p>这里演示一下,可以传送看一下,在 Github API 4.0 开放出的 GraphQL API,它将 Github 所有的对外类型都暴露出来了。可以看到每一个类型对应的定义和解释都在左面有显示出来。每一个类型都有对应的 UML 图展示,这是一个比较大并且比较复杂的 UML 关系图。我们主要平时用到一个核心的类型其实就是仓库 (repository) 类型,我们可以看到这个类型比较复杂,同时它也是比较核心的,和它有所关联的类型就非常的多,仓库类型下还有 issue 这个属性。如果我们参考 Github 开放的 API 4.0,就可以做到在 Github上面开发相关的插件。</p>
<p><a></a></p>
<h3>避免数据冗余</h3>
<p><img src="/img/remote/1460000018997638" alt="image.png" title="image.png"></p>
<p>使用 GraphQL 的第三点好处就是可以避免数据冗余。我们在传统的 RESTful 处理冗余的数据字段大约有这么三种处理方式:</p>
<ul>
<li>一是前端选择要不要展示这些字段;</li>
<li>二是要么做一个中间层(BFF)去筛选这些字段,然后再返回终端来展示出来;</li>
<li>三则比较传统也比较麻烦,还不一定能生效,就是前端和后端去做约定,如果说这一个接口这一个字段已经不要,可以和后端商量一下把这个删掉,但是有一种情况可能造成冗余字段删不掉的,那就是后端的同学做这个接口可能是“万能接口”,也就是说这个接口在这个页面会用,在另外一个页面也能用,在这个应用会用,在另外一个应用也可能会用,多端之间存在部分数据共享,后端同学为了方便可能会写这么一个“万能”的接口来应付这种情况,久而久之,发现字段冗余到很多了,但是随便删除又可能会影响到很多地方,导致这个接口大而不能动,所以前后端都不得不忍受它。</li>
</ul>
<p>但如果使用 GraphQL,就可以避免接口字段冗余这个问题,使用 GraphQL 的话,前端可以自己决定自己想要的返回的数据结构。刚刚我也解释过,GraphQL 实际上是一种查询语言,我们在使用时就像是在数据库里面查询数据一样,查询的某一个数据要哪些字段可以在查询语句里写好,要哪些字段就返回给我们哪些字段。</p>
<p><img src="/img/remote/1460000018997639" alt="" title=""></p>
<p>拿 PPT 上这个作为示例:我们要去拿 id 为 1 的文章,如果我只要 id 和 content,我在 query 里面指定这两个字段,那么返回的就是 id 和 content,如果除了 id 和 content 之外,我还要拿需要作者信息的时候,我只需要在 query 里面指定 author , GraphQL 就将作者的信息给返回回来。这样就能做到前端决定自己想要什么结构的数据返回的就是什么样的数据。</p>
<p><a></a></p>
<h3>多种数据聚合</h3>
<p><img src="/img/remote/1460000018997640" alt="" title=""></p>
<p>最重要一点当然是数据聚合,数据聚合在使用传统的 RESTful 的方式时有多种解决方案:</p>
<p>一种前端发针对这个页面上的多数据源单独发起数据请求,然后一一展示出来,这样可能会出现页面数据加载不同步的情况。<br>第二种就是开发做数据拼装的中间层(BFF),用于拼装后端提供的数据,然后返回给前端。<br>还有一种是宋小菜在最前期的使用一种方案,那就是后端同学编写针对页面的 API,即所谓胶水代码,来拼接各个服务的数据,返回给前端。</p>
<p>如果是第三种情况的话,就会有大量的工程需要我们去维护,大量的 API 需要我们去维护。但如果使用 GraphQL 的话,这些问题都不会存在,因为它是天生支持数据拼装的。</p>
<p><img src="/img/remote/1460000018997641" alt="" title=""></p>
<p>为什么它是天生支持数据拼装的呢?我来尝试着从 GraphQL 执行的原理上大概解释一下。这是个GraphQL 执行的大致流程,第一步我们去验证需要去执行 GraphQL 的标准,同时去验证将要去查询语句的合法性,第二步生成执行的上下文,关键点在第三步和第四步,第三步是获取查询语句所需要查询的字段,这里叫 fields,所有需要查询的字段可以在查询语句里通过算法拿到,这里可以解释刚刚提到的 GraphQL 怎么做到避免返回数据的冗余的。拿到所有需要查询的字段后,第四步针对每一个字段去执行它的 resolver,可以从 resolver 返回数据里面拿到字段对应的数据,最后是格式化结果并返回。</p>
<p><img src="/img/remote/1460000018997642" alt="" title=""></p>
<p><img src="/img/remote/1460000018997643" alt="" title=""></p>
<p>第四步我解释一下,在GraphQL里面有一个类型的概念叫类型 (type),每一个类型下面对应的是一个或多个字段,每一个字段绑定了一个 resolver,这个 resolver 的作用就是获取字段对应的数据。对应到刚刚举的例子,比如 article 这个类型,它有四个字段: id,author,content,comment。每一个字段都对应的一个 resolver。而这个 resolver 其实是可以被开发者重新定义的,如果说没有定义的话 GraphQL 会给一个默认的 resolver,像Article 的 author 字段类型是 User , User 可以从用户服务里面去获取,所以我们可以将 author 这个字段 resolver 重新定义一下,通过 UserService 获取用户信息。下面的评论(comment)也一样,我们可以通过 CommentService 获取评论数据,这样可以做到在查询这个文章的时候既获取了文章本身的数据,也通过 UserService 和 CommentService 获取到了作者信息和评论信息,然后经过拼装返回给客户端,这样就达到了使用 GraphQL 进行数据拼接的目的。</p>
<p><a></a></p>
<h3>方便数据 Mock</h3>
<p>第五点是附加的一点,我们可以适当地利用 GraphQL 做数据 mock。那么使用 GraphQL 怎么去做到 mock 呢?</p>
<p><img src="/img/remote/1460000018997644" alt="" title=""></p>
<p>GraphQL 的类型大致可以分为两种类型:</p>
<ul>
<li>一种标量类型,像普通的开发语言一样,提供 Int,Float,String 这种标量类型,这种类型在 GraphQL 中也对用着一个 resolver,我们可以通过重新定义其 resolver 来做到对标量类型的 mock, 像 Int 返回的范围是什么,Float返回的范围是什么?String 返回的格式是什么样的?等。同时我们在开发中常用到的一些简单但是有一定规则的数据类型像手机号码、图片地址、身份证号码、身份证号码这样的数据我们也可以通过自定义标量类型来做到数据 mock。</li>
<li>第二种是普通类型,像刚刚示例中的文章(Article)类型,普通类型下面可能会有多个字段,每个字段对应的数据类型可能是普通类型也可能是标量类型,这种类型也可以做 mock,如果我们对标量类型做了适当的 mock 以后,像 Article 的 mock 数据就会自动生成。</li>
</ul>
<p>使用 GraphQL 做数据 mock 还有一个方便之处在于经典 mock 数据可以被很方便地复用。如刚刚示例中查询 Article 下面类型为 User 的 字段 author 的时候可以利用这个特性,因为用户信息(User)这个类型不仅仅会用于文章的作者也可能会用于评论的作者,所以我们针对User 类型做一个 mock 数据,这个 mock 数据可以会在查询文章作者和查询评论作者中同时用到,同时我们也可以在返回 mock 数据时耍一些小花招,例如从几个用户数据中随机返回一个用户信息,或者根据查询条件返回对应的假数据等。</p>
<p>使用 GraphQL 做数据 mock 有多方面的好处:</p>
<ul>
<li>好处之一就是 mock 数据随着类型 (type) 走,当我们修改类型以后,它的 mock 数据也是会被同步修改,不会出现 mock 数据和类型不同步的情况;</li>
<li>好处之二就是能很容易地实现 mock 数据的细粒度,原理刚刚也解释过了,这样能够很大提高我们的开发效率。</li>
<li>好处之三是 mock 数据可以复用,节约开发时间。</li>
<li>最后一点,那就是 mock 数据的职责可以由前后端共同承担。或者说由前端自己来做,因为通常情况下 mock 数据的消费者都是前端自己,为何不自产自销呢,省去大量的交流成本。</li>
</ul>
<p><a></a></p>
<h2>GraphQL 数据聚合系统形态</h2>
<p>这里简单做一个演示,展示一下 GPM 的最终形态:</p>
<p><img src="/img/remote/1460000018997645" alt="" title=""></p>
<p><img src="/img/remote/1460000018997646" alt="" title=""></p>
<p>在 GPM 中每一个生成类型都会以表单的形式展现出来,当然代码的形式也会有特定的地方呈现,我们只是对每一个类型都进行可视化,如果作为一个新人来使用,只需要点击按纽添加类型,指定类型名字,填写类型描述,根据类型的实际情况设置缓存有效时间,绑定到宋小菜的哪些 APP。然后针对已经添加好的类型可以对它做字段的添加的操作,指定字段的名字、类型、描述、缓存有效时间,以及 mock 数据。</p>
<p><img src="/img/remote/1460000018997647" alt="" title=""></p>
<p><img src="/img/remote/1460000018997648" alt="" title=""></p>
<p>同时这一个系统可以直接在线上测试并发布类型的:我们在编辑好一个类型以后,可以部署到开发环境上,然后在 IDE 里面做调试提前查看返回数据是否正确。像刚刚说到的处理数据字段冗余是怎么做的,这里可以演示一下,在前端不想要这一个字段时,直接在查询语句里面删掉然后执行查询就能拿到不包含这个字段的数据了。我们也可以通过 IDE 获取这个查询语句结果的 mock 数据。</p>
<p><img src="/img/remote/1460000018997649" alt="" title=""></p>
<p>在写查询语句的时候这个 IDE 根据我们已经生产的 schema 自动帮我们提示,就像使用普通的桌面 IDE 一样,而每一个类型的文档可以从右边的弹窗里面看到。GPM 将 IDE 分为了正式服务和测试服务的 IDE, 正式 IDE 时针对线上数据做查询的。我们在测试好了新增或者修改的类型以后就可以部署正式环境上了,不用重新发布 GPM 就可以做到。</p>
<p><img src="/img/remote/1460000018997650" alt="" title=""></p>
<p>这是刚刚提到文档展示,GPM 也集成进来了,可以看到这些类型有哪些,然后这些类型到底有什么含义,类型和类型之间的关系是什么样的,都可以在这里很方便的去查看。</p>
<p><img src="/img/remote/1460000018997651" alt="" title=""></p>
<p>在 GPM 上我们还做了一些附加的功能,因为我们后端提供的微服务大多数是用使用 RSETful 的方式去调用的,所以我们特意做了一个针对 RSETful 请求的追踪,这里可以看到每一个 RSETful 访问的情况。</p>
<p><img src="/img/remote/1460000018997652?w=1413&h=720" alt="" title=""></p>
<p>最重要的其实是对每一次 GraphQL 查询语句的追踪。可以看到,像我们执行这么一个查询语句,拿到的数据结果,执行时间,这一个查询语句的详情都能看到,同时还可以看到每一个字段查询速度如何。又比如说,像这一个接口,它绑定两个服务,一个服务是囤货单的服务,还有一个服务是供应商信息服务,这样子可以看到每一个查询字段它追踪到这种执行效率怎么样的,可以根据这个查询结果来告知后端同学做优化。</p>
<p><img src="/img/remote/1460000018997653" alt="" title=""></p>
<p>还有我们的部分自定义 Mock,这就是整个 GPM 大概的样子。因为时间的关系,我就只稍微说一下我们是怎么去实现在线编辑部署 GraphQL 的。</p>
<p><a></a></p>
<h2>如何实现 Schema 的可在线编辑</h2>
<p>GPM 是使用 Nodejs 搭建的,所以这个方案是针对 nodejs 的,其他语言的解决方案需要大家自己去探索了,实现这个功能有以下几个关键点。</p>
<p><img src="/img/remote/1460000018997654" alt="" title=""></p>
<p>关键点之一是替换 schema,实际上 schema 可以被修改的,只要我们使用特定的方式将每次执行的 schema 修改掉,那就做到了每次执行 graphql 时都会使用到最新的 schema 了。</p>
<p><img src="/img/remote/1460000018997655" alt="" title=""></p>
<p>关键点之二怎么做到修改已经在使用中的 schema:我们将 GraphQL 的 schema 分为两部分:一部分是类型定义,另一部分是 resolver。前面也提到过,每个类型下面有字段,每个字段下面绑定了 resolver,我们其实可以把类型定义和 resolver 分开来,同时对 resolver 进行适当的分层。GPM 的分层结构是这样子,但这是我们自己的这种分层,其实还有其他方案,后面的讲师会讲到。 然后我们将 resolver 和 type 定义做好以后,将它使用一些开发工具将它绑定起来,就生成了这么 GraphQL 的 schema 。</p>
<blockquote>typeDefs 的本质是 String,关键自傲与如何动态生成 Resolver。</blockquote>
<p>在做查询时候就参考 schema 来做,type 定义本质上是 string,关键的一点就是怎么去动态生成 resolver,也就是第三个关键点,这里稍微简单讲一下。</p>
<p><img src="/img/remote/1460000018997656" alt="" title=""></p>
<p>实现这个生成工作需要这么几个关键环节:</p>
<ul>
<li>替换 schema</li>
<li>将 typeDefs 和 resolver 抽象为数据模型</li>
<li>充分利用 context,简化 resolver,便于动态生成</li>
<li>进行参数提取</li>
</ul>
<p>结合上图,我们首先需要去简化 resolver,resolver 本身它的形式是固定的,函数签名其实就是这样,类型下面字段名字,字段名字下面有四个参数,然后返回结果:</p>
<ul>
<li>第一个参数是父类型的查询结果,我们有可能会使用到它类型下面的一些查询的数据</li>
<li>第二个是指定的查询参数</li>
<li>第三个最就是我们刚刚提到的执行上下文(Context),我们可以在执行上下文 (Context) 里面去调用绑定的各种服务。</li>
</ul>
<p>这就是是 GPM 中 resolver 大致形式,第一步拼装参数,第二步使用执行上下文调用服务,就可以动态拿到数据,这样就可以做到动态生成 resolver。</p>
<p><a></a></p>
<h2>使用 GraphQL 数据聚合面临的问题</h2>
<p>我们在使用 GraphQL 的时候有一些无法避免的问题是需要去解决的,这里有两个绕不开的问题:</p>
<ul>
<li>第一是安全问题</li>
<li>第二是慢查询的问题</li>
</ul>
<p>针对慢查询,在终端已经有很多用缓存去解决这个问题的方案了,像 apollo、relay。还有就是在 GraphQL 服务里面去做缓存,apollo 提供的 apollo-engine 就是这种方式,但这个要翻墙才能用,所以只能用来它作为参考。还有一种方案是宋小菜在 GPM 里面用到的:合理地利用 GraphQL 提供的指令 (directives) ,去置换 resolver,这样做到 GQ 服务数据的缓存。还有使用 dataloader 来批量处理多次重复查询。</p>
<p><a></a></p>
<h2>如何做数据搜集</h2>
<p>最后有一个让人眼前一亮的玩意,就在做 GraphQL 的时候有一个数据收集,在 GQ 生态里面有 GraphQL-extension,用起来非常好用,我们可以参考它来做一个自己的 extension 追踪 GraphQL 查询语句的执行情况,我们也可以使用第三方工具来做,如 apollo 的 trace。</p>
<p>最后来一起开个脑洞:</p>
<p><img src="/img/remote/1460000018997657" alt="" title=""></p>
<p>GraphQL 本身其实是一个标准,我们没有必要一定要使用官方 提供的 GraphQL 引擎,我们可以根据自己的实际情况去实现自己的 GraphQL,重新回到 GraphQL 的执行的一个流程,我们在实现自己的 GraphQL 引擎时可以做到以下优化:</p>
<ul>
<li>相同的 query 是不是每次都需要 Vlidate</li>
<li>相同的 query,它们的 fields 是否也不用重复 collect</li>
<li>execteFields 是否还有优化空间</li>
</ul>
<p>相同的查询语句其实没必要每次都去做验证,这里可以节约一点点查询时间。既然是相同的查询语句它的这种字段收集其实没有必要再去做收集,可以用一些比较简单的方式去避免重复 collect fields。还有比较提升性能一点,官方的 graphql-js 去执行每一个字段的 resolver 时是循环串行执行的,有没有可能做到针对实际情况适当地并行执行 resolver。</p>
<p><img src="/img/remote/1460000018997658" alt="" title=""></p>
<p><a></a></p>
<h2>小结</h2>
<p>最后做一个总结,当宋小菜在使用 GraphQL 尝试去优化前后端效率的时候,概括起来有以下六个特点:</p>
<ol>
<li>单一入口,单端的入口方便前端做工程管理,避免后端做烦琐的API 版本管理</li>
<li>文档,这个文档可能在一定程度上能够解决文档同步的问题和前端开发阅读的问题</li>
<li>数据冗余比较方便,减少前后端交流成本</li>
<li>数据聚合。GraphQL 天生支持数据聚合。因为每一个类型绑定resolver,所以定义不同的 resolver,就可以拿到不同服务上的数据,可以做到不同类型数据源的数据拼装</li>
<li>MOCK,适当将 MOCK 的职责交到前端,或者前后端一起维护,而且维护起来比较简单。所以说 MOCK 方便我们开发</li>
<li>动态编辑做到实时部署,敏捷开发。实时部署很快做到线上数据的响应</li>
</ol>
<p>而对于宋小菜的前后端合作工作流,直观上可以看到这几个变化:</p>
<ol>
<li>前端从接口设计环节,向前介入到服务端的系统设计中的库表结构评审环节,此时不仅能了解到库表的字段分布和业务含义,也能在库表设计上就提出一些建议,帮助服务端输出更友好的字段类型和结构给前端,比如 精度和维度,这两个是分开存,还是用逗号隔开,存一个 String,是有分别的</li>
<li>服务端省去 Mock,省去胶水 API 的设计和维护,省去 Mock,节约的时间可以专心做底层基于业务的系统拆分,提供更稳定的数据服务,构建更健壮兼容的底层架构</li>
<li>前端在接口评审之前,就可以在 GraphQL 的自定义类型 Mock 上抽象大部分的字段出来(服务端一但确定库表结构,后续改动的可能性就会很小了),此时就可以把 DOM 页面实现后,把占位符的字段就填进去了大部分,最终结构上在接口评审环节双方针对接口特殊性,再核对调整一遍就好了</li>
<li>前端由于有服务端领域边界的支撑,可以针对特定领域及领域的组合,来封装更有弹性的组件,组件的扩展性可以由配置决定,而不是某一个 API 决定,这个配置向下就是 GraphQL 的聚合能力</li>
</ol>
<p>关于第 3 点,是需要前后端不断磨合的,关于第 4 点,我们仍然在探索尝试,最终想要表达下我们前端团队的做事的一些理念,我个人认为这一点很重要,尤其对于初创团队。团队里面,无论事情看上去是属于谁的,最终事情一定是公司的,无论一个技术推广影响到谁或者撼动了谁的所谓原来立场所代表的利益,只要对公司研发团队效率有利,有利于技术演进,有利于推动业务更快的走,那么就要果断尝试。最终,为我们所有人的行动买单的是公司,但最最终,依然是我们自己。</p>
<p>这是 2018 年 6 月份我们在 GraphQLParty 上的分享,时至今日我们依然在不少的业务场景中应用,但也遇到了实际的困难,最大的困难是团队人手的紧缺,导致我们始终无法更深度的去优化和重构它,所以它的价值一直未得到最大化,但我们心里一直有准备继续做这件事,如果你对 Node 比较精通,对前后端协同感兴趣,欢迎来我们团队一起在这个方向上继续沉淀。</p>
<p>最最后,本文作为预热篇,旨在针对如下话题为大家输出:<br>把团队蛮荒到自动化运维的从 0 到 1<br>成长历程总结输出给社区,帮助更多的小团队少走弯路<br>以一种可被量化的方式汇聚小菜前端的困惑、沉淀与方法路径,给团队带来更多创作成就感<br>从更多视角侧切进入团队管理/技术演进/个人成长的过程中,探讨工程师团队的价值最大化<br>如果大家感兴趣,我们小菜前端团队,会集体智慧共同凝聚,一起撰写并推出一本偏前端职业生涯、技术成长和团队成长的小册,回馈给大家,大家在文后记得留言评论和提需求哦,还有别忘了加 Scott 微信哈: codingdream。</p>
学习方法:如何在工作内外获得持续的技术成长
https://segmentfault.com/a/1190000018997570
2019-04-26T14:26:12+08:00
2019-04-26T14:26:12+08:00
Scott
https://segmentfault.com/u/codingdream
33
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream。<br>本系列共 15+ 篇,此为第五篇碎碎念来务虚,大家感兴趣后面文章可以点下关注,再转发下朋友圈我就心满意足了。</p>
<h2>正文开始</h2>
<blockquote>成长永远不是一种结果,而是一种累积效应,更是一种习惯,每个人都时刻在累积,但成长力度却相差甚远,原因就在于特定客观环境内,是各种束缚导致自己打破不掉习惯以及打破后不能坚持。要突破就要从工作内外这两个战场下手,工作内是最佳的成长之地,而工作外是工作内所不能提供的试验田,可以有更多的涉猎与想法验证。</blockquote>
<h2>成长本质是突破天花板</h2>
<p>成长是一件很难捉摸和量化的事情,完全不同的环境和主观意识加上完全不同的行动措施既可以让一个人快速成为某个领域的顶尖高手,也可能完全相反,在开始本文的讨论之前,我们先看几个案例,这是我 19 年发起了一个 “Scott 前端早早聊” 的公益活动(感兴趣可以加微信: codingdream),利用平时上下班的 2 个小时内,与行业迷茫困惑的同学语音交流,交流后他们会做文字记录,先看标题:</p>
<ul>
<li>聊聊 1 - 3 年前端走出成长的焦虑</li>
<li>聊聊 2 - 1 年前端小生之跳槽困惑</li>
<li>聊聊 3 - 4 年高级前端如何走出舒适区</li>
<li>聊聊 4 - 3 年前端出来闯荡还是在家赋闲</li>
<li>聊聊 5 - 4 年前端跨过学历的硬伤</li>
<li>聊聊 6 - 4 年前端频繁跳槽要何去何从</li>
<li>聊聊 7 - 4 年前端非科班如何进阶</li>
<li>聊聊 8 - 2 年前端频繁跳槽怎么破</li>
<li>聊聊 9 - 2 年前端面对职业危险期</li>
<li>聊聊 10 - 2 年前端重复性工作如何破</li>
</ul>
<p>几乎每个人都遇到了成长受限、成长瓶颈、成长迷茫的问题,每个人的原因背景都不同,比如:</p>
<ul>
<li>转行做前端,在大公司里,业务与团队环境趋于稳定,找不到成长机会,与同龄人也有差距,心有不甘想要破局,看不清楚从哪里做起,坚持下去。</li>
<li>从事前端 1 年,公司业务偏外包型,没有组织及主管对自己直接负责,团队归属感弱成长慢,较强的跳槽意愿,近期简历投递不少,但效果不尽如人意。</li>
<li>从事前端 4 年,有转管理的机会,技术属于上升期,在这样的十字路口,面对业务已是熟练手,想要大发力找不到发力点,思考蛮多但仍有困惑,感觉遇到了职业瓶颈,希望走出舒适区。</li>
<li>14 高中毕业,培训 4 个月 UI 后发现自己更喜欢代码,然后自学转前端,后又自学 PHP、JAVA 等基础,但效果都学得不是很理想。</li>
<li>17 年毕业,两年前端经验,第一年就分别在两家公司工作,面临跳槽频繁的职业发展问题。</li>
<li>就职于一家房地产相关的互联网公司,工作时间近两年。技术部门不是主导,团队中前端虽然是业务主导,但彼此之间协作较少,基础建设和团队配置较为落后。近期业务繁忙而人手不够,技术提升也十分有限。</li>
</ul>
<p>平时微信上我也会收到非常非常多这样的困惑:</p>
<blockquote>大佬,我想请教你一个最近一直困扰我的问题,我想问问你如何看待繁重的业务和个人技术成长之间的矛盾,繁重的业务是建立在jquery这种特别老旧的技术之上的,而且领导要求维稳,这就限制了在业务中成长技术的可能性...同时个人技术成长又很重要,毕竟出去面试前端人家不会问产品业务,只会问一些技术,这就造成了一个很严重的矛盾...是不是只能找一个同样看重技术、关注技术成长的志同道合的团队...</blockquote>
<p>全部看下来,背景不同结果都类似,那就是想要提升却无从发力甚至无从下手,对于接下来需要马上进行的 Action 没有清晰的规划,那么所有的这些问题,把他抽象成工作内外,来看看从方法套路上如何打破僵局取得进步。</p>
<p><a></a></p>
<h2>了解技术的成本和门槛</h2>
<p>我们很多时候,会非常喜欢追风追潮流,其实我本人也不例外,但快 10 年了,我才终于意识到,对技术寻根溯源追求本质是最重要的,但比这个更重要的是自己的时间分配和如何选择,你的时间远比你以为的要值钱的多,请珍惜它。</p>
<p>对自己而言如何选择我们后面再讨论,先看时间分配,我们知道,任何技术都有它优劣势,也有它的学习上手成本,那么这些成本结合自己的业务场景,也会有进一步的实现复杂度成本,也就是它的应用场景也是一道成本,对这个成本我们要有一些预判,比如在很早期,我给团队同学梳理了这样一张图:</p>
<p><img src="/img/remote/1460000018997573" alt="image.png" title="image.png"><br></p>
<p>那时候所整理的业务应用端和背后的技术,已经多样到眼花缭乱,而要挑出来押注的技术方向是需要长期的技术栈过程发展,然后我们又整理了第二张图:<br><br><img src="/img/remote/1460000018997574" alt="image.png" title="image.png"></p>
<p>将两者结合后,我们发现针对不同的业务场景,不同的技术栈从陌生到能拿来干活,到运用熟练,都有一定的时间周期,比如对于普通的前端工程师,要把 H5 或者 小程序玩的比较溜,需要 1 年以上的经验,而 iOS/Android 则需要更久,所以哪些技术栈是时间长度相对可被接受,也就是哪些学习成本可以被接受是你需要思考的,思考清楚后,再去选择,会更有侧重,然后再来看不同的技术学习成本背后,哪个更贴合自己。</p>
<p><a></a></p>
<h2>求变之前要先认清自己</h2>
<blockquote>我是谁?我的身份是?未来我想要做什么?当下我可以做什么?我擅长什么?我还需要学会什么?</blockquote>
<p>诸如此类的终极拷问,建议大家在每个深夜难眠的时候,都问问自己,在每个聚会的酒后,都问问朋友,它的答案永远在变化,也永远没在变,时间越久思考的越久经历也越多,就会距离它最真实的答案越近。</p>
<p>比如 “我是一个四线城市来北京的前端小菜,北漂三年半在小公司做营销活动页面开发,未来我想成为一个能独当一面的资深前端,当下我可以积累项目经验,我擅长发现团队及工作中的问题,我还需要学会很多前端的热门框架和基础知识” 这样的命题,大家可以找张纸把问题写下来(重点:一定动手写下来),开始分析:</p>
<ul>
<li>我到底想不想成为这样的前端?是一般想,非常想,还是撕心裂肺的想?</li>
<li>我知道资深前端要具备什么能力么?是要会一些框架,会一些思想,要有哪些框架,要有哪些思想?</li>
<li>我知道独当一面的意思么?是独立做项目,能带人,还是独立完成分配的任务,还是经验丰富?</li>
<li>我的强项是什么?除了发现问题,还有什么?解决问题能力如何,思考深度如何,沟通能力如何?</li>
<li>我来北京为了什么,去上海北京厦门和杭州行不行?是什么在牵绊我约束我,是朋友还是面子还是勇气?</li>
<li>我过往的跳槽经历和项目经历,哪个对我影响最大?是什么影响了我,合作流程、他人还是某件事?</li>
<li>我这些年过的开不开心?开心是为了什么?不开心是为了什么?哪些不开心最难释怀?哪些回忆更甜蜜?</li>
<li>我想要做前端的初心变化了么?为了更好的用户体验,做牛逼的产品,为了生计,为了编程兴趣?</li>
<li>我最能坚持做的事情是什么?运动、听歌、看电影、发呆、闲逛、看书、看抖音玩微博,还是旅游?</li>
<li>我离开做前端行业要靠什么生存?写书、做运营、转产品、回老家开店、找人创业?我有信心么?</li>
<li>我最不能忍受的事情是什么?别人的诬陷、业务方的强势、老板的冷漠、合作方的甩锅还是没有成就感?</li>
<li>我知道 Vue/React 要看源码懂原理为什么没掌握?全部时间被压缩干净了,还是没韧劲啃不动就放弃?</li>
<li>我知道程序员也需要社交为什么自己宅几年不出去?是我习惯满意了当下的生活还是失去了进取的动力?</li>
<li>我知道能力弱会薪资会但看别人拿高薪为什么会不开心?是我希望少劳多得,还是发生在我身上的都是不公平?</li>
<li>...</li>
</ul>
<p>其实有太多太多的问题,我们可以尝试问自己,但我们往往找别人去问,都会挑选跟自己内心与未来无关的话题,比如我选框架 A 还是 B,我是重构还是保持,我是转产品还是转管理....其实所有的答案都取决于我接下来 3 ~ 9 个月具体的行动,这些答案来源于我的原动力以及我规划的最优或者最可执行路径,可一旦我们眼睛看到 9 月后的结果,而忽视这个可执行路径,甚至忽略我的原动力的时候,结果就变得非常惋惜,那就是我竟然整个思考过程,我也就压根无法了解自己的真实诉求和真实能力。</p>
<p><a></a></p>
<h2>习惯养成与定目标计划</h2>
<p>在经过深思熟虑后去制定的目标成功的概率更大,而脑袋一热跑出来的目标往往会泡汤,泡汤到也罢了,这会让自己陷入定目标 - 执行难度过大 - 放弃 - 再定目标这样的死循环,信心和成就感一天天挫败下去,就变成了今日的自己,晚上想千万条路早上起来走原路,越来越麻木越来越气馁。</p>
<p>我的建议是,在定一个目标时候,比如半年内就要看完 6 个框架源码或者写博客,那么要考虑自己有没有阅读代码和写博客的习惯,如果从来没有,那么这个目标就有点激进,比如对于看代码,有效的做法是,先逼自己用 2 周时间,最多一个月时间,在相对固定的时间段去阅读源码,如果用两三周,发现自己完全坚持不下来,那么这个目标就要修正,如果自己坚持两三周慢慢形成了阅读代码的习惯,并且也从中受益获得一些兴趣和成就感,这时候才是要定目标的时候,因为这时候,你的习惯正在养成。</p>
<p>当你有了一种正在建立中的习惯或者成熟的习惯,也定了具体的目标后,就可以定具体的计划了,计划就是行动指南,要一板一眼的去执行的,坚决不能马虎大意,最好是一条条的写下来,比如:</p>
<ul>
<li>每周晚上 10 点钟,花 20 分钟粗读 React 的生命周期函数源码</li>
<li>每周六花 1 个小时,对本周 5 天的源码阅读及当时的笔记进行整理汇总,绘制函数关系图或者原理图</li>
<li>每周日花 2 个小时,针对本周阅读源码遇到的问题进行深入研究,及本地用代码测试模拟甚至模仿</li>
</ul>
<p>然后再把这个规律性的事项,分解到每一天,每一天都要打一个对勾,任务才算完成,完成了要给你自己一个激励,比如连续 5 天完成,可以奖励自己周末去看场电影,如此这般会有很多像打游戏闯关的奖惩细则,最后叠加进去到每日的手机/电脑/智能手表的行程中,给与自己强力的提醒,我相信如果这样能坚持一个月,也就是将近 100 天,一个习惯大概率就能养成了,就可以定第二个目标去养成第二个习惯了。</p>
<p>所以习惯和目标及计划的关系是,定目标前要尽可能先养成一个潜在的习惯,把自己的底线测试出来,然后调整目标,再拆解目标形成规律性的计划,最后把计划完成跟奖惩关联起来,并通过软硬件来跟自己进行提醒的互动,这注定是一个略显单调的过程,但这一定是一个越坚持越好玩的过程,等我们的习惯训练有了雏形的时候,我们才会真正启动持续成长这件事情。</p>
<p><a></a></p>
<h2>训练稳定的思维路径</h2>
<p>我们前面对自己有了更客观的认知,也培养了完成目标的习惯,这两个前提条件就成立了,还缺第三样东西,就是稳定的思维路径,最刻板也最简单的思维方式就是穷尽式的提问,也就是前面认清自己这里,我用列举问题的这种办法,来让自己不断的接近某一个真相,那么面对任何一个困局的时候,都可以用这种方法。实际上,当你把几十个问题都回答一遍的过程中,你可以继续写下更击中灵魂的问题,而这次问题写下去的时候,往往答案就自然浮出水面。</p>
<p>提问的套路可以更简单一些,就是 What Why How,这个问题是什么,当前的真相是什么,为什么发生,为什么走到这个地步,基于这些原因要如何解决,无论任何事情,都逼自己去捉摸它去思考它的前因后果,慢慢会发现自己会变成一个喜欢上思考和善于思考的人,再也不是之前的那个鲁莽的毛头小子,看问题只看负面看现象只看表面。</p>
<p>认识自己、习惯养成、思维训练这三个要成年累月持续的做,当这些都逐渐变成长在自己身体内的一种能力的时候,所以你面临的问题都不会让你像之前那样焦虑,在做完这么长铺垫后,我们再来看如何获得持续的技术成长。</p>
<p><a></a></p>
<h2>工作内外的技术成长</h2>
<p>我们大家如果把小册所有文章看完,一定会有很多的启发,但对于技术成长这件事,还是会觉得缺少了点什么,业务忙起来什么都够不上了,连续 2 个月可能就混混沌沌的过去了,1 年可能不知不觉的过去了,又或者自己对于技术的选型始终摇摆,一个月就摇摆过去了,又或者自己想做的事情推不动,东拉西扯的一个月就又过去了,相信我,所有的这些经历我都经历过,我也相信几乎所有的工程师都有这样的经历。</p>
<p>开始讨论前,我必须亮出我的核心观点:成长是经常不符合预期的,请记住,它大概率是不符合预期的,原因是自己的预期本身是非常主观不准确的,同时成长只是过程的积累并不是一个很直观的结果。</p>
<p>基于这样的背景,我们希望达成的共识是,无论成长是否预期,我都希望有持续的成长,同时盼望奇迹的发生 - 就是远超预期的成长会发生在我是身上。</p>
<p><a></a></p>
<h4>工作内的成长主要来自项目</h4>
<p>带着这样的期望,我们回到工作内工作外会发现,所有的成长最核心的过程指标就是项目经验,工作内天然就可以沉淀,那么如何沉淀或者挖掘成长点呢?</p>
<p>很多人在面试中会被问到一个问题「你做的项目有什么难点」。可能大家会把思维局限在我做的这个业务有什么难的地方,我用了什么牛逼的技术去解决了业务上的什么难题。我相信大部分人不会有这样的经历,由此会觉得这个问题很难答。那么这个问题其实就可以引申为我们如何在工作中、业务中发现问题并得到成长?</p>
<p>如何把业务实现在大部分情况下不会是一个难题,但是如何把业务中相关的组件、逻辑等等可以复用的东西抽象出来,这就是一个难题了。你可以通过学习比你厉害的同事的代码,也可以学习这方面业内顶尖的库是如何实现的,这就是在工作中学习及成长。</p>
<p>在实现业务的过程中,大家肯定会使用各种各样的库及框架。那么当我们熟练使用这个库的时候,就应该尽可能的去了解常用的库的实现原理。我们可以通过文章去了解,也可以通过阅读源码去了解,这也是在工作中学习及成长。</p>
<p>实际上大部分工作场景中的项目,对他深度的思考持续的思考都会带来较大的技术成长,但往往我们没有耐心和动力去做这件事情,因为会有雇佣心态,也就是你付我那点工资,凭什么我想破头皮去捉摸怎么优化它,这就等于是把自己拦到了池子之外,公司付薪水(无论多少)是购买了你的时间,而你的成长是基于这些时间如何在池子里学游泳技能,池子大小水温深浅甚至形状你都很难有控制权,但蛙泳仰泳自由泳甚至闭气潜水这些都是自己说了算,如果这些都玩溜了,去任意一个池子都能如鱼得水,不是么?</p>
<p>前文已经介绍了很多在业务中找技术突破点或者机会的案例,再来举两个更简单的案例让大家感知下 “工作环境中成长的机会无处不在” 这个观点:</p>
<p>如果你的团队每次发布都要上服务器动手,除了发布系统外,可不可以有邮件和钉钉提醒,来推送给相关人,那么这个推送功能有没有可能做成一个独立的消息提醒中台系统,任何发布无论前后端都可以接入这个平台,然后在这个平台上配置应用与应用相关人,任何发布都会触发这个消息提醒服务,又贴心又实用,开发这么个系统既有前端也有后端,如果全部是自己动手做,哪怕是在下班后加班做,也岂不乐哉,因为是为工作打造的贴心功能,也大概率不会遇到阻力,同时它还有价值,自己技术也可以有更多的尝试,这样就是双赢的结果。</p>
<p>如果觉得上面的距离业务有点远,那可以再贴近一层,从一个项目的开发、联调、测试、上线、监控全链路来看,一定能找到无数的流程串联环节目前团队是缺乏建设的,比如小菜从开始用 RN 写 APP 实际上在下图中每个环节都有问题,但直到使用 2 年多后,我们开始意识到并开始把它的全链路工具全部开发并且串联起来,才形成了一个 APP 端算是完整的研发流,参与研发的所有同学都获得极大的技术成长:</p>
<p><img src="/img/remote/1460000018997575?w=1530&h=814" alt="" title=""></p>
<p>所以工作内,不仅靠耐心,还要有不怕吃亏的心态,更要有善于发现的双眼,无数机会都在你面前,都可以持续不断的带来成长,同时给自己团队和个人带来更多效率和体验的提升。</p>
<p><a></a></p>
<h4>工作外的成长主要来自尝试与思考</h4>
<p>工作外的成长更简单易操作一些,往往就是技术储备、技术尝鲜和总结思考,技术储备一部分是为了自己为了的职业考虑,比如学习 RN/Flutter/Go 等,另一方面也可以是为了自己公司业务未来的可能性领域,比如 NodeJS/Taro/MPVue 等等,所有感兴趣的方向都可以去学习储备。</p>
<p>另外就是自己的想法,可以把他变成现实,比如一个行程提醒小工具,一个萝莉妹子叫起床小工具,一个自动生成周末食谱的工具等等,任何一个生活痛点和创意想法,都可以动手把它实现出来,前后端可以一起做,技术栈可以激进,所有的这些尝鲜都会带来技术视野的扩张,也会带来技术深度的沉淀。</p>
<p>最值得尝试的就是思考和总结,把任何自己学习的框架,看过的书,做过的项目,甚至解决过的 Bug,都可以有序的整理起来,把这些整理变成文字和图表,来强化自己对于技术的记忆,所有的这些记忆重复训练的次数越多,对于他们的理解和运营就越娴熟,往往最慢的反而是最有效的。</p>
<p><a></a></p>
<h2>小结</h2>
<p>成长是一个永恒的话题,互联网几十年来,无数的新人问成长,也无数的新人变老人,有的混成一方大拿,有的混成螺丝工头,抛开经济环境、行业趋势和公司经营,更多时候取决于我们成长的是一些学习方法,更根本上依然是我们对于自己的理解、规划和持之以恒的执行,这里面无关运气更关乎实力,不是环境带来的成长去选择你,而是你选择在任何环境中都能成长,具备选择权后,剩下的无非是规划、执行与坚持,无它!</p>
<p>最最后,本文作为预热篇,旨在针对如下话题为大家输出:<br>把团队蛮荒到自动化运维的从 0 到 1<br>成长历程总结输出给社区,帮助更多的小团队少走弯路<br>以一种可被量化的方式汇聚小菜前端的困惑、沉淀与方法路径,给团队带来更多创作成就感<br>从更多视角侧切进入团队管理/技术演进/个人成长的过程中,探讨工程师团队的价值最大化<br>如果大家感兴趣,我们小菜前端团队,会集体智慧共同凝聚,一起撰写并推出一本偏前端职业生涯、技术成长和团队成长的小册,回馈给大家,大家在文后记得留言评论和提需求哦,还有别忘了加 Scott 微信哈: codingdream。</p>
新人成长:新人如何快速融入技术实力强的前端团队
https://segmentfault.com/a/1190000018997488
2019-04-26T14:23:03+08:00
2019-04-26T14:23:03+08:00
Scott
https://segmentfault.com/u/codingdream
12
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream。<br>本系列共 15+ 篇,此为第四篇务虚篇,篇幅可以缩短了一下,大家看完后点下关注,再转发下朋友圈我就心满意足了。</p>
<h3>正文开始</h3>
<blockquote>小菜前端团队经历多次的新人进入。比如校招过来的实习生,社招过来的有经验的工程师,包括我自己作为 8 年老司机,刚进小菜时也是新人,小菜近 1 年半大概进入了 6 位新人,还有正在招聘要进来的 8 位新人。本文基于新同学自身经验所表述的观点(行文风格因人而异,请大家理解),我把这些观点进行了聚合和整理,转述到这里,同时也会加上作为老司机的思考。</blockquote>
<p>步入社会之后,工作开始成为生活的一大部分,与我们所相处时间最多的往往是身边的同事。在这样的环境下,如何与身边的同事融洽相处、如何在一个新的环境下快速成长以及融入团队,成为了每个人工作中必经的阶段。</p>
<p><a></a></p>
<h3>小菜前端技术骨干的典型特征</h3>
<p>一个技术强的团队,一定是靠技术骨干撑起来的,先来看下小菜技术骨干身上所具备的特征,这也是小菜对前端工程师提出的更高的要求:</p>
<ul>
<li>较强的学习能力:前端这些年飞速发展,不断有新的解决方案涌现,无论是 Node.js 社区中丰富成熟的框架库,还是 ReactNative 跨系统开发 App 的能力,提高前端数据接入效率的 GraphQL,包括新的产品形态下的端场景,比如微信小程序/公众号,凡是提高效率的手段,在 ToB 的业务场景下都需要积极研究,谨慎落地,这就需要工程师有快速适应的能力,以开放的心态拥抱社区的优秀方案。</li>
<li>较强的项目合作能力:生鲜 B2B 的流通路径及链路非常长,每个节点上都能长出产品,这些产品背后也有着全新的业务概念。而这 7 款 App,不同的前端工程师都可能参与,参与时候所合作的业务方/产品/设计/服务端也都不同,需要工程师跟合作方有效率的沟通,快速消化理解产品的交互形态和背后的业务路径,才能在项目中有效的发现和解决出现的问题。</li>
<li>跨端编程和体验优化能力:不同的端意味着不同的物理设备和使用场景,也意味着不同的用户人群。比如 PC 端跟 App 不同,iOS/Android App 跟微信小程序又不同。它们背后的技术栈也有差异,比如宿主环境、布局原理、系统规范、接口能力都不同,这就需要工程师对不同的端都有理解。不仅在编程技巧、工程健壮性、跨端组件复用上面有较好的实践,同时对于用户真实的端交互方式和使用体验也有更加准确的判断。前端是在用户体验上最接近用户的群体,因为前端的工作就是用代码来输出体验。</li>
<li>创造性的工程基建能力:尽管在工程保障和线上运行稳定性上面,社区工具也不断推陈出新,但新轮子叠旧轮子,并没有一个系统化的方案。尤其是小菜的主技术栈是 2015 年才面世的 ReactNative,甚至是小程序,在这方面更为匮乏,这就需要前端工程师利用 Node.js 这个顺手工具来在团队内外,业务流上下,快速研发贴合 ToB 工程场景的工具系统,保障前端的研发效率和线上产品体验。</li>
</ul>
<p>怎么融入这样的一个团队呢,我们听听大家的看法。</p>
<p><a></a></p>
<h3>标准融入的 SOP 流程</h3>
<p>针对这个命题,有童鞋根据自己的过往经验,总结了如下几点:</p>
<ul>
<li>了解团队</li>
<li>适应团队</li>
<li>融入团队</li>
</ul>
<p>与之并行的是:</p>
<ul>
<li>了解技术</li>
<li>熟悉业务</li>
<li>进入项目</li>
</ul>
<p>前者是人,后者是事,就像是标准操作流程,以上的几个环节折腾完,基本就算是融入一个团队了。比如了解团队,是可以像销售一样去调查大家的爱好的,然后来做整理输出给大家,这个过程可以快速了解所有人的兴趣和方向,比如小菜在非常早期做过这样的一个小调查:</p>
<p><img src="/img/remote/1460000018997492" alt="image.png" title="image.png"></p>
<p>基本上很快就知道了所有人当前预期的职业方向,这可以为之后跟不同人聊他的话题打下很好的基础。我们再回到新入职的时候,可以更具象的来脑补这样的一个融入画面:</p>
<blockquote>一般新入职都会有一份入职指南,一个老司机和你大概讲一下就说:“你先自己看一下,有什么不了解的再问我”,那我们究竟要看什么呢?</blockquote>
<ul>
<li>首先要了解的就是团队的一个大的宏观的战略方向,这一般是一个长期的稳定的,所有团队成员的奋斗目标;</li>
<li>其次要知道团队平时都要承担哪些任务,又有哪些压力,项目的节奏,这会让你更快的适应团队;</li>
<li>然后就要了解和技术相关的内容了,都使用哪些技术栈,有哪些业务场景,eg:PC, h5, RN, 小程序, node...</li>
</ul>
<blockquote>可能有一些是你有过实践的,有一些是不熟悉的,这很正常,不要盲目的去看去学,要和 Leader 稍微沟通一下,了解可能接下来需要你接手的项目与你比较擅长的地方相结合考量一下,知道了你将要做什么就可对症下药了。你接手第一个项目的过程就是一个很好的融入团队的开端,在这期间不忙的时候你就可以看一下之前的项目中的一些代码,一些 UI 组件库,工具库都是怎么实现的,有哪些常见的业务场景试着去探索一下,也可以和同事相互讨论一下。</blockquote>
<p>接下来我们继续深入探讨本文的核心命题:如何快速融入技术强的团队?重点是技术强。</p>
<p><a></a></p>
<h3>充分挖掘自己的优势与强项</h3>
<p>如果你进了一个技术强的团队,每个人身上都有那么多优点,都有那么厉害的技能,这会给自己带来很多惊喜,但反过来也会带来不少压力。毕竟单点比较的话,总是感觉比别人落下一大段距离,这时候需要正确调整自己的心态:如果你能经过一道道面试被选择进入这个团队,说明你一定也比较厉害,至少你也是个好苗子,而一定不是一名平庸至极的选手。如果是那样的话,就算能进来,你依然过不了试用期,最终一定会被整个团队刷掉。</p>
<p>以上是基于能力的正确认识。但它不是全部,我们要知道,融入更多是指人的融入,而技术则只是技术。既然是人的融入,我们就要把眼光放大到整个团队和人的上面,特别是自己身上。因为往往一个工程师最后入职团队,抛开能力一定是他/她的其他特质可能也能弥补这个团队所欠缺的,比如你:</p>
<ul>
<li>是一个幽默气质的逗比小话痨,可以在茶余饭后工作缝隙调动团队气氛,发动话题,营造更轻松愉快的氛围</li>
<li>是一个酒桌上的老英雄兼游戏达人,会喝会玩,可以利用聚餐团建和喝酒的同学玩翻天玩嗨皮</li>
<li>是一个对业务和产品非常敏感的人,可以主动出击去撩产品和业务童鞋,输出更多思考给到团队</li>
<li>是一个工具效率黑科技折腾侠,可以分享更多有趣有用的知识和方案,帮整个团队提效闪亮双眼</li>
<li>是一个协调和攻略达人,可以在 outing/小型活动 扮演主持人和当导游,带团队各种游戏与轰趴</li>
<li>是一个电子竞技游戏达人,可以把更多游戏世界的有趣新闻/攻略/背后的研发故事分享给团队</li>
<li>...</li>
</ul>
<blockquote>举一个 Scott 2010 年刚参加工作的小例子:我进公司没多久,作为团队新人,其实归属感和荣誉感是比较弱的。看到公司有人在组织上山清扫垃圾的公益活动,我就主动加入后从志愿者慢慢成为领队,连续组织了近三年的活动,甚至还组织了我所在的大部门去往徽杭古道包括环西湖等大型的公益活动。不仅我所在的部门甚至其他部门也都有很多人来参加,结果是结识了更多不同岗位的人,也很好的锻炼了自己的社交能力。在团队内的影响力也自然有很大提升,与此同时我还组建了公司的足球队,作为队长组织球队踢了二三十场的球赛,队友之间有了非常铁的革命感情,同样通过比赛个人的社会人脉也有了很大的扩展。</blockquote>
<p>还有很多很多套路大家可以继续发散,在团队融入这块,外向型人格的同学会更有优势,这也是很多技术团队所欠缺的。因为通常程序员会更朴素冷静沉稳,热情满满风风火火随时嗨翻天的童鞋比较缺少,而这些特质其实很多同学身上都具备,只是自己没有把它可以放大而已。</p>
<p>对于内向型人格的童鞋呢,优势和机会也有很多,大家发现我上面没有把纯技术能力的优势放进来,对于内向型人格的同学,技术讨论/技术分享/技术影响力/技术的行业趋势/技术的应用场景等等都是可以尝试的方向了,只要自己擅长或者只要自己有兴趣潜心研究,都有无数的方法,可以给团队注入不可或缺的新想法和活力。</p>
<p>简而言之,每个人身上都有无数的特质和优势。只要你具备的这些特质是团队刚好欠缺的,那么就缺什么补什么,不要保留不要畏惧,即便结果不那么尽如人意,你在团队老大的眼中已经迈出了重要的一步,起码在认同感融入这个层面就已经成功了。</p>
<p><a></a></p>
<h3>通过执行力来输出自己的责任感</h3>
<p>在没有了解足够多的团队工程技术栈之前,以及在没有理解足够的产品和业务之前,往往对于新人最大的挑战就是任务的及时完成。这个任务可能是独立承担,也可能是有一个小组长分配给自己,或者是与别人共同完成,头几个月的完成度和完成率非常关键,在这个过程中的责任感的传达是关键中的关键。</p>
<p>而责任感传达的最好方式,就是你的执行力和主动性。执行力就是说到做到,无论是要通宵还是要周末无休,拿到结果就是底线。同样主动的沟通进度和上报风险则是一项软技能,不能因为好面子或者怕失去信任而强行大包大揽。这样造成无法完成的结果,对自己对团队都是不够负责任的表现,所以在拼死完成和必要的风险上抛求助之间是要有一个度自己反复拿捏的。</p>
<p><a></a></p>
<h3>把赞美体现在代码上</h3>
<p>工程师是喜欢被别人夸代码的一群人,无论他的技术多厉害都不会拒绝这样的赞美,除了口头的美誉还有很多可以尝试的方式,比如到团队的代码仓库里,多花时间把不同同学的代码都看看,一个是可以帮助自己更了解这个团队的代码风格和质量,更重要的是这是一个极佳的了解别人技术深度的机会,在翻阅别人的代码的时候,看到不懂的地方可以做个笔记,凑合适的机会可以当面请教下,还有一个更有意思的动作就是对写的让自己眼前一亮的代码,进行在线评论,赤果果的表达自己的崇拜之情,比如 “这个去重函数还可以这样封装啊,真是开眼界了!” 等等这样的崇拜脸,有了这样的尝试,可以让所有技术好的同学对你产生好感,进而更愿意接受你的求助。</p>
<p>同样,当自己在项目中参考别人的代码,也可以把引用信息备注到注释里,标明是受到了谁的启发诸如此类,如果再 open 一些,可以把这段参考别人实现的地方截图发技术大群,向别人炫耀自己遇到了一个很好的代码实现,用这种方式来为原作者博得更多的成就感。</p>
<p>往往打动别人才是迈出的第一步,而打扰别人往往成为你走出去的最后一步,两者的区别大家可以仔细品味下。</p>
<h3>将代码仓库视为藏宝地</h3>
<p>每一个团队的每一个仓库,背后都有它神秘的故事,所有的故事细节都埋藏在 commit 记录里,如果想让自己快速融入整个团队的技术栈里,必要的代码 review 是必须走的一步,这一步可以用寻宝的心态走。既然是寻宝,就一定是先粗筛选找出最有价值最有技术含量的仓库和组件,甚至是框架或者通用方案,定位这个仓库后,让自己一边看源码咀嚼里面的设计思想,一边用文字记录这个过程,也就是为这个仓库编写一篇技术实现分析的文章,通过这种方式,不仅让自己对原来团队的宝贝仓库代码更有理解,更重要的是,这个文章的团队内部发表,可以快速的激起大家的兴趣,任何一个点都可以拿来跟仓库的维护者进行一些形而上的讨论,从整个过程里可以进一步获得到他们原本深思熟虑的精髓思想,而这些思想,如果你没有经过自己的整理和理解,完全靠他们主动灌输也是很难消化的,但经历了这样的整理过程,你不仅会收获别人更多的输入更容易理解原理,也会获得更高的人气,更多的仓库的作者都希望被你 Review,这种事情当你做过后,你会发现自己可能比团队更了解团队,至于技术的提升,更不是问题了。</p>
<p>浏览代码宝库的另外的一个好处是,可以更快的在大脑中建立当前团队缺失的地带,形成一些方向性的建议,比如我对小菜前端早期的代码仓库盘点后,列出了很粗的可以做的大事情的大时间轴,其实就是缺什么补什么,也就是当时最原始的大计划:</p>
<blockquote>
<p><a></a></p>
<h2>大计划</h2>
<h4>
<a href="https://link.segmentfault.com/?enc=Rsa1IkoAwRfKphVcm6Yshw%3D%3D.5jWbrHLyt1uUgLzEfecP%2FHPNxm87RhIqo4EcCpFhh8ISXrt9yp%2FU%2B4LJStao%2B1zT6gBY6iTv2Fk7SQQ4oG%2BMXW84dKI0M7oMeWTqHq9lcaU%3D" rel="nofollow">第一阶段</a> - 2017.7~2017.8</h4>
<ul>
<li>至少 2 个项目全部代码规范化<br>
</li>
<li>仓库分支协作规范落地<br>
</li>
<li>App 发布流程锁定权限规范化<br>
</li>
<li>组件化服务器与组件化框架方向落地<br>
</li>
<li>仓库协作周报系统上线<br>
</li>
</ul>
<h4>
<a href="https://link.segmentfault.com/?enc=Gyp6GanV28RYhSVWRd1Q5w%3D%3D.yLgff6uMWMvA%2FZpZWDTyLRWDsdU5xLZVdwyHLFAHGExE51yquqwWazkwom34%2BJoYNh4Hf7rJrVU0D14XDnu05W0Gg%2FoHO2he8PJGBsEk%2FqE%3D" rel="nofollow">第二阶段</a> - 2017.9-2017.10</h4>
<ul>
<li>RN 打点 SDK 集成<br>
</li>
<li>RN 项目单元测试录入<br>
</li>
</ul>
<p><a></a></p>
<h4>
<a href="https://link.segmentfault.com/?enc=CgIbnfcZLSI2KB4rvGmVAg%3D%3D.7ZSwJuUtG%2BnuL6Xcla6kW3Te99v%2Bwbda3Bivb07wnWcBPWb5RXRISLrR3pkcGFi%2BkiRu2JxP5GAAEhg6HBh%2B%2BB8srCHtMR75gGWIa9jCZ5E%3D" rel="nofollow">第三阶段</a> - 2017.11 -2017.12</h4>
<ul>
<li>issue 工作流落地<br>
</li>
<li>资源轮转实现补位练习<br>
</li>
<li>打包发布系统优化及对接<br>
</li>
<li>发布及热更新系统重构<br>
</li>
</ul>
</blockquote>
<p>基于这个大计划,我们一边尝试一边摸索,过程中又启发大家抓住更多机会点,结合不同同学的思考和建议,就很快形成了我们自己的套路版图:</p>
<p><img src="/img/remote/1460000022430967" alt="image.png" title="image.png"></p>
<p>又比如这里面的堂哥 - 一个自动生成周报的系统,我们的一个同学 review 代码后,通过代码梳理了它的流程:</p>
<p><img src="/img/remote/1460000022430968" alt="" title=""></p>
<p>这个流程又被他反复优化,最后服务于整个团队,带来了很多便携性,所有这些事情,或者说是机会,其实都是从历史代码仓库,与大家沟通以及讨论共创后收到的惊喜,而它的起点就在于代码仓库这里。</p>
<p><a></a></p>
<h3>适当的制造一些惊喜</h3>
<p>惊喜总是能让人眼前一亮,耳目一新,而适当的制造一些惊喜,对于融入团队有很大的帮助。比如你接手一个项目,又快又好的完成了项目并且还跟进了项目的后期效果,最终让合作方对你乃至整个前端团队都建立了新的好感和认知,那么这就是对于团队的惊喜,再往小一点,从家乡带一些特产来跟大家伙分享,也算是一种惊喜。</p>
<p>所以惊喜不一定拘泥于工作,也不拘泥形式,只要团队因为你的到来,而大幅度的或者小幅度的发生一些更好的变化。无论是整体研发能力还是气氛的营造都变得更好,那么你的到来注定是被所有人拥抱欢迎的,融入过程中的障碍也就更小了。</p>
<p><a></a></p>
<h3>小结</h3>
<p>我们简单探讨了新人融入团队的几个常规路径,以及快速融入可以尝试的三个办法:第一是让自己的优势弥补团队的短板;第二是让自己的执行力和责任感给团队成员注入一针信任剂;第三是制造一些惊喜让团队因你而变得更有趣。那么无论你的技术在团队内是强还是弱,你会更容易融入这样一个技术强的团队。</p>
<p>最最后,本文作为预热篇,旨在针对如下话题为大家输出:</p>
<p>把团队蛮荒到自动化运维的从 0 到 1<br>成长历程总结输出给社区,帮助更多的小团队少走弯路<br>以一种可被量化的方式汇聚小菜前端的困惑、沉淀与方法路径,给团队带来更多创作成就感<br>从更多视角侧切进入团队管理/技术演进/个人成长的过程中,探讨工程师团队的价值最大化</p>
<p>如果大家感兴趣,我们小菜前端团队,会集体智慧共同凝聚,一起撰写并推出一本偏前端职业生涯、技术成长和团队成长的小册,回馈给大家,大家在文后记得留言评论和提需求哦,还有别忘了加 Scott 微信哈: codingdream。</p>
职业思考:如何看待 996.ICU 的创业公司与成长型前端团队
https://segmentfault.com/a/1190000018997417
2019-04-26T14:20:14+08:00
2019-04-26T14:20:14+08:00
Scott
https://segmentfault.com/u/codingdream
7
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream。</p>
<p>本系列共 15+ 篇,此为第三篇务虚篇-[干货少,做了部分删减],大家看完后点下关注,再转发下朋友圈我就心满意足了。</p>
<h3>正文开始</h3>
<blockquote>所谓成长就是,每过段时间审视自己,都觉得自己曾是一个傻逼的过程。</blockquote>
<p>你中意的公司有万千个,团队有百千种,选择了去一家公司做事,不仅仅是选择一个打工赚工资的场所,也是选择了一个让自己每天浸润在里面得到成长的土壤,眼睛看得到的每年工资卡里的收入数字和年终奖,眼睛看不到的是自己周身从内到外年年浸泡后的格局与能量,我们往往是告诉自己格局与能量更重要,却往往因现实的收入数字而妥协,个中心酸,只有多年经历才能深有体会。</p>
<p><a></a></p>
<h2>一、如何看待 996.ICU</h2>
<p>996.ICU 在 Github 上很短时间就掀过了 20 万 Star,让人一下子感受到了程序员这个默默无闻的群体抱团发声的力量,支持的和反对的也都有各自的阵营,但总而言之这是一件让人欣慰的事情,那就是敢于表达自己的不满,敢于正视自己的需求,太多时候我们都对此视而不见藏着掖着。</p>
<p>在很长一段时间内,我都没有花多少时间去关注这个运动,都是从朋友圈和知乎上看到零零碎碎的观点,直到某一天有一个同学跑过来问我,我是如何看待 996.ICU 的,我当时简单的回复了这样一个观点:<br><br><img src="/img/remote/1460000018997420" alt="image.png" title="image.png"></p>
<p>在小菜团队,我们是介于 965~985 之间,成长欲望更强的同学会主动忙到 995 甚至更晚,从内心深处,我自己既不支持也不反对,倒不是和稀泥打太极,而是我觉得其实是你在选择 996,而不是 996 选择了你,在几千家中国 Top 的互联网公司里面,每个人都有足够多的跳槽机会,996 根本无法束缚你,因为除了 996 这种偏高强度的部分公司外,还有大量 955,甚至 965/985 这种强度可接受的公司供你选择,要确认这是否是你内心可接受的成长路径。</p>
<p>不可否认,市面上有太多 SABC 的公司,也有那么多 SABC 的决策,你不幸跳入其中浪费青春,对这种公司的不合理的体制,要大方的撕逼与对抗,也不可否认,<strong><em>还有很多的心术正三观正的优秀企业家在整合所有团队的能力,去博取一个更易生存的空间,去为社会也为组织创造更大的价值,我们每一个人都置身其中共同发热,只不过在过程里面,我们需要经常把心态跳出来再跳进去,去清醒的认识到资本与资本家的逐利性,也要足够明白自己的主观能动性,这样看问题就不会非黑即白</em></strong>。</p>
<blockquote>用我一个朋友的话说,抛开上纲上线抛开是非黑白,双选的背后是匹配自己的核心需求与可妥协需求,每个人都可以选择一条船融入一个追寻宝藏的大航海船队,这条船可能处在船队的核心位置,也可能处在边缘位置甚至被抛弃,每个船上都有不同分工的角色,选择一个靠谱的船长,选择一艘更大的船,选择一个海盗属性更弱的船,被遗弃的概率才会更小,跟对人上对船,才能成长更快不枉青春。</blockquote>
<p>在中国特色的社会主义阶段,在全民创业的互联网全球大浪潮下,在中美贸易搏杀的开放与冲突的过程中,<strong><em>在扎破头皮挤互联网红利公交车的非生即死的创业形势下,把自己作为一个生存谋发展的个体,放到任何一个 997/996/995/985/955 的公司里面,其实都是合情合理的,过分高强度的工作制度可能是变态的反人性甚至是违法的,但这种体制下的成长一定是最扎实的最有竞争力的,对公司而言对你而言皆是如此</em></strong>,当 996 选择你的时候,你可以去选择 995,而当你不满足 955,你可以去挑战 996,当你真实对待自己的时候,现实也会真实的反馈与你,只不过你还是要想清楚,什么是你想要的,你是否能获取满意的回报。</p>
<blockquote>举我身边三个真实小案例:A 同学毕业后从成都来杭州,无休假无周末拼命写电商搜索引擎,多次感冒肺炎住院,2 年时间就成为公司最早的一批技术专家,并且练就了一身铁打的管人理事本领,后来换行业去创业获得更大成功;<br>B 同学北京来杭州做产品经理,带一堆工程师品研发新业务,拼到凌晨 2 点是家常便饭,团队业绩非常漂亮,大量跟随的工程师突突晋升获得百万股票奖励而自己也连续晋升 3 级,去挑更大的担子;<br>C 同学木讷腼腆,从广州来杭州写代码,无论在公司在家都在写博客总结都在服务器中探索,晋升速度不快但很平稳,最终股票变现去一个更累的创业公司带大数据团队,每天都硬钢到 11 点。他们付出的努力都远大于 997 的强度,与他们交谈,他们也吐槽很累但从内心深处不后悔,并且很感恩有这样的舞台去发光放热。</blockquote>
<p>我还可以举很多很多这样的 ABC,我也还可以举出很多反例的 CDE,但我们回过头看,如果你想要的是成长,你想要的是薪资福利,你想要的是未来更大的价值回报,你想要的镀金镀银的漂亮履历,你想要的是一个荣誉与共的有人情味的公司和团队,这里面任何一个因素不能如你所愿的时候,它就跟 9xx 没了关系,变成了你的内心和当下现实之间,是和解还是再选择的关系,只不过再选择的时候,我们可以有更好的参考标准和丈量尺度。</p>
<p><a></a></p>
<h2>二、想清楚自己想要的和能要的</h2>
<p>今天要聊的话题是创业公司与成长型团队,创业往往让人联想到上市敲钟或者死亡倒闭,而成长二字总是让人想到磨砺与活着,我们总是以为创业公司节衣缩食但一定有着比大公司更多的适合成长的蛮荒之地,可这些成长的基础与环境实际上并没有大公司来的肥沃和优越,它虽然多却未必适合生长,<strong><em>只有蒲公英和仙人掌这样的九条命选手,才适合在创业公司东闯西撞,所以问题要回归到你是否是想成为这样的选手?</em></strong></p>
<p>如果你是九条命选手,你非常适合在创业公司生存和成长,能在创业公司生存的人,在大公司同样能施展手脚,因为你经历了太多的从无到有,从死到生,从干裂到丰润,从惊恐到惊喜,求生求成功的欲望更强,而如果你不是,那么在大公司里你应该能稳中求长,来到创业公司可能会鼻青脸肿甚至职业生涯一命呜呼,这就是创业的残忍之处,<strong><em>杀不死你的是狂风骤雨,而杀死你的往往是温泉流水,对我而言,我把创业看作是人生成长的修行,既然是修行,大概率是一路荆棘一路痛,缝缝伤口继续冲</em></strong>。</p>
<p>创业这趴儿聊了后,我们再来看看大家在择时时候比较关心的话题 - 如何看待成长型团队,这俩其实并没有必然关系,创业型公司也有成长型团队,但它未必有成长型的研发团队,这一点大家一定铭记在心,有的创业公司非常传统,业务非常重,对研发的需求和期待很低,研发连成长的机会都没有,而有的创业公司虽然研发比重很高,但研发的方向和支撑的宽度研发的模式很人肉,往往这样的公司是遇到了一个眼光保守或者话语权很弱的技术领导,说服不了公司重研发效率而不是研发数量,低成本堆起来的人带来的可能是高成本的时间窗口风险和协同灾难,我们想要的一定是一个有潜力的创业公司,那么我去往的团队最好是成长型的研发团队,就算公司没成,至少我的能力成长没有停滞,我的身价依然很值钱。</p>
<p>那我们应该如何挑选创业公司呢?如何评判他的研发团队是成长型团队呢?</p>
<p><a></a></p>
<h2>三、如何选择有潜力的创业公司</h2>
<p><a></a></p>
<h3>1. 看公司成立年限</h3>
<p>刚刚成立的公司最好有深度了解和深度认同,且自己的专业性足够强,全凭运气是一件很不值得鼓励的决定,要知道创业公司的死亡比例非常之高。如果成立了好多好多年,比如超过 5 年超过 7 年却没什么市场规模,那么也要慎之又慎,这样的公司往往是模式依然有问题,可能是高不成低不就的状态,是否还能发力要深度推敲。</p>
<p>如果大家让我给一个年限的话,那么我建议是 3~5 年,这样的公司往往是在 B/C/D 轮,有不太落后的的市场薪资,有不错的业务发力和规模化机会,有相对较年轻有斗志的研发团队,有一群头脑活跃思想坚定的年轻人,重要的是还有期权。</p>
<p><a></a></p>
<h3>2. 看公司的创始团队</h3>
<p>现在有很多查公司信息的 App,甚至比较专业的会有收费服务,去这些平台上查公司的创始团队成员,然后挨个把他们的名字到各个创业/财经/知乎等平台,去搜他们过往的创业履历以及打过的官司。如果这些人大部分出身名门(也就是大公司或者上市公司高管),也就是这些人已经成功过甚至早就财富自由,那么跟随他们一定比跟随无名之辈靠谱许多。因为这些人二次创业往往更纯粹,有更强的使命感驱动,小家子气的概率比较低。</p>
<p><a></a></p>
<h3>3. 看公司的融资清单</h3>
<p>我说好不是真的好,大家说好才是真的好,这一点在择业上其实也是成立的,投资机构的眼光是非常毒辣的。如果是非常知名的投资机构参投跟投,并且这些投资机构出现的负面新闻比较少,投资的成功案例非常多,那么从天使到 ABCD 轮里面,大部分身影都是知名投资机构,那么这个公司比起其他公司大概率靠谱许多,要知道比我们专业的人会赌这公司会赢,我们跟随专业的人更不容易犯错。</p>
<p>至于大家让我说哪些投资机构比较知名,大家可以搜仅今年上市或者快上市的公司,他们的背后都是谁投的,比如今日头条,趣头条,拼多多,美团,饿了么,大搜车等等,看这些公司背后的投资机构有没有出现在你中意的这家公司的资方清单里,如果一个都没有,那么要谨慎了。</p>
<p><a></a></p>
<h3>4. 看公司所做的业务所处的行业</h3>
<p>不感兴趣的事情很难做到极致,这一点对于当前的年轻人很关键。如果你经过了仔细的了解,你发现真心不喜欢这个公司的业务以及它所处的行业,甚至压根不认同这样的模式,那么最好不要选择这家公司。但也不要武断的拒绝机会,而是看能不能进一步跟里面的高层以面试的方式拿到接触机会,聊聊到底他们在做什么做了什么想做什么,也许听一听会改变你既有的认知,同时也可以通过自己人脉以及全网的搜索,正面侧面地看看这家公司对外的形象、发言和对社会的贡献到底如何。</p>
<p><a></a></p>
<h3>5. 看公司的竞争对手</h3>
<p>这算是另辟蹊径了,有时候了解一个人最好的方式,除了他的朋友,反而是通过他的对立面来了解,这样可以提供一些不同的视角。依然是通过各种渠道来搜索它所处赛道上目前有哪些公司,他们大概的成立时间、员工数量、业务规模情况,以及一些第三方的财务周刊对该赛道的评价,是如何评价这家公司以及它的竞争对手的,这些商业观察员的商业总结能力是远远优于一个普通程序员的,所以可以透过它来看到一些公司的正面和负面,积极和诟病的形象乃至商业模式的短板。</p>
<p><a></a></p>
<h2>四、如何判断是一个成长型的前端团队</h2>
<p>前面聊了很多非常虚的选择,回到我们最关心的话题,如果我想要进入一个创业型的公司,并且这个研发团队是成长型的,那么到底我从哪里来判断是否符合预期呢?</p>
<p>首先,无论这个团队是否是成长型的,假如公司不是你想去的公司,你自己各种调查发现这公司有问题或者不是你能认同的企业文化,那无论这个研发团队多么吸引你,都可以保守一些不要前去,也就是说,你要选择团队的前提是,这家公司你要有基本的认可,否则会经历一个内心煎熬的磨合期。</p>
<p>如果公司你觉得还行,那么接下来要仔细研究下它的研发团队及它的前端团队了。获取信息的渠道无非下面几种,从最具有参考性到一般参考性:</p>
<ul>
<li>你有没有熟人、朋友、前同事曾呆过这家公司甚至这个团队,直接听一听他的评价,他为什么选择在这家公司做事,以及他为什么离开和为什么还没离开,他是如何看待这家公司的研发能力、做事方式和技术部的主管能力的。</li>
<li>从所有的技术媒介上(技术会议平台、Github、掘金、各种技术论坛)去搜索这家公司前端团队留过的痕迹,无论是 PPT,开源的代码库,还是一些技术博客和观点,从里面听一听他们对于技术的开放程度,他们心目中的技术理想国,他们是否为自己的技术成果而感到一定程度的满足。如果有,那么这个团队大概率是一个技术氛围活泼开放的团队,如果没有任何音讯,那么说明这个团队很低调,也或许这个团队内外的话语权都很小,还发不出自己的声音。</li>
<li>直接使用它们的产品,浏览它们的官网,看他们对于产品的打磨细心度,注意这是一把双刃剑,不同的公司这一点做的很迥异,通常 toC 的公司外部产品都很精细,而 toB 的公司可能会很粗糙甚至找外包公司做一些外部产品,因为他们的核心产品都不依赖于外部这些产品,所以小菜前端就曾经被好多候选人质疑,官网做的很糟糕,App 做的很粗糙,这一点的确是事实,因为我们的工夫都花在了行业相对封闭且闭环的产品建设上,官网以及交易 App 没有花心思去打磨,但无论如何,外部产品打磨不好的公司,这一点一定是减分项,如果做的很不错,至少说明这个团队对于细节有一定的把控和要求。</li>
</ul>
<p>最后,就是面试流程中的信息收集,建议可以与面试官聊聊团队的过去,而不仅仅是现在和未来,通过观望过去可以看到更多这个团队求变的勇气和魄力,可以把小菜前端剖开,看下这一年多的团队大事时间线:</p>
<p><img src="/img/remote/1460000018997421" alt="宋小菜前端大事记 copy.png" title="宋小菜前端大事记 copy.png"><br></p>
<p>为什么我前文说不需要为 9xx 纠结,它是双选关系,是可以从这张图上,从管理的视角梳理出来这样几条线:</p>
<ul>
<li>人员变动线</li>
<li>技术变化线</li>
<li>组织调整线</li>
</ul>
<p>这几条线是能反映出一个组织的健康程度,我后面的文章中也会讨论组织与管理相关的内容,这里仅举例给大家参考,一个健康的组织这几条线应该都像流动的水一样,不是阳光春风一样完全没问题,而是在组织不断的成长推进中不断的解决新老问题,促使这个组织不断发生正向的变化,从人到事情都要有变化,所以既有技术的动作在频繁发生,也不断有新鲜血液补充,当然也有跟不上队伍的同学的劝退,大家看待自己的组织健康度也可以从这几个视角评估。</p>
<p>以上提供了很多视角,我们再回到个人与团队的双选关系,如果这个团队一直在等某个关键人才来才能打破僵局发生改变,那你要 Make Sure 你就是这个 Key Person,你拥有足够资深的能量进去后去唤醒这个团队,不然久而久之你也会被团队所侵蚀腐化掉。因为环境比想象中要现实的多,好的环境中你会越来越好持续变好,而走向枯竭的团队会日以继夜的侵蚀你的意志,并最终击垮你的心智,无论是绿洲团队还是荒漠团队,对于我们个人而言,<strong><em>自己内心要足够隐忍强大,因为任何团队都有它的荒漠周期,也只有如此,你才能在繁花似锦的创业汪洋中找到属于自己的理想归属地,去发挥自己三千六百万吨当量的潜能</em></strong>。</p>
<p>用我比较喜欢的一句话来结束这个话题:杀不死你的必使你强大,而杀死你的才会让你再次觉醒。</p>
<p>最最后,本文作为预热篇,旨在针对如下话题为大家输出:</p>
<ul><li>把团队蛮荒到自动化运维的从 0 到 1</li></ul>
<p>成长历程总结输出给社区,帮助更多的小团队少走弯路</p>
<ul>
<li>以一种可被量化的方式汇聚小菜前端的困惑、沉淀与方法路径,给团队带来更多创作成就感</li>
<li>从更多视角侧切进入团队管理/技术演进/个人成长的过程中,探讨工程师团队的价值最大化</li>
</ul>
<p>如果大家感兴趣,我们小菜前端团队,会集体智慧共同凝聚,一起撰写并推出一本偏前端职业生涯、技术成长和团队成长的小册,回馈给大家,大家在文后记得留言评论和提需求哦,还有别忘了加 Scott 微信哈: codingdream。</p>
技术栈:为什么 Node 是小菜前端团队的核心技术栈
https://segmentfault.com/a/1190000018997288
2019-04-26T14:16:58+08:00
2019-04-26T14:16:58+08:00
Scott
https://segmentfault.com/u/codingdream
21
<blockquote>著作权归作者所有。商业转载请联系 Scott 获得授权,非商业转载请注明出处[务必保留全文,勿做删减]。</blockquote>
<p>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬抗,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream。</p>
<p>本系列共 15 篇,此为第二篇,大家看完转发下朋友圈我就心满意足了。</p>
<blockquote>任何可以用 JavaScript 来写的应用,最终都将用 JavaScript 来写。 -- <a href="https://link.segmentfault.com/?enc=KrKGc%2ByClyWaSIolR2M6Ew%3D%3D.TzXwsPwBBJgQY4LlWKql1i9GLGrrxO%2B0PgTr%2FZWtU%2BW161v6l3obgoIbyudLRn4xwPph9Lm6jQu4oMK1fhdQbSkAJtqoiNVsxMS5GXKu%2FY2kgamWxjwg8Y93Uaiti6tlamUhVgGWXR4EWEPoyTABjw%3D%3D" rel="nofollow">阿特伍德定律</a>
</blockquote>
<p><img src="/img/remote/1460000018997291" alt="image.png" title="image.png"><br></p>
<p>这篇文章向大家介绍下小菜前端的基建在一步步走过来的过程中,NodeJS 是如何使用的及扮演了哪些角色,它对于工程师个人,团队能力,公司研发效率,业务支撑,技术的探索与突破等等到底有什么实际的意义,以及为什么是它而不是 Python/C++/PHP/Java 成为了前端团队的核心技术栈。</p>
<p><a></a></p>
<h3>被 NodeJS 加速的框架演进速度</h3>
<p>2019 年的前端与 2009 年的前端早已是君住长江头我住长江尾,短短十年,人是物非,React/Vue 一统天下,Webpack 标配江湖,单纯看近 2 年的 【Npm Trends】:</p>
<p><img src="/img/remote/1460000018997292" alt="image.png" title="image.png"></p>
<p>或者参考近 10 年的【<a href="https://link.segmentfault.com/?enc=5gqJfkzTgolaJuM9qbw5WQ%3D%3D.ApTAOBSLLTxiM%2B1p3Yo%2Bk1PoeMWtg0gEvFRT8ymxUYhi5VWo23rEoab8yDLxYwqicQyGJsYsNHq83Qx4zzBs2dr1OR4thSxQ2lVBH%2FxHfjSmMf0bUHJ2wxMFuvTkfwDFHVE8CwjrVKNUFqa1I0nWV9QbtPiFyFcEr15WLQbW9UYOs0xpXAG93%2BERD2n9AmJs" rel="nofollow">Google Trends</a>】:</p>
<p><img src="/img/remote/1460000018997293?w=1152&h=462" alt="image.png" title="image.png"></p>
<p>热度一定程度反映了社区活跃,和占用市场的体量,可以发现 AngularJS 也是经历了过山车,市场被 React/Vue 不断侵蚀,那再把 jQuery 加进来看下:</p>
<p><img src="/img/remote/1460000018997294" alt="image.png" title="image.png"></p>
<p>令人瞠目结舌,即便 React/Vue(绿色和紫色) 如日中天的今天,在整个网络的搜索热度上,也远远低于 jQuery 和 NodeJS,尤其是 jQuery,虽然它的热度在持续降低,但依然是整个互联网中不能忽视的重要组成部分,</p>
<p>虽然早期与 jQuery 同时代还有很多其他框架类库,比如 ExtJS/Mooltools/Dojo/Yui/Kissy 等等等等,但它们的体量比起 jQuery 都差之甚远不再比较,如果大家把近十年听到的看到的框架罗列起来,几十上百都不成问题,生命周期能超过 5 年却寥寥无几,尤其是在 2012 年 NodeJS 在全球推广到一定规模后,框架的诞生迭代替换更为快速,所以从框架的生命力来看,jQuery 目前为止依然是赢家,那它跟 NodeJS 有什么关系呢?</p>
<p>NodeJS 的持续变热,jQuery 也在持续走冷,一部分原因就是 NodeJS 生态基建能力,在之上不断的生长出来新的框架与解决方案(不限于 AngularJS/React/Vue),也在不断的蚕食 jQuery 的市场,倘若没有 NodeJS,自然也不可能有新框架的繁荣之态,今天大有可能依然是 jQuery 在一统江湖。</p>
<p>在今天,无论是 Angular/React/Vue/Webpack,从开发体验、单元测试到打包编译,脱离了 NodeJS 生态,都无法正常运转,NodeJS 就是整个上层建筑的物理基础和配套设施,我们从宏观上了解了 NodeJS 对于前端框架进化和保障的重要性。</p>
<p>接下来,就结合小菜前端在 NodeJS 上的建设与大家聊聊它的重要性,2 年来,我们重度使用 NodeJS 陆续参与了十几个重要的工具/产品/系统的建设,下面挑选四个有代表性的分享给大家:</p>
<p><a></a></p>
<h3>小菜前端第一次尝鲜 NodeJS - APP 热更新服务</h3>
<p>写一些 NodeJS 自动化脚本,代码校验甚至利用 Express/Koa 搭建一些简单的服务,这些都不能算做真正意义使用 NodeJS,我们也抛开 ReactNative/Webpack 等前端开发打包编译需要依赖 NodeJS 这样的场景,我们第一次真正意义使用 NodeJS, 就是对 ReactNative APP 开发的热更新系统,代号神奇博士,服务端框架用的 ThinkJS 框架,那时候是 2016 年中,Scott 还没有入职小菜。</p>
<p>这样一个热更新发布系统可以让客户端 APP 动态更新到增量的代码包,最原始的更新流程如下图:</p>
<p><img src="/img/remote/1460000018997295" alt="image.png" title="image.png"></p>
<p>在热更新系统中,需要针对 iOS/Android 的 IPA/APK 包进行特定操作系统的资源拆包,增量包/原生包存储,包版本管理,权限管理等功能,这些事情是不太可能让服务端童鞋比如 Java 童鞋替你做的,只能前端自己做,也只能用 NodeJS 才能快速的开发出来。</p>
<p>系统上线后,整个公司的 App 发版频率从一个月一两次(审核还会被打回)提升到一周三四次,效率至少提升 10 倍,而且用户的更新体验得到质的提升,对于业务/运营/产品/用户都有极大的价值。</p>
<p>这时候我们概念里面的 NodeJS 可能更像是一个特定场景的功能玩具,并没有深挖它的重要性和可能性,虽然尝到了甜头,但往后的一年多没有再持续挖掘。</p>
<p><a></a></p>
<h3>小菜前端第二次尝鲜 NodeJS - APP 打包平台</h3>
<p>Scott 是从 2011 年开始接触和使用 NodeJS,从 2013 年后技术栈以 NodeJS 为主,开始尝试搭建比较复杂的系统,非常清楚它的优势和短板,在 2017 年下半年开始带前端团队的时候,收到了很多的反馈和投诉,主要分为两类: APP 更新失败的问题(在非常高的迭代节奏下) 和前后端协作的接口/联调问题,针对 APP 更新下失败的问题,我们先来还原下当时的开发状态,大家如果也有多人协作 RN APP 的开发,可以参考接下来我们的做法,相信对你有用。</p>
<p>我们的 APP 当时一共有 5 个 - 宋小菜(对外)、宋小菜司机(对外)、宋小菜供应商(对外),宋小福(对内)、采秘(对内),所有的 APP 都是 RN 开发,都有 iOS/Android 两个版本,其中对外的是商业开发版本,要发布到苹果商店和推送到特定渠道,对内的都是企业包,不对外公开,我们通过公司自己的网站托管应用供员工安装。</p>
<p>这些 APP 之间的业务也有一定的联系,通常开发宋小菜,也会联动要修改宋小福或者采秘,在本地开发的时候,需要在每个包里面,区分连接的是日常测试环境,还是线上生产环境,还要区分是可以打印出日志的 debug 包,还是非 debug 包,并且最终上线前,再由每个同学在本地 Mac 上打出一个包上传到热更新平台,这个流程里面会出现大量问题,我曾经画了这样一张图给服务端的同学解释为什么前端打包 APP 到上线会经常出问题:</p>
<p><img src="/img/remote/1460000018997296" alt="image.png" title="image.png"></p>
<p>这样就会有很多组合,有的包是要频繁打的,有的偶尔来几发,打包的时候要区分:</p>
<ul>
<li>是哪一个 APP</li>
<li>是打 iOS 还是 Android 的包</li>
<li>是正式环境,还是日常测试环境</li>
<li>打的包要不要开启热更新功能,不开启就不会走线上热更新流程</li>
<li>这个包要不要实时连到本地打一些 log 出来,也就是是否 Debug</li>
<li>是在哪个同学电脑上打的包</li>
</ul>
<p>这样硬组合就可以打出 64 个不同的包,意味着可能需要把配置文件修改 64 次,另外,每个同学电脑上的 Mac 操作系统版本会有不同,XCode/Gradle 也可能版本不同,更不用说 Node 以及 NPM 所安装的三方包,甚至本地预装的开发者证书也时有不一致的情况,于是整个团队陷在了打包/包正确性/一致性/是否能打出来一堆问题形成的泥坑里,艰难的对外解释,艰难的互相配合,针对这个问题,我们思路是让这一切可以傻瓜一点自动化,让团队共用一个打包环境,以它打的包为准,于是我们启动了大伯伯打包平台,采购了一台高配 Mac Mini 部署在内网,把所有的配置项都通过界面来管理,简要流程如下:</p>
<p><img src="/img/remote/1460000018997297" alt="image.png" title="image.png"></p>
<p>界面一开始很朴素,长这个样子:</p>
<p><img src="/img/remote/1460000018997298" alt="image.png" title="image.png"></p>
<p>这个系统上线 1 年来,我们已经打了 1000 多个包,因为打包而出现环境错误问题 0 次,极大的解放了团队效率和提升打包的正确性,更重要的是对于团队也沉淀了一些基于 Node 使用的技能,坚定了大家使用它的信心:</p>
<p><img src="/img/remote/1460000018997299" alt="image.png" title="image.png"></p>
<p><a></a></p>
<h3>小菜前端第三次尝鲜 NodeJS - 报表快速制作平台</h3>
<p>无论是 toB 还是 toC 公司,把数据库里的数据拎出来,无论直接导出为 Excel,还是通过接口输出到前端页面中展示,都是硬刚需,小菜也不例外,而且小菜的业务早些年变化特别高频,每次变化都要提一堆报表需求来监控调整前后的业务变化是否符合预期,如果没有了报表就跟算命一样全靠猜,然后这样一个普通不能再普通的需求,却让小菜整个产品技术团队头疼了好几年。</p>
<p>在紧张的业务开发项目中,让前后端各自抽出资源来对接一个个的报表字段,再通过接口 - 页面的联调和发布,是一件非常浪费资源的事情,后端感觉自己像是一个写 SQL 的和接口胶水代码的,前端感觉自己就是个纯粹 Table 报表页面仔,而且经常资源交叉冲突导致报表优先级降低甚至拖很久不能给到业务方,所以公司做了整整 3 年,总共才产出了 50 多个报表零散的扔在 ERP 系统里面,针对这个问题,前端启动了一个项目 - 大表哥报表平台,用来解决报表产出效率的问题,实现 SQL 到页面的自动生成,后端工程师,甚至会 SQL 的产品经理和运营都可以到平台上,按照约定的规则粘贴一些 SQL,或者基于编辑页面组装一些 SQL 的子语句,咔咔!报表生成,这个系统上线 1 年来,生产力一下子得到释放,总共产出了 400 多张报表:</p>
<p><img src="/img/remote/1460000018997300" alt="image.png" title="image.png"></p>
<p>公司的员工浏览报表每天都有一两千次,直接导出 Excel 就导出了 1 万 6 千多次,已经是公司内部最成功的一个工具产品,服务于全公司所有部门,报表展示大概长这样:</p>
<p><img src="/img/remote/1460000018997301" alt="image.png" title="image.png"><br><img src="/img/remote/1460000018997302" alt="image.png" title="image.png"></p>
<p>一个报表的制作界面大概长这样:</p>
<p><img src="/img/remote/1460000018997303" alt="image.png" title="image.png"><br><img src="/img/remote/1460000018997304" alt="image.png" title="image.png"></p>
<p>通过对 SQL 的各种查询词的组件封装,可以从界面快速生成一个可在数据库执行的复杂 SQL 语句,或者反向贴入符合规则的 SQL,自动拆解成报表的表头(字段的中文名称),自动映射到组件(日期、排序、筛选、二级跳转的子报表等等),包括整个报表的需求提出、描述、认领、上下线、制作和发布这样的工作流等等也全部用 NodeJS 实现,这次尝鲜不仅奠定了 NodeJS 在前端团队绝对的位置,也实质性的在支撑业务这里拿到很好的结果,更让我们感到欣喜的是,在报表系统里面使用 GraphQL 是多么的便捷,同时前端部门独立支撑数据相关的业务产品这条路变得可行,NodeJS 的角色从工具也延展到了业务。</p>
<p><a></a></p>
<h3>小菜前端第四次尝鲜 NodeJS - 前后端数据聚合服务</h3>
<p>如果说前面几个,都是与服务端团队解耦的,是前端可以独立完成的,那么这一次,则是跟服务端在职能上和系统上都有强耦合的地方,是跨团队研发层面的尝试,这次发生在 2018 年 2 月份,也就是在前两次尝鲜后,我们又一次比较大胆的突破。</p>
<p>背景依然是前端的页面与后端的接口这里,关于这个后面会专门有一篇详细与大家聊聊前后端合作研发上我们的思考,这里我简述一下,前后端的合作方式通常是数据接口,也就是数据格式和字段约定,一个吐数据一个消费数据,吐什么样的数据取决于消费什么样的数据,消费的数据则来源于产品流程上的 UI 展示形式,一份概念里统一的数据,是有可能被分拆成两个 UI 块展示和复用,可能会让接口颗粒度更小拆成 2 个,或者共用一个大的,频次高一些的 UI 改版也会导致接口的通用性变得很弱,最终产生一堆大而全的重体积接口,进而对前端维护页面和用户的加载产生较大的影响。</p>
<p>而且接口里面永远是黑盒,在前端是看不全接口的能力了,一旦文档没有跟上,接口的输出与 UI 的使用便会脱节,为产品运行的带来了更强的不稳定性,所以我们会希望接口都是纯粹的,用到多少字段就输出多少字段,用到什么格式就输出什么格式,同一个页面的数据,尽量一个接口返回而不是三四个接口返回,但这显然对服务端提出了更高的要求,也是很多公司从前端产品层面试图推动后端团队时候无功而返的最大阻力。一个人群中,大部分人都倾向于不作出改变,在没有看到太多对自己带来的好处之前,而短期成本与长期红利之间大部分会选择短期,因为它容易预见。</p>
<p>我们的解决办法是,用 NodeJS(EggJS) + GraphQL 搭建一个系统,它负责三件事:</p>
<ul>
<li>负责对前端输出所需数据(单接口,要什么给什么,无冗余可组合)</li>
<li>负责去拿所有的服务端微服务接口数据(HTTP 协议或者 RPC 协议)</li>
<li>提供一个可以在线连接接口、约束字段以及实时 Mock 的编辑系统</li>
</ul>
<p>对它的要求是可在线编辑,可联调测试,可数据热发布与热回滚,这个系统上线后,我们接管了 2 款 App 的接口需求,前端拼装页面和组合数据时候变得更灵活自如,同时正向逆向的数据监控,让我们对数据更有把控力,对于服务端来说,也可以更加不关注 UI 如何,更关注业务领域的搭建与标准数据接口的封装,它的界面长这个样子:</p>
<p><img src="/img/remote/1460000018997305" alt="image.png" title="image.png"></p>
<p><img src="/img/remote/1460000018997306" alt="image.png" title="image.png"></p>
<p><img src="/img/remote/1460000018997307" alt="image.png" title="image.png"><br><img src="/img/remote/1460000018997308" alt="image.png" title="image.png"></p>
<p>还有接口地图、数据关系网络、接口字段监控、Mock 系统等等不再一一截图,这个 NodeJS 搭建的系统的复杂度还是蛮高的,上线后我们专门组织了一场技术分享 - <a href="https://link.segmentfault.com/?enc=di6vN257%2BHCV8doT%2BmTsvQ%3D%3D.fa6VrzO0EwJAT8kVvyxpY2itbK7JVeUG0TCViYxxMlSJ6zg3f1enMUGxwVuJ8BbN" rel="nofollow">杭州第一届 GraphQLParty</a>,让它开源的群众呼声很高,我们觉得还需要更多 NodeJS 的专家进来把系统进一步完善后,才真正能达到开源的标准,目前依然是在公司内部使用。</p>
<p>综上,小菜前端基于 NodeJS 既有 Eat Your Own Shit 的内部场景的问题解决,也有直接服务于前端产品的工具,也有直接把数据当做业务来支撑公司决策的业务产品,还有专注在前后端研发效率的数据聚合层的全方位尝试,从内到外从前到后,而这些系统的尝试,又为前端团队沉淀了非常多的服务端能力,系统设计能力,甚至带来跨语言栈的变化,童鞋们的技术能力也都大幅提升,所以 NodeJS 越来越成为前端团队的核心技术栈,目前第五次大规模的 NodeJS 使用我们聚焦的是运维健康体系的搭建,相信在你的团队,基于它做深度使用,只要能贴合你团队的痛点,公司业务的痛点,解决掉问题带来价值,那么这些尝试或者说试错都是值得肯定和鼓励的。</p>
<p>最最后,本文作为预热篇,旨在针对如下话题为大家输出:</p>
<ul>
<li>把团队蛮荒到自动化运维的从 0 到 1</li>
<li>成长历程总结输出给社区,帮助更多的小团队少走弯路</li>
<li>以一种可被量化的方式汇聚小菜前端的困惑、沉淀与方法路径,给团队带来更多创作成就感</li>
<li>从更多视角侧切进入团队管理/技术演进/个人成长的过程中,探讨工程师团队的价值最大化</li>
</ul>
<p>如果大家感兴趣,我们小菜前端团队,会集体智慧共同凝聚,一起撰写并推出一本偏前端职业生涯、技术成长和团队成长的小册,回馈给大家,大家在文后记得留言评论和提需求哦,还有别忘了加 Scott 微信哈: codingdream。</p>
技术栈:小菜前端的技术栈是如何规划和演进的
https://segmentfault.com/a/1190000018997167
2019-04-26T14:11:54+08:00
2019-04-26T14:11:54+08:00
Scott
https://segmentfault.com/u/codingdream
64
<p>Scott 近两年无论是面试还是线下线上的技术分享,遇到许许多多前端同学,由于团队原因,个人原因,职业成长,技术方向,甚至家庭等等原因,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬抗,大家可以找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream。</p>
<hr>
<p>本系列共 15 篇,此为第一篇,大家看完转发下朋友圈我就心满意足了。</p>
<h2>正文开始</h2>
<blockquote>做规划、管人、管资源、管优先级,这便是一个 Tech Team Leader 的宿命。</blockquote>
<p>本文 Scott 以管理者的视角,与大家分享下我自 2017 年 7 月入职小菜后,与前端同学一起是如何规划团队的技术栈的,这条技术栈上的技能点又是如何在不同童鞋不同业务中生长出来的。</p>
<p>先来看一张图:</p>
<p><img src="/img/remote/1460000018997170" alt="image.png" title="image.png"></p>
<p>这张图是 2018 年 8 月份我为团队制定的技术栈架构分工图,上面基本涵盖了 2018 ~ 2020 年团队所需要的的技术栈能力,它也会随着业务和团队不断的微调和修正,等到了 2019 年 8 月份我会重新梳理一个新版本,将来到这里分享给大家。</p>
<p>在带这个团队的一年多时间里,我对于团队的构想其实发生了很多次的变化,抽象的通用一点,一共会有两个并行的过程,一个是从人和团队视角的做好团队规划与管理,一个是结合业务针对团队做具体的技术栈的演进和架构路线调整,两个过程会交叉实施互相影响。这些方法和结论也有它特殊的公司背景和局限性,未必适用于大家所在业务形态下的团队,千万不要硬搬,可以关注下这些过程中的变化,以及我的思考过程,最终我们再回到上面的这张图上,大家就能明白一个团队的技术栈架构和演进背后的方法论了。</p>
<p><a></a></p>
<h2>一、团队管理</h2>
<p>首先说团队管理,这个是前提,没有配套的团队管理手段辅助,是很难单纯的让技术栈发生持续的好的变化,也很难将架构理念推进落地的,在团队管理这里我主要是分成四步走。</p>
<p><a></a></p>
<h3>第一步 了解团队的长与短</h3>
<p>新加入到一个团队,尤其是成为资深工程师后新带领一个团队,除了埋头做事外,有一个很重要的事情要尽早做,那就是去了解团队,方式有很多,比如:</p>
<ul>
<li>主动去看团队仓库里的历史代码,了解大家的编码水平,编程风格,工程维护的方式,架构的成熟度</li>
<li>与每个同学单独聊聊天,聊聊他对于一个技术的看法,对于业务上思考,对于自己和所处团队的认知</li>
<li>请大家去吃吃饭,听听大家都聊什么,玩什么,关注什么,每个人的气场和表达方式,在办公桌和餐桌上有什么不同</li>
<li>找服务端团队和业务团队的同学,问问他们对于前端团队的印象,对于合作童鞋的看法</li>
<li>在会议上抛出一些问题,观察大家的参与积极性和表述观点的深度</li>
</ul>
<p>还可以一起去打游戏看电影,一起参加公司活动等等,这是一个比较粗的了解,我进团队后,也是挑了上面两三种方式对团队成员有了一个比较粗的摸底,看到了很多好的特征也看到了不少问题。</p>
<blockquote>好的方面:都很年轻很聪明,学习能力较好,可塑性都很强,没什么城府,对技术有激情也有热情,技术栈很新颖,每个人潜力都很大。</blockquote>
<p>基于这些,可以预判这个团队只要理清楚每个阶段的重点,就可以快速成长,每个人都能不断的突破天花板,所以大盘子的性质不错,资质也不错,再来看看问题:</p>
<blockquote>问题:职场的专业度不够,比较情绪化,对于业务多变有一定抵触,职业规划无感知,对于好的不好的评判标准比较狭隘比较封闭,整体工具化工程化以及基建的方向都没有太多思考,对于整个行业的判断比较粗浅,属于比较原始蛮荒的阶段,团队成员的能力层次不齐,补位与大局意识比较薄弱。</blockquote>
<p>具体的方法论,可以把近几周的问题做汇总,然后给它们打标分类,比如这样:</p>
<p><img src="/img/remote/1460000018997171" alt="image.png" title="image.png"></p>
<p>结合业务和开发过程,来梳理问题共性,最终的问题可以总结为:</p>
<ul>
<li>人心不稳定</li>
<li>技能短板多</li>
<li>职业无规划</li>
<li>合作意识差</li>
<li>团队无规范</li>
<li>工具基建弱</li>
<li>业务无感知</li>
<li>梯队未搭建</li>
</ul>
<p>基于这些,可以预判团队需要一个不短的磨合期,在磨合期中需要先逐步建立信任,同时针对不同的问题需要学唐僧跟大家经常讲多讲,也就是通过灌输让大家先有一个正确做事的概念在脑海中,然后再针对每一个同学的特征,以不同的方式分配任务,驱动和辅导,另外,需要有一些事情大家要一起做来形成团队合力和凝聚力,我最终选择了技术分享作为一个大家共同做的事情,让团队在这一件事情达成唯一的共识 - 技术团队影响力的提升和个人总结能力的提高。</p>
<p><a></a></p>
<h3>第二步 鞭策团队完善内部短板</h3>
<p>所谓内部短板,就是完全是自己的锅的问题,比如发布系统不完善,比如代码不规范,比如工具不健全这些都是甩都别想甩出去的锅,有了第一步的总结归纳后,就可以在这些问题里面,优先挑选跟业务有强关系的问题重点突破。</p>
<p>我当时选择的是开发的上线流,也就是从开发到发布这个开发团队必须具备的刚需能力,从这条线劈出来各种工具和系统,童鞋们的反对声音会相对低,而且由于系统的效率和稳定性能带来更多的资源释放,也能带来参与同学的极大成长,所以通过规范和工程的方式来弥补内部短板,是一个非常可取的团队管理手段,见下图,是从 2017 年下半年之后到 2018 年,在开发上线流程上发生的变化:</p>
<p><img src="/img/remote/1460000018997172?w=1950&h=376" alt="image.png" title="image.png"></p>
<p>这一路的基建过程大概陆续进行了半年多,基本团队里最人肉最脏最累的活儿,都由机器做掉了,虽然跟业务没有直接关系,但它间接保障了业务的可持续性和稳定性,同时一路升级打怪,也让参与开发的小伙伴们都有较大的编程和工程能力提升,成为最早的一批技术骨干。</p>
<p><a></a></p>
<h3>第三步 推动团队迈向无主之地</h3>
<p>如果已经解决掉了团队的核心内部问题,接下来就可以把跟产品,运营、业务有关系的环节完善掉了,比如 App 在线上运行的异常监控这些,实际上在创业公司,一般是没有一个部门直接对它负责的,大家都焦点在业务上,那么这时候从前端团队手里出去的作品,理应由前端自己驱动自己来为它负责,这里我把线上运行时的监控单独作为一条线,它配合内部问题的 Mock 阶段的 GPM(GraphQL 数据聚合服务层),都是跨出了前端团队的职能,与其他团队产生了关系,见下图:</p>
<p><img src="/img/remote/1460000018997173" alt="image.png" title="image.png"></p>
<p>不仅对业务,对于其他的中台部门比如人事、财务和行政都是一样,只要有精力,都可以尽可能用成本最低的技术手段,来为公司内三不管的无主之地做一些协同的工具和系统,这会给团队带来很多正向的口碑,同时也有技术的提升,最重要的是,在内部问题和外部协同上,一旦你成为发起者和驱动者,你的角色和身份就发生了变化,你既是产品经理也是项目经理,既是需求方也是业务方,对于个人的综合能力会有很大的提升,对于整个团队在公司内部的影响力提升也有帮助,在工作中部门之间互相帮助也打下了一些底子,这一点对于不善表达比较木讷的工程师团队很有意义。</p>
<p><a></a></p>
<h3>第四步 鼓励团队技术与业务创新</h3>
<p>从前面的三步,大家可以看出我的套路,带团队往前走,比较稳的方式就是从内到外,从技术到跨团队事务到业务,最终也就是第四步,再回归到业务和技术的结合,来利用技术创新驱动业务,利用业务可能性倒逼技术突破,这虽然不是终极态,但对于工程师团队已经是一个非常可接受的状态了。</p>
<p>差不多在 2018 年 5 月份开始,我开始 push 前端团队把一只脚迈进到业务中,无论是技术预研,还是业务场景挖掘,我们在做好业务支撑的同时,绞尽脑汁去思考,到底这么多这么酷的前端技术,怎么跟我的业务产生关系,怎么挖到产品经理挖不到的地方,另辟蹊径为业务创造可能性,那么在这一点上因为会触及公司的核心商业机密,我接下来就举一个早期的脱敏案例供大家感受。</p>
<p>在我们的移动生态都是 App 的时候,微信生态也在蓬勃生长,那么如果产品延展到了小程序,我们将如何支撑,要知道此时全公司都没有任何一个业务包括产品有过类似的具体规划,但大家都有一些很虚的想法和概念丢进来,这时候工程师通过与业务方出差去用户现场,去评估有没有小程序落地的可能性,回来后我们开始做小程序的技术预研,通过这个过程,我们抢在业务和产品前面,做了必要的技术储备,从而为后来快速打开微信生态,进入小程序的新载体阵营打下了关键的技术基础。如果工程师在这时候没有主动进入业务的意识的话,也是完全不可能让业务方有信息甚至有意愿来进入一个新的生态的,所以等到团队里的部分工程师都能成长出这种意识和能力的时候,我认为就是一个合适的时候,来做技术栈的长远规划了。</p>
<p><a></a></p>
<h2>二、技术栈规划</h2>
<blockquote>在我带团队的前面 10 个月,其实我也尝试做过零碎的技术栈规划,但效果并不尽如人意,一个是客观基建基础不满足,很难做相对可靠可落地的规划,一个是团队成员的整体意识包括个人能力没有上来,这时候做有点拔苗助长,甚至会引起组员的抵触情绪,总结下就是必要的小的相对零碎的技术规划一定要有,但不建议垮大周期做大而全的,可以做 1 ~ 1.5 年左右的。</blockquote>
<p><a></a></p>
<h3>ReactJS - 第一次大规模应用技术栈归一</h3>
<p>无论是 RN,还是 PC 端的 ReactJS,小菜前端的 React 技术栈在头三年就实现归一了,只是归一而不规范,以及还有旧 App 是原生架构这样的历史包袱,但总体上到 2017 年下半年,React 技术栈外加 Webpack 是团队的标配了。</p>
<p>这条归一的技术栈结合后面的 NodeJS 能力,也就孵化了我们的两个核心前端框架:</p>
<ul>
<li>客户端 RN 框架 Brick</li>
<li>PC ERP 单页框架 Highway</li>
</ul>
<p><a></a></p>
<h3>NodeJS - 第二次大规模技术栈锁定归一</h3>
<p>我们再回到 NodeJS,也就 2017 年初是初步使用,2017 年底是深度使用,从 2017 年底开始,NodeJS 就成为了团队的一个核心能力,通过它,我们把 RN 的基建全家桶一条龙全部实现了,比如脚手架,组件化,代码校验,机器打包,支持白名单的热更新发布,包安装成功失败与跟踪,端用户访问行为数据可视化,端运行异常监控与指派等等,这一条龙让我们有信心来把所有的 App 全部重构为固定的 RN 版本最新的路由,</p>
<p>除了支撑客户端基建,NodeJS 还为我们打开了内部系统开发的一扇门 - 服务端能力,这扇门对于前端对于公司都是有极大好处的,从前端的角度,可以掌握更多技能可以支撑更多业务可以把技术玩的更 6,从公司的角度,在不大规模动用前后后端产品和运营的资源下,前端工程师可以独立完成跟业务相对不那么强耦合的业务,又省钱又省时间,是非常划算的投入产出比。</p>
<p>那么在 NodeJS 这个技术栈上,我们长出了很多能力,为业务提供了大量帮助,对于团队而言,沉淀了一个核心的服务端框架:</p>
<ul><li>Node 服务端(基于 Egg)框架 Cross</li></ul>
<p>之所以研发 Cross, 是因为我们一路用 ExpressJS/KoaJS/ThinkJS 过来,框架的定制升级和集成我们想要复用的功能都不够规范,也不够严谨,直到我们使用 EggJS,基于它的强约定和插件机制可以方便的集成过来,来定制我们自己的框架,我们再 2018 年下半年开始启动这个框架的定制直到年底出炉。</p>
<p><a></a></p>
<h3>GraphQL - 第三次小规模的技术栈尝试</h3>
<p>GraphQL 一定会成为 2019 年相对高频的词汇出现在大家的视线里,我们是从 2017 年开始使用,同时在 2018 年 4 月份直接研发了聚合数据服务系统,集成到了我们的网关下面,为各个 App 端提供定制数据的能力,我们尝到了很多甜头,也遇到了不少阻力和调整,在 2019 年我们会持续的耕耘它,至少在特定的领域内大规模使用。</p>
<p>还有一些数据搜集、加工计算和可视化的一些组装层我们是交给了 Python 和 C#,甚至是 Rust 的尝试,这些都可以看做是技术预研,还不能称为我们的核心能力,所以暂时不作为核心技术栈的演进目标。</p>
<p><a></a></p>
<h3>MPVue/Vue - 第四次大规模的小程序技术栈归一</h3>
<p>如果说 GraphQL 是我们遇到的一个惊喜的彩蛋,那么 Vue 则是一个让我们惊讶的彩蛋,我们原本的演进路线里并不包含它,但限于我们业务的复杂度,和当时市面上可选择的局限性,我们最终选择了 MPVue 作为我们的小程序框架载体,那么也自然没有考虑京东的 Taro,那时候 Taro 还太青涩无法在生产环境用,虽然使用 MPVue 给我们带来了很多可能性和效率,它也为我们带来了困扰,那就是技术栈在团队内出现了一定程度的割裂,毕竟它跟 React 的语法和生态不同,到目前为止,基于小程序的生态,我们把 MPVue 作为核心的小程序技术栈,基于这样的一个端领域实现了归一。</p>
<p>那么总体全篇下来,会发现我们的技术栈演进,是会随着团队人员能力基建成熟度,也就是一定的团队管理和成长而变化的,同时也会跟我们的业务及生态有强关联性,除此之外,技术栈规划确实是一个看着很客观但实际上也比较主管的工作,它里面杂糅了很多的因素,这些因素在不同时期的权重还不同,当团队能力强的时候,可以规划的长远一些硬核一些,团队能力弱的时候就要灵活一些。</p>
<p>于是从 2018 年下半年开始,我开始做相对硬核的技术栈和架构规划,也就是有开篇的这张图:</p>
<p><img src="/img/remote/1460000018997174" alt="image.png" title="image.png"></p>
<p>一共是这十二个课题和方向:</p>
<ul>
<li>Node 服务,支撑工具、业务系统、运维、监控等</li>
<li>前端基础框架,支撑未来几十个甚至上百个 PC/H5 ERP/Saas 工具系统</li>
<li>前后端协同方案,支撑特定业务领域的数据聚合,降低开发成本</li>
<li>端行为数据监控,为业务/产品/运营提供产品设计及业务调整决策</li>
<li>端性能监控跟踪,为端可靠性稳定性提供保障</li>
<li>端数据计算中心,为可视化、图形图像及视频多媒体提供高性能计算服务</li>
<li>构建部署,为多端提供整体开发、测试、打包、发布部署提供运维能力</li>
<li>客户端逆向,为社群/CRM/人与人新的链接关系提供必要的技术底层方案</li>
<li>安全防控,为全端提供安全监测、警报、拦截等护航保障</li>
<li>平台组件化,为跨端提供低成本可复用的 UI 组件及未来的智能化拼装</li>
<li>交互研究,为交互体验、ABTest、用户行为价值、设计表达输出工具与方法论</li>
<li>端/数据报表透视与可视化,为全公司提供友好的可快速产出与维护的报表可视化方案</li>
</ul>
<p>这些课题向下,再延展出各个技术栈的方向规划,就是当前团队内我们开始并持续关注的事项了,接下来的技术栈也会顺着这些课题方向而不断的演进升级。</p>
<p>最后,业务支撑、技术价值、个人成长、组织升级这几者之间的确很难达到理想中的平衡的,但基于创造更多的业务价值这一核心立论,不断去寻找场景寻找突破点的这样的 action 是我们作为管理者和技术骨干所要坚持到底,无论何时,这都是优秀的工程师和技术决策者的责任和宿命 - 为人负责,并为结果负责,借事修人,借人成事。</p>
<hr>
<p>最最后,本文作为预热篇,旨在针对如下话题为大家输出:</p>
<ul>
<li>把团队蛮荒到自动化运维的从 0 到 1</li>
<li>成长历程总结输出给社区,帮助更多的小团队少走弯路</li>
<li>以一种可被量化的方式汇聚小菜前端的困惑、沉淀与方法路径,给团队带来更多创作成就感</li>
<li>从更多视角侧切进入团队管理/技术演进/个人成长的过程中,探讨工程师团队的价值最大化</li>
</ul>
<p>如果大家感兴趣,我们小菜前端团队,会集体智慧共同凝聚,一起撰写并推出一本偏前端职业生涯、技术成长和团队成长的小册,回馈给大家,大家在文后记得留言评论和提需求哦。</p>
创业公司的 Nodejs 工程师
https://segmentfault.com/a/1190000007025059
2016-09-27T22:11:45+08:00
2016-09-27T22:11:45+08:00
Scott
https://segmentfault.com/u/codingdream
32
<h3>创业团队撸 Node</h3>
<hr>
<h3>前言</h3>
<p>大家好,我是 Scott,2016 年 9 月 25 日在杭州大搜车总部举行的杭州 Node Party 上分享了一个话题 - 《创业公司撸 Node》 ,分享之后我以文字的形式又记录了一遍,分享给没有与会的朋友,也方便大家通过搜索引擎者一些技术社区平台来看到这篇文章。</p>
<p>写在前面,感谢芋头哥和大搜车,给了我这个机会跟大家在大搜车面基,说实话,从我出道以来,这还真的是我第一次正式在公开场合装逼,尤其是当着这么多大牛大咖的面儿装逼。</p>
<h3>某天当你进入创业团队</h3>
<p>今天跟大家分享的话题是,现阶段下创业团队中对于 Nodejs 工程师的认可程度,以及如果有一天你进入了创业团队,在做技术选型的时候,基于什么标准来判断,要不要使用 Nodejs 开发,以及如何跟进技术的演变。</p>
<p><img src="/img/remote/1460000007025062?w=783&h=432" alt="image_1atkko8genctbat1dn12os1dg79.png-39.4kB" title="image_1atkko8genctbat1dn12os1dg79.png-39.4kB"></p>
<p>我特意加了前端逆袭这个小标题,是为了在咱们现场做个小调查,请从前和现在做过前端开发的的同学举一下手好么,看看多少人搞了前端现在也在搞 Node。现场举手的超过一半人数,前端这个职业真的是屌爆了。</p>
<h3>我的职业转型</h3>
<p>ok,首先做一个自我介绍,我跟大家一样,从前也是一名前端工程师,从 2010 开始,在阿里妈妈做了四年前端,后期做了不少广告投放相关的前端页面,跟后端的创意投放管理系统对接,制作和优化广告效果模板等等,大家如果去上 Youku, 微博,各种电影小说新闻媒体网站,应该会有印象曾看过这样满屏滚来滚去的淘宝豆腐块广告。</p>
<p><img src="/img/remote/1460000007025063?w=765&h=542" alt="image_1atkmoo3m1v0kg5l148vbcdi4316.png-494.3kB" title="image_1atkmoo3m1v0kg5l148vbcdi4316.png-494.3kB"></p>
<p>哈哈,很不好意思,2014 年以前,你在全网看到的差不多有 70% 的豆腐块广告都是我做的,你在淘宝搜了鲜花啊,内裤啊,硬盘啊,种子啊,再去访问其他网站,都能看到豆腐块里的类似商品,当时我的工作就是开发这些模板的样式,优化这些模板的特效,测试在各种终端设备上的兼容性,数据方面需要跟各种算法引擎团队约定各种异步数据格式,业务上需要考虑复杂的参数加密解密二跳透传,Cookie 的读取定向等等来落地不同推广场景下的异步交互方案,最终基于各种广告系统接入和投放到目标网站。</p>
<p>所以在最初我仍然是一个很纯的前端工程师,后来怎么就开始折腾 Nodejs 了呢,我们可以看下上图最右上角的这个轮播图,它由上下两部分组成,上面是轮播的商品列表图,下面是推广的商品关键词,它俩是两个独立的数据接口,而且很可能是隶属于两个完全不同的数据引擎团队,从前端开发的角度呢,我需要发两次请求来分别获取和控制这两个数据接口的展现,而从后台开发的角度看,两个接口最好相对独立,互不影响,因此我们前端工程师,尽管很希望将两个接口合并成为一个接口,却很难推动后端工程师团队为我们这样某一个模板,专门开发一个接口出来,由这个接口统一获取两个接口数据合并后再交给前端展现,于是我们就很难从至少是请求个数这个层面,来优化这个广告的展现速度和展现完整度,有时候是图片先出来,有时候是关键词先出来,如果等待同时出来,万一某一个接口挂了怎么办,这时候再等待超时以后去获取打底的接口或者类似接口,用户早就离开了。</p>
<p>但是这样一个模板在全网的每天为阿里带来的收益,是非常巨量的,而它的生命周期也许只有 2 周,2 个月就撤下去换别的模板了,所以从维护的角度上,后端工程师的确也很难及时跟进前端和产品层面频繁的改动,而从收益方面,就需要跟后端工程师努力的沟通解释,非常费劲,协作成本居高不下。</p>
<p>但是现在有了 Nodejs 后,我们设想一下,如果把 Node 作为接口这一层,由它来决定调用哪几个接口,合并哪几个接口,哪些接口使用哪些打底数据,是不是这样的场景就迎刃而解了呢,关于这个我就不再探讨了,可能会涉及到公司保密协议,因为我后来从阿里离职出来创业了。</p>
<p>创业以后,开始了我的职业转型,这近 3 年时间,我一直在创业公司用 Nodejs 开发产品,我也就从一个标准的前端开发工程师逐步切换为一个会使用 Nodejs 的开发工程师,中间费了不少力气,想了解我的技术成长路线的,可以看上一篇文章 - <a href="https://link.segmentfault.com/?enc=orhCHGjM40LtyMu%2FcgTkhA%3D%3D.uAbLvFHDnVA%2FdjU7m1aSuL2s2TSbWkxujLt8WTL8Fov9J90JwyFGVAEDD9hi%2BRKL" rel="nofollow">4 年前端狗,2 年 CTO</a>,进入一个新的 领域,作为新人是要踩很多坑的,有的是有必要踩,有的没必要踩,我就把自己的一些心得整理做成视频,放到了慕课网上。</p>
<p>地址见这里:<a href="https://link.segmentfault.com/?enc=ZrulmZbcdpHduHlWhpeiwQ%3D%3D.Gm0xoANRms3vFi3fnlvy2FRab%2Bt%2BsQT87PLqo%2BLUnX8g1e1EwtMoxgDenyy%2FEhw1pEZl4wmlb4910u1If%2BHOaA%3D%3D" rel="nofollow">http://www.imooc.com/u/108492/courses?sort=publish</a></p>
<p><img src="/img/remote/1460000007025064?w=694&h=411" alt="image_1atkosk8jeg7g1d1sac1jls1hco1j.png-242.6kB" title="image_1atkosk8jeg7g1d1sac1jls1hco1j.png-242.6kB"></p>
<p>如果是刚入行的新人可以去看看,里面知识点也许有点陈旧,讲解也未必很严谨,可以选择性的理解流程和项目思路。</p>
<p>那么现在,我是 CampusRoom 这个网站的技术负责人,大家可能都没听过 CampusRoom, 没关系,估计部分同学听说过 Moveha,创业这几年中,无论是 CampusRoom,Moveha,还是微信服务号,包括其他的一些内部的外部的,做了没上线,上线了又下线的大小项目,统统都是用 Nodejs 来搭建的,整个创业团队也充分体验到了使用 Nodejs 建站或者启动一个项目时候敏捷所带来的高效率,其中有一个小案例,近几年,一些欧美国家不是太安全,我们为了让学生和家长能对当地的居住环境有一个安全方面的了解,就用 Nodejs 很快速的搭建了一个爬虫小系统,爬取一些州和城市的警署犯罪数据,然后合理的分类和评级打分后,给出一个数据可视化的效果,这个功能的产品价值可能是很大的,然而实现成本是非常非常小的,效果见下图:</p>
<p><img src="/img/remote/1460000007025065?w=712&h=328" alt="image_1atkotmi212csc041nsk15mc5so20.png-81.1kB" title="image_1atkotmi212csc041nsk15mc5so20.png-81.1kB"></p>
<h3>市场对于 Nodejs 工程师的需求</h3>
<p>以上都是从我自身,从我们公司来来感受 Nodejs 的开发效率和对公司的价值,但是整个业界对于 Nodejs 的态度又是怎样的呢,他们的接受度又是如何呢,我们再举个例子,大家可能看到过 CNode 论坛上的这个招聘贴,我截图了有赞的和大搜车的,最后一个就是我发的,也就是 Moveha 公司的招聘,哦,说一句,Moveha 是 CampusRoom 的前身,CampusRoom 是从 Moveha 孵化出来的,我要说的重点是,我发的这个 Node 工程师招聘贴,是论坛里最先被加精的招聘帖子,也是阅读量最高的帖子,现在有 4 万多个阅读量,400 多个评论,这个帖子给我带来了 100 多份简历,现在我们公司的所有工程师都是从这个帖子招过来的。</p>
<p><img src="/img/remote/1460000007025066?w=713&h=175" alt="image_1atkpa9hv19eo17fidsr1e3rf4k2d.png-82.6kB" title="image_1atkpa9hv19eo17fidsr1e3rf4k2d.png-82.6kB"></p>
<p>在这个帖子前后 - 2014 年秋季,在论坛或者社区中,很多公司对于 Nodejs 工程师的认知包括他们的价值定位其实是不够清晰的,从招人的风气中就能看出来,在我发这个帖子以前的时候,很多公司跑到 CNode 上发帖,都是姿态比较高,一副你爱来不来的样子,对自己公司团队文化介绍的三言两语模棱两可,薪资区间从来不敢放,自从我发这个帖子之后,逐渐的论坛的招聘贴开始接地气了开始有诚意了,薪资够不到 20K 的公司甚至都不好意思上来发帖了,从这件事情上就能反映出工程师社区的结果导向,玩虚的根本不行,结果好市场认同自然容易被人接受,CNode 上面大量的招聘也从侧面证明了,这三四年以来,Nodejs 工程师越来越被认可,越来越被重视,一个职位到底含金量高不高,其实不是你说了算,也不是我说了算,而是这个市场说了算。</p>
<p>我们再来看下 indeed 上面统计的职位需求变化的趋势,第一个图是 Nodejs 的需求量变化,第二个是 Fullstack 的需求量变化:</p>
<p><img src="/img/remote/1460000007025067?w=627&h=429" alt="image_1atkprbcm144uup8ib71lh31rt82q.png-81.4kB" title="image_1atkprbcm144uup8ib71lh31rt82q.png-81.4kB"><br><img src="/img/remote/1460000007025068?w=610&h=424" alt="image_1atkps52gbkqh6fdu418951cda37.png-95.8kB" title="image_1atkps52gbkqh6fdu418951cda37.png-95.8kB"></p>
<p>这两个职位,即便是在今天,现在依然处在井喷暴涨的阶段,整个市场已经对 Nodejs 工程师有了足够的认可,所以大家的职业黄金期真的是已经到了,再过两三年,Nodejs 工程师就会真的遍布大街小巷各种公司,现在是跟上这个大潮的最佳时期。</p>
<p>那为什么这么多公司对 Nodejs 工程师这么认可呢,特别是中小型团队,特别是创业团队,为什么明明可以选择 PHP,可以选择同样敏捷的 Ruby,可以选择更加成熟,程序员相对更容易招聘的 Java,Python,却非要费劲巴力的去招聘紧缺的 Nodejs 工程师呢,尤其是具备前端工程师能力的 Nodejs 工程师呢?</p>
<p>答案非常简单,就是因为利用 Nodejs 开发一个新项目,会非常的高效敏捷,无论从最终的用户体验,还是上线后的产品迭代节奏,使用 Nodejs 都有巨大的成本优势。</p>
<p>而成本对于创业公司来讲,是非常敏感的事情,现在市面上成千上万家嗷嗷待哺的创业公司,其实跟屌丝无异,不是没钱,就是没人,没钱,没人也就罢了,很多 CEO 还想要有好的用户体验,还想要有更短的研发周期,更快的迭代节奏。</p>
<p>说白了,也只有通过这种快速迭代和小步快跑,才能跟同类产品的大公司竞争中拿到时间差优势,最快的拿到用户反馈和市场反应,最终才能在竞争中和夹缝中杀出一条血路,现实的确是如此残酷。快速的推出产品,熬过最艰难的阶段,找准了产品的盈利点,抓住了目标用户群,有了可以拿到桌面上的各种数据,自然更有优势融资,那时候再去改进优化技术栈甚至更换开发语言也完全有足够的缓冲余地。</p>
<p>所以我们 Nodejs 工程师的核心价值,尤其对于创业公司,就是能够快速产出,迭代的速度更快,前端后端可以通吃,为创业公司节省巨大的人力成本,这就是为什么在市场上,Nodejs 这么受欢迎的原因,创业公司选择我们,不仅因为它能最快速的满足初创团队的场景,也是因为 Javascript 也是唯一的能跨越前后端,用一种语言搞定产品实现的选择了,关于 Nodejs 的适用场景,它的优势劣势,它的开发和维护成本,相信大家做了这么久都有自己的见解,不再过多赘述,我们且往下看。</p>
<p>究竟什么样的创业项目,比较适合 Nodejs 呢,或者说, Nodejs 作为创业团队立项时候所考虑的技术选型,有它适用的边界么,如果有,边界在哪里,有哪些衡量的标准。如果在创业公司,我们需要确定用 Nodejs 开启一个项目,那么以怎样的标准,或者说怎样的准则来衡量, Nodejs 怎么用,框架怎么选,版本如何跟进呢?</p>
<p>太多的问号在脑海中回荡,我个人认为,可以简化为如下三个问题,就能解决从决策到执行的流程:</p>
<p><img src="/img/remote/1460000007025069?w=813&h=312" alt="image_1atl46sfi19bojldies1uhc1od69.png-217.4kB" title="image_1atl46sfi19bojldies1uhc1od69.png-217.4kB"></p>
<h3>一、要不要用 Nodejs</h3>
<p>首先第一个,什么样的创业项目,适合用 Nodejs,哪些又不适合用,我们从这三个因素来衡量:</p>
<p><img src="/img/remote/1460000007025070?w=679&h=355" alt="image_1atl49aastfh1s0eo74f031dfhm.png-40.2kB" title="image_1atl49aastfh1s0eo74f031dfhm.png-40.2kB"></p>
<h5>1. 期望的迭代节奏</h5>
<p>任何一个产品,立项之初,都有它特殊的商业背景和商业目标,在这个背景和目标下,会给予对它的一些期望,希望它以怎样形式,多长时间开发上线,上线后,以多长的周期进行版本的更新迭代,这些都很好理解,如果是一个展示型的,扔上去不需要怎样去增加功能,也不需要多么频繁的改版升级,那么就没必要一定要使用 Nodejs,用 PHP,Ruby 统统没问题。</p>
<h5>2. 团队工程师能力</h5>
<p>我们知道,就像这世界的大部分事物一样,工程师的能力也是大概符合正态分布,除去特别弱的,比如 3 年前的我,除去特别强的,大部分工程师其实都处在中间的这个地带,就像现在的我,对于 Nodejs 及周边生态的掌握可能比较好,但不是特别特别好,而 Nodejs 又是一个新的职业方向,火热的市场上根本没有足够时间来沉淀,于是大部分的创业团队是并没有足够资深的 Nodejs 工程师,这意味着我们在快速开发的时候,往往也面临着更高的业务风险,一旦 Nodejs 用的姿势不对或者技术选型失误,会给业务带来灾难性的打击。</p>
<p>这一点其实被很多公司所忽视,整个团队在当下与未来半年的一个规模,团队成员的技术背景,自我学习的能力,对于新技术升级的接受程度,如果是不能很好的驾驭 Nodejs 而且自学能力又偏弱的话,就需要慎重考虑一下。</p>
<h5>3. 跟产品的匹配程度</h5>
<p>其实创业类的产品,往往很少有上来就规模化,高难度的,所以许多类型都适合,我们与其想那些可以用 Nodejs 开发,不如反过来看,那些类型的不太适合用 Nodejs 开发,排除掉这些场景,剩下的都可以评估一下用 Nodejs 是不是可以。</p>
<p>我这里罗列了几种,其实大家照着这个方向走,未必只有这 4 点:</p>
<ul>
<li><p>极高并发数</p></li>
<li><p>密集 CPU 运算</p></li>
<li><p>高安全高可靠性</p></li>
<li><p>内存精密控制及释放</p></li>
</ul>
<p>并发数本来是 Nodejs 的强项,高吞吐量,但是如果上来就是要应对爆发式井喷的场景,需要堆机器的时候,显然这些非 Nodejs 领域内软实力会过度消耗工程师的时间成本,这一点一旦工程师的学习能力跟不上来,就会反过来制约业务的发展,如果非要给一个数字的话,可以以 10 万作为一个衡量点,并发大于 10 万的,都要慎重评估一下。</p>
<p>而对于大循环的数据结构,需要长时间的运算的,对 CPU 强依赖,导致时间片释放迟缓的场景就尽量不要用 Nodejs 来做,可以交给 Scala,可以交给 Go,甚至可以交给 Java 和 C++ 来做。</p>
<p>举一个例子,比如有旅游路线的实时计算,对用户的出行路线进行推荐,需要基于多维度不同权重的因子进行算法推演,考虑进去用户的性别,喜好,预算,期望的出行方式,天气,当地景点的分布,目的地有没有类似 G20 的大会等等各种因素,背后则可能依靠一些大数据做支撑,这时候用户不可能等待太久,而是希望马上拿到路线报告,这些场景下我们处于中段能力值附近的工程师就不要逞强,避免使用 Nodejs。</p>
<p>安全可靠也同理,一些支付或者银行对接从场景,服务的稳定性非常之高,不能有任何可能异常导致的进程挂起,引起数据不一致,这种如果其他语言已经具备很好的线上解决方案的话,那么 Nodejs 就可以只做它擅长的方面,把这些交给其他更专业的技术来实现,Nodejs 只调用接口就行。</p>
<p>一个项目做大了之后,代码中会有更多的隐患或者风险,一个疏忽就可能导致内存泄露,而如果业务层面是对内存非常敏感的,由于内存使用不精细导致对外的服务质量不平稳,这些都是业务不能接受的,那么这样的场景也要慎重权衡一下。</p>
<p>其实,考虑到创业团队特定的起步方式,不平衡的工程师能力,产品迭代的节奏,只要是一些略苛刻的场景,都应该要多思考一下,用 Nodejs 除了效率,能带来的价值能否高过带来的挑战和风险,如果答案是否定的,我们就要慎重使用 Nodejs。</p>
<p>我们始终需要去找到一个在工程师能力,Nodejs 满足和匹配业务的程度,以及公司的产品节奏之间找到这个平衡点,而且这个平衡点会随着业务的膨胀,团队的成长而不断的变化,在变化之中我们需要不断的评估,去反思。</p>
<p>那么我们回到产品本身,一旦我们排除掉这些场景以后,我们就可以大胆使用 Nodejs 了,或者说,不是我们,而是更多已经大力度投入到 Nodejs 阵营中的先驱者和执行者们,比如下图:</p>
<p><img src="/img/remote/1460000007025071?w=719&h=424" alt="image_1atlbgjdj5m0n3gnj2ss9uq313.png-179kB" title="image_1atlbgjdj5m0n3gnj2ss9uq313.png-179kB"></p>
<p>太多全球的大公司,已经在使用 Nodejs 了,就连 微软这样印象中比较封闭刻板的软件帝国,都已经对 Nodejs 有着很大的投入,对开源有很大的包容度,推出了很多 Nodejs 好用的工具和服务,甚至要 Fork 一个 Nodejs 推出新的引擎。</p>
<p><img src="/img/remote/1460000007025072?w=764&h=344" alt="image_1atlbuq1o11avqs11okc119ffh1g.png-170.5kB" title="image_1atlbuq1o11avqs11okc119ffh1g.png-170.5kB"></p>
<p>甚至更另类一点的,发射太空任务的 NASA 都要用 Nodejs 来开发一些应用或者是运行一些系统,甚至是 2016 年 Github 上评选的,最受欢迎的项目中,有将近一半都是 Nodejs 相关的项目,或者有用到 Nodejs 做一些构建工作。</p>
<p>总结起来就是一句话,Nodejs 上天入地,刚前刚后,流行只是我们看到的现象,背后是它较低的使用门槛,较小的协作成本,以及更好的开发体验,和不错的性能表现。</p>
<p><img src="/img/remote/1460000007025073?w=753&h=453" alt="image_1atlbvf941ng9f9q1bjf197o1okc1t.png-114.2kB" title="image_1atlbvf941ng9f9q1bjf197o1okc1t.png-114.2kB"></p>
<h3>二、扔掉历史包袱</h3>
<p>虽然有这么多我们乐于看到的方面,作为一个工程师,我们依然需要谨慎对待,当我们确定使用 Nodejs 以后,如何选择版本或者语法层面的一些编程习惯,毕竟 JS 编程始终太灵活,有许多问题大家纠结好多年,而 JS 的快速进化也带来更多的编程方向,站在这个十字路口,往前一步未必是大海,往后一步也未必是悬崖,但是前进总比后退要更能接近未来。</p>
<p>举一个简单的例子,让很多工程师头痛了很多年的例子,就是 Callback, 这是个老生常谈的问题了,不同的团队不同的项目历史背景不同的技术风格,显然对于 Callback 的态度和选择是不同的,比如芋头哥在大搜车,对于 Callback 的态度是相对宽容的,因为几十万行的历史代码,说实话交给我维护,我也不敢乱来。</p>
<p><img src="/img/remote/1460000007025074?w=540&h=242" alt="image_1atlc7r7t9om1tcoq3u17dknk42a.png-54.4kB" title="image_1atlc7r7t9om1tcoq3u17dknk42a.png-54.4kB"></p>
<p>那么我个人的看法呢,Callback 显然是不爽的,是反人类的,我的观点是,初创团队,如果没有历史包袱或者历史包袱不大的话,坚决丢掉,可以直接上 Promise,因为包袱只要背在身上,只会越来越重,越来越不敢扔掉。</p>
<p>如果再激进一些,可以将 Promise 和 Generator Function 混用;<br>如果再激进一些,就结合 Babel 来使用 async/await;</p>
<p>我们来看一个例子,通过这个搜索框,输入学校或者城市,可以搜学校周边或者城市周边的房子。</p>
<p><img src="/img/remote/1460000007025075?w=603&h=261" alt="image_1atlc9j3e1j0a1k6asar5np51e2n.png-51.5kB" title="image_1atlc9j3e1j0a1k6asar5np51e2n.png-51.5kB"></p>
<p>搜索实现的路径,我这里做了最大的简化,只有两种,在以后继续升级的产品形态中,会更加复杂,比如有精确查询和模糊查询,有除了城市和学校以外的经纬度直接查询,有标题查询,也有邮编号码查询等等,他们的搜索显然都是异步的。</p>
<p>那么这个简化的例子,第一条路,输入学校,搜索学校,拿到学校以后搜索周边房源。第二条路,搜索城市,搜索到城市以后,搜城市里面的大学,再搜城市里面的房源。</p>
<p>由于我们不知道用户输入的是学校的类型,还是城市的类型,我们需要两个都查,以学校的结果为主。</p>
<p><img src="/img/remote/1460000007025076?w=1304&h=910" alt="image_1atlcahk91qtn1amg11hosbs1k1k34.png-343.8kB" title="image_1atlcahk91qtn1amg11hosbs1k1k34.png-343.8kB"></p>
<p>如果用 Callback 的方式开发,很容易就写出这样的代码,通过嵌套就强行锁定了搜索的优先级,以及并发和非并发的次序,当然每一个异步查询都要处理一个后置的错误对象判断,这些错误不能进行合并,要分别处理 5 次,有的会中断流程,有的也许不会,加上如果使用 eslint,这里的 err 都需要单独命名,不可以重名,单从维护的角度看,如果以后要调整这里的搜索优先级,就会很头痛,相信这些事情大家都有遇到过,我们再来看第二段代码,这一段我们使用了 Promise 和 Generator Function 结合以后的一个升级版本。</p>
<p><img src="/img/remote/1460000007025077?w=1241&h=889" alt="image_1atlccobh1u5v13i1s6b82tt7t3h.png-288kB" title="image_1atlccobh1u5v13i1s6b82tt7t3h.png-288kB"></p>
<p>很显然,这个升级直接就解决了 Callback 的几个痛点,首先是逻辑可以分拆开来,升级维护更方便,如果先以城市为第一优先级搜索,直接把底下代码整块扔上来就行了,另外,错误的捕获可以合并起来,当然也可以做更精细的控制,同时呢,比如搜索城市大学和城市房源它俩是可以并行的,我们就用 Promise 和 Generator 就能很自然的做到这件事,当然用 callback 也可以集合 eventproxy 或者 async 做流程控制,但是也会进一步引入代码的复杂度。</p>
<p>其实只要解决掉 Callback 的问题,我们就已经往前迈了很大很大一步了,因为我们引入了 Promise ,引入了 Generator Function,甚至可以突进到 await 和 async,这意味着底层的 Nodejs 的版本也会有更大的升级,带来更多编程思路的变化。</p>
<h3>三、Nodejs 跟进升级</h3>
<p><img src="/img/remote/1460000007025078?w=708&h=361" alt="image_1atlcj06b7ig3h7n51p4415t43u.png-130.3kB" title="image_1atlcj06b7ig3h7n51p4415t43u.png-130.3kB"></p>
<p>那么说到 Nodejs 的版本,我的观点是,我们需要保持对 Nodejs 大版本的跟进,因为站在 2016 年的这个节点上,其实 Nodejs 已经经过了 7 年之痒,后面的日子比前面的几年要幸福太多了,这个我可以从自身的一些经验来说下吧:</p>
<p>我从 2013 年开始兼职创业做我们公司的项目,那时候的 Nodejs 版本是 0.8,我一直使用到 2014 年 7 月份,才从 0.8 升级到了 0.10,然后又使用到了 2015 年春节,没有忍住,从 0.10 升级到了 0.12,一直使用到 2016 年 1 月份,再次升级到了 4.x,现在仍然保持在 4.x 的版本状态,我经历了这几次大的版本周期,感觉是这样的。</p>
<p>从 0.10 到 0.12 是一个比较大的飞升,从 0.12 到 4.x 是一个巨大的飞升<br>从 4.x 到 6.x 也将是一个巨大的飞升,当然了, Nodejs 有它特殊的历史进程,比如 0.10 的版本中,有一个重大的安全漏洞,不升级都不行,在 4.x 推出以前,Nodejs 社区还分出来 io.js 阵营,结结实实的对抗了很长时间,再往后面合并后就正常化了,只要官方推了 LTS 版本,在首个 LTS 版本之后,可以观望一个月左右,就可以考虑升级了。</p>
<p>当然,在 LTS 版本升级之前的至少 1 个月,我们本地的开发环境,就应该已经切换到了这个大版本了,在我们本地来开发来测试。</p>
<h4>升级到 6.x</h4>
<p>接下来,我们都会面临 6.x 版本甚至是即将发布的 7.x 版本,官方也罗列了一些重大的变化,我谈下我觉得需要关注的点。</p>
<h5>1. V8 升级到 5.0.x</h5>
<p>每一次版本的升级,都不可例外的,会优化提升整体的性能,包括安全方面的增强,文档的完善,测试用例的覆盖,但是都没有重大的引擎升级来的给力,作为一个 Javascript 运行环境,Nodejs 是依赖于 Chrome V8 引擎进行代码解释,所以 Chrome V8 的能力基本上限定了 Nodejs 的能力,那么这次,相比较于 4.x,6.x 的底层引擎 v8 升级到 5.0.x,这意味着,由于底层 v8 自身的很多缺陷和 Bug 都已经通过大升级而一下子就修复了,所以整个 6.x 的表现会跟 4.x 有很大不同。</p>
<h5>2. 覆盖 93% 的 ES6 特性</h5>
<p>6.x 覆盖 93% ES6 特性,则代表我们可以大胆的使用 es6 的几乎全部特性了,比如 解构,剩余参数,类啊,super 关键字啊,我们知道,往往我们在使用一个库或者框架的时候,甚至是语言,常常用到的总是那 5 成,6 成,顶天了 7 成的 API,就能完全满足我们的业务需要,那么 ES6 的覆盖率如此之高,我们的确可以敞开胸怀,去拥抱 ES6.</p>
<h5>3. 模块加载比 4.x 快 4 倍</h5>
<p>模块加载比 4.x 快 4 倍<br>,如果你是一个项目负责人,或者技术组长,那么这个对于你来讲肯定是有意义的,我们线上应用启动,或者重启的时间会变得更短,让我们的线上服务对用户来说,切换更加的平滑,由重启引起的波动也感知更小。</p>
<p><img src="/img/remote/1460000007025079?w=1388&h=736" alt="image_1atlcugvu1m2r1vn61r66rd21a5v4b.png-226.7kB" title="image_1atlcugvu1m2r1vn61r66rd21a5v4b.png-226.7kB"></p>
<p>然而我们除了从语法层面去避免历史疑难杂症以外,我们更需要关注 Nodejs 版本本身带来的巨大差异和变化,来看一下 Nodejs 这张表,从现在到 2018 年,我们自身的技能是不断增长的,同时我们对于 ES6 的使用和了解会越来越深入,那么我们就应该选择一个未来的版本来切入技能栈,说句老实话,接下来两年我们会持续的在 6.x 的版本上跑我们的项目,那么接下来几个月就是升级线上版本的缓冲期。</p>
<h3>搭积木一样搭建 Nodejs 应用</h3>
<p>当我们把上面的问题都考虑清楚,剩下的事情就变得简单很多,到了 2016 年,我们并不像是在 2014 年之前那样,处在大跃进的年代,太多的变化导致太多的不稳定性,现在社区的生态环境已经相当完善。</p>
<p><img src="/img/remote/1460000007025080?w=732&h=391" alt="image_1atldgp3k1lqu18f5qd51tettjj4o.png-138.8kB" title="image_1atldgp3k1lqu18f5qd51tettjj4o.png-138.8kB"></p>
<p>从静态资源、Web 框架,模板输出,数据库中间件到第三方通信,消息推送各种 SDK 和 CDN 内容分发,都有太多优秀的库可以使用,我们做一些适当的定制和改造便可以拎到项目中大胆使用。</p>
<p><img src="/img/remote/1460000007025081?w=601&h=367" alt="image_1atldqff91q97d7h1pdi1crp1ect55.png-58.8kB" title="image_1atldqff91q97d7h1pdi1crp1ect55.png-58.8kB"></p>
<p>然而当我们把魔爪伸向后端,使用 Nodejs 搭建企业级应用的时候,我们抓过来的不仅是更多的价值体现,我们也抓过来更多的职责和信任,后端底层乃至团队规范都需要我们花费更多的时间去了解对接的方式,接入的阶段,不需要精通,但需要备份为基础的常识,这些软实力,是我们成为一个优秀 Nodejs 工程师的必备要素。</p>
<p>最后,我来对创业公司中使用 Nodejs,做一个小总结,我们在妥善处理了 运维、集群管理、性能调优等等这些传统语言已经做的非常棒非常成熟的领域,在大部分的创业公司,都可以由前端团队推动,来使用 Nodejs 去接管数据访问层与渲染层的事情,等到公司规模上来以后,就可以依靠更资深的工程师以及原来团队的沉淀,来做 比如日志、监控系统、分布式服务接入这些事情,Nodejs 的落地需要前端工程师,需要 Nodejs 工程师,更需要强大的运维之锤,了解除了 JS 以外的更多技能,比如数据库,比如系统的设计,比如接口服务,比如团队规范协作流程等等等等,在大公司可以扎根一个方向挖下去,在小公司则需要放眼天下,筹备未来。</p>
<p>无论是怎样的技术背景,如果有一天你进入创业公司,在立项之初,你都可以先大胆的来做一个假设或者推演,假设说把赌注押到 Nodejs 上,会不会拿到一个更快更好的结果,如果是,请毫不犹豫的选择 Nodejs。</p>
4 年前端狗,2 年 CTO
https://segmentfault.com/a/1190000006723431
2016-08-26T10:35:45+08:00
2016-08-26T10:35:45+08:00
Scott
https://segmentfault.com/u/codingdream
94
<p><img src="/img/bVCnd4?w=960&h=440" alt="图片描述" title="图片描述"><br>图片来自 <a href="https://link.segmentfault.com/?enc=rR5K6U3q5DT2Tun2WsYShA%3D%3D.%2F7SrVMlua69teCWgw0%2BesdFv%2FdW%2BvC%2Brw6aZ0%2FvGwp8%3D" rel="nofollow">http://www.longroad.com.au/</a></p>
<p>我,Scott,一家创业公司的 CTO。</p>
<p>从业 6 年却很少写文章,近一年来接触了几十个刚毕业的前端新人,也面试了 100 多个前端工程师和 Nodejs 工程师,对于前端发展的这个职业算是有些感触吧,打算陆续写一些从业经验也好,技术分享也好,对自己前 6 年的经历做一些文字上的沉淀,按照我工科背景不善修辞的尿性,这些文章很可能凌乱也许更会烂尾,还请误入的童鞋谅解。</p>
<p>这是一篇准鸡汤文,谨献给工作 0 ~ 3 年的前端工程师,内容都是我的亲身经历,不精彩但接地气。</p>
<p>2010 年毕业于一所普通 211 大学,电气学院自动化专业,了解这个专业的大概知道自动化是弱电方向,就业高不成低不就,不读研仅靠本科的技术积累很难进入好单位,而我又是那种一进大学就迷失自我的 “逃课生”,四年逃课挂科无数,不仅荒废了专业,也虚度了青春,彼时年少而又轻狂,骄傲却不知路在何方,唯一的收获是大一便早早的搞定了老婆,恋爱 8 年后领了证,认识到现在已经整整 10 年,所以说码农恋爱要趁早啊。</p>
<p>以上是典型的屌丝工科男背景介绍。。。。。。</p>
<p>如下的一切,都源自毕业实习到了杭州钢铁集团,说是实习其实是见习,带着安全帽到各个生产线上看看钢材生产流程做个笔记,仅此而已。初到杭州,得知我有一个学霸级的高中女同学在杭州淘宝的广告部门实习,就在实习间隙登门拜访,学习求经。</p>
<h2>入行以前</h2>
<h4>贵人点拨改换行业</h4>
<p>见到高中女同学的同时,也结识了她学霸级的男朋友,跟她都同在淘宝,是一名资深的 Java 工程师,他俩知道我对互联网很感兴趣后,便向我口述了淘宝种种开放的职场氛围,有趣的江湖文化,每天发生的每一个故事都深深打动了我,激发起了我对于互联网的兴趣和想要进入淘宝的动力,后面两位开始给我出谋划策,鼓励我从事编程方向,比如 Java 编程,可以从自学开始。其实,早在 2009 年,就有朋友建议我从事前端开发方向,并且帮我选了月影的《Javascript 王者归来》这本大厚书,但是因为不够了解加上没有兴趣支撑,一直放角落里风干积灰,直到如今我也没看完。</p>
<h4>初学 Java 编程</h4>
<p>当时对于 HTML,CSS,Javascript,我其实一无所知,于是决定学习 Java,6 月份毕业后在杭州租了个小房间,每天啃杭州图书馆的 Java 书籍,同时在网上看马士兵老师的 Java 视频教程,陆续跟下来一个小聊天室和仿 QQ 通讯的小软件,但也只是照葫芦画瓢,并没有吃透技术点,心急如焚!加上这两个月窘迫到口袋里只剩下几十块钱,开始每天只吃一顿挂面,也是在这个时期留下了胃溃疡等一堆胃病,快撑不下去了,找工作就势在必行了。</p>
<p><img src="/img/bVCndq?w=774&h=748" alt="clipboard.png" title="clipboard.png"></p>
<p>拖了很久去做的胃镜</p>
<h4>寻找 Java 岗工作</h4>
<p>从 8 月中旬开始逼自己投简历找 Java 工程师的工作,面过的 2 家公司都发了 offer,但薪资都是 1500,不仅是学徒工,更要签 4 年合同且不许毁约,想想有些后怕就跑去找之前提到的学霸女同学求建议,她男朋友建议我可以先考虑试试前端这个岗位,上手快并且我活泼的性格更适合设计相关的工作,回头想想,人生有时候不仅需要运气,更需要贵人点拨,于是当天下午回到住处便开始了为期 2 周的废寝忘食背书模式。</p>
<h4>放弃 Java 投奔前端</h4>
<p>所谓背书模式,其实就是把能搜到的前端知识都手抄到纸上,然后开始背诵,一天到晚脑海中不停的像放电影一样,熟记块状元素和行内元素的区别、绝对定位和相对定位的区别、jQuery 二级下拉菜单的 Javascript 插件代码实现。。。甚至背下了DOCTYPE、几种文档声明的写法,陈年小抄中,还能隐约看到 <strong><em>垂直居中</em></strong> 几个字:<br><img src="/img/bVCnee?w=914&h=590" alt="图片描述" title="图片描述"><br>如果说前面的两个月是信心百倍,有的放矢的充电 Java,那么这两周就是完全是饥不择食,慌不择路的学习前端,在快要被房东赶出去的时候,再次逼自己开始又一轮的找工作。</p>
<h2>面试上岗</h2>
<h4>面试前端岗位</h4>
<p>精心准备了什么都精通的简历,也是第一份前端简历,投给了口碑网(淘宝当时内部新成立的项目)来练手,结果面试官电话里第一个问题就把我问懵逼了:</p>
<blockquote>你知道 IE6 的双边距怎么解决么?</blockquote>
<p>我嘞个大擦!这是什么鬼?!我听都没听过!!!</p>
<p>此时的我,根本不了解原来浏览器竟然有兼容性问题!也根本不知道前端开发是需要对 IE6 的样式和行为写 Hack 脚本进行兼容的(包括 IE7 和 IE8)!</p>
<p>再往后面又问到不同文档类型下的盒模型...,我就像是一个傻子一样,在电话这头大气都不敢出一个,真心想找地缝儿钻进去,气氛尴尬的要死。</p>
<p>面试官看出我啥也不会,便心平气和的给我普及了一下前端开发需要关注的知识点,不出意外的礼貌拒绝了我。</p>
<h4>掉头重新学习前端</h4>
<p>那次面试之后,我的信心受到了巨大打击,也发现了自己和一个哪怕是及格的前端开发工程师,相差的距离是如此的遥远,梦想看着就在眼前,而你臂展不够,各种不好的心理暗示开始浮上心头:</p>
<ul>
<li>淘宝肯定进不去了......</li>
<li>杭州我白来一趟了......</li>
<li>工作肯定找不到了......</li>
<li>爸妈没法骗下去了......</li>
</ul>
<p>此时已是 9 月出头,我亲爱的同学们都已经转正上岗,而我还在原地踟蹰。我只能安慰自己:你是 0 编程基础的新人(大学计算机都是挂的,对于挂计算机课还是略后悔的),不要拿自己和别人比较,这个阶段是正常的,挺过去就好了!</p>
<p>于是我努力回忆面试官的问题,重点突击 IE 兼容性问题,办法依然是背,感谢上苍赋予了我强大的临时抱佛脚能力,从小学到大学,都是以临考突击的方式应对,短期记忆量可以很大,但说忘就忘的一干二净,幸好有面试官的耐心提点,我才有的放矢,后来面试官我们私底下成为了很好的朋友。这一次背书只经历了 3 天 3 夜,对的,不眠不休的记忆,我便又开始新一轮的求职经历。</p>
<h4>第三次求职面试</h4>
<p>这一次花了一下午做简历,只投给了两家小公司,其中一家 HR 效率极高,几个小时候后便电话联系面试。去了后做了一套笔试卷子,我就和公司老总在办公室聊起来了,没想到越聊越嗨,为什么呢,因为我俩聊的是足球,我大学一直是院队主力左后卫,踢了四年校联赛,于是跟这个老总在足球这个话题上开始投机。</p>
<p>有时人生真是捉摸不定的曲折离奇啊,第二天中午我便拿到了这家公司的 offer,但 offer 的内容是:</p>
<blockquote>把你外派到淘宝当外包,你愿意不愿意?工资会比较低</blockquote>
<p>当下才知道这家公司是外包公司,思前想后,决定还是接受这个 offer,即便薪资低的可怜,勉强够交房租。</p>
<p>不过这只是第一关,还需要到淘宝去参加第二轮面试,被淘宝面试选中才能最终获得外派资格,于是屁颠屁颠跑到华星科技面试,开始依然是做了一套笔试题,面试官看完我答的卷子后是这样跟我讲的: 果然是刚毕业的学生,卷子填的满满的,但是题目全部做错了,又问了我 apply 和 call 的区别,我自然是不会的,甚至连上下文都搞不清楚是啥意思,只知道它俩传参的区别,于是面试官问我其他方面的,比如为啥从事这个职业之类的,我拼尽全力声情并茂讲述我的求职渴望,这也是我唯一可以讲的东西了。</p>
<p>走出华星科技大厦,心情是灰色的,感觉就要和淘宝真正的 say byebye 了,背的知识点遇到资深的面试官随便一挖,我便原形毕露伪装失败,越想越伤心,此时竟然雷声大作瓢泼大雨没头没脑哗啦啦的下起来了,我把档案塑料袋顶在头上,默默的往家走,躲雨的心情都没有,脑海中一片空白,雨越下越大,迷住了前面的道路,迷住了我的视线...</p>
<h4>雨过天晴</h4>
<p>人生是如此的曲折离奇,第二天便接到通知,淘宝竟然要我了!于是跑到外包公司签了就业合同便去淘宝报道了,此时是 2010 年 9 月 6 号,到了淘宝才意外发现,我竟然跟之前的学霸女同学在同一个大部门 - 淘宝广告事业部,人生处处是惊喜,一言不合就相遇。</p>
<p>自此我开始了 4 年的前端工程师之旅。</p>
<p>自知才疏学浅,我进入部门后,也是尽量的谦虚做人,不懂就问,跟同事好好相处,同事帮我解决了一个问题,我就基于这个问题,晚上到家后,根据他的解决思路,把所有相关的知识点,全部在百度搜一遍(那时候还不会科学上网),如此坚持了一年,这第一年技术也成长迅速,在外包公司的工程师队伍里已经是走在最前列了,那么外包公司也是给出较大幅度的涨薪,但是跟阿里正式的前端工程师待遇依然不可同日而语,毕竟是外包,要赚你的人头费,不过之后没多久淘宝觉得我已经完全达到正式工程师的水准了,便赔了外包公司一笔钱(这个我没考证,是听外包同事说的),于是我就欢天喜地的转正成为淘宝正式员工,但和外包公司老总依然成为了很好的朋友,同时也组建了这家公司成立以来的第一支球队,作为队长我带领外包公司的球队在杭州城参加各种比赛,虽然胜负参半也没拿到太好的成绩,但是跟这一波外包公司的队员一起风吹日晒, 建立了珍贵的革命友情,后来随着转正淘宝正式员工并且加入了淘宝的球队之后,跟老球队一起踢球的次数越来越少了...</p>
<h2>职业沉淀</h2>
<h4>4 年阿里前端生涯</h4>
<p>铺垫了那么多转行求职历程,其实只是为了说明,我是非常普通的一个人,跟所有的求职者经历不同但起点类似,有提心吊胆,有惊喜连连,有彷徨失落,有坚决果敢...,但选择了前端开发,无论它是不是不归路,都是我自认为的一条很适合自己的路,认识到这一点,就要铁了心走下去。</p>
<p>在阿里的四年,最大的收获是见识到了什么是大牛。在公众视野中不少活跃的各种圈内牛人红人(包括我自己,有些新人认为我很牛),接触下来其实根本比不上大公司里那些低调做事的大牛,他们做人做事,对自己的定位、要求和产出,总是能让我意识到自己的种种不足——不够谦虚不够努力。如果说这是榜样的力量,ok,那我承认与优秀的人共事总是十分难忘的经历,而我自己作为一个普通的工程师,自认够努力,但还远不够优秀,也许是天分不足,也许是尘世扰心,我的职业瓶颈还是早早出现,而要迈过去需要更长时间。</p>
<p>在工作 2 年左右,我发现自己在技术深度上很难有专业造诣的时候,我开始把眼光放的更长远,我不再把自己仅仅定位成一个前端工程师,而是会开始关心互联网的发展趋势与整体格局,关心产品从 0 到 1 诞生过程中的盈利模式,关心在产品迭代中工程师与运营多方参与的角度和结合的效率,关心工作流程和团队文化,这一切其实都是我潜意识不自觉的关注,是一种不安分,过后很久才逐渐意识到自己早就在默默铺路,有时候一个选择早就做了,只是你还未意识到。</p>
<p>那么对于技术这个领域,我也开始去关注更多非前端的生态,从 Linux 生产环境配置部署到域名解析,到软文策略和 SEO 推广,从移动端、 PC 端的前端分离和架构,去折腾 PHP 的 Wordpress,Codeigniter...,折腾 Ruby on Rails,直到接触到 Nodejs,尝试借助 Nodejs 拉上 Mongodb 做数据接口,和模板输出的工作,从数据库的安装到主从灾备,不求精通只求通,下班的无数的晚上和周末,在屏幕前消耗青春,通过乱七八糟的折腾这一系列有的没的,我逐渐意识到自己可以创造的价值不再是仅仅前端页面的输出,这个价值不单单是指可以一己之力搭建一个完整的网站,而是有了前后的动手经验,能从更高的一个层次上去把握一个项目以什么样的形式去设计,以什么样的思路去迭代会更加的省时省力,这个省时省力其实能更好的促成产品,拿到商业目标,而有了这个意识,就能更好的配合产品经理实现他脑海中的想法,如果你认为是不切实际海阔天空的想法,没关系,来小成本验证一下,验证之后说不定就真的是海阔天空,也是这种想法促使我业余时间结交了许许多多的朋友,以兼职的方式参与了至少 3 个小创业项目,自己的技术面和技术深度也得到了很大的拓展。</p>
<h4>发掘自己的更大价值</h4>
<p>当聚焦的点不再单单是前端开发的时候,我发现了更多的乐趣和更多的可能性,从前,我会花好几天反复测试一个广告投放模板,对于里面的一个模块加载器或者特效组件如何去设计才能最小化体积,减少展示延迟,最大化优化动画流畅度,针对移动端的广告投放用哪些效果兼容性最好最省电这些细碎的点占据着我工作的大部分时间,必须承认,解决这些技术点是很有成就感的,但是技术的革新速度实在太快了,昨天还在纠结的几 K 大小带来的网络延迟、代码执行效率带来的性能消耗,今天突然在百兆宽带甚至是 4G 大水管高规格硬件时代变得不那么敏感了,昨天还是小心翼翼使用 radius 圆角图片两套并存的兼容方案,今天 CSS3 属性放开随便用,这些当然是我们需要不断更新的知识栈,但仔细想来,让我花费数倍的时间去研究底层的优化细节,跟实现我的个人价值放到一起的时候,是不是最佳的途径呢?很多类似的技术问题,我可能需要花费 2 天,而天分好的同事,只需要花费 1 天甚至更少,从这一点上,我越来越不认可自己的技术方向和优势,于是我摘掉带有职业界限的眼镜去看待彼此的分工,带着合作共赢的心态去接触更多的领域,包括前面我提到的小创业团队,他们都没有能够生存下来,有的是因为技术原因,而有的是因为资源问题,参与这些项目也给了我更多的感触,让我逐渐明白想要做好一件事情,是要先定位实现的程度也就是预期目标,这个不同时期的目标完全取决于不同时期的资源配置,平衡追求这个性价比才是做事的关键,说白了,就是知道什么可为不可为,外加一些方法论。</p>
<h2>创业萌芽</h2>
<h4>职业波动期</h4>
<p>在阿里工作的第 3 年节点上,我萌生了创业的想法,但并没有机会也没有胆量迈出这一步,并且就在这个第三年中,我在阿里迎来了职业生涯中最心旷神怡的几个月,被分配到了技术非常优秀的主管,也开始参与更有挑战性的项目,个人技术成长越来越快,无论是前端开发能力,还是后端开发能力,然而好光景持续了仅仅几个月,便被分派去支持双 11、双 12 推广会场。在阿里这种变化是常态,业务支持永远是第一位的,因为客户永远是第一位的,所以抽调出来支持一个活动是很正常的,我起初也是很平静的参与这个项目,然而这个活动的历程却充满了心酸,耗尽了我的耐心。</p>
<p>成长受阻,陷于无序的需求算是一个促使我做出离职创业的导火索吧,另外一个重要原因则是遵从内心的创业冲动,后文会写到。</p>
<p>关于这个项目呢,原本是提前了 2 个月筹备这个活动,从后端数据到前端和运营,全部到位了,虽然前端在里面扮演的角色很关键,但技术难度却并不高,工作量也不大,就是把页面过来时候带的参数,按照规则梳理一下,发一些请求到后端,拿到加密值然后重新替换到页面里的所有 a 标签 href 中,也就是刷页面参数,然后把这套代码抽象成组件,集成到一个大系统里面,根据不同的会场类型加载不同的刷参逻辑。</p>
<p>原本是 3 周做完的项目,用了整整 7 周的时间才最终落定下来,主要原因是产品经理更换了 3 个,需求方大 Boss 介入了好几次,项目经理风险意识不够导致工作不断重做,解释成本也因此居高不下。每一次联调出问题,都先会把责任全部抛过来丢给前端,也就是我,然后每一次我都要反过来充当半个项目经理的角色,去 push 各个参与的团队来配合我核查问题的来源,而每一次查出来后要么是后端数据环境更改异常,要么是数据引擎切换引发不兼容,要么是产品设计规则不全出现参数漏洞,总之就是项目负责人的不专业,加上团队协作的成本高,导致参与的人都做的不开心,其实在这之前也参与过类似这样的扯皮的延期项目,然而这一次对于我却尤其难熬。</p>
<h4>挣扎在白天黑夜边缘</h4>
<p>在双 11 项目远没开始的时候,我接触到了一个创业项目,兼职赚外快补贴家用,平时的晚上和周末断断续续在做,大概到了 10 月份,这个项目准备去找融资,因此希望我在 10 ~ 12 月份能尽快把项目原型开发上线,我评估了一下剩余的工作量,差不多需要 15 人日,同时算了一下时间,10 月份至少有 3 周的空闲周末,还不算晚上,再加上 11 月份甚至 12 月份的晚上和周末大概能有 20 多天的时间,时间简直不能再充裕了,于是便也一口答应了下来。</p>
<p>然而这个从双 11 前就启动,一直持续到双 12 的公司项目,却频频上线出问题,而每一次出问题,都需要前端工程师介入联调,于是几乎所有的周末全部都被公司征用,不止如此,白天只能调试,不能发布,需要熬夜发布,出问题后还要配合回滚,回滚后,还是不能走,要等测试工程师测试完,再重复以上过程,于是就有了连续的周末通宵,这个答应在 12 月份上线的创业项目,便搁浅了,毕竟公司事大,孰轻孰重我还是分的清楚。</p>
<p>总算双 12 上线一周后,我下班回到久违的家中,眼看要延误掉这个创业项目的融资窗口,我想既然承诺了,无论如何都要拿下!于是,白天去公司工作,幸好是双 12 之后,这个项目不再变动了,每天只需要配合调整策略参数就行,不需要投入大精力去开发。晚上回家以后,7 点开始写代码赶这个创业项目,敲代码一口气通宵到到第二天早上 6 点,洗漱一下出门到公司吃个早餐,然后在公司躺椅上睡到 9 点,起来洗把脸,冲上浓咖啡,配合这个双 12 的 项目继续做沟通啊,邮件通报啊,参数更正啊这些琐碎的事情,中午吃过饭,又在躺椅上睡一个小时,下午跟进一些常规的部门工作,晚上回家后继续写代码,如此反复,经历了大概 12 天,期间至少有 2 次半夜敲着敲着代码就一头栽在桌子上睡着了zzz。要预发布创业项目的那个晚上,需要跑通发布环境,我买了一箱的红牛,一夜喝了 5 罐,凌晨 4 点,突然一阵恍惚,有一种灵魂出窍的感觉,手脚冰麻,说不出一句话,视力急速下降,那一刻,我想,我怕是要猝死了。</p>
<p>在这种症状持续的 2 分钟时间里,我心里怕到了极点,想了许多许多,如果我猝死了,父母怎么办?外婆怎么办?我的事业怎么办?这个项目怎么办?我闭上双眼,让自己使劲喘气,慢慢的回过神来,然后起来走动了一下,狠了狠心,继续折腾发布环境,差不多 7 点多,环境弄好后,就洗个脸到了公司。这一次到公司没敢睡觉,担心躺下了会彻底体力崩溃,就咬牙坚持了 1 天,晚上回家又熬夜大概到 2 点,成功发布上线,整个心才真的像大石头一样放了下来,顿时困倦无比,迷迷糊糊正打算去睡,突然又发现一个环境异常问题,赶紧屏住呼吸紧急调试,这一次调试的每一秒钟我都记忆深刻,因为我需要把已经休眠的身体和意识拉回来,大概 5 分钟左右重新修复上线,我给公司主管发了短信上午在家请假休息,就混沌沌的睡去了。</p>
<p>大概 2 周后,这个上线的创业项目拿到了 200 多万的天使投资,这个就是促使我做出出来创业的重要原因吧,这也是我目前正在创业的项目。</p>
<h4>离职创业</h4>
<p>在大公司当一颗螺丝钉,其实我并没什么不爽,但当发现一些不好的兆头或者流程大问题的时候,由于我人微言轻,再好的技术,或者说再好的工作态度都无法改善这个情况,我做了反馈但所有人都摇头,我做了推动但所有人都表示无能为力,这种无力感越来越强,我发现除了被我抓在手中的这些前端技能和可怜的工资,我什么也没有,什么也做不到,我开始怀疑人生,是坚持死磕到公司上市死磕到自己在公司和团队有更好的能力和话语权,还是选择离开。</p>
<p>这时候已经是 2014 年春天,我重新开始考虑去向,这时候年前参与的创业项目投资到位了,我也基本了解了它的业务模式,可能是年前拼命赶项目那次太投入,导致我对它也有很深的感情,毕竟是自己一手写出来的代码,是自己一手养大的孩子,这时候对方希望我以技术合伙人的身份加入,我最终想了想便答应了,其实还是有点冲动的,因为恰恰是那个时候是我在公司做项目最不爽的时候,在公司的无力感和在创业项目上的认同感成就感形成了鲜明的对比。</p>
<p>Anyway,我是希望可以通过我的力量,证明一些或者是实现一些我的想法,我希望可以有一些事情是可以在我影响和控制范围之内的,于是到了 6 月份,也就是阿里巴巴上市前夕,我递交了辞职书,这次走的虽有留恋但是毫无遗憾。</p>
<h4>创业狗的日常</h4>
<p>创业到今天,已经两年多,走的并不轻松,而创业两个字跟 CTO 一样,都是听起来真的很高大上,但是做的事情可能是灰突突的并无新意,唯一不同的时候,这是一条踩在我自己脚下的路,我走快一点就看到目标近一些,我走慢一些,就看到远方模糊一些。</p>
<p>创业有太多的不确定性,最大的不确定性就是能否兼顾好自己的身体和家庭,因为无论是时间投入还是资金回报,都是看公司状况和市场反应,所以像 i5ting 这样的 CTO 也要出书立作,也要有在线课堂,在拓宽人脉影响力和技术布道修炼的同时,也可以赚点小钱贴补家用,没错,就是贴补家用,不要以为创业公司合伙人都是高富帅,白富美,其实我认识的不少也仅仅是够花,甚至是穷屌丝,我也不例外,所以和慕课网合作讲授自己的前端实战经验,以下是我 2015 年底起业余时间录制的一些 Nodejs 进阶学习课程—— <a href="https://link.segmentfault.com/?enc=JqKMM6EGZvJXQYgdidYwHQ%3D%3D.27wkiNIWutJ8ow4pb75eaX2EWz%2Fn6zfFD7FousDh8bY%3D" rel="nofollow">《Nodejs 上线部署/React Native/Koa2/7天搞定 Nodejs 微信公众号开发等》</a>,刚入行的新人可以参考我这个老人开发一个小项目的切入方向,开发功能所涉猎的角度,以及推进的方式是怎样的,如果你资金尚且充足,对知识又充满渴望,不妨看看这个视频课程,支持下我这个所谓的创业狗 - 草根 CTO,这是个硬广,对,说到硬广,我这一年来招进来的员工,还真的的确是看过我慕课网 Nodejs 课程入门这个行业的,所以我还是很欣慰的,其他的一些 Nodejs 课程是 2 年前创业前后边做项目边录制的,其实比较过时了,居然还可以帮助到入行的新人,我已经很满足了。</p>
<h4>写在后面的话 - 所谓 CTO 的称谓</h4>
<p>对外面我总是宣称自己是这家创业公司的 CTO,而对朋友和同事,我总是希望大家把我当成一个普通的程序员看待。因为对外,可以树立公司的形象和减小解释成本,这个 CTO 的 title 有明显的代入感,而对身边朋友,包括对我自己来讲其实它意义不大,我丝毫不认为有一顶 CTO 的帽子在头上,技术就能牛逼几分,身价就能增加几分,相反,有这顶帽子在头上,带给我更多的是一种责任,而恰恰,我慢慢成为了一个有责任感爆棚的人。在技术方面,我始终不认为自己可以配上 CTO 这个称谓,只不过对当下这个团队这样的业务规模,我尚可以完全 handle 住,但至于未来会怎样,依然还是个未知数。</p>
<p>后面我的文章,可以聊一聊我是怎么学习 Nodejs,我是怎么学习某些技术点,我是怎么对待技术和创业的结合,我是怎么看待毕业后 0 基础,如何选型如何切入到前端这个行业,等等等等吧,大家不要寄希望,我是烂尾王,哈哈哈。技术路漫漫且修远,吾将上下而求索,与各位共勉。</p>
<p>我应该会在简书、segmentfault 等平台进行发布,转载本文章请注明出处。</p>