# 2019 年度总结

2019年主要分为两个阶段，5月份之前在体验技术部，小钱袋相关开发。5月转岗到保险事业部，在相互宝项目组中，真正体验到大规模用户产品业务场景。

## 小钱袋

在体验技术部做面向 c 端的产品，没有太大的外部业务压力。随着越来越多的渠道流量接入，当时看来 100w 日活的目标还是容易实现的。

这一段时间，探索完成硬件接入，这条路基本走通了，硬件的开发并没有我们想象中那么高不可攀。底层资金账户功能逐步优化(完成多人转入开发)，用户反馈最多的问题也慢慢解决，技术上，我们开始接触资金操作，技术稳定性上，更加可靠了。 但这一切随着一次意外的用户反馈事件之后都改变了，随后小钱袋业务确定转交给余额宝团队。

### 多人转入

小钱袋这一段时间业务上终于实现了多人转入功能，这是我们第一次处理资金相关功能。这个功能最大的难点在于我们需要**串联两个支付流程，并且保障资金逆向流程正确**。最大的风险点在于资金如果处理不当，可能导致用户资金被锁定，无法使用。

 ![image.png](https://iling.fun/api/files.get?sig=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1cGxvYWRzL2MyMzFmODM0LTY3ZGQtNGJjZi1iM2RmLWYxMTQ2NGUxM2Y0MS9kZTMxN2Q5MS0zN2UzLTRlMmMtYTdiNy0zN2ZlYjJkMzdkY2YvaW1hZ2UucG5nIiwidHlwZSI6ImF0dGFjaG1lbnQiLCJpYXQiOjE3OTA0Mzg0MDAsImV4cCI6MTc5MDUyNDgwMH0.ykUFQ5OXP5RU-vWO_xJIX0cmQJzv2lK1aL0Q64o9jlw)

资金链路上两个阶段，这两个阶段是分裂的，第一阶段转账并冻结到余额，第二阶段解冻并转入到余额宝子卡。如果第二阶段失败，余额宝退回到最初冻结到余额状态，这一部分无法再退回到原用户相互，只能由小钱袋负责解冻。

这些功能本来应该基于分布式事务来处理，支付失败，直接原路退回，但是 chair 应用是无法接入分布式事物。在当时的情况下，只能依赖我们的应用来处理异常情况了。最终，通过定期任务定期清理异常订单加上离线核对两个措施，来人肉完成分布式事务所完成的事情。最终上线运行，功能还算稳定。

### czone 部署

此外，我们开始为未来一年做技术贮备了，同时基于业务上考虑，我们开始准备做 czone 部署，数据库缓存，应用功能拆分这些事情了。

czone 部署应用对于应用本身来说改动不大，只是数据库改成 gzone 写，czone 读模式，在 czone 每个机房部署一个只读数据库副本。实际上，这种部署模式未来是支持更大量用户并发访问的，可以在 czone 部署读接口，这样数据库压力会小很多。

czone 部署完成后，财富 tr 接口时间从 30ms 减少到 10ms 以内，但根本的问题却是财富卡片来的用户却越来越少了。依托于公司基础设施，要做大流量、多用户应用本身并不难，最难的是业务问题，如何把用户拉进来。

### 总结

财年快结束的时候，小钱袋业务最终确定转出去了，我们开始做交接工作，同时拾锋找我分享一下。于是整理了一下小钱袋这两年做的[技术经验](https://www.yuque.com/eward/bt8ny4/wvu1hw)。

业务突然停止，然后开始回头总结，这种感觉和做了将近三年凤蝶后转去其他组的时候有点像。我都留下一个维护了两年的应用给后面人接手，但是我希望，这次这个应用不至于留下那么多坑了。

小钱袋技术上，最重要的是基于 TypeScript 开发，在这之上，我们开始引入依赖注入的方式管理服务。同时对服务进行了更细致的分层，服务端单向依赖，这个架构图是核心了

 ![image.png](https://iling.fun/api/files.get?sig=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1cGxvYWRzL2MyMzFmODM0LTY3ZGQtNGJjZi1iM2RmLWYxMTQ2NGUxM2Y0MS8xOTA3MmZlMi1jNzAyLTQ0NGUtODVlMi0wMmM0M2ZiMjgyMDcvaW1hZ2UucG5nIiwidHlwZSI6ImF0dGFjaG1lbnQiLCJpYXQiOjE3OTA0Mzg0MDAsImV4cCI6MTc5MDUyNDgwMH0.kJUEP2wOC2ug9NNdiRPC6ovvLFfBMhK7USKMwW1HrZU)

服务单向依赖，这也解决了最初引入依赖注入的时候遇到的循环依赖的问题。在最初模式下，很容易就会写出循环依赖的代码。在使用依赖注入后，这种问题会越来越难受，每次引入一个服务，我们需要不停地关注这个服务是否有间接的循环依赖。

最终，两年的小钱袋应用开发经验，整理成一文总结后，我踏上了去往保险业务线的路了。一方面，当时对保险行业、对相互宝的兴趣使然，另外一方面，感觉在体验技术部这五年，做的凤蝶和小钱袋，实际上是在做类似事情，都是服务业务逻辑的 chair 应用，也是时候换换环境了。

## 相互宝

来到保险，主要负责相互宝业务开发。正赶上产品功能基本完善的时候，最开始做了一两个小需求，后来来了一个大项目，再后来来了一堆大项目，半年时间，整个相互宝应用基本重做了一遍。

总的来说，主要可以分为业务和技术两个维度，两者相辅相成。技术的核心是解决业务问题，如何使用技术，如何更高效是技术上关注之处。

### 加入链路改造

加入流程优化，是当时接手的第一个项目，评审阶段整体项目节奏看起来还是正常的，大家对这次改造都比较看好，产品经理还信誓旦旦的说，这次加入流程改造，至少坚持一年不动。

最终开发节奏并不顺利，到了交付提测的时候还有好多功能没做好，系分的时候考虑不周，没有考虑到新系统开发成本。但也没有办法，我们的技改也没法占用太多的时间，业务部门对于时间要求还是更严格的。

后面只能喊对二帮忙一起拼命补位、修复 bug 了。但到了快发布的时候，整个项目的目标变更了。又重新修改，灰度测试了两周，在7月10号终于全量发布了。发布后加入量暴跌，当天不停修改了，发了好几次。现在回想起来，只觉得当时头晕晕的，发布那天一直在修复 bug ，重新发版。

第一次上线搞得和打仗似的，运营看着加入量跌了，愁眉苦脸了一整天。我本来还想着出国 outing 的，最终连国内团都无心参加了，这是我加入阿里以来第一次错过团建，也是第一次做产品做出了打仗的感觉。后来加入链路为了开通量又改了无数次，这个号称能用半年的版本的代码两三个月后就被删光了。

### 公示链路改造

这是我们做的第二个项目，第二场仗，从开通链路之后开启了相互宝整体产品重构之路了，一直到九月份心智之战。

公示链路改造主要是对二在负责，整体进度还算正常。发布是为了赶上7月21的公示日，那时候对二刚好去日本 outing 了。当天 0 点状态切换后，对二远在日本发现问题，立马拉群排查。到早上凌晨修复完成，服务端重新发布。

那个周日，服务端问题修复后，前端又爆出两个问题。小课堂 banner 高度错误和白屏率暴涨，第一个问题好解决，第二个问题有些不知道从何入手。以前从来没接触过白屏率，也不大清楚容器那边的判断标准。但群里说，如果一直不解决将导致故障等级上升，只能停止公示 card 消息发送了。

最终，客户端开发给出一些建议，我们修复后白屏率慢慢跌下来了。修复方式也很简单，页面不等待 rpc 接口，直接渲染一些占位的 dom 结点。从容器角度来说，白屏是不可接受的，我们的页面必须不依赖 rpc 接口。

最终公示经过一整天的折腾，终于趋于稳定了。现在想想，仿佛又回到了当时那种紧绷的状态，周末完全没有了周末的感觉。

### 其他

再后来，我们又连续做了退出链路改造、首页改版、开通链路二期连续几个项目，以及一堆的日常小需求集合、营销活动，一直到八月份的心智之战。

这一段时间我们一直处于紧绷状态中，每个人都并发至少两个需求。在开发中的需求和评审中的需求中不停的切换，靠我们当时几个人已经完全无法支撑了。只能依靠大团队一起帮忙抗了，到最后心智之战，全组人基本都加入进来了。

我们和业务方、测试技术沟通更频繁，交流更紧密了。团队内部也同样，我们慢慢形成了加班越忙，越需要在饭后一起爬山的习惯。一方面可以放松一些紧绷的神经，另一方面也锻炼锻炼身体，毕竟身体是一切的基础。正如亦池所说，我们几个开发有了一种战友的感觉。

最终，我们在6月份到8月份这三个月时间，把相互宝 90% 的逻辑重新实现了一遍，首页和开通页还都做了不下两个大版本。这样的节奏，前端真是太难了，这一段时间大家都辛苦了。尤其是对二和亦池，都是新加入蚂蚁没多久，经过初期一个月短暂的磨合，很快就能进入到能 hold 住大项目的状态了。

心智之战之后，业务上慢慢平稳一些，主要是小需求集合加营销互动开发，我们开始有一些时间投入考虑技术上提升了。

### 技术发展

#### TypeScript

技术上来到相互宝后，做的第一个重要的事情是把 insxhbbff 应用基于 TypeScript 搭建起来。小钱袋积累的 chair TypeScript 开发经验引入到了保险，慢慢的有越来越的应用开始往 TypeScript 迁移，这个大的方向大家是认可的。

TypeScript 可以提高稳定性，减少代码沟通成本，这一点已经毋庸置疑，算是共识了，但真正使用好 TypeScript 不是那么容易，很多 chair 应用只不过把文件后缀改了一下。判断的一个标准是类型完备程度，如果搞一堆 any ，那其实和 js 没什么区别。所以仅仅引入 TypeScript 还是不够的，在团队内部有过一次分享 ts ，但是关于如何使用还是需要有更多的介绍才行了，未来还需要再做一些更多的推广。

在保险服务端应用上，我发现 jar2proxy 解析得到的类型声明文件会丢失泛型。而保险所有的应用都是有通用的返回结构，这个结构肯定是包含泛型的。**类型不完备，这一点是不可忍受的**。我这边断断续续改了一下 jar2proxy ，终于补上了这一块的缺陷，同时修复了以前一个陈年老 bug 。

#### tr-snapshot

此外，针对 bff 应用的特征，数据都是来源于外部服务，对测试用例进行了改造，完成了 tr-snapshot 的开发，在组内进行了[一次分享](https://www.yuque.com/eward/bt8ny4/iikc68)。tr-snapshot 实现并不难，最关键的是测试的使用方式。我们应该**使用测试用例来联调，来排查线上问题，来验证 bug 修复，这种意识是最重要的**。

tr-snapshot 其实只是一个简单的工具，没几行代码，它能解决的也只是使用用例更加方便一些而已，真正的代码效率提升还是需要从业务本身抽象来考虑了。TypeScript 也只能解决可维护性问题，bff 业务面临的问题还是一样存在的。

#### model-bus

在一次和皋天讨论中，他提到他们喜欢用的 common.invoke ，通过一个 rpc 接口动态转发到 proxy ，形成一个通用的透传 proxy 接口。这个想法，我一开始觉得有些黑科技，有点不符合常理，如果 bff 都是这种逻辑，那是不是 bff 层本身存在的意义没有了。

后来再仔细一想，这种需求确实是存在的，很多简单的接口，就是做透传，这并不影响 bff 本身处理数据的必要性。我隐隐约约觉得这其实是很好的一个思路，可以解决 bff 模板化代码过多的问题。后来，我慢慢把目光聚焦在这一个问题上，尝试解决 bff 开发效率问题。

最终，我完成了 model-bus ，把 bff 的开发重心从页面接口改为数据模型开发。这一套理念还在实践过程中，但我相信这个方式是能解决很多问题的，未来一年继续前行吧。

### 总结

在相互宝这半年多，很辛苦，也蛮充实的。在匆忙的业务中，最大的快乐就是能够沉淀一些技术实践了，这些业务场景是我以前不曾遇到过的，也想不到的。这一段时间接触了更多的其他合作方，产品、测试、服务端，在这里遇到了我见过的专业的 pd ，以及他那可以当系分的 prd ，和大家一起合作挺开心的。

## 个人

个人生活上，今年宝宝两岁了，已经慢慢会说话，和我吵架了，感觉挺神奇的，这么一个小人慢慢有了自我意识。

今年和家人一起旅游了两次，一次千岛湖，一次海南。海南还是很适合一家人出游的，那样的天气和大海，甚至让我有些渴望住在海口了。拖家带口的出游和以前两个人一起出去玩，差异是非常大的，有了娃，看着她开心的走来走去，我们一家就觉得非常开心。我爸说过很多次想去看看大海，终于帮他实现愿望了，他也很开心，还在海里游泳了很久。

此外，最重要的事情，第二个宝宝怀上了，感觉压力有些大，两个娃还是很烧钱，费精力的。还好有家人支持，帮忙带娃。

新的一年，希望自己能够更加平和，我还是不太擅长控制情绪，太容易激动了。

---

**Documents**

- [基于实践谈谈软件架构设计](https://iling.fun/s/blog/doc/5z65lqo5a6e6le16lci6lci6l2v5lu25p625p6e6k66k6h-tsGrQnNSNu)
- [rspack 使用体验过程](https://iling.fun/s/blog/doc/rspack-u8S4Mtjkfz)
- [E2E test with Playwright](https://iling.fun/s/blog/doc/e2e-test-with-playwright-JLFKAvWQ0U)
- [Vim everywhere](https://iling.fun/s/blog/doc/vim-everywhere-v6WZyLzGA1)
- [滴答 FaaS 研发平台小结](https://iling.fun/s/blog/doc/faas-XQxhEO3e5r)
- [Cod 服务编排之路](https://iling.fun/s/blog/doc/cod-0CFsOfiX20)
- [Cod 起源和用武之地](https://iling.fun/s/blog/doc/cod-1aAA2rVJZY)
- [2019 年度总结](https://iling.fun/s/blog/doc/2019-RhbTD2SiCn)
- [凤蝶区块历史及其问题排查记录](https://iling.fun/s/blog/doc/5yek6j225yy65z2x5y6g5yy5yk5yw26zeu6aky5o6s5pl6k6w5b2v-WoaaJ9QHpq)
- [如何用单元测试](https://iling.fun/s/blog/doc/5aac5l2v55so5y2v5ywd5rwl6kv-3zwG1cJvTn)
- [小钱袋 Node 应用开发经验总结](https://iling.fun/s/blog/doc/node-QpFfYCuoE0)
- [简单 JS 算数表达式求值算法的实现探索](https://iling.fun/s/blog/doc/js-FXcWkpW2vw)
- [凤蝶可视化编辑实现原理](https://iling.fun/s/blog/doc/5yek6j225yv6keg5yyw57yw6l6r5a6e546w5y6f55cg-ZsBj0CS1ev)
- [凤蝶服务端渲染经验总结二](https://iling.fun/s/blog/doc/5yek6j225pyn5yqh56uv5riy5pt57up6aqm5oc757ut5lqm-a4Kd59d7Td)
- [凤蝶服务端渲染经验总结](https://iling.fun/s/blog/doc/5yek6j225pyn5yqh56uv5riy5pt57up6aqm5oc757ut-GBhTESymbn)
- [Node.js 中 sourcemap 使用问题总结](https://iling.fun/s/blog/doc/nodejs-sourcemap-duex3wDhWt)
- [如何实现一个 mvvm 组件](https://iling.fun/s/blog/doc/mvvm-8TXAVSXe77)
- [webpack 热加载原理探索](https://iling.fun/s/blog/doc/webpack-7Wjn9z1fUB)
- [再谈 vim](https://iling.fun/s/blog/doc/vim-UBf5u57ko7)
- [How to realize velocity template interpreters](https://iling.fun/s/blog/doc/how-to-realize-velocity-template-interpreters-4s1KEznjYR)
- [joycss](https://iling.fun/s/blog/doc/joycss-bGvBvDGF7k)