Tản mạn đêm khuya

Khi bắt đầu học, tìm hiểu về một ngôn ngữ lập trình, một framework mới thì cách tiếp cận của mình đó là xác định tổng quan về mục đích mà ngôn ngữ đó được ra đời, tại sao mình nên học nó, sau đó tìm hiểu các khái niệm cơ bản, làm các ví dụ và bắt đầu tự làm project nhỏ demo để hiểu hơn về ngôn ngữ lập trình đó. Nhưng sau một thời gian được làm project với một số nhóm thực tế thì mình nhận ra rằng mình đã thiếu đi một phần rất quan trọng đó là học cách viết code có quy tắc.
Việc viết code có quy tắc sẽ giúp code dễ đọc code của người khác cũng như của mình, dễ bảo trì, giúp cho chúng ta tránh một số lỗi không đáng có, và cả các anti-patterns. Tuy nhiên không phải quy tắc nào, hay thời điểm nào cũng phù hợp để áp dụng mà có thể còn tùy đội dự án hay project mà chúng ta đang làm lớn nhỏ khác nhau, cần nhanh chóng hay khả năng mở rộng… Cách tốt nhất đó là kết hợp giữa kinh nghiệm lập trình của bản thân, các công nghệ áp dụng và dựa trên nguyên tắc code chuẩn.
VueJS thật tuyệt vời khi chính trong trang chủ của framework này đội ngũ core members đã có những chia sẻ cụ thể cho chúng ta về những nguyên tắc nên áp dụng, tham khảo khi code. Bài viết sau đây mình xin phép được dịch từ bài gốc Style guide: Priority B Rules: Strongly Recommended (Improving Readability) và kết hợp kinh nghiệm bản thân trình bày một số phần theo ý hiểu.

Priority B Rules: Strongly Recommended (Improving Readability)

Đây là nguyên tắc số 2 trong 4 nguyên tắc được đề cập tới bài viết
Priority A Rules: Essential (Error Prevention)
Priority B Rules: Strongly Recommended (Improving Readability)
Priority C Rules: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
Priority D Rules: Use with Caution (Potentially Dangerous Patterns)

#Component file

Khi xây dựng hệ thống mà sẵn sàng sử dụng chung, kết hợp nhiều files thì mỗi component nên được xây dựng trong từng file tách biệt của riêng chúng.
Điều này giúp chúng ta nhanh chóng hơn trong việc tìm kiếm component, sửa chữa hoặc xem lại cách sử dụng của nó.

Bad

Vue.component('TodoList', {
  // ...
})
Vue.component('TodoItem', {
  // ...
})

Good

components/
|- TodoList.vue
|- TodoItem.vue

#Singlesfile component filename casing

Tên của single file component nên để dạng PascalCase (in hoa chữ cái đầu mỗi từ) hoặc kebab-case (chữ thường toàn bộ và có có gạch nối - giữa các từ)

Bad

components/
|- mycomponent.vue
components/
|- myComponent.vue

Good

components/
|- MyComponent.vue
components/
|- my-component.vue

#Base component names

Base component là component thành phần hay component cở sở sẽ được sử dụng ở trong component khác. Những component được xây dựng để đáp ứng về thiết kế hoặc một số hành vi cụ thể trong ứng dụng của chúng ta.
Nó có thể chỉ bao gồm:

  • HTML elements
  • Một hoặc nhiều Base component khác, và
  • Các thành phần UI của bên thứ 3

Nhưng nó sẽ không bao giờ chứa component state (ví dụ như Vuex store)
Tên của những component này sẽ bào gồm phần prefix là Base | App | V và theo sau là tên của element mà nó thể hiện (ví dụ BaseButton | AppButton | VButton).
Những lợi ích của việc đặt tên này:

  • Khi mà trình biên dịch của chúng ta tổ chức file theo thứ tự từ điển thì những component này sẽ được sắp xếp liền nhau và chúng ta có thể dễ dàng nhận ra chúng.
  • Khi mà tên của component luôn phải đặt theo nguyên tắc multi-words thì cách đặt tên này ngăn ngừa chúng ta lựa chọn từ bắt đầu trong tên của component một cách tùy tiện (vd: MyButton* | VueButton).
  • Khi những component này thường xuyên được sử dụng thì chúng ta có thể cài đặt chúng là global thay vì phải import nó trong mỗi file component mà mình sử dụng.

Bad

components/
|- MyButton.vue

Good

components/
|- BaseButton.vue
components/
|- AppButton.vue
components/
|- VButton.vue

#Tightly coupled component names

Là những component con mà được kết hợp chặt chẽ với component cha của nó thì khi đặt tên nên thêm tên của componet cha làm tiền tố cho component con.
Cách giải quyết khác có thể mình tạo phân cấp folder cha con với tên folder cha giống tên component cha như sau:

// (*)
components/
|- TodoList/
   |- Item/
      |- Button.vue
   |- Item.vue
|- TodoList.vue

Nhưng với cách (*) sẽ có bất tiện đó là:

  • Khi mình muốn mở file trên editor trong trường hợp có nhiều component con cùng tên ví dụ như Button có thể có cả trong LoginForm component chẳng hạn và nhiều hơn thế nữa thì lúc này khi tìm kiếm theo tên file sẽ gây ra kho khăn cho chúng ta lựa chọn đúng file component mà mình muốn sử dụng.
  • Khi cây phân cấp của mình có độ sâu tương đối lớn thì việc mở file thông qua sidebar của editor đúng là khủng khiếp 😄

Bad

components/
|- TodoList.vue
|- TodoItem.vue

Good

components/
|- TodoList.vue
|- TodoListItem.vue

#Self-closing components

Những component không chứa nội dung giữa hai thẻ đóng và mở (ví dụ <MyComponent></MyComponent>) thì nên được self-closingsingle file component, string templateJSX nhưng không bao giờ trong DOM.
Đó là những component không chỉ thông báo rằng nó không có content, nhưng nó còn có nghĩa là phải không có content. Ví như việc một trang giấy trắng trong một quyển sách và một trang chỉ chứa dòng dữ “Trang này để trống”.

Good

<!-- In single-file components, string templates, and JSX -->
<MyComponent/>

<!-- In DOM templates -->
<my-component></my-component>

Code của chúng ta sẽ nhìn gọn gàng hơn khi bỏ đi tag đóng không cần thiết.

#Full-word component names

Sử dụng từ ngữ đầy đủ để đặt tên cho component thay vì viết tắt. Nguyên tắc này có thể chúng ta sẽ dễ mắc phải khi gặp những component mà tên của nó khá là dài. Tuy nhiên thì chúng ta luôn luôn nên tránh viết tắt để đảm bảo tính dễ hiểu của code

Bad

components/
|- SdSettings.vue
|- UProfOpts.vue

Good

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue

#Prop name casing

Tên của prop nên luôn được khai báo dưới dạng camelCase nhưng sử dụng kebab-key trong template và JSX

Bad

Bad

props: {
  'greeting-text': String
}
<WelcomeMessage greetingText="hi"/>

Good

props: {
  greetingText: String
}
<WelcomeMessage greeting-text="hi"/>

#Simple computed property

Một computed property phức tạp thì nên tách ra thành nhiều property nhỏ hơn nên có thể, để dễ test, dễ đọc và dễ thay đổi hơn khi có sự thay đổi về yêu cầu thiết kế.

Bad

computed: {
  price: function () {
    var basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}

Good

computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}

#Directive shorthands

Việc sử dụng derective (vd: v-bind, v-on) hay shorthands (vd: :, @) cần lựa chọn 1 trong 2, hoặc là dùng hoặc là không bao giờ, chứ đừng chỗ này dùng derective, chỗ khác dùng shorthands.

Bad

<input
  v-on:input="onInput"
  @focus="onFocus"
>

Good

<input
  @input="onInput"
  @focus="onFocus"
>
// hoặc
<input
  v-on:input="onInput"
  v-on:focus="onFocus"
>

Tổng kết

Trên đây là những nguyên tắc nằm trong bộ nguyên tắc với mức độ ưu tiên thứ hai mà chúng ta nên áp dụng, tham khảo khi bắt tay vào viết ứng dụng với Vue.js. Hãy nhỡ rằng đó là Strongly RecommendedStrongly Recommended!
Cảm ơn bạn đã dành thời gian đọc hết bài viết!