JavaScript 程式庫和架構之間的差異

Umar Hansa
Umar Hansa

本文將說明在用戶端 JavaScript 環境 (即在網路瀏覽器中執行的程式碼) 中,架構和程式庫的差異。不過,本文提出的部分觀點也適用於其他環境,因為程式庫和架構是許多軟體工程領域 (例如原生行動應用程式開發) 的一部分。

本篇文章討論的焦點是程式庫和架構之間的質性差異,而非量化差異。例如:

  • 定量:架構通常會遵循反轉控制原則。
  • 定性:在找工作時,架構經驗可讓未來的雇主更感興趣。

為什麼要學習程式庫和架構?

JavaScript 程式庫和架構的使用率在網路上十分普遍。其他網站似乎都會使用一些第三方程式碼做為 JavaScript 資源的一部分。網頁的重量會隨著時間而變得更糟,進而影響使用者JavaScript 是影響網頁整體大小的重要因素,而這類 JavaScript 通常包含第三方程式庫和架構。

建議您不要說「停止使用 JavaScript 架構」,因為架構可為開發人員帶來極大助益。架構可協助您有效編寫程式碼,並快速提供功能,還能帶來其他好處。相反地,您應該自行瞭解相關資訊,以便在需要時做出明智的決定。

您可能不會問自己:「我今天應該使用程式庫還是架構?」程式庫和架構是兩種截然不同的東西。不過,程式庫和架構經常會混淆,因此您對這兩者瞭解得越多,就越有可能根據實際情況做出明智的決定。

程式庫和架構的範例

您可能會看到其他名稱的第三方程式碼,例如小工具、外掛程式、polyfill 或套件。不過,這些工具通常都屬於程式庫或架構類別。基本上,這兩者之間的差異可歸納如下:

媒體庫

程式庫通常比架構簡單,且功能範圍較窄。如果您將輸入內容傳遞至方法並接收輸出內容,表示您可能使用了程式庫。

請參考以下 lodash 程式庫的範例:

import lodash from 'lodash'; // [1]
const result = lodash.capitalize('hello'); // [2]
console.log(result); // Hello

就像許多程式庫一樣,您可以詳閱這段程式碼,瞭解其功能。這項技術幾乎不需要任何魔法:

  1. import 陳述式會將 lodash 程式庫匯入 JavaScript 程式。
  2. 系統會叫用 capitalize() 方法。
  3. 單一引數會傳遞至方法。
  4. 傳回值會擷取至變數中。

架構

架構通常比程式庫大,且會對整體網頁重量造成更大的影響。事實上,架構可以包含程式庫。

這個範例會顯示沒有程式庫的一般架構,並使用 Vue,這是熱門的 JavaScript 架構:

<!-- index.html -->
<div id="main">
  {{ message }}
</div>

<script type="module">
import Vue from './node_modules/vue/dist/vue.esm.browser.js';

new Vue({
  el: '#main',
  data: {
    message: 'Hello, world'
  }
});
</script>

如果您將這個架構範例與先前的程式庫範例進行比較,可能會發現以下差異:

  • 架構程式碼包含多種技巧,並將這些技巧抽象化為自有的 API。
  • 開發人員無法完全控制運算作業的發生方式和時間。舉例來說,Vue 會將 'Hello, world' 字串寫入網頁的方式和時間,都會從您這裡抽象化。
  • Vue 類別的例項化會產生一些連帶效果,這在使用架構時很常見,而程式庫則可能會提供純函式
  • 此架構會指定特定的 HTML 範本系統,而非使用您自己的系統。
  • 如果您進一步閱讀 Vue 架構說明文件或大多數其他架構說明文件,就能瞭解架構如何規定可用的架構模式。JavaScript 架構可減輕您的認知負擔,因為您不必自行瞭解這些概念。

使用程式庫與架構的時機

閱讀完程式庫和架構的比較後,您可能會開始瞭解何時該使用哪一個:

  • 架構可為開發人員降低複雜度。如前所述,架構可以抽象化邏輯、行為,甚至是架構模式。這項功能在您開始新專案時特別實用。程式庫可以協助處理複雜性,但通常會著重於程式碼重複使用。
  • 架構作者希望您能提高工作效率,因此經常會開發額外的工具、偵錯軟體和其他資源的完整指南,協助您有效使用架構。程式庫作者也希望您能提高工作效率,但程式庫中不常見到專門的工具。
  • 大多數架構都會提供功能性起點,例如架構或樣板,協助您快速建構網路應用程式。程式庫會成為您已建立的程式碼集的一部分。
  • 一般來說,架構會為程式碼集帶來一些複雜性。一開始不一定會發現複雜性,但隨著時間推移,複雜性就會顯現。

提醒您,通常不會將程式庫與架構進行比較,因為這兩者是用於執行不同工作。不過,您對這兩種方法的瞭解越多,就越能決定哪一種方法最適合您。您最終決定要使用哪個架構或程式庫,取決於您的需求。

可切換性

您不會每週更換程式庫或架構。不過,建議您瞭解套件會將您鎖定在其生態系統的缺點。此外,建議您瞭解,決定使用第三方套件的開發人員必須負責在套件和應用程式原始碼之間建立鬆散連結。

與原始碼相關聯的套件較難移除及換成其他套件。您可能需要在下列情況下交換套件:

  • 您必須更新已停止維護的套件。
  • 您發現套件有太多錯誤,無法正常運作。
  • 您會瞭解更符合需求的新套裝方案。
  • 產品需求有所變更,因此不再需要該套件。

以這段程式碼為例:

// header.js file
import color from '@package/set-color';
color('header', 'dark');

// article.js file
import color from '@package/set-color';
color('.article-post', 'dark');

// footer.js file
import color from '@package/set-color';
color('.footer-container', 'dark');

先前的範例在三個個別檔案中使用第三方 @package/set-color 套件。如果您要處理這個程式碼,且需要替換第三方套件,則必須在三個位置更新程式碼。

或者,您也可以簡化維護作業,並將程式庫用法抽象到單一位置,如以下範例所示:

// lib/set-color.js file
import color from '@package/set-color';

export default function color(element, theme = 'dark') {
  color(element, theme);
}

// header.js file
import color from './lib/set-color.js';
color('header');

// article.js file
import color from './lib/set-color.js';
color('.article-post');

// footer.js file
import color from './lib/set-color.js';
color('.footer-container');

在前述範例中,直接使用程式庫已抽象化。因此,如果您必須換用第三方套件,只需更新一個檔案即可。此外,內部 set-color.js 檔案會設定要使用的預設色彩主題,因此程式碼現在更容易使用。

易用性

架構可能會提供複雜的 API,但架構可以提供開發人員工具,讓整體使用體驗更簡單。使用便利性取決於多項因素,且可能非常主觀。架構可能難以使用,原因如下:

  • 這個架構的 API 本身就相當複雜。
  • 這個架構的文件不完整,需要反覆嘗試才能解決問題。
  • 架構使用您和團隊不熟悉的技術。

架構可透過常見的最佳做法緩解這些挑戰,例如:

  • 這個架構提供開發人員和診斷工具,方便您進行偵錯。
  • 這個架構擁有活躍的開發人員社群,他們會共同合作,製作免費的說明文件、指南、教學課程和影片。您只要使用這項內容,就能有效運用架構。
  • 此架構提供的 API 遵循一般程式設計慣例。您先前已學習這類慣例,並熟悉程式碼樣式,因此可有效運用架構。

雖然這些問題通常是架構造成的,但也可能是程式庫造成的。舉例來說,D3.js JavaScript 程式庫功能強大,且擁有龐大的生態系統,提供工作坊、指南和文件等資源,這些資源都會影響其易用性。

此外,架構通常會為您的網頁應用程式規定架構,而程式庫通常會與現有架構相容,不論架構為何。

成效

一般來說,架構對效能的影響比程式庫更大,但這並非絕對。網路效能涵蓋的範圍很廣,因此本節將著重於兩個值得注意的主題:樹狀圖移除和軟體更新。

樹狀圖移除

雖然捆綁只是網頁效能的其中一個面向,但對效能有重大影響,尤其是在使用較大的程式庫時。在匯入和匯出期間使用樹狀圖抖動功能可提升效能,因為這項功能會找出並移除應用程式不需要的程式碼。

當您將 JavaScript 程式碼打包時,可以執行一個稱為樹狀圖搖動 (tree shaking) 的實用步驟,這是一種可提升程式碼效能的最佳化,不過使用程式庫比使用架構更容易執行這項操作。

將第三方程式碼匯入原始碼時,通常會將程式碼合併為一或多個輸出檔案。舉例來說,header.jsfooter.jssidebar.js 檔案都會合併為 output.js 檔案,也就是您在網頁應用程式中載入的輸出檔案。

如要進一步瞭解樹狀圖移除,請參考以下程式碼範例:

// library.js file
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// main.js file
import {add} from './library.js';

console.log(add(7, 10));

為了示範目的,我們刻意將 library.js 程式碼範例縮減至較小的規模,以便與實際情況進行比較。實際情況下,程式庫可能長達數千行。

簡單的套件處理程序可能會匯出以下輸出的程式碼:

// output.js file
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

console.log(add(7, 10));

雖然這個應用程式不需要 subtract() 函式,但仍會納入最終套件。這類不必要的程式碼會增加下載大小、剖析和編譯時間,以及使用者必須支付的執行成本。基本樹狀圖移除方法會移除無效程式碼,並產生以下輸出內容:

// output.js file
function add(a, b) {
  return a + b;
}

console.log(add(7, 10));

請注意,程式碼變得更短、更精簡。在這個範例中,效能提升幅度微不足道,但在實際應用程式中,程式庫的長度可能有數千行,效能影響就會更顯著。有趣的是,Parcel、Webpack 和 Rollup 等新式套件工具更進一步結合了精簡和樹狀結構搖晃,以便建立經過高度最佳化的套件。為了展示套件工具的效能,我們使用 Parcel 建立套件檔案,其中包含先前的程式碼範例。Parcel 移除了所有未使用的程式碼,並匯出這個單一模組:

console.log(7+10);

Parcel 會聰明地移除匯入陳述式、函式定義和其他項目的行為,以便建立經過高度最佳化的程式碼。

雖然捆綁只是網頁效能的其中一個面向,但對效能有重大影響,尤其是在使用較大的程式庫時。相較於使用架構,使用程式庫進行樹狀圖搖動通常更為簡單。

軟體更新

對於許多程式庫和架構而言,軟體更新會新增功能、修正錯誤,並且隨著時間推移而不斷增加大小。您不一定需要下載更新,但如果更新內容包含錯誤修正、所需功能的強化或安全性修正,則建議您更新。不過,透過電匯傳送的資料越多,應用程式效能就越低,對使用者體驗的影響也越大。

如果程式庫的大小增加,您可以使用樹狀圖搖動來減緩成長速度。或者,您也可以使用較小的 JavaScript 程式庫替代方案。詳情請參閱「可互換性」。

如果架構的大小不斷增加,樹狀圖搖晃不僅會變得更加困難,更換架構的難度也會提高。詳情請參閱「可互換性」。

就業能力

許多公司都會對開發人員提出嚴格要求,要求他們熟悉特定架構。他們可能會忽略您對網路基礎知識的瞭解,只專注於您對特定 JavaScript 架構的具體知識!無論對錯,許多工作都面臨這個現實。

您不必具備幾個 JavaScript 程式庫的知識,才能應徵工作,但這也無法保證您能脫穎而出。如果您熟悉幾個熱門的 JavaScript 架構,雇主很可能會認為您在目前的網頁開發人員職缺市場中具有優勢。有些大型企業組織仍使用非常舊的 JavaScript 架構,甚至可能急需熟悉這些架構的候選人。

您可以利用這項公開的秘密來發揮優勢。不過,請謹慎進入職場,並考量下列事項:

  • 請注意,如果您在職涯中花費大量時間只使用一個架構,可能會錯過學習其他更現代架構的機會。
  • 舉例來說,如果開發人員不熟悉軟體開發或網頁開發的基礎知識,卻被聘為架構開發人員,這位開發人員無法編寫有效的程式碼,因此您可能會覺得處理這類程式碼集相當困難或繁重。在某些情況下,這種情況可能會導致工作倦怠。舉例來說,如果程式碼速度緩慢,您可能就需要重構程式碼或調整程式碼效能。
  • 學習網路開發時,最佳的學習路徑就是先專注於網路開發、軟體開發和軟體工程的基礎知識。有了這麼穩固的基礎,您就能快速有效地掌握任何 JavaScript 架構。

結論

您很努力瞭解 JavaScript 架構和程式庫的比較方式,做得好!除非您從事新興專案或擔任顧問,否則不太可能經常選擇架構或程式庫。不過,當這類問題發生時,您對該主題的知識越多,做出的決策就越明智。

如您所知,選擇的架構 (在某些情況下,選擇的程式庫) 可能會大幅影響開發人員體驗和使用者體驗 (例如效能)。