Tại sao nhiều nhà phát triển tin rằng hiệu suất, khả năng đọc và khả năng bảo trì không thể cùng tồn tại?


34

Trong khi trả lời câu hỏi này , tôi bắt đầu tự hỏi tại sao rất nhiều nhà phát triển tin rằng một thiết kế tốt không nên tính đến hiệu suất vì làm như vậy sẽ ảnh hưởng đến khả năng đọc và / hoặc khả năng bảo trì.

Tôi tin rằng một thiết kế tốt cũng sẽ được xem xét về hiệu suất tại thời điểm nó được viết và một nhà phát triển tốt với thiết kế tốt có thể viết một chương trình hiệu quả mà không ảnh hưởng xấu đến khả năng đọc hoặc bảo trì.

Mặc dù tôi thừa nhận rằng có những trường hợp cực đoan, tại sao nhiều nhà phát triển khẳng định một chương trình / thiết kế hiệu quả sẽ dẫn đến khả năng đọc kém và / hoặc khả năng bảo trì kém, và do đó hiệu suất không nên được xem xét thiết kế?


9
Sẽ gần như không thể lý giải về nó ở quy mô lớn, nhưng đối với các đoạn mã nhỏ thì điều đó là khá rõ ràng. Chỉ cần so sánh các phiên bản có thể đọc và hiệu quả của quicksort.
SK-logic

7
Mu. Bạn nên bắt đầu bằng cách hỗ trợ tuyên bố của mình rằng nhiều nhà phát triển nhấn mạnh rằng hiệu quả dẫn đến không thể nhận ra.
Peter Taylor

2
SK-logic: Theo tôi đó là một trong những phần tốt nhất trong tất cả các trang web trao đổi stackexchange, vì người ta có thể đặt câu hỏi rõ ràng, có thể khỏe mạnh mọi lúc mọi nơi. Những gì có thể rõ ràng với bạn có thể không rõ ràng với người khác, và ngược lại. :) Chia sẻ là quan tâm.
Andreas Johansson

2
@Justin, không. Đối với tôi, chủ đề đó dường như đoán trước một tình huống trong đó có một sự lựa chọn bắt buộc giữa mã hiệu quả hoặc mã duy trì. Người hỏi không nói rằng anh ta thường xuyên thấy mình trong tình huống đó như thế nào và những người trả lời dường như không thường xuyên ở trong tình huống đó.
Peter Taylor

2
-1 cho câu hỏi. Khi tôi đọc nó, tôi nghĩ rằng đây là một người đàn ông rơm để đuổi câu trả lời đúng duy nhất: "Bởi vì họ không sử dụng trăn."
Ingo

Câu trả lời:


38

Tôi nghĩ rằng những quan điểm như vậy thường là phản ứng đối với những nỗ lực tối ưu hóa sớm (vi mô) , vẫn còn phổ biến và thường gây hại nhiều hơn là tốt. Khi một người cố gắng chống lại những quan điểm như vậy, rất dễ rơi vào - hoặc ít nhất là trông giống như - cực đoan khác.

Tuy nhiên, với sự phát triển to lớn của tài nguyên phần cứng trong những thập kỷ gần đây, đối với hầu hết các chương trình được viết ngày nay, hiệu suất đã không còn là yếu tố hạn chế chính. Tất nhiên, người ta nên tính đến hiệu suất mong đợi và có thể đạt được trong giai đoạn thiết kế, để xác định các trường hợp khi hiệu suất có thể (đến) là một vấn đề lớn . Và sau đó, điều thực sự quan trọng là thiết kế cho hiệu suất ngay từ đầu. Tuy nhiên, tổng thể đơn giản, dễ đọc và bảo trì vẫn quan trọng hơn . Như những người khác lưu ý, mã tối ưu hóa hiệu suất phức tạp hơn, khó đọc và bảo trì hơn và dễ bị lỗi hơn so với giải pháp làm việc đơn giản nhất. Do đó, mọi nỗ lực dành cho tối ưu hóa phải được chứng minh - không chỉ tin tưởng- để mang lại lợi ích thực sự, trong khi làm giảm khả năng duy trì lâu dài của chương trình càng ít càng tốt. Vì vậy, một thiết kế tốt sẽ tách biệt các phần phức tạp, hiệu năng cao với phần còn lại của mã , được giữ đơn giản và sạch sẽ nhất có thể.


8
"Khi một người cố gắng chống lại những quan điểm như vậy, rất dễ rơi vào - hoặc ít nhất là trông giống như - cực đoan khác" Tôi luôn gặp vấn đề với mọi người khi nghĩ rằng tôi giữ quan điểm ngược lại khi tôi chỉ cân bằng các ưu điểm với nhược điểm Không chỉ trong lập trình, trong mọi thứ.
jhocking

1
Tôi phát ngán với việc mọi người thảo luận về điều này đến nỗi tôi tức giận và cực đoan ..
Thomas Bonini

Đã có một số phản hồi tốt, nhưng tôi nghĩ rằng bạn đã nỗ lực hết sức để chi tiết về nguồn gốc của tâm lý này. Cảm ơn mọi người tham gia!
justin

Câu trả lời của tôi ... hầu hết các nhà phát triển đều kém trong công việc của họ
TheCatWhisperer

38

Đến với câu hỏi của bạn từ phía một nhà phát triển làm việc về mã hiệu suất cao, có một số điều cần xem xét trong thiết kế.

  • Đừng quá sớm bi quan. Khi bạn có sự lựa chọn giữa hai thiết kế có độ phức tạp bằng nhau, hãy chọn một thiết kế có các đặc tính hiệu suất tốt nhất. Một trong những ví dụ nổi tiếng của C ++ là sự phổ biến của việc tăng sau các bộ đếm (hoặc các vòng lặp) trong các vòng lặp. Đây là một sự bi quan sớm hoàn toàn không cần thiết mà CÓ THỂ không làm bạn mất bất cứ thứ gì, nhưng nó MIGHT, vì vậy đừng làm điều đó.
  • Trong nhiều trường hợp, bạn không có kinh doanh để đi bất cứ nơi nào gần tối ưu hóa vi mô. Tối ưu hóa thuật toán là một loại trái cây treo thấp hơn và hầu như luôn dễ hiểu hơn rất nhiều so với tối ưu hóa thực sự ở mức độ thấp.
  • Nếu và CHỈ nếu hiệu suất là cực kỳ quan trọng, bạn sẽ xuống và bẩn. Trên thực tế, bạn cô lập mã nhiều nhất có thể trước tiên và THÌ bạn xuống và bẩn. Và nó trở nên thực sự bẩn thỉu ở đó, với các sơ đồ bộ đệm, đánh giá lười biếng, tối ưu hóa bố cục bộ nhớ cho bộ nhớ đệm, các khối nội tại hoặc lắp ráp, lớp mẫu trên lớp, v.v. làm tổn thương nếu bạn phải thực hiện bất kỳ bảo trì nào trong mã này, nhưng bạn phải làm vì hiệu suất là cực kỳ quan trọng. Chỉnh sửa: Nhân tiện, tôi không nói mã này không thể đẹp và nó phải đẹp như có thể, nhưng nó vẫn sẽ rất phức tạp và thường bị sai lệch so với mã ít được tối ưu hóa.

Làm cho đúng, làm cho nó đẹp, làm cho nó nhanh chóng. Theo thứ tự đó.


Tôi thích quy tắc của ngón tay cái: 'làm cho nó đẹp, làm cho nó nhanh. Theo thứ tự đó '. Tôi sẽ bắt đầu sử dụng nó.
Martin York

Chính xác. Và cô lập mã ở điểm thứ ba, càng nhiều càng tốt. Bởi vì khi bạn chuyển sang phần cứng khác, thậm chí một thứ nhỏ như bộ xử lý có kích thước bộ đệm khác, những thứ này có thể thay đổi.
KeithB

@KeithB - ​​bạn đưa ra một quan điểm tốt, tôi sẽ thêm nó vào câu trả lời của tôi.
Joris Timmermans

+1: "Làm cho đúng, làm cho đẹp, làm cho nhanh. Theo thứ tự đó." Tóm tắt rất hay, mà tôi đồng ý 90%. Đôi khi tôi chỉ có thể sửa một số lỗi nhất định (hiểu đúng) khi tôi thấy nó đẹp (và dễ hiểu hơn).
Giorgio

+1 cho "Không sớm bi quan". Lời khuyên để tránh tối ưu hóa sớm là không được phép sử dụng các thuật toán xương đầu. Nếu bạn đang viết Java và bạn có một bộ sưu tập bạn sẽ gọi containsrất nhiều, hãy sử dụng một HashSet, không phải một ArrayList. Hiệu suất có thể không quan trọng, nhưng không có lý do gì để không. Khai thác sự phù hợp giữa thiết kế tốt và hiệu suất - nếu xử lý một số bộ sưu tập, hãy cố gắng thực hiện mọi thứ trong một lần duy nhất, điều này có thể sẽ dễ đọc hơn và nhanh hơn (có thể).
Tom Anderson

16

Nếu tôi có thể đoán là "mượn" sơ đồ đẹp của @ greengit và thực hiện một bổ sung nhỏ:

|
P
E
R
F
O  *               X <- a program as first written
R   * 
M    *
A      *
N        *
C          *  *   *  *  *
E
|
O -- R E A D A B I L I T Y --

Tất cả chúng ta đều được "dạy" rằng có những đường cong đánh đổi. Ngoài ra, tất cả chúng ta đều cho rằng chúng ta là những lập trình viên tối ưu đến mức bất kỳ chương trình cụ thể nào chúng ta viết đều quá chặt chẽ trên đường cong . Nếu một chương trình nằm trên đường cong, bất kỳ cải tiến nào trong một chiều nhất thiết phải chịu một chi phí ở chiều khác.

Theo kinh nghiệm của tôi, các chương trình chỉ đến gần bất kỳ đường cong nào bằng cách điều chỉnh, tinh chỉnh, búa, sáp và nói chung được chuyển thành "mã golf". Hầu hết các chương trình có nhiều chỗ để cải thiện trong tất cả các chiều. Ý tôi là đây.


Cá nhân tôi nghĩ rằng có một kết thúc khác của đường cong nơi nó đi lên một lần nữa ở phía bên tay phải (miễn là bạn di chuyển đủ xa về bên phải (có thể có nghĩa là nghĩ lại thuật toán của bạn)).
Martin York

2
+1 cho "Hầu hết các chương trình có nhiều chỗ để cải thiện về mọi mặt."
Steven

5

Chính xác bởi vì các thành phần phần mềm hiệu suất cao thường là các đơn đặt hàng có độ lớn phức tạp hơn các thành phần phần mềm khác (tất cả những thứ khác đều bằng nhau).

Ngay cả khi đó không phải là cắt giảm rõ ràng, nếu các số liệu hiệu suất là một yêu cầu cực kỳ quan trọng thì điều bắt buộc là thiết kế phải phức tạp để đáp ứng các yêu cầu đó. Điều nguy hiểm là một nhà phát triển lãng phí nước rút vào một tính năng tương đối đơn giản khi cố gắng vắt thêm vài mili giây ra khỏi thành phần của mình.

Bất kể, sự phức tạp của thiết kế có mối tương quan trực tiếp với khả năng của nhà phát triển nhanh chóng học hỏi và làm quen với thiết kế như vậy, và sửa đổi thêm chức năng trong một thành phần phức tạp có thể dẫn đến các lỗi không thể bị bắt bởi các bài kiểm tra đơn vị. Các thiết kế phức tạp có nhiều khía cạnh hơn và các trường hợp thử nghiệm khả thi để xem xét thực hiện mục tiêu bao phủ 100% đơn vị thử nghiệm thậm chí nhiều hơn một giấc mơ ống.

Với điều đó đã được lưu ý rằng một thành phần phần mềm hoạt động kém có thể hoạt động kém chỉ vì nó được viết một cách ngu ngốc và phức tạp không cần thiết dựa trên sự thiếu hiểu biết của tác giả ban đầu, (thực hiện 8 cuộc gọi cơ sở dữ liệu để xây dựng một thực thể duy nhất khi chỉ một người sẽ làm , mã hoàn toàn không cần thiết dẫn đến một đường dẫn mã bất kể, v.v ...) Những trường hợp này là vấn đề cải thiện chất lượng mã và tăng hiệu suất xảy ra do hậu quả của bộ tái cấu trúc và KHÔNG nhất thiết là hậu quả mong muốn.

Tuy nhiên, giả sử một thành phần được thiết kế tốt, nó sẽ luôn ít phức tạp hơn một thành phần được thiết kế tương tự được điều chỉnh cho hiệu suất (tất cả những thứ khác đều bằng nhau).


3

Nó không quá nhiều đến nỗi những thứ đó không thể cùng tồn tại. Vấn đề là mã của mọi người chậm, không thể đọc được và không thể nhận biết được trong lần lặp đầu tiên. Thời gian còn lại dành cho việc cải thiện bất cứ điều gì quan trọng nhất. Nếu đó là hiệu suất, sau đó đi cho nó. Đừng viết mã khủng khiếp, nhưng nếu nó phải là X nhanh, thì hãy làm cho X nhanh. Tôi tin rằng hiệu suất và sự sạch sẽ về cơ bản là không tương thích. Mã biểu diễn không gây ra mã xấu. Tuy nhiên, nếu bạn dành thời gian để điều chỉnh từng bit mã một cách nhanh chóng, hãy đoán xem bạn đã không dành thời gian để làm gì? Làm cho mã của bạn sạch sẽ và có thể bảo trì.


2
    |
    P
    E
    R
    F
    Ôi *
    R * 
    M *
    Một *
    N *
    C * * * * *
    E
    |
    O - S READN SÀNG -

Bạn có thể thấy...

  • Hy sinh khả năng đọc có thể tăng hiệu suất - nhưng chỉ rất nhiều. Sau một thời điểm nhất định, bạn phải dùng đến "thực" nghĩa là giống như các thuật toán và phần cứng tốt hơn.
  • Ngoài ra, mất hiệu suất với chi phí dễ đọc chỉ có thể xảy ra ở một mức độ nào đó. Sau đó, bạn có thể làm cho chương trình của bạn có thể đọc được nhiều như bạn muốn mà không ảnh hưởng đến hiệu suất. Ví dụ: thêm nhiều bình luận hữu ích không hiệu suất thu phí.

Vì vậy, hiệu suất và khả năng đọc có liên quan khiêm tốn - và trong hầu hết các trường hợp, không có ưu đãi lớn thực sự nào thích cái trước hơn cái sau. Và tôi đang nói ở đây về các ngôn ngữ cấp cao.


1

Theo tôi hiệu suất nên được xem xét khi nó là một vấn đề thực tế (hoặc ví dụ như một yêu cầu). Không làm như vậy có xu hướng dẫn đến vi mô hóa, điều này có thể dẫn đến mã bị xáo trộn nhiều hơn chỉ để tiết kiệm một vài micro giây ở đây và ở đó, từ đó dẫn đến mã ít được bảo trì và ít đọc hơn. Thay vào đó, người ta nên tập trung vào các nút thắt thực sự của hệ thống, nếu cần và nhấn mạnh vào hiệu suất ở đó.


1

Điểm không dễ đọc nên luôn luôn hiệu quả. Nếu bạn biết rằng thuật toán của bạn cần phải có hiệu quả cao, thì đó sẽ là một trong những yếu tố bạn sử dụng để phát triển nó.

Vấn đề là hầu hết các trường hợp sử dụng không cần mã nhanh. Trong nhiều trường hợp IO hoặc tương tác người dùng gây ra nhiều độ trễ hơn thì việc thực thi thuật toán của bạn gây ra. Vấn đề là bạn không nên đi ra ngoài để làm cho một số thứ hiệu quả hơn nếu bạn không biết đó là cổ chai.

Tối ưu hóa mã cho hiệu suất thường làm cho nó phức tạp hơn bởi vì nó thường liên quan đến việc thực hiện mọi thứ một cách thông minh, thay vì trực quan nhất. Mã phức tạp hơn khó bảo trì hơn và khó hơn cho các nhà phát triển khác để nhận (cả hai đều là chi phí phải được xem xét). Đồng thời, trình biên dịch rất tốt trong việc tối ưu hóa các trường hợp phổ biến. Có thể việc bạn cố gắng cải thiện một trường hợp phổ biến có nghĩa là trình biên dịch không nhận ra mẫu đó nữa và do đó không thể giúp bạn thực hiện mã của mình nhanh. Cần lưu ý rằng điều này không có nghĩa là viết bất cứ điều gì bạn muốn mà không quan tâm đến hiệu suất. Bạn không nên làm bất cứ điều gì rõ ràng là không hiệu quả.

Vấn đề là không lo lắng về những điều nhỏ nhặt có thể làm cho mọi thứ tốt hơn. Sử dụng một hồ sơ và thấy rằng 1) những gì bạn có bây giờ là một vấn đề và 2) những gì bạn đã thay đổi nó là một cải tiến.


1

Tôi nghĩ rằng hầu hết các lập trình viên đều có cảm giác như vậy đơn giản bởi vì hầu hết thời gian, mã hiệu suất là mã dựa trên nhiều thông tin hơn (về bối cảnh, kiến ​​thức phần cứng, kiến ​​trúc toàn cầu) so với bất kỳ mã nào khác trong các ứng dụng. Hầu hết các mã sẽ chỉ thể hiện một số giải pháp cho các vấn đề cụ thể được gói gọn trong một số khái niệm trừu tượng theo cách mô đun (như các hàm) và điều đó có nghĩa là giới hạn kiến ​​thức về bối cảnh chỉ nhập những gì được đóng gói (như tham số hàm).

Khi bạn viết cho hiệu suất cao, sau khi bạn sửa bất kỳ tối ưu hóa thuật toán nào, bạn sẽ nhận được các chi tiết đòi hỏi nhiều kiến ​​thức hơn về bối cảnh. Điều đó có thể tự nhiên áp đảo bất kỳ lập trình viên nào không cảm thấy đủ tập trung cho nhiệm vụ.


1

Bởi vì chi phí cho sự nóng lên toàn cầu (từ các chu kỳ CPU bổ sung được tăng lên bởi hàng trăm triệu PC cộng với các cơ sở trung tâm dữ liệu lớn) và thời lượng pin tầm thường (trên thiết bị di động của người dùng), do yêu cầu chạy mã tối ưu kém của họ, hiếm khi xuất hiện trên hầu hết hiệu suất của lập trình viên hoặc đánh giá ngang hàng.

Đó là một ngoại ứng tiêu cực về kinh tế, tương tự như một hình thức ô nhiễm bị bỏ qua. Vì vậy, tỷ lệ chi phí / lợi ích của suy nghĩ về hiệu suất hoàn toàn bị lệch khỏi thực tế.

Các nhà thiết kế phần cứng đã làm việc chăm chỉ để thêm tính năng tiết kiệm năng lượng và mở rộng xung nhịp cho các CPU mới nhất. Các lập trình viên tùy thuộc vào việc để phần cứng tận dụng các khả năng này thường xuyên hơn, bằng cách không nhai lại mọi chu kỳ xung nhịp CPU có sẵn.

THÊM: Quay lại thời cổ đại, chi phí cho một máy tính là hàng triệu, vì vậy tối ưu hóa thời gian CPU là rất quan trọng. Sau đó, chi phí phát triển và duy trì mã trở nên lớn hơn chi phí của máy tính, do đó tối ưu hóa không được ưu tiên so với năng suất của lập trình viên. Tuy nhiên, bây giờ, một chi phí khác đang trở nên lớn hơn chi phí cho máy tính, chi phí cung cấp năng lượng và làm mát cho tất cả các trung tâm dữ liệu đó hiện đang trở nên lớn hơn chi phí của tất cả các bộ xử lý bên trong.


Ngoài câu hỏi nếu PC đóng góp vào sự nóng lên toàn cầu, ngay cả khi đó là sự thật: Đó là một lời ngụy biện, rằng hiệu quả năng lượng nhiều hơn dẫn đến nhu cầu năng lượng ít hơn. Hầu như điều ngược lại là đúng, như có thể thấy từ ngày đầu tiên một PC xuất hiện trên thị trường. Trước đó, một số Mainframe hàng trăm hoặc hàng năm (mỗi cái hầu như được trang bị nhà máy điện riêng của họ) sử dụng ít năng lượng hơn ngày nay, trong đó 1 phút CPU tính toán nhiều hơn so với nhu cầu năng lượng và chi phí. Tuy nhiên, tổng nhu cầu năng lượng cho máy tính cao hơn trước.
Ingo

1

Tôi nghĩ thật khó để đạt được cả ba. Hai tôi nghĩ có thể khả thi. Ví dụ, tôi nghĩ rằng có thể đạt được hiệu quả và khả năng đọc trong một số trường hợp, nhưng khả năng bảo trì có thể khó với mã điều chỉnh vi mô. Mã hiệu quả nhất trên hành tinh nói chung sẽ thiếu cả khả năng bảo trì và khả năng đọc vì có lẽ là điều hiển nhiên đối với hầu hết, trừ khi bạn là loại có thể hiểu được mã SIMD đa luồng, đa luồng mà Intel viết bằng cách lắp ráp nội tuyến hoặc cắt nhiều nhất thuật toán -edge được sử dụng trong ngành công nghiệp với các bài báo toán học dài 40 trang chỉ được xuất bản 2 tháng trước và 12 thư viện có giá trị mã cho một cấu trúc dữ liệu cực kỳ phức tạp.

Hiệu quả vi mô

Một điều tôi muốn đề xuất có thể trái với ý kiến ​​phổ biến là mã thuật toán thông minh nhất thường khó bảo trì hơn thuật toán đơn giản được điều chỉnh vi mô nhất. Ý tưởng này cho thấy các cải tiến về khả năng mở rộng mang lại nhiều lợi ích hơn cho mã vi điều chỉnh (ví dụ: các mẫu truy cập thân thiện với bộ đệm, đa luồng, SIMD, v.v.) là điều tôi thách thức, ít nhất là đã làm việc trong một ngành công nghiệp đầy phức tạp cấu trúc dữ liệu và thuật toán (ngành công nghiệp FX trực quan), đặc biệt là trong các lĩnh vực như xử lý lưới, bởi vì tiếng nổ có thể rất lớn nhưng rất tốn kém khi bạn giới thiệu các thuật toán và cấu trúc dữ liệu mới mà chưa ai từng nghe thấy trước đây vì chúng là thương hiệu Mới. Tôi thêm nữa'

Vì vậy, ý tưởng này cho rằng tối ưu hóa thuật toán luôn luôn át chủ bài, tối ưu hóa liên quan đến các mẫu truy cập bộ nhớ luôn là điều tôi không hoàn toàn đồng ý. Tất nhiên, nếu bạn đang sử dụng một loại bong bóng, không có lượng tối ưu hóa vi mô nào có thể giúp bạn ở đó ... nhưng trong lý do, tôi không nghĩ rằng nó luôn luôn rõ ràng như vậy. Và tối ưu hóa thuật toán được cho là khó bảo trì hơn tối ưu hóa vi mô. Tôi thấy việc bảo trì dễ dàng hơn nhiều, giả sử, Embree của Intel sử dụng thuật toán BVH cổ điển và đơn giản và chỉ điều chỉnh các crap ra khỏi nó so với mã OpenVDB của Dreamwork để cải tiến thuật toán mô phỏng chất lỏng tiên tiến. Vì vậy, trong ngành của tôi ít nhất, tôi muốn thấy nhiều người quen thuộc hơn với kiến ​​trúc máy tính tối ưu hóa vi mô hơn, như Intel có khi họ bước vào hiện trường, trái ngược với việc đưa ra hàng ngàn và hàng ngàn thuật toán và cấu trúc dữ liệu mới. Với tối ưu hóa vi mô hiệu quả, mọi người có thể tìm thấy ngày càng ít lý do để phát minh ra các thuật toán mới.

Tôi đã làm việc trong một cơ sở mã di sản trước đây khi mà hầu hết mọi thao tác của người dùng đều có cấu trúc dữ liệu và thuật toán riêng biệt đằng sau nó (thêm tới hàng trăm cấu trúc dữ liệu kỳ lạ). Và hầu hết trong số họ có đặc điểm hiệu suất rất sai lệch, được áp dụng rất hẹp. Sẽ dễ dàng hơn nhiều nếu hệ thống có thể xoay quanh vài chục cấu trúc dữ liệu được áp dụng rộng rãi hơn và tôi nghĩ đó có thể là trường hợp nếu chúng được tối ưu hóa vi mô tốt hơn nhiều. Tôi đề cập đến trường hợp này bởi vì tối ưu hóa vi mô có khả năng cải thiện khả năng bảo trì rất lớn trong trường hợp như vậy nếu điều đó có nghĩa là sự khác biệt giữa hàng trăm cấu trúc dữ liệu vi mô hóa thậm chí không thể được sử dụng một cách an toàn cho các mục đích chỉ đọc nghiêm ngặt liên quan đến lỗi bộ nhớ cache và đúng so với

Ngôn ngữ chức năng

Trong khi đó, một số mã có thể bảo trì nhất mà tôi từng gặp là hiệu quả hợp lý nhưng cực kỳ khó đọc, vì chúng được viết bằng các ngôn ngữ chức năng. Nói chung, khả năng đọc và khả năng duy trì uber là những ý tưởng mâu thuẫn trong quan điểm của tôi.

Thật sự rất khó để làm cho mã có thể đọc được, có thể duy trì và hiệu quả cùng một lúc. Thông thường, bạn phải thỏa hiệp một chút trong một trong ba điều đó, nếu không phải là hai, như thỏa hiệp khả năng đọc để duy trì hoặc thỏa hiệp khả năng duy trì để đạt hiệu quả. Đó thường là khả năng duy trì mà bạn phải chịu đựng khi bạn tìm kiếm nhiều thứ khác.

Khả năng đọc so với khả năng bảo trì

Bây giờ như đã nói, tôi tin rằng khả năng đọc và bảo trì không phải là khái niệm hài hòa. Xét cho cùng, mã dễ đọc nhất đối với hầu hết mọi người trong chúng ta ánh xạ rất trực quan đến các kiểu suy nghĩ của con người và các kiểu suy nghĩ của con người vốn dễ bị lỗi: " Nếu điều này xảy ra, hãy làm điều này. Nếu điều đó xảy ra, hãy làm điều đó. , Tôi đã quên một cái gì đó! Nếu các hệ thống này tương tác với nhau, điều này sẽ xảy ra để hệ thống này có thể làm điều này ... oh chờ đã, còn hệ thống đó khi sự kiện này được kích hoạt thì sao?"Tôi đã quên câu trích dẫn chính xác nhưng ai đó đã từng nói rằng nếu Rome được xây dựng giống như phần mềm, nó sẽ chỉ lấy một con chim đậu trên tường để hạ nó xuống. Đó là trường hợp của hầu hết các phần mềm. Nó dễ vỡ hơn chúng ta thường quan tâm Một vài dòng mã dường như vô hại ở đây và có thể khiến nó dừng lại ở điểm khiến chúng ta phải xem xét lại toàn bộ thiết kế, và các ngôn ngữ cấp cao nhằm mục đích dễ đọc nhất có thể không phải là ngoại lệ đối với các lỗi thiết kế của con người như vậy .

Các ngôn ngữ chức năng thuần túy gần như không thể bị ảnh hưởng bởi điều này mà người ta có thể có được một cách khả thi (thậm chí không gần với bất khả xâm phạm, nhưng tương đối gần hơn nhiều so với hầu hết). Và đó là một phần vì họ không lập bản đồ trực giác với suy nghĩ của con người. Chúng không thể đọc được. Họ ép buộc các kiểu suy nghĩ theo chúng ta, điều khiến chúng ta phải giải quyết các vấn đề với càng ít trường hợp đặc biệt càng tốt bằng cách sử dụng lượng kiến ​​thức tối thiểu có thể và không gây ra bất kỳ tác dụng phụ nào. Chúng cực kỳ trực giao, chúng cho phép mã thường được thay đổi và thay đổi mà không gây ngạc nhiên đến mức chúng ta phải suy nghĩ lại về thiết kế trên bảng vẽ, thậm chí đến mức thay đổi suy nghĩ về thiết kế tổng thể, mà không cần viết lại mọi thứ. Nó dường như không dễ bảo trì hơn thế ... nhưng mã vẫn rất khó đọc,


1
"Hiệu quả vi mô" giống như nói "Không có quyền truy cập bộ nhớ O (1)"
Caleth

0

Một vấn đề là thời gian nhà phát triển hữu hạn có nghĩa là bất cứ điều gì bạn tìm cách tối ưu hóa đều lấy đi thời gian dành cho các vấn đề khác.

Có một thử nghiệm khá tốt được thực hiện trên tài liệu này được tham chiếu trong Hoàn thành mã của Meyer. Các nhóm nhà phát triển khác nhau được yêu cầu tối ưu hóa tốc độ, sử dụng bộ nhớ, khả năng đọc, độ mạnh và vv. Nó đã được tìm thấy rằng các dự án của họ đạt điểm cao trong bất cứ điều gì họ được yêu cầu để tối ưu hóa, nhưng thấp hơn trong tất cả các phẩm chất khác.


Rõ ràng là bạn có thể dành nhiều thời gian hơn nhưng cuối cùng bạn bắt đầu đặt câu hỏi tại sao các nhà phát triển lại dành thời gian cho các emac lập trình để bày tỏ tình yêu dành cho con cái của họ, và tại thời điểm đó, về cơ bản bạn là Sheldon từ Lý thuyết Big Bang
deworde

0

Bởi vì các lập trình viên có kinh nghiệm đã học được rằng đó là sự thật.

Chúng tôi đã làm việc với mã gọn và có nghĩa và không có vấn đề về hiệu năng.

Chúng tôi đã làm việc với rất nhiều mã rằng, để giải quyết các vấn đề về hiệu năng là RẤT phức tạp.

Một ví dụ ngay lập tức xuất hiện là dự án cuối cùng của tôi bao gồm 8.192 bảng SQL được phân tách thủ công. Điều này là cần thiết vì các vấn đề hiệu suất. Việc thiết lập để chọn từ 1 bảng đơn giản hơn nhiều so với việc chọn và duy trì 8.192 phân đoạn.


0

Ngoài ra còn có một số đoạn mã nổi tiếng được tối ưu hóa cao sẽ uốn cong hầu hết bộ não của mọi người hỗ trợ cho trường hợp mã được tối ưu hóa cao rất khó đọc và khó hiểu.

Đây là nổi tiếng nhất tôi nghĩ. Lấy từ Đấu trường Quake III và được gán cho John Carmak, mặc dù tôi nghĩ rằng đã có một vài lần lặp lại chức năng này và ban đầu nó không được tạo ra bởi anh ta ( không phải Wikipedia rất tuyệt sao? ).

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
    //      y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}
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.