iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0
Software Development

程式淨化計畫:痛苦是重構的起源!系列 第 26

Clean Code - Chapter 12 Emergence(嶄露頭角)

  • 分享至 

  • xImage
  •  

以下是讀完Clean code第12章節 Emergence的筆記:

Getting Clean via Emergent Design

  • 根據Kent Beck的四條規則, 只要能遵循, 設計就能變簡單
    • 執行所有測試
    • 不可以重複
    • 表達開發者的意圖
    • 盡可能減少類別和方法的數量
    • 以上規則是按照其重要程度而排列

Simple Design Rule 1: Runs All the Tests

  • 不可測試的系統 = 不能驗證系統正確 = 不該部署!
  • 遵循SRP、DIP等原則, 能使類別短小、好維護、鬆耦合等, 使測試更容易寫

Simple Design Rules 2–4: Refactoring

  • 當寫了一些程式碼, 得思考是否重構設計
    • 重構最好的條件是, 要先有測試
      • 測試消除了整理程式碼會破壞程式碼的恐懼
  • 重構最簡的三道規則如後面提到

No Duplication

  • 重複是良好系統的最大敵人!
  • 常見的集合類別會有的方法:
int size() {}
boolean isEmpty() {}
  • 實作上, 可以重複使用
boolean isEmpty() {
	return 0 == size();
}
  • 另外再看一個函數案例:
public void scaleToOneDimension(
  float desiredDimension, float imageDimension) {
  if (Math.abs(desiredDimension - imageDimension) < errorThreshold)
    return;
  float scalingFactor = desiredDimension / imageDimension;
  scalingFactor = (float)(Math.floor(scalingFactor * 100) * 0.01 f);
  RenderedOp newImage = ImageUtilities.getScaledImage(
    image, scalingFactor, scalingFactor);
  image.dispose();
  System.gc();
  image = newImage;
}

public synchronized void rotate(int degrees) {
  RenderedOp newImage = ImageUtilities.getRotatedImage(
    image, degrees);
  image.dispose();
  System.gc();
  image = newImage;
}
  • scaleToOneDimension和rotate有一些重複程式碼, 重構後:
public void scaleToOneDimension(
  float desiredDimension, float imageDimension) {
  if (Math.abs(desiredDimension - imageDimension) < errorThreshold)
    return;
  float scalingFactor = desiredDimension / imageDimension;
  scalingFactor = (float)(Math.floor(scalingFactor * 100) * 0.01 f);
  replaceImage(ImageUtilities.getScaledImage(
    image, scalingFactor, scalingFactor));
}

public synchronized void rotate(int degrees) {
  replaceImage(ImageUtilities.getRotatedImage(image, degrees));
}

private void replaceImage(RenderedOp newImage) {
  image.dispose();
  System.gc();
  image = newImage;
}
  • 當不斷抽取函數, 漸漸破壞SRP原則
    • 建議可以把新函數分解到別的類別
  • Template method模式是移除高層級重複的通用技術, 如下方案例
    • accrueUSDivisionVacation和accrueEUDivisionVacation有大量相似的程式碼
public class VacationPolicy {
  public void accrueUSDivisionVacation() {
    // code to calculate vacation based on hours worked to date
    // ...
    // code to ensure vacation meets US minimums
    // ...
    // code to apply vaction to payroll record
    // ...
  }

  public void accrueEUDivisionVacation() {
    // code to calculate vacation based on hours worked to date
    // ...
    // code to ensure vacation meets EU minimums
    // ...
    // code to apply vaction to payroll record
    // ...
  }
}
  • 透過template method, 重構後:
abstract public class VacationPolicy {
  public void accrueVacation() {
    calculateBaseVacationHours();
    alterForLegalMinimums();
    applyToPayroll();
  }
  private void calculateBaseVacationHours() {
    /* ... */ };
  abstract protected void alterForLegalMinimums();
  private void applyToPayroll() {
    /* ... */ };
}

public class USVacationPolicy extends VacationPolicy {
  @Override protected void alterForLegalMinimums() {
    // US specific logic
  }
}

public class EUVacationPolicy extends VacationPolicy {
  @Override protected void alterForLegalMinimums() {
    // EU specific logic
  }
}

Expressive

  • 軟體專案的主要成本: 長期維護!!!
  • 作者將程式碼寫得越清楚, 其他人花在理解程式碼的時間就少, 也能減少缺陷、縮減維護成本
  • 從權責命名、短小函數、短小類別、標準命名(比如Design pattern的command, vistor等)、單元測試, 都是增加維護性的技巧
  • 最重要的是, 要多嘗試!
    • 多花時間琢磨這些技巧

Minimal Classes and Methods

  • 當我們盡力遵守SRP原則、消除重複程式碼等技巧, 可能寫出太多很短小的函數與類別
  • 有時某些教條太奇怪, 會導致產出太多無意義的函數與類別
    • 避免盲目遵從
  • 這是4大規則的最後優先順序, 最重要的仍是前三項規則!

上一篇
Replace Type Code with Class 的重構
下一篇
Clean Code - Chapter 2 Meaningful Names - Part 1
系列文
程式淨化計畫:痛苦是重構的起源!31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言