程式碼質量第 2 層 - 可重用的程式碼

騰訊雲加社群發表於2022-01-20

點選一鍵訂閱《雲薦大咖》專欄,獲取官方推薦精品內容,學技術不迷路!

可重用的程式碼可以減少重複勞動。一個軟體中,會有很多類似的業務場景。將這些場景抽象成可重用的程式碼。開發新功能時,重用程式碼可減少重複勞動。

可重用的程式碼可以減少因需求變動,導致多次改動和漏改的情況。試想,要修改全站提交按鈕的顏色,如果全站有100個包含提交按鈕的頁面,每個頁面的按鈕的樣式都沒複用,這改動量和漏改的風險都很大。如果做成可重用的,則只需改動一處。

如何寫出可重用的程式碼?

程式碼塊的職責越多,越難被複用。寫出可重用的程式碼就是:識別,分離出可複用的部分。

考慮這樣的場景:程式碼塊A 的功能是獲取介面資料,並渲染 UI。程式碼塊B 的 UI 和 A 一樣,但獲取的介面資料不一樣。程式碼塊C 獲取的資料和 A 一樣,但 UI 和 A 不一樣。A,B,C 之間的程式碼都不能被複用。

要改成可複用的程式碼,就是將可複用的 UI,獲取介面資料的程式碼獨立出來。

下面,我們來看些常見的可複用的部分和複用方法。

一、UI 展示

UI 展示為外觀的展示,包含:HTML 和 CSS。不包含資料的獲取和事件處理。

用元件可以實現 UI 展示程式碼的複用。這樣的元件被稱為展示元件。資料和事件處理通過屬性傳入。Ant Design 之類的元件庫裡的元件均為展示元件。如下是 React 實現的新聞列表:

import React from 'react'
import s from './style.scss'
import Item, {IItem} from './item'

export interface INewsListProps {
  list: IItem[],
  onItemClick: (id: number) => void
}

const NewsList: FC<INewsListProps> = ({ list, onItemClick }) => {
  return (
    <div className={s.list}>
      {
        list.map(item => (
          <Item
            key={item.id}
            onClick={onItemClick}
            payload={item}
          />
        ))
      }
    </div>
  )
}

export default React.memo(NewsList)

二、介面呼叫

介面呼叫有兩部分可以複用:

介面請求和響應的通用處理。
具體介面的呼叫。

三、介面請求和響應的通用處理

介面呼叫時,常常要做一些通用的處理。比如:

前後端分離的網站,要在介面的請求頭中要加 token 來標識使用者。
介面報錯時,要將錯誤碼轉化成對使用者友好的錯誤資訊。
用 axios 這麼處理:

// 請求攔截器
axios.interceptors.request.use(...)
// 響應攔截器
axios.interceptors.response.use(...)

四、具體介面的呼叫

介面呼叫程式碼一般會放在一個檔案中,如 service.js:

export const fetchList = ...
export const fetchDetail = ...
export const createItem = ...
export const updateItem = ...
export const deleteItem = ...

介面呼叫,還有 Loading 狀態管理,防抖,節流,錯誤重試,快取等場景。React 可以用 useRequest,Vue 也有類似的輪子。

五、業務流程

很多業務流程是類似的,可以被複用。比如,管理後臺列表頁的業務流程都類似是這樣的:

進入頁面時,獲取列表資料。
點搜尋按鈕,根據當前的查詢條件,獲取列表資料。
點分頁,獲取指定頁的列表。
自定義 hooks(Vue3 中叫組合式 API) 支援內部的狀態管理和生命週期。因此,可以用 hooks 來封裝業務流程。下面是用 Vue3 的組合式 API 來封裝管理後臺的列表頁的實現:

import { onMounted, reactive, ref, Ref } from 'vue'
export interface Params {
  url: string
  searchConditions: Record<string, any>
}

interface Return<T> {
  searchConditions: Record<string, any>
  resetConditions: () => void
  pagination: Record<string, any>
  fetchList: (isReset: boolean) => void
  list: Ref<T[]>
  isLoading: Ref<boolean>
}

function useList<T extends Record<string, any>> ({
  url,
  searchConditions: initCondition
}: Params): Return<T> {
  const searchConditions = reactive({...initCondition})
  const pagination = reactive({
    pageSize: 10
  })
  const list = ref<T[]>([]) as Ref<T[]>
  const isLoading = ref(false) as Ref<boolean>
  // isReset 為 true 表示搜第一頁。
  const fetchList = (isReset: boolean = false): void => ...

  // 進入頁面
  onMounted(() => {
    fetchList()
  })

  return {
    searchConditions,
    pagination,
    fetchList,
    list,
    isLoading,
  }
}

export default useList

推薦個 hooks 工具庫:ahooks。Vue 版:ahooks-vue。

六、資料

有些資料指會被多個地方用到。如:登入的使用者資訊,許可權資料。

可以用狀態管理庫來管理這些資料。React 狀態管理一般用 Redux,Mobx 或 Context API。 Vue 一般用 Vuex。

七、工具函式

工具函式是與業務無關的。如:格式化日期,生成唯一的 id 等。Lodash 和 moment.js 包含了很多的工具方法。

總結

要寫出可重用的程式碼,本質就是識別和分離出可複用的部分。前端可以從 UI 展示,介面呼叫,業務流程,資料,工具函式 中找出可複用的部分。

程式碼質量的下一層次就是:可重構的程式碼。我會在下一篇文章中介紹。

金偉強往期精彩文章推薦:

聊聊程式碼質量 - 《學得會,抄得走的提升前端程式碼質量方法》前言
程式碼質量第五層 - 只是實現了功能
程式碼質量第四層 - 健壯的程式碼
程式碼質量第三層 - 可讀的程式碼

image.png

《雲薦大咖》是騰訊雲加社群精品內容專欄。雲薦官特邀行業佼者,聚焦於前沿技術的落地及理論實踐之上,持續為您解讀雲時代熱點技術、探索行業發展新機。點選一鍵訂閱,我們將為你定期推送精品內容。

相關文章