
Như họ nói, nếu bạn không xấu hổ về mã cũ của mình, thì bạn sẽ không phát triển với tư cách là một lập trình viên - và tôi đồng ý với ý kiến này. Tôi bắt đầu lập trình cho vui cách đây hơn 40 năm, còn về chuyên môn thì cách đây 30 năm nên tôi mắc rất nhiều sai sót. rất nhiều. Với tư cách là một giáo sư khoa học máy tính, tôi dạy học sinh của mình học hỏi từ những sai lầm—của họ, của tôi và của người khác. Tôi nghĩ đã đến lúc phải nói về những lỗi lầm của mình để không đánh mất sự khiêm tốn. Tôi hy vọng chúng sẽ hữu ích cho ai đó.
Vị trí thứ ba - Trình biên dịch Microsoft C
Giáo viên ở trường tôi tin rằng Romeo và Juliet không thể được coi là một bi kịch vì các nhân vật không có tội lỗi bi thảm - họ chỉ cư xử ngu ngốc, như những thanh thiếu niên nên làm. Lúc đó tôi không đồng ý với anh ấy, nhưng bây giờ tôi thấy quan điểm của anh ấy có phần hợp lý, đặc biệt là liên quan đến lập trình.
Khi tôi học xong năm thứ hai tại MIT, tôi còn trẻ và thiếu kinh nghiệm, cả trong cuộc sống lẫn lập trình. Vào mùa hè, tôi thực tập tại Microsoft, trong nhóm biên dịch C. Lúc đầu, tôi làm những công việc thường ngày như hỗ trợ lập hồ sơ, và sau đó tôi được giao nhiệm vụ làm phần thú vị nhất của trình biên dịch (như tôi nghĩ) - tối ưu hóa phụ trợ. Đặc biệt, tôi đã phải cải thiện mã x86 cho các câu lệnh nhánh.
Quyết tâm viết mã máy tối ưu cho mọi trường hợp có thể xảy ra, tôi đã lao đầu vào bể bơi. Nếu mật độ phân phối của các giá trị cao, tôi đã nhập chúng vào . Nếu chúng có ước chung, tôi dùng nó để làm cho bảng chặt chẽ hơn (nhưng chỉ khi phép chia có thể được thực hiện bằng cách sử dụng ). Khi tất cả các giá trị đều là lũy thừa của hai, tôi đã thực hiện một tối ưu hóa khác. Nếu một tập hợp các giá trị không thỏa mãn điều kiện của tôi, tôi chia nó thành nhiều trường hợp có thể tối ưu hóa và sử dụng mã đã được tối ưu hóa.
Đó là một cơn ác mộng. Nhiều năm sau, tôi được biết rằng lập trình viên kế thừa mã của tôi ghét tôi.

Bài học kinh nghiệm
Như David Patterson và John Hennessy viết trong Kiến trúc máy tính và Thiết kế hệ thống máy tính, một trong những nguyên tắc chính của kiến trúc và thiết kế là làm cho mọi thứ hoạt động nhanh nhất có thể.
Việc tăng tốc các trường hợp phổ biến sẽ cải thiện hiệu suất hiệu quả hơn so với việc tối ưu hóa các trường hợp hiếm gặp. Trớ trêu thay, những trường hợp phổ biến lại thường đơn giản hơn những trường hợp hiếm gặp. Lời khuyên hợp lý này giả định rằng bạn biết trường hợp nào được coi là phổ biến - và điều này chỉ có thể thực hiện được thông qua quá trình kiểm tra và đo lường cẩn thận.
Để bào chữa cho mình, tôi đã cố gắng tìm hiểu xem các câu lệnh nhánh trông như thế nào trong thực tế (chẳng hạn như có bao nhiêu nhánh và các hằng số được phân bổ như thế nào), nhưng vào năm 1988, thông tin này không có sẵn. Tuy nhiên, tôi không nên thêm các trường hợp đặc biệt bất cứ khi nào trình biên dịch hiện tại không thể tạo mã tối ưu cho ví dụ nhân tạo mà tôi nghĩ ra.
Tôi cần gọi cho một nhà phát triển có kinh nghiệm và cùng với anh ta suy nghĩ về những trường hợp phổ biến và giải quyết chúng một cách cụ thể. Tôi sẽ viết ít mã hơn, nhưng đó là một điều tốt. Như người sáng lập Stack Overflow Jeff Atwood đã viết, kẻ thù tồi tệ nhất của lập trình viên chính là chính lập trình viên đó:
Tôi biết bạn có những ý định tốt nhất, tất cả chúng tôi cũng vậy. Chúng tôi tạo ra các chương trình và thích viết mã. Đó là cách chúng ta được tạo ra. Chúng tôi nghĩ rằng mọi vấn đề đều có thể được giải quyết bằng băng keo, một chiếc nạng tự chế và một chút mật mã. Mặc dù các lập trình viên rất đau lòng khi phải thừa nhận điều đó, nhưng mã tốt nhất là mã không tồn tại. Mỗi dòng mới đều cần gỡ lỗi và hỗ trợ, cần phải hiểu nó. Khi thêm mã mới, bạn nên làm điều đó một cách miễn cưỡng và chán ghét vì tất cả các lựa chọn khác đã cạn kiệt. Nhiều lập trình viên viết quá nhiều mã, khiến nó trở thành kẻ thù của chúng ta.
Nếu tôi viết mã đơn giản hơn bao gồm các trường hợp phổ biến thì việc cập nhật nếu cần sẽ dễ dàng hơn nhiều. Tôi đã để lại một mớ hỗn độn mà không ai muốn giải quyết.

Vị trí thứ hai: quảng cáo trên mạng xã hội
Khi tôi làm việc tại Google về quảng cáo trên mạng xã hội (bạn có nhớ Myspace không?), tôi đã viết một cái gì đó như thế này bằng C++:
for (int i = 0; i < user->interests->length(); i++) {
for (int j = 0; j < user->interests(i)->keywords.length(); j++) {
keywords->add(user->interests(i)->keywords(i)) {
}
}Lập trình viên có thể thấy ngay lỗi: đối số cuối cùng phải là j chứ không phải i. Kiểm tra đơn vị không phát hiện ra lỗi và người đánh giá của tôi cũng vậy. Quá trình khởi chạy được thực hiện và một đêm nọ, mã của tôi đến máy chủ và làm hỏng tất cả các máy tính trong trung tâm dữ liệu.
Không có gì xấu xảy ra. Không có gì sai sót đối với bất kỳ ai vì trước khi ra mắt toàn cầu, mã đã được thử nghiệm trong một trung tâm dữ liệu. Trừ khi các kỹ sư của SRE đã ngừng chơi bida một thời gian và thực hiện lùi lại một chút. Sáng hôm sau, tôi nhận được một email có kết xuất lỗi, sửa mã và thêm các bài kiểm tra đơn vị để phát hiện lỗi. Vì tôi đã tuân theo giao thức - nếu không thì mã của tôi sẽ không chạy được - nên không có vấn đề gì khác.

Bài học kinh nghiệm
Nhiều người chắc chắn rằng một sai lầm lớn như vậy chắc chắn sẽ khiến thủ phạm bị sa thải, nhưng thực tế không phải vậy: thứ nhất, tất cả các lập trình viên đều mắc lỗi, và thứ hai, họ hiếm khi mắc cùng một lỗi hai lần.
Trên thực tế, tôi có một người bạn là lập trình viên, một kỹ sư xuất sắc và đã bị sa thải chỉ vì mắc một lỗi nhỏ. Sau đó, anh ấy được thuê tại Google (và sớm được thăng chức) - anh ấy đã thành thật nói về sai lầm mình mắc phải trong một cuộc phỏng vấn và nó không được coi là nghiêm trọng.
Đó là những gì về Thomas Watson, người đứng đầu huyền thoại của IBM:
Một lệnh của chính phủ trị giá khoảng một triệu đô la đã được công bố. Tập đoàn IBM - hay đúng hơn là cá nhân Thomas Watson Sr. - thực sự muốn có được nó. Thật không may, đại diện bán hàng đã không thể thực hiện được điều này và IBM đã thua cuộc. Ngày hôm sau, nhân viên này vào văn phòng ông Watson và đặt một phong bì lên bàn làm việc của ông. Ông Watson thậm chí còn không buồn nhìn vào nó - ông ấy đang đợi một nhân viên và biết rằng đó là một lá thư xin nghỉ việc.
Watson hỏi có chuyện gì vậy.
Đại diện bán hàng đã nói chi tiết về tiến độ của cuộc đấu thầu. Ông kể tên những sai lầm đã mắc phải mà lẽ ra có thể tránh được. Cuối cùng, anh ấy nói, “Ông Watson, cảm ơn vì đã để tôi giải thích. Tôi biết chúng tôi cần đơn đặt hàng này đến mức nào. Tôi biết anh ấy quan trọng như thế nào,” và chuẩn bị rời đi.
Watson đến gần anh ở cửa, nhìn vào mắt anh và trả lại chiếc phong bì với dòng chữ: “Làm sao tôi có thể để anh đi? Tôi vừa đầu tư một triệu đô la vào việc giáo dục của bạn.
Tôi có một chiếc áo phông có dòng chữ: “Nếu bạn thực sự học hỏi từ những sai lầm thì tôi đã là bậc thầy rồi”. Thực tế, khi nói đến sai sót, tôi là một bác sĩ khoa học.
Vị trí đầu tiên: API nhà phát minh ứng dụng
Những lỗi thực sự khủng khiếp ảnh hưởng đến một lượng lớn người dùng, được công chúng biết đến, mất nhiều thời gian để sửa chữa và được thực hiện bởi những người không thể tạo ra chúng. Sai lầm lớn nhất của tôi phù hợp với tất cả các tiêu chí này.
Càng tệ càng tốt
tôi đọc về cách tiếp cận này vào những năm 1990 khi còn là một nghiên cứu sinh, và tôi thích nó đến mức tôi đã hỏi sinh viên của mình. Nếu không nhớ rõ thì hãy ôn lại trí nhớ, chuyện nhỏ thôi. Bài tiểu luận này đối lập với mong muốn “làm đúng” và cách tiếp cận “tệ hơn là tốt hơn” theo nhiều cách, bao gồm cả sự đơn giản.
Nó phải như thế nào: thiết kế phải đơn giản trong cách triển khai và giao diện. Sự đơn giản của giao diện quan trọng hơn sự đơn giản của việc thực hiện.
Càng tệ càng tốt: thiết kế phải đơn giản trong cách triển khai và giao diện. Sự đơn giản trong việc thực hiện quan trọng hơn sự đơn giản của giao diện.
Chúng ta hãy quên điều đó trong một phút. Thật không may, tôi đã quên nó trong nhiều năm.
Nhà phát minh ứng dụng
Khi làm việc tại Google, tôi là thành viên của nhóm một môi trường phát triển trực tuyến kéo thả dành cho người mới bắt đầu Android- Các nhà phát triển. Đó là năm 2009, và chúng tôi đang gấp rút phát hành phiên bản alpha đúng hạn để có thể tổ chức các buổi hội thảo cho giáo viên vào mùa hè, sau đó họ sẽ có thể sử dụng môi trường này trong lớp học vào mùa thu. Tôi tình nguyện triển khai phần sprite, gợi nhớ lại thời gian tôi viết game trên máy tính TI-99/4. Đối với những người chưa biết, sprite là một đối tượng đồ họa hai chiều có thể di chuyển và tương tác với các yếu tố phần mềm khác. Ví dụ về sprite bao gồm tàu vũ trụ, tiểu hành tinh, quả bóng và vợt.
Chúng tôi đã triển khai App Inventor hướng đối tượng trong Java nên chỉ có một loạt đối tượng trong đó. Vì quả bóng và sprite hoạt động rất giống nhau nên tôi đã tạo một lớp sprite trừu tượng với các thuộc tính (trường) X, Y, Speed (tốc độ) và Heading (hướng). Họ có những phương pháp giống nhau để phát hiện va chạm, bật ra khỏi mép màn hình, v.v.
Sự khác biệt chính giữa một quả bóng và một sprite là những gì được vẽ chính xác - một vòng tròn đầy hoặc một raster. Vì tôi đã triển khai các họa tiết trước tiên nên việc chỉ định tọa độ x và y ở góc trên bên trái nơi đặt hình ảnh là điều hợp lý.

Khi các sprite đã hoạt động, tôi quyết định rằng tôi có thể triển khai các đối tượng quả bóng với rất ít mã. Vấn đề duy nhất là tôi đã chọn con đường đơn giản nhất (theo quan điểm của người thực hiện), chỉ ra tọa độ x và y của góc trên bên trái của đường viền đóng khung quả bóng.

Trên thực tế, cần phải chỉ ra tọa độ x và y của tâm đường tròn, như được dạy trong bất kỳ sách giáo khoa toán học nào và bất kỳ nguồn nào khác có đề cập đến đường tròn.

Không giống như những sai lầm trước đây của tôi, sai lầm này không chỉ ảnh hưởng đến đồng nghiệp của tôi mà còn ảnh hưởng đến hàng triệu người dùng App Inventor. Nhiều người trong số họ là trẻ em hoặc hoàn toàn mới làm quen với lập trình. Họ đã phải thực hiện rất nhiều bước không cần thiết khi làm việc trên từng ứng dụng có bóng. Nếu tôi nhớ những lỗi cười khác của mình, thì lỗi này khiến tôi đổ mồ hôi cho đến tận hôm nay.
Cuối cùng tôi mới vá được lỗi này gần đây, mười năm sau. “Đã vá”, không phải “đã sửa”, vì như Joshua Bloch đã nói, API là vĩnh cửu. Không thể thực hiện các thay đổi có thể ảnh hưởng đến các chương trình hiện có, chúng tôi đã thêm thuộc tính OriginAtCenter với giá trị sai trong các chương trình cũ và đúng trong tất cả các chương trình trong tương lai. Người dùng có thể đặt một câu hỏi hợp lý: ai thậm chí còn nghĩ đến việc đặt điểm bắt đầu ở một nơi nào khác ngoài trung tâm. Cho ai? Gửi một lập trình viên đã quá lười biếng để tạo một API bình thường cách đây mười năm.
Bài học kinh nghiệm
Khi làm việc trên API (điều mà hầu hết mọi lập trình viên đôi khi phải làm), bạn nên làm theo lời khuyên tốt nhất được nêu trong video của Joshua Bloch ""Hoặc :
- Một API có thể mang lại cho bạn cả lợi ích to lớn và tác hại lớn.. Một API tốt sẽ tạo ra những khách hàng thường xuyên. Điều tồi tệ sẽ trở thành cơn ác mộng vĩnh viễn của bạn.
- API công khai, giống như kim cương, tồn tại mãi mãi. Hãy cống hiến hết mình: sẽ không bao giờ có cơ hội khác để làm mọi việc đúng đắn.
- Đề cương API phải ngắn gọn - một trang có chữ ký và mô tả lớp và phương thức, chiếm không quá một dòng. Điều này sẽ cho phép bạn dễ dàng cơ cấu lại API nếu nó không hoàn hảo trong lần đầu tiên.
- Mô tả các trường hợp sử dụngtrước khi triển khai API hoặc thậm chí làm việc với đặc tả của nó. Bằng cách này, bạn sẽ tránh được việc triển khai và chỉ định một API hoàn toàn không có chức năng.
Nếu tôi viết dù chỉ một bản tóm tắt ngắn bằng chữ viết nhân tạo, rất có thể tôi đã xác định được lỗi và sửa nó. Nếu không thì một trong những đồng nghiệp của tôi chắc chắn sẽ làm điều đó. Bất kỳ quyết định nào có hậu quả sâu rộng đều cần phải được suy nghĩ ít nhất một ngày (điều này không chỉ áp dụng cho việc lập trình).
Tiêu đề bài luận của Richard Gabriel, "Tệ hơn là tốt hơn", đề cập đến lợi thế của người đầu tiên đưa ra thị trường - ngay cả với một sản phẩm không hoàn hảo - trong khi người khác dành cả đời để theo đuổi sản phẩm hoàn hảo. Nghĩ lại về mã sprite, tôi nhận ra rằng tôi thậm chí không cần phải viết thêm mã để làm đúng. Dù người ta có thể nói gì đi nữa, tôi đã nhầm to.
Kết luận
Các lập trình viên mắc lỗi mỗi ngày, cho dù đó là viết mã có lỗi hay không muốn thử thứ gì đó sẽ cải thiện kỹ năng và năng suất của họ. Tất nhiên, bạn có thể là một lập trình viên mà không mắc phải những sai lầm nghiêm trọng như tôi đã mắc phải. Nhưng không thể trở thành một lập trình viên giỏi nếu không nhận ra sai lầm của mình và học hỏi từ chúng.
Tôi liên tục gặp phải những sinh viên cảm thấy như họ mắc quá nhiều lỗi và do đó không thể lập trình được. Tôi biết hội chứng kẻ mạo danh phổ biến như thế nào trong lĩnh vực CNTT. Tôi hy vọng bạn sẽ học được những bài học mà tôi đã liệt kê - nhưng hãy nhớ điều chính: mỗi chúng ta đều mắc sai lầm - xấu hổ, hài hước, khủng khiếp. Tôi sẽ ngạc nhiên và buồn bã nếu trong tương lai tôi không có đủ tài liệu để viết tiếp bài viết.
Nguồn: www.habr.com
