Lập trình sạch sẽ khi viết mã khoa học


169

Tôi không thực sự viết các dự án lớn. Tôi không duy trì một cơ sở dữ liệu khổng lồ hoặc xử lý hàng triệu dòng mã.

Mã của tôi chủ yếu là các loại công cụ "kịch bản" - những thứ để kiểm tra các hàm toán học hoặc để mô phỏng một cái gì đó - "lập trình khoa học". Các chương trình dài nhất mà tôi đã làm cho đến thời điểm này là vài trăm dòng mã và hầu hết các chương trình tôi làm việc là khoảng 150.

Mã của tôi cũng tào lao. Tôi đã nhận ra điều này vào một ngày khác khi tôi đang cố gắng tìm một tập tin mà tôi đã viết cách đây một thời gian nhưng tôi có thể ghi đè lên và tôi không sử dụng kiểm soát phiên bản, điều này có thể khiến một số lượng lớn bạn đau đớn vì sự ngu ngốc của tôi.

Phong cách mã của tôi là phức tạp và chứa đầy các bình luận lỗi thời lưu ý các cách khác để làm một cái gì đó hoặc với các dòng mã được sao chép qua. Mặc dù các tên biến luôn bắt đầu rất đẹp và mô tả, khi tôi thêm hoặc thay đổi mọi thứ theo ví dụ, một cái gì đó mới mà ai đó muốn kiểm tra, mã được phủ lên trên và ghi đè lên và vì tôi cảm thấy điều này nên được kiểm tra nhanh chóng ngay bây giờ có một khung công tác tôi bắt đầu sử dụng tên biến crappy và tập tin đi vào pot.

Trong dự án tôi đang thực hiện, tôi đang trong giai đoạn mà tất cả những điều này sẽ quay trở lại để cắn tôi một cách lớn. Nhưng vấn đề là (ngoài việc sử dụng kiểm soát phiên bản và tạo một tệp mới cho mỗi lần lặp mới và ghi lại tất cả trong một tệp văn bản ở đâu đó, điều này có thể sẽ giúp cải thiện tình hình một cách đáng kể) Tôi thực sự không biết cách tiến hành cải thiện phong cách mã hóa thực tế của tôi.

Là thử nghiệm đơn vị cần thiết để viết các đoạn mã nhỏ hơn? Làm thế nào về OOP? Những cách tiếp cận nào là tốt để viết mã tốt, sạch nhanh khi thực hiện "lập trình khoa học" thay vì làm việc trên các dự án lớn hơn?

Tôi hỏi những câu hỏi này bởi vì thông thường, bản thân chương trình không quá phức tạp. Đó là nhiều hơn về toán học hoặc khoa học mà tôi đang thử nghiệm hoặc nghiên cứu với chương trình. Ví dụ, một lớp cần thiết khi hai biến và hàm có thể có thể chăm sóc nó? .

Có lẽ điều này là quá rộng, và nếu vậy, tôi xin lỗi, nhưng nhìn vào sách lập trình, chúng dường như thường được giải quyết tại các dự án lớn hơn. Mã của tôi không cần OOP và nó khá ngắn nên không giống như "ồ, nhưng tệp sẽ bị giảm hàng nghìn dòng nếu chúng tôi làm như vậy!" Tôi muốn biết làm thế nào để "bắt đầu lại" và lập trình sạch sẽ cho các dự án nhỏ hơn, nhanh hơn này.

Tôi sẽ vui mừng cung cấp chi tiết cụ thể hơn, nhưng lời khuyên càng chung chung, tôi càng hữu ích. Tôi đang lập trình trong Python 3.


Có người đề nghị một bản sao. Hãy để tôi nói rõ rằng tôi không nói về việc bỏ qua các tiêu chuẩn lập trình tiêu chuẩn hoàn toàn. Rõ ràng, có một lý do những tiêu chuẩn đó tồn tại. Nhưng mặt khác, việc viết mã có nghĩa là OOP khi thực hiện một số nội dung tiêu chuẩn có thể đã được thực hiện, sẽ nhanh hơn nhiều và có thể dễ đọc hơn vì độ ngắn của nó chương trình?

Có ngoại lệ. Hơn nữa, có thể có các tiêu chuẩn cho lập trình khoa học ngoài các tiêu chuẩn đơn giản. Tôi cũng đang hỏi về những điều đó. Đây không phải là nếu các tiêu chuẩn mã hóa bình thường nên được bỏ qua khi viết mã khoa học, đó là về việc viết mã khoa học sạch!


Cập nhật

Chỉ cần nghĩ rằng tôi sẽ thêm một loại cập nhật "không phải một tuần sau". Tất cả những lời khuyên của bạn là vô cùng hữu ích. Bây giờ tôi đang sử dụng kiểm soát phiên bản - git, với git kraken cho giao diện đồ họa. Nó rất dễ sử dụng và đã dọn sạch các tệp của tôi một cách quyết liệt - không cần thêm các tệp cũ dính xung quanh, hoặc các phiên bản mã cũ đã nhận xét "chỉ trong trường hợp".

Tôi cũng đã cài đặt pylint và chạy nó trên tất cả các mã của tôi. Một tập tin có điểm âm ban đầu; Tôi thậm chí không chắc làm thế nào là có thể. Tập tin chính của tôi bắt đầu với số điểm ~ 1,83 / 10 và hiện tại là ~ 9,1 / 10. Tất cả các mã bây giờ phù hợp khá tốt với các tiêu chuẩn. Tôi cũng lướt qua nó bằng chính đôi mắt của mình đang cập nhật những tên biến đã biến mất ... uhm ... thật kỳ quặc, và tìm kiếm các phần để tái cấu trúc.

Cụ thể, tôi đã hỏi một câu hỏi gần đây trên trang web này về việc tái cấu trúc một trong những chức năng chính của tôi, và bây giờ nó gọn gàng hơn và ngắn hơn rất nhiều: thay vì một chức năng đầy, dài, đầy đủ, bây giờ chỉ còn chưa đến một nửa kích thước và dễ dàng hơn nhiều để tìm hiểu những gì đang xảy ra.

Bước tiếp theo của tôi là thực hiện "thử nghiệm đơn vị" các loại. Ý tôi là một tệp mà tôi có thể chạy trên tệp chính của mình, nó xem xét tất cả các chức năng trong đó với các câu lệnh khẳng định và thử / chấp nhận, đây có thể không phải là cách tốt nhất để thực hiện và dẫn đến rất nhiều mã trùng lặp, nhưng tôi sẽ tiếp tục đọc và cố gắng tìm ra cách để làm nó tốt hơn.

Tôi cũng đã cập nhật đáng kể tài liệu tôi đã viết và thêm các tệp bổ sung như bảng tính excel, tài liệu và giấy liên quan đến kho lưu trữ github. Nó trông giống như một dự án lập trình thực sự bây giờ.

Vì vậy, ... tôi đoán đây là tất cả để nói: cảm ơn bạn .




8
Nếu bạn chủ động muốn cải thiện mã của mình, bạn có thể xem xét đăng một số bài trên Đánh giá mã . Cộng đồng ở đó sẽ sẵn lòng giúp bạn với điều đó.
hoffmale

7
Khi bạn nói "ngoài việc sử dụng kiểm soát phiên bản và tạo một tệp mới cho mỗi lần lặp mới và ghi lại tất cả trong một tệp văn bản ở đâu đó" bởi "và" bạn có nghĩa là "hoặc" bởi vì nếu bạn đang sử dụng kiểm soát phiên bản, bạn không nên Sẽ không sao chép các phiên bản dán. Vấn đề là kiểm soát phiên bản sẽ giữ tất cả phiên bản cũ cho bạn
Richard Tingle

2
@mathreadler Tôi không nghĩ bạn khá hiểu. Vâng, chỉ có tôi là tôi sẽ thực sự đọc và viết mã (mặc dù bạn không bao giờ biết, và tôi có ai đó tôi đang làm việc với người có thể lập trình, mặc dù bằng một ngôn ngữ khác) ... nhưng mã vẫn tào lao Tôi sẽ phải đọc nó sau và tìm hiểu lại những gì tôi đang làm. Đây một vấn đề và tôi có thể làm chứng cho vấn đề này vì hiện tại tôi đang gặp phải các hiệu ứng và mọi thứ trở nên dễ dàng hơn khi tôi triển khai kiểm soát phiên bản và các kỹ thuật khác được đề xuất ở đây.
thạch

Câu trả lời:


163

Đây là một vấn đề khá phổ biến đối với các nhà khoa học. Tôi đã nhìn thấy nó rất nhiều, và nó luôn bắt nguồn từ thực tế rằng lập trình là thứ bạn chọn ở bên cạnh như một công cụ để thực hiện công việc của mình.

Vì vậy, kịch bản của bạn là một mớ hỗn độn. Tôi sẽ đi ngược lại với lẽ thường và nói rằng, giả sử bạn đang lập trình một mình, điều này không tệ lắm! Bạn sẽ không bao giờ chạm vào hầu hết những gì bạn viết một lần nữa, vì vậy dành quá nhiều thời gian để viết mã đẹp thay vì tạo ra "giá trị" (vì vậy kết quả của kịch bản của bạn) sẽ không ảnh hưởng nhiều đến bạn.

Tuy nhiên, sẽ có lúc bạn cần quay lại với những gì bạn đã làm và xem chính xác cách thức hoạt động của một cái gì đó. Ngoài ra, nếu các nhà khoa học khác sẽ cần xem lại mã của bạn, điều đó thực sự quan trọng đối với nó phải rõ ràng và súc tích nhất có thể, để mọi người có thể hiểu được mã đó.

Vấn đề chính của bạn sẽ là khả năng đọc, vì vậy đây là một vài mẹo để cải thiện:

Tên biến:

Các nhà khoa học thích sử dụng các ký hiệu súc tích. Tất cả các phương trình toán học thường sử dụng các chữ cái đơn lẻ làm biến số và tôi sẽ không ngạc nhiên khi thấy rất nhiều biến số rất ngắn trong mã của bạn. Điều này làm tổn thương khả năng đọc rất nhiều. Khi bạn quay lại mã của mình, bạn sẽ không nhớ những gì y, i và x2 đại diện và bạn sẽ dành nhiều thời gian để cố gắng tìm ra nó. Thay vào đó, hãy thử đặt tên cho các biến của bạn một cách rõ ràng, sử dụng các tên thể hiện chính xác chúng là gì.

Chia mã của bạn thành các hàm:

Bây giờ bạn đã đổi tên tất cả các biến của mình, phương trình của bạn trông rất tệ và dài nhiều dòng.

Thay vì để nó trong chương trình chính của bạn, hãy di chuyển phương trình đó sang một hàm khác và đặt tên cho nó. Bây giờ thay vì có một dòng mã lớn và rối tung, bạn sẽ có một hướng dẫn ngắn gọn cho bạn biết chính xác những gì đang xảy ra và phương trình bạn đã sử dụng. Điều này cải thiện cả chương trình chính của bạn, vì bạn thậm chí không cần nhìn vào phương trình thực tế để biết bạn đã làm gì và chính mã phương trình, như trong một hàm riêng biệt, bạn có thể đặt tên cho biến của mình theo cách bạn muốn và quay lại các chữ cái đơn quen thuộc hơn.

Trên dòng suy nghĩ này, hãy cố gắng tìm ra tất cả các đoạn mã đại diện cho một cái gì đó, đặc biệt nếu đó là thứ gì đó bạn phải làm nhiều lần trong mã của mình và chia chúng thành các hàm. Bạn sẽ thấy rằng mã của bạn sẽ nhanh chóng trở nên dễ đọc hơn và bạn sẽ có thể sử dụng các chức năng tương tự mà không cần viết thêm mã.

Đóng băng trên bánh, nếu những chức năng đó là cần thiết trong nhiều chương trình của bạn, bạn có thể tạo thư viện cho chúng và bạn sẽ luôn có sẵn chúng.

Biến toàn cầu:

Quay lại khi tôi mới bắt đầu, tôi nghĩ rằng đây là một cách tuyệt vời để truyền dữ liệu tôi cần trong nhiều điểm của chương trình. Hóa ra có nhiều cách khác để vượt qua mọi thứ, và điều duy nhất các biến toàn cầu làm là khiến mọi người đau đầu, vì nếu bạn đi đến một điểm ngẫu nhiên của chương trình, bạn sẽ không bao giờ biết khi nào giá trị đó được sử dụng hoặc chỉnh sửa lần cuối, và theo dõi nó sẽ là một nỗi đau. Cố gắng tránh chúng bất cứ khi nào có thể.

Nếu các hàm của bạn cần trả về hoặc sửa đổi nhiều giá trị, hãy tạo một lớp với các giá trị đó và chuyển chúng xuống dưới dạng tham số hoặc làm cho hàm trả về nhiều giá trị (với các bộ dữ liệu có tên) và gán các giá trị đó trong mã người gọi.

Kiểm soát phiên bản

Điều này không trực tiếp cải thiện khả năng đọc, nhưng giúp bạn làm tất cả những điều trên. Bất cứ khi nào bạn thực hiện một số thay đổi, hãy cam kết kiểm soát phiên bản (kho lưu trữ Git cục bộ sẽ đủ tốt) và nếu có gì đó không hoạt động, hãy xem những gì bạn đã thay đổi hoặc chỉ cần quay lại! Điều này sẽ làm cho việc tái cấu trúc mã của bạn dễ dàng hơn và sẽ trở thành một mạng lưới an toàn nếu bạn vô tình phá vỡ mọi thứ.

Giữ tất cả những điều này trong tâm trí sẽ cho phép bạn viết mã rõ ràng và hiệu quả hơn, và cũng sẽ giúp bạn tìm ra những lỗi có thể nhanh hơn, vì bạn sẽ không phải lội qua các hàm khổng lồ và các biến lộn xộn.


56
Lời khuyên tuyệt vời. Tuy nhiên tôi không thể đánh giá cao cho nhận xét "đó không phải là quá tệ". Thật là tệ Các kịch bản khoa học chất lượng thấp là một vấn đề lớn đối với khả năng tái tạo trong phân tích dữ liệu và là nguồn thường xuyên xảy ra lỗi trong phân tích. Viết mã tốt có giá trị không chỉ để bạn có thể hiểu nó sau này mà còn để bạn có thể tránh lỗi ngay từ đầu.
Jack Aidley

22
Nếu mã là một triển khai của một công thức nổi tiếng, thì tên biến một chữ cái và đó có thể là điều đúng đắn. Phụ thuộc vào khán giả ... và hơn thế nữa, liệu người đọc có dự kiến ​​sẽ biết ý nghĩa của những cái tên đó hay không.
cHao

11
@cHao vấn đề không phải là khi các biến đó được cắm vào công thức (do đó lời khuyên "đổi tên chúng bên trong hàm"), mà là khi chúng đọc và thao tác bên ngoài nó và khi chúng bắt đầu xung đột với các biến khác xuống dòng (ví dụ: tôi đã thấy những người cần ba biến "x" đặt tên cho họ là x1, x2, x3)
BgrWorker

4
"Tôi sẽ đi ngược lại với lẽ thường ..." Không, bạn không phải. Bạn đang đi ngược lại giáo điều thịnh hành, điều này trái với lẽ thường. ;) Đây là tất cả lời khuyên hoàn hảo âm thanh.
jpmc26

3
Là một lập trình viên khoa học (trước đây), tôi thường áp dụng quy tắc ba. Nếu tôi kết thúc việc viết mã tương tự ba lần, chức năng sẽ được bổ sung và viết thành một mô-đun riêng với tài liệu (thường chỉ là nhận xét, nhưng điều đó là đủ). Điều này hạn chế sự hỗn loạn của lập trình ad-hoc và cho phép tôi xây dựng một thư viện mà tôi có thể mở rộng trong tương lai.
rcollyer

141

Nhà vật lý ở đây. Đã ở đó.

Tôi cho rằng vấn đề của bạn không nằm ở việc lựa chọn công cụ hay mô hình lập trình (kiểm thử đơn vị, OOP, bất cứ điều gì). Đó là về thái độ , suy nghĩ. Thực tế, tên biến của bạn được chọn tốt lúc đầu và cuối cùng là tào lao là đủ để lộ. Nếu bạn nghĩ rằng mã của bạn là một lần chạy, sau đó vứt bỏ, thì chắc chắn nó sẽ là một mớ hỗn độn. Nếu bạn nghĩ nó là sản phẩm của thủ công và tình yêu, nó sẽ rất đẹp.

Tôi tin rằng chỉ có một công thức để viết mã sạch: viết nó cho con người sẽ đọc nó, không phải cho người phiên dịch sẽ chạy nó. Trình thông dịch không quan tâm nếu mã của bạn là một mớ hỗn độn, nhưng người đọc không quan tâm.

Bạn là một nhà khoa học. Bạn có thể có thể dành nhiều thời gian để đánh bóng một bài báo khoa học. Nếu bản nháp đầu tiên của bạn trông có vẻ phức tạp, bạn sẽ cấu trúc lại nó cho đến khi logic chỉ chảy theo cách tự nhiên nhất. Bạn muốn đồng nghiệp của bạn đọc nó và tìm thấy các đối số rõ ràng. Bạn muốn sinh viên của bạn có thể học hỏi từ nó.

Viết mã sạch là hoàn toàn giống nhau. Hãy nghĩ về mã của bạn như là một lời giải thích chi tiết về một thuật toán chỉ tình cờ có thể đọc được bằng máy. Hãy tưởng tượng bạn sẽ xuất bản nó như một bài viết mà mọi người sẽ đọc. Bạn thậm chí sẽ thể hiện nó tại một hội nghị và dẫn dắt khán giả đi qua từng dòng một. Bây giờ tập lại bài thuyết trình của bạn . Vâng, từng dòng một ! Xấu hổ quá phải không? Vì vậy, hãy dọn sạch các slide của bạn (err ... ý tôi là, mã của bạn) và thử lại lần nữa. Lặp lại cho đến khi bạn hài lòng với kết quả.

Sẽ tốt hơn nếu sau khi diễn tập, bạn có thể hiển thị mã của mình cho người thật thay vì chỉ là người tưởng tượng và con người tương lai của bạn. Đi xuyên qua từng dòng một được gọi là mã đi bộ trên mạng, và đó không phải là một thực tế ngớ ngẩn.

Tất nhiên, tất cả điều này đi kèm với một chi phí. Viết mã sạch mất nhiều thời gian hơn so với viết mã vứt đi. Chỉ bạn mới có thể đánh giá xem lợi ích có cao hơn chi phí cho trường hợp sử dụng cụ thể của bạn hay không.

Đối với các công cụ, tôi đã nói trước khi họ không quan trọng. Tuy nhiên, nếu tôi phải chọn một, tôi sẽ nói kiểm soát phiên bản là hữu ích nhất.


32
«Viết mã sạch hoàn toàn giống nhau [như viết một bài viết rõ ràng].» Tôi hoàn toàn tán thành điều đó, cũng được!
juandesant

43
Đây là điều mà hầu hết các lập trình viên chuyên nghiệp quên nói vì nó quá rõ ràng. Mã của bạn kết thúc khi có thể đọc và sửa đổi bởi một lập trình viên khác. Không phải khi nó chạy và tạo ra đầu ra chính xác. OP cần phải dành và thêm giờ cho mỗi lần tái cấu trúc tập lệnh và nhận xét mã của mình để làm cho nó có thể đọc được.
UEFI

31
Mặc dù viết mã sạch sẽ tốn nhiều thời gian hơn so với viết mã vứt đi, nhưng điều quan trọng hơn nhiều là việc đọc mã ném mất nhiều thời gian hơn so với đọc mã sạch.
dùng949300

3
@UEFI Không, đó là điều mà hầu hết các lập trình viên chuyên nghiệp thậm chí không nhận ra. Hoặc không quan tâm.
jpmc26

2
Đồng ý 100%. Thống kê đã trở thành lập trình viên, vì vậy tôi thực hiện một số lượng lớn chương trình 'khoa học' trong công việc. Xóa mã, với các nhận xét có ý nghĩa là cứu cánh khi bạn phải quay lại mã đó 1, 4 hoặc 12 tháng sau. Đọc mã cho bạn biết những gì mã đang làm. Đọc các bình luận cho bạn biết những gì mã được cho là đang làm.
railsdog

82

Kiểm soát phiên bản có thể sẽ cung cấp cho bạn nhiều bang nhất cho buck của bạn. Nó không chỉ dành cho lưu trữ dài hạn, thật tuyệt khi theo dõi thử nghiệm ngắn hạn của bạn và quay lại phiên bản cuối cùng hoạt động, ghi chú trên đường đi.

Tiếp theo hữu ích nhất là các bài kiểm tra đơn vị. Điều về kiểm thử đơn vị là các cơ sở mã thậm chí với hàng triệu dòng mã được kiểm tra đơn vị một chức năng tại một thời điểm. Kiểm thử đơn vị được thực hiện trong phạm vi nhỏ, ở mức độ trừu tượng thấp nhất. Điều đó có nghĩa là về cơ bản không có sự khác biệt giữa các thử nghiệm đơn vị được viết cho các cơ sở mã nhỏ và các thử nghiệm được sử dụng cho lớn. Chỉ có nhiều hơn trong số họ.

Kiểm tra đơn vị là cách tốt nhất để tránh làm hỏng thứ gì đó đã hoạt động khi bạn sửa một thứ khác, hoặc ít nhất là nhanh chóng cho bạn biết khi bạn làm. Chúng thực sự hữu ích hơn khi bạn không phải là một lập trình viên lành nghề, hoặc không biết làm thế nào hoặc không muốn viết thêm mã dài dòng được cấu trúc để làm cho các lỗi ít có khả năng hoặc rõ ràng hơn.

Giữa kiểm soát phiên bản và kiểm tra đơn vị viết khi bạn đi, mã của bạn sẽ tự nhiên trở nên sạch hơn rất nhiều. Các kỹ thuật khác để mã hóa sạch hơn có thể được học khi bạn đạt đến một cao nguyên.


78
Tôi tôn trọng đơn vị kiểm tra hầu hết các mã của tôi nhưng tôi đã tìm thấy đơn vị thử nghiệm thăm dò, mã khoa học ít hơn vô dụng . Phương pháp cơ bản dường như không hoạt động ở đây. Tôi không biết bất kỳ nhà khoa học tính toán nào trong lĩnh vực của mình, người kiểm tra mã phân tích của họ. Tôi không chắc lý do của sự không phù hợp này là gì nhưng một trong những lý do chắc chắn là, ngoại trừ các đơn vị tầm thường, thật khó hoặc không thể thiết lập các trường hợp thử nghiệm tốt.
Konrad Rudolph

22
$ một số đầu ra có thể đọc được của con người hoặc hình dung. Vấn đề ở đây có thể là sự phân tách các mối quan tâm kém dẫn đến làm mờ các dòng đó, dẫn đến một nhận thức rằng thử nghiệm đơn vị trong bối cảnh này là không thể, dẫn bạn trở lại bắt đầu trong một chu kỳ lặp lại.
Ant P

18
Mặt khác, kiểm soát phiên bản cũng hoạt động khá độc đáo đối với các tài liệu LaTeX, vì định dạng có thể thay đổi theo văn bản. Theo cách này, bạn có thể có một kho lưu trữ cho cả giấy tờ của mình và mã hỗ trợ chúng. Tôi đề nghị xem xét kiểm soát phiên bản phân tán, như Git. Có một chút về đường cong học tập, nhưng khi bạn hiểu nó, bạn đã có một cách sạch đẹp để lặp lại sự phát triển của mình và bạn có một số tùy chọn thú vị để sử dụng một nền tảng như Github, cung cấp tài khoản nhóm miễn phí cho các học giả .
Dan Bryant

12
@AntP Có thể không có nhiều mã có thể được tái cấu trúc một cách có ý nghĩa thành các đơn vị kiểm tra được xác định rõ. Rất nhiều mã khoa học về cơ bản là ghi lại một loạt các thư viện với nhau. Các thư viện này sẽ được kiểm tra tốt và có cấu trúc rõ ràng, có nghĩa là tác giả chỉ phải viết "keo", và theo kinh nghiệm của tôi, gần như không thể viết các bài kiểm tra đơn vị cho keo không phải là tautological.
James_pic

7
"Giữa kiểm soát phiên bản và kiểm tra đơn vị viết khi bạn đi, mã của bạn sẽ tự nhiên trở nên sạch hơn rất nhiều." Điều này không đúng Tôi có thể chứng thực cá nhân nó. Cả hai công cụ này đều không ngăn bạn viết mã crappy, và đặc biệt, viết các bài kiểm tra tào lao trên đầu mã crappy chỉ khiến việc dọn dẹp trở nên khó khăn hơn. Các thử nghiệm không phải là một viên đạn bạc ma thuật, và nói như chúng là một điều khủng khiếp đối với bất kỳ nhà phát triển nào vẫn đang học (đó là tất cả mọi người). Kiểm soát phiên bản thường không bao giờ gây ra thiệt hại cho chính mã như thử nghiệm xấu.
jpmc26

29

(ngoài việc sử dụng kiểm soát phiên bản và tạo một tệp mới cho mỗi lần lặp mới và ghi lại tất cả trong một tệp văn bản ở đâu đó, điều này có thể sẽ giúp tình huống đáng kể)

Có thể bạn đã tự mình tìm ra điều này, nhưng nếu bạn phải " ghi lại tất cả trong một tệp văn bản ở đâu đó " thì bạn không sử dụng hệ thống kiểm soát phiên bản với tiềm năng đầy đủ của nó. Sử dụng một cái gì đó như Subversion, git hoặc Mercurial và viết một thông điệp cam kết tốt với mỗi cam kết và bạn sẽ có một nhật ký phục vụ mục đích của tệp văn bản nhưng không thể tách rời khỏi kho lưu trữ.

Ngoài ra, sử dụng kiểm soát phiên bản là điều quan trọng nhất bạn có thể làm vì một lý do mà không câu trả lời nào hiện có đề cập: độ tái lập của kết quả . Nếu bạn có thể sử dụng thông điệp tường trình của mình hoặc thêm ghi chú vào kết quả bằng số sửa đổi thì bạn có thể chắc chắn có thể tạo lại kết quả và bạn sẽ được xuất bản tốt hơn để xuất bản mã bằng giấy.

Là thử nghiệm đơn vị cần thiết để viết các đoạn mã nhỏ hơn? Làm thế nào về OOP? Những cách tiếp cận nào là tốt để viết mã tốt, sạch nhanh khi thực hiện "lập trình khoa học" thay vì làm việc trên các dự án lớn hơn?

Kiểm thử đơn vị là không bao giờ cần thiết, nhưng sẽ hữu ích nếu (a) mã đủ mô-đun để bạn có thể kiểm tra các đơn vị thay vì toàn bộ; (b) bạn có thể tạo các bài kiểm tra. Lý tưởng nhất là bạn có thể viết đầu ra dự kiến ​​bằng tay thay vì tạo nó bằng mã, mặc dù việc tạo nó bằng mã ít nhất có thể cung cấp cho bạn các bài kiểm tra hồi quy cho bạn biết liệu có gì đó thay đổi hành vi của nó hay không. Chỉ cần xem xét các thử nghiệm có nhiều khả năng bị lỗi hơn mã mà chúng đang thử nghiệm hay không.

OOP là một công cụ. Sử dụng nó nếu nó giúp, nhưng nó không phải là mô hình duy nhất. Tôi giả sử rằng bạn chỉ thực sự biết lập trình thủ tục: nếu đó là trường hợp, thì trong bối cảnh được mô tả tôi nghĩ bạn sẽ được hưởng lợi nhiều hơn từ việc nghiên cứu lập trình chức năng hơn OOP, và đặc biệt là kỷ luật tránh tác dụng phụ khi có thể. Python có thể được viết theo phong cách rất chức năng.


4
+1 cho tin nhắn cam kết; chúng giống như những bình luận không thể bị lỗi thời bởi vì chúng được gắn với phiên bản mã khi chúng thực sự được áp dụng. Để hiểu mã cũ của bạn, việc xem qua lịch sử của dự án sẽ dễ dàng hơn (nếu các thay đổi được cam kết ở mức độ chi tiết hợp lý) hơn là đọc các bình luận lỗi thời.
Silly Freak

Lật đổ, git và Mercurial không bị nấm. Tôi rất muốn ủng hộ việc sử dụng Git (hoặc Mercurial) với kho lưu trữ cục bộ trên Subversion. Với một lập trình viên solo, lỗ hổng của Subversion không phải là vấn đề nhưng nó không phải là một công cụ tuyệt vời để phát triển hợp tác và điều đó có thể xảy ra trong nghiên cứu
phá hủy

2
@mcottle, cá nhân tôi thích git nhưng tôi không nghĩ đây là nơi thích hợp để đi sâu vào chi tiết về sự khác biệt, đặc biệt là sự lựa chọn là một trong những cuộc chiến tôn giáo tích cực. Tốt hơn là khuyến khích OP sử dụng thứ gì đó hơn là khiến họ sợ hãi khỏi khu vực và quyết định không phải là vĩnh viễn trong mọi trường hợp.
Peter Taylor

21

Ở trường đại học, tôi đã tự viết một số mã nặng thuật toán. Đó là một chút khó khăn để phá vỡ. Nói một cách dễ hiểu, rất nhiều quy ước lập trình được xây dựng xoay quanh ý tưởng đưa thông tin vào cơ sở dữ liệu, truy xuất nó đúng lúc và sau đó xoa bóp dữ liệu đó để trình bày cho người dùng, thường sử dụng thư viện cho bất kỳ toán học nào hoặc phần nặng thuật toán của quá trình đó. Đối với các chương trình này, mọi thứ bạn đã nghe về OOP, chia mã thành các hàm ngắn và làm cho mọi thứ dễ hiểu trong nháy mắt, nơi có thể là lời khuyên tuyệt vời. Nhưng nó không hoạt động hoàn toàn đối với mã nặng thuật toán hoặc mã thực hiện các phép tính toán học phức tạp và ít thứ khác.

Nếu bạn đang viết các tập lệnh để thực hiện các tính toán khoa học, có lẽ bạn có các bài báo với các phương trình hoặc thuật toán bạn sử dụng được viết trong đó. Nếu bạn đang sử dụng những ý tưởng mới mà bạn tự mình khám phá, bạn hy vọng sẽ xuất bản chúng trên các bài báo của riêng bạn. Trong trường hợp này, quy tắc là: Bạn muốn mã của mình đọc càng giống các phương trình đã xuất bản càng tốt. Dưới đây là một câu trả lời trên phần mềm Engineering.SE với hơn 200 upvotes ủng hộ phương pháp này và giải thích những gì nó trông giống như: Có một cái cớ cho tên biến ngắn?

Một ví dụ khác, có một số đoạn mã tuyệt vời trong Simbody , một công cụ mô phỏng vật lý được sử dụng cho nghiên cứu vật lý và kỹ thuật. Các đoạn mã này có một nhận xét cho thấy một phương trình đang được sử dụng để tính toán, theo sau là mã đọc càng sát với các phương trình đang được thực hiện càng tốt.

ContactGeometry.cpp:

// t = (-b +/- sqrt(b^2-4ac)) / 2a
// Discriminant must be nonnegative for real surfaces
// but could be slightly negative due to numerical noise.
Real sqrtd = std::sqrt(std::max(B*B - 4*A*C, Real(0)));
Vec2 t = Vec2(sqrtd - B, -sqrtd - B) / (2*A);

ContactGeometry_Sphere.cpp:

// Solve the scalar Jacobi equation
//
//        j''(s) + K(s)*j(s) = 0 ,                                     (1)
//
// where K is the Gaussian curvature and (.)' := d(.)/ds denotes differentiation
// with respect to the arc length s. Then, j is the directional sensitivity and
// we obtain the corresponding variational vector field by multiplying b*j. For
// a sphere, K = R^(-2) and the solution of equation (1) becomes
//
//        j  = R * sin(1/R * s)                                        (2)
//          j' =     cos(1/R * s) ,                                      (3)
//
// where equation (2) is the standard solution of a non-damped oscillator. Its
// period is 2*pi*R and its amplitude is R.

// Forward directional sensitivity from P to Q
Vec2 jPQ(R*sin(k * s), cos(k * s));
geod.addDirectionalSensitivityPtoQ(jPQ);

// Backwards directional sensitivity from Q to P
Vec2 jQP(R*sin(k * (L-s)), cos(k * (L-s)));
geod.addDirectionalSensitivityQtoP(jQP);

9
Cộng với một để tạo ra "mã để đọc càng nhiều phương trình được công bố càng tốt". Xin lỗi, ủng hộ tên biến dài, có ý nghĩa. Các tên có ý nghĩa nhất trong các mã khoa học thường rất khó chịu, ngắn và tàn bạo vì đó chính xác là quy ước được sử dụng trong một bài báo khoa học mà bộ luật đang cố gắng thực hiện. Đối với một đoạn mã nặng phương trình thực hiện các phương trình được tìm thấy trong một bài báo, tốt nhất là nên ở gần nhất có thể với danh pháp trong bài báo, và nếu điều này đi ngược lại với tiêu chuẩn mã hóa tốt, khó khăn.
David Hammen

@DavidHammen: Là một học sinh tốt nghiệp, tôi tôn trọng điều đó. Là một lập trình viên, sau đó tôi khẳng định rằng bạn có một khối nhận xét khổng lồ ở đầu mỗi chức năng mô tả bằng tiếng Anh đơn giản (hoặc ngôn ngữ bạn chọn), mỗi biến số là gì, ngay cả khi chỉ là một trình giữ chỗ tạm thời. Bằng cách đó tôi ít nhất có một tài liệu tham khảo để nhìn lại.
tonysdg

1
@DavidHammen Bên cạnh đó, Python hỗ trợ UTF-8 trong các tệp nguồn và các quy tắc đơn giản cho các tên biến giúp dễ dàng khai báo λhoặc φthay vì xấu xí lambda_hoặc phy...
Mathias Ettinger

1
@tonysdg Bạn đã có một tài liệu tham khảo; nó được gọi là "Hammen, et al. (2018)" (hoặc bất cứ điều gì). Nó sẽ giải thích ý nghĩa của các biến chi tiết hơn nhiều so với bất kỳ khối nhận xét nào từng có thể. Lý do để giữ các tên biến gần với ký hiệu trong bài viết chính xác là để giúp kết nối những gì trong bài báo với những gì trong mã dễ dàng hơn.
Không ai vào

17

Vì vậy, công việc hàng ngày của tôi là nghiên cứu xuất bản và bảo quản dữ liệu cho hệ thống Đại học California. Một vài người đã đề cập đến khả năng tái tạo và tôi nghĩ đó thực sự là vấn đề cốt lõi ở đây: ghi lại mã của bạn theo cách bạn ghi lại bất cứ điều gì khác mà ai đó cần để tái tạo thử nghiệm của bạn, và, lý tưởng nhất là viết mã giúp đơn giản cho người khác để tái tạo thử nghiệm của bạn và kiểm tra kết quả của bạn để tìm nguồn lỗi.

Nhưng một điều mà tôi chưa thấy đề cập đến, mà tôi nghĩ là quan trọng, đó là các cơ quan tài trợ đang ngày càng xem xuất bản phần mềm như một phần của xuất bản dữ liệu và làm cho xuất bản phần mềm trở thành một yêu cầu cho khoa học mở.

Cuối cùng, nếu bạn muốn một cái gì đó cụ thể, nhắm vào các nhà nghiên cứu thay vì các nhà phát triển phần mềm nói chung, tôi không thể đề xuất tổ chức Mộc phần mềm đủ cao. Nếu bạn có thể tham dự một trong những hội thảo của họ , thật tuyệt; nếu tất cả những gì bạn có thời gian / quyền truy cập để làm là đọc một số bài viết của họ về thực hành tốt nhất về máy tính khoa học , thì điều đó cũng tốt. Từ sau

Các nhà khoa học thường phát triển phần mềm của riêng họ cho các mục đích này vì làm như vậy đòi hỏi kiến ​​thức cụ thể về miền. Do đó, các nghiên cứu gần đây đã phát hiện ra rằng các nhà khoa học thường dành 30% hoặc hơn thời gian để phát triển phần mềm. Tuy nhiên, 90% trở lên chủ yếu là tự học và do đó thiếu tiếp xúc với các thực tiễn phát triển phần mềm cơ bản như viết mã có thể bảo trì, sử dụng kiểm soát phiên bản và trình theo dõi vấn đề, đánh giá mã, kiểm tra đơn vị và tự động hóa tác vụ.

Chúng tôi tin rằng phần mềm chỉ là một loại thiết bị thử nghiệm khác và cần được xây dựng, kiểm tra và sử dụng cẩn thận như mọi thiết bị vật lý. Tuy nhiên, trong khi hầu hết các nhà khoa học cẩn thận xác nhận phòng thí nghiệm và thiết bị hiện trường của họ, thì hầu hết không biết phần mềm của họ đáng tin cậy đến mức nào. Điều này có thể dẫn đến các lỗi nghiêm trọng ảnh hưởng đến kết luận trung tâm của nghiên cứu được công bố. Giáo dục

Ngoài ra, do phần mềm thường được sử dụng cho nhiều dự án và thường được các nhà khoa học khác sử dụng lại, các lỗi máy tính có thể có tác động không tương xứng đến quá trình khoa học. Loại tác động xếp tầng này đã gây ra một số rút lại nổi bật khi một lỗi từ mã của nhóm khác không được phát hiện cho đến sau khi xuất bản.

Một phác thảo cấp cao về các thực hành mà họ đề xuất:

  1. Viết chương trình cho mọi người, không phải máy tính
  2. Hãy để máy tính làm việc
  3. Thay đổi gia tăng
  4. Đừng lặp lại chính mình (hoặc người khác)
  5. Lên kế hoạch cho những sai lầm
  6. Tối ưu hóa phần mềm chỉ sau khi nó hoạt động chính xác
  7. Thiết kế tài liệu và mục đích, không phải cơ học
  8. Hợp tác

Bài viết đi sâu vào chi tiết đáng kể về từng điểm này.


16

Có thực sự có ý nghĩa khi viết mã có nghĩa là OOP khi một số nội dung tiêu chuẩn có thể đã được thực hiện, sẽ nhanh hơn nhiều để viết và sẽ có mức độ dễ đọc tương tự vì độ ngắn của chương trình?

Câu trả lời cá nhân:
Tôi cũng làm rất nhiều kịch bản cho mục đích khoa học. Đối với các tập lệnh nhỏ hơn, tôi chỉ đơn giản là cố gắng tuân theo các thực tiễn lập trình tốt chung (nghĩa là sử dụng kiểm soát phiên bản, thực hành tự kiểm soát với các tên biến). Nếu tôi chỉ viết một cái gì đó để nhanh chóng mở hoặc trực quan hóa một tập dữ liệu, tôi không bận tâm với OOP.

Câu trả lời chung:
"Nó phụ thuộc." Nhưng nếu bạn đang vật lộn để tìm ra khi nào nên sử dụng một khái niệm hoặc mô hình lập trình, thì đây là một vài điều cần suy nghĩ:

  • Khả năng mở rộng: Tập lệnh sẽ đứng một mình, hay cuối cùng nó sẽ được sử dụng trong một chương trình lớn hơn? Nếu vậy, chương trình lớn hơn có sử dụng OOP không? Mã trong tập lệnh của bạn có thể dễ dàng tích hợp vào chương trình lớn hơn không?
  • Tính mô đun: Nói chung, mã của bạn phải là mô-đun. Tuy nhiên, OOP phá mã thành nhiều phần theo cách rất đặc biệt. Kiểu mô-đun đó (tức là chia tập lệnh của bạn thành các lớp) có hợp lý với những gì bạn đang làm không?

Tôi muốn biết làm thế nào để "bắt đầu lại" và lập trình sạch sẽ cho các dự án nhỏ hơn, nhanh hơn này.

# 1: Làm quen với những gì ở ngoài kia:
Mặc dù bạn "chỉ" viết kịch bản (và bạn thực sự chỉ quan tâm đến thành phần khoa học), bạn nên dành chút thời gian để tìm hiểu về các khái niệm và mô hình lập trình khác nhau. Bằng cách đó, bạn có thể có một ý tưởng tốt hơn về những gì bạn nên / không nên sử dụng và khi nào. Điều đó có vẻ hơi nản chí. Và bạn vẫn có thể có câu hỏi, "Tôi bắt đầu từ đâu / tôi bắt đầu nhìn vào cái gì?" Tôi cố gắng giải thích một điểm khởi đầu tốt trong hai điểm tiếp theo.

# 2: Bắt đầu sửa những gì bạn biết là sai:
Cá nhân tôi sẽ bắt đầu với những điều mà tôi biết là sai. Nhận một số kiểm soát phiên bản và bắt đầu kỷ luật bản thân để trở nên tốt hơn với những tên biến đó (đó là một cuộc đấu tranh nghiêm trọng). Sửa chữa những gì bạn biết là sai có thể nghe rõ ràng. Tuy nhiên, theo kinh nghiệm của tôi, tôi đã thấy rằng việc sửa một thứ sẽ dẫn tôi đến một thứ khác, v.v. Trước khi tôi biết điều đó, tôi đã tiết lộ 10 điều khác nhau mà tôi đã làm sai và tìm ra cách khắc phục chúng hoặc cách thực hiện chúng một cách sạch sẽ.

# 3: Nhận đối tác lập trình:
Nếu "bắt đầu lại" đối với bạn không liên quan đến việc tham gia các lớp học chính thức, hãy xem xét hợp tác với nhà phát triển và yêu cầu họ xem lại mã của bạn. Ngay cả khi họ không hiểu phần khoa học về những gì bạn đang làm, họ có thể có thể cho bạn biết những gì bạn có thể đã làm để làm cho mã của bạn thanh lịch hơn.

# 4: Tìm kiếm các tập đoàn:
Tôi không biết bạn đang ở khu vực khoa học nào. Nhưng tùy thuộc vào những gì bạn làm trong thế giới khoa học, hãy thử tìm kiếm các tập đoàn, nhóm làm việc hoặc người tham gia hội nghị. Sau đó xem nếu có bất kỳ tiêu chuẩn mà họ đang làm việc. Điều đó có thể dẫn bạn đến một số tiêu chuẩn mã hóa. Ví dụ, tôi làm rất nhiều công việc không gian địa lý. Nhìn vào các tài liệu hội nghị và các nhóm làm việc đã đưa tôi đến Hiệp hội không gian địa lý mở . Một trong những điều họ làm là làm việc dựa trên các tiêu chuẩn để phát triển không gian địa lý.

Tôi hy vọng điều đó sẽ giúp!


Lưu ý bên lề: Tôi biết bạn chỉ sử dụng OOP làm ví dụ. Tôi không muốn bạn nghĩ rằng tôi bị mắc kẹt về cách xử lý viết mã bằng OOP. Nó chỉ dễ dàng hơn để viết một câu trả lời tiếp tục với ví dụ đó.


Tôi nghĩ # 3 là vấn đề quan trọng nhất - một lập trình viên có kinh nghiệm có thể nói với OP các khái niệm họ cần (# 1), cách tổ chức các tập lệnh theo cách tốt hơn và cách sử dụng kiểm soát phiên bản (# 2).
Doc Brown

16

Tôi khuyên bạn nên tuân thủ nguyên tắc Unix: Giữ nó đơn giản, ngu ngốc! (HÔN)

Hoặc, đặt một cách khác: Làm một việc tại một thời điểm, và làm điều đó tốt.

Điều đó nghĩa là gì? Vâng, trước hết, nó có nghĩa là chức năng của bạn nên ngắn. Bất kỳ chức năng nào không thể hiểu đầy đủ về mục đích, cách sử dụng và triển khai trong vòng vài giây chắc chắn là quá dài. Có khả năng làm một số việc cùng một lúc, mỗi việc nên là một chức năng của riêng họ. Vì vậy, chia nó.

Về các dòng mã, heuristic của tôi là 10 dòng là một chức năng tốt, và bất cứ điều gì ngoài 20 rất có thể là tào lao. Những người khác có heuristic khác. Phần quan trọng là giữ độ dài xuống đến mức bạn có thể thực sự nắm bắt ngay lập tức.

Làm thế nào để bạn phân chia một chức năng dài? Vâng, đầu tiên bạn tìm kiếm các mẫu mã lặp lại. Sau đó, bạn tính ra các mẫu mã này, đặt cho chúng một tên mô tả và xem mã của bạn thu nhỏ lại . Thực sự, tái cấu trúc tốt nhất là tái cấu trúc làm giảm kích thước mã.

Điều này đặc biệt đúng khi chức năng trong câu hỏi đã được lập trình với sao chép-dán. Bất cứ khi nào bạn thấy một mô hình lặp đi lặp lại như vậy, bạn ngay lập tức biết rằng điều này có thể sẽ được biến thành một chức năng của riêng nó. Đây là nguyên tắc Đừng lặp lại chính mình (DRY) . Bất cứ khi nào bạn đang nhấn copy-paste, bạn đang làm sai điều gì đó! Tạo một chức năng thay thế.

Giai thoại
tôi đã dành vài tháng để tái cấu trúc mã có chức năng khoảng 500 dòng mỗi dòng. Sau khi tôi hoàn thành, tổng số mã ngắn hơn khoảng một nghìn dòng; Tôi đã tạo ra đầu ra tiêu cực về các dòng mã. Tôi nợ công ty ( http://www.geekherocomic.com/2008/10/09/programmers-salary-policy/index.html ). Tuy nhiên, tôi tin chắc rằng đây là một trong những tác phẩm quý giá nhất tôi từng làm ...

Một số chức năng có thể dài bởi vì chúng đang thực hiện một số điều khác biệt lần lượt. Đây không phải là vi phạm DRY, nhưng chúng cũng có thể được chia. Kết quả thường là một hàm cấp cao gọi một hàm đầy đủ các hàm thực hiện các bước riêng lẻ của các hàm ban đầu. Điều này thường sẽ tăng kích thước mã, nhưng tên hàm được thêm vào làm việc kỳ diệu trong việc làm cho mã dễ đọc hơn. Bởi vì bây giờ bạn có một hàm cấp cao nhất với tất cả các bước của nó được đặt tên rõ ràng. Ngoài ra, sau khi phân tách, nó rõ ràng, bước nào hoạt động trên dữ liệu nào. (Đối số chức năng. Bạn không sử dụng biến toàn cục, phải không?)

Một heuristic tốt cho loại phân chia chức năng mặt cắt này là bất cứ khi nào bạn muốn viết một bình luận phần, hoặc khi bạn tìm thấy một bình luận phần trong mã của bạn. Đây rất có thể là một trong những điểm mà chức năng của bạn nên được phân chia. Nhận xét phần cũng có thể phục vụ để truyền cảm hứng cho một tên cho chức năng mới.

Các nguyên tắc KISS và DRY có thể đưa bạn đi một chặng đường dài. Bạn không cần phải bắt đầu với OOP, v.v. ngay lập tức, đôi khi bạn có thể đạt được sự đơn giản hóa tuyệt vời chỉ bằng cách áp dụng hai điều này. Tuy nhiên, về lâu dài sẽ biết về OOP và các mô hình khác vì chúng cung cấp cho bạn các công cụ bổ sung mà bạn có thể sử dụng để làm cho mã chương trình của bạn rõ ràng hơn.

Cuối cùng, ghi lại mọi hành động với một cam kết. Bạn tính một cái gì đó vào một chức năng mới, đó là một cam kết . Bạn hợp nhất hai chức năng thành một, bởi vì chúng thực sự làm cùng một thứ, đó là một cam kết . Nếu bạn đổi tên một biến, đó là một cam kết . Cam kết thường xuyên. Nếu một ngày trôi qua và bạn không cam kết, có khả năng bạn đã làm sai điều gì đó.


2
Điểm tuyệt vời về việc chia phương pháp dài. Một heuristic tốt khác liên quan đến đoạn đầu tiên sau giai thoại: nếu phương pháp của bạn có thể được chia thành các phần một cách hợp lý và bạn muốn viết một bình luận giải thích những gì từng phần, thì nó nên được chia ra tại các bình luận. Tin tốt, những bình luận đó có thể cung cấp cho bạn một ý tưởng tốt về những gì để gọi các phương pháp mới.
Jaquez

@Jaquez Ah, hoàn toàn quên mất cái đó. Cảm ơn vì đã nhắc tôi. Tôi đã cập nhật câu trả lời của mình để bao gồm điều này :-)
cmaster 7/07/18

1
Những điểm tuyệt vời, tôi muốn đơn giản hóa điều này để nói rằng "DRY" là yếu tố duy nhất quan trọng nhất. Xác định "lặp lại" và loại bỏ chúng là nền tảng của gần như tất cả các cấu trúc lập trình khác. Nói cách khác, tất cả các cấu trúc lập trình đều ở đó, ít nhất là một phần, để giúp bạn tạo mã DRY. Bắt đầu bằng cách nói "Không trùng lặp bao giờ" và sau đó thực hành xác định và loại bỏ nó. Hãy cởi mở với những gì có thể là một bản sao - ngay cả khi nó không phải là mã tương tự, nó có thể là chức năng sao chép ...
Bill K

11

Tôi đồng ý với những người khác rằng kiểm soát phiên bản sẽ giải quyết nhiều vấn đề của bạn ngay lập tức. Đặc biệt:

  • Không cần phải duy trì một danh sách những thay đổi đã được thực hiện hoặc có nhiều bản sao của tệp, v.v. vì đó là điều mà phiên bản kiểm soát quan tâm.
  • Không có thêm tệp bị mất do ghi đè, v.v. (miễn là bạn chỉ bám vào những điều cơ bản; ví dụ: tránh "viết lại lịch sử")
  • Không cần bình luận lỗi thời, mã chết, vv được giữ xung quanh "chỉ trong trường hợp"; một khi họ cam kết kiểm soát phiên bản, vui lòng nuke chúng. Điều này có thể cảm thấy rất tự do!

Tôi sẽ nói đừng lật đổ nó: chỉ cần sử dụng git. Bám sát các lệnh đơn giản (ví dụ: chỉ một masternhánh), có thể sử dụng GUI và bạn sẽ ổn. Là một phần thưởng, bạn có thể sử dụng gitlab, github, v.v để xuất bản và sao lưu miễn phí;)

Lý do tôi viết câu trả lời này là để giải quyết hai điều bạn có thể thử mà tôi chưa thấy đề cập ở trên. Đầu tiên là sử dụng các xác nhận như một sự thay thế nhẹ cho thử nghiệm đơn vị. Các kiểm tra đơn vị có xu hướng ngồi "bên ngoài" chức năng / mô-đun / bất cứ điều gì đang được kiểm tra: chúng thường gửi một số dữ liệu vào một chức năng, nhận lại kết quả, sau đó kiểm tra một số thuộc tính của kết quả đó. Đây thường là một ý tưởng tốt, nhưng có thể bất tiện (đặc biệt là mã "vứt đi") vì một số lý do:

  • Kiểm tra đơn vị cần quyết định dữ liệu nào họ sẽ cung cấp cho chức năng. Dữ liệu đó phải thực tế (nếu không có ít điểm kiểm tra nó), nó phải có định dạng chính xác, v.v.
  • Các bài kiểm tra đơn vị phải có "quyền truy cập" vào những điều họ muốn khẳng định. Cụ thể, kiểm tra đơn vị không thể kiểm tra bất kỳ dữ liệu trung gian nào bên trong hàm; chúng ta sẽ phải tách chức năng đó thành các phần nhỏ hơn, kiểm tra các phần đó và cắm chúng lại với nhau ở một nơi khác.
  • Các bài kiểm tra đơn vị cũng được coi là có liên quan đến chương trình. Ví dụ, các bộ kiểm tra có thể trở nên "cũ" nếu có những thay đổi lớn kể từ lần chạy cuối cùng và thậm chí có thể có một loạt các thử nghiệm cho mã thậm chí không được sử dụng nữa.

Các xác nhận không có những nhược điểm này, vì chúng được kiểm tra trong quá trình thực thi chương trình bình thường. Đặc biệt:

  • Vì chúng chạy như một phần của việc thực thi chương trình thông thường, chúng tôi có dữ liệu trong thế giới thực để chơi. Điều này không yêu cầu giám tuyển riêng và (theo định nghĩa) là thực tế và có định dạng chính xác.
  • Các xác nhận có thể được viết ở bất cứ đâu trong mã, vì vậy chúng tôi có thể đặt chúng ở bất cứ đâu chúng tôi có quyền truy cập vào dữ liệu mà chúng tôi muốn kiểm tra. Nếu chúng ta muốn kiểm tra một số giá trị trung gian trong một hàm, chúng ta có thể đặt một số xác nhận vào giữa hàm đó!
  • Vì chúng được viết thẳng hàng, các xác nhận không thể "không đồng bộ" với cấu trúc của mã. Nếu chúng tôi đảm bảo rằng các xác nhận được kiểm tra theo mặc định, chúng tôi cũng không cần phải lo lắng về việc chúng sẽ bị "cũ" vì chúng tôi sẽ thấy ngay lập tức liệu chúng có vượt qua lần tiếp theo khi chúng tôi chạy chương trình hay không!

Bạn đề cập đến tốc độ như là một yếu tố, trong trường hợp đó, việc kiểm tra xác nhận có thể là không mong muốn trong vòng lặp đó (nhưng vẫn hữu ích để kiểm tra thiết lập và xử lý tiếp theo). Tuy nhiên, gần như tất cả các triển khai xác nhận cung cấp một cách để tắt chúng; ví dụ trong Python rõ ràng họ có thể bị vô hiệu hóa bằng cách chạy với -Otùy chọn (Tôi không biết điều này, vì tôi chưa bao giờ cảm thấy cần phải vô hiệu hóa bất kỳ xác nhận nào của mình trước đây). Tôi khuyên bạn nên để chúng trêntheo mặc định; nếu chu trình mã hóa / gỡ lỗi / kiểm tra của bạn chậm lại, bạn có thể kiểm tra tốt hơn với một tập hợp con dữ liệu nhỏ hơn hoặc thực hiện ít lần lặp hơn một số mô phỏng trong quá trình kiểm tra hoặc bất cứ điều gì. Nếu cuối cùng bạn vô hiệu hóa các xác nhận trong các lần chạy thử nghiệm vì lý do hiệu suất, điều đầu tiên tôi khuyên bạn nên làm là đo lường xem chúng có thực sự là nguồn gốc của sự chậm lại không! (Rất dễ để ảo tưởng bản thân khi gặp phải các tắc nghẽn về hiệu suất)

Lời khuyên cuối cùng của tôi là sử dụng một hệ thống xây dựng để quản lý các phụ thuộc của bạn. Cá nhân tôi sử dụng Nix cho việc này, nhưng cũng đã nghe thấy những điều hay về Guix . Cũng có những lựa chọn thay thế như Docker, ít hữu ích hơn từ góc độ khoa học nhưng có lẽ quen thuộc hơn một chút.

Các hệ thống như Nix chỉ mới trở nên phổ biến (một chút) và một số người có thể coi chúng là quá mức cần thiết cho mã "vứt đi" như bạn mô tả, nhưng lợi ích của chúng đối với khả năng tái tạo của máy tính khoa học là rất lớn. Hãy xem xét một tập lệnh shell để chạy thử nghiệm, như thế này (ví dụ run.sh):

#!/usr/bin/env bash
set -e
make all
./analyse < ./dataset > output.csv

Thay vào đó, chúng ta có thể viết lại thành "đạo hàm" Nix, như thế này (ví dụ run.nix):

with import <nixpkgs> {};
runCommand "output.csv" {} ''
  cp -a ${./.} src
  cd src
  make all
  ./analyse < ./dataset > $out
''

Nội dung giữa ''...''là mã bash, giống như chúng ta đã có trước đây, ngoại trừ ${...}có thể được sử dụng để "ghép" trong nội dung của các chuỗi khác (trong trường hợp này ./., sẽ mở rộng sang đường dẫn của thư mục chứa run.nix). Các with import ...dòng nhập khẩu Nix của thư viện chuẩn , cung cấp runCommandcho chạy mã bash. Chúng ta có thể chạy thử nghiệm bằng cách sử dụng nix-build run.nix, sẽ cho ra một đường dẫn như thế nào /nix/store/1wv437qdjg6j171gjanj5fvg5kxc828p-output.csv.

Vì vậy, những gì này mua chúng tôi? Nix sẽ tự động thiết lập môi trường "sạch", nơi chỉ có quyền truy cập vào những thứ mà chúng tôi yêu cầu rõ ràng. Cụ thể, nó không có quyền truy cập vào các biến như $HOMEhoặc bất kỳ phần mềm hệ thống nào mà chúng tôi đã cài đặt. Điều này làm cho kết quả không phụ thuộc vào chi tiết của máy hiện tại của chúng tôi, như nội dung ~/.confighoặc các phiên bản chương trình chúng tôi đã cài đặt; AKA thứ ngăn người khác sao chép kết quả của chúng tôi! Đây là lý do tại sao tôi thêm rằngcplệnh, vì dự án sẽ không thể truy cập theo mặc định. Có vẻ khó chịu khi phần mềm của hệ thống không có sẵn cho tập lệnh Nix, nhưng nó cũng đi theo một cách khác: chúng tôi không cần bất cứ thứ gì được cài đặt trên hệ thống của chúng tôi (ngoài Nix) để sử dụng tập lệnh đó trong tập lệnh; chúng tôi chỉ yêu cầu và Nix sẽ tắt và tìm nạp / biên dịch / bất cứ điều gì cần thiết (hầu hết mọi thứ sẽ được tải xuống dưới dạng nhị phân; thư viện chuẩn cũng rất lớn!). Ví dụ: nếu chúng tôi muốn có một loạt các gói Python và Haskell cụ thể, đối với một số phiên bản cụ thể của các ngôn ngữ đó, cộng với một số rác khác (vì tại sao không?):

with import <nixpkgs> {};
runCommand "output.csv"
  {
    buildInputs = [
      gcc49 libjson zlib
      haskell.packages.ghc802.pandoc
      (python34.withPackages (pyPkgs: [
        pyPkgs.beautifulsoup4 pyPkgs.numpy pyPkgs.scipy
        pyPkgs.tensorflowWithoutCuda
      ]))
    ];
  }
  ''
    cp -a ${./.} src
    cd src
    make all
    ./analyse < ./dataset > $out
  ''

Điều tương tự nix-build run.nixsẽ chạy cái này, tìm nạp mọi thứ chúng tôi yêu cầu trước tiên (và lưu trữ tất cả trong trường hợp chúng tôi muốn sau). Đầu ra (bất kỳ tệp / thư mục nào được gọi $out) sẽ được lưu trữ bởi Nix, đây là đường dẫn mà nó phun ra. Nó được xác định bởi hàm băm mật mã của tất cả các đầu vào mà chúng tôi yêu cầu (nội dung tập lệnh, các gói khác, tên, cờ trình biên dịch, v.v.); các gói khác được xác định bằng cách băm các đầu vào của chúng , và do đó chúng ta có một chuỗi chứng minh đầy đủ cho tất cả mọi thứ, ngay từ phiên bản GCC đã biên dịch phiên bản GCC đã biên dịch bash, v.v.

Hy vọng rằng tôi đã chứng minh rằng điều này mua cho chúng tôi rất nhiều về mã khoa học và khá dễ dàng để bắt đầu. Nó cũng bắt đầu để có được thực hiện rất nghiêm túc bởi các nhà khoa học, ví dụ như (top Google nhấn) https://dl.acm.org/citation.cfm?id=2830172 như vậy có thể là một kỹ năng quý báu để trau dồi (giống như lập trình)


2
Câu trả lời rất chi tiết hữu ích - Tôi thực sự thích các câu trả lời khác, nhưng các xác nhận nghe có vẻ như là bước đầu tiên rất hữu ích.
thạch

9

Không đi đến kiểm soát phiên bản đầy đủ + đóng gói + kiểm tra đơn vị loại tư duy (đó là những thực tiễn lập trình tốt mà bạn nên cố gắng đạt được vào một lúc nào đó), một giải pháp trung gian mà tôi nghĩ sẽ phù hợp là sử dụng Jupiter Notebook . Điều này dường như tích hợp tốt hơn với tính toán khoa học.

Nó có lợi thế là bạn có thể trộn suy nghĩ của mình với mã; giải thích lý do tại sao một cách tiếp cận tốt hơn cách tiếp cận khác và để lại mã cũ như trong một phần đặc biệt. Bên cạnh việc sử dụng các ô đúng cách sẽ tự nhiên dẫn bạn phân đoạn mã của bạn và sắp xếp nó thành các hàm có thể giúp hiểu biết về nó.


1
Thêm vào đó, điều này thực sự có ích với khả năng tái tạo - bạn có thể chạy chính xác cùng một mã để tạo ra một số liệu xuất bản, hoặc quay trở lại một cái gì đó mà bạn đã bỏ đi vài tháng trước có lẽ để kết hợp các nhận xét của người đánh giá.
afaulconbridge

Đối với ai đó muốn đọc thêm, điều này còn được gọi là lập trình biết chữ.
llrs

6

Các câu trả lời hàng đầu đã tốt, nhưng tôi muốn trực tiếp giải quyết một số câu hỏi của bạn.

Là thử nghiệm đơn vị cần thiết để viết các đoạn mã nhỏ hơn?

Kích thước của mã không liên quan trực tiếp đến nhu cầu kiểm tra đơn vị. Nó có liên quan gián tiếp: các bài kiểm tra đơn vị có giá trị hơn trong các cơ sở mã phức tạp và các cơ sở mã nhỏ thường không phức tạp như các bài kiểm tra lớn hơn.

Các thử nghiệm đơn vị tỏa sáng cho mã nơi dễ mắc lỗi hoặc khi bạn sẽ có nhiều triển khai mã này. Các bài kiểm tra đơn vị làm rất ít để giúp bạn phát triển hiện tại , nhưng chúng làm rất nhiều để ngăn bạn mắc lỗi trong tương lai khiến mã hiện tại đột nhiên hoạt động sai (mặc dù bạn không chạm vào thứ đó).

Giả sử bạn có một ứng dụng trong đó Thư viện A thực hiện bình phương số và Thư viện B áp dụng định lý Pythagore. Rõ ràng, B phụ thuộc vào A. Bạn cần sửa một cái gì đó trong thư viện A, và giả sử bạn giới thiệu một lỗi làm khối số thay vì bình phương chúng.

Thư viện B sẽ đột nhiên bắt đầu hoạt động sai, có thể ném ngoại lệ hoặc đơn giản là đưa ra kết quả sai. Và khi bạn nhìn vào lịch sử phiên bản của thư viện B, bạn sẽ thấy rằng nó không bị ảnh hưởng. Kết quả cuối cùng có vấn đề là bạn không có dấu hiệu cho thấy điều gì có thể xảy ra và bạn sẽ phải gỡ lỗi hành vi của B trước khi bạn nhận ra vấn đề nằm ở A. Điều đó thật lãng phí nỗ lực.

Nhập bài kiểm tra đơn vị. Các xét nghiệm này xác nhận rằng thư viện A đang hoạt động như dự định. Nếu bạn giới thiệu một lỗi trong thư viện A khiến nó trả về kết quả xấu, thì các bài kiểm tra đơn vị của bạn sẽ nắm bắt được điều đó. Do đó, bạn sẽ không bị mắc kẹt khi cố gắng gỡ lỗi thư viện B.
Điều này nằm ngoài phạm vi của bạn, nhưng trong quá trình phát triển tích hợp liên tục, các kiểm tra đơn vị được thực hiện bất cứ khi nào ai đó thực hiện một số mã, có nghĩa là bạn sẽ biết bạn đã phá vỡ điều gì đó càng sớm càng tốt.

Đặc biệt đối với các phép toán phức tạp, các bài kiểm tra đơn vị có thể là một phước lành. Bạn thực hiện một vài tính toán mẫu, sau đó bạn viết các bài kiểm tra đơn vị so sánh đầu ra được tính toán và đầu ra thực tế của bạn (dựa trên cùng các tham số đầu vào).

Tuy nhiên, lưu ý rằng các bài kiểm tra đơn vị sẽ không giúp bạn tạo mã tốt, mà là duy trì nó. Nếu bạn thường viết mã một lần và không bao giờ xem lại nó, các bài kiểm tra đơn vị sẽ ít có lợi hơn.

Làm thế nào về OOP?

OOP là một cách nghĩ về các thực thể riêng biệt, ví dụ:

Khi một người Customermuốn mua một Product, anh ta nói chuyện với Vendorđể nhận được một Order. Sau Accountantđó sẽ trả Vendor.

So sánh điều này với cách một lập trình viên chức năng nghĩ về mọi thứ:

Khi một khách hàng muốn purchaseProduct(), anh ấy talktoVendor()sẽ sendOrder()cho anh ấy. Các acccountant sau đó sẽ payVendor().

Táo và cam. Không ai trong số họ là khách quan tốt hơn so với người khác. Một điều thú vị cần lưu ý là đối với OOP, Vendorđược đề cập hai lần nhưng nó đề cập đến cùng một điều. Tuy nhiên, đối với lập trình chức năng, talktoVendor()payVendor()là hai điều riêng biệt.
Điều này cho thấy sự khác biệt giữa các phương pháp. Nếu có nhiều logic cụ thể của nhà cung cấp được chia sẻ giữa hai hành động này, thì OOP giúp giảm trùng lặp mã. Tuy nhiên, nếu không có logic chia sẻ giữa hai người, thì việc hợp nhất chúng thành một là một Vendorcông việc vô ích (và do đó lập trình giả tưởng hiệu quả hơn).

Thường xuyên hơn không, các phép tính toán học và khoa học là các hoạt động riêng biệt không dựa trên logic / công thức ngầm được chia sẻ. Do đó, lập trình chức năng thường được sử dụng hơn OOP.

Những cách tiếp cận nào là tốt để viết mã tốt, sạch nhanh khi thực hiện "lập trình khoa học" thay vì làm việc trên các dự án lớn hơn?

Câu hỏi của bạn ngụ ý rằng định nghĩa "mã tốt, sạch" thay đổi cho dù bạn đang lập trình khoa học hay làm việc trên các dự án lớn hơn (tôi cho rằng bạn có nghĩa là doanh nghiệp).

Định nghĩa của mã tốt không thay đổi. Tuy nhiên, cần phải tránh sự phức tạp (có thể được thực hiện bằng cách viết mã sạch), tuy nhiên, sẽ thay đổi.

Lập luận tương tự trở lại đây.

  • Nếu bạn không bao giờ xem lại mã cũ và hiểu đầy đủ logic mà không cần phải thu gọn nó, thì đừng bỏ ra quá nhiều nỗ lực để làm cho mọi thứ có thể duy trì được.
  • Nếu bạn xem lại mã cũ hoặc logic yêu cầu quá phức tạp để bạn có thể giải quyết tất cả cùng một lúc (do đó yêu cầu bạn phải ngăn cách các giải pháp), sau đó tập trung vào viết sạch, có thể tái sử dụng.

Tôi hỏi những câu hỏi này bởi vì thông thường, bản thân chương trình không quá phức tạp. Đó là nhiều hơn về toán học hoặc khoa học mà tôi đang thử nghiệm hoặc nghiên cứu với chương trình.

Tôi nhận ra sự khác biệt mà bạn đang thực hiện ở đây, nhưng khi bạn nhìn lại mã hiện có, bạn đang xem xét cả toán học và lập trình. Nếu một trong hai là phức tạp hoặc phức tạp, thì bạn sẽ phải vật lộn để đọc nó.

Ví dụ, một lớp cần thiết khi hai biến và hàm có thể có thể chăm sóc nó?

Bỏ qua các nguyên tắc OOP, lý do chính khiến tôi viết các lớp để chứa một vài giá trị dữ liệu là vì nó đơn giản hóa việc khai báo các tham số phương thức và trả về giá trị. Ví dụ: nếu tôi có nhiều phương thức sử dụng vị trí (cặp lat / lon), thì tôi sẽ nhanh chóng mệt mỏi vì phải gõ float latitude, float longitudevà sẽ thích viết hơn Location loc.

Điều này còn phức tạp hơn nữa khi bạn cho rằng các phương thức thường trả về một giá trị (trừ khi các tính năng cụ thể của ngôn ngữ tồn tại để trả về nhiều giá trị hơn) và những thứ như vị trí sẽ muốn bạn trả về hai giá trị (lat + lon). Điều này khuyến khích bạn tạo một Locationlớp để đơn giản hóa mã của bạn.

Ví dụ, một lớp cần thiết khi hai biến và hàm có thể có thể chăm sóc nó?

Một điều thú vị khác cần lưu ý là bạn có thể sử dụng OOP mà không cần trộn các giá trị và phương thức dữ liệu. Không phải mọi nhà phát triển đều đồng ý ở đây (một số người gọi nó là antipotype), nhưng bạn có thể có các mô hình dữ liệu thiếu máu nơi bạn có các lớp dữ liệu riêng biệt (lưu trữ các trường giá trị) và các lớp logic (lưu trữ các phương thức).
Tất nhiên, đây là trên một quang phổ. Bạn không cần phải thiếu máu hoàn toàn, bạn có thể sử dụng nó khi bạn thấy nó phù hợp.

Ví dụ, một phương thức chỉ đơn giản ghép tên và họ của một người vẫn có thể được đặt trong Personchính lớp đó, vì nó không thực sự là "logic" mà là một giá trị được tính toán.

(Hãy xem xét những điều này cũng thường là các tình huống trong đó tốc độ của chương trình được ưu tiên ở mức nhanh hơn - khi bạn đang chạy 25.000.000+ bước thời gian của một mô phỏng, bạn có thể muốn nó diễn ra.)

Một lớp luôn lớn bằng tổng các trường của nó. Lấy ví dụ về Locationmột lần nữa, bao gồm hai floatgiá trị, điều quan trọng cần lưu ý ở đây là một Locationđối tượng sẽ chiếm nhiều bộ nhớ như hai floatgiá trị riêng biệt .

Theo nghĩa đó, không quan trọng bạn có sử dụng OOP hay không. Dấu chân bộ nhớ là như nhau.

Hiệu suất bản thân nó cũng không phải là một trở ngại lớn để vượt qua. Sự khác biệt giữa ví dụ: sử dụng một phương thức toàn cục hoặc một phương thức lớp không liên quan gì đến hiệu năng thời gian chạy, nhưng có mọi thứ để làm với việc tạo mã byte theo thời gian biên dịch.

Hãy nghĩ về nó theo cách này: cho dù tôi viết công thức bánh của mình bằng tiếng Anh hay tiếng Tây Ban Nha sẽ không thay đổi thực tế là chiếc bánh sẽ mất 30 phút để nướng (= hiệu suất thời gian chạy). Điều duy nhất mà ngôn ngữ của công thức thay đổi là cách người đầu bếp trộn các thành phần (= biên dịch mã byte).

Đối với Python cụ thể, bạn không cần phải biên dịch trước mã một cách rõ ràng trước khi gọi nó. Tuy nhiên, khi bạn không biên dịch trước, quá trình biên dịch sẽ xảy ra khi cố gắng thực thi mã. Khi tôi nói "thời gian chạy", ý tôi là chính việc thực thi, không phải là quá trình biên dịch có thể đi trước việc thực hiện.


6

Lợi ích của mã khoa học sạch

  • ... Nhìn vào sách lập trình, chúng dường như thường được giải quyết tại các dự án lớn hơn.

  • ... Có thực sự có ý nghĩa khi viết mã có nghĩa là OOP khi một số nội dung tiêu chuẩn có thể được thực hiện, sẽ nhanh hơn nhiều để viết và có thể dễ đọc hơn vì độ ngắn của chương trình không?

Có thể hữu ích để xem xét mã của bạn từ quan điểm của một lập trình viên tương lai.

  • Tại sao họ mở tập tin này?
  • Những gì họ đang tìm kiếm?

Từ kinh nghiệm của tôi,

Mã sạch sẽ giúp dễ dàng xác minh kết quả của bạn

  • Giúp người dùng dễ dàng biết chính xác những gì họ cần làm để chạy chương trình của bạn.
  • Bạn có thể muốn phân chia chương trình của mình để các thuật toán riêng lẻ có thể được điểm chuẩn riêng.

  • Tránh viết các chức năng với các tác dụng phụ phản trực giác trong đó một hoạt động không liên quan làm cho một hoạt động khác hoạt động khác đi. Nếu bạn không thể tránh nó, hãy ghi lại những gì mã của bạn cần và cách thiết lập nó.

Mã sạch có thể dùng làm mã ví dụ cho các lập trình viên tương lai

Xóa các bình luận (bao gồm cả các bình luận cho thấy các hàm nên được gọi như thế nào) và các hàm được phân tách tốt có thể tạo ra sự khác biệt lớn trong thời gian một người nào đó mới bắt đầu (hoặc tương lai bạn) để tạo ra thứ gì đó hữu ích cho công việc của bạn.

Ngoài ra, việc tạo một "API" thực sự cho thuật toán của bạn có thể giúp bạn chuẩn bị tốt hơn nếu bạn quyết định biến các tập lệnh của mình thành một thư viện thực sự để người khác sử dụng.

khuyến nghị

"Trích dẫn" công thức toán học bằng cách sử dụng các ý kiến.

  • Thêm nhận xét vào "trích dẫn" các công thức toán học, đặc biệt nếu bạn đã sử dụng tối ưu hóa (danh tính trig, chuỗi Taylor, v.v.).
  • Nếu bạn có công thức từ cuốn sách, hãy thêm một nhận xét John Smith Method from Some Book 1st Ed. Section 1.2.3 Pg 180, nếu bạn tìm thấy công thức trên một trang web hoặc trong một tờ giấy, hãy trích dẫn điều đó.
  • Tôi khuyên bạn nên tránh các bình luận "chỉ liên kết", đảm bảo bạn tham khảo phương pháp theo tên ở đâu đó để cho phép mọi người google nó, tôi đã chạy vào một số bình luận "chỉ liên kết" được chuyển hướng đến các trang nội bộ cũ và họ có thể rất bực bội .
  • Bạn có thể cố gắng nhập công thức trong nhận xét của mình nếu vẫn dễ đọc bằng Unicode / ASCII, nhưng điều này có thể rất khó xử (nhận xét mã không phải là LaTeX).

Sử dụng bình luận một cách khôn ngoan

Nếu bạn có thể cải thiện khả năng đọc mã của mình bằng cách sử dụng tên biến / tên hàm tốt, trước tiên hãy làm điều đó. Hãy nhớ rằng các bình luận sẽ tồn tại mãi mãi cho đến khi bạn xóa chúng, vì vậy hãy cố gắng đưa ra những bình luận không lỗi thời.

Sử dụng tên biến mô tả

  • Các biến đơn có thể là lựa chọn tốt nhất nếu chúng là một phần của công thức.
  • Nó có thể rất quan trọng cho người đọc trong tương lai để có thể nhìn vào mã bạn đã viết và so sánh nó với phương trình bạn đang thực hiện.
  • Khi thích hợp, hãy xem xét thêm một hậu tố cho nó để mô tả ý nghĩa thực sự của nó, ví dụ ,. xBar_AverageVelocity
  • Như đã đề cập trước đây, tôi khuyên bạn nên chỉ rõ công thức / phương pháp bạn đang sử dụng theo tên trong một nhận xét ở đâu đó.

Viết mã để chạy chương trình của bạn chống lại dữ liệu xấu đã biết và đã biết.

Là thử nghiệm đơn vị cần thiết để viết các đoạn mã nhỏ hơn?

Tôi nghĩ thử nghiệm đơn vị có thể hữu ích, tôi nghĩ hình thức thử nghiệm đơn vị tốt nhất cho mã khoa học là một loạt các thử nghiệm chạy trên dữ liệu xấu và tốt đã biết.

Viết một số mã để chạy thuật toán của bạn và kiểm tra xem kết quả khác bao xa so với những gì bạn mong đợi. Điều này sẽ giúp bạn tìm ra các vấn đề (có khả năng rất xấu và khó tìm) khi bạn vô tình mã cứng thứ gì đó gây ra kết quả dương tính giả hoặc mắc lỗi khiến hàm luôn trả về cùng giá trị.

Lưu ý rằng điều này có thể được thực hiện ở bất kỳ mức độ trừu tượng nào. Ví dụ: bạn có thể kiểm tra toàn bộ thuật toán khớp mẫu hoặc bạn có thể kiểm tra một hàm chỉ tính khoảng cách giữa hai kết quả trong quá trình tối ưu hóa của bạn. Bắt đầu với các lĩnh vực quan trọng nhất đối với kết quả của bạn trước tiên và / hoặc các phần của mã mà bạn quan tâm nhất.

Giúp dễ dàng thêm các trường hợp thử nghiệm mới, xem xét thêm các chức năng "trợ giúp" và cấu trúc dữ liệu đầu vào của bạn một cách hiệu quả. Điều này có thể có nghĩa là có thể lưu dữ liệu đầu vào vào tệp để bạn có thể dễ dàng chạy lại các bài kiểm tra, tuy nhiên hãy cẩn thận để tránh các kết quả dương tính giả hoặc các trường hợp kiểm tra sai lệch / giải quyết tầm thường.

Xem xét sử dụng một cái gì đó như xác nhận chéo , xem bài đăng này trên xác thực chéo để biết thêm thông tin.

Sử dụng kiểm soát phiên bản

Tôi sẽ khuyên bạn nên sử dụng kiểm soát phiên bản và lưu trữ kho lưu trữ của bạn trên một trang web bên ngoài. Có những trang web sẽ lưu trữ miễn phí.

Ưu điểm:

  1. Nó cung cấp một bản sao lưu trong trường hợp đĩa cứng của bạn bị lỗi
  2. Nó cung cấp một lịch sử, khiến bạn không phải lo lắng nếu một vấn đề gần đây xảy ra là do bạn vô tình thay đổi một tập tin, trong số những lợi ích khác.
  3. Nó cho phép bạn sử dụng phân nhánh, đây là một cách tốt để làm việc trên mã thử nghiệm / dài hạn mà không ảnh hưởng đến công việc không liên quan.

Hãy thận trọng khi sao chép / dán mã

Phong cách mã của tôi là phức tạp và chứa đầy các bình luận lỗi thời lưu ý các cách khác để làm một cái gì đó hoặc với các dòng mã được sao chép qua.

  • Sao chép / dán mã có thể giúp bạn tiết kiệm thời gian, nhưng đó là một trong những điều nguy hiểm nhất bạn có thể làm, đặc biệt là nếu đó là mã bạn không tự viết (ví dụ: nếu đó là mã từ đồng nghiệp).

  • Ngay sau khi bạn làm cho mã hoạt động và được kiểm tra, tôi khuyên bạn nên xem xét kỹ nó để đổi tên bất kỳ biến hoặc nhận xét bất cứ điều gì bạn không hiểu.



6

Các công cụ của thương mại thường được phát minh để giải quyết nhu cầu. Nếu bạn có nhu cầu sử dụng công cụ, nếu không, rất có thể bạn không phải làm vậy.

Cụ thể, các chương trình khoa học không phải là mục tiêu cuối cùng, chúng là phương tiện. Bạn viết chương trình để giải quyết vấn đề hiện tại - bạn không hy vọng chương trình đó sẽ được người khác sử dụng (và phải được duy trì) trong mười năm. Điều đó một mình có nghĩa là bạn không phải suy nghĩ về bất kỳ công cụ nào cho phép nhà phát triển hiện tại ghi lại lịch sử cho những người khác như kiểm soát phiên bản hoặc nắm bắt chức năng trong mã như kiểm tra đơn vị.

Điều gì sẽ có lợi cho bạn sau đó?

  • kiểm soát phiên bản là tốt vì nó cho phép bạn rất dễ dàng sao lưu công việc của bạn. Kể từ năm 2018, github là một nơi rất phổ biến để làm như vậy (và bạn luôn có thể di chuyển nó sau này nếu cần - git rất linh hoạt). Một thay thế rẻ tiền và đơn giản để sao lưu là các quy trình sao lưu tự động trong hệ điều hành của bạn (Time Machine cho Mac, rsync cho Linux, v.v.). Mã của bạn cần phải ở nhiều nơi!
  • Kiểm thử đơn vị là tốt vì nếu bạn viết chúng trước tiên, bạn buộc phải suy nghĩ về cách kiểm tra mã thực sự làm gì, điều này giúp bạn thiết kế API hữu ích hơn cho mã của mình. Điều này rất hữu ích nếu bạn từng viết mã để được sử dụng lại sau này và giúp bạn trong khi thay đổi thuật toán vì bạn biết nó hoạt động trong những trường hợp này.
  • Tài liệu. Tìm hiểu cách viết tài liệu phù hợp bằng ngôn ngữ lập trình bạn sử dụng (ví dụ javadoc cho Java). Viết cho tương lai bạn. Trong quá trình này, bạn sẽ thấy rằng các tên biến tốt giúp việc ghi chép tài liệu dễ dàng hơn. Lặp đi lặp lại. Cung cấp cùng một lượng chăm sóc cho tài liệu của bạn như một nhà thơ làm cho các bài thơ.
  • Sử dụng các công cụ tốt. Tìm một IDE giúp bạn và học nó tốt. Tái cấu trúc như đổi tên các biến thành một tên tốt hơn theo cách này dễ dàng hơn nhiều.
  • Nếu bạn có đồng nghiệp xem xét sử dụng đánh giá ngang hàng. Có một cái nhìn bên ngoài và hiểu mã của bạn, là phiên bản hiện tại của tương lai bạn viết cho. Nếu đồng nghiệp của bạn không hiểu mã của bạn, bạn có thể sẽ không gặp lại sau này.

Làm thế nào có câu trả lời này không nhận được một upvote? Nó có ngay bây giờ. Nhóm của chúng tôi đã tìm thấy đánh giá ngang hàng là một trong những công cụ hiệu quả nhất, quan trọng hơn nhiều so với các bài kiểm tra đơn vị khi nói đến mã khoa học. Thật dễ dàng để gây ra lỗi khi dịch một bộ phương trình phức tạp trong một bài báo tạp chí khoa học sang mã. Các nhà khoa học và kỹ sư đôi khi làm cho các lập trình viên cực kỳ nghèo; đánh giá ngang hàng có thể bắt gặp những điểm xấu về kiến ​​trúc làm cho mã khó duy trì / hiểu / sử dụng.
David Hammen

5

Ngoài những lời khuyên tốt đã có ở đây, bạn có thể muốn xem xét mục đích lập trình của mình và do đó, điều gì là quan trọng đối với bạn.

"Đó là nhiều hơn về toán học hoặc khoa học mà tôi đang thử nghiệm hoặc nghiên cứu với chương trình."

Nếu mục đích là để thử nghiệm và kiểm tra một cái gì đó theo sự hiểu biết của riêng bạn và bạn biết kết quả sẽ như thế nào thì mã của bạn về cơ bản là nhanh chóng và cách tiếp cận hiện tại của bạn có thể đủ, mặc dù có thể được cải thiện. Nếu kết quả không như mong đợi, bạn có thể quay lại và xem xét.

Tuy nhiên, nếu kết quả mã hóa của bạn đang thông báo hướng nghiên cứu của bạn và bạn không biết kết quả sẽ như thế nào, thì tính chính xác trở nên đặc biệt quan trọng. Một lỗi trong mã của bạn có thể khiến bạn rút ra kết luận sai từ thí nghiệm của mình với nhiều hàm ý xấu cho nghiên cứu tổng thể của bạn.

Trong trường hợp đó, việc phá mã của bạn thành các chức năng dễ hiểu và có thể kiểm chứng bằng các bài kiểm tra đơn vị sẽ giúp bạn xây dựng các khối gạch vững chắc hơn giúp bạn tự tin hơn về kết quả của mình và có thể giúp bạn tránh khỏi nhiều thất vọng về sau.


5

Tuyệt vời như kiểm soát phiên bản và kiểm tra đơn vị là để giữ cho mã tổng thể của bạn được tổ chức và hoạt động, không thực sự giúp bạn viết mã sạch hơn.

  • Kiểm soát phiên bản sẽ cho phép bạn xem cách thức và thời điểm mã trở nên lộn xộn như vậy.
  • Các thử nghiệm đơn vị sẽ đảm bảo rằng, mặc dù mã là một mớ hỗn độn hoàn toàn, nó vẫn hoạt động.

Nếu bạn muốn ngăn mình viết mã lộn xộn, bạn cần một công cụ hoạt động ở nơi xảy ra sự lộn xộn: khi bạn viết mã. Một loại công cụ phổ biến được gọi là kẻ nói dối. Tôi không phải là nhà phát triển python, nhưng có vẻ như Pylint có thể là một lựa chọn tốt.

Một kẻ nói dối nhìn vào mã bạn đã viết và so sánh nó với một tập hợp thực tiễn tốt nhất có thể định cấu hình. Nếu kẻ nói dối có một quy tắc là các biến phải là camelCase, và bạn viết một biến vào snake_case, nó sẽ đánh dấu đó là một lỗi. Linters tốt có các quy tắc từ "biến được khai báo phải được sử dụng" đến "Độ phức tạp theo chu kỳ của các hàm phải nhỏ hơn 3".

Hầu hết các trình soạn thảo mã có thể được cấu hình để chạy một kẻ nói dối mỗi khi bạn lưu hoặc chỉ nói chung khi bạn nhập và chỉ ra các vấn đề nội tuyến. Nếu bạn nhập một cái gì đó như x = 7, xsẽ được tô sáng, với một hướng dẫn sử dụng tên dài hơn, tốt hơn (nếu đó là những gì bạn đã cấu hình). Điều này hoạt động như kiểm tra chính tả trong hầu hết các trình xử lý văn bản, làm cho nó khó bỏ qua và giúp xây dựng các thói quen tốt hơn.


Điều này nên có nhiều upvote hơn. +1
thạch vào

2
Nhưng, vì lợi ích của thiên đường, hãy chắc chắn rằng bạn biết cách định cấu hình kẻ nói dối theo phong cách mà bạn thích, nếu không nó sẽ khiến bạn phát điên với sự ồn ào của nó.
DrMcCleod

4

Tất cả mọi thứ bạn liệt kê là một công cụ trong hộp công cụ ẩn dụ. Giống như bất cứ điều gì trong cuộc sống, các công cụ khác nhau phù hợp cho các nhiệm vụ khác nhau.

So với các lĩnh vực kỹ thuật khác, phần mềm hoạt động với một loạt các phần riêng lẻ, khá đơn giản. Một tuyên bố chuyển nhượng không đánh giá khác nhau tùy thuộc vào biến động nhiệt độ của phòng. Một iftuyên bố không ăn mòn tại chỗ và tiếp tục trả lại điều tương tự sau một lúc. Nhưng vì các yếu tố riêng lẻ rất đơn giản và phần mềm do con người tạo ra, các yếu tố đó được kết hợp thành các phần lớn hơn và lớn hơn cho đến khi kết quả trở nên quá lớn và phức tạp, nó đạt đến giới hạn của những gì mọi người có thể quản lý về mặt tinh thần.

Khi các dự án phần mềm đã phát triển và lớn mạnh, mọi người đã nghiên cứu chúng và tạo ra các công cụ để cố gắng quản lý sự phức tạp đó. OOP là một ví dụ. Ngày càng nhiều ngôn ngữ lập trình trừu tượng là một phương tiện khác. Bởi vì phần lớn số tiền trong phần mềm đang làm nhiều hơn thế , các công cụ để đạt được đó là những gì bạn sẽ thấy và đọc về. Nhưng có vẻ như những tình huống đó không áp dụng cho bạn.

Vì vậy, đừng cảm thấy như bạn cần phải làm bất cứ điều gì trong số đó. Vào cuối ngày, mã chỉ là một phương tiện để kết thúc. Thật không may, những gì tốt nhất sẽ cung cấp cho bạn quan điểm đúng đắn về những gì và những gì không phù hợp là làm việc trên một số dự án lớn hơn, vì rất khó để biết những gì còn thiếu khi hộp công cụ là tâm trí của bạn.

Trong mọi trường hợp, tôi sẽ không lo lắng về việc không sử dụng OOP hoặc các kỹ thuật khác miễn là tập lệnh của bạn nhỏ. Nhiều vấn đề bạn mô tả chỉ là các kỹ năng tổ chức chuyên nghiệp nói chung, tức là không mất tập tin cũ là điều mà tất cả các lĩnh vực phải giải quyết.


4

Ngoài tất cả các đề xuất tốt được cung cấp cho đến nay, một thực tế tôi đã học theo thời gian và thấy cần thiết là rất tự do thêm bình luận chi tiết vào mã của bạn. Đó là điều quan trọng nhất đối với tôi khi tôi trở lại một thứ gì đó sau một khoảng thời gian dài. Giải thích cho bản thân bạn đang nghĩ gì. Phải mất một ít thời gian để làm nhưng nó tương đối dễ dàng và chủ yếu là không đau.

Đôi khi tôi có số dòng nhận xét nhiều gấp hai hoặc ba lần so với khi tôi viết mã, đặc biệt là khi các khái niệm hoặc kỹ thuật còn mới đối với tôi và tự giải thích cho mình.

Kiểm soát phiên bản, cải thiện thực hành của bạn, vv .... tất cả các bên trên. Nhưng giải thích mọi thứ cho chính bạn khi bạn đi. Nó hoạt động thực sự tốt.


4

Những phẩm chất nào là quan trọng cho loại chương trình này?

Nó có thể không quan trọng cho dù nó dễ dàng để duy trì hoặc phát triển nó, bởi vì cơ hội là điều đó sẽ không xảy ra.

Có lẽ nó không quan trọng như thế nào là hiệu quả.

Nó có thể không quan trọng cho dù nó có giao diện người dùng tuyệt vời hay liệu nó có an toàn trước những kẻ tấn công độc hại hay không.

Nó có thể quan trọng rằng nó có thể đọc được: rằng ai đó đọc mã của bạn có thể dễ dàng thuyết phục bản thân rằng nó làm những gì nó tuyên bố sẽ làm.

Nó chắc chắn là vấn đề chính xác. Nếu chương trình cho kết quả không chính xác, đó là kết luận khoa học của bạn ngoài cửa sổ. Nhưng nó chỉ cần xử lý chính xác đầu vào mà bạn thực sự yêu cầu nó xử lý; nó thực sự không quan trọng lắm nếu nó rơi xuống nếu được cung cấp các giá trị dữ liệu đầu vào âm, nếu tất cả các giá trị dữ liệu của bạn là dương.

Nó cũng là vấn đề mà bạn duy trì một số mức độ kiểm soát thay đổi. Kết quả khoa học của bạn cần có thể được tái tạo và điều đó có nghĩa là bạn cần biết phiên bản nào của chương trình tạo ra kết quả mà bạn dự định công bố. Vì chỉ có một nhà phát triển, nên việc kiểm soát thay đổi không cần quá phức tạp, nhưng bạn cần đảm bảo rằng bạn có thể quay lại thời điểm và tái tạo kết quả của mình.

Vì vậy, đừng lo lắng về mô hình lập trình, định hướng đối tượng, sự tao nhã của thuật toán. Đừng lo lắng về sự rõ ràng và dễ đọc và về khả năng truy nguyên nguồn gốc của những thay đổi của bạn theo thời gian. Đừng lo lắng về giao diện người dùng. Đừng lo lắng về việc kiểm tra mọi sự kết hợp có thể của các tham số đầu vào, nhưng hãy kiểm tra đủ để tự tin (và làm cho người khác tự tin) rằng kết quả và kết luận của bạn là hợp lệ.


4

Tôi đã làm việc trong một môi trường tương tự với các học giả viết rất nhiều mã (toán / khoa học) nhưng tiến độ của họ chậm do những lý do tương tự như bạn mô tả. Tuy nhiên, tôi đã nhận thấy một điều đặc biệt mà tôi nghĩ cũng có thể giúp bạn: xây dựng và duy trì một bộ thư viện chuyên ngành có thể được sử dụng trên nhiều dự án. Các thư viện này sẽ cung cấp các chức năng tiện ích và do đó sẽ giúp giữ cho dự án hiện tại của bạn cụ thể cho miền có vấn đề.

Ví dụ: bạn có thể phải xử lý rất nhiều phép biến đổi phối hợp trong trường của mình (ECEF, NED, lat / lon, WGS84, v.v.), vì vậy, một hàm như convert_ecef_to_ned()sẽ đi vào một dự án mới được gọi CoordinateTransformations. Đặt dự án dưới sự kiểm soát phiên bản và lưu trữ nó trên máy chủ của bộ phận của bạn để người khác có thể sử dụng (và hy vọng cải thiện) nó. Sau một vài năm, bạn sẽ có một bộ thư viện mạnh mẽ với các dự án của bạn chỉ chứa mã cụ thể cho một vấn đề / lĩnh vực nghiên cứu cụ thể.

Một số lời khuyên chung hơn:

  • Luôn hướng tới mô hình hóa vấn đề cụ thể của bạn một cách chính xác nhất có thể, bất kể đó là gì. Bằng cách đó, các câu hỏi thiết kế phần mềm như cái gì / ở đâu / làm thế nào để đặt một biến sẽ trở nên rõ ràng hơn để trả lời.
  • Tôi sẽ không bận tâm với sự phát triển theo hướng thử nghiệm vì mã khoa học mô tả các ý tưởng và khái niệm và sáng tạo và trôi chảy hơn; không có API để xác định, các dịch vụ cần duy trì, rủi ro đối với mã của người khác khi thay đổi chức năng, v.v.

Đừng để người khác cải thiện nó. Có thể họ không hiểu mục đích của mã và họ sẽ làm mọi thứ rối tung lên.
toán học

@mathreadler Vâng, nếu chúng là các thư viện tiện ích chung thì sẽ hơi khó để người khác làm phiền, đó là ý tưởng.
jigglypuff

Tại sao nó khó gây rối cho các thư viện mục đích chung? Sẽ không quá khó nếu bạn không biết mình đang làm gì, hoặc nếu bạn thực sự cố gắng, hoặc là vì vấn đề đó.
toán học

@mathreadler Bởi vì thường chỉ có một cách để thực hiện chuyển đổi phối hợp hoặc chuyển đổi đơn vị chẳng hạn.
jigglypuff

Thường có rất nhiều cách tùy thuộc vào cách các số của bạn được lưu trữ trong bộ nhớ, đại diện mà chúng sử dụng và rất nhiều thứ khác, CPU mà bạn dự định biên dịch thư viện. Một lập trình viên có thể cho rằng tất cả mọi người sẽ luôn sử dụng các nhân đôi của IEEE chẳng hạn, nhưng một người khác hầu như luôn sử dụng độ chính xác đơn hoặc một số định dạng kỳ lạ thứ ba. Một lập trình viên sau đó sẽ sử dụng đa hình mẫu nhưng một người khác có thể bị dị ứng với nó, một người thứ ba thậm chí còn kỳ quặc hơn sẽ mã hóa mọi thứ ở mức độ thấp c hoặc lắp ráp.
toán học

3

Sau đây là ý kiến ​​của tôi và bị ảnh hưởng rất nhiều bởi con đường cụ thể của riêng tôi.

Mã hóa thường tạo ra quan điểm giáo điều trong cách bạn nên làm mọi việc. Thay vì các kỹ thuật & công cụ, tôi nghĩ bạn cần xem xét các giá trị & chi phí tích lũy để quyết định một chiến lược phù hợp.

Viết mã tốt, dễ đọc, có thể sửa lỗi, mã vững chắc tốn rất nhiều thời gian và công sức. Trong nhiều trường hợp, với một chân trời kế hoạch hạn chế, nó không đáng để làm điều này (tê liệt phân tích).

Một đồng nghiệp có một quy tắc của ngón tay cái; Nếu bạn đang làm về cơ bản cùng một thứ cho lần thứ ba thì hãy đầu tư công sức, nếu không thì một công việc nhanh & bẩn là phù hợp.

Thử nghiệm một số loại là cần thiết, nhưng đối với một dự án, chỉ cần nhãn cầu có thể là đủ. Đối với bất cứ điều gì đáng kể, kiểm tra và cơ sở hạ tầng kiểm tra là cần thiết. Giá trị là nó giải phóng bạn khi mã hóa, chi phí là nếu thử nghiệm tập trung vào một triển khai cụ thể thì các thử nghiệm cũng cần bảo trì. Các xét nghiệm cũng nhắc nhở bạn về cách mọi thứ được cho là hoạt động.

Đối với các tập lệnh tắt của riêng tôi (thường dành cho những thứ như xác thực ước tính xác suất hoặc tương tự), tôi thấy hai điều nhỏ rất hữu ích: 1. Bao gồm một nhận xét cho biết cách sử dụng mã. 2. Bao gồm một mô tả ngắn gọn về lý do tại sao bạn viết mã. Những điều này rất rõ ràng khi bạn viết mã, nhưng sự rõ ràng lãng phí thời gian :-).

OOP là về việc tái sử dụng mã, trừu tượng hóa, đóng gói, bao thanh toán, v.v ... Rất hữu ích, nhưng dễ bị lạc lõng nếu sản xuất mã & thiết kế chất lượng không phải là mục tiêu cuối cùng của bạn. Phải mất thời gian và nỗ lực để sản xuất công cụ chất lượng.


3

Trong khi tôi nghĩ rằng các bài kiểm tra đơn vị có giá trị của chúng, chúng có giá trị đáng ngờ cho sự phát triển khoa học - chúng thường chỉ quá nhỏ để cung cấp nhiều giá trị.

Nhưng tôi thực sự thích các bài kiểm tra tích hợp cho mã khoa học:

Cô lập một đoạn nhỏ mã của bạn có thể tự hoạt động, ví dụ: đường ống ETL. Sau đó viết một bài kiểm tra cung cấp dữ liệu, chạy đường ống etl (hoặc chỉ một bước) và sau đó kiểm tra xem kết quả đó có phù hợp với mong đợi của bạn không. Trong khi đoạn thử nghiệm có thể có rất nhiều mã, thử nghiệm cung cấp giá trị tĩnh:

  1. Bạn có một hook liên tục để thực thi lại mã của mình, điều này giúp chạy nó thường xuyên.
  2. Bạn có thể kiểm tra một số giả định trong bài kiểm tra của mình
  3. Nếu đôi khi bị hỏng, thật dễ dàng để thêm một bài kiểm tra thất bại và sửa lỗi
  4. Bạn mã hóa các đầu vào / đầu ra dự kiến, tránh đau đầu thông thường dẫn đến việc cố gắng đoán định dạng dữ liệu đầu vào.
  5. Mặc dù không gọn gàng như các bài kiểm tra đơn vị, các bài kiểm tra CNTT vẫn giúp tách mã của bạn ra và buộc bạn phải thêm một số ranh giới trong mã của mình.

Tôi đang sử dụng kỹ thuật này thường xuyên và thường kết thúc với một chức năng chính có thể đọc được tương đối nhưng các chức năng phụ thường khá dài và xấu, nhưng có thể được sửa đổi và sắp xếp lại nhanh chóng do ranh giới I / O mạnh mẽ.


2

Tôi thường làm việc trên một cơ sở nguồn rất lớn. Chúng tôi sử dụng tất cả các công cụ bạn đề cập. Gần đây, tôi đã bắt đầu làm việc với một số kịch bản python cho một dự án phụ. Họ là một vài chục đến vài trăm dòng nhiều nhất. Theo thói quen, tôi cam kết các kịch bản của mình để kiểm soát nguồn. Điều này rất hữu ích vì tôi có thể tạo các nhánh để thử các thí nghiệm có thể không hoạt động. Tôi có thể rẽ nhánh nếu tôi cần sao chép mã và sửa đổi nó cho mục đích khác. Điều này để lại bản gốc trong chiến thuật trong trường hợp tôi cần phải mang nó ra một lần nữa.

Đối với "kiểm tra đơn vị" tôi chỉ có một số tệp đầu vào nhằm tạo ra một số đầu ra đã biết mà tôi kiểm tra bằng tay. Tôi có thể tự động hóa nó, nhưng cảm giác như sẽ mất nhiều thời gian hơn để làm điều đó hơn là tôi sẽ tiết kiệm bằng cách thực hiện nó. Có lẽ nó phụ thuộc vào tần suất tôi phải sửa đổi và chạy các tập lệnh. Dù bằng cách nào, nếu nó hoạt động, làm điều đó. Nếu nó rắc rối hơn giá trị của nó, đừng lãng phí thời gian của bạn.


2

Với mã viết - như với viết nói chung - câu hỏi chính là:

Những người đọc bạn có trong tâm trí? hoặc Ai tiêu thụ mã của bạn?

Những thứ như hướng dẫn mã hóa chính thức không có ý nghĩa gì khi bạn là khán giả duy nhất của bạn.

Điều đó đang được nói, mặt khác, sẽ rất hữu ích khi viết mã theo một cách nào đó, tương lai của bạn, bạn có thể hiểu nó ngay lập tức.

Vì vậy, một "phong cách tốt" sẽ là một, giúp bạn nhiều nhất. Phong cách đó sẽ như thế nào là một câu trả lời tôi không thể đưa ra.

Tôi nghĩ rằng bạn không cần kiểm tra OOP hoặc Đơn vị cho các tệp 150 LỘC. Một VCS chuyên dụng sẽ rất thú vị khi bạn có một số mã đang phát triển. Nếu không thì a .baklừa. Những công cụ này là một phương pháp chữa bệnh tuyệt vọng, thậm chí bạn có thể không có.

Có lẽ bạn nên viết mã của mình theo cách như vậy, ngay cả khi bạn đọc nó trong khi say, bạn có thể đọc, hiểu và sửa đổi 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.