kiến thức 4 cấp độ lỗi của code và một số thủ thuật sửa lỗi debug

  • Người tạo chủ đề Người tạo chủ đề leuleuleu789
  • Ngày bắt đầu Ngày bắt đầu

leuleuleu789

Senior Member
Cấp độ 1: lỗi tính toán của code
bạn thấy được code đưa sai giá trị nào. Vd hàm "ReturnDouble(2) mà ra kết quả là 5 thay vì 4" thì bạn biết được lỗi là ở trong định nghĩa của hàm.

Hoặc vd một đoạn code như sau:
// Convert farenheit to celcius
celcius_degrew = ... <== Điểm breakpoint bạn chạy đến đây thấy celcius_degree cho ra kq tính toán sai

Ở cấp độ này thường chỉ cần bạn dùng IDE có hỗ trợ breakpoint hoặc viết unittest tốt là có thể tái hiện lại lỗi để sửa.

Cấp độ 2: code đúng trong hầu hết trường hợp nhưng sai trong một số điều kiện đặc biệt

Vd các trường hợp input = 0 hay code bạn viết có sử dụng các biến tổng thể (non constant global variable) thì có thể bị lỗi kiểu này. Các lỗi này có thể khá khó nhằn, đặc biệt là nếu bạn viết code chạy song song. Kĩ thuật tốt nhất để debug loại này là logging thật tốt để bạn bắt đc lúc lỗi xảy ra thì các biến số đang ở giá trị nào để tái hiện lại lỗi (reproduce bug)
 
Nói chung khó nhưng rèn dc thì tốt là nên viết unit test rồi code hàm sau
 
Nói chung khó nhưng rèn dc thì tốt là nên viết unit test rồi code hàm sau

Cái này là test driven development. Tôi thấy ai làm được nên học theo. Ngoài việc giúp giảm bớt bug thì nó đòi hỏi bạn phải có tư duy nhất định về việc phân tách, hoạch định code của bạn sao cho dễ viết test. Vd như ai viết code có nhiều global state thì hầu như khó viết unittest đc rồi. Việc "code sao cho dễ test" nó cũng khiến code bạn tốt hơn nhiều.
 
Cái này là test driven development. Tôi thấy ai làm được nên học theo. Ngoài việc giúp giảm bớt bug thì nó đòi hỏi bạn phải có tư duy nhất định về việc phân tách, hoạch định code của bạn sao cho dễ viết test. Vd như ai viết code có nhiều global state thì hầu như khó viết unittest đc rồi. Việc "code sao cho dễ test" nó cũng khiến code bạn tốt hơn nhiều.

Cái tdd này có giống như kiểu mình phải xác định input và các output, các cases của hàm đó rồi mới viết phải k bác??

Sent from Vsmart Active 3 using vozFApp
 
cũng đang định hỏi, viết rồi thì viết nốt 2 cái còn lại đi bác chủ thớt :)
 
Để thư thư tí tôi viết tiếp các bạn ơi. Tôi hay viết kiểu chia phần để tùy xem cộng đồng có thấy hữu ích không mà đầu tư thời gian viết tiếp :D
 
tôi có câu hỏi là, khi 1 hàm cần nhận vào nhiều biến thì ta nên làm thế nào?
1. cứ cần nhận biến nào thì khai báo luôn biến đó ở param >> nhìn rất chuối hàm mà nhận vào đến cả chục param, nhưng người dùng sẽ biết chính xác phải truyền vào biến nào

2. làm 1 cái hash map, vào trong hàm thì get biến lại theo value >> viết kiểu này thì thằng truyền param vào phải nắm đc nội dung hàm từ document, vì không biết phải viết tên của biến thế nào cho đúng (vd: viết theo camel,hay snake,chữ hoa chữ thường ...), cái này tôi thấy các framework ruby,php hay dùng nhiều khi đọc code tự hỏi bọn kia sao nó biết đc nên truyền biến gì vào ??

3. chỉ truyền những biến chứa dữ liệu cần thiết, còn lại sẽ lấy dữ liệu từ các biến global >> cách này sẽ chết nếu ko kiểm soát đc biến global, cái này thấy hay gặp ở những code ngày xưa hoặc ko viết theo OOP, mà viết theo fucntion, điển hình nhất tôi thấy là thằng php, các cụ hay dùng thẳng luôn cái biến global $_GET

4. xé nhỏ method kia ra thành nhiều method con, nên mỗi method sẽ nhận vào ít param hơn

à qua câu hỏi trên tôi cũng muốn hỏi luôn là, có bắt buộc là tất cả các biến đưa vào hàm phải là được truyền vào không ( ngoại trừ các biến final,static final), best practice của việc truyền dữ liệu vào hàm sẽ là gì

các bác có kinh nghiệm thì share kinh nghiệm giải quyết cái này với
 
tôi có câu hỏi là, khi 1 hàm cần nhận vào nhiều biến thì ta nên làm thế nào?
1. cứ cần nhận biến nào thì khai báo luôn biến đó ở param >> nhìn rất chuối hàm mà nhận vào đến cả chục param, nhưng người dùng sẽ biết chính xác phải truyền vào biến nào

2. làm 1 cái hash map, vào trong hàm thì get biến lại theo value >> viết kiểu này thì thằng truyền param vào phải nắm đc nội dung hàm từ document, vì không biết phải viết tên của biến thế nào cho đúng (vd: viết theo camel,hay snake,chữ hoa chữ thường ...), cái này tôi thấy các framework ruby,php hay dùng nhiều khi đọc code tự hỏi bọn kia sao nó biết đc nên truyền biến gì vào ??

3. chỉ truyền những biến chứa dữ liệu cần thiết, còn lại sẽ lấy dữ liệu từ các biến global >> cách này sẽ chết nếu ko kiểm soát đc biến global, cái này thấy hay gặp ở những code ngày xưa hoặc ko viết theo OOP, mà viết theo fucntion, điển hình nhất tôi thấy là thằng php, các cụ hay dùng thẳng luôn cái biến global $_GET

4. xé nhỏ method kia ra thành nhiều method con, nên mỗi method sẽ nhận vào ít param hơn

à qua câu hỏi trên tôi cũng muốn hỏi luôn là, có bắt buộc là tất cả các biến đưa vào hàm phải là được truyền vào không ( ngoại trừ các biến final,static final), best practice của việc truyền dữ liệu vào hàm sẽ là gì

các bác có kinh nghiệm thì share kinh nghiệm giải quyết cái này với
hỏi thì phải cụ thể ngôn ngữ nào ==". chứ chung chung vậy sao trả lời được
 
tôi có câu hỏi là, khi 1 hàm cần nhận vào nhiều biến thì ta nên làm thế nào?
1. cứ cần nhận biến nào thì khai báo luôn biến đó ở param >> nhìn rất chuối hàm mà nhận vào đến cả chục param, nhưng người dùng sẽ biết chính xác phải truyền vào biến nào

2. làm 1 cái hash map, vào trong hàm thì get biến lại theo value >> viết kiểu này thì thằng truyền param vào phải nắm đc nội dung hàm từ document, vì không biết phải viết tên của biến thế nào cho đúng (vd: viết theo camel,hay snake,chữ hoa chữ thường ...), cái này tôi thấy các framework ruby,php hay dùng nhiều khi đọc code tự hỏi bọn kia sao nó biết đc nên truyền biến gì vào ??

3. chỉ truyền những biến chứa dữ liệu cần thiết, còn lại sẽ lấy dữ liệu từ các biến global >> cách này sẽ chết nếu ko kiểm soát đc biến global, cái này thấy hay gặp ở những code ngày xưa hoặc ko viết theo OOP, mà viết theo fucntion, điển hình nhất tôi thấy là thằng php, các cụ hay dùng thẳng luôn cái biến global $_GET

4. xé nhỏ method kia ra thành nhiều method con, nên mỗi method sẽ nhận vào ít param hơn

à qua câu hỏi trên tôi cũng muốn hỏi luôn là, có bắt buộc là tất cả các biến đưa vào hàm phải là được truyền vào không ( ngoại trừ các biến final,static final), best practice của việc truyền dữ liệu vào hàm sẽ là gì

các bác có kinh nghiệm thì share kinh nghiệm giải quyết cái này với
Tôi viết JS thì t hay dùng Object(hash map), viết thêm interface bằng TS để warning. Ngoài ra JS nó có một thằng rất hay là arguments để đọc tất cả param ra, nếu truyền thiếu hoặc ko đúng thì có thể trả lỗi ngay ở runtime hoặc là dùng giá trị mặc định.
Nếu viết Java thì t dùng overloading.
Có một cách khác là dùng builder pattern
 
Tôi viết JS thì t hay dùng Object(hash map), viết thêm interface bằng TS để warning. Ngoài ra JS nó có một thằng rất hay là arguments để đọc tất cả param ra, nếu truyền thiếu hoặc ko đúng thì có thể trả lỗi ngay ở runtime hoặc là dùng giá trị mặc định.
Nếu viết Java thì t dùng overloading.
Có một cách khác là dùng builder pattern
JS cái arguments này giờ là legacy rồi bác.giờ có thể thay thế bằng rest parameters (...rest). vì nó là dạng "Array-like"nên ko dùng dc method của Array
 
Tiếp cấp độ lỗi này.

Cấp độ 3:

API chạy cho ra kết quả đúng, nhưng có những hệ quả không lường (unexpected side effects).

Code kiểu này rất nguy hiểm vì API là hợp đồng duy nhất có giá trị bền vững đối với các bên gọi API. Phần implementation của API có thể thay đổi bất cứ lúc nào.

Một trong những bug nổi tiếng nhất về cái này là bug memory của Microsoft.

Đại khái Windows có một hàm là hàm trả lại bộ nhớ (free memory). Trước windows XP thì hàm này khi bạn gọi ko làm gì về phần bộ nhớ đã có, nên phần gọi API vẫn có thể dùng bộ nhớ đã xoá.

Đến khi windows cập nhật lên bản XP, họ đổi implementation của hàm này khiến cho bộ nhớ đã bị xoá ko còn sử dụng lại được gây ra lỗi trên game Sim City. Kết quả là đội windows phải viết lại hàm free bộ nhớ của họ kiểu như sau:
If play_sim_city():
use old memory deallocator
else:
use newmemory deallocator

Vậy lỗi ở đây là gì?
1) Các nhà sản xuất game sim City phá vỡ contract của memory deallocator, vẫn sử dụng memory sau khi xoá
2) Các lập trình viên microsoft chủ quan trong chuyện defend API của họ. Ko xoá đi phần bộ nhớ cũ trong implementation đầu tiên.

Một điểm quan trọng cần chú ý là nếu bạn là platform hoặc library developer, bạn ko thể trách customer bạn ngu được. "What can go wrong will go wrong" --> thế nên nhiệm vụ của bạn là phải foolproof cả API và implementation của bạn để tránh người dùng sử dụng sai.

Đọc thêm bài viết tiếng Anh sau của Joel Software: https://www.joelonsoftware.com/2004/06/13/how-microsoft-lost-the-api-war/
 
Vd nếu tôi là lập trình viên của Windows bản cũ, tôi sẽ viết hàm free memory như sau:

def free_memory():
...<Do real stuff to reset memory pointer>
Generate garbage data in old memory location


Đoạn code màu tím đc thêm vào để bảo đảm nếu client của API ko thể làm gì với phần memory họ đã free. Ko tốn thêm bao nhiêu công (little runtime cost) nhưng lại giúp free_memory() method của bạn fool-proof hơn.
 
Cấp độ 4 của lỗi code là về code dependency và team structure. Viết phần này hơi khó nên tôi tóm tắt một tình huống bug như sau:

đội A sở hữu code A.

đội B thấy code đội A hay ho, sử dụng lại code của đội A bằng cách gọi trực tiếp code hoặc service của đội A (without A's consent).

Đội A có định hướng mới về sản phẩm, thay đổi code của họ --> break software của đội B.

Đội B bực mình đến gặp đội A, bảo "sao anh thay đổi code mà ko báo cho tôi?"

Đội A: "what the actual f*ck???"


Một ví dụ cơ bản trong thực tế: đội A và đội B là 2 đội trong một tập đoàn lớn. Đội A làm sản phẩm về web app, một trong các tính năng của web app của họ là in ra thời gian trong ngày (tuỳ thuộc vào user đang ở múi giờ địa lý nào).

Đội B làm một cái app khác về quản lí lịch hẹn. Họ ko biết cách lấy thời gian trong ngày theo vị trí địa lý sao cho đúng, nên make API call sang app của đội A để giải quyết phần lấy thời gian của user trong ngày.

Đội A đổi hướng sản phẩm, chuyển app của họ sang luôn hiển thị thời gian từ địa điểm ban đầu của người dùng --> Đội B một ngày kia phát hiện ra họ bị lỗi tính thời gian, người dùng đang đi du lịch ở Dubai mà múi giờ trả về là giờ Hà Nội. :beat_shot:
 
Để đối mặt với loại lỗi thứ 4, các bạn hãy ghi nhớ câu proverb sau của Golang:




Screen Shot 2021-07-08 at 10.58.25 PM.png
 
tôi có câu hỏi là, khi 1 hàm cần nhận vào nhiều biến thì ta nên làm thế nào?
1. cứ cần nhận biến nào thì khai báo luôn biến đó ở param >> nhìn rất chuối hàm mà nhận vào đến cả chục param, nhưng người dùng sẽ biết chính xác phải truyền vào biến nào

2. làm 1 cái hash map, vào trong hàm thì get biến lại theo value >> viết kiểu này thì thằng truyền param vào phải nắm đc nội dung hàm từ document, vì không biết phải viết tên của biến thế nào cho đúng (vd: viết theo camel,hay snake,chữ hoa chữ thường ...), cái này tôi thấy các framework ruby,php hay dùng nhiều khi đọc code tự hỏi bọn kia sao nó biết đc nên truyền biến gì vào ??

3. chỉ truyền những biến chứa dữ liệu cần thiết, còn lại sẽ lấy dữ liệu từ các biến global >> cách này sẽ chết nếu ko kiểm soát đc biến global, cái này thấy hay gặp ở những code ngày xưa hoặc ko viết theo OOP, mà viết theo fucntion, điển hình nhất tôi thấy là thằng php, các cụ hay dùng thẳng luôn cái biến global $_GET

4. xé nhỏ method kia ra thành nhiều method con, nên mỗi method sẽ nhận vào ít param hơn

à qua câu hỏi trên tôi cũng muốn hỏi luôn là, có bắt buộc là tất cả các biến đưa vào hàm phải là được truyền vào không ( ngoại trừ các biến final,static final), best practice của việc truyền dữ liệu vào hàm sẽ là gì

các bác có kinh nghiệm thì share kinh nghiệm giải quyết cái này với
Hàm nhận nhiều biến thường là design có vấn đề bạn ạ. Thường người ta khuyên là một hàm nên làm ít việc thôi, thế nên nếu hàm của bạn làm nhiều thứ quá thì nên tách nhỏ nó ra các hàm khác.

Một thủ thuật nữa là bạn có thể gộp nhiều biến vào một object. Vd như sau:

Thay vì hàm dưới đây
Add2DVectors(float x, float y, float a, float b)

Bạn viết lại thành:

Add2DVectors(2DVector vector_a, 2DVector vector_b).
 
tôi có câu hỏi là, khi 1 hàm cần nhận vào nhiều biến thì ta nên làm thế nào?
1. cứ cần nhận biến nào thì khai báo luôn biến đó ở param >> nhìn rất chuối hàm mà nhận vào đến cả chục param, nhưng người dùng sẽ biết chính xác phải truyền vào biến nào

2. làm 1 cái hash map, vào trong hàm thì get biến lại theo value >> viết kiểu này thì thằng truyền param vào phải nắm đc nội dung hàm từ document, vì không biết phải viết tên của biến thế nào cho đúng (vd: viết theo camel,hay snake,chữ hoa chữ thường ...), cái này tôi thấy các framework ruby,php hay dùng nhiều khi đọc code tự hỏi bọn kia sao nó biết đc nên truyền biến gì vào ??

3. chỉ truyền những biến chứa dữ liệu cần thiết, còn lại sẽ lấy dữ liệu từ các biến global >> cách này sẽ chết nếu ko kiểm soát đc biến global, cái này thấy hay gặp ở những code ngày xưa hoặc ko viết theo OOP, mà viết theo fucntion, điển hình nhất tôi thấy là thằng php, các cụ hay dùng thẳng luôn cái biến global $_GET

4. xé nhỏ method kia ra thành nhiều method con, nên mỗi method sẽ nhận vào ít param hơn

à qua câu hỏi trên tôi cũng muốn hỏi luôn là, có bắt buộc là tất cả các biến đưa vào hàm phải là được truyền vào không ( ngoại trừ các biến final,static final), best practice của việc truyền dữ liệu vào hàm sẽ là gì

các bác có kinh nghiệm thì share kinh nghiệm giải quyết cái này với
Đọc thêm builder pattern
 
Vd nếu tôi là lập trình viên của Windows bản cũ, tôi sẽ viết hàm free memory như sau:

def free_memory():
...<Do real stuff to reset memory pointer>
Generate garbage data in old memory location


Đoạn code màu tím đc thêm vào để bảo đảm nếu client của API ko thể làm gì với phần memory họ đã free. Ko tốn thêm bao nhiêu công (little runtime cost) nhưng lại giúp free_memory() method của bạn fool-proof hơn.

Write vào memory tốn hơi khá cycle chứ không phải ít đâu. Cỡ ~ 200 cycle / 1 cache line khi miss cache. CPU giờ có thể writeback, đưa tạm vào một write buffer nhưng cũng có giới hạn, cỡ đâu đó khoảng 60 entry, nếu số line phải write vượt quá số lượng này thì sẽ bị stalled.

Thời 2004 thì lại càng tệ hơn vì mấy cái công nghệ optimization kiểu này chưa/khó áp dụng được.
 
Sửa lần cuối:

Thống kê chủ đề

Ngày tạo
leuleuleu789,
Người trả lời cuối
tu_do_quan_diem,
Trả lời
26
Lượt xem
5.193
Quay lại
Lên đầu trang