Clean Code
Team IT – 03/2018
Mục đích
● Do lúc review code, cảm thấy người kế tiếp khó phát triển tiếp nên đọc sách này để tìm ý tưởng
● Đây là phần tóm tắt lại sách “Clean Code: A Handbook of Agile Software Craftmanship”
○ Bạn dễ dàng đọc lại code do chính mình viết sau một quãng thời gian
○ Mọi người dễ nắm công việc của bạn
○ Sản phẩm dễ dàng thêm chức năng mới, chỉnh sửa theo yêu cầu và bảo trì
○ Trông rất ngầu!
Dr.Guru
Nguyên tắc 5S
● Phương pháp được phát triển bởi Nhật Bản
● Nội dung:
○ Seiri (Sort – Sàng lọc): Xác định và phân loại
○ Seiton (Systemmatize – Sắp xếp): Sắp xếp, bố trí lại để dễ dàng tìm kiếm
○ Seiso (Shine – Sạch sẽ): Giữ cho nơi làm việc gọn gàng
○ Seiketsu (Standardization): Duy trì tiêu chuẩn về sạch sẽ và ngăn nắp
○ Shutsuke (Self-discipline): Hình thành thói quen và thực hành
Nguyên tắc 5S dành cho Developer
● Nguyên tắc này do Robert C. Martin (Uncle Bob) trong “Clean Code” đề xuất:
○ Seiri (Sort – Sàng lọc): Đặt tên biến, class, hàm rõ ràng, dễ hiểu
○ Seiton (Systemmatize – Sắp xếp): Cấu trúc rõ ràng, để dễ dàng tra lại đoạn code cần tìm
○ Seiso (Shine – Sạch sẽ): Không xả rác trong code, nhất là những đoạn code không dùng
○ Seiketsu (Standardization): Luôn chuẩn hoá code theo coding convention
○ Shutsuke (Self-discipline): Luôn có ý thức thực hành nghiêm túc, sẵn sàng đối mặt với sự thay đổi
! ?
1 2 3 4 5 6 7 8 9 10
Cách đặt tên biến
● Đặt tên rõ ràng, không dùng ký tự viết tắt
○ elapsedTimeInDays, source, destination | d, a1,
● Sử dụng từ rõ nghĩa
○ accounts, accountGroup | list
● Phát âm dễ dàng
○ marker | modymdhms, genymdhms
● Dễ tìm kiếm (thường áp dụng với các biến hằng số)
○ for (index = 0; index < NUMBER_OF_TASKS; index++) | for (index = 0; index < 69; index++)
● Hạn chế có tiền tố (có một trường phái khuyên dùng tiền tố - prefix)
○ description | str_description
● Quy tắc đặt tên tuỳ vào ngữ cảnh, đặc thù dự án, không nên quá cứng
Hàm/Phương thức
● Chỉ làm một nhiệm vụ
● Đặt tên bắt đầu bằng động từ
○ makeSomeNoise | testableHtml
● Tối đa 3 tham số, trừ một số hàm đặc biệt (nên hạn chế)
● Khi cần nhiều hơn 3 tham số, nên chuyển tham số về dạng Object
○ Circle makeCircle(Point center, double radius) | Circle makeCircle(double x, double y, double radius)
● Nên có cơ chế xử lý Exception và trả về mã lỗi (Error Code)
● Nên tham khảo “Refactoring: Improving the Design of Existing Code” để cấu trúc được rõ ràng hơn
Comment
● Đừng viết comment cho đoạn code “rởm” . Hãy viết lại nó [1]
● Nội dung phải ngắn gọn, súc tích
● Nên viết khi:
○ Khai báo bản quyền của đoạn mã
○ Giải thích ý nghĩa một hàm/phương thức
○ Giải thích ý nghĩa tham số
○ Cảnh báo về một đoạn code nào đó
○ Đánh dấu việc cần làm
● Không nên:
○ Nhồi nhét quá nhiều thông tin
○ Chỗ nào quá rõ ràng, không cần thiết phải viết comment
Định dạng
● Cấu trúc rõ ràng, dễ dàng chỉnh sửa theo yêu cầu
● Mỗi ngôn ngữ lập trình đều có phong cách riêng, không nên gượng ép
● Theo chiều dọc:
○ Một file không nên quá 500 dòng
○ Mỗi concept nên ngăn cách bởi một dấu xuống dòng (blank line)
○ Nếu một hàm gọi một hàm khác, hàm gọi nên nằm phía trên hàm được gọi
○ Nhóm hàm cùng tên khác tham số hoặc cùng nhóm chức năng nên được sắp xếp gần nhau
● Theo chiều ngang:
○ Số ký tự trên một dòng vào khoảng 100 ~ 120 ký tự
○ Nên dùng khoảng trắng phân tách giữa các từ
○ Tránh Deep Nesting (callback/statement lồng nhau quá nhiều)
Cấu trúc dữ liệu
● Cố gắng tổng quát hoá kiểu dữ liệu
● Tuỳ chiến lược phát triển mà chọn hướng lập trình thủ tục hoặc hướng đối tượng
○ Lập trình hướng thủ tục dễ dàng thêm chức năng mà không cần thay đổi cấu trúc dữ liệu. Tương đương, khó mở rộng
cấu trúc dữ liệu mới do phải thay đổi tất cả các chức năng liên quan.
○ Lập trình hướng đối tượng dễ dàng mở rộng đối tượng mà không cần thay đổi các hàm hiện có. Tương đương, khó mở
rộng chức năng do phải thay đổi tất cả các lớp liên quan.
● Hãy tuân theo nguyên tắc Demeter [1] để tránh sự phụ thuộc lẫn nhau
○ “Chỉ chơi với thân bằng quyến thuộc” hoặc “Đừng chơi với người lạ mặt”
○ user.lastest_post | user.posts.order(“created_at DESC”).first
Xử lý lỗi
● Dùng Exception thay vì trả về mã lỗi và dùng try-catch
● Nên ghi log khi throw Exception
● Lợi ích của việc xử lý lỗi:
○ Dễ bảo trì: Dễ tìm ra lỗi cấu trúc lỗi theo kịch bản có sẵn, không cần phải ngắt luồng xử lý
○ Dễ đọc: Trong lúc viết code, dễ nắm bắt được các lỗi có thể xảy ra với chức năng đó
● Hàm không được trả về NULL, thay vào đó hãy trả về Special Case [1] để tránh xử lý NullPointerException
○ return Collection.emptyList() | return NULL
● Nếu hàm trả về NULL là điều xấu thì input của hàm chấp nhận tham số NULL là một tội ác
Tầm kiểm soát
● Thỉnh thoảng dự án cần dùng 3rd-party hoặc mã nguồn mở. Do đó sẽ dẫn đến phụ thuộc vào nhóm phát triển.
● Để kiểm soát 3rd-party, cần dành thời gian kiểm tra kỹ lưỡng trước khi tích hợp vào hệ thống
● Nên tổng quát hoá mã nguồn để tránh cho 3rd-party can thiệp sâu vào hệ thống, giảm được công sức bảo trì khi
3rd-party thay đổi. Có thể dùng Adapter Pattern [1] cho trường hợp này.
Kiểm thử đơn vị
● Việc viết unit test là một bước trong Test-Driven Development (TDD) để đảm bảo chất lượng mã nguồn
● Unit Test mục đích không phải để tìm lỗi, mà để kiểm tra tính hiệu quả của cách thiết kế mã nguồn
● Mỗi Test Case chỉ với một concept
● Quy tắc của TDD
○ Luôn viết Unit Test trước khi viết code
○ Không viết thêm Test Case tiếp theo khi Test Case trước còn sai
○ Không viết thêm code vào khi Test Case vẫn còn đang sai
● Lợi ích đem lại
○ Dễ dàng phát hiện lỗi
○ Khi nhìn lại các Unit Test, bản thân nó đã là tài liệu hướng dẫn sử dụng, bản thiết kế hệ thống
Class
● Kích thước một class không quá lớn
○ Áp dụng Single Responsibility Principle [1], phần xử lý chuyên biệt nên tách sang một lớp chuyên biệt khác.
■ VD: ProductController.getAll gọi ProductRepository.getAll
○ Số lượng các biến và phương thức không quá nhiều
● Việc thay đổi là chuyện thường xuyên, cố gắng tổng quát quá.
○ Áp dụng Dependency Inversion Principle [2]
■ Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào abstraction.
■ Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại. (Các class giao tiếp với nhau thông qua
interface, không phải thông qua implementation.)
Đã xong phần Cơ Bản
Một năm sau hãy đọc lại quyển sách này để hiểu thêm vấn đề
(Bạn đã được xem qua 10/17 chương, thiếu 3 phần phụ lục)
Lưu ý: Sau khi ngộ xong phần Cơ Bản, hãy đọc tiếp các chương còn lại
Sưu tầm
Tham khảo
● Robert C. Martin, “Clean Code: A Handbook of Agile Software Craftmanship”; Pretice Hall, 2009
● https://en.wikipedia.org/wiki/5S_(methodology)
● https://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118
● https://kipalog.com/posts/Nguyen-tac-Demeter-trong-huong-doi-tuong
● https://www.linkedin.com/pulse/clean-code-art-exception-handling-niharika-gupta/
● http://programmer.97things.oreilly.com/wiki/index.php/The_Three_Laws_of_Test-Driven_Development
● http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises
● https://techmaster.vn/posts/33702/nguyen-tac-phat-trien-phan-mem-tot
● https://toidicodedao.com/2016/06/14/series-solid-cho-thanh-nien-code-cung-dependency-inversion-principle

Clean code

  • 1.
    Clean Code Team IT– 03/2018
  • 2.
    Mục đích ● Dolúc review code, cảm thấy người kế tiếp khó phát triển tiếp nên đọc sách này để tìm ý tưởng ● Đây là phần tóm tắt lại sách “Clean Code: A Handbook of Agile Software Craftmanship” ○ Bạn dễ dàng đọc lại code do chính mình viết sau một quãng thời gian ○ Mọi người dễ nắm công việc của bạn ○ Sản phẩm dễ dàng thêm chức năng mới, chỉnh sửa theo yêu cầu và bảo trì ○ Trông rất ngầu!
  • 3.
  • 4.
    Nguyên tắc 5S ●Phương pháp được phát triển bởi Nhật Bản ● Nội dung: ○ Seiri (Sort – Sàng lọc): Xác định và phân loại ○ Seiton (Systemmatize – Sắp xếp): Sắp xếp, bố trí lại để dễ dàng tìm kiếm ○ Seiso (Shine – Sạch sẽ): Giữ cho nơi làm việc gọn gàng ○ Seiketsu (Standardization): Duy trì tiêu chuẩn về sạch sẽ và ngăn nắp ○ Shutsuke (Self-discipline): Hình thành thói quen và thực hành
  • 5.
    Nguyên tắc 5Sdành cho Developer ● Nguyên tắc này do Robert C. Martin (Uncle Bob) trong “Clean Code” đề xuất: ○ Seiri (Sort – Sàng lọc): Đặt tên biến, class, hàm rõ ràng, dễ hiểu ○ Seiton (Systemmatize – Sắp xếp): Cấu trúc rõ ràng, để dễ dàng tra lại đoạn code cần tìm ○ Seiso (Shine – Sạch sẽ): Không xả rác trong code, nhất là những đoạn code không dùng ○ Seiketsu (Standardization): Luôn chuẩn hoá code theo coding convention ○ Shutsuke (Self-discipline): Luôn có ý thức thực hành nghiêm túc, sẵn sàng đối mặt với sự thay đổi
  • 6.
    ! ? 1 23 4 5 6 7 8 9 10
  • 7.
    Cách đặt tênbiến ● Đặt tên rõ ràng, không dùng ký tự viết tắt ○ elapsedTimeInDays, source, destination | d, a1, ● Sử dụng từ rõ nghĩa ○ accounts, accountGroup | list ● Phát âm dễ dàng ○ marker | modymdhms, genymdhms ● Dễ tìm kiếm (thường áp dụng với các biến hằng số) ○ for (index = 0; index < NUMBER_OF_TASKS; index++) | for (index = 0; index < 69; index++) ● Hạn chế có tiền tố (có một trường phái khuyên dùng tiền tố - prefix) ○ description | str_description ● Quy tắc đặt tên tuỳ vào ngữ cảnh, đặc thù dự án, không nên quá cứng
  • 8.
    Hàm/Phương thức ● Chỉlàm một nhiệm vụ ● Đặt tên bắt đầu bằng động từ ○ makeSomeNoise | testableHtml ● Tối đa 3 tham số, trừ một số hàm đặc biệt (nên hạn chế) ● Khi cần nhiều hơn 3 tham số, nên chuyển tham số về dạng Object ○ Circle makeCircle(Point center, double radius) | Circle makeCircle(double x, double y, double radius) ● Nên có cơ chế xử lý Exception và trả về mã lỗi (Error Code) ● Nên tham khảo “Refactoring: Improving the Design of Existing Code” để cấu trúc được rõ ràng hơn
  • 9.
    Comment ● Đừng viếtcomment cho đoạn code “rởm” . Hãy viết lại nó [1] ● Nội dung phải ngắn gọn, súc tích ● Nên viết khi: ○ Khai báo bản quyền của đoạn mã ○ Giải thích ý nghĩa một hàm/phương thức ○ Giải thích ý nghĩa tham số ○ Cảnh báo về một đoạn code nào đó ○ Đánh dấu việc cần làm ● Không nên: ○ Nhồi nhét quá nhiều thông tin ○ Chỗ nào quá rõ ràng, không cần thiết phải viết comment
  • 10.
    Định dạng ● Cấutrúc rõ ràng, dễ dàng chỉnh sửa theo yêu cầu ● Mỗi ngôn ngữ lập trình đều có phong cách riêng, không nên gượng ép ● Theo chiều dọc: ○ Một file không nên quá 500 dòng ○ Mỗi concept nên ngăn cách bởi một dấu xuống dòng (blank line) ○ Nếu một hàm gọi một hàm khác, hàm gọi nên nằm phía trên hàm được gọi ○ Nhóm hàm cùng tên khác tham số hoặc cùng nhóm chức năng nên được sắp xếp gần nhau ● Theo chiều ngang: ○ Số ký tự trên một dòng vào khoảng 100 ~ 120 ký tự ○ Nên dùng khoảng trắng phân tách giữa các từ ○ Tránh Deep Nesting (callback/statement lồng nhau quá nhiều)
  • 11.
    Cấu trúc dữliệu ● Cố gắng tổng quát hoá kiểu dữ liệu ● Tuỳ chiến lược phát triển mà chọn hướng lập trình thủ tục hoặc hướng đối tượng ○ Lập trình hướng thủ tục dễ dàng thêm chức năng mà không cần thay đổi cấu trúc dữ liệu. Tương đương, khó mở rộng cấu trúc dữ liệu mới do phải thay đổi tất cả các chức năng liên quan. ○ Lập trình hướng đối tượng dễ dàng mở rộng đối tượng mà không cần thay đổi các hàm hiện có. Tương đương, khó mở rộng chức năng do phải thay đổi tất cả các lớp liên quan. ● Hãy tuân theo nguyên tắc Demeter [1] để tránh sự phụ thuộc lẫn nhau ○ “Chỉ chơi với thân bằng quyến thuộc” hoặc “Đừng chơi với người lạ mặt” ○ user.lastest_post | user.posts.order(“created_at DESC”).first
  • 12.
    Xử lý lỗi ●Dùng Exception thay vì trả về mã lỗi và dùng try-catch ● Nên ghi log khi throw Exception ● Lợi ích của việc xử lý lỗi: ○ Dễ bảo trì: Dễ tìm ra lỗi cấu trúc lỗi theo kịch bản có sẵn, không cần phải ngắt luồng xử lý ○ Dễ đọc: Trong lúc viết code, dễ nắm bắt được các lỗi có thể xảy ra với chức năng đó ● Hàm không được trả về NULL, thay vào đó hãy trả về Special Case [1] để tránh xử lý NullPointerException ○ return Collection.emptyList() | return NULL ● Nếu hàm trả về NULL là điều xấu thì input của hàm chấp nhận tham số NULL là một tội ác
  • 13.
    Tầm kiểm soát ●Thỉnh thoảng dự án cần dùng 3rd-party hoặc mã nguồn mở. Do đó sẽ dẫn đến phụ thuộc vào nhóm phát triển. ● Để kiểm soát 3rd-party, cần dành thời gian kiểm tra kỹ lưỡng trước khi tích hợp vào hệ thống ● Nên tổng quát hoá mã nguồn để tránh cho 3rd-party can thiệp sâu vào hệ thống, giảm được công sức bảo trì khi 3rd-party thay đổi. Có thể dùng Adapter Pattern [1] cho trường hợp này.
  • 14.
    Kiểm thử đơnvị ● Việc viết unit test là một bước trong Test-Driven Development (TDD) để đảm bảo chất lượng mã nguồn ● Unit Test mục đích không phải để tìm lỗi, mà để kiểm tra tính hiệu quả của cách thiết kế mã nguồn ● Mỗi Test Case chỉ với một concept ● Quy tắc của TDD ○ Luôn viết Unit Test trước khi viết code ○ Không viết thêm Test Case tiếp theo khi Test Case trước còn sai ○ Không viết thêm code vào khi Test Case vẫn còn đang sai ● Lợi ích đem lại ○ Dễ dàng phát hiện lỗi ○ Khi nhìn lại các Unit Test, bản thân nó đã là tài liệu hướng dẫn sử dụng, bản thiết kế hệ thống
  • 15.
    Class ● Kích thướcmột class không quá lớn ○ Áp dụng Single Responsibility Principle [1], phần xử lý chuyên biệt nên tách sang một lớp chuyên biệt khác. ■ VD: ProductController.getAll gọi ProductRepository.getAll ○ Số lượng các biến và phương thức không quá nhiều ● Việc thay đổi là chuyện thường xuyên, cố gắng tổng quát quá. ○ Áp dụng Dependency Inversion Principle [2] ■ Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào abstraction. ■ Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại. (Các class giao tiếp với nhau thông qua interface, không phải thông qua implementation.)
  • 16.
    Đã xong phầnCơ Bản Một năm sau hãy đọc lại quyển sách này để hiểu thêm vấn đề (Bạn đã được xem qua 10/17 chương, thiếu 3 phần phụ lục) Lưu ý: Sau khi ngộ xong phần Cơ Bản, hãy đọc tiếp các chương còn lại
  • 17.
  • 18.
    Tham khảo ● RobertC. Martin, “Clean Code: A Handbook of Agile Software Craftmanship”; Pretice Hall, 2009 ● https://en.wikipedia.org/wiki/5S_(methodology) ● https://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118 ● https://kipalog.com/posts/Nguyen-tac-Demeter-trong-huong-doi-tuong ● https://www.linkedin.com/pulse/clean-code-art-exception-handling-niharika-gupta/ ● http://programmer.97things.oreilly.com/wiki/index.php/The_Three_Laws_of_Test-Driven_Development ● http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises ● https://techmaster.vn/posts/33702/nguyen-tac-phat-trien-phan-mem-tot ● https://toidicodedao.com/2016/06/14/series-solid-cho-thanh-nien-code-cung-dependency-inversion-principle

Editor's Notes

  • #4 Hình ảnh diễn viên điện ảnh Ấn Độ - Aamir Khan trong bộ phim PK. Anh là người mang đến nhiều cảm hứng cho giới trẻ thông qua bộ phim nổi tiếng “3 Idiots”. Xem thêm tại https://en.wikipedia.org/wiki/Aamir_Khan Trong tiếng Phạn, guru có nghĩa là một bậc thầy, người hướng dẫn kiến thức nào đó. Xem thêm tại https://en.wikipedia.org/wiki/Guru
  • #5 Xem thêm tại https://en.wikipedia.org/wiki/5S_(methodology)
  • #7 Trong quyển “Judge this” của Chip Kidd, tác giả sử dụng thang đo này để minh hoạ cho mức độ hiểu biết ý nghĩa về ấn tượng ban đầu với một đối tượng bất kỳ. Ở mức 1 (gần về !) là rõ ràng. Mức 10 (gần về ?) là mơ hồ, ẩn ý. Trong nghệ thuật viết code cũng vậy, chúng ta phải nhận xét đoạn mã có thể hiểu chức năng ngay lần đầu tiếp xúc hoặc nhìn lại sau một thời gian. Ta có thể dùng thang đo này để nhận xét mức độ rõ ràng.
  • #8 # Ghi chú genymdhms: generationTimestamp modymdhms: modificationTimestamp
  • #10 Do từ “comment” trong lập trình không có từ nào trong tiếng Việt mang rõ nghĩa, xin phép dùng từ gốc tiếng Anh. # Chú giải 1. ^ Brian W. Kernighan vàP. J. Plaugher. “Don’t comment bad code – rewrite it”
  • #11 Thật lòng mà nói, có một số Đấng thích viết code sát rạt, đọc muốn nổ mắt :angry: ``` for (var i=0;i<23;i++) { console.log(‘Aluha Ubakaka!’); } ``` Có thể tham khảo thêm tại https://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118
  • #12 Nên tham khảo một số trường hợp liên quan đến vi phạm nguyên tắc Demeter https://hocchoi.com/code-smells-la-gi # Chú thích ^ https://kipalog.com/posts/Nguyen-tac-Demeter-trong-huong-doi-tuong
  • #13 Trong phần Error Handling của Clean Code, họ có nhắc đến Test-Driven Development (TDD), Open/Close Principle. Nội dung slide này dựa theo link dưới đây https://www.linkedin.com/pulse/clean-code-art-exception-handling-niharika-gupta/ Xem thêm ở đây để biết thêm một số sai lầm khi thực thành TDD https://kipalog.com/posts/Mot-so-sai-lam-khi-thuc-hanh-TDD Xem thêm về Open/Close Principle https://kipalog.com/posts/SOLID-la-gi---Ap-dung-cac-nguyen-ly-SOLID-de-tro-thanh-lap-trinh-vien-code--cung https://viblo.asia/p/open-closed-principle-7eEREJJrMgNj # Chú thích 1. ^ Special Case: tuỳ vào ngữ cảnh sẽ trả về đối tượng rỗng. VD: nếu bạn lấy về danh sách nhân viên, nếu không có nhân viên nào thì trả về một mảng rỗng.
  • #14 Phần này thiên về rủi ro do việc không kiếm soát được 3rd-party # Chú thích 1. ^ https://en.wikipedia.org/wiki/Adapter_pattern
  • #15 Tên tiếng Việt hơi chuối, có thể tìm hiểu thêm với từ khoá tiếng Anh “Unit Testing” Ngoài ra, để viết Test Case rõ ràng, ta nên tuân thủ nguyên tắc F.I.R.S.T Fast: Test Case phải chạy nhanh, do tần suất chạy rất cao. Chạy càng sớm, càng tìm ra lỗi sớm. Nếu chạy chậm có thể dẫn đến developer chán nản, bỏ qua việc viết Unit Test. Independent: Mỗi test nên độc lập từ các test khác. Người phát triển nên có thể thực thi bất kỳ phương thức test nào đó, hoặc một tập các test độc lập. Nếu có sự phụ thuộc từ các test thì chúng dễ bị ảnh hưởng khi viết các test mới. Repeatable: Dễ dàng tái tạo trên nhiều môi trường khác nhau như máy của developer, máy của tester, CI, môi trường dev, môi trường production Self-Validating: Test nên trả về kiểu boolean để khi chạy xong xuất ra log. Mục đích để khi nhìn vào có thể tự đánh giá được kết quả thay vì phải làm thủ công. Hiện nay, các xUnit đã hỗ trợ việc này. Timely: Mục đích của việc viết test trước khi viết code là do sau khi viết code sẽ rất khó viết test. # Tham khảo ^ http://labs.septeni-technology.jp/none/best-practice-can-thiet-khi-viet-tdd/ ^ http://programmer.97things.oreilly.com/wiki/index.php/The_Three_Laws_of_Test-Driven_Development ^ http://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html ^ http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/
  • #16 Class trong lập trình hướng đối tượng # Chú thích ^ https://techmaster.vn/posts/33702/nguyen-tac-phat-trien-phan-mem-tot ^ https://toidicodedao.com/2016/06/14/series-solid-cho-thanh-nien-code-cung-dependency-inversion-principle/
  • #18 # Nguồn ^ https://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118 ^ https://stackoverflow.com/questions/184618/what-is-the-best-comment-in-source-code-you-have-ever-encountered ^ https://toidicodedao.com/2015/04/09/review-sach-clean-code-a-handbook-of-agile-software-craftsmanship/ ^ http://www.devchronicles.com/2013/07/android-api-fun.html