Upgrade to Pro — share decks privately, control downloads, hide ads and more …

不断归零的前端人生 - 2016 中国软件开发者大会

Joseph Chiang
November 18, 2016

不断归零的前端人生 - 2016 中国软件开发者大会

分享这两年半追寻梦想、在澳大利亚工作、技术与前端等多方面归零的心得。

Joseph Chiang

November 18, 2016
Tweet

More Decks by Joseph Chiang

Other Decks in Technology

Transcript

  1. 袋鼠进⾏行行式 現在在悉尼的 Stackla 2014.5 Now • 社交媒体撷取器 • 撷取后可管理理过滤资料 •

    可⽤用三种⽅方式投射 • 多⽤用于⾏行行销活动、⼴广告 • 成功的 Startup 撷取 过滤 投射
  2. ⼈人⽣生的归零 我们不断地增加依赖 • npm install ⼯工作 • npm install ⽆无⼈人机

    • npm install 宠物 • npm install ⻋车⼦子 • npm install 女友 • npm install 房⼦子 • npm install 孩⼦子 • npm install 妻⼦子 • 归零:是否能舍弃某些依赖?
  3. 转变与冲击 • 好处:⾼高薪、成功产品、才华洋溢的创办⼈人、顶尖的同事、优秀的软硬体设备 • 代价:F1 ⽅方程式般的开发速度、并满⾜足像乔布斯般要求完美的创办⼈人 = ⼯工时⻓长 在跟客户 Demo

    时破 图,这是完全没办法 接受的 在台湾的最后⼀一份⼯工作 ⴀ⺫涸儻♳䙼罌✫䖎⛉觉䖤这呋涸欰崞♶僽䧮銴涸 䩞觉䖤꨾⨞ⴀ佖」⿡寻䪪䧮涸唁䟝
  4. ⼀一开始的乐观 • 经验:不相信非⻄西⽅方国家的经历,即使我曾在台湾雅虎 • 语⾔言:⾯面试、电话常⽆无法完全理理解或有效回答对⽅方的问题 • 签证:没有可以⼯工作的签证 = 没公司或猎头感兴趣 •

    ⾦金金钱:三个⽉月没收入,压⼒力力很⼤大 https://www.linkedin.com/pulse/why-your-resume-landed-my-trash-stacey-alcorn 在台湾意⽓气⻛风发 出国乏⼈人问津
  5. 回顾:⼈人⽣生归零 • ⼯工作:不想放弃⾼高薪、好的职位 • 爱情:在澳⼤大利利亚打⼯工度假的女友即将回台 • 语⾔言:怀疑⾃自⼰己的英⽂文能⼒力力 • 其他:得抛弃房⼦子、⻋车⼦子、宠物、家⼈人、朋友 归零前所考量量的困难点

    归零后的实际结果 • ⼯工作:调薪、升迁、5:00 下班、住公司对⾯面 • 爱情:已经是老婆、每天有架吵! • 语⾔言:英⽂文能⼒力力绝对够⽤用 • 其他:公司越来越好、朋友越来越多、永久居留留申请中
  6. 回顾:⼈人⽣生归零 • ⼯工作:不想放弃⾼高薪、好的岗位 • 爱情:在澳⼤大利利亚打⼯工度假的女友即将回台 • 语⾔言:怀疑⾃自⼰己的英⽂文能⼒力力 • 其他:得抛弃房⼦子、⻋车⼦子、宠物、家⼈人、朋友 重置前所考量量的困难点

    重置后的实际结果 • ⼯工作:调薪、升迁、5:00 下班、住公司对⾯面 • 爱情:已经是老婆、每天有⼈人吵架 ^^ • 语⾔言:英⽂文能⼒力力绝对够⽤用 • 其他:公司越来越好、朋友越来越多、永久居留留申请中 其实转换跑道、创业都可以算是⼈人⽣生的归零 伴随⻛风险,但即使失败,也必定相当的收获 我期待未来继续归零,你呢? Reset Success! ⼈人⽣生归零成功!
  7. 不習慣 真正的新创公司 • ⼼心态不同 • 著重于完成功能,較少程序员间的品质交流 • 过去有:⼯工程⽂文件制作、Peer programming、Code review、重构、分享会

    • ⽆无前端架构 • 仍然⽤用 <script/> tag,没有 RequireJS 模块依赖 • 混乱的全域变数、⽅方法 • 有很多的复制黏贴 • 没有⽤用比较好的⽅方法:例例如 OOP • 对好东⻄西 Grunt、LiveReload 没兴趣
  8. 调整⼼心态 迅速改变代价太⾼高 • 缺乏程序员间的品质交流:先摆⼀一边,但尽可能写⽂文档 • 没有 RequireJS 模块依赖:先⽤用 grunt-usemin 解决布署问题

    • 混乱的全域变数、⽅方法:先摆⼀一边,未来不再使⽤用 • 有很多的复制贴上:把 DOM 的部份改⽤用 Mustache • 没有比较好的制度:例例如 OOP:新功能再使⽤用 • 对好东⻄西 Grunt、LiveReload、RequireJS 没兴趣 • 导入 Grunt 开始处理理 SASS 的编译问题 • 开始两个礼拜⼀一次的内部分享会 离理理想很远,但却是⼤大家能够接受的改变,也不会把⾃自⼰己累死
  9. Git 流程 第⼀一次不⽤用 Git Flow 所有开发、修 Bug 都在 STAC-<票号> 的

    branch 减少了了很多不必要的⼿手续、步骤、甚⾄至架构 对⼩小团队的我们其实够⽤用了了 http://d.pr/y57H STAC-<票号> master qa bugs 或新功能 提交给 QA 的测试 所有⼈人皆可 merge Push 后会⾃自动布署到 QA 测试环境 需要发 GitHub Pull Request 先布署到 Staging 环境 再到 Production 环境
  10. 导入 Redux • Delegation 困难: • 由上⽽而下要带太多 props • 太多概念念在同

    JSX 中: • View 逻辑 • API 资料载入 • 资料 Decoration • State 管理理出问题: • ⽆无法在元件之外共⽤用 • 随意增加 State ⼀一个档案超过 2000 ⾏行行! ⼀一样也是碰到问题再来处理理,避免太早抽象化
  11. ▾ Object ‣ allcontent/index: Object ‣ common: Object ‣ events/index:

    Object ‣ filters/index: Object ‣ hostedhub/index: Object ‣ plugins/index: Object ‣ report/user: Object ▾ report/network: Object ‣ data: Array[30] ‣ meta: Object ‣ widgets/index: Object Store #1 Redux Single Store - 初期规划 • 由路路径决定命名空间 • data - API 取得的资料 • 可以是 Object • meta - UI State • common - 共⽤用组件 • ex. Tag 选单 • 优点:直觉 • 缺点:资料会重复 ⽬目标:搬移原本 Container Component 的 setState
  12. 不做⽆无谓的抽象化 Ducks ducks-modular-redux 开〄时剤涸劼⠔ SFEVDFSBDUJPOT僽♧对涸 为什什么要拆开来放? // Actions const LOAD

    = 'my-app/widgets/LOAD'; const CREATE = 'my-app/widgets/CREATE'; const UPDATE = 'my-app/widgets/UPDATE'; const REMOVE = 'my-app/widgets/REMOVE'; // Action Creators export function loadWidgets() { return { type: LOAD }; } export function createWidget(widget) { return { type: CREATE, widget }; } export function updateWidget(widget) { return { type: UPDATE, widget }; } export function removeWidget(widget) { return { type: REMOVE, widget }; } // Reducer export default function reducer(state = {}, action = {}) { switch (action.type) { // do reducer stuff default: return state; } }
  13. Redux 简化 redux-actions // Actions const LOAD = 'my-app/widgets/LOAD'; const

    CREATE = 'my-app/widgets/CREATE'; const UPDATE = 'my-app/widgets/UPDATE'; const REMOVE = 'my-app/widgets/REMOVE'; // Action Creators export function loadWidgets() { return { type: LOAD }; } export function createWidget(widget) { return { type: CREATE, widget }; } export function updateWidget(widget) { return { type: UPDATE, widget }; } export function removeWidget(widget) { return { type: REMOVE, widget }; } // Reducer export default function reducer(state = {}, action = {}) { switch (action.type) { // do reducer stuff default: return state; } } 过⿡3FEVY➿码剤ꅾ㢖䚍넞 import {createAction} from 'redux-actions'; const PREFIX = 'my-app/widgets'; // Action Creators export const loadWidgets = createAction(`${PREFIX}/LOAD`) export const createWidget = createAction(`${PREFIX}/CREATE`); export const updateWidget = createAction(`${PREFIX}/UPDATE`); export const removeWidget= createAction(`${PREFIX}/REMOVE`); // Reducer export default const reducer = handleActions({ [loadWidgets]: (state) => {/* do load widget */} }); 现㖈诔歋䊨Ⱘⲹ㼱䖎㢵
  14. ‣ report/user: Object ▾ report/network: Object ▾ common: Object ‣

    data: Array[30] ‣ meta: Object visibleResultsCount: 3 Redux Store #2 ⽅方法 把共⽤用的 Ducks ⽤用 Function 包起来 export default function(PREFIX) { return { // Action Creators changeFilters: createAction(`${PREFIX}/CHANGE_FILTERS`), resetFilters: createAction(`${PREFIX}/RESET_FILTERS`), saveReport: createAction(`${PREFIX}/SAVE_REPORT`), // Reducer reducer: combineReducers({ reports: handleActions({ [saveReport]: () => {}, }), options: combineReducers({ filters: handleActions({ [changeFilters]: () => {}, [resetFilters]: () => {}, }) }) }) } }; report/common/redux.js import commonRedux from './common/redux'; const PREFIX = 'reports/user'; const { changeFilters, resetFilters, savedReport, reducer, } = commonRedux(PREFIX); export default combineReducers({ common: reducer, visibleResultsCount: handleAction() }); report/user/redux.js
  15. #1 ESLint 代码的基本品质⼯工具 • 只启⽤用部分规则 (不然修不完) • 将警告、错误全部修复 • 将部分规则改为

    Error,让所有⼈人⼀一定得遵守 问题:早就在⽤用,但警告太多,没⼈人理理会
  16. #2 CSS Module ˙ 〫针对 TDTT㢅椚䪾 DTT殆给痧♲倰库 ˙ ゘欽DBNFM4QBDF㖈+49⚥㥪写❉ ˙

    嫲预⠮㔮难♳许㢵㔔过⿡⯋⟝呋䒭邍⚥幋杂⢪欽㚖 避免全域 CSS 覆写问题 问题:全域 CSS 覆写问题⽇日渐严重 全栈⼯工程师对 CSS 策略略没兴趣 .wrapper { background: red; } .tag-box { border: solid 1px #ccc; } import css from './style.scss'; export default (props) => ( <div className={css.wrapper}> <div className={css.tagBox}>...</div> </div> );
  17. #3 组件结构 ⽬目录及语法调整 jsx ├── scroll-box │ ├── demo.jsx │

    ├── index.jsx │ └── style.scss ├── search-box │ ├── demo.jsx │ ├── index.jsx │ └── style.scss └── step-progress ├── demo.jsx ├── index.jsx └── style.scss 问题:过去 JSX 与 jQuery 插件混放 语法不⼀一致(改为 import, ES6 class) 好处:让⼤大家知道⽬目录结构调整 也邀了了全栈⼯工程师⼀一起帮忙
  18. #4 单元测试 替 API 层写测试 import {Observable} from 'rxjs'; export

    const TagsAPI = { URL: '/api/tags', create$() { return Observable.ajax({method: 'POST', ...}); } retrieve$() { return Observable.ajax({method: 'GET', ...}); } modify$() { return Observable.ajax({method: 'PUT', ...}); } destroy$() { return Observable.ajax({method: 'DELETE', ...}); } }; 问题:⼤大家介⾯面名称不统⼀一、实作⽅方法也不⼀一致 益处:互相写测试、學習,提出不少改进
  19. 前端草创 前端⼯工程师 1 全栈⼯工程师 3 React Well.. Nice! Promise ❤

    导入新技术速度较慢 㣐㢵数4UBSUVQ♶⠔剤僈显涸⵹た畮ⴕ䊨 ⡎⵹畮开〄罏应领导⵹畮䊨Ⱘ涸⢪欽 选择腋㹊꣢鍑Ɀ问题♶㟞⸈负䬐涸䊨ⰨⰦ㸐➃⠔䖎乐䠑騈ꥦ OOP
  20. Store #3 碫⡂〫剤DPOUSPMMFS涸嚌䙂 ˙♶㖈⛖ꅾ㢖资俲 ˙"1*鵦㔐阵⴪♶㢅椚 碫⡂剤NPEFM DPOUSPMMFS涸嚌䙂 ˙ 尝剤ꅾ㢖资俲 ˙

    "1*鵦㔐꨾贖椚 OPSNBMJ[SKT 阶段 #1:不考虑共⽤用 ‣ report/user: Object ▾ report/network: Object ‣ data: Array[30] ‣ meta: Object 阶段 #2:考慮 Redux 共⽤用 ‣ report/user: Object ▾ report/network: Object ▾ common: Object ‣ data: Array[30] ‣ meta: Object visibleResultsCount: 3 阶段 #3:切分出 model ▾ entities: Object ▾ reports: Object ▾ models: Object ‣ 2f48a879: Object ‣ 4c5ed1d5: Object ‣ 4fc165f5: Object ‣ 5eb92930: Object ‣ 7a095e5d: Object ‣ syncing: Object ‣ report/user: Object ▾ report/network: Object ‣ meta: Object
  21. 档案架构演化 • reports/user/index.jsx • reports/user/redux.js • Action Creators • Reducer

    • reports/user/style.scss 阶段 #1:不考虑共⽤用 • reports/common/index.jsx • reports/common/redux.jsx • Action Creators • Reducer • reports/user/index.jsx • reports/user/redux.js • Action Creators • Reducer • reports/user/style.scss 阶段 #2:导入共⽤用层 • common/entities/syncing.js • common/entities/sorting.js • common/entities/reports/epic.js • common/entities/reports/redux.js • Action Creators • Reducer • Selector • Schema • reports/common/index.jsx • reports/common/redux.js • reports/content/index.jsx • reports/content/redux.js • Action Creators • Reducer • Selector • Schema • reports/content/style.scss 阶段 #3:導入許多技術跟檔案 normalizr reselect serializr dotDrop
  22. 是进化也是退化 前端⼯工程师 * 3 全栈⼯工程师 * 4 ESLint redux-observable entities

    WTF! WTF! WTF! WTF! 团队成⻓长也是个挑战 现ⲃ➠꨾銴栈䊨玑师涸贡柄⡎过㢵䪮术ⵖ鸤✫ꥬ阂 reselect Unit Test CSS Modules serializr normalizr Convention epics redux-actions
  23. 是进化还是退化 前端⼯工程师 * 3 全栈⼯工程师 * 4 ESLint redux-observable entities

    WTF! WTF! WTF! WTF! 团队成⻓长也是个挑战 现ⲃ➠꨾銴栈䊨玑师涸贡柄⡎过㢵䪮术ⵖ鸤✫ꥬ阂 reselect Unit Test CSS Modules serializr normalizr Convention epics redux-actions 永远不要忘了了问⾃自⼰己这个问题 「我 (我们团队) 真的需要他吗?」 ⽰⢪没剤这❉䪮术问题♧呋剤鍑岁鸠䏞䧴许刿䘰
  24. HTML ⽂文件 结构、样式、⾏行行为全部写在 HTML 中 1995 WaSP ⽹网⻚页标准化⼩小组 1998 React

    暴暴红 2015 最佳实践:HTML、CSS、JS 应分离 最佳实践:HTML、CSS、JS 应合并 最佳实践:HTML、样式、JS 合并⼀一起写
  25. CSS 命名⽅方式 CSS2 1998 2005 以 ID、模块为命名空间、禁⽌止以外观命名 2005 2015 CSS

    Module - 随意以外观命名 2015 Bootstrap 热⻔门、带动了了 OOCSS 2011 最佳实践:⽆无 (随意命名) 最佳实践:命名空间、结构化 最佳实践:元件化、⽤用 BEM、SUITCSS 等命名策略略 最佳实践:⽆无 (随意命名) #ykpmh .hd .media-object {} .person__head {} .person--tall {}
  26. JS 编程⽅方式 仅表单验证,只需写 Function 1998 JavaScript 开始变得复杂 (Web 2.0) 2004

    函数式编程火红、只需写 Function 2015 最佳实践:函数式编程 最佳实践:⾯面向对象编程 最佳实践:函数式编程
  27. 套件管理理 CSS 预处理理器 JS 模块载入 JS 语法编译器 构建系统 less-loader sass-loader

    coffee-loader ts-loader babel-loader style-loader 架構的演化 混乱,但持续往好的⽅方向发展
  28. 套件管理理 CSS 预处理理器 JS 模块载入 JS 语法编译器 构建系统 less-loader sass-loader

    coffee-loader ts-loader babel-loader style-loader 架構的演化 混乱,但持续往好的⽅方向发展 技术重置 = 持续地汰换、往好⽅方向发展 不断分裂⼜又集成、让前端接近真正的软体开发