如何在新時代下的結對程式設計中將程式碼玩出花來

原始碼終結者發表於2019-04-30

如何在新時代下的結對程式設計中將程式碼玩出花來

好久沒寫文章了,標題起的有點膨脹。

你猜我想說什麼

我想寫一個結對程式設計小記。最近在和 S (帥氣的花名) 利用業餘時間,進行了一次結對程式設計。現在我準備把結對程式設計的一些思考分享給大家,下面開始吧。

PS: 此篇文章,不拘泥於細節,將會聚焦整體上的見解,希望對各位小夥伴有所幫助。

為什麼就叫新時代下的結對程式設計

這裡我說明一下原因,請往下看。

傳統結對程式設計

百度百科的定義如下:

結對程式設計(英語:Pair programming)是一種敏捷軟體開發的方法,兩個程式設計師在一個計算機上共同工作。一個人輸入程式碼,而另一個人審查他輸入的每一行程式碼。輸入程式碼的人稱作駕駛員,審查程式碼的人稱作觀察員(或導航員)。兩個程式設計師經常互換角色。 在結對程式設計中,觀察員同時考慮工作的戰略性方向,提出改進的意見,或將來可能出現的問題以便處理。這樣使得駕駛者可以集中全部注意力在完成當前任務的“戰術”方面。觀察員當作安全網和指南。結對程式設計對開發程式有很多好處。比如增加紀律性,寫出更好的程式碼等。結對程式設計是極端程式設計的組成部分。

為什麼我覺得過時了呢,聽我簡單(胡)析(謅)下:

兩個人共用一臺計算機,這可能在 ACM 競賽或者組隊 PK 中常見。但對於業務開發來說,有點不科學,首先效率就不高,如果對方程式碼太可愛,可能會忍不住打他。當然了,在特殊場景下也會出現,但是 95% 的場景下,是不可能存在下圖這種場景的。

下面這種場景猶如六月飛雪:

如何在新時代下的結對程式設計中將程式碼玩出花來

不過這種場景倒是很樂意接受的:

如何在新時代下的結對程式設計中將程式碼玩出花來

當然,別問我為什麼,因為:

如何在新時代下的結對程式設計中將程式碼玩出花來

那什麼是我認為的新時代的結對程式設計呢?

新時代的結對程式設計

我認為新時代的結對程式設計,應該是這樣一種狀態:

兩(N)個 coder , 兩(N)臺電腦,坐在一起(後續也可以不用坐在一起)進行開發。程式碼可以互相看到。最關鍵的一點就是,我們可以互相看到並且看懂對方的程式碼。

什麼意識呢,這裡我舉個例子:

我和 S 達成意見,S 負責 node , 也就是後端,我負責前端,前後端分離。然後各自的程式碼我們都能互相看到,要開發什麼功能,我們都知道,我可以 review S 的程式碼,S 也可以 review 我的程式碼。當開發的時候,我可以通過 review S 的程式碼,提前知道 S 的介面邏輯。如果我認為他的邏輯寫的有問題,我會和他進行溝通,提前把可能存在的疑問處理掉。我也會提前按照他寫的介面來預留好請求這塊的邏輯處理。總之,在我理解的結對程式設計中。應該是能力相同,程式碼相同,通過互相 review 對方的功能程式碼,來對比自己的程式碼。從而告訴對方可能存在的問題,而這種問題的解決會讓開發的效率大大增加,更早的解決了潛在的一些問題。

PS: 當然這種新的方式,需要一定的技術基礎,比如你要能看懂後端的程式碼。嗯,如果是 Java ,你可能會比較艱難。當然,他也會更艱難。所以還是 node 大法好,手動滑稽。總之,這是我認為的新時代下的結對程式設計,它不具有普適性,當然這種形式的好處是顯而易見的。

結對程式設計之前的狂歡?

嗯?按照傳統,當然是來一次結對前的慶祝。去了趟 1912 ,吃了個大餐,享受了下日式服務。然後去咖啡館開始 face to face talking ,愉快的結對程式設計就要開始了。

怎麼玩出花呢?

我分為兩個部分去介紹,第一部分是前端,第二部分是後端。

前端

技術架構選擇

首先,框架的選擇這塊,在衡量之後,選擇的是 Vue 。這裡我對用什麼框架,其實沒什麼看法,唯一的看法就是:

根據實際情況,來選擇合適的開發框架,從而提高整體的開發效率。

要不要使用腳手架,這塊我也持上面的那句話,根據實際情況做出合適的選擇。這裡我選擇 Vue-cli3 來快速搭建應用。怎麼使用,自己去研究一下就知道了。

這裡可以提供幾個路徑

第一個路徑:去 cli.vuejs.org/ 官網研究

第二個路徑:去看 vue-cli3 的原始碼,瞭解一下內部的一些機制,比如 chainWebpack 的實現,vue.config.js 的預設設定是如何實現的。

第三個路徑:去 github 上,找一些用 vue-cli3 搭建的專案,clone 下來,研究一下別人是如何使用的。

PS: 我個人認為腳手架是不會存在技術上的難度的,多看看文件,不行的話再去看原始碼搗鼓搗鼓,就差不多了。

樣式方案的選擇

選完技術框架,我們再來看看樣式的選擇,通用的樣式方案,業界的標準基本都是相同的。但是關於元件中的樣式該放哪,目前在業界,大概有這麼兩種。

樣式和元件目錄分離

樣式和元件目錄分離,這個是目前很多 ui 庫採取的方式。 比如 iview elementui ,我來截圖展示一下。

如圖所示 iview 的截圖:

如何在新時代下的結對程式設計中將程式碼玩出花來

從上圖可以發現,元件的樣式全部放在了 style 目錄裡,並且用的是 less

樣式和元件目錄不分離

說到這個,目前具有代表的大概就是 ant-design 了。

如圖所示 ant-design 的截圖:

如何在新時代下的結對程式設計中將程式碼玩出花來

我們可以看到,在 ant-design 中,元件的樣式是放在元件目錄裡面的,同時也是用的 less

使用哪種樣式進行編寫

至於使用哪種樣式風格編寫。為了玩出花,我採取的是同時使用三種樣式:scss less stylus 。在這個過程中,我更喜歡 stylus,因為其類似 python 的縮排寫法,簡單快速。一不用寫分號,二不用寫括號,三也可以不用寫冒號。如果你看過 vue-cli3 的原始碼,你會發現其中的 ui 部分,樣式使用的就是 stylus

vue-cli3 原始碼中的的 ui 部分如圖所示:

如何在新時代下的結對程式設計中將程式碼玩出花來

總結

關於樣式方案的選擇,我想表達的是:

在元件的樣式處理方面,業界存在兩個標準,不存在好和不好,但是我們需要知道這些標準,通過知曉,來給自己的實踐中多提供一些參考和幫助。

我使用的是:

樣式和元件目錄不分離的方案,同時樣式編寫採用的是三個樣式,主用 stylus

關於狀態管理

業界的狀態管理有很多,vuexreduxmobxdva 等等。目的都很明確:通過抽象封裝掉混亂。

對於我來說,會思考一個問題,此專案是否真的需要 vuex ,為了玩出花,我做的處理是:

切了兩個分支,一個不使用 vuex ,一個使用 vuex

什麼時候使用 vuex

當元件中需要共享一些資料的時候,並且資料較多,就可以使用 vuex 。如果資料不需要共享,或者較少,其實也沒有必要用 vuex

vuex 的兩種形式

使用 vuex 時,如果需要管理的狀態不是很多,那可以直接寫到一個檔案中。如果需要處理的狀態很多,那就使用 module 的寫法。將狀態進行分類,分成不同的 module

關於請求的處理

對於請求,我這邊做的是,將請求部分儘可能的抽離出來, 預留好以後可能會出現的坑。比如,預留請求攔截,預留對請求進行加密,預留公共的引數,預留好模擬資料的坑。

我一般將這部分邏輯分成三個類。一個是 StateService ,一個是 ApiService ,一個是Service 。當然如果服務過多,可以對 Service 進行細分,比如 UploadServiceMonitorService 等。

關於模擬資料

說到模擬資料,大家第一反應可能是,使用 easy-mock ,使用 rap 等。而在我這邊,選擇了一種很少人知道的做法,那就是通過裝飾器來進行資料模擬。

什麼意識呢?我簡單介紹下

如圖所示:

如何在新時代下的結對程式設計中將程式碼玩出花來

從上圖可以知道,我對 Service 中的 getuserinfo 進行了裝飾攔截,通過裝飾器來將模擬資料注入進去。再通過環境判斷來確保在生產環境上,此裝飾器方法失效。

雖然會有入侵程式碼的味道,但是在真正嘗試了後,你會感受到利用裝飾器來解決資料模擬 的魅力,因為你可以隨心所欲的控制所有請求邏輯。從而達到完全不依賴後端介面來實現前端全流程的模擬。

關於工具方法

對於這個,需要去思考此專案需不需要依賴一些工具庫,比如 lodashramda 。如果不怎麼依賴,那就用原生寫吧。

對於工具方法,我也會進行分類,我會分為內部方法和外部方法。如果只是提供給另一個方法使用,並不會暴露到業務中,那我會把它認為是內部方法。

關於效能

這個是老生常談的事情了,我一般把效能這塊分為兩個方面。

腳手架能做到的事情

  1. 將依賴包和業務程式碼進行分離
  2. js css 等進行壓縮,是否對 css 進行分離
  3. 是否對圖片進行壓縮,是否對小圖片進行轉成 base64
  4. 根據業務情況決定是否使用 cdn
  5. 對第三方 ui 庫進行效能處理,比如後置編譯
  6. 和後端進行溝通,決定是否開啟 gzip

腳手架做不到的事情

關於圖片壓縮

雖然 webpack 有圖片壓縮,但是根據對比,其壓縮的質量和效果還是沒有 tinypng 優秀,如果有不知道 tinypng 的小夥伴,可以點選 tinypng.com/ 進行 TP

tinypng 的壓縮演算法沒有開源,雖然可以免費使用,但是會存在一些限制,對此 github 上有人專門開發了 tinypng for mac 。 小夥伴可以自行了解一下,工具還是很好用的。可以原位置替換檔案,壓縮後的圖片基本沒有損失。

github.com/godkun/Tiny…

程式碼級別的效能提升

這是腳手架做不了的,我們在寫程式碼的時候,要注意程式碼方面的效能。比如將資料存到區域性變數、優化迴圈、函式去抖、函式節流、圖片懶載入等等吧。效能這塊我就不提了,太老生常談了。

關於async await 和 promise

這塊我提一下。在專案中,我們究竟要怎麼靈活使用 async awaitpromise ,首先明確的一點是,不能為了使用而使用。這裡我發表一下個人看法,下面是幾種使用兩者的場景。

  1. 當你想用 try catch 捕捉非同步操作的異常時
  2. 當你要在一個非同步操作中巢狀另一個非同步操作時
  3. 當你想將一個函式包裹成 promise 的時候

我簡單舉個例子,如下程式碼:

fn(res => {
  // TODO:
})
複製程式碼

上圖中,fn 是一個非同步操作,該函式中會執行回撥函式。現在有兩個問題:

  1. 如果我們想讓 fn 變成 promise 呢?
  2. 如果我們想在回撥函式中繼續執行其他的非同步操作呢?

針對上面的兩個問題,現在來依次解決一下。

解決第一個問題:

首先我們把非同步操作的 fn 變成 promise 形式,很簡單。

大致程式碼如下:

function wrap() {
  return new Promise((resolve, reject) => {
    fn(res => {
      resolve()
    })
  })
}
複製程式碼

解決第二個問題:

如果 fn 的回撥函式中,還要進行非同步操作,那該如何優雅的解決這個問題呢?這個時候就要使用 async await 了。

大致程式碼如下:

function wrap() {
  return new Promise(async (resolve, reject) => {
    try {
      fn( async res => {
        let result = await fn2()
      })
    }catch(err) {
      // TODO:
    }
  })
}
複製程式碼

是不是發現,程式碼都是同步的,可以使用 try catch 。嗯,就是這麼簡單自然。

關於動畫銜接

我們知道,互動這塊要友好,不能太生硬,跳轉等需要保證流暢性。所以在部分頁面中,使用了 gsap ,不瞭解的小夥伴可以去查一下資料。

簡潔程式碼如下:

// 只用到了 TweenLite 、TimelineLite 兩個方法
import { TweenLite, TimelineLite } from 'gsap'
let tw = new TimelineLite()
tw.add(TweenLite.to(this.style.blocks[0], 0.5, { opacity: 1, delay: 0.5 }))
tw.add(TweenLite.to(this.style.blocks[2], 0.5, { opacity: 1 }), '-=0.3')
複製程式碼

通過對樣式的設定來達到銜接的流暢性。

關於 loading 元件

我們在開發微信 H5 、天貓淘寶 H5 、 開發快應用、開發小程式等的時候。 loading 這塊是一個必須要做的事情。比如請求開始時,loading 開始,使用者不能進行其他操作,請求結束或者異常時,loading 結束。

那麼在面對第三方 ui 庫 或者 APP 自帶的實現時,我們要怎麼去選擇呢,是使用現成的,還是寫一個最適合自己的呢?

這塊我個人的意見是自己手寫一個適合自己的 loading 。這樣做的原因我高度概括一下,就是:統一和靈活。

PS: 當然,這個不是絕對的。只是提供一個思路,比如微信 H5 , 天貓 H5 , 就不要用自帶的 loading ,使用同一的 loading 元件。

關於開屏特效

開屏特效有很多方式,比如可以使用 vue-touch 來完成向下滑屏的操作。

大致效果如下 gif 圖:

如何在新時代下的結對程式設計中將程式碼玩出花來

在完成以後,感覺不夠炫酷。於是進行改良,執行第二種方案,採用序列幀來完成開屏的特效。

什麼是序列幀呢?

序列幀就是通過將一段視訊分解成一幀一幀的形式。然後通過 canvas 來按照一定的時間間隔畫出來,從而讓使用者感覺到是一連串的特效畫面。可以想象成 PPT 的快閃效果。

既然需要序列幀,那麼就需要載入的進度條。進度條這塊可以封裝成元件,思路就是通過資料載入的進度來設定百分比,同時設定一些動畫的效果。

大致效果如下 gif 圖:

如何在新時代下的結對程式設計中將程式碼玩出花來

從上面可以看到,當 godkun: 原始碼終結者 顯示完全的時候,也就是進度條達到 100% 的時候。表明序列幀需要的資料已經載入完成。

關於圖片合成

需要做分享圖,如果交給後端去做,由於需要合成的圖片很多,後端的壓力會變大。商量後,決定在前端合成,通過 canvas 來將10 張圖片,合成為一張分享圖,這裡的注意點不多。需要注意的就是在圖片 onload 事件回撥中再進行畫圖。

大致程式碼如下:

async drawCanvas() {
  let canvas = this.$refs.myCanvas
  canvas.width = xxx
  canvas.height = xxx
  let bg = await this.drawBg()
  this.drawImage(bg) // 不變
  // TODO: 繪製其他
  let data = canvas.toDataURL('image/jpeg')
  const params = {
    base64: data
  }
  let result = await Server.getImage(params)
  this.$refs.canvasImg.setAttribute('src', result)
}
複製程式碼

PS: 這裡有個坑,安卓手機下無法儲存 srcbase64 的圖片,後面經過採坑,決定通過將 base64 資料發到後端,然後返回 png 的地址來解決這個坑。

關於埋點

埋點的目的是收集各種資訊,比如 PVUV 、點選率、異常。那麼埋點該怎麼做,一般的前端埋點,我認為,需要遵循兩點:

第一點:不要過度入侵程式碼,也就是俗稱的硬編碼

第二點:做到複用性,也就是進行統一的封裝

比如,將對應的埋點進行重新命名,如 b1 b2 b3

大致程式碼如下,簡單粗暴:

burryDetail ={
  b1: {
    actionName: 'gotohome'
  }
}

export default function burry(key) {
  let burryObject = burryDetail[key]
  // TODO: args
  let argN = burryObject.actionName
  send(...args, argN)
}
複製程式碼

這樣做的好處是將所有埋點放在一個檔案中進行集中處理,不要在業務程式碼裡面直接寫,有利於解耦。對於有一些特殊情況,需要在業務程式碼裡面寫的,那就特殊對待吧。

關於執行模式

說到執行模式,可以想到有開發模式,生產模式,甚至還有分析模式。目前在 vue-cli3 下,按照其規定的方法進行設定就好了。比如新建 .env.dev .env.prd .env.xxx 檔案

如下 .env.dev 程式碼:

NODE_ENV = "development"
VUE_APP_BASE_URL = "xxxxxxxxxxxx"
複製程式碼

然後在 scripts 中寫入

"dev": "vue-cli-service serve --mode dev",
複製程式碼

就可以通過 npm run dev 來執行開發模式了。

關於第三方 sdk 的程式碼提示問題

有時候,你會發現,引入 sdk 後,沒有程式碼提示。然後去網上找,也找不到官方解決方案,這個時候怎麼辦呢?

顯然,只能自己去編寫宣告檔案了,這裡是針對 VSCODE 來說的,標準方法就是新建一個型別目錄,然後新建 sdk.d.ts

程式碼大致如下:

declare namespace SDK {
  function fn1(callback: () => void): void
  function fn2(text: String): void
  function fn3(): void
  function fn4(
    object: {
      arg1: String
      arg2: String
      arg3: String
      arg4: String
    },
    callback: (res: {}) => void
  ): void
}
複製程式碼

這塊自己根據具體的 SDK 去編寫你需要的提示就好了。

後端

後端是 S 寫的,所以我就以一個 code review 的形式去大致說一下後端的整體情況吧。

後端要做什麼

大致有如下幾點:

  1. 編寫 API 介面
  2. 編寫後臺管理
  3. 編寫一些其他的輔助功能
  4. 設計資料庫
  5. xxxx...

後端的框架選擇

這裡使用的是 egg.js ,其通過約定的哲學,來快速搭建應用,提高開發效率。egg 的學習文件有很多,貼個官網文件地址吧:

eggjs.org/zh-cn/intro…

如何編寫介面

這個沒啥好說的,通過路由攔截,然後轉到對應的邏輯處理,中間可能需要經過相應的中介軟體進行處理。

如何集中處理響應

如何更好地設計返回,這裡的做法是將返回封裝成 plugin ,然後擴充套件到 context 上。這樣的話,你就可以通過 ctx.sendresult 來統一處理返回內容了。

中介軟體的使用

中介軟體也沒啥好說的,本質上就是一個匯出的函式。用來處理接收到的資料,並進行對應的資料處理。

資料處理基本有兩種結局:

  1. 第一種結局:走到下一步
  2. 第二種結局:在這個中介軟體內就 game over

舉個真實場景:

比如最常見的,鑑權。我們可以在路由中就進行控制:

程式碼如下:

router.post('/api/xxx', auth(), controller.xxx);
複製程式碼

在處理受限介面的請求時,先進行 auth 處理,如果沒有成功,就中斷後續的邏輯處理,直接返回沒有登入或者沒有授權之類的響應內容。

node 的 MVC 和前端的 MV*

V

這裡我簡單提一下,在 node 層,和在前端層,其 V 大家都是能理解的,都是檢視的意識,node 層,也要寫頁面的,比如我們寫一個 404 頁面,配合處理異常的中介軟體。如果中介軟體捕捉到了 404 ,那麼直接返回 404 頁面給前端。

C

C 在前端來說,其實是最富有變化的一個點,所以我加了 * 表示。Cnode 來說,時候也是最重要的一個部分,它專門去處理接收到的請求,並且分發給各個邏輯處理中心,最後通過一系列的處理,再通過 C 層返回給前端。

M

Mnode 來說很簡單,在處理邏輯的時候,需要和資料庫進行互動,來實現 CRUD 從而實現資料的增刪改查。M 對前端來說,也很簡單,就是對 V 層的資料進行 CRUD 。前後端的 M 層還是有點區別的。

總結一下,後端的 MVC 看起來,是比前端的 MVC 好理解,前端的 MVC 就好像被強行安排了一波?。

前端的配置和後端的配置

隨著前端工程化的持續完善,前端的配置和後端的配置 ,在思想上,基本是一致的,這裡我就不提了。

關於資料庫

上面提了,使用 mysql ,當然了,像 egg-sequelize mysql2 這些都要用的。模型定義通常情況下是在 model 目錄下,定義好模型,然後掛在到 Application 下,通過 app.model.xxx 來拿到對應模型的上下文。對模型的處理,一般是放在 service 目錄下。

關於 publicPath

絕大多數情況下,前端的專案在打包後,會放到後端的 public 目錄下,所以看到這,小夥伴應該明白了構建工具中的 publicPath 是什麼意識了吧(手動滑稽)。

總結

看完後端部分,是不是發現也挺簡單的,程式碼都是 js ,前端怎麼寫業務邏輯,後端就怎麼寫業務邏輯。

兩者的區別主要是前後端需要考慮的點不一樣。

後端需要考慮安全、考慮伺服器的壓力、考慮介面的設計、考慮資料庫的設計。當然高層次一點,還要考慮負載均衡,高併發等。而前端則需要考慮頁面的美觀性、頁面的流暢性、使用者互動的友好性、頁面的開啟速度等等。總之,大家都不容易的,唯有執子之手,才能與子偕老。(手動滑稽 +2 )

文末總結

讀完,是不是有點感覺和結對程式設計沒啥關係,我特喵的讀完也感覺到了。

寫了 6000 字,我圖個啥。

如何在新時代下的結對程式設計中將程式碼玩出花來

開玩笑的,開玩笑的,其實,本文和結對程式設計是有強聯絡的,這個過程是我和 S 一起參與完成的。

下圖體現在整個過程中。

如何在新時代下的結對程式設計中將程式碼玩出花來

畢竟不能只說結對程式設計,還是要說一下其他的東西的。

我認為結對程式設計的魅力,就在於可以:

互相反饋,及時調 整,共同提高開發效率。當然最重要的是可以 搞(你在說)基(什麼?)

備註

  • 五一的番外篇,寫的有點倉促,記錄一下近期結對程式設計的體驗
  • 玩出花這個事情,其實從文中也能體會到,比如三套樣式、兩套狀態管理、裝飾器解決資料模擬,序列幀解決開屏,實時 review 後端程式碼,根據後端程式碼寫前端請求邏輯等等,好像也是有點花的。
  • 文章難免有錯,還請多多包涵,歡迎在評論處指出錯誤,多多交流

參考

我的一些其他系列文章

交流

掘金系列技術文章彙總如下,覺得不錯的話,點個 star 鼓勵一下哦。

github.com/godkun/blog

我是原始碼終結者,歡迎技術交流。

如何在新時代下的結對程式設計中將程式碼玩出花來

也可以進 前端狂想錄群 大家一起頭腦風暴。有想加的,因為人滿了,可以先加我好友,我來邀請你進群。

如何在新時代下的結對程式設計中將程式碼玩出花來

風之語

明天就五一了,祝小夥伴五一快樂,我不管什麼安康,我只要你們快樂!

最後:尊重原創,各位首富,轉載請註明出處哈?

相關文章