Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Refactoring lesson : from GPA 1.4 to GPA 3.0
Search
Yi-Ting Cheng
September 24, 2016
Technology
8
1.6k
Refactoring lesson : from GPA 1.4 to GPA 3.0
RubyConf China 2016 - Xdite
Yi-Ting Cheng
September 24, 2016
Tweet
Share
More Decks by Yi-Ting Cheng
See All by Yi-Ting Cheng
Blitzbuilding Product with Rails
xdite
2
1.6k
第六屆做自己論壇 - Xdite 鄭伊廷
xdite
4
5.7k
全棧班畢業贈語
xdite
1
40k
Intro to RedPotion
xdite
0
250
莫拉克颱風災情支援網
xdite
1
350
Intro to self Growth Hack
xdite
61
20k
Building a workshop / community
xdite
6
1.2k
Building SaaS using Rails
xdite
15
2.1k
Maintainable_Rails_View.pdf
xdite
29
2.3k
Other Decks in Technology
See All in Technology
SRE×AIOpsを始めよう!GuardDutyによるお手軽脅威検出
amixedcolor
0
150
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
2
1.7k
初心者向けAWS Securityの勉強会mini Security-JAWSを9ヶ月ぐらい実施してきての近況
cmusudakeisuke
0
130
リンクアンドモチベーション ソフトウェアエンジニア向け紹介資料 / Introduction to Link and Motivation for Software Engineers
lmi
4
300k
RubyのWebアプリケーションを50倍速くする方法 / How to Make a Ruby Web Application 50 Times Faster
hogelog
3
950
Amplify Gen2 Deep Dive / バックエンドの型をいかにしてフロントエンドへ伝えるか #TSKaigi #TSKaigiKansai #AWSAmplifyJP
tacck
PRO
0
390
第1回 国土交通省 データコンペ参加者向け勉強会③- Snowflake x estie編 -
estie
0
130
TanStack Routerに移行するのかい しないのかい、どっちなんだい! / Are you going to migrate to TanStack Router or not? Which one is it?
kaminashi
0
600
エンジニア人生の拡張性を高める 「探索型キャリア設計」の提案
tenshoku_draft
1
130
マルチモーダル / AI Agent / LLMOps 3つの技術トレンドで理解するLLMの今後の展望
hirosatogamo
37
12k
The Role of Developer Relations in AI Product Success.
giftojabu1
1
130
Zennのパフォーマンスモニタリングでやっていること
ryosukeigarashi
0
140
Featured
See All Featured
Art, The Web, and Tiny UX
lynnandtonic
297
20k
Site-Speed That Sticks
csswizardry
0
27
Building a Modern Day E-commerce SEO Strategy
aleyda
38
6.9k
Unsuck your backbone
ammeep
668
57k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
Gamification - CAS2011
davidbonilla
80
5k
The Cult of Friendly URLs
andyhume
78
6k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
Measuring & Analyzing Core Web Vitals
bluesmoon
4
130
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
Transcript
Refactoring lesson : from GPA 1.4 to GPA 3.0
About me • xdite • 微信号 xxddite • 公眾号 Xdite
全栈营教头 • Ruby on Rails • Agile • Growth Hack
• 认知⼼心理学 + 技术教学 https://ruby-china.org/topics/31080 無編程經驗的新⼿手,如何在四周開發實戰等級產品
为什么会来这次⼤大会 • 刚好我在北京 • 筹备组就问我要不要来 • 顺便投⼀一个题⺫⽬目 • 去年我都没有在燃烧我的激情 (
a.k.a 写 code ) • 想了⼀一下还是投了⼀一个题⺫⽬目
Refactoring lesson : from GPA 1.4 to GPA 3.0 酷,程序员听到「翻修」就充满激情
1.4 -> 3.0 codeclimate.com
3.0
1.4
背景故事
2014 年 7 ⽉月 • 矽⾕谷 O2O 送餐公司 • 种⼦子轮
拿了 250 万美⾦金 • A 轮拿了 1100 万美⾦金 • 来台湾征才 • 8 ⼈人公司加⼊入了 SpoonRocket • 公司⼤大举招⼈人
• Angular - 客⼾戶 Web 端 • Android • iOS
• Rails - Admin • jQuery - Dispathcher (⼈人⼯工配餐台)
• 2 ⼈人技术团队,⼀一个⽉月之内扩编到 20 ⼈人 • ⼤大家就⼀一直踩到隔壁的脚
• 虽然技术团队 20 ⼈人 • 每天可以拉上超过 20 ⽀支 pull-request •
但是每天只能 deploy 2 ⽀支 pull-request • 凌晨 3:00 (台湾时间)开店,SA 只能睡公司....
• 经常性 Rollback • 20 ⼈人还是只有 2 ⼈人战⼒力 • 每天开店⽼老是炸
• ⽆无法做促销,呼叫⼀一只菜单 API ~= 700ms • 开启 Admin Controller 超过 60 秒
• 刚加⼊入没多久就后悔 • Grape API • 每⼀一只 Grape API 约
1000-2000 ⾏行 • 毫⽆无逻辑的 EndPoint • 重复逻辑到处复制贴上 • Admin 后台的单⼀一 index action 也⾼高达数千⾏行
• CTO 与第⼀一个 RD。凭借蛮⼒力硬是上线 • 永远保持能卖东⻄西就好 • 我⻅见识到的是 GPA 1.0
的代码也能募到这么多钱.... • 所以代码是否干净与能不能赚钱没有关系
⼈人⼈人都想 Refactor
但⼈人⼈人都不想 Refactor
• ⾝身为 RD Lead • ⼤大便只能由我先吃 • 毕竟这是我的⼯工作..
結果 • API 代码 95 % 以上覆盖 • 上了 CI
• 全代码覆盖率 60% • GPA 3.0
挑战 1 :从哪⾥里开始?
• 快 100 只 API • 50 只以上 Controller •
快 70 个 model • 10000 多⾏行代码
答案:先补⽂文档
WIKI 上必须要有主要 API 的⽂文档 • GET / POST • 输⼊入参数
/ 输出结果 • 回传值 • (真实资料)
• 取得全局感 • ⼤大致上有多少 API 我们得⾯面对 • 估计⼯工作量 • 估计「重构」所损失的战⽃斗⼒力
( 必须公司可承受)
⽼老板说他只能承受 2 周没有⽣生产⼒力...
⽼老板说他只能承受 2 周没有⽣生产⼒力... 当然事实上是 1 天 都不能没有
挑战 2 :先写哪边的 Test ?
答案:先写 API Test
• 把每⼀一⽀支 APP 都开⼀一⽀支 Redmine Ticket
实作步骤 • 半强迫每个 RD,⼀一个礼拜必须写 10 ⽀支测试 • 没时间也⾄至少做到 • API
200 • 验证格式正确 • ⼿手头掰不出测试资料就使⽤用「真实资料」
• 牵涉到 3rd Party 的 API 不写 Test • 呼叫演算法的
API 不写 Test • 因为代码太渣了,⽆无法强⾏行 mock…
• ⼀一个礼拜补完所有 API Test …(⾄至少有 200 与格式) • ⾄至少 RD
要是拉 pull request,没有绿灯就可以叫他滚 回去了 • 快速滤掉第⼀一层低级错误 • rollback 率⼤大幅下降
挑战 3 :先重构哪部分的代码 ?
从 API 分离下⼿手 • Before : ⼀一⽀支 API 档案 >
1000 ⾏行代码 • After :⼀一⽀支 APP 的「档案」必须⼩小于 160 ⾏行
从 API 分离下⼿手 • 原先 API ⼤大约有 10 个 Endpoint
• 降到 3 个 End Point
开始有办法清楚的看懂代码
闪坑 • 不会再被 if / else 坑到 • 不会再也不知道⾃自⼰己再改那个 end
point 的代码 • 有机会把「相近」的 Resource 放在同⼀一个档案 • 因为有 200 Test 可以放⼼心的搬家
抽出业务逻辑 • 把业务逻辑搬到 ServiceObject • API 只负责呼叫 Service Object •
API 的 Test 只负责验证 200
None
None
• 添加 error! • 将业务逻辑细细拆分 • 终于可以仔细拆分不同 状况,不需到处 mock •
甚⾄至可以开始 stub ServiceObject
开始处理⽆无法 Mock 的 API • 要求「演算法」也抽出成 ServiceObject • 不测试演算法 •
但 API 必须补「格式」Test
⼩小结
• Step 1: 先估计「⼯工作量」 • Step 2: 装上红绿灯,⾄至少保证永远有基础绿灯。 • Step
3: 切细变成可以「重构」的区块 • Step 4: 盒⼦子打包法,补⿊黑盒⼦子测试
挑战 4 :补「重构」哪部分的代码 ?
CodeClimate Refactor 法 • 找出 F 等级代码。 • 专攻重复区域,打包成 method,补
unit test。 • ⼜又补了⾄至少 > 50 个 Test • 重复的代码 = 重要的业务逻辑(到处都⽤用到)
• ServiceObject (商业流程) • Calculator ( 计费可以随时抽换不同公式 ) • Validator
( ⼀一个 Order ⾄至少要经过 10 道验证,把验证做到可叠 加 ) • Serializer ( 原先是 Hash,改⽤用 Serializer 好管理 ) • Cells ( 让 View 可重复使⽤用 ) • StrategyClass ( 可策略抽换应付「营销活动」与「价格模型」 ) • Worker ( 把效能瓶颈移到背景去执⾏行 ) • Concern ( 复合使⽤用把常⻅见⼯工具类 method )
ServiceObject • 查价 / 库存 • 下单 • 退单 •
跟踪订单 • 计算运送所需时间 • 不同版本 API,使⽤用不同 ServiceObject
None
Calculator • 不同地区不同税率 • 冷的不收税、热的收税 • 司机⼩小费 • 礼物卡的税务逻辑
Strategy • 地区营销活动 • API 上可插拔 • 活动结束直接关掉 Strategy
Worker • 付款呼叫 Stripe • 伪卡 • 霸⺩王餐⾏行为
SOA • 演算法 • Dispatcher (⾼高 JavaScript 耦合)
⼩小结
• 每个业务逻辑的接⼝口必须干净,容易插拔 • 每整理⼀一个业务模块,就补 Test • 修改 / 新增功能,必须补 Test
花了 1 个⽉月
• 2 pull request => 5 => 10 • 终于可以上
CI server • 不是绿灯,pull request 不会有⼈人理
讲完 API ,来讲 Controller
• ⼀一个 Controller ⼏几千⾏行代码 • ⽼老板把逻辑都写在 JavaScript ⾥里⾯面
• 因为 Dispatcher 台是 JavaScript 写的 • 只好其他业务逻辑也⽤用同样的⽅方式
第⼀一步 • 把 Dispatcher 「以外」的部分搬去 Rails CRUD • 不太需要写 Test
• 烂了请美国同事 hotfix,也不影响消费者下单 • 拆了 ~15 ⽀支 Controller
第⼆二步 • 把 Dispatcher 当作是 Client • 不再是 Rails 与
JavaScript 混合产⽣生 View • 显⽰示逻辑都使⽤用 JavaScript • Rails 作为 API 提供资料 • 补 API Test
• Frontend 组搞了很久 • 巨坑.... • 那时候剛有 React, … •
学到以后复杂逻辑绝对別⽤用 jQuery 先搞。
经过这⼀一轮 • 1 个⽉月就从 1.4 => 2.95 • 代码覆盖率到 40%
+ • 花了另外的 5 个⽉月 2.95 => 3.06 • 花了另外的 5 个⽉月代码覆盖率到 60% • ⾜足够好
挑战 5 :Release 太快带来的问题
• 每天 Release 15 ⽀支 pull request • db migration
或是改资料,还是个坑,需要⼈人为介⼊入 • 运营团队抱怨虽然没有 500,但是业务逻辑⼀一直在变 • 应该要出 Release ⽇日报
zendesk/samson
⼀一键 deploy
None
Deploy 架构 • samson 修改版 for heroku deployment • heroku
pipeline
• ⾃自动汇集 pull request 成 deploy ⽇日报 • 必须叙述作⽤用 •
若有 migration 必须在 #Risk 环节注记 • Deploy ⾃自动执⾏行
成果 • GPA 3.06 • 60 % test coverage •
15 pull request/day • API has ~95% test coverage. • major API response time < 80 ms • We shipped 6-8 major features every week.
Take away • 先搞清楚有多少测试要写。 (否则会遭到公司否决) • 先写 Integration Test •
Integration test -> Service Object test -> Unit test • 尽量提供 developer 「动机」去写 • 测试资料 • 可复制的测试代码
Take away • 做 Refactor 前⼀一定要先上 Test • 前期⺫⽬目标是「有动机去做」 •
中期⺫⽬目标是「接⼝口干净」 • 远期⺫⽬目标是「⾃自动部署」
不过
• 虽然「补测试」这么不爽 • 之后创业我还是不会先写测试 • 因为我理解了 GPA 1.0 还是可以拿到 1100
万美⾦金 • 商业的重点是「测试」你的 「idea」,⽽而不是「代码」 • 赚了钱你要雇⼏几个⼤大⽜牛来帮你重构都⾏行
Q & A