Khái niệm Bug là gì? Các lợi ích đến từ việc “chiến đấu” với bug là gì? Đó là một câu hỏi mà không mấy vui vẻ, bởi vì có lẽ hầu hết lập trình viên cũng đều muốn làm tính năng mới.

Trong ngành lập trình thì ta thường xuyên bắt gặp nhiều khái niệm “bug”. Tuy nhiên ngoài những developers thì đại đa số mọi người chưa hiểu rõ cụ thể về bug là gì, có những loại bug nào với tác dụng của bug trong việc lập trình. Cùng 123job tìm hiểu kỹ càng hơn về bug ở trong bài viết sau đây nhé!

I. Bug là gì? Thế nào là debug và fix bug?    

Bug chính là khái niệm được sử dụng để chỉ nhiều lỗi xảy ra trong quá trình lập trình một hệ thống và chương trình hay ứng dụng máy tính, khiến cho những chương trình và ứng dụng cũng không thể chạy được, hay trả về kết quả sai lệch, không được đúng như mong muốn của người lập trình. Một vài nguyên nhân thường dẫn tới bug có thể kể đến như sau: Viết sai câu lệnh, sai cú pháp, viết những câu lệnh if lồng nhau, đặt câu lệnh else sai nhánh để đưa giả định ban đầu không chính xác và thuộc tính dữ liệu có vấn đề,… 

Vậy debug là gì? Debug còn là khái niệm dùng để chỉ quá trình việc tìm kiếm, phát hiện ra bug. Việc rà soát bug trong hàng chục ngàn trong dòng code của một chương trình cũng không phải một việc đơn giản, do đó debug đòi hỏi về người lập trình cần phải kiên nhẫn. Việc debug cũng sẽ giúp cho lập trình viên rà soát được quá trình chương trình chạy và từ đó có thể tối ưu hóa những dòng code

Khái niệm bug là gì?

Khái niệm bug là gì?

Sau khi debug xong thì công việc của lập trình viên lúc này sẽ là sửa lại bug sao cho đúng. Công việc sửa lỗi còn được gọi là fix bug. Sau khi fix bug và chạy thử, nếu như ứng dụng có thể chạy trơn tru thì coi như bug cũng đã được fix hoàn chỉnh. Còn nếu chương trình vẫn đang có lỗi, người làm lập trình cần phải tiếp tục quay lại quá trình debug cũng như fix bug.

II. Một số loại bug phổ biến khi lập trình

Trên thực tế, có tới hàng chục loại bug có thể xuất hiện trong nhiều dòng code trong một chương trình, một vài ứng dụng ở trong suốt quá trình lập trình. Dưới đây sẽ là 5 loại bug phổ biến nhất

1. Bug tí hon

Bug tí hon được sử dụng để chỉ những lỗi nhỏ có liên quan đến cấu trúc và quy chuẩn trong câu lệnh, ví dụ như là thừa/thiếu dấu chấm phẩy, dấu ngoặc, dấu cách hay thụt lề sai,… trong khi gõ code. Bởi vì “tí hon” nên những bug này cũng khá khó để nhận diện và sửa chữa. Việc debug những bug tí hon sẽ dễ dàng hơn nếu như code được viết trên những IDE phù hợp đối với ngôn ngữ lập trình đang sử dụng. 

2. Bug khủng

Bug khủng là những bug từ các lỗi chính tả và lỗi cú pháp của nhiều dòng code. Để tránh bug khủng, bạn cần chú ý tới thuật toán đang sử dụng, logic của dòng code với nguồn tài nguyên khi code ( như là cách sử dụng dữ liệu, phạm vi truy cập dữ liệu,…). Mỗi ngôn ngữ lập trình cũng sẽ có cú pháp khác nhau, và rất dễ bị nhầm lẫn nếu như người lập trình không cẩn thận. Bug khủng tương đối dễ nhận biết với những trình biên dịch

3. Bug không tồn tại

Đây là những bug sẽ gây hoang mang cho khá nhiều lập trình viên, bởi tuy compile error của những bug này vẫn nhảy và chương trình bị báo lỗi các liên tục ngay cả khi developer đã review code. Trong các trường hợp này, lỗi phần lớn do trình biên dịch cũ hơn về chương trình, vậy nên nó không thể đọc được nhiều tính năng mới, đôi khi nó vừa báo những bug không tồn tại vừa bỏ qua các bug khác. Do đó, lập trình viên cũng nên chọn lựa kỹ càng và update trình biên dịch thường xuyên để có thể dễ dàng truy xuất bug

4. Bug ẩn danh (hay bug ẩn thân)

Bug ẩn thân là những bug không hiển thị khi đang biên dịch và do đó chỉ có thể truy xuất được khi đã được hoàn thành chương trình. Những bug ẩn danh này chính là lỗ hổng khiến cho các chương trình xảy ra lỗi sau khi cài đặt và sử dụng. Đây cũng chính là các điểm yếu “chí mạng” dễ dàng bị hacker hack thấy được phần mềm. 

5. Bug bất ngờ

Đúng như tên gọi thì bug bất ngờ là những bug đột nhiên được xuất hiện không theo quy luật. Đây là loại bug sẽ gây khó chịu nhất cho những lập trình viên bởi nó có thể xuất hiện trong một ngày bất cứ sau khi tưởng rằng chương trình đã chạy tốt. Đôi khi có những loại bug cũng không thể truy tìm và fix được một cách dễ dàng mà đòi hỏi về lập trình viên phải mất rất nhiều thời gian và tốn công sức

III. Lợi ích của việc gặp bug là gì?  

Trong quá trình lập trình thì việc gặp bug là điều khó cũng có thể tránh khỏi. Và trên thực tế thì bug cũng không hẳn là “lỗi” mà bug được coi đó là tính năng. Bởi lẽ, trong quá trình debug và fix bug sẽ giúp cho lập trình viên có cơ hội review lại toàn bộ về chương trình cũng như những dòng code mình đã được viết, từ đó có thể tối ưu hóa về chương trình. Việc fix bug còn giúp việc tăng cường tính năng cho các ứng dụng và hoàn thiện về sản phẩm tốt hơn. Với lập trình viên, quá trình tìm lỗi để  sửa lỗi là lúc các bạn ôn tập về kiến thức cũ và tích lũy được rất nhiều về kiến thức lập trình mới hiệu quả. Việc học từ những bug cũng sẽ làm cáccác bạn trở nên giàu kinh nghiệm hơn. 

IV. Cách hiệu quả nhất để ghi lại bug là gì?

Lý do của việc cần phải ghi lại của bug là gì? Để các bạn có thể học hỏi hiệu quả nhất từ các bug bạn đã fix. Phương pháp mà tôi sử dụng là luôn dành ra vài phút để ghi chú lại nhiều thông tin: mô tả bug, cách fix và bài học kinh nghiệm.

Nguyên tắc:

  • Chỉ ghi chú nhiều bug khó nhằn hay thực sự thú vị. Đây không phải đó là bug tracker.
  • Ghi chú các bug do chính mình gây ra. (Trừ trường hợp bug của người khác tuy nhiên đủ thú vị).
  • Ghi lại bug ngay sau khi  đã fix xong. Tránh nhớ nhầm thì nhớ không chi tiết.
  • Cách ghi lại bug
  • Tôi thường sử dụng form dưới đây để ghi lại bug ở dưới dạng file text (bugs.txt). Bạn có thể tham khảo qua ví dụ sau:

Thông tin nền:
Ngày: 17/8/2004
Triệu chứng: Vòng lặp vô tận khi giải mã tín hiệu Q.931.
Nguyên nhân: Khi tìm thấy id trong một thành phần chưa biết trong tín hiệu Q.931, ta có thể tìm cách bỏ qua nó bằng cách lấy chiều dài, và di chuyển con trỏ của pos tương ứng cùng với độ dài tìm được. Tuy nhiên, đối với trường hợp độ dài bằng 0 làm ta có thể liên tục bỏ qua cùng 1 id.

Cách tìm ra: Nhờ vào phân tích về tín hiệu SETUP lấy từ trace của Ethereal ở Nortel. Tín hiệu của họ cũng có độ dài 1016 bytes, tuy nhiên MSX_MAX_LEN chỉ có 1000. Thường ta sẽ nhận một vài tín hiệu bị cắt từ common/Communication.cxx, tuy nhiên ở đây khi cung cấp dữ liệu trực tiếp để phân tích và khoảng bộ nhớ vượt quá array bị truy cập, và vô tình nó cũng bằng 0, làm xuất hiện nhiều lỗi. Để sửa lỗi, tôi đã thêm vào vài lệnh print trong phần code phân tích của Q.931. Tuy nhiên may mắn là dữ liệu lại bằng 0.
Cách sửa – Quá trình sửa:

Sửa: Nếu như chiều dài tìm thấy bằng 0 thì đặt nó lại bằng 1. Như vậy chúng ta cũng sẽ luôn đi tiếp được.
Sửa ở trong file(s): callh/q931_msg.cxx
Thủ phạm chính là tôi: Đúng vậy.
Thời gian trong sửa bug: 1 giờ.
Bài học rút ra được:

Bài học: Đặt “niềm tin lầm chỗ” vào các dữ liệu của tín hiệu gửi tới. Giá trị dữ liệu có thể quá lớn để làm chương trình chạy sai. Ngoài ra trong khi chiều dài bằng 0 cũng có thể đó là một dấu hiệu xấu.

Xem thêm: Render là gì? Kiến thức nền tảng về lĩnh vực thiết kế đồ họa

V. Ba bài học lớn dành cho lập trình viên

1. Về coding

Những lỗi phạm phải ở trong code? Có phải bạn đã quên một else-part? Có phải một lệnh gọi hệ thống đã bị thất bại, tuy nhiên hồi đáp chưa được check? Làm sao chỉnh sửa code để tránh các vấn đề này trong tương lai?

Những bài học từ Bug cho lập trình viên

Những bài học từ Bug cho lập trình viên 

Trình tự sự kiện
Khi xử lý sự kiện và những câu hỏi sau sẽ rất có ích:

  • Liệu sự kiện có thể dẫn theo trật tự khác được không?
  • Sẽ thế nào nếu như không nhận được sự kiện này? Sẽ thế nào nếu các sự kiện này được diễn ra hai lần liên tiếp?
  • Thậm chí, nếu như nó không bao giờ xảy ra, bugs ở những phần khác trong hệ thống (hoặc của các hệ thống khác có tương tác) vẫn có thể khiến cho nó xảy ra.

Quá sớm
Cái này chính là một trường hợp đặc biệt trong phần “Trình tự sự kiện” ở trên. Tuy nhiên bởi vì nó gây ra một số lỗi rất khó tìm vậy nên nó được đặt ra riêng.

“Cái chết êm đềm”
Một trong số các lỗi khó phát hiện nhất đó là khi chúng lặng lẽ ra đi và chương trình sẽ tiếp tục được thực thi mà không quăng ra những exception nào.

Chương trình tiếp tục chạy trong trạng thái sai và làm cho debug càng trở nên khó hơn. Nói chung tốt nhất đó là một lỗi nên được quăng ra càng sớm càng tốt.

If
Lệnh if cùng với nhiều điều kiện, if (a or b) và đặc biệt là khi được nối lại cùng với nhau, if (x) else if (y) để gây ra quá trời lỗi cho tôi. Dù cho câu lệnh if về mặt khái niệm quá đơn giản đi nhưng chúng vẫn dễ bị sai trong khi có nhiều điều kiện đi kèm. Bây giờ tôi cố gắng viết code đơn giản hơn để có thể tránh phải xử lý những câu if phức tạp.

Else
Cũng có quá trời lỗi đó là do không xét đến trường hợp và bỏ qua lệnh else. Gần như tất cả trường hợp và luôn phải có một lệnh else cho mỗi câu if. Hơn nữa, nếu như bạn đặt một biến bên trong lệnh if và khả năng cao là bạn phải đặt nó ở nhiều chỗ khác nữa.

Thay đổi các giả định
Những lỗi khó nên phòng tránh nhất trong giai đoạn đầu thường là do bạn thay đổi giả định. Nói chung không khó để có thể tìm tất cả những phần phụ thuộc hiển nhiên. Cái khó đó là tìm ra những phần phụ thuộc đã tiềm ẩn bên trong thiết kế cũ. Tôi không biết cách nào tốt để có thể đề phòng những trường hợp này, nếu bạn nào biết thì hãy gợi ý giúp tôi với nhé.

Logging
Điều tối quan trọng là có nhận thức về điều gì chương trình hoạt động và đặc biệt trong những chương trình có logic phức tạp. Cần chắc chắn về logging được đặt vừa đủ và đúng chỗ, để các bạn có thể lý luận tại sao chương trình lại chạy như vậy. Khi mọi thứ được hoạt động trơn tru thì không sao, tuy nhiên ngay khi chương trình xảy ra lỗi (và chuyện không thể tránh khỏi), ít ra bạn sẽ cảm thấy hạnh phúc vì đã logging đúng chỗ.

2. Về Testing

Có những bug rõ ràng vậy nên được “khui” ra ngay ở quá trình test. Nếu vậy, phần test nào đã được thiếu sót – unit, functional, hoặc system? Test case nào đang bị thiếu?

0 và null
Luôn chắc chắn để có thể kiểm tra cùng với giá trị 0 và null (nếu như có thể). Đối với chuỗi, bạn cần phải chú ý chuỗi rỗng, và chuỗi là null.. Một ví dụ khác đó là: kiểm tra trường hợp đứt trong kết nối TCP trước khi bất cứ một dữ liệu nào ( hay zero bytes) nào được gửi. Bỏ qua việc khi kiểm tra các trường hợp trên đó là lý do số một làm cho bug cũng sẽ lọt khỏi phần test của tôi.

Thêm vào và xóa đi
Thường những tính năng mới cũng sẽ dính tới chuyện thêm về thiết lập mới vào hệ thống, ví dụ như là một kiểu định dạng mới số điện thoại.

Thường thì các bạn cũng sẽ kiểm tra xem có thể thêm định dạng mới hay không, tuy nhiên tôi thấy là rất dễ dàng quên khi kiểm tra trường hợp xóa định dạng cũ.

Xử lý lỗi
Phần code sử dụng để có thể xử lý lỗi thường rất khó để kiểm tra. Tốt nhất là nên có những test tự động để có thể kiểm tra phần này, nhưng đôi khi việc này trở nên bất khả.

Một mẹo tôi hay sử dụng đó là sửa code tạm thời để có thể kích hoạt phần khi xử lý lỗi. Dễ nhất đó là lật ngược điều kiện if lại, chẳng hạn như là chuyển if error_count > 0 thành if error_count == 0.

Một ví dụ khác đó là giả vờ viết sai tên một column ở trong database để có thể kích hoạt về lỗi.

Sử dụng những dữ liệu đầu vào ngẫu nhiên. Một cách kiểm tra khác có thể sử dụng để có thể phát hiện bug là sử dụng dữ liệu đầu vào ngẫu nhiên. Kiểm tra về hành động không mong muốn có thật sự KHÔNG đã diễn ra. Thường testing có liên quan đến xem thử hành động mong muốn có xảy ra hay không. Tuy nhiên lại rất dễ bỏ qua trường hợp ngược lại – kiểm tra hành động không như mong muốn thật sự không diễn ra.

Tự làm tool
Tôi thường tự làm những tool nhỏ để test dễ hơn. Bằng cách bắt đầu nhỏ, và dần dần sẽ phát triển thêm tính năng cho nó, cuối cùng tôi có trong này về công cụ rất hữu dụng. Lợi ích của việc này đó là tôi có những công cụ đúng như tôi đang mong muốn.

3. Về Debugging

Cách nhanh hơn để “khui” bug là gì? Tôi đã dùng đúng tool hay chưa? Có phải tôi đã phỏng đoán quá nhiều không? Tôi có cần logging tốt hơn không?

Thảo luận
Nếu như bạn hỏi tôi cách hiệu quả nhất để có thể xử lý bug là gì? Tôi sẽ trả lời là thảo luận cùng với đồng nghiệp. Trong lúc tìm cách giải thích cho họ sao cho hiểu vấn đề gặp phải là gì, tôi cũng sẽ đồng thời hiểu sâu và rõ hơn về nó. Thêm nữa, mặc dù không quen thuộc với code trong câu hỏi, thường thì họ sẽ có cái nhìn khách quan để chỉ ra các vấn đề có thể nảy sinh từ đâu. Đây là cách cực kì hiệu quả giúp cho tôi giải quyết những bug khó nhằn nhất.

Cẩn thận đến từng tiểu tiết
Khi việc debug ngốn quá nhiều thời gian thì thường là do tôi cũng đã suy đoán sai. Cho nên, hãy chắc chắn các bạn đã kiểm tra lại tất cả chi tiết thay vì mặc định mọi thứ. Thật dễ dàng để thấy những gì bạn mong muốn thấy, hơn là những gì thật sự ở đó.

Thay đổi mới nhất
Khi những thứ từng hoạt động tự dưng bị trục trặc, thường sẽ là do những thay đổi mới nhất đã gây nên. Có trường hợp, các bạn chỉ thay đổi logging, song một lỗi trong logging đã bị gây nên sự cố lớn hơn nhiều. Để dễ truy tìm các sự cố kiểu này, bạn nên commit về thay đổi khác nhau trong những commit khác nhau, và ghi chú rõ ràng về những việc thay đổi.

Tin ở người dùng
Đôi khi người sử dụng report một vấn đề nào đó, ý nghĩ đầu tiên của tôi đó là: Không thể nào! Chắc chắn họ nhầm lẫn chứ chuyện đó sao xảy ra được! Nhưng rồi hóa ra họ cũng đã report đúng.

Dĩ nhiên tôi vẫn cần phải kiểm tra lại để xem mọi thứ đã được thiết lập đúng hay chưa. Tuy nhiên tôi đã gặp rất nhiều trường hợp kì quặc sẽ xảy ra bởi vì một thiết lập không thường gặp và một cách sử dụng không được dự đoán trước, hay giả định ban đầu của tôi rằng chúng cần phải như vậy. Và thế là chương trình đã chạy sai.

Test phần đã sửa
Sau khi đã sửa xong thì bước tiếp theo bạn cần làm đối với bug là gì? Khi bug đã sửa xong thì các bạn buộc phải test lại. Trước tiên, hãy chạy code mà không cần dùng phần đã sửa và theo dõi bug. Sau đó, khi sử dụng phần đã sửa và chạy lại test case.

Xem thêm: Bootstrap là gì? Hướng dẫn cách sử dụng Bootstrap hiệu quả nhất

VI. Kết luận

Hy vọng rằng, thông qua việc tìm hiểu bug là gì, các bạn đã có thêm các kiến thức về lĩnh vực Công nghệ thông tin. Nếu như bạn mong muốn tìm kiếm việc làm thì hãy lựa chọn 123job để tìm việc. Truy cập 123job.vn ngay hôm nay để không bị bỏ lỡ những vị trí hấp dẫn nhất nhé!