Làm thế nào tôi có thể định nghĩa và đo lường sự đơn giản trong mã?


13

Có nhiều câu trả lời trong câu hỏi trước đây của tôi về tính đơn giản liên quan đến tính dễ đọc giúp tôi thấy định nghĩa và sự hiểu biết về tính đơn giản trong mã là, rất có thể, không chính xác.

Làm thế nào tôi có thể định nghĩa sự đơn giản trong mã? Những phép đo và số liệu phần mềm nào có sẵn để đo lường sự đơn giản của mã?


2
@MarkTrapp Có nhiều cách khác để thảo luận về tính đơn giản của mã mà không có chủ đề từ kỹ thuật phần mềm theo kinh nghiệm, những chủ đề mà tôi không quen thuộc lắm. Ví dụ, thảo luận về tính đơn giản về khả năng viết bài kiểm tra tự động. Kỹ năng và kiến ​​thức của tôi cho phép tôi trả lời câu hỏi này từ quan điểm của một kỹ sư phần mềm, trong khi những người khác có thể trả lời từ các quan điểm khác. Việc thêm câu nói đó vào câu hỏi sẽ hạn chế số lượng câu trả lời hữu ích một cách đáng kể, khiến nó (IMO) trở nên quá cục bộ. Nếu bạn muốn thêm nó, bạn có thể, nhưng đây là một câu hỏi hay.
Thomas Owens

2
@ThomasOwens Câu hỏi thực sự có câu trả lời , không phải ý tưởng hay ý kiến. Thu hẹp phạm vi để mọi người diễn giải cách trả lời câu hỏi theo cùng một cách chính xác là những gì Stack Exchange nói về. Có thể có nhiều hơn một cách tiếp cận để giải quyết vấn đề, nhưng chỉ có một vấn đề được nêu rõ ràng.

Ở trạng thái hiện tại, có rất ít câu trả lời cho câu hỏi này (câu trả lời của tôi đề cập đến quan điểm kỹ thuật phần mềm theo kinh nghiệm, với các số liệu chung - có thể có những câu hỏi khác). Không có ý nghĩa gì để loại trừ các câu trả lời cung cấp các lựa chọn thay thế hợp lệ từ các quan điểm khác, đó là những gì từ ngữ của câu hỏi này làm. Tôi không đồng ý hoàn toàn với các chỉnh sửa này và câu hỏi nên được hoàn nguyên về dạng ban đầu.
Thomas Owens

@MarkTrapp Vấn đề không rõ ràng: Làm cách nào để xác định tính đơn giản của mã? Có một số câu trả lời tốt. Mine đang sử dụng các kỹ thuật kỹ thuật phần mềm theo kinh nghiệm để đo lường độ phức tạp. Một cách khác có thể là viết các bài kiểm tra tự động và nếu khó viết bài kiểm tra tốt, mã rất phức tạp - một câu trả lời hoàn toàn hợp lệ. Có thể có những người khác mà tôi không biết. Nếu bạn cần đo độ phức tạp / đơn giản của một cơ sở mã, câu hỏi nên được diễn đạt theo cách cho phép tất cả các phương án được trình bày để người hỏi có thể chọn giải pháp tốt nhất cho trường hợp cụ thể của mình.
Thomas Owens

Câu trả lời:


16

Các số liệu phổ biến nhất để đo độ phức tạp (hoặc đơn giản, nếu bạn coi sự đơn giản là đối lập với độ phức tạp) là Độ phức tạp theo chu kỳ của McCabeSố liệu độ phức tạp Halstead .

Độ phức tạp theo chu kỳ đo số lượng các đường dẫn riêng biệt thông qua một đơn vị nhất định, thường là một phương thức hoặc hàm, mặc dù nó cũng có thể được tính trên một lớp. Khi số lượng đường dẫn tăng lên, việc ghi nhớ luồng dữ liệu thông qua một mô-đun đã cho sẽ trở nên khó khăn hơn, có liên quan đến khái niệm bộ nhớ làm việc . Độ phức tạp chu kỳ cao có xu hướng cho thấy khó khăn trong khả năng kiểm tra một mô-đun - cần nhiều trường hợp thử nghiệm hơn để bao quát các đường dẫn khác nhau thông qua hệ thống. Cũng đã có những nghiên cứu đã liên kết độ phức tạp chu kỳ cao với tỷ lệ khuyết tật cao. Thông thường, độ phức tạp theo chu kỳ là 10 chỉ ra rằng một đơn vị nên được xem xét và có thể được tái cấu trúc.

Các biện pháp phức tạp Halstead sử dụng đầu vào của các toán tử và toán hạng tổng và riêng biệt để tính toán khối lượng, độ khó và nỗ lực của một đoạn mã. Khó khăn, đó là (số toán tử duy nhất / 2) * (tổng số toán hạng / số toán hạng duy nhất), gắn liền với khả năng đọc và hiểu mã cho các tác vụ như tìm hiểu hệ thống hoặc thực hiện đánh giá mã. Một lần nữa, bạn có thể tính điều này ở cấp độ hệ thống, cấp độ lớp hoặc cấp độ phương thức / chức năng. Có một vài bài đăng về tính toán các phép đo này ở đâyđây .

Chỉ cần đếm các dòng mã cũng có thể cho bạn một ý tưởng về sự phức tạp. Nhiều dòng mã hơn có nghĩa là có nhiều thứ để đọc và hiểu trong một mô-đun. Tôi sẽ do dự khi sử dụng nó như một phép đo độc lập. Thay vào đó, tôi sẽ sử dụng nó với các phép đo khác, chẳng hạn như số lượng khuyết tật trong một mô-đun nhất định để có được mật độ khuyết tật. Mật độ khiếm khuyết cao có thể chỉ ra các vấn đề trong việc viết bài kiểm tra và thực hiện đánh giá mã, điều này có thể hoặc không thể gây ra bởi mã phức tạp.

Fan-in và fan-out là hai số liệu khác, liên quan đến luồng dữ liệu. Như được định nghĩa ở đây , fan in là tổng của các thủ tục được gọi, đọc tham số và biến toàn cục đọc và quạt là tổng các thủ tục gọi một thủ tục đã cho, các tham số được ghi (tiếp xúc với người dùng bên ngoài, được truyền qua tham chiếu), và các biến toàn cục được viết thành. Một lần nữa, fan-in và fan-out cao có thể là dấu hiệu của một mô-đun có thể khó hiểu.

Trong các mô hình cụ thể, có thể có các biện pháp hoặc số liệu khác cũng hữu ích. Ví dụ, trong thế giới hướng đối tượng, khớp nối giám sát (ham muốn thấp), sự gắn kết (ham muốn cao) và độ sâu của thừa kế (ham muốn thấp) có thể được sử dụng để đánh giá mức độ đơn giản hoặc phức tạp của một hệ thống.

Tất nhiên, điều quan trọng là phải nhận ra rằng rất nhiều biện pháp và số liệu chỉ đơn giản là các chỉ số. Bạn cần sử dụng phán đoán của mình để xác định xem có cần thiết phải cấu trúc lại để tăng tính đơn giản hay không nếu nó không đáng để nỗ lực làm điều đó. Bạn có thể thực hiện các phép đo, tính toán các số liệu và tìm hiểu về mã của mình, nhưng bạn không muốn thiết kế hệ thống của mình theo các con số. Cuối cùng, làm những gì có ý nghĩa.


5
Tôi biết bạn đã đề cập đến nó nhưng điều quan trọng cần nhấn mạnh là độ phức tạp chu kỳ thực sự chỉ hữu ích ở cấp độ chức năng / phương pháp và trở nên chủ quan / vô dụng hơn đáng kể ở các cấp cao hơn.
Ryathal

Vấn đề là trong khi các biện pháp này là một hướng dẫn chung. Có một số trường hợp các chương trình "xấu" đạt điểm cao, ví dụ có hàng tá hàm, trong đó một hàm có hai tham số sẽ đủ và ngược lại, nhiều chương trình "tốt" là giải pháp được viết tốt cho một vấn đề phức tạp có thể ghi điểm tệ.
James Anderson

@James tôi chỉ rõ điều đó. Bất kỳ phép đo hoặc số liệu nào cũng cần được thực hiện trong bối cảnh như một chỉ báo cho thấy cần phải xem xét điều gì đó. Phải có sự phán xét của một kỹ sư để xác định xem có cần hành động khắc phục hay không và hành động đó là gì. Tuy nhiên, trừ khi bạn đang tích cực thu thập dữ liệu, không có cách nào theo kinh nghiệm để biết về các vấn đề tiềm ẩn.
Thomas Owens

7

Thay vì nhìn vào một chế độ chính thức để xác định tính đơn giản, tôi muốn xác định tính đơn giản là một thuộc tính của chất lượng viết mã.

Tôi không đặt ra một số biện pháp đơn giản nhưng khi nào bạn gọi một cái gì đó đơn giản hay không.

1. Code Traversal:
Dễ dàng điều hướng qua mã như thế nào? Có dễ dàng nhận ra nơi các hàm API được viết không? Có dễ hiểu các luồng cuộc gọi không, ví dụ các phương thức nào đang gọi các phương thức khác (và tại sao) - có các máy trạng thái tốt được triển khai hoặc xác định rõ ràng các thuật toán không?

Khi truyền tải mã dễ dàng, mã rất đơn giản để làm theo.

2. Đặt tên
Trong khi các tiêu chuẩn mã hóa khác giúp làm cho mã trông gọn gàng hơn - điều quan trọng nhất là việc đặt tên các lớp / đối tượng / Biến / phương thức. Việc sử dụng tên rõ ràng và rõ ràng rõ ràng có tác động lớn đến tính Đơn giản của mã. Khi khó xác định một tên đơn giản, đó là một dấu hiệu cho thấy bạn có thể muốn nghĩ lại ý tưởng là biến / phương thức đó.

3. Giải thích và tham khảo
Mỗi phương pháp của bạn có vai trò rõ ràng. Có phải mỗi biến / thuộc tính đều dễ dàng xác định vai trò họ đang chơi không? Khi một đoạn mã thực hiện điều gì đó ngụ ý các giả định hoặc ảnh hưởng đến tập hợp các biến không liên quan, có thể trở thành một cơn ác mộng bảo trì.

4. Sự phụ thuộc hoặc khớp nối
Điều này rất khó để đánh giá chỉ bằng cách xem mã, nhưng sẽ trở nên rất rõ ràng nếu ai đó cố gắng sửa lỗi của bạn. Khi một số thứ khác thay đổi trong một số đối tượng khác, hoạt động ở đây có thay đổi không? Là những thay đổi rõ ràng? Bạn có yêu cầu thay đổi API thường xuyên để chứa đồ không. Những điều này cho thấy các mối quan hệ giữa các mô hình không đơn giản

5. Đầu vào Người dùng hoặc Ứng dụng
Cuối cùng, đầu vào hoặc ứng dụng của người dùng được chấp nhận đơn giản như thế nào trên API / UI? Khi nhiều người dùng / ứng dụng có thể (cho các mục đích khác nhau) cần cung cấp cho bạn - chúng có rõ ràng không? Có các trạng thái / chi tiết không liên quan đến độ trừu tượng cao hơn nhưng vẫn đi ngược lại giao diện không?

Một câu hỏi đơn giản tôi thường hỏi là như sau: Nếu thay vì một chương trình, nếu tôi đã yêu cầu chức năng tương tự được thực hiện bởi một con người, tôi có điền thông tin này vào một biểu mẫu giấy không? Nếu không, tôi không đủ đơn giản ở đây.

Tôi sẽ không nói danh sách này là đầy đủ, nhưng tôi đoán rằng tiêu chí là việc sử dụng và sửa đổi phần mềm dễ hay khó như thế nào. Điều đó thật đơn giản.


1
Ông yêu cầu các phép đo và số liệu. Đây là chủ quan, vì vậy tôi không nghĩ rằng họ rất quan điểm.
psr

@psr Tôi đồng ý với bạn. Nó cũng rất rõ ràng từ câu trả lời từ câu trả lời của Thomas. Tuy nhiên, ông đề cập đến sự đơn giản liên quan đến khả năng đọc . Câu trả lời của Thomas liên quan đến độ phức tạp Cyclomatic - điều này cho bạn biết mức độ phức tạp của việc kiểm tra mã và không phải mức độ phức tạp của mã về khả năng đọc và có thể mở rộng khả năng bảo trì . Đây là hai khái niệm rất khác nhau. Đó là chính xác lý do tại sao tôi viết câu trả lời này để đặt mâu thuẫn rõ ràng. Thật không may, theo hiểu biết của tôi, không có số liệu nào đề cập đến tính đơn giản của mã về khả năng đọc.
Dipan Mehta

"Sử dụng tên không thể hiểu lầm" - IMHO đây là mục tiêu quá cao, đến một mục tiêu phi thực tế và không thể. Tôi thà không cố tỏ ra dứt khoát và chỉ đơn giản nói "sử dụng tên rõ ràng và rõ ràng".
Péter Török

@ PéterTörök Tôi đồng ý. Tôi nghĩ thông thường, trong nhiều tổ chức, quy định rất rõ ràng về quy tắc đặt tên và vẫn còn một số nhầm lẫn về cường độ của biến cụ thể vẫn tồn tại. Vì vậy, nhấn mạnh là để nói rằng sự rõ ràng của mục đích lên đến sự đơn giản trái ngược với một quy tắc chính thức. Có thể tôi đã quá nhiệt tình trong cách tôi mô tả. Cảm ơn.
Dipan Mehta

@Dipan Độ phức tạp theo chu kỳ có liên quan đến khả năng đọc mã, thông qua bộ nhớ làm việc. Mã có độ phức tạp chu kỳ cao (hoặc thậm chí chỉ là độ sâu khối cao) rất khó để giữ trong bộ nhớ làm việc, do đó khó đọc thẳng hơn.
Thomas Owens

0

Tôi không biết về bất kỳ số liệu tốt hiện có nào về tính đơn giản của mã (điều đó không có nghĩa là chúng không tồn tại - chỉ là tôi không biết về chúng). Tôi có thể đề xuất một số, có thể một số sẽ giúp:

  • Tính đơn giản của các tính năng ngôn ngữ được sử dụng: nếu ngôn ngữ có các tính năng có thể được coi là "nâng cao" và "đơn giản", bạn có thể đếm số lần xuất hiện của các tính năng nâng cao. Cách bạn định nghĩa "nâng cao" có thể chủ quan hơn một chút. Tôi cho rằng một số người có thể nói rằng điều này cũng giống như đo lường "sự thông minh" của một chương trình. Một ví dụ phổ biến: một số có thể nói rằng ?:toán tử phải là một tính năng "nâng cao", những người khác có thể không đồng ý. Tôi không biết việc viết một công cụ có thể kiểm tra việc này dễ đến mức nào.

  • Tính đơn giản của các cấu trúc trong chương trình: Bạn có thể đo số lượng tham số mà hàm sẽ chấp nhận. Nếu bạn có> n % của tất cả các hàm có tham số > m , bạn có thể chọn tính nó là không đơn giản, tùy thuộc vào cách bạn xác định nm (có thể n = 3 và m = 6?). Tôi nghĩ rằng có một số công cụ phân tích tĩnh có thể đo lường điều này - Tôi nghĩ rằng JTest chỉ đơn giản là các hàm được đo với các tham số > m .

  • Bạn có thể thử đếm số vòng lặp lồng nhau hoặc cấu trúc điều khiển. Điều này tôi nghĩ thực sự không phải là một số liệu tồi và tôi nghĩ rằng có một cái tên cho nó (không thể nhớ ra khỏi đỉnh đầu của tôi). Một lần nữa, tôi nghĩ rằng có những công cụ (một lần nữa, như JTest) có thể đo lường điều này, ở một mức độ.

  • Bạn có thể thử đo "khả năng tái cấu trúc". Nếu mã của bạn chứa nhiều đoạn mã có thể được cấu trúc lại nhưng không , có lẽ điều đó sẽ không đơn giản. Tôi cũng nhớ lại từ khi tôi làm việc với JTest rằng họ cũng đã cố gắng đo lường điều này, nhưng tôi nhớ rằng tôi thường không đồng ý với nó trong trường hợp này, vì vậy YMMV.

  • Bạn có thể thử đo số lớp giữa các phần khác nhau trong hệ thống của bạn. Ví dụ: có bao nhiêu đoạn mã khác nhau sẽ chạm vào dữ liệu xuất phát từ một biểu mẫu web trước khi nó được lưu trữ trong cơ sở dữ liệu? Đây có thể là một mẹo khó để đo lường chính xác ...


2
Tôi tin rằng # 3 được gọi là độ sâu khối. Nó cũng liên quan đến Độ phức tạp theo chu kỳ nếu có các cấu trúc điều khiển quyết định liên quan.
Thomas Owens

Không có lời giải thích downvote?
Thất vọngWithFormsDesigner

Không thể đồng ý với "tính đơn giản của các tính năng ngôn ngữ". Các tính năng nâng cao có mặt để đơn giản hóa mã. Chỉ sử dụng các tính năng cơ bản, đơn giản sẽ che khuất những gì mã thực sự đang làm, nó chắc chắn sẽ dẫn đến rò rỉ các lớp trừu tượng. Các tính năng ngôn ngữ nâng cao cho phép thể hiện mức độ trừu tượng cao hơn, khiến mã của bạn dày đặc hơn và dễ đọc hơn. Các tính năng nâng cao hơn mà bạn đang sử dụng (dĩ nhiên là khôn ngoan), càng tốt cho sự đơn giản. Chỉ cần so sánh một mã trong, giả sử, Matlab (thực sự là "nâng cao") với một mã Fortran tương tự chỉ được làm bằng các tính năng cơ bản.
SK-logic

Và tôi sẽ không đồng ý với một số số liệu lớp. Nếu bạn có thể làm một cái gì đó trong một tá các bước nhỏ và sạch hoặc trong một biến đổi xoắn, tốt hơn là thực hiện trong một số bước. Nhiều lớp đơn giản và tách biệt rõ ràng tốt hơn (và đơn giản hơn) so với một lớp xoắn đơn.
SK-logic

@ SK-logic: Tôi đoán tôi nên gọi đó là "sự thông minh", nó gần với ý tôi hơn. Tôi chỉ nói rằng những thứ như ?:là một vấn đề khi chúng được lồng 5 sâu. Đối với các lớp, các lớp được phân tách sạch sẽ tốt hơn một lớp phức tạp. Nhưng 7 lớp chủ yếu là dư thừa, khi chỉ cần 2 hoặc 3 là một điều tồi tệ.
Thất vọngWithFormsDesigner
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.