編寫可維護的程式碼是一種溝通技巧 - Max Chernyak

banq發表於2021-12-04

編寫可維護的程式碼很容易。只需保持方法和引數列表簡短,名稱和註釋較長,並遵循樣式指南。

正如一位著名記者曾經寫道:“對於每一個複雜的問題,都有一個清晰、簡單和錯誤的答案。”

使程式碼難以維護的不是樣式和形狀。這是在缺乏明確的如何程式碼工作,它代表什麼以及為什麼它以這種方式被寫?

我將這些問題稱為 “怎麼樣?”, “什麼?”,以及 “為什麼?” 簡稱。

問題很簡單,但回答它們卻沒有什麼直截了當的。

可維護的程式碼是能夠雄辯而周到地向讀者傳達它是如何實現的、什麼實現的以及為什麼實現的程式碼。

 

怎麼樣?

指編寫程式或演算法的表達程度。

您必須將複雜的演算法分解為清晰的步驟。你必須尋找好的比喻來幫助人們理解你的抽象程式碼。換句話說,您必須編寫不斷指導其他工程師的程式碼。這種清晰的溝通水平是罕見的,但偉大的程式碼庫也是如此。

冗長的、令人費解的,或者又是完全的胡言亂語:

def r(s1, s2, s3)
  [s3.bytes, [32], s1.bytes, [10]*2, s2.bytes].map { |ba|
    ba.flat_map(&:chr).inject { |v, a| "#{a}#{v}" }.reverse
  }.inject(&:+)
end

使程式碼易於理解。您可以看到字串正在連線:

def r(s1, s2, s3)
  s3 + " " + s1 + "\n\n" + s2
end

 

什麼?

“將複雜性隔離在一個永遠不會被發現的地方几乎與完全消除複雜性一樣好。”

只要你的函式被很好地隔離、經過很好的測試和很好的命名,你就很難寫出糟糕的程式碼。

在下面的示例中,名稱太長並且考慮到它們的上下文是多餘的。

def render_email_with_a_greeting(email_recipient_name_string_for_rendering_email, email_body_string_for_rendering_email, email_greeting_string_for_rendering_email)
  email_greeting_string_for_rendering_email + " " + email_recipient_name_string_for_rendering_email + "\n\n" + email_body_string_for_rendernig_email
end

好的程式碼:

def render_email(recipient_name, body, greeting: 'Hello,')
  greeting + " " + recipient_name + "\n\n" + body
end

 

為什麼?

“給光,人們就會找到路。”

一些思想流派認為所有程式碼註釋都是程式碼表達的失敗。也就是說,程式碼是最可靠的事實來源:

重要的是要學會:

  1. 查明哪些決策實際上需要上下文。通常,需要解釋的決定來自以下四種情況之一:1) 您的決定存在不明顯的商業原因 2) 您進行了大量研究以做出決定 3) 您對您選擇的解決方案或 4) 您在程式碼審查中被問到了一個問題。在每種情況下,留下澄清評論可能是個好主意。
  2. 確定您的受眾所需的詳細程度。閱讀你的程式碼註釋的人很可能是熟悉你公司內部術語和流程的有經驗的程式設計師。依靠您共享的知識進行有效溝通。

不好程式碼:

# Keyword argument `greeting` has a default value.
def render_email_to_send(recipient_name, body, greeting: 'Hello,')
  # Emails can be plain and html, and while most email
  # clients support html, it's a good practice to add plain
  # text versions as a fallback.
  greeting + " " + recipient_name + "\n\n" + body
end

好程式碼:

def render_email(recipient_name, body, greeting: 'Hello,')
  greeting + " " + recipient_name + "\n\n" + body
end

在檢視上面的程式碼時,我們可以假設熟悉基礎知識並確定幾個潛在的問題:

  • 為什麼我們需要支援自定義問候語?
  • 既然我們使用\n,那麼這個函式是否只用於純文字電子郵件?
  • (對於 ruby​​ists 那裡)為什麼我們連線+而不是"#{interpolation}"?

這是解決它們的一種方法。

# We allow custom greetings because marketing wants to be able to
# personalize them by time of day, e.g. "Good Afternoon, Person".
def render_plain_text_email(recipient_name, body, greeting: 'Hello,')
  # We avoid interpolation because we want nil values to error out.
  # Helps prevent missing content in sent emails.
  greeting + " " + recipient_name + "\n\n" + body
end

現在有程式碼註釋解釋了為什麼我們允許自定義問候語並避免插值。

或者,我們可以考慮通過重新命名greeting為personalized_greeting來消除評論:

def render_plain_text_email(recipient_name, body, personalized_greeting: 'Hello,')
  # We avoid interpolation because we want nil values to error out.
  # Helps prevent missing content in sent emails.
  personalized_greeting + " " + recipient_name + "\n\n" + body
end

 

有用的框架

“如果我有一個小時來解決一個問題,而我的生命取決於解決方案,那麼我會花前 55 分鐘來確定要問的正確問題,一旦我知道正確的問題,我就可以在不到五分鐘的時間內解決問題。 ”

當我們與工程師同事和利益相關者合作時,我們會進行三種最困難的交流:1) 提供反饋(在程式碼審查中)2)協商(在估計中)和 3)傳達抽象概念(在程式碼中)。這些對話可能會引起焦慮,我們每天都會進行多次!這 “怎麼樣?”, “什麼?” 和 “為什麼?” 框架可以幫助我們組織我們的思想。

  1. 在進行程式碼審查時,您可以更具體地指出問題:
    • “我明白你在做什麼,但很難理解它是如何運作的。”
    • “我看到這是如何工作的,以及為什麼我們需要這個,但提取的方法將使它更容易理解什麼這一塊在做什麼。”
    • “我看到正在完成的工作,以及它是如何完成的,但我不清楚我們為什麼做出這個特別的選擇。”
  2. 在協商重構最後期限時,您現在擁有的語言可以幫助利益相關者準確理解您要實現的目標:

    • “很難理解這段程式碼在幕後是如何工作的。在我們自信地改變它之前,我們需要進行重構。”
    • “這個程式碼需要被打破了,所以我們可以更容易地遵循什麼就做什麼。”
    • “我們許多的原因,為什麼從來沒有寫下來,所以我們想嘗試,並新增一些上下文的程式碼庫,我們忘記了。”
  3. 最後,它提供了一個清單,用於在您與團隊共享之前反思您自己的工作:

    • “讀者會很容易理解我的程式碼是如何工作的嗎?”
    • “我的名字是否清楚地表達了我的程式碼完成的任務?”
    • “我是否給出了適當的上下文來表達我為什麼這樣編寫程式碼?”

  4. 相關文章