
Dịch
Kinh nghiệm của chúng tôi cho thấy rằng các nhà phát triển không chuyên về kỹ thuật và các nhà phát triển tự học thường không dựa vào các nguyên tắc lý thuyết mà dựa vào các phương pháp heuristic.
Heuristic là các mẫu và quy tắc đã được chứng minh mà nhà phát triển đã học được từ thực tiễn. Chúng có thể không hoạt động hoàn hảo hoặc ở một mức độ hạn chế, nhưng chúng hoạt động đủ tốt và không cần phải suy nghĩ nghiêm túc. Dưới đây là một số ví dụ về heuristic:
- "Sử dụng
$(document).ready(function(){})để khởi tạo mã trên các trang jQuery" - "Thiết kế
var self = thisbắt buộc phải gọi một phương thức trong hàm gọi lại" - "Hàm mũi tên không có toán tử
return»
Đồng thời, nguyên lý lý thuyết có thể được sử dụng để tìm lời giải cho các bài toán khác. Nó luôn luôn đúng và thường quyết định chính cấu trúc hoạt động của một phần tử cụ thể. Các nguyên tắc lý thuyết bao gồm, ví dụ:
Xin lưu ý rằng chúng tôi chỉ đặt các ví dụ về phương pháp phỏng đoán trong dấu ngoặc kép để nhấn mạnh tính chất thủ công của phương pháp phỏng đoán so với tính chặt chẽ của khung lý thuyết. Không có ví dụ heuristic nào có thể áp dụng phổ biến, nhưng chúng hoạt động trong đủ tình huống mà các nhà phát triển sử dụng chúng có được mã hoạt động mà không cần hiểu đầy đủ về cách thức hoạt động của nó.
Những lập luận ủng hộ cách tiếp cận lý thuyết
Chúng tôi thường thấy rằng các nhà phát triển không chuyên về kỹ thuật không muốn giải quyết vấn đề bằng cách sử dụng các nguyên tắc lý thuyết. Điều này thường là do họ không có cơ hội học chúng sớm trong sự nghiệp của mình và vì phương pháp phỏng đoán hoạt động tốt nên họ tiếp tục sử dụng chúng.
Tuy nhiên, bất chấp sự phức tạp rõ ràng, việc học lý thuyết có thể rất hữu ích. Để làm gì? Bởi vì lý thuyết sẽ cho phép bạn cảm thấy tự tin rằng giải pháp của mình có hiệu quả, đồng thời có thể độc lập rút ra câu trả lời cho các câu hỏi mới mà không cần phải tìm kiếm giải pháp của người khác. Trong ngắn hạn, các thuật toán heuristic có vẻ giống như một giải pháp đơn giản và nhanh chóng, nhưng thường sẽ dẫn đến những giải pháp kém lý tưởng hơn—nếu có.
Hơn nữa, bằng cách dựa vào phương pháp phỏng đoán, bạn sẽ không bao giờ học được cách giải quyết vấn đề một cách thực sự. Có lẽ khá thường xuyên bạn sẽ tìm được giải pháp hiệu quả, nhưng sớm hay muộn bạn sẽ đi vào ngõ cụt mà không tìm ra lối thoát. Các lập trình viên C&P dựa vào phương pháp phỏng đoán trong công việc của họ.
Tiêu chí cấp độ kỹ năng của nhà phát triển
Khi phỏng vấn các nhà phát triển giao diện người dùng, chúng tôi đưa ra cho họ một thử thách lập trình và nói với họ rằng họ có thể tự do sử dụng bất kỳ nguồn nào, có thể là Google hoặc Stack Overflow. Bằng cách này, bạn có thể dễ dàng xác định xem nhà phát triển là người theo đuổi lý thuyết hay theo kinh nghiệm.
Những cái đầu tiên, không có ngoại lệ, sao chép mã từ các ví dụ ít nhiều phù hợp từ Stack Overflow. Chỉ khi mã không hoạt động như kế hoạch, họ mới bắt đầu điều chỉnh nó cho phù hợp với mình. Thường thì họ không làm được điều này.
Cái sau có xu hướng tìm kiếm câu trả lời trong tài liệu API. Ở đó, họ tìm thấy thông tin về số lượng tham số mà một hàm cụ thể nhận hoặc cú pháp cụ thể của dạng mở rộng của thuộc tính CSS mong muốn.
Ngay trong năm phút đầu tiên của cuộc phỏng vấn, bạn có thể xác định chính xác ứng viên thuộc loại lập trình viên nào.
Ví dụ
Hãy lấy nhà phát triển Bill làm ví dụ. Anh ấy đã tham gia một số khóa đào tạo, giải quyết một số vấn đề về JavaScript và viết trang web khi rảnh rỗi, nhưng anh ấy không “thực sự” nghiên cứu về JavaScript.
Một ngày nọ Bill tình cờ gặp một vật thể như thế này:
const usersById = {
"5": { "id": "5", "name": "Adam", "registered": true },
"27": { "id": "27", "name": "Bobby", "registered": true },
"32": { "id": "32", "name": "Clarence", "registered": false },
"39": { "id": "39", "name": "Danielle", "registered": true },
"42": { "id": "42", "name": "Ekaterina", "registered": false }
}
Một đối tượng như vậy có thể hiển thị danh sách người dùng và liệu họ đã đăng ký một sự kiện cụ thể hay chưa.
Giả sử Bill cần truy xuất danh sách người dùng đã đăng ký. Nói cách khác, hãy lọc chúng ra. Anh ấy đã tìm thấy đoạn mã trong đó phương thức .filter() dùng để lọc danh sách. Vì vậy, anh ấy thử một cái gì đó như:
const attendees = usersById.filter(user => user.registered);Và đây là những gì anh ấy nhận được:
TypeError: usersById.filter is not a function “Đây là một điều vô nghĩa,” Bill nghĩ, bởi vì anh ấy đã nhìn thấy đoạn mã trong đó .filter() đóng vai trò như một bộ lọc.
Vấn đề là Bill đã dựa vào phương pháp heuristic. Anh ấy không hiểu điều đó filter là một phương thức được xác định trên mảng, trong khi usersById - một đối tượng bình thường không có phương thức filter.
Bill Google bối rối "bộ lọc javascript" Anh ta tìm thấy rất nhiều đề cập đến mảng và nhận ra rằng anh ta cần phải chuyển usersById đến một mảng. Sau đó theo yêu cầu "javascript biến đối tượng thành mảng» anh ấy tìm thấy các ví dụ về Stack Overflow bằng cách sử dụng Object.keys(). Sau đó anh ấy cố gắng:
const attendees = Object.keys(usersById).filter(user => user.registered); Lần này không có lỗi nào được hiển thị, nhưng trước sự ngạc nhiên của Bill, trường attendees vẫn còn trống.
Thực tế là Object.keys() trả về khóa của đối tượng chứ không trả về giá trị của đối tượng. Về cơ bản, tên của biến user dễ gây hiểu nhầm vì nó không phải là một đối tượng uservà mã định danh, tức là chuỗi. Vì thuộc tính registered không được xác định cho chuỗi, filter đánh giá từng mục nhập là sai và mảng sẽ trống.
Bill xem xét kỹ hơn các câu trả lời trên Stack Overflow và thực hiện thay đổi sau:
const attendees = Object.keys(usersById).filter(id => usersById[id].registered); Lần này kết quả tốt hơn: ["5", "27", "39"]. Nhưng Bill muốn lấy đồ vật của khách truy cập chứ không phải ID của họ.
Để tìm ra cách lọc khách truy cập, Bill bực bội tìm kiếm "bộ lọc đối tượng javascript", kiểm tra kết quả tìm kiếm trên Stack Overflow và tìm thấy với đoạn mã sau:
Object.filter = (obj, predicate) =>
Object.keys(obj)
.filter( key => predicate(obj[key]) )
.reduce( (res, key) => (res[key] = obj[key], res), {} );Bill sao chép những dòng này và thử:
const attendees = Object.filter(usersById, user => user.registered); Mọi thứ đều hoạt động - mặc dù không rõ tại sao. Bill không hiểu nó dùng để làm gì reduce và nó được sử dụng như thế nào. Hơn nữa, Bill không hiểu rằng mình vừa định nghĩa cho đối tượng toàn cục Object phương pháp phi tiêu chuẩn mới.
Nhưng Bill không quan tâm - nó có tác dụng! Anh ấy vẫn chưa quan tâm đến hậu quả.
Bill đã làm gì sai?
Bill đã thử phương pháp heuristic để giải quyết vấn đề và gặp phải các vấn đề sau:
- sử dụng
.filter()về biến, Bill đã nhậnTypeError. Anh ấy không hiểu điều đófilterkhông được phát hiện trên các vật thể thông thường. - Anh ây đa nộp đơn
Object.keys()để "biến đối tượng thành một mảng", nhưng bản thân việc này không mang lại kết quả gì. Anh ta cần tạo ra một mảng các giá trị đối tượng. - Ngay cả sau khi lấy các giá trị và sử dụng chúng làm điều kiện để lọc, anh ta chỉ nhận được các mã định danh thay vì các đối tượng người dùng được liên kết với các mã định danh đó. Điều này là do mảng được lọc chứa ID chứ không phải đối tượng người dùng.
- Theo thời gian, Bill từ bỏ phương pháp này và tìm ra giải pháp hiệu quả trên Internet. Tuy nhiên, anh ấy vẫn không hiểu nó hoạt động như thế nào - và anh ấy sẽ không lãng phí thời gian để tìm hiểu nó, vì anh ấy còn việc khác phải làm.
Đây là một ví dụ nhân tạo nhưng chúng tôi đã thấy các nhà phát triển giải quyết vấn đề theo cách tương tự nhiều lần. Để giải quyết chúng một cách hiệu quả, bạn cần tránh xa các phương pháp heuristic và nghiên cứu lý thuyết.
Hãy đi xuống những điều cơ bản
Nếu Bill là người đề xuất phương pháp tiếp cận lý thuyết thì quy trình sẽ như thế này:
- Xác định các đầu vào nhất định và xác định đầu ra mong muốn - xét về các thuộc tính của chúng: “Tôi có một đối tượng có khóa là chuỗi đại diện cho ID và giá trị của đối tượng là đối tượng đại diện cho người dùng. Tôi muốn lấy một mảng có giá trị sẽ là đối tượng người dùng - nhưng chỉ các đối tượng người dùng đã đăng ký"
- Hiểu cách lặp qua một đối tượng: "Tôi biết tôi có thể lấy mảng khóa trong một đối tượng bằng cách gọi
Object.keys(). Tôi muốn lấy một mảng vì mảng hỗ trợ phép lặp". - Nhận ra rằng phương pháp này giúp lấy được khóa và bạn cần chuyển đổi khóa thành giá trị và ghi nhớ về
maplà một phương pháp rõ ràng để tạo một mảng mới bằng cách chuyển đổi các giá trị của mảng khác:Object.keys(usersById).map(id => usersById[id]) - Hãy thấy rằng bây giờ bạn có một mảng các đối tượng tùy chỉnh có thể lọc chứa các giá trị thực tế mà bạn muốn lọc:
Object.keys(usersById).map(id => usersById[id]).filter(user => user.registered)
Nếu Bill đi theo con đường này, anh ấy đã có thể làm việc cho chúng tôi.
Tại sao mọi người không dùng đến lý thuyết thường xuyên hơn?
Đôi khi họ không biết cô ấy. Thông thường, họ quá bận rộn để có thể dành thời gian học cách giải quyết vấn đề này - họ chỉ cần làm cho mọi việc diễn ra suôn sẻ. Họ có nguy cơ biến cách tiếp cận này thành một thói quen sẽ trở thành trở ngại cho việc phát triển các kỹ năng của họ.
Để tránh những sai lầm như vậy, hãy luôn bắt đầu từ lý thuyết. Ở mỗi giai đoạn của quy trình, hãy suy nghĩ về dữ liệu bạn đang xử lý. Thay vì luôn dựa vào các mẫu quen thuộc, hãy xem xét các kiểu dữ liệu nguyên thủy: mảng, đối tượng, chuỗi, v.v. Khi bạn sử dụng một hàm hoặc phương thức, hãy kiểm tra tài liệu để đảm bảo bạn biết chính xác loại dữ liệu nào nó hỗ trợ, đối số nào và đầu ra của nó là gì.
Với phương pháp này, bạn sẽ có thể tìm ra giải pháp hiệu quả ngay lần thử đầu tiên. Bạn có thể chắc chắn về tính chính xác của nó vì bạn đã chọn cụ thể các hành động của mình dựa trên dữ liệu đầu vào và đầu ra mong muốn nhất định. Tìm hiểu những kiến thức cơ bản về từng thao tác (loại dữ liệu và giá trị trả về), thay vì ngôn ngữ kinh doanh mơ hồ (như “người dùng đã đăng ký”).
Nguồn: www.habr.com
