簡體   English   中英

if-throw 前提條件檢查有效性和 DRY 原則

[英]if-throw precondition check effectiveness and the DRY principle

許多互聯網資源堅持通過if (something_is_wrong) throw Exception{}而不是assert(!something_is_wrong)來檢查 API 函數中的前提條件,我看到了其中的一些優點。 但是,我擔心這種用法可能會導致相同的檢查加倍:

void foo(int positive) {
  if (positive < 1) {
    throw std::invalid_argument("param1 must be positive");
  }
}
void caller() {
  int number = get_number_somehow();
  if (number >= 1) {
    foo(number);
  }
}

可能會像

int number = get_number_somehow();
if (number >= 1) {
  if (number < 1) {
    throw std::invalid_argument("param must be positive");
  }
}

除非調用實際上會通過刪除if之一來內聯和優化,我猜。 此外,兩次寫入檢查(在foo()caller() )可能違反 DRY 規則。 因此,也許我應該去

void caller() {
  int number = get_number_somehow();
  try {
    foo(number);
  } catch (std::invalid_argument const&) {
    // handle or whatever
  }
}

避免重復這些前提條件檢查,在功能合同更改的情況下提供一些性能和大量可維護性。

但是,我不能總是應用這樣的邏輯。 想象一下std::vector只有at()而不是operator[]

for (int i = 0; i < vector.size(); ++i) {
  bar(vector.at(i)); // each index is checked twice: by the loop and by at()
}

此代碼導致額外的 O(N) 檢查! 是不是太多了? 即使它以與上述相同的方式進行了優化,對於可能不會內聯的間接調用或長函數的情況呢?

那么,我的程序應該按照下面的規則編寫嗎?

  • 如果 API 函數可能不會被內聯,或者預計會在調用站點上進行檢查時被多次調用(參見vector示例),則assert()其先決條件(在其中);
  • try-catch 拋出函數而不是在調用之前檢查它們的先決條件(后者似乎破壞了 DRY)。

如果不是,為什么?

因此,您在談論兩個獨立的事情:DRY 和性能。

DRY 是關於代碼維護和結構的,並不真正適用於您無法控制的代碼。 因此,如果 API 是一個黑匣子,並且其中碰巧有您無法更改的代碼,但是您需要單獨擁有,那么我不會認為它不是 DRY 在您的代碼。 Y 是你自己。

但是,您仍然可以關心性能。 如果你衡量一個性能問題,然后用任何有意義的方式修復它——即使它是反干燥的(或者如果它是可以的)。

但是,如果您控制雙方(API 和客戶端)並且您真的想要一個純粹的、無重復的、高性能的解決方案,那么就會有一個類似於這個偽代碼的模式。 我不知道名字,但我認為它是“提供證明”

let fn = precondition_check(myNum)
if fn != nil {
    // the existence of fn is proof that myNum meets preconditions
    fn()
}

API func precondition_check返回一個函數,該函數捕獲其中的myNum並且不需要檢查它是否滿足前提條件,因為它僅在滿足前提條件時才被創建。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM