很久沒寫文章了,標題起的有點膨脹。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
。
業界的狀態管理有不少,vuex
、 redux
、 mobx
、 dva
等等。目的都很明確:經過抽象封裝掉混亂。
對於我來講,會思考一個問題,此項目是否真的須要
vuex
,爲了玩出花,我作的處理是:
切了兩個分支,一個不使用 vuex
,一個使用 vuex
。
何時使用
vuex
當組件中須要共享一些數據的時候,而且數據較多,就可使用 vuex
。若是數據不須要共享,或者較少,其實也沒有必要用 vuex
。
vuex 的兩種形式
使用 vuex
時,若是須要管理的狀態不是不少,那能夠直接寫到一個文件中。若是須要處理的狀態不少,那就使用 module
的寫法。將狀態進行分類,分紅不一樣的 module
。
對於請求,我這邊作的是,將請求部分儘量的抽離出來, 預留好之後可能會出現的坑。好比,預留請求攔截,預留對請求進行加密,預留公共的參數,預留好模擬數據的坑。
我通常將這部分邏輯分紅三個類。一個是 StateService
,一個是 ApiService
,一個是Service
。固然若是服務過多,能夠對 Service
進行細分,好比 UploadService
、 MonitorService
等。
說到模擬數據,你們第一反應多是,使用 easy-mock
,使用 rap
等。而在我這邊,選擇了一種不多人知道的作法,那就是經過裝飾器來進行數據模擬。
什麼意識呢?我簡單介紹下
如圖所示:
從上圖能夠知道,我對 Service
中的 getuserinfo
進行了裝飾攔截,經過裝飾器來將模擬數據注入進去。再經過環境判斷來確保在生產環境上,此裝飾器方法失效。
雖然會有入侵代碼的味道,可是在真正嘗試了後,你會感覺到利用裝飾器來解決數據模擬 的魅力,由於你能夠爲所欲爲的控制全部請求邏輯。從而達到徹底不依賴後端接口來實現前端全流程的模擬。
對於這個,須要去思考此項目需不須要依賴一些工具庫,好比 lodash
、 ramda
。若是不怎麼依賴,那就用原生寫吧。
對於工具方法,我也會進行分類,我會分爲內部方法和外部方法。若是隻是提供給另外一個方法使用,並不會暴露到業務中,那我會把它認爲是內部方法。
這個是老生常談的事情了,我通常把性能這塊分爲兩個方面。
js
css
等進行壓縮,是否對 css
進行分離base64
cdn
ui
庫進行性能處理,好比後置編譯gzip
關於圖片壓縮
雖然 webpack
有圖片壓縮,可是根據對比,其壓縮的質量和效果仍是沒有 tinypng
優秀,若是有不知道 tinypng
的小夥伴,能夠點擊 tinypng.com/ 進行 TP
。
tinypng
的壓縮算法沒有開源,雖然能夠無償使用,可是會存在一些限制,對此 github
上有人專門開發了 tinypng for mac
。 小夥伴能夠自行了解一下,工具仍是很好用的。能夠原位置替換文件,壓縮後的圖片基本沒有損失。
代碼級別的性能提高
這是腳手架作不了的,咱們在寫代碼的時候,要注意代碼方面的性能。好比將數據存到局部變量、優化循環、函數去抖、函數節流、圖片懶加載等等吧。性能這塊我就不提了,太老生常談了。
這塊我提一下。在項目中,咱們究竟要怎麼靈活使用 async await
和 promise
,首先明確的一點是,不能爲了使用而使用。這裏我發表一下我的見解,下面是幾種使用二者的場景。
try catch
捕捉異步操做的異常時promise
的時候我簡單舉個例子,以下代碼:
fn(res => {
// TODO:
})
複製代碼
上圖中,fn
是一個異步操做,該函數中會執行回調函數。如今有兩個問題:
fn
變成 promise
呢?針對上面的兩個問題,如今來依次解決一下。
解決第一個問題:
首先咱們把異步操做的 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')
複製代碼
經過對樣式的設置來達到銜接的流暢性。
咱們在開發微信 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: 這裏有個坑,安卓手機下沒法保存
src
爲base64
的圖片,後面通過採坑,決定經過將base64
數據發到後端,而後返回png
的地址來解決這個坑。
埋點的目的是收集各類信息,好比 PV
、 UV
、點擊率、異常。那麼埋點該怎麼作,通常的前端埋點,我認爲,須要遵循兩點:
第一點:不要過分入侵代碼,也就是俗稱的硬編碼
第二點:作到複用性,也就是進行統一的封裝
好比,將對應的埋點進行重命名,如 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
的形式去大體說一下後端的總體狀況吧。
大體有以下幾點:
API
接口這裏使用的是 egg.js
,其經過約定的哲學,來快速搭建應用,提升開發效率。egg
的學習文檔有不少,貼個官網文檔地址吧:
這個沒啥好說的,經過路由攔截,而後轉到對應的邏輯處理,中間可能須要通過相應的中間件進行處理。
如何更好地設計返回,這裏的作法是將返回封裝成 plugin
,而後擴展到 context
上。這樣的話,你就能夠經過 ctx.sendresult
來統一處理返回內容了。
中間件也沒啥好說的,本質上就是一個導出的函數。用來處理接收到的數據,並進行對應的數據處理。
數據處理基本有兩種結局:
game over
舉個真實場景:
好比最多見的,鑑權。咱們能夠在路由中就進行控制:
代碼以下:
router.post('/api/xxx', auth(), controller.xxx);
複製代碼
在處理受限接口的請求時,先進行 auth
處理,若是沒有成功,就中斷後續的邏輯處理,直接返回沒有登陸或者沒有受權之類的響應內容。
MVC
和前端的 MV*
V
這裏我簡單提一下,在 node
層,和在前端層,其 V
你們都是能理解的,都是視圖的意識,node
層,也要寫頁面的,好比咱們寫一個 404
頁面,配合處理異常的中間件。若是中間件捕捉到了 404
,那麼直接返回 404
頁面給前端。
C
C
在前端來講,實際上是最富有變化的一個點,因此我加了 *
表示。C
對 node
來講,時候也是最重要的一個部分,它專門去處理接收到的請求,而且分發給各個邏輯處理中心,最後經過一系列的處理,再經過 C
層返回給前端。
M
M
對 node
來講很簡單,在處理邏輯的時候,須要和數據庫進行交互,來實現 CRUD
從而實現數據的增刪改查。M
對前端來講,也很簡單,就是對 V
層的數據進行 CRUD
。先後端的 M
層仍是有點區別的。
總結一下,後端的 MVC
看起來,是比前端的 MVC
好理解,前端的 MVC
就好像被強行安排了一波😂。
隨着前端工程化的持續完善,前端的配置和後端的配置 ,在思想上,基本是一致的,這裏我就不提了。
上面提了,使用 mysql
,固然了,像 egg-sequelize
mysql2
這些都要用的。模型定義一般狀況下是在 model
目錄下,定義好模型,而後掛在到 Application
下,經過 app.model.xxx
來拿到對應模型的上下文。對模型的處理,通常是放在 service
目錄下。
絕大多數狀況下,前端的項目在打包後,會放到後端的 public
目錄下,因此看到這,小夥伴應該明白了構建工具中的 publicPath
是什麼意識了吧(手動滑稽)。
看完後端部分,是否是發現也挺簡單的,代碼都是 js
,前端怎麼寫業務邏輯,後端就怎麼寫業務邏輯。
二者的區別主要是先後端須要考慮的點不同。
後端須要考慮安全、考慮服務器的壓力、考慮接口的設計、考慮數據庫的設計。固然高層次一點,還要考慮負載均衡,高併發等。而前端則須要考慮頁面的美觀性、頁面的流暢性、用戶交互的友好性、頁面的打開速度等等。總之,你們都不容易的,惟有執子之手,才能與子偕老。(手動滑稽 +2
)
讀完,是否是有點感受和結對編程沒啥關係,我特喵的讀完也感受到了。
寫了 6000
字,我圖個啥。
開玩笑的,開玩笑的,其實,本文和結對編程是有強聯繫的,這個過程是我和 S
一塊兒參與完成的。
下圖體如今整個過程當中。
畢竟不能只說結對編程,仍是要說一下其餘的東西的。
我認爲結對編程的魅力,就在於能夠:
互相反饋,及時調 整,共同提升開發效率。固然最重要的是能夠 搞(你在說)基(什麼?)
review
後端代碼,根據後端代碼寫前端請求邏輯等等,好像也是有點花的。本人的一次結對編程體驗
@當愛的表達趕上現實的裝飾器 歡迎關注這位大佬的微信公衆號: 欣仔互動
掘金系列技術文章彙總以下,以爲不錯的話,點個 star 鼓勵一下哦。
我是源碼終結者,歡迎技術交流。
也能夠進 前端狂想錄羣 你們一塊兒頭腦風暴。有想加的,由於人滿了,能夠先加我好友,我來邀請你進羣。
明天就五一了,祝小夥伴五一快樂,我無論什麼安康,我只要大家快樂!
最後:尊重原創,各位首富,轉載請註明出處哈😋