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

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

你猜我想說什麼

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

PS: 此篇文章,不拘泥於細節,將會聚焦總體上的看法,但願對各位小夥伴有所幫助。前端

爲何就叫新時代下的結對編程

這裏我說明一下緣由,請往下看。vue

傳統結對編程

百度百科的定義以下:node

結對編程(英語:Pair programming)是一種敏捷軟件開發的方法,兩個程序員在一個計算機上共同工做。一我的輸入代碼,而另外一我的審查他輸入的每一行代碼。輸入代碼的人稱做駕駛員,審查代碼的人稱做觀察員(或導航員)。兩個程序員常常互換角色。 在結對編程中,觀察員同時考慮工做的戰略性方向,提出改進的意見,或未來可能出現的問題以便處理。這樣使得駕駛者能夠集中所有注意力在完成當前任務的「戰術」方面。觀察員看成安全網和指南。結對編程對開發程序有不少好處。好比增長紀律性,寫出更好的代碼等。結對編程是極端編程的組成部分。python

爲何我以爲過期了呢,聽我簡單(胡)析(謅)下:mysql

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

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

不過這種場景卻是很樂意接受的: 程序員

固然,別問我爲何,由於:

那什麼是我認爲的新時代的結對編程呢?

新時代的結對編程

我認爲新時代的結對編程,應該是這樣一種狀態:

兩(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

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

也能夠進 前端狂想錄羣 你們一塊兒頭腦風暴。有想加的,由於人滿了,能夠先加我好友,我來邀請你進羣。

風之語

明天就五一了,祝小夥伴五一快樂,我無論什麼安康,我只要大家快樂!

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

相關文章
相關標籤/搜索