程式碼背後的智慧:20條程式設計感悟

木宛城主發表於2024-11-09

大家好,我是木宛哥;在 10餘年的工作經歷讓我深刻體會到軟體開發不僅僅是寫程式碼,更是一個系統化的交付過程。
為此我總結了20條程式設計感悟,涵蓋了程式碼規範、設計原則、測試方法與交付流程等多個方面;​透過遵循程式碼規範,讓程式碼更加可讀與可維護,同時合理的設計能夠有效應對需求變化,模組化的單元測試又確保了產品的可靠性,顧全的交付流程最後提升了專案質量。
希望這些感悟更多程式設計師提供參考,幫助大家在程式設計的道路上不斷進步。

1. 清晰的命名

● 原則:程式碼應該易於閱讀和理解;例如:變數、函式和類的名稱應能清楚表達其意圖;

● 示例:

// 明確表示學生數量
int numberOfStudents = 30; 

/**
 * 計算圓面積
 * @param radius 半徑
 * @return 面積
 */
public double calculateAreaOfCircle(double radius) {
    return Math.PI * radius * radius;
}

2. 使用註釋

● 原則:在複雜或重要的程式碼段新增註釋,幫助他人理解;

● 示例:

/**
 * 計算給定列表的平均值
 *
 * @param numbers 要計算的數字列表
 * @return 返回數字的平均值,如果列表為空則返回0
 */
public static double calculateAverage(List<Double> numbers) {
    if (numbers == null || numbers.isEmpty()) {
        return 0;
    }

    double sum = 0.0; // 用於儲存數字的總和
    int count = 0; // 用於記錄有效數字的數量

    // 遍歷列表中的每個數字並計算總和
    //【注意】:檢查列表中的每個元素是否為 null,需要過濾
    for (Double num : numbers) {
        if (num != null) {
            sum += num; 
            count++;
        }
    }

    if (count == 0) {
        return 0;
    }
    double average = sum / count;
    return average;
}

3. 一致的編碼風格

● 原則:遵循團隊的編碼標準,保持程式碼風格一致;

● 示例:使用統一的縮排和大括號位置。例如 IDEA 等 IDE 中配置統一的 CodeStyle:Alibaba-CodeStyle 、Google-CodeStyle 等;

4. 程式碼模組化

● 原則:將功能分解成小模組,增加重用性;

● 示例:

public class Calculator {
    /**
     * 加
     * @param a
     * @param b
     * @return
     */
    public int add(int a, int b) {
        return a + b;
    }

    /**
     * 減
     * @param a
     * @param b
     * @return
     */
    public int subtract(int a, int b) {
        return a - b;
    }
}

5. 避免重複程式碼

● 原則:遵循DRY原則(Don’t Repeat Yourself);

● 示例:

//不好的實踐:重複
public class Calculator {
    public void addAndPrint(int a, int b) {
        int result = a + b;
        System.out.println("Result: " + result);
    }

    public void addAndPrintAnother(int x, int y) {
        int result = x + y;
        System.out.println("Result: " + result);
    }
}

//好的實踐:我們可以提取出一個公共方法來遵循DRY原則:
public class Calculator {

    public void addAndPrint(int a, int b) {
        printResult(add(a, b));
    }

    public int add(int a, int b) {
        return a + b;
    }

    private void printResult(int result) {
        System.out.println("Result: " + result);
    }
}

6. 依賴介面而不是具體的實現

● 原則:依賴介面而不是具體的實現,增強靈活性;

● 示例:


public interface Shape {
    double area();
}

public class Circle implements Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

public class Square implements Shape {
    private double sideLength;

    public Square(double sideLength) {
        this.sideLength = sideLength;
    }

    @Override
    public double area() {
        return sideLength * sideLength;
    }
}

//依賴介面而不是具體的實現
void printf(Shape shape);

7. 避免魔法數字

● 原則:使用常量代替魔法數字;

● 示例:


final double FIXED_RATE = 3
double area = FIXED_NO * radius

8. 簡化條件語句

● 原則:避免複雜的條件邏輯。用快速 return 來減少 if 巢狀層次;

● 示例:


//不推薦:巢狀太深
public void checkUser(User user) {
    if (user != null) {
        if (user.getAge() > 18) {
            if (user.isActive()) {
                // 允許訪問
                System.out.println("Access granted");
            } else {
                System.out.println("User is not active");
            }
        } else {
            System.out.println("User is underage");
        }
    } else {
        System.out.println("User is null");
    }
}

//推薦:快速失敗返回
public void checkUser(User user) {
    if (user == null) {
        System.out.println("User is null");
        return;
    }
    
    if (user.getAge() <= 18) {
        System.out.println("User is underage");
        return;
    }

    if (!user.isActive()) {
        System.out.println("User is not active");
        return;
    }

    // 允許訪問
    System.out.println("Access granted");
}

9. 異常處理

● 原則:透過適當的異常處理提高程式的健壯性;

● 示例:


//異常
try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    log.error("非法引數,不能被零除");
}

//熔斷
try (Entry entry = SphU.entry("resourceName")) {  
    // 你的業務邏輯  
} catch (BlockException ex) {  
    // 處理被阻止的請求  
}

10. 標準化錯誤日誌處理

● 原則:統一錯誤處理的方式和日誌記錄。方便日誌採集和告警配置;

● 示例:


public void logError(String message) {
    log.error("ERROR|Trace:{0}|Msg:{1} " Context.getTrace(), message);
}

11. 方法引數不宜過長

● 原則:方法引數應儘量少,避免混亂,超過3個推薦封裝成模型;

● 示例:


//不推薦
void createUser(String name,int age,String email);


//推薦
public class UserService {
    public void createUser(User user) {
        
    }
}

class User {
    private String name;
    private int age;
    private String email;

    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    // Getters and Setters
}

12. 使用現有工具類來簡化操作

● 原則:優先使用現有工具類 如apache.commons來簡化操作

● 示例:


StringUtils.isNotEmpty("");
CollectionUtils.isNotEmpty()

13. 儘量使用不變的變數

● 原則:使用final關鍵字宣告不可變的變數,提高程式碼的可靠性;

● 示例:


final int MAX_VALUE = 100;
ImmutableList.of();

14. 測試驅動開發(TDD)

● 原則:先寫測試,再寫程式碼,確保程式碼的可測試性;

● 示例:


@Test
public void testAdd() {
    Calculator calculator = new Calculator();
    assertEquals(5, calculator.add(2, 3));
}

15. 避免過度最佳化

● 原則:優先考慮程式碼的可讀性,最佳化通常是在識別出效能問題後進行的;

16. 使用版本控制

● 原則:使用版本控制工具(git)管理程式碼變化;

17. 重視系分文件

● 原則:

○ 開發前,考慮清楚為什麼要做這個需求。從背景及現狀分析->為什麼要做(why)->要做什麼(what)->如何去做(how) 體系化思考;

○ 再從業務用例分析->系統依賴分析->領域模型分析->架構設計分析->時序圖分析等落地最終的系分;

18. 重視程式碼評審

● 原則:定期進行程式碼評審,提高程式碼質量,提高團隊研發意識;

19. 重視每一次交付

● 原則:

○ 事前鎖定資源,上下游達成一致,明確里程碑計劃;

○ 事中按需推進,每週專案進度同步,及時通曬風險;

○ 事後組織覆盤以及關注業務資料(關注價值)

20.重視交付質量

● 原則:新功能需多考慮灰度驗證

○ 後端服務:可按分組進行灰度驗證(gray 分組->default 分組)

○ 客戶端:小範圍升級驗證無問題後,逐步放量升級;

寫在最後

歡迎關注我的公眾號:程式設計啟示錄,第一時間獲取最新訊息;

微信 公眾號
image image

相關文章