CODING CƠ BẢN DÀNH CHO FRESHER

22/12/2021 443
coding 5
CODEWELL

Bạn là một Coder? Chắc hẳn trong quá trình viết ra những dòng code, theo thói quen mỗi cá nhân sẽ có một style nhất định nào đó, hoặc dựa theo một số quy chuẩn của dự án để thực hiện. Không khó để viết code để cho máy có thể hiểu được nhưng để người có thể hiểu được thì không phải là đơn giản. Đã có một thống kê chỉ ra rằng: Trong quá trình thi triển coding của một coder, tỷ lệ về thời gian giữa việc đọc code và việc viết code là 10:1. Đủ để bạn thấy rằng code sao cho dễ đọc, dễ hiểu sẽ giúp ích cho bạn cũng như cả đồng đội của bạn rất nhiều.

coding 2

Dưới đây là những điều đúc rút từ kinh nghiệm thực tế công việc của chuyên gia tại CO-WELL Asia.

 

1. Convention

Bất kể thực hiện một dự án nào cũng cần tuân theo một Coding Standard. Chính vì vậy bạn cũng nên nắm được các tiêu chuẩn này và lựa chọn cho mình một Coding Stardard phù hợp.

Có khá nhiều chuẩn khác nhau cho mỗi ngôn ngữ, ví dụ Java thì có IBM/Google Convention; PHP thì có Zend/ PSR-0, PSR-1, PSR-2 Standard; JS thì có Eslint…

Và khi tìm hiểu về convention thì bạn sẽ gặp một số các thuật ngữ phổ biến như: Hungarian notation, quy tắc đặt tên theo underscores (snake_case), camelCase, hay PascalCase, thụt đầu dòng (indent) theo tab hay theo space…

Các Coding Editor (IDE) hiện đại (như PHPStorm, Visual Studio Code, Eclipse…) đều hỗ trợ trực tiếp hoặc có các plugins hỗ trợ việc kiểm tra theo các chuẩn code. Các bạn chỉ cần lựa chọn, sử dụng và sẽ dần tạo thành thói quen cho mình.

 

2. Đặt tên class, hàm, biến có ý nghĩa

“Good code is self-documenting”

“Code should speak for itself whenever possible”

Trước khi tạo ra một Class, Hàm hay Biến, Thuộc tính nào, bạn nên giành cho chúng một cái tên phù hợp dễ hiểu để nó thực sự có ý nghĩa và giúp bạn dễ dàng tìm kiếm.

 

3. Comment vừa đủ

Hãy tạo thói quen chỉ comment ở những chỗ thực sự cần thiết (đầu file, class, đầu hàm, một số logic quan trọng/phức tạp…). Một trong những điều được khuyến nghị dành cho viết comment đó là: Nội dung của comment cần phải trả lời được câu hỏi Why cho sự tồn tại của đoạn code thay vì trả lời cho câu hỏi What liên quan đến nội dung code đó xử lý gì. Tuy nhiên với một số đoạn code xử lý dài có logic phức tạp thì bạn vẫn có thể có một comment mô tả ngắn gọn đoạn code đó xử lý gì thì khi đọc code và điều tra sẽ nhanh hơn, không phải đi sâu đọc kỹ nội dung code.

Ví dụ:
Comment không cần thiết:

/** paging limit default is 10 **/

pageLimit = 10;

Comment phù hợp:

/**

* Get user shopping history list

**/

private function getUserShoppingHistory() {

// 1. Get user shopping data from DB

......

// 2. Call API to get user data from XYZ system

........

// Merge data of 1, 2

.......

return ...

}

Ngoài ra, các IDE ví dụ như Visual Studio Code có các plugins hỗ trợ xem được lịch sử liên quan đến từng dòng source tại vị trí con trỏ đang chỉ.

coding 1

 

4. Tách hàm, file common, tái sử dụng code nhiều nhất có thể

Những code đã có trong hệ thống thường là đã được test rồi, nên trước khi bắt tay vào sáng tác mới một xử lý nào đó, hãy ưu tiên tham khảo và sử dụng lại những xử lý có sẵn để đảm bảo đúng các spec đã có của hệ thống cũng như giảm số lượng bug phát sinh.

Cần tránh duplicate code ở mức thấp nhất có thể được. Có một rule rất nổi tiếng liên quan đến việc này là DRY (Don’t Repeat Yourself) hay còn được biết là rule DIE (Duplication Is Evil).

Ví dụ:

Có một case khá phổ biến với vấn đề này, là khi ta cần thay đổi logic của một hàm được sử dụng nhiều chỗ (common) để phục vụ cho một spec mới với hoặc một giao diện cụ thể.

Thông thường bạn sẽ clone hàm cũ ra một hàm mới để sử dụng cho phần của mình. Vừa nhanh lại không sợ ảnh hưởng đến các chỗ sử dụng khác. Tuy nhiên điều này sẽ dẫn đến hậu quả là sau này khi phát sinh một thay đổi mới đến tất cả các giao diện liên quan, thì thay vì sửa một chỗ ở hàm common, ta sẽ phải sửa ở hai chỗ khác nhau, hoặc có thể sửa lại bị sót.

Việc clone chỉ nên làm khi có một feedback của khách hàng cần xử lý gấp, không có nhiều thời gian test. Nếu không thì thay vì duplicate code bạn hãy cố gắng sửa hàm cũ bằng cách thêm một tham số mới hoặc sử dụng một biến/thuộc tính có sẵn để sử dụng check riêng cho trường hợp spec phát sinh riêng của mình. Như vậy code sẽ gọn hơn và cũng tránh bị ảnh hưởng.

 

5. Độ dài hàm vừa phải

Về nguyên tắc mỗi hàm là một đơn vị xử lý làm một việc hoặc thực hiện một mục đích chứ ko phải để làm nhiều việc cùng lúc. Vì vậy độ dài của hàm sẽ không thể quá dài được, và khi nội dung hàm quá dài việc đọc code để hiểu mục đích xử lý của hàm sẽ gặp khó khăn.

Có khá nhiều tiêu chuẩn khác nhau về độ dài hàm, tuy nhiên cá nhân thì tôi nghĩ tối đa 1 hàm chỉ nên từ 30-40 dòng. Nếu quá bạn hãy nghĩ cách để tách nội dung xử lý ra thành các hàm nhỏ để dễ code hơn.

Ngoài ra thì hàm cũng không nên quá nhiều tham số (tối đa là 3), nếu cần nhiều hơn hãy truyền theo kiểu object thay vì các parameter tách biệt.

 

6. Không viết khai báo, xử lý SQL hay gọi API trong các vòng lặp

Hãy tưởng tượng bạn có vòng lặp với 200 userID khác nhau. Và trong vòng lặp này bạn xử lý lấy hoặc update dữ liệu với mỗi user ID tương ứng, sau đó gọi API để liên kết dữ liệu với bên thứ ba. Kết quả khi chạy thực tế sẽ là 200 câu query cùng với 200 request API sẽ được thực hiện! Vì vậy đừng khiến trường hợp này xảy ra nhé.

 

7. Không dùng nhiều tầng If hoặc nhiều vòng lặp lồng nhau

Việc dùng nhiều tầng như thế khi điều tra source rất khó và cũng ảnh hưởng đến Performance của code. Tối đa chỉ nên tới 2 tầng. Cần nhiều hơn thì bạn hãy nghĩ phương án khác để xử lý cho phù hợp, ví dụ như tách các xử lý bên trong thành hàm con thì source cũng sẽ dễ nhìn hơn.

 

8. Check biến trước khi sử dụng

coding 3

Luôn thực hiện check biến đã được khởi tạo hay có rỗng hay không, trước khi sử dụng. Nhất là khi lấy thuộc tính để sử dụng thì cũng phải check tầng cha của thuộc tính.

Khi viết một hàm thì luôn check các tham số truyền vào trước khi sử dụng. Làm sao để việc này thành tiềm thức mỗi khi tạo một hàm mới, bạn sẽ tránh được nhiều bug phát sinh sau này.

function doSomething (paramFirst, paramSecond...) {

if (paramFirst == null ){

return or doSomethingFun;

}

if (paramSecond == null ){

return or doSomethingSad;

}

//Main processing

}

 

9. Lưu ý khi tái sử dụng source code của người khác

Đôi khi ta thường sử dụng nguyên đoạn code cũ trong dự án, hoặc search google, copy/paste cả đoạn source mà bỏ qua một số logic check nhỏ khác trong xử lý của đoạn code này có thể confict với spec của phần bạn đang làm, từ đó có thể gây ra các lỗi degrade. Vì vậy, tham khảo và tái sử dụng là một việc rất cần thiết khi code, tuy nhiên cần tỉnh táo.

 

10. Xử lý LOG

Logging là một skill mà bất kể DEV nào đều phải biết khi tham gia dự án.

Khi bạn build một source code bất kể cho dự án lớn hay nhỏ nào thì cũng nên chú ý tới việc build cơ chế xuất Log chung của dự án. Đây sẽ là cách rất hữu ích để bạn điều tra các bug phát sinh trong quá trình phát triển.

Xử lý Log còn liên quan đến chiến lược Error-Handling (xử lý lỗi) của mỗi hệ thống. Thông thường các hệ thống khi đẩy lên Product, thường có các tool để monitoring Log như Zabbix hay CloudWatch của AWS để notification cho người quản lý mỗi khi hệ thống phát sinh các Log lỗi Error.

Tuy nhiên không phải chỗ nào cũng xuất Log thì sẽ làm cho code rất lộn xộn, khó đọc.

  • Log ở những chỗ xử lý core, quan trọng (ví dụ phần core gửi mail, gửi SMS, gọi API, sử dụng thư viện third party…)
  • Log ở những chỗ try-catch Exceptions

Và sau khi bạn thêm Log vì mục đích debug, điều tra một vấn đề nào đó, khi giải quyết xong hãy đừng quên xóa đi trước khi commit source.

 

11. Check ảnh hưởng

Check ảnh hưởng mỗi khi sửa code đã có hoặc thêm code mới vào source code đã có. Đây là cả một câu chuyện dài mà ngay cả những DEV kinh nghiệm đôi khi làm vẫn bị sót.

Có nhiều loại ảnh hưởng khác nhau trong quá trình code:

  • Ảnh hưởng về hiển thị

Ví dụ bạn thêm xử lý css mới, sửa một css cũ.

  • Ảnh hưởng về spec / nghiệp vụ

Ví dụ sửa nghiệp vụ bên giao diện Update nhưng logic lại ảnh hưởng đến bên giao diện Create

  • Ảnh hưởng về môi trường

Ví dụ: sửa chỗ gửi SMS mà lại sử dụng config của bên môi trường thật => tắc thở.

  • Ảnh hưởng đến hệ thống khác

Ví dụ bạn sửa logic update dữ liệu hệ thống của bạn, nhưng dữ liệu này lại đang được đồng bộ sang hệ thống khác để sử dụng.

  • Ảnh hưởng về mặt dữ liệu

Ví dụ khi bạn tạo một cột mới cho một bảng, thì bạn cũng sẽ phải chú ý vấn đề là tạo các dữ liệu default cho các dữ liệu có sẵn của bảng đó thế nào. Để đảm bảo khi release lên môi trường thật thì chức năng với các dữ liệu cũ vẫn hoạt động đúng.

 

12. Performance/ Security

Khi làm outsource, nhất là với khách hàng Nhật, đôi khi dự án của bạn sẽ phải làm việc với các framework khá cũ, đôi khi là code thuần. Vì vậy lúc này việc xử lý security/ hay performance càng cần chú ý.

Ví dụ: khi bạn viết các câu SQL để lấy dữ liệu, cần xử lý parameter hóa các giá trị điều kiện truyền vào câu SQL để tránh lỗi SQL Injection.

Thêm một điều rất đơn giản nhưng dễ bị bỏ qua khác là khi test code của mình các bạn phải luôn có case nhiều dữ liệu.

Bình thường các DEV khi code thường ít khi tạo dữ liệu để test hoặc chưa biết cách hoặc không đủ nhiều thời gian để tạo dữ liệu test. Nên với các dữ liệu thông thường thì chạy rất OK nhưng khi lượng dữ liệu tăng lên thì lại gây ra các lỗi khá nghiêm trọng.

Ví dụ một case đơn giản như sau:

Khi thực hiện Get request với tham số đẩy lên URL. Mỗi Browser đều có giới hạn về độ dài của URL khi truyền lên. Nhiều bạn truyền tham số lên (ví dụ như một mảng ID) mà ko lường các case nhiều dữ liệu, khi dữ liệu tăng lên thì URL vượt giới hạn độ dài, sẽ bị cắt phần đuôi nên sẽ ko thể chạy bình thường, gây ra Exception.

Hãy thay Post bằng Get nếu bạn thấy dữ liệu truyền lên có khả năng nhiều. Hoặc thay vì truyền tham số lên URL hãy nghĩ đến các cách truyền khác (như lưu session, storage, hoặc lưu dữ liệu tạm trong DB…).

 

13. Tiêu chuẩn 2 giây

Luôn có một nguyên tắc/ tiêu chuẩn bất di bất dịch đó là tốc độ load trang phải không quá 2 giây. Nếu quá 2 giây thì sẽ phải tìm mọi cách để giải quyết. Vì dụ với các trang search với dữ liệu rất lớn (ví dụ vài triệu người dùng), nhiều bảng, với kỹ thuật thông thường ko thể tối ưu được thì họ đã phải tìm đến các phương án khác phức tạp hơn ví dụ như dùng Search Engine của bên thứ ba. Với vai trò developer, bạn cũng luôn nên tâm niệm các tiêu chuẩn về performance như vậy để có hướng giải quyết vấn đề phù hợp từ ban đầu.

Người dùng luôn không đủ kiên nhẫn và sẽ sẵn sàng rời trang mình đang vào khi thấy load chậm, dù trang của bạn có đẹp hay nhiều tính năng hữu ích mấy chăng nữa. Code lởm chưa chắc là thảm họa mà sản phẩm code ra không có người dùng mới là hậu quả không ai mong muốn.

Việc load chậm không chỉ làm người dùng khó chịu, mà bản thân chúng ta là những người phát triển cũng sẽ cảm thấy rất ức chế, mất thời gian lãng phí không cần thiết, ảnh hưởng đến tiến độ công việc.

 

14. Write Test

Đây là một công việc không phải Developer nào cũng thích, đủ kiên trì làm, và khá ít dự án khách hàng yêu cầu thực hiện điều này, vì sẽ làm đội công số (chi phí) phát triển lên gấp 1.5 đến 2 lần.

Tuy nhiên, bạn cần tìm hiểu và làm thực tế về Unit Test ít nhất một lần thì sau đó việc viết code của bạn sẽ chuẩn và chất lượng hơn.

 

15. Tránh code rác

 

  • Các hàm/ các biến khai báo không sử dụng thì hãy xóa đi.
  • Xóa các khai báo import/include mà không sử dụng
  • Xóa các comment code thừa:

Không biết các bạn thế nào chứ cá nhân tôi rất ác cảm khi đang đọc code mà thấy có một đoạn code dài thoòng đang được comment. Những nội dung code này người ta gọi là zombie code.

Có thể người code là một người cẩn thận hoặc nghĩ rằng nội dung code này là vô cùng quý giá, ko thể xóa được, hoặc tránh rủi ro sau có thể dùng lại nên comment tạm thời lại.

Có một điều thú vị là theo thời gian các nội dung code xung quanh lại dần biến đổi, và các dòng source comment dần không còn ý nghĩa và không có giá trị sử dụng gì nữa.

  • Tránh có các đoạn code debug thừa ko cần thiết:

Log.debug(…) (Chỉ nên giữ lại các xử lý Log.Info hoặc Log.Error thực sự cần thiết)

windows.console.log(…)

 

16. Code refactoring

Khi giải quyết vấn đề, bạn hãy ưu tiên tập trung vào coding để giải quyết vấn đề một cách hiệu quả và nhanh nhất. Chưa vội nghĩ đến việc Refactoring.

Chỉ khi đã giải quyết xong vấn đề, nhất là trước thời điểm commit/ tạo Merge Request cho task của mình, thì nên view lại code một lượt để thực hiện refactoring. Những lúc có khoảng thời gian trống thì có thể dành thời gian để refactoring và tối ưu lại code. Việc này sẽ làm giảm chi phí về maintain code về sau, cũng như tăng thêm skill của DEV.

Vậy ngược lại các bạn sẽ hỏi Refactoring thì là làm những gì? Câu trả lời rất đơn giản, ngoài các đặc thù đặc trưng không nhiều của mỗi dự án, thì điều trước tiên cần làm chính là thực hiện lại các điều đã được đề cập ở trên.

 

17. Học hỏi từ code của người khác

Trong quá trình làm project học từ source có sẵn, học từ source người khác đã viết trong project, học khi review source của người khác. Tham khảo các open-source và cách họ viết (github là cả một thế giới đầy giá trị). Thay vì chỉ sử dụng, bạn thử đọc xem cách họ viết như thế nào. Một số cuốn sách kinh điển về code như Code Complete, Clean Code cũng là tài liệu tham khảo hữu ích.

Hy vọng bài viết trên đã cho bạn cái nhìn cơ bản về coding. Đừng quên theo dõi chuyên mục CODEWELL trên website CO-WELL Asia để đón đọc những bài viết công nghệ bổ ích nhé!

 

Phạm Minh Tuấn – CO-WELL Asia