身為開發人員,我們都浪費了時間,盯著一段程式碼,試圖破解其目的,並想知道原始作者在想什麼。在軟體開發的世界中,專案易手且程式碼庫快速發展,編寫自文件程式碼不僅是一種可有可無的東西,而且也是一種可有可無的東西。這是必要的。

在本文中,我們將探索編寫不言自明的程式碼的藝術,減少對外部文件的依賴,並使您自己和其他開發人員的生活變得更輕鬆。

什麼是自文件程式碼?

自記錄程式碼是以清晰、富有表現力和有意的方式編寫的程式碼,使其目的和功能易於理解,而不需要大量註解或外部文件。

這是關於編寫以下程式碼:

  • 可讀性:程式碼一目了然,易於閱讀與理解

  • 富有表現力:清晰傳達其意圖和目的的程式碼

  • 可維護:易於修改和更新的程式碼,不會引入錯誤或破壞性更改

為什麼自我文件化程式碼很重要

編寫自文件程式碼有幾個好處:

  1. 減少認知負擔:當程式碼不言自明時,開發人員可以快速掌握其目的和功能,從而減少理解和使用程式碼庫所需的腦力勞動。

  2. 更快的入職:當程式碼庫是自記錄的時,新的團隊成員可以更快地上手,因為他們不需要嚴重依賴外部文件或廣泛的知識轉移會議。

  3. 改進的協作:自記錄程式碼有助於團隊成員之間更好的協作,因為它可以最大限度地減少誤解並促進對程式碼庫的共同理解。

  4. 增強的可維護性:當程式碼是自記錄的時,隨著時間的推移,維護和更新會更容易,因為開發人員可以快速理解現有程式碼並做出明智的更改。

編寫自文件程式碼的技術

讓我們探索一些編寫自文件程式碼的實用技術,重點是 TypeScript:

1.使用有意義的名字

使程式碼自記錄的最有效方法之一是為變數、函數、類別和模組使用有意義的名稱。考慮以下範例:

// Bad
const x = 5;
const y = 10;
const z = x + y;

// Good
const numberOfItems = 5;
const itemPrice = 10;
const totalCost = numberOfItems * itemPrice;

在「Good」範例中,變數名稱清楚地傳達了它們的用途,使程式碼更具可讀性和不言自明。

2. 寫出小而集中的函數

編寫小型、集中的函數是自文件程式碼的另一個關鍵方面。函數應具有單一職責,並準確命名以反映其目的。例如:

// Bad
function processData(data: any): any {
    // ...
    // Lots of complex logic
    // ...
    return result;
}

// Good
function extractRelevantFields(data: Record<string, any>): Record<string, any> {
    // ...
    return relevantFields;
}

function applyBusinessRules(relevantFields: Record<string, any>): Record<string, any> {
    // ...
    return processedData;
}

function formatOutput(processedData: Record<string, any>): string {
    // ...
    return formattedResult;
}

透過將大函數分解為具有描述性名稱的更小、更集中的函數,程式碼變得更具可讀性和自記錄性。

3. 使用描述性函數和方法名稱

命名函數和方法時,請使用能夠清楚傳達其目的和操作的描述性名稱。避免使用像handle()process()這樣的通用名稱。相反,選擇描述函數功能的名稱。例如:

// Bad
function handleInput(input: string): void {
    // ...
}

// Good
function validateUserCredentials(username: string, password: string): boolean {
    // ...
}

描述性名稱validateUserCredentials可以清楚地表明該函數的用途,而無需其他註釋。

4.利用 TypeScript 的型別系統

TypeScript 強大的類型系統可以大幅增強程式碼的自記錄性質。透過利用 TypeScript 的功能,您可以讓程式碼更具表現力並儘早發現潛在錯誤。例如:

  • 介面和類型:使用介面和自訂類型來定義資料結構的形狀,使程式碼更具可讀性和不言自明。
interface User {
    id: number;
    name: string;
    email: string;
}

function getUserById(id: number): User | undefined {
    // ...
}
  • 枚舉:利用枚舉來表示一組固定的值,提供清晰易讀的方式來處理不同的場景。
enum PaymentStatus {
    Pending = 'pending',
    Completed = 'completed',
    Failed = 'failed',
}

function processPayment(status: PaymentStatus): void {
    // ...
}
  • 類型推斷:盡可能讓 TypeScript 推斷類型,因為它可以減少冗長並使程式碼更具可讀性。
// Bad
const count: number = 10;
const message: string = 'Hello, world!';

// Good
const count = 10;
const message = 'Hello, world!';

5.使用強型別ID

在 TypeScript 中使用 ID 時,請考慮使用強型別 ID,而不是簡單的字串或數字。強型別 ID 提供了額外的類型安全性,並使程式碼更加自文件化。

實作強型別 ID 的一種方法是使用不透明類型:

// user.ts
export type UserId = string & { readonly __brand: unique symbol };

export function createUserId(id: string): UserId {
    return id as UserId;
}

// post.ts
export type PostId = string & { readonly __brand: unique symbol };

export function createPostId(id: string): PostId {
    return id as PostId;
}

透過使用強型別 ID,您可以確保 UserId 只能指派給需要 UserId 的屬性或函數,而 PostId 只能指派給需要 PostId 的屬性或函數。

function getUserById(userId: UserId): User | undefined {
    // ...
}

const userId = createUserId('user-123');
const postId = createPostId('post-456');

getUserById(userId); // No error
getUserById(postId); // Error: Argument of type 'PostId' is not assignable to parameter of type 'UserId'.

強類型 ID 有助於在編譯時捕獲潛在錯誤,並使程式碼更具表現力和自記錄性。然而,與使用簡單的字串類型相比,它們確實引入了一些開銷。根據專案的需求和規模考慮權衡。

6. 在團隊中建立一致性並設定期望

當作為團隊的一部分處理程式碼庫時,建立一致性並設定明確的期望至關重要。這有助於確保每個人都在同一頁上並遵循相同的約定,從而使程式碼更具可讀性和可維護性。

一致性的一個重要面向是命名約定。建立一個風格指南,定義變數、函數、類別和其他實體的命名方式。例如,考慮以下術語及其含義:

  • get :從 API 或資料來源檢索單一值。

  • list :從 API 或資料來源檢索一組值。

  • patch :部分更新現有實體或物件。

  • upsert :更新現有實體或插入新實體(如果不存在)。

透過定義這些術語及其用法,您可以確保整個程式碼庫的一致性。例如:

function getUser(userId: UserId): Promise<User> {
    // ...
}

function listUsers(): Promise<User[]> {
    // ...
}

function patchUser(userId: UserId, updatedData: Partial<User>): Promise<User> {
    // ...
}

一致性有助於使程式碼庫對所有團隊成員更具可預測性和更容易理解。除了命名約定之外,還可以考慮為程式碼庫的其他方面建立指南,例如檔案和資料夾結構、註解、錯誤處理、測試和程式碼格式。

在團隊中工作時,您個人可能不會總是同意所有正在執行的約定。然而,重要的是要記住一致性和協作對於專案的成功至關重要。即使您有不同的偏好或編碼風格,遵守商定的約定也有助於維護有凝聚力的程式碼庫並減少其他團隊成員之間的混亂。

7.複雜場景使用JSDoc或TSDoc

雖然自記錄程式碼應該是主要目標,但在某些情況下可能需要額外的文件,例如複雜的演算法或複雜的業務邏輯。在這種情況下,請考慮使用 JSDoc 或 TSDoc 來提供清晰簡潔的文件。

/**
 * Calculates the Fibonacci number at the given position.
 *
 * @param {number} position - The position of the Fibonacci number to calculate.
 * @returns {number} The Fibonacci number at the specified position.
 */
function fibonacci(position: number): number {
    if (position <= 1) {
        return position;
    }
    return fibonacci(position - 1) + fibonacci(position - 2);
}

透過使用 JSDoc 或 TSDoc,您可以為複雜程式碼提供額外的上下文和解釋,而不會使程式碼庫本身變得混亂。

結論

編寫自文件程式碼是每個開發人員都應該努力掌握的藝術。透過利用有意義的名稱、小而集中的函數、TypeScript 的類型系統以及文件的明智使用,您可以建立可讀、富有表現力和可維護的程式碼。

請記住,我們的目標是編寫不言而喻的程式碼,減少對外部文件的依賴,並使其他開發人員的生活更輕鬆。因此,下次編寫程式碼時,請花點時間考慮如何使其更加自文件化。未來的你和你的隊友都會感謝你!

還有無恥的插頭🔌。如果您在敏捷開發團隊工作並使用線上會議工具(例如規劃撲克或回顧),請查看我的免費工具Kollabe


原文出處:https://dev.to/mattlewandowski93/writing-self-documenting-code-4lga


共有 0 則留言