Cách làm cho một cơ sở mã lớn dễ hiểu hơn


104

Giả sử rằng tôi đang phát triển một dự án tương đối lớn. Tôi đã ghi lại tất cả các lớp và chức năng của mình với Doxygen, tuy nhiên, tôi có ý tưởng đặt "ghi chú của lập trình viên" vào mỗi tệp mã nguồn.

Ý tưởng đằng sau điều này là để giải thích theo thuật ngữ của giáo dân về cách một lớp cụ thể hoạt động (và không chỉ tại sao như hầu hết các bình luận làm). Nói cách khác, để cung cấp cho các lập trình viên đồng nghiệp một cái nhìn khác về cách một lớp hoạt động.

Ví dụ:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

Đây có phải là một cách tốt để làm cho một dự án lớn dễ dàng hơn cho các lập trình viên / cộng tác viên mới hiểu cách thức hoạt động của nó? Ngoài việc duy trì một phong cách mã hóa nhất quán và tổ chức thư mục 'tiêu chuẩn', còn có 'tiêu chuẩn' hay khuyến nghị nào cho những trường hợp này không?


32
Trời ơi không. Nếu mã của bạn không thể đọc được, tài liệu sẽ không giúp ích.
Telastyn

35
@jeffo - vấn đề là dành thời gian để làm điều này có thể xảy ra một lần. Thời gian để giữ mã có thể đọc được xảy ra theo thời gian. Tôi đã từng đến những nơi có loại tài liệu này, được thực hiện khi dự án còn trẻ hoặc khi Joe the Perfectionist vẫn còn trong đội. Sau đó nó đã bị bỏ rơi và các ý kiến ​​nán lại, không còn chính xác.
Telastyn

25
Ở cấp độ cao hơn ít nhất, một mô tả văn xuôi ngoài mã về những gì một dự án làm, cách thức hoạt động và những gì đánh đổi đã được thực hiện trong kiến ​​trúc là vô giá. Loại tài liệu này là phải đọc cho người mới trước khi họ thực hiện một chuyến tham quan mã. Có rất nhiều phương pháp my--là-quá-triệt-để-docs-anh chàng nhảm nhí khắp nơi trên mạng, và trong khi nó sự thật rằng một vòm doc ban đầu và một vòm phát triển doc sẽ không gắn kết, một mô tả văn xuôi là cần thiết cho bất cứ ai để nhanh chóng nắm bắt một cơ sở mã lớn, không tầm thường. Dưới đây là một ví dụ (kém): zxq9.com/erlmud/html/001-002_arch architecture.html
zxq9

11
@Telastyn: Điều này không liên quan gì đến việc mã có thể đọc được hay không (và tôi hy vọng là như vậy). Tài liệu thiết kế hợp lý là hoàn toàn quan trọng.
Các cuộc đua nhẹ nhàng trong quỹ đạo

7
@Telastyn: Vâng, có thể. Cá nhân tôi sẽ viết nó trong một tài liệu độc lập. Nhưng các khối nhận xét ở đầu các tệp nguồn không quá tệ.
Các cuộc đua nhẹ nhàng trong quỹ đạo

Câu trả lời:


139

Điều này thật tuyệt. Tôi muốn nhiều nhà phát triển phần mềm đã dành thời gian và nỗ lực để làm điều này. Nó:

  • Nói bằng tiếng Anh đơn giản những gì lớp học làm (nghĩa là trách nhiệm),
  • Cung cấp thông tin bổ sung hữu ích về mã mà không lặp lại nguyên văn những gì mã đã nói,
  • Phác thảo một số quyết định thiết kế và lý do tại sao chúng được đưa ra, và
  • Làm nổi bật một số vấn đề có thể xảy ra với người tiếp theo đọc mã của bạn.

Than ôi, nhiều lập trình viên rơi vào trại "nếu mã được viết đúng, nó không cần phải được ghi lại." Không đúng. Có nhiều mối quan hệ hàm ý giữa các lớp mã, phương thức, mô-đun và các tạo phẩm khác không rõ ràng từ việc chỉ đọc chính mã.

Một lập trình viên có kinh nghiệm có thể cẩn thận chế tạo một thiết kế có kiến ​​trúc rõ ràng, dễ hiểu, rõ ràng mà không cần tài liệu. Nhưng có bao nhiêu chương trình như thế bạn đã thực sự thấy?


15
Và tại sao "Tháng người đàn ông huyền thoại" trở thành một lời tiên tri tự hoàn thành, không ai dành thời gian để viết tất cả những điều này cho nhà phát triển mới khi nó còn mới mẻ trong tâm trí của họ và dự án đã không bị tụt lại phía sau.
JeffO

3
Tôi đồng ý với mọi điểm bạn làm ở đây. Tôi không thích thuật ngữ OP sử dụng trong bài viết của mình how a class works. Điều này thay đổi theo thời gian và bảo trì. Mặc dù nhóm của tôi không đưa những điều trên vào nguồn. Chúng tôi duy trì wiki với các quyết định và sao chép thảo luận kênh chùng về các quyết định thiết kế thô vào tài liệu (Chúng tôi cung cấp một liên kết từ bản tóm tắt quyết định và kết luận đến các ghi chú thô để chúng tôi không phải băm lại các quyết định cũ). Tất cả được thực hiện gọn gàng trong github (vì vậy tất cả nằm ở một nơi).
Martin York

1
Vấn đề duy nhất của tôi là áp dụng điều này trên toàn cầu. Lớp này đủ phức tạp, với một số vấn đề nhất định có sẵn, rõ ràng nó thực sự hữu ích (mặc dù bạn vẫn kết thúc giao dịch với Comment Rot). Khi một lớp rõ ràng hơn, bình luận có thể là một chút thừa.
deworde

1
"Một lập trình viên có kinh nghiệm có thể cẩn thận tạo ra một thiết kế có kiến ​​trúc rõ ràng, dễ hiểu, rõ ràng mà không cần tài liệu. Nhưng có bao nhiêu chương trình như bạn đã thấy" Trong khi điều này là đúng, chất lượng của tài liệu không bao giờ tốt hơn chất lượng của mật mã. Mã kiến ​​trúc tốt có xu hướng có tài liệu tốt, nếu vô nghĩa ,. Mã được kiến ​​trúc kém có các nhận xét như "tăng x 1"
deworde

3
Tôi hoàn toàn đồng ý với câu trả lời này và nếu tôi tìm thấy một cái gì đó giống như ví dụ của OP trong mã, tôi sẽ rất hạnh phúc. Chỉ là một bổ sung duy nhất: xem xét thêm một ngày vào bình luận của bạn, chỉ để đưa ra gợi ý cho người đọc cuối cùng về sự mới mẻ của mô tả và cập nhật nó mỗi khi bạn cập nhật văn bản.
Svalorzen

36

Chìa khóa để làm việc với một cơ sở mã lớn là không phải đọc toàn bộ cơ sở mã để thực hiện thay đổi. Để cho phép một lập trình viên nhanh chóng tìm thấy mã mà anh ta đang tìm kiếm, mã phải được tổ chức và tổ chức rõ ràng. Nghĩa là, mỗi đơn vị logic trong mã, từ tệp thực thi, thư viện, không gian tên, đến lớp riêng lẻ phải có trách nhiệm rõ ràng rõ ràng. Do đó, tôi sẽ không chỉ tài liệu các tập tin nguồn, mà còn các thư mục họ cư trú.

Ghi chú của lập trình viên của bạn cũng đưa ra nền tảng về các quyết định thiết kế. Mặc dù đây có thể là thông tin có giá trị, tôi sẽ tách nó ra khỏi tuyên bố trách nhiệm (để cho phép người đọc chọn xem anh ta có muốn đọc về trách nhiệm của lớp học hay lý do thiết kế của nó không) và di chuyển nó gần với nguồn mà nó mô tả càng tốt, để tối đa hóa cơ hội tài liệu được cập nhật khi mã được (tài liệu chỉ hữu ích nếu chúng ta có thể tin tưởng vào độ chính xác của nó - tài liệu lỗi thời có thể tệ hơn không có gì!).

Điều đó nói rằng, tài liệu nên vẫn là DRY, tức là không lặp lại thông tin có thể được thể hiện bằng mã hoặc đã được mô tả ở nơi khác (cụm từ như "như các trạng thái tài liệu" là một dấu hiệu cảnh báo). Cụ thể, những người duy trì trong tương lai sẽ chỉ thành thạo ngôn ngữ lập trình của dự án như bằng tiếng Anh; diễn giải việc thực hiện trong các bình luận (mà tôi thấy hoàn toàn quá thường xuyên khi mọi người tự hào về tài liệu của họ) không có lợi ích gì, và có khả năng chuyển hướng khỏi việc thực hiện, đặc biệt nếu tài liệu không ở gần mã mà nó mô tả.

Cuối cùng, cấu trúc của tài liệu nên được chuẩn hóa trong toàn dự án để mọi người có thể tìm thấy nó (đó là một mớ hỗn độn của các tài liệu Peter trong trình theo dõi lỗi, Sue trong wiki, Alan trong readme và John trong mã nguồn ...) .


Câu đầu tiên của bạn là chính xác cách tôi xem này. Các cơ sở mã lớn nên được cấu thành như một số thành phần nhỏ hơn trong đó một lập trình viên mới có thể thay đổi một cách đáng tin cậy mà không gây nguy hiểm cho bất kỳ thành phần nào khác.
Jon Chesterfield

1
di chuyển nó càng gần với nguồn mà nó mô tả càng tốt, để tối đa hóa cơ hội tài liệu được cập nhật khi mã được . Đây là kinh nghiệm quý giá.
laike9m

DRY như một hướng dẫn cho tài liệu là một điểm rất tốt! Điều đó tự động đặt quyền tập trung và cấm các bình luận "// gia tăng x 1" đáng ghét.
Hans-Peter Störr

13

Tôi không đồng ý đây là một cách tiếp cận rất tốt, chủ yếu là do

  1. Khi bạn cấu trúc lại dự án của mình, di chuyển các phương thức xung quanh, tài liệu sẽ bị hỏng.

  2. Nếu tài liệu không được cập nhật đúng cách, nó sẽ dẫn đến sự nhầm lẫn nhiều hơn là giúp hiểu mã.

Nếu bạn có các bài kiểm tra đơn vị cho từng phương pháp / kiểm tra tích hợp cho từng mô-đun, thì đó sẽ là một tài liệu tự bảo trì dễ hiểu và dễ hiểu hơn so với nhận xét mã.

Vâng, có một cấu trúc thư mục thích hợp chắc chắn sẽ giúp.


+1 cho Kiểm tra là cách tốt nhất để hiểu cơ sở mã. Các bài kiểm tra đơn vị, kiểm tra tích hợp, kiểm tra chấp nhận đều kể câu chuyện về cách ứng dụng được cho là hoạt động và cách sử dụng ứng dụng.
BZink

7

Cá nhân tôi là một fan hâm mộ của một tài liệu thiết kế cấp cao - tốt nhất là được viết TRƯỚC bất kỳ mã nào - đưa ra một cái nhìn tổng quan về thiết kế và một danh sách các lớp và tài nguyên. Thiết kế từ trên xuống đơn giản hóa rất nhiều thứ - của bạn có thể là "công cụ trò chơi -> phần cứng -> bộ điều khiển -> cần điều khiển"; do đó, một lập trình viên mới nói "sửa nút 'a' trên bộ điều khiển 'xyz" ít nhất sẽ biết bắt đầu tìm ở đâu.

Quá nhiều ngôn ngữ hiện đại có xu hướng phá mã thành hàng trăm tệp nhỏ, vì vậy chỉ cần tìm đúng tệp có thể là một thách thức đối với ngay cả một dự án vừa phải.


16
20 năm trước, tất cả mã của tôi nằm trong một tệp lớn. Bây giờ nó có trong hàng ngàn tệp nhỏ và tệp thử nghiệm. Có một lý do chính đáng cho điều này và nó phản ánh 20 năm phát triển phần mềm (hệ sinh thái nói chung, không phải kiến ​​thức của tôi). Mặc dù quá lâu cho một bình luận.
Michael Durrant

4
ah, phương pháp thác nước cũ bằng cách viết một, tất cả bao gồm, không thay đổi, Sự thật trước khi mã hóa thậm chí bắt đầu và làm cho nó không thể đi chệch hướng trong việc thực hiện từ Sự thật nói.
jwenting

2
@jwenting: Bạn không cần phải đi quá xa. Nhưng vẫn tốt để có một số ý tưởng về những gì bạn đang xây dựng.
Robert Harvey

1
Chắc chắn không có sự cảnh báo về cách phá vỡ điều này một cách chính xác và nơi để phá vỡ các quy tắc, bạn sẽ nhanh chóng có một tài liệu hết hạn hoặc một cối xay. "Tôi cần thêm một lớp mới; vào Documanto, Behemoth ăn thời gian!"
deworde

2
@deworde: Tôi đọc là "quá lười để duy trì tài liệu."
Robert Harvey

6

Nếu cơ sở mã lớn - tôi cố gắng cung cấp một tài liệu thiết kế để vạch ra các yếu tố chính của thiết kế và việc thực hiện . Ý định ở đây không phải là chi tiết bất kỳ lớp nào được sử dụng, mà cung cấp một khóa để viết mã và ý nghĩ đi vào thiết kế. Nó đưa ra một bối cảnh bao quát cho hệ thống, các thành phần của nó và ứng dụng của nó.

Những điều cần bao gồm trong tài liệu thiết kế là;

  • Kiến trúc ứng dụng
  • Cấu trúc mã logic
  • Luồng dữ liệu
  • Các mẫu chính được sử dụng và động lực đằng sau việc sử dụng chúng
  • Cấu trúc nguồn mã
  • Cách xây dựng nó (điều này cung cấp cái nhìn sâu sắc về các phụ thuộc ngầm định và cấu trúc nguồn mã vật lý)

Theo đó, tài liệu cho các lớp và các hàm / phương thức nên được hoàn thành khi thích hợp . Cụ thể là API công khai; cần phải rõ ràng tất cả những gì sau đây trong mỗi trường hợp;

  • Điều kiện tiên quyết
  • Các hiệu ứng
  • Bất biến
  • Điều kiện ngoại lệ (ném)

+1 Tốt hơn so với mô tả từng lớp, vì điều đó sẽ thoát khỏi cách nhanh hơn so với thiết kế tổng thể.
Lode

4

Quy tắc quan trọng nhất mà tôi đã tìm thấy để giúp các nhà phát triển mới dễ dàng hiểu được một cơ sở mã là thỏa thuận hoàn hảo là tốn kém.

Nếu các nhà phát triển mới phải hiểu một cách hoàn hảo hệ thống mà họ đang làm việc, nó sẽ ngăn chặn tất cả các cơ hội cho việc học. Tôi nghĩ rằng các ghi chú của lập trình viên là một khởi đầu tuyệt vời, nhưng tôi sẽ đi xa hơn. Cố gắng viết mã, nếu được tiếp cận một lần nữa, sẽ cho phép nhà phát triển tìm ra những gì họ đang làm một cách nhanh chóng, thay vì yêu cầu họ tìm hiểu trước khi họ làm. Những điều nhỏ nhặt như khẳng định cho các trường hợp bạn biết không bao giờ có thể xảy ra, cùng với các bình luận giải thích lý do tại sao khẳng định đó là hợp lệ, đi một chặng đường dài. Viết mã không thành công một cách duyên dáng thay vì viết sai nếu bạn làm bất cứ điều gì sai.


Quy tắc của tôi là ý kiến ​​nên về TẠI SAO chứ không phải CÁCH . Mã mô tả CÁCH.
dùng11393

3

Tôi đã thấy các lớp lớn có tài liệu và sau khi đọc tài liệu tôi không biết được lớp này được cho là tốt và tại sao mọi người sẽ sử dụng nó! Đồng thời, tôi có nhu cầu về một số chức năng và tôi hoàn toàn chắc chắn rằng phải có một lớp để xử lý nó và không thể tìm thấy nó ở bất cứ đâu - bởi vì không có tài liệu nào đưa tôi từ những gì tôi cần đến lớp làm việc đó.

Vì vậy, điều đầu tiên mà tôi muốn trong tài liệu chỉ là một vài câu mà một lớp học làm gì và tại sao tôi lại muốn sử dụng nó. Các ý kiến ​​trong câu hỏi ban đầu đang làm khá tốt trong khía cạnh đó. Sau khi đọc những bình luận này, nếu tôi có một phím điều khiển không hoạt động tốt bởi vì tôi không thể diễn giải các giá trị mà nó mang lại, tôi sẽ biết nên kiểm tra mã nào.


0

Tương tự như những gì @meriton đã nói, hãy chia mã thành các thành phần riêng biệt. Thậm chí tốt hơn, chia cơ sở mã thành các gói riêng biệt (JAR, đá quý, trứng, bất cứ thứ gì) để làm cho nó rõ ràng hơn về cách các thành phần được tách ra. Nếu có lỗi, nhà phát triển chỉ cần tìm gói có lỗi và (hy vọng) chỉ sửa nó ở đó. Chưa kể, việc kiểm tra đơn vị sẽ dễ dàng hơn và bạn có thể tận dụng lợi thế của quản lý phụ thuộc.

Một giải pháp khác: làm cho codebase nhỏ hơn. Càng ít mã, càng dễ hiểu. Tái cấu trúc ra mã không sử dụng hoặc trùng lặp. Sử dụng các kỹ thuật lập trình khai báo . Điều này đòi hỏi nỗ lực, tất nhiên, và thường là không thể hoặc thực tế. Nhưng đó là một mục tiêu xứng đáng. Như Jeff Atwood đã viết: Mã tốt nhất là không có mã nào cả


-1

Đối với các hệ thống phức tạp, có thể đáng để không chỉ ghi lại từng tệp, mà cả các tương tác và phân cấp của chúng, và cách cấu trúc chương trình và lý do.

Ví dụ, một công cụ trò chơi thường khá phức tạp và thật khó để quyết định cái gì gọi là gì sau hàng trăm lớp trừu tượng. Có thể đáng để tạo một tệp như "Architecture.txt" để giải thích cách thức và lý do tại sao mã được cấu trúc như thế này và tại sao lại có lớp trừu tượng trông vô nghĩa ở đó.


-7

Điều này có thể là một phần bởi vì rất khó để một lập trình viên viết nó, vì mỗi cá nhân chỉ hiểu một phần dự án của họ.

Đôi khi bạn có thể lấy thông tin này từ các ghi chú của người quản lý dự án, nhưng đó là tất cả những gì bạn sẽ nhận được, vì họ sẽ hiếm khi viết lại ghi chú của họ ở định dạng này.


7
Nếu bạn nhìn vào github, bạn sẽ tìm thấy rất nhiều dự án có loại ghi chú này trong tệp README.md. Nó trở thành một phần của văn hóa git nói chung và các dự án javascript nói riêng với hầu hết mọi người sẽ không sử dụng một thư viện không có loại tài liệu cấp cao này. Vì vậy, không đúng khi "không có lập trình viên nào viết nó" vì bạn chỉ cần nhìn vào một cái gì đó như jQuery hoặc socket.io và tìm các lập trình viên viết những thứ như vậy. Nó cũng đã trở thành một văn hóa mà các tệp README không tạo ra các báo cáo lỗi chính xác.
slebetman

1
Điều này dường như không trả lời câu hỏi, mà đang tìm kiếm lý do tại sao phong cách tài liệu được đề xuất sẽ hoặc không hoạt động, và cũng cho các tiêu chuẩn tài liệu.
dùng52889

5
Nếu bạn có một nhóm lập trình viên làm việc trên một sản phẩm và mỗi lập trình viên chỉ hiểu mã cụ thể mà họ đã làm việc, thì không chỉ nhóm của bạn vô cùng rối loạn với yếu tố xe buýt vô lý, mà người ta còn đặt câu hỏi về chất lượng của mã. Làm thế nào để một người tích hợp mã vào một sản phẩm mà không hiểu phần còn lại của mã trong cùng một hệ thống ??!?
Các cuộc đua nhẹ nhàng trong quỹ đạo
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.