Làm thế nào để vượt qua lập trình bằng sự trùng hợp? [đóng cửa]


24

Trong cuốn sách Lập trình viên thực dụng , các nhà văn đề cập đến lập trình theo khái niệm trùng hợp . Nó giải thích nó là gì, tại sao nó được gây ra, những nguy hiểm bạn có thể gặp phải là gì và nó so sánh với một bãi mìn trong một cuộc chiến.

Bạn có bao giờ xem những bộ phim chiến tranh đen trắng cũ không? Người lính mệt mỏi tiến lên một cách thận trọng ra khỏi bàn chải. Có một giải phóng mặt bằng phía trước: có bất kỳ mỏ đất, hoặc nó có an toàn để vượt qua? Không có bất kỳ dấu hiệu nào cho thấy đó là một bãi mìn không có dấu hiệu, dây thép gai hoặc miệng hố. Người lính chọc đất trước mặt anh ta bằng lưỡi lê và nhăn mặt, mong chờ một vụ nổ. Không có cái nào cả. Vì vậy, anh ta tiến hành một cách siêng năng qua cánh đồng một lúc, chọc và chọc khi anh ta đi. Cuối cùng, tin rằng lĩnh vực này là an toàn, anh ta đứng thẳng và diễu hành về phía trước, chỉ để được thổi thành từng mảnh.

Các thăm dò ban đầu của người lính cho các mỏ không tiết lộ gì, nhưng đây chỉ là may mắn. Anh ta bị dẫn đến một kết luận sai lầm với kết quả thảm hại.

Là nhà phát triển, chúng tôi cũng làm việc trong các bãi mìn. Có hàng trăm cái bẫy chỉ chờ để bắt chúng ta mỗi ngày. Ghi nhớ câu chuyện của người lính, chúng ta nên cảnh giác khi đưa ra kết luận sai. Chúng ta nên tránh lập trình bởi sự trùng hợp ngẫu nhiên, dựa vào may mắn và những thành công tình cờ, có lợi cho việc lập trình một cách có chủ ý ...

Nhưng tôi không thực sự hài lòng về cách họ mô tả vấn đề "làm thế nào để vượt qua nó". Vâng, bạn phải suy nghĩ trước khi viết mã, nhưng làm thế nào để thực hành điều đó? Điều duy nhất tôi có thể nghĩ là bằng cách thêm các tính năng cho các dự án nguồn mở hiện tại, nơi bạn phải có kiến ​​thức về cả "những gì tôi đang làm hiện tại" và "Các đoạn mã khác đang hoạt động như thế nào" và nó không áp dụng được khi bạn đang viết dự án của riêng bạn.

CHỈNH SỬA:

một bản tóm tắt từ bài viết của bạn:

  • Đừng đoán động thái tiếp theo của bạn, hãy chứng minh là đúng
  • Kiểm tra đơn vị và tái cấu trúc càng nhiều càng tốt, khi cần thiết
  • Thêm tính năng kiểm tra biên dịch trên mạng thường xuyên
  • Nếu bạn không thể giải thích mã cho một người mới, có lẽ bạn đang lập trình theo sự trùng hợp.

BTW, thật khó để chấp nhận một câu trả lời, nó thực sự khó. Tất cả các câu trả lời là thực sự tuyệt vời :)


6
Nó sẽ giúp những người có thể đã không đọc cuốn sách trong một thời gian dài để có một liên kết như pragprog.com/the-paticsatic-programmer/extuces/coincidence .
btilly

Trừ khi bạn có một sự nghiệp lập trình rất ngắn (hoặc là một cửa hàng một người đàn ông), bạn có thể gặp phải mã trông có vẻ kỳ lạ và một số bước đi mã sau, đồng xu giảm: đó là của bạn. Đây không chỉ là một sự cân nhắc về Nguồn mở ...
Robbie Dee

@Robbie Dee. bạn có thể làm rõ hơn một chút không? Tôi không hiểu bạn Thật vậy, tôi có một sự nghiệp lập trình ngắn và đó là lý do của thẻ lập trình viên cơ sở.
py_script

2
@py_script Tôi chỉ đưa ra quan điểm rằng bạn có thể dễ dàng bắt gặp mã của chính bạn nhiều năm sau đó (và bị đánh bại bởi nó) như một người khác. Vì vậy, nếu bạn bắt đầu với những thói quen tốt, điều này sẽ trả cổ tức sau này.
Robbie Dee

Câu trả lời:


26

Bạn không cần phải suy nghĩ trước, chỉ đơn giản là rất rõ ràng về những gì đã được thực hiện và rất rõ ràng về những gì bạn đang làm ngay bây giờ.

Các chương trình con nên nói những gì họ làm, làm những gì họ nói và không có những phụ thuộc ẩn. Sau đó, ai đó gọi cho họ có thể dễ dàng hơn lý do về những gì họ sẽ làm.

Tránh nhà nước toàn cầu. (Biến, singletons, v.v.) Càng có nhiều trạng thái mà bạn phải có trong đầu để hiểu những gì làm, càng khó hiểu những gì được cho là xảy ra và tìm các trường hợp cạnh.

Viết bài kiểm tra đơn vị. Các bài kiểm tra đơn vị rất tốt để nắm bắt hành vi thực tế của mã mà bạn vừa viết, thay vì hành vi lý tưởng mà bạn đang hy vọng tìm thấy.

Rút ngắn chu kỳ chỉnh sửa / biên dịch / kiểm tra của bạn. Khi bạn thêm một đoạn mã lớn và kiểm tra kém, thì tỷ lệ cược là nó sẽ hoạt động khác với bạn nghĩ. Sau đó, bạn "sửa" nó bằng một số thay đổi ngẫu nhiên và bạn đã có câu trả lời đúng vào lúc này, nhưng không biết nó thực sự đã xảy ra như thế nào. Bây giờ bạn đang lập trình bởi sự trùng hợp. Nhưng khi bạn thêm 5 dòng và sau đó kiểm tra, tỷ lệ cược mà bạn có câu trả lời đúng bởi vì nó hoạt động như bạn nghĩ nó hoạt động tốt hơn nhiều. Tôi có thể nói từ kinh nghiệm rằng 5 khối 10 dòng mỗi dòng, được kiểm tra riêng lẻ, là một con thú rất khác so với 50 dòng mã được kiểm tra cùng một lúc.

Tái cấu trúc một cách tàn nhẫn. Nhiều lần tôi đã phát hiện ra một công cụ tái cấu trúc sẽ làm cho mã của tôi đơn giản hơn một chút nhưng đảm nhận một loạt công việc mà tôi không muốn làm. Sau khi tôi bắt đầu cố tình giải quyết các nhà tái cấu trúc đó như một ưu tiên, tôi đã thấy rằng nó thường tự trả hết trong vòng một tháng. Nhưng lưu ý chìa khóa, các nhà tái cấu trúc mà tôi tập trung vào là những người làm cho cuộc sống hàng ngày đơn giản hơn, và không phải là những người đáp ứng một số thẩm mỹ tùy ý tốt hơn hoặc tổng quát hơn. Những người tái cấu trúc mà tôi đã học được cách thận trọng hơn nhiều.

Không có những điều này yêu cầu lập kế hoạch trước. Nhưng tất cả đều giúp dễ hiểu mã hiện tại của bạn hơn và do đó giúp dễ dàng thực hiện đoạn mã nhỏ tiếp theo của bạn một cách có chủ ý.


Cảm ơn, câu trả lời thực sự tốt. Tôi nghĩ rằng phần về chu kỳ là thực sự có giá trị. Bạn có thể cho tôi ví dụ về tái cấu trúc rằng bạn nên thực hiện chúng, nhưng sẽ mất nhiều thời gian để thực hiện và điều đó có thể làm nản lòng ai đó?
py_script

1
Tôi có rất nhiều ví dụ. Trong một dự án C ++, tôi đã tạo các lớp mà không có các phương thức chuỗi. Khi tôi tạo chúng, việc gỡ lỗi trở nên dễ dàng hơn và phát triển nhanh hơn. Trong một dự án Perl, chúng tôi đã có một hàm băm cấu hình trong đó mỗi nhà phát triển có bản sao được điều chỉnh riêng của từng cấu hình mới. Thêm tham số cấu hình là một vấn đề khó khăn vì bạn phải chỉnh sửa cấu hình của mọi nhà phát triển. Tôi đã viết hệ thống mẫu cho băm, và điều đó trở nên dễ dàng hơn. Trong một hệ thống báo cáo tôi đã thêm một tính năng để hiển thị kết quả trung gian. Sự phát triển của tôi tăng tốc và tôi thậm chí còn nhận được báo cáo lỗi người dùng ...
btilly

1
nơi bộ phận tài chính đã theo dõi logic của tôi và tìm ra truy vấn chính xác mà tôi đã sai và lỗi của tôi là gì. (Tôi đã vô tình đè bẹp các hàng trùng lặp với UNIONnơi tôi cần UNION ALL.) Và cứ thế.
btilly

1
Bên trong một tháng? Tôi thường thấy rằng mỗi lần chạm vào mã tôi cảm thấy nên được cấu trúc lại, nhưng không được cấu trúc lại, sẽ mất gần như nhiều thời gian để tái cấu trúc mã.
Amy Blankenship

1
@AmyBlankenship Có. Bên trong một tháng. Đôi khi vô lý bên trong, đôi khi không. Điều tập tin cấu hình tôi đã đề cập ở trên là một ví dụ về "đôi khi không". Phải mất vài ngày để tôi viết, tài liệu và thử nghiệm một công cụ mẫu mới. Sau đó viết lại cấu hình hiện có để sử dụng nó, và ngắn hơn nhiều, nhưng tạo ra cấu trúc dữ liệu chính xác tương tự. (Đó là phần khó nhất của dự án.) Vì vậy, ngày bị lãng phí, hoàn toàn không có kết quả rõ ràng. Tuy nhiên, nỗ lực đã được đền đáp chỉ trong vòng chưa đầy một tháng, nhưng đã thu được tiền lãi kể từ đó.
btilly

41

Nó khá sôi sục để không đoán . Hầu hết các lập trình viên mới làm điều đó, nhưng tôi đã thấy các cựu chiến binh cũng làm điều đó, bởi vì họ nghĩ rằng nó tiết kiệm thời gian nghiên cứu. Một cái gì đó không làm việc, vì vậy bạn có thêm một +1hoặc một -1, thay đổi một trueđến một falsehoặc ngược lại, sắp xếp lại một số báo cáo, thêm hoặc chậm trễ thay đổi, ưu tiên thay đổi chủ đề, và sự biến đổi nhỏ khác, về cơ bản thử nghiệm hoán vị ngẫu nhiên cho đến khi nó hoạt động.

Điều đó chủ yếu áp dụng để thay đổi mã hiện có, nhưng cũng là một yếu tố trong mã hoàn toàn mới, bởi vì không ai thực sự bắt đầu từ đầu. Bạn luôn xây dựng trên các thư viện tiêu chuẩn, hệ điều hành hoặc ít nhất là các kiến ​​trúc bộ xử lý.

Nói cách khác, bạn không hoàn thành cho đến khi bạn biết lý do tại sao sửa chữa của bạn hoạt động. Con đường bạn đi để đến đó không quan trọng lắm. Ngay cả các hoán vị ngẫu nhiên đôi khi cũng có thể hữu ích để thu hẹp một lỗi khó chẩn đoán, miễn là bạn dành thời gian sau đó để tự hỏi: "Được rồi, thay đổi thành sai đã sửa, nhưng tại sao?"


1
Điểm xuất sắc +1. Không nơi nào áp dụng điều này nhiều hơn sửa lỗi mã ...
Robbie Dee

Thật không may cho tôi quá, thật không may. Thành thật mà nói, có những khó khăn khách quan như đôi khi thiếu tài liệu. Hôm nay, tôi đã sửa mã của mình một chút và tôi đã nhận ra một thực tế là tôi không biết tham số nào hữu ích, vì thiếu tài liệu. Chúng tôi chỉ biết đó là một con số.
py_script

Tôi thừa nhận. Khi đối mặt với hội chứng tăm nghiêng, việc xếp chồng lên nhau có thể dễ dàng hơn cho đến khi nó hoạt động hơn là tìm ra có bao nhiêu lớp thoát bạn đang đối mặt với ...
btilly

16

Bình luận đáng sợ nhất tôi từng gặp trong một chương trình là

Đừng chạm vào cái này. Nó hoạt động. Chúng tôi không biết làm thế nào hoặc tại sao, nhưng nó hoạt động. 1

và thật đáng sợ chỉ vì nó thừa nhận rằng đoạn mã là kết quả của lập trình bởi sự trùng hợp .

Để tránh lập trình bởi sự trùng hợp ngẫu nhiên, bạn nên có thể giải thích (với đồng nghiệp, chính mình hoặc một con vịt cao su ) chính xác những gì mã làm và lý do tại sao nó hoạt động. Các viên đạn để lập trình có chủ ý chủ yếu là hỗ trợ để tiến tới mục tiêu đó là có thể giải thích mã.


1 Đối với ngữ cảnh, nhận xét này xuất hiện trong mã xử lý các chuyển đổi ngữ cảnh trong HĐH nguyên thủy. Mã đã được sản xuất trong vài năm khi tôi gặp nó.


2
đây cũng được gọi là mã hóa gà voodoo c2.com/cgi/wiki?VoodooChickenCoding
trừ

1
Ngay cả khi các lập trình viên tin rằng nó là sự thật, loại bình luận đó là vô ích. Mã có thể rất phức tạp, nhưng nếu bạn đọc mã khác, bạn có thể nghĩ rằng nó đơn giản. Tất cả các bình luận làm là tăng hoang tưởng!
Robbie Dee

3
Điều này cũng có thể xảy ra khi duy trì một cơ sở mã cũ, trong ngôn ngữ mà hầu hết nhóm phát triển hiện tại không thoải mái lắm.
pcurry

Vì vậy, vịt cao su không chỉ để gỡ lỗi. Thật tuyệt ... Tôi nghĩ chúng tôi đang làm việc trong cùng một công ty, chúng tôi có nhiều nhận xét như thế này: P
py_script

có những tình huống khi một bản sửa lỗi chỉ hoạt động do trục trặc trong API và không có bản sửa lỗi nào tốt hơn và hợp lý hơn. Gỡ lỗi một số lib bên thứ ba được biên dịch có thể đi sâu như gỡ lỗi kernel. Và ngay cả khi bạn tìm thấy vấn đề, sau nhiều giờ gỡ lỗi, bạn vẫn có thể làm được rất ít. Vì vậy, bạn tiếp cận vấn đề khác nhau. Bạn chấp nhận mô hình "hộp đen" bắt buộc bạn phải lập trình theo sự trùng hợp. Bạn chơi xung quanh với hành vi kỳ lạ của hộp đen và nếu bạn xoay sở để khiến nó hoạt động theo cách bạn muốn, TUYỆT VỜI, hãy thêm một nhận xét với "ma thuật không chạm vào" và tiếp tục.
Radu Simionescu

7

Đối với các lập trình viên mới, phần quan trọng nhất của việc khắc phục điều này là thực sự hiểu những gì họ đang làm.

Trong nhiều lĩnh vực, khi bạn không biết cách làm một cái gì đó, bạn chỉ cần thử và sai. Thử một cái gì đó; Nếu nó hoạt động, tuyệt vời, nếu không, hãy thử một cái gì đó khác.

Trong lập trình, đặc biệt là khi sử dụng ngôn ngữ có khái niệm về hành vi không xác định (như C hoặc C ++), cách tiếp cận này đơn giản là không hiệu quả, bởi vì thành công không còn là quyết định boolean. Bạn có thể có những thứ "loại" hoạt động, đôi khi hoạt động, hoạt động cho một số đầu vào nhưng không phải là những thứ khác.

Đôi khi tôi đã dạy kèm cho các lập trình viên mới và xu hướng thử gõ các công cụ ngẫu nhiên để xem nó có hoạt động phổ biến không. Họ sẽ gõ một dòng, sau đó quay sang tôi và hỏi, "Nó có hoạt động theo cách này không?" trong khi rõ ràng là họ hoàn toàn không có manh mối nào.

Điều đáng nói là với tư cách là một lập trình viên mới, bạn thực sự phải có khả năng giải thích mã của bạn làm gì. Bạn phải học cách đọc mã, không chỉ viết nó.

(Tất nhiên cũng áp dụng cho các lập trình viên dày dạn kinh nghiệm, nhưng kinh nghiệm của tôi ở đây chủ yếu là với những người mới bắt đầu hoàn thành.)


<< Bạn phải học cách đọc mã, không chỉ viết nó. >> Vì vậy, về câu hỏi ban đầu của tôi, bạn có nghĩ nó sẽ giúp tôi thêm các tính năng vào các dự án nguồn mở không?
py_script

2

Quá dễ để viết mã, kiểm tra và sửa lỗi "trên đường đua". Bạn có một số chức năng đã cung cấp cho X & Y, tạo Z. Nhưng nếu X bị hỏng và Y không khả dụng thì sao? Nếu bạn không thể xuất Z thì sao? Liên tục có trong tâm trí những gì có thể đi sai và ghi chú về nó cho chu kỳ kiểm tra.

Giữ thói quen của bạn ngắn và mô tả - mã tốt nhất yêu cầu ít ý kiến ​​(nếu có).

Phương thức có ý nghĩa, tên lớp và tên biến đi một chặng đường dài để hỗ trợ khả năng đọc.

Nếu bạn gặp một mùi mã thì DỪNG. Mùi đó khó có thể biến mất và một chút nỗ lực bây giờ có thể giúp bạn tiết kiệm một lượng lớn đau buồn sau này.

Bao gồm thử nghiệm trong quá trình phát triển của bạn. Tôi ủng hộ việc sử dụng BDD thay vì TDD vì nó buộc bạn phải mô tả những gì bạn đang hướng tới để đạt được thay vì mù quáng dựa vào một loạt các bài kiểm tra có thể mang lại cho bạn cảm giác an toàn sai lầm.

Chống lại sự thôi thúc để thêm các tính năng thú vị (trừ khi đó là dự án thú cưng của riêng bạn). Bất kỳ mã bổ sung cần phải được thiết kế, viết, kiểm tra và bảo trì. Nếu khách hàng / doanh nghiệp không yêu cầu - bạn có nguy cơ điều này sẽ gây tổn thất lớn cho tài nguyên của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.