Làm thế nào để đặt tên resource một cách hiệu quả trong lập trình Android?
Bạn có nhớ lần cuối mình phải ngụp lặn trong strings.xml để tìm đoạn String bạn cần không? Hay những lần bạn phải mở từng cái drawable ra xem để có cái bạn muốn? Mỗi khi chúng ta khởi động 1 project mới, chúng ta thường rất quan tâm đến việc xác định cấu trúc dự án, setup CI, loại build,... ...
Bạn có nhớ lần cuối mình phải ngụp lặn trong strings.xml để tìm đoạn String bạn cần không? Hay những lần bạn phải mở từng cái drawable ra xem để có cái bạn muốn?
Mỗi khi chúng ta khởi động 1 project mới, chúng ta thường rất quan tâm đến việc xác định cấu trúc dự án, setup CI, loại build,... Nhưng bạn đã từng nghĩ đến việc làm sao để đặt tên resource 1 cách hiệu quả chưa? Bạn nên như vậy! Việc Google không đưa ra 1 cấu trúc chính thống cho việc đặt tên file XML đã làm cho việc quản lý resource trong Android trở nên khó khăn và hết sức nhàm chán, đặc biệt là đối với những project lớn.
Ở bài viết này tôi sẽ giới thiệu một cấu trúc đặt tên đơn giản nhưng có thể phần nào giúp ích được cho các bạn:
- Dễ dàng tìm kiếm bất kì resource nào bằng autocomplete.
- Tên được đặt 1 cách logic và dễ đoán.
- Sắp xếp resource 1 cách khoa học.
- Phân chia các loại resource một cách rõ ràng
Nguyên tắc cơ bản
Tên của các loại resource sẽ đều dựa theo 1 quy ước như sau:
Đầu tiên hãy cùng xem mỗi thành phần trong cấu trúc này có ý nghĩa như thế nào:
<WHAT>
Chỉ ra thứ mà resource này đại diện cho, thường là 1 class view của Android. Chỉ áp dụng cho 1 vài loại resource.
Ví dụ: MainActivity => activity
<WHERE>
Miêu tả vị trí logic của nó trong app. Resource nào được sử dụng ở nhiều màn hình thì sẽ sử dụng từ all, còn những cái khác thì sử cái phần mà mình tự đặt tên cho cái view đó.
Ví dụ: MainActivity => main | DetailFragment => detail
<DESCRIPTION>
Dùng để phân biệt những thành phần trong một màn hình.
Ví dụ: title
<SIZE> (KHÔNG BẮT BUỘC)
Được định nghĩa theo kiểu 1 size chính xác hoặc size mang ý nghĩa bao hàm. Thường được sử dụng với drawable và dimen.
Ví dụ: 24dp | small
Dưới đây là cheat sheet để bạn dễ tham khảo:
LỢI ÍCH
- Sắp xếp resource theo màn hình
Thành phần WHERE miêu tả việc resource này thuộc về màn hình nào, vì vậy nó sẽ làm cho việc xác định các id, dimen, drawables,... trở nên dễ dàng cho một màn hình cụ thể nào đó.
- Dễ dàng xác định kiểu resource
Đối với id của resource, thành phần WHAT sẽ miêu tả kiểu của resource đó (ví dụ linearlayout) giúp ích cho việc gán và ép kiểu bằng findViewById().
- Tổ chức resource hiệu quả
Các trình duyệt file thường sắp xếp file theo thử tự bảng chữ cái. Điều này có nghĩa là layout và drawable sẽ được sắp đặt bằng tiền tố WHAT hay WHERE tương ứng.
- Autocomplete hiệu quả
Bởi vì tên resource đã trở nên rất dễ đoán đồng nghĩa với việc sử dụng autocomplete cũng trở nên dễ dàng hơn rất nhiều. Thường thì bạn chỉ cần gõ tiền tố WHAT hoặc WHERE là đã đủ để tìm ra resource mà mình cần.
- Không còn sợ việc trùng tên
Resource giống nhau ở những màn hình khác nhau sẽ có thành phần all hoặc WHERE trong tên. 1 cấu trúc đặt tên cố định sẽ giúp bạn tránh việc đật trùng tên.
- Tên được đặt rõ ràng
Về cơ bản thì tên resource sẽ được đặt một cách logic và hợp lý hơn, góp phần làm cho project trở nên súc tích hơn.
- Công cụ hỗ trợ
Cấu trúc đặt tên này có thể được hỗ trợ một cách dễ dàng bởi việc Android Studio cung cấp những chức năng như: lint rules để bắt buộc cấu trúc này, hỗ trợ refactor khi bạn muốn thay đổi WHAT hay WHERE, sắp xếp resource một cách dễ nhìn hơn...
LAYOUT
Việc đặt tên layout là khá đơn giản bởi 1 màn hình thường chỉ có một vài layout là nhiều. Vì thế cấu trúc này có thể được viết lại như sau:
Trong đó <WHAT> có thể là:
Ví dụ:
- activity_main: layout content của MainActivity
- fragment_detail: layout content của DetailFragment
- view_graph: layout được inflate bởi class custom view GraphView
- item_book: list item trong BookRecyclerView
- layout_actionbar_backbutton : layout chứa 1 action bar và 1 nút back (quá đơn giản nên ko tạo custom view)
STRING
Thành phần <WHAT> trong 1 String là ko cần thiết và ko có tác dụng, nên hoặc là chúng ta sử dụng tiền tố <WHERE> để chỉ ra nơi mà String sẽ được sử dụng:
hoặc tiền tố all nếu string được sử dụng ở nhiều nơi trong app:
Ví dụ:
- detail_title: title of DetailFragment
- feedback_explanation: feedback explanation trong FeedbackFragment
- feedback_namehint: gợi ý của trường đặt tên trong FeedbackFragment
- all_ok: có thể được tái sử dụng trong toàn app
DRAWABLE
Tương tự với String, việc đặt tên drawable sử dụng tiền tố <WHERE> để chỉ ra vị trí mà drawable này sẽ được sử dụng:
hoặc tiền tố all nếu drawable được tái sử dụng ở nhiều nơi trong app:
Bạn còn có thể thêm thành phần size vào cuối của tên nếu resource có nhiều phiên bản với size khác nhau.
Ví dụ:
- detail_placeholder: placeholder trong DetailFragment.
- all_infoicon: info icon có thể tái sử dụng ở nhiều nơi.
- all_infoicon_large: phiên bản có kích thước lớn của info icon.
- all_infoicon_24dp: phiên bản 24dp của info icon.
ID
Đối với id, <WHAT> là tên class của thành phần có id này. <WHERE> là màn hình mà id này được sử dụng. <DESCRIPTION> có thể được sử dụng để phân biệt những thành phần giống nhau trong 1 screen.
Ví dụ:
- tablayout_main -> TabLayout trong MainActivity
- imageview_menu_profile -> ảnh profile trong MenuView
- textview_detail_title -> title TextView trong DetailFragment
DIMENSION
App chỉ nên định nghĩa một tập hợp có giới hạn các dimen để tái sử dụng lại liên tục. Điều này làm cho hầu hết các dimen mặc định có thành phần all.
Vì thế thường thì bạn nên dùng:
Và trong 1 số trường hợp có dimen dành riêng cho 1 màn hình thì:
Trong đó <WHAT> có thể là:
Chú ý là list này chỉ chứa những thành phần <WHAT> thông dụng nhất. Những qualifier khác như rotation, scale,.. thường chỉ được sử dụng với drawable nên sẽ hiếm khi được tái sử dụng.
Ví dụ:
- height_toolbar: Chiều cao của tất cả các toolbar
- textsize_medium: Size medium cho tất cả các text
- size_menu_icon: size của icon trên menu
- height_menu_profileimage: chiều cao của ảnh đại diện ở menu
CÁC HẠN CHẾ ĐÃ BIẾT
- Mỗi màn hình cần có tên độc nhất
Để tránh việc đặt trùng tên trong thành phần <WHERE>, các class view cần có tên độc nhất. Vì thế bạn không thể cùng có MainActivity và MainFragment vì tiền tố main sẽ không còn để chỉ 1 màn hình duy nhất.
- Không support refactor
Thay đổi tên class không làm cho tên resource thay đổi theo. Nên nếu bạn đổi tên MainActivity thành ContentActivity, tên của layout activity_main sẽ không được tự cập nhật và bạn sẽ phải đổi tên nó bằng tay. Hi vọng trong tương lai Android Studio sẽ hỗ trợ điều này.
- Chưa hỗ trợ tất cả các loại resource
Quy tắc đặt tên này tạm thời chưa hỗ trợ tất cả các loại resource. Đối với vài loại resource thì đó là do chúng thường ít được sử dụng hay rất đa dạng (như raw hay assets). Một số loại khác thì rất khó để khái quát hóa (như themes/styles/colors/animations).
KẾT
Tuy quy tắc đặt tên này chưa hỗ trợ hết các loại resource, nó cung cấp cho chúng ta một cách giải quyết đơn giản và dễ dàng trong việc đặt tên XML trong lập trình Android. Qua bài viết hi vọng các bạn sẽ nắm bắt được những điểm mạnh và điểm yếu của phương pháp này để áp dụng vào trong project của mình.
Bài viết này được dịch từ blog A SUCCESSFUL XML NAMING CONVENTION của tác giả Jeroen Mols.