Tâm sự coder

Cách giải quyết các vấn đề khó khăn trong lập trình

Mẹo dành cho các lập trình viên mới vào nghề không biết bắt đầu từ đâu

Tôi nghe một số developer mới vào nghề đang xoay sở và không biết bắt đầu từ đâu rằng họ hiểu vấn đề, hiểu logic, các syntax cơ bản, etc. Lúc nhìn code của người khác thì có thể hiểu, nhưng nếu tự làm thì lại không cảm thấy chắc ăn lắm khi chuyển suy nghĩ của mình thành code ngay cả khi họ hiểu syntax hoặc logic. Đây là trình tự hoặc là các mẹo để giải quyết các vấn đề(ví dụ) đó, hy vọng sẽ có ích với bạn.

Cách giải quyết các vấn đề khó khăn trong lập trình

giai quyet van de trong lap trinh

1. Đọc vấn đề ít nhất 3 lần(hoặc cho đến khi nào bạn cảm thấy thoải mái)

Bạn không thể giải quyết vấn đề nếu bạn không hiểu(đừng thử vận may bằng cách sửa hàm này, sửa biến kia). Có sự khác nhau giữa vấn đề thực sự và vấn đề mà bạn nghĩ là mình đang sửa. Đọc vài line code đầu và bạn sẽ dễ dàng lâm vào sai lầm là giả định phần còn lại của nó cũng tương tự.

Nếu làm một cái game nổi tiếng như Hangman, chắc chắn rằng mình đã đọc qua tất cả các rule ngay cả khi bạn đã từng chơi nó trước đó. Một lần tôi làm game giống Hangman và nhận ra rằng mình chỉ là “Hangman Quỷ Dữ” vì chỉ đọc hướng dẫn mà không đọc tất cả các rule. Vì vậy hãy đọc nốt pần code còn lại. Đừng hiểu một nửa, sẽ khiến bạn hiểu nhầm vấn đề, bỏ thêm thời gian lúc đầu này sẽ có giá trị, càng hiểu nhiều thì sẽ càng giải quyết vấn đề dễ dàng.

Giả vờ như chúng ta đang tạo một function đơn giản selectEvenNumbers là trả về một mảng các số chẵn evenNumbers trong một mảng hỗn hợp các con số chẵn lẻ. Nếu không có số chẵn nào cả thì trả về mảng rỗng evenNumbers

Sau đây là vài câu hỏi chạy qua trong đầu tôi:

  • Làm thế nào mà máy tính biết số nào là chẵn? Chia nó cho 2 và xem phần còn lại có là 0
  • Tôi sẽ gán cái gì vào function này? Một array
  • Mảng đó chứa cái gì? Một hoặc vài con số One or more numbers
  • Kiểu dữ liệu của từng element trong array? Các con số
  • Mục đích của function này là gì? Tôi sẽ trả về những gì vào cuối function? Mục tiêu là lướt qua các phần tử và chọn ra các số chẵn rồi cho nó vào array và trả về ở cuối function, nếu không có số chẵn nào thì trả về array rỗng.

2. Thử bằng tay ít nhất 3 set dữ liệu mẫu khi giải quyết vấn đề

Lấy một mớ giấy viết và thử bằng tay ít nhất 3 set dữ liệu mẫu. Thử các trường hợp góc cũng như là cạnh
Ví dụ, sau đây là một vài mẫu data có thể dùng:

Khi mới bắt đầu, rất dễ bị bỏ qua các bước. Bởi vì não của bạn đã quen với các số chẵn, bạn sẽ nhìn vào các dữ liệu mẫu trên và tập trung vào các số như 2 , 4 , 6 và từ đó trở đi không còn cẩn thận làm toàn bộ các bước để khắc phục vấn đề. Nếu đây là thử thách, “thà một lần đau” thử sử dụng một lương dữ liệu mẫu thật lớn để tập cho não bạn thói quen xử lý chi tiết từng bước một

Bây giờ hãy nhìn vào array [1]

  • Soi vào element duy nhất của array [1]
  • Xác định nó là chẵn hoặc lẻ
  • Chú ý rằng không còn element nào khác trong array
  • Thấy rằng không có số chẵn nào trong array này
  • Trả về array rỗng

Bây giờ hãy nhìn vào array [1, 2]

  • Tập trung vào element đầu tiên của array [1, 2]
  • Nó là 1
  • Xác định nó là chẵn hay lẻ
  • Tập trung vào element tiếp theo trong array
  • Nó là 2
  • Đúng nó là chẵn rồi
  • Tạo một array evenNumbers và thêm 2 vào array này
  • Chú ý rằng không còn element nào trong array này
  • Trả về array evenNumbers trong đó có [2]
  • Tôi làm như vậy vài lần. Chú ý là các bước tôi viết ra cho [1] có thay đổi một chút từ [1, 2].

Đó là lý do vì sao tôi thử với nhiều set dữ liệu mẫu khác nhau. Có vài set có 1 element, có set thì số thập phân thay vì số nguyên, một vài thì số có nhiều chữ số, một số thì là số âm…

Tôi làm như vậy vài lần. Chú ý là các bước tôi viết ra cho [1] có thay đổi một chút từ [1, 2]. Đó là lý do vì sao tôi thử với nhiều set dữ liệu mẫu khác nhau. Có vài set có 1 element, có set thì số thập phân thay vì số nguyên, một vài thì số có nhiều chữ số, một số thì là số âm…

3. Đơn giản hóa và tối ưu hóa các bước

Cách giải quyết các vấn đề khó khăn trong lập trình

giai quyet van de trong lap trinh 3

Tìm các mẫu chung và xem có thể rút ngắn cái gì hay không, để có thể giảm một số bước lặp đi lặp lại

  • Tạo một function selectEvenNumbers
  • Tạo một array rỗng evenNumbers để lưu các số chẵn nếu có
  • Lướt qua các element trong array [1, 2]
  • Tìm element đầu tiên
  • Xác định nếu nó là chẵn bằng cách chia hết cho 2 rồi add nó vào evenNumbers
  • Tìm element tiếp theo
  • Lặp lại bước #4
  • Lặp lại bước #5 và #4 cho đến khi không còn element nào trong array
  • Trả về array evenNumbers, không cần quan tâm có cái gì trong đó

4. Viết code giả

Ngay cả sau khi hoàn thành các bước chung chung, viết ra các mã để chuyển hóa ý tưởng sẽ giúp xác định được cấu trúc của code và làm cho việc viết code dễ dàng hơn nhiều. Viết code giả bằng tay từng dòng một. Bạn có thể làm trên giấy hoặc trên editor. Tôi đề xuất bạn viết trên giấy để tập trung tốt hơn.

Mã giả nhìn chung không thực sự có quy tắc nào cụ thể nhưng đôi lúc, tôi vẫn áp dụng các syntax từ ngôn ngữ lập trình vì tôi đủ quen thuộc với ngôn ngữ đó. Nhưng đừng quá chú trọng syntax mà hãy tập trung vào logic và các bước chạy code trên kia

Cách giải quyết các vấn đề khó khăn trong lập trình

giai quyet van de trong lap trinh 2

Đối với ví dụ trên, có rất nhiều cách khác nhau. Ví dụ bạn có thể dùng filter nhưng để cho đơn giản và dễ theo dõi, chúng ta dùng vòng lặp for cơ bản(nhưng sẽ dùng filter sau, khi cấu trúc lại code).

Đây là ví dụ của mã giả viết một cách dài dòng:

Đây là ví dụ của mã giả viết một cách ngắn gọn hơn:

Dù bằng cách nào cũng được miễn là bạn viết ra từng dòng một và hiểu logic của từng dòng.

5. Chuyển mã giả sang code và debug

Sau khi xong mã giả, chuyển đổi từng dòng sang code thực bằng ngôn ngữ mà bạn đang làm việc. Tôi dùng Javascript cho ví dụ này.

Nếu bạn đã viết nó ra giấy, gõ lại nó trên editor rồi replace từng dòng

Sau đó tôi gọi function và truyền vào các dữ liệu mẫu mà chúng ta dùng lúc trước. Tôi dùng chúng để xem kết quả trả về có đúng ý muốn hay không. Bạn cũng có thể viết các test case đề kiểm tra output có đúng mong đợi hay không.

Tôi dùng console.log() sau mỗi biến hoặc dòng để theo dõi biết hay code có hoạt động như mong đợi trước khi tiếp tục bước tiếp theo, bằng cách này tôi tóm được bất kỳ lỗi nào trước khi sai quá xa. Dưới đây là ví dụ

Sau khi bước qua từng dòng mã giả, tôi để lại // . Còn text đậm là code thực sự bằng JavaScript.

Sau đó bỏ mã giả:

Đôi khi các developer mới vào nghề sẽ bị mắc kẹt với syntax làm cản trở việc tiến lên phía trước. Hãy nhớ rằng syntax chỉ trở nên tự nhiên và thân quen sau khi làm việc lâu năm và không có gì xấu hổ khi tra lại các tài liệu để hoàn chỉnh cú pháp sau này, khi code thực sự.

6. Đơn giản hóa và tối ưu hóa code của bạn

Trong ví dụ này, một cách tối ưu hóa nó bằng việc lọc ra các item từ array, trả về array mới sử dụng filter. Theo đó, chúng ta không cần phải define một biến mới evenNumbers bởi vì filter sẽ trả về array mới với các bản sao của các element đã lọc phù hợp, không khác gì cách ban đầu, cũng không cần phải dùng vòng lặp for. filter sẽ duyệt đến từng item, trả về true, để có element đó trong array hoặc về false để bỏ qua nó.

7. Debug

Khi tôi tìm kiếm các bug, tôi tra từng dòng code để xem việc gì không đúng đã diễn ra. Sau đây là một số kỹ thuật tôi dùng:

Kiềm tra console xem các thông điệp lỗi. Đôi lúc nó sẽ chỉ ra line nào và mình bắt đầu từ chỗ đó, những cũng có khi lỗi thực sự lại nằm ở line khác.

Comment vô hiệu hóa một số dòng code và output ra những gì mình cần để nhanh chóng có được những thông tin về hành động của code.

Dùng các dữ liệu mẫu khác và xem nó hoạt động ra sao
Lưu thành nhiều phiên bản khác nhau và thử từng cách tiếp cận riêng biệt. Kiểu như nhiều mẫu thử trong phòng thí nghiệm để tránh đánh mất một kết quả quan trọng hoặc đúng đắn nào đó trong suốt quá trình thử nghiệm

8. Viết các comment hữu ích

Bạn không thể nào luôn nhớ được chức năng tuyệt vời của từng dòng code trong một tháng tới, và người khác lại càng không. Đó là lý do vì sao viết comment hữu ích rất quan trọng để tránh những vấn đề và tiết kiệm thời gian khi bạn quay trở lại với nó sau này.

Nhưng cũng tránh những comment như sau:

Tôi cố gắng viết tóm tắt để người đọc comment có thể hiểu những gì đang diễn ra nếu nó không thực sự rõ ràng. Đặc biệt là ở những đoạn code phức tạp, giải thích rõ ràng từng function để làm gì và tại sao. Cũng nên sử dụng những tên biến, tên function và các comment rõ ràng để bạn và người khác có thể hiểu:

Code này để làm gì?

Code này đang làm gì?

9. Nhận phản hồi thông qua các code review

Nhận phản hồi từ các đồng nghiệp, các chuyên gia hoặc các developer khác. Check lại trong Stack Overflow. Xem cách mà những người khác hỏi về vấn đề đó và học từ nó. Đôi khi một vấn đề có nhiều cách tiếp cận. Làm rõ nó là gì sẽ nhanh và tốt hơn cho bạn

Cách giải quyết các vấn đề khó khăn trong lập trình

giai quyet van de trong lap trinh 2

10. Thực hành, thực hành, thực hành

Ngay cả các developer nhiều kinh nghiệm vẫn luôn thực hành và học hỏi. Nếu nhận được phản hồi hữu ích, hãy tích hợp nó, tái hiện lại problem hoặc fix problem tương tự, thúc đẩy bạn tiến lên, mỗi problem bạn giải quyết xong là một bước tiến tốt hơn cho bạn trên con đường làm developer. Hãy ăn mừng mỗi thành công và nhớ rằng bạn đã tiến xa như thế nào.

Nguồn: blog.techtalk.vn