如何定義團隊的命名規範 - Programming Naming Conventions

Sep.25.2022

命名是個很深奧的議題,剛開始因為不影響功能、命名似乎也不是什麼太大的問題,容易被忽視,但隨著時間的推移,需求不斷增加與變動、程式碼越來越多種寫法,不僅是團隊每個人的命名格式不太一致,就連同一個時空的自己、或許過了一個晚上,可能又想到更好的命名 🥲

如果沒有儘早與團隊成員討論命名,相同類型的命名、要依照 A 同事還是 B 同事的格式?或者自己想到更好的寫法?會有點不太清楚要如何寫會更好,不僅影響程式碼品質、更可能導致技術債的產生。

命名是非常值得關注的細節,好的命名、能幫助程式碼閱讀、提高開發效率、降低維護成本。


什麼是好的命名?

或許我們可以多花一點時間去思考命名是否有符合表達的內容? 檢視我們的命名是否容易理解、能夠幫助閱讀並具有一致性


容易理解

  1. 適當區分單複數 例如:user 是單數,usersuserList 是複數。 從變數命名,可以猜測 users、userList 的值會是 array。
  2. 新增變數的狀態 例如:isSelectedpublishedVersion
  3. 使用有意義而不是難以理解的縮寫

程式碼簡潔很重要,但更重要的是易於理解

例如:

  • 有意義的縮寫
    • id ( identity )、rwd ( responsive web design )等
  • 較難理解的縮寫
    • order system 裡面的 user 簡寫成 osUser
// bad  
const yyyymmdstr = moment().format("YYYY/MM/DD");
// good  
const currentDate = moment().format("YYYY/MM/DD");

幫助閱讀

  • 縮寫不使用全部大寫,看起來更容易閱讀
    • 例如:RWDIP
      • RWDDotsStyleRwdDotsStyle
      • getIPAddressgetIpAddress

觀察如果將縮寫改成全部大寫,會變得較難閱讀。

一致性

  1. 歸納命名格式 例如:Google 官方的 JavaScript Guide,定義 function 使用 camelCase、constants 使用 CONSTANT_CASE

  2. 避免使用不同的命名來描述相同的內容 例如:

  • usermember
  • startbegin
  • getretrieve

在不同開發語言、不同團隊、每個人可能都會有各自的命名習慣,命名沒有標準的答案,是團隊間的約定,主要還是以內部討論為基準、透過溝通的方式,共同定義技術文件、再逐步依循並統一寫法。

如果能夠越早定義團隊的命名規範,溝通出團隊內擁有共識的命名方式,讓產品的程式碼具有明確的命名,最重要的是保持格式的一致性,能夠使得大家開發與維護更加順利。

我們也許會根據一些官方文件或技術文章作為命名的參考,但沒有最好的命名規範,只有透過溝通才能找出最適合團隊的命名規範,在開發階段,如果發現有更適合的命名方式,可以再隨時提出問題並與團隊同仁討論。

針對主要使用 TypeScript 作為開發語言的專案,整理一些命名規範與相關討論如下:

Variables

  • camelCase
    • variableNamesLikeThis
// Immutable Variables
const timeZone = 'Asia/Taipei';
const isSelected = item.id === selectedId;

Function

  • camelCase
    • functionNamesLikeThis

Prefer verbs or verbs + nouns in general.

Function names should be verbs if the function changes the state of the program, and nouns if they're used to return a certain value.

const getUsers = () => { ... }

Constants

  • CONSTANT_CASE
    • CONSTANT_VALUES_LIKE_THIS

Constants’ names are typically nouns or noun phrases.

// True Constants
const IMAGE_URL = 'https://media.aaa.com/';

Enum

  • PascalCase
    • EnumNamesLikeThis
enum ProductStatus {
  Draft = 'DRAFT',
  Active = 'ACTIVE',
  Archived = 'ARCHIVED',
}

Type

  • PascalCase
type ImagePosition = 'LEFT' | 'RIGHT';

type ProductBanner = {
  title: string;
  description?: string;
  imagePosition: ImagePosition;
  status: ProductStatus;
}

Interface

  • PascalCase

變數命名方式因語言會有所差異,例如:Interface 在 C# 推薦加上大寫 I 的前綴,但是在 TypeScript coding guidelines 不建議加上前綴。

Do not use "I" as a prefix for interface names.

interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: number;
}

Use type and interface

  • Use type when you might need a union or intersection
type Foo = number | { someProperty: number }
  • Use interface when you want extends or implements
interface Foo {
  foo: string;
}

interface FooBar extends Foo {
  bar: string;
}

class X implements FooBar {
  foo: string;
  bar: string;
}

Use const and let


Acronyms

// bad
convertOriginalToRWDValue
// good
convertOriginalToRwdValue

// bad
RWDDotsStyle
// good
rwdDotsStyle

// bad
templateHTML
// good
templateHtml

命名對工程師來說,真的是很深奧的一門學問,最後針對 Variable Names ,推薦以下 2 個網站,裡面蒐集各個 Javascript libraries 裡動詞、名詞、形容詞的詞彙,或許可以在開發的時候能夠帶給大家一些靈感

其他參考資源

  • Programming
  • Naming