Có phải hội nghị trên cấu hình không phải là vi phạm các nguyên tắc lập trình cơ bản?


51

Tôi đã xem xét khung công tác MVVM của WPF Caliburn.Micro và đọc rằng rất nhiều điều tiêu chuẩn được dựa trên các quy ước đặt tên .

Ví dụ: tự động liên kết các thuộc tính trong Chế độ xem thành thuộc tính trong ViewModel. Mặc dù điều này có vẻ thuận tiện (loại bỏ một số mã soạn sẵn), nhưng phản ứng bản năng đầu tiên của tôi là nó không hoàn toàn rõ ràng đối với một lập trình viên mới sẽ đọc mã này. Nói cách khác, chức năng của ứng dụng không hoàn toàn được giải thích bằng mã riêng của nó, mà còn bằng tài liệu của khung.

BIÊN TẬP:

Vì vậy, cách tiếp cận này được gọi là quy ước về cấu hình. Vì tôi không thể tìm thấy bất kỳ câu hỏi nào liên quan đến điều này, tôi đã thay đổi câu hỏi của mình:

Câu hỏi của tôi là:

Là quy ước về cấu hình là một cách chính xác để đơn giản hóa mọi thứ, hay nó vi phạm một số nguyên tắc lập trình (và nếu có, đó là những nguyên tắc nào)?


8
Hầu hết các cách tiếp cận / nguyên tắc vi phạm một số cách tiếp cận / nguyên tắc khác ở một mức độ nào đó. Đây chủ yếu là vấn đề ưu tiên và đánh đổi.
Joachim Sauer

1
Đúng, nhưng tôi thấy sự khác biệt được nêu trong câu hỏi của tôi hơi kỳ lạ, và do đó tôi quan tâm đến sự đánh đổi cụ thể và có thể vi phạm các nguyên tắc khi sử dụng quy ước về cấu hình.
Geerten

Khái niệm về truy xuất nguồn gốc phần mềm có liên quan ở đây. Các lập trình viên dựa vào các công cụ như grep, nhưng cần các công cụ tốt hơn để theo dõi việc sử dụng mã được tạo. Ví dụ, các công cụ nên làm rõ hơn rằng lớp "id-id" của css có liên quan đến phương thức được tạo getUserId () và cột bảng user_id.
Macneil

Câu trả lời:


49

Tôi không coi "một ứng dụng nên được giải thích đầy đủ bằng chính mã của nó" là một nguyên tắc lập trình cơ bản. Có rất nhiều điều không được giải thích bằng cách chỉ nhìn vào mã của một ứng dụng. Ngoài việc biết những điều cơ bản của chính ngôn ngữ lập trình (cú pháp và ngữ nghĩa), bạn cần biết các quy ước. Nếu một mã định danh trong Java bắt đầu bằng chữ in hoa, thì đó là một loại. Có rất nhiều quy ước bạn cần biết.

Quy ước về cấu hình là về việc giảm số lượng quyết định mà lập trình viên phải đưa ra về mọi thứ. Đối với một số điều, điều này là hiển nhiên - không ai có thể nghĩ rằng có một ngôn ngữ trong đó viết hoa các loại là thứ bạn cần khai báo ở đầu chương trình của bạn - nhưng đối với những thứ khác thì không rõ ràng lắm.

Cân bằng quy ước và cấu hình là một nhiệm vụ khó khăn. Quá nhiều quy ước có thể làm cho mã khó hiểu (ví dụ: lấy các biến ẩn của Perl). Quá nhiều tự do về phía lập trình viên có thể làm cho các hệ thống trở nên khó hiểu, vì kiến ​​thức thu được từ một hệ thống hiếm khi hữu ích khi nghiên cứu hệ thống khác.

Một ví dụ điển hình về nơi quy ước hỗ trợ lập trình viên khi viết các trình cắm thêm Eclipse. Khi nhìn vào một plugin tôi chưa từng thấy, tôi biết ngay nhiều điều về nó. Danh sách các phụ thuộc nằm trong MANIFEST.MF, các điểm mở rộng nằm trong plugin.xml, mã nguồn nằm dưới "src", v.v. Nếu những điều này tùy thuộc vào lập trình viên, thì mỗi plugin Eclipse sẽ khác nhau và việc điều hướng mã sẽ khó khăn hơn nhiều.


4
+1: phát triển phần mềm đủ phức tạp. Nếu bạn có thể tránh sự phức tạp trong những thứ bạn có quyền kiểm soát, hãy làm như vậy. Tiết kiệm sự phức tạp cho những nơi bạn thực sự cần nó.
Scrwtp

1
Cảm ơn đã giải thích rõ ràng về sự khác biệt và cân bằng.
Geerten

3
"Nếu một mã định danh trong Java bắt đầu bằng chữ in hoa, thì đó là một loại." - cho dù đó là một loại phụ thuộc vào ngữ cảnh cú pháp không phụ thuộc vào mẫu đặt tên, các quy ước đặt tên Java không ảnh hưởng đến 'cấu hình biên dịch'. Bạn có chắc chắn đó là một ví dụ hợp lệ? Ví dụ cuối cùng cũng không đúng - đó là về "quy ước cấu hình" chứ không phải "quy ước về cấu hình". Bạn đang nói những điều đúng nhưng chúng ít liên quan đến nguyên tắc subj.
Den

4
Đừng bao quát các ví dụ, chúng chỉ là ví dụ. Cái đầu tiên chỉ là một ví dụ về một quy ước, cái cuối cùng là một ví dụ trong đó quy ước là một điều tốt. Ví dụ Perl là một ví dụ trong đó có quá nhiều quy ước (ẩn ý) là một điều xấu (IMO, tôi nên thêm vào).
JesperE

1
Điều tôi ghét là khi quy ước về cấu hình trở thành quy ước mà không có cấu hình ... trong trường hợp sau, bạn có xu hướng bị mắc kẹt với một cơ sở mã, khó có thể tích hợp với các công cụ khác.
Andy

77

Đã cho +1 vào @JesperE và muốn thêm một cái gì đó:

nó có vi phạm một số nguyên tắc lập trình không

Có, "quy ước về cấu hình" vi phạm nguyên tắc "rõ ràng là tốt hơn ngầm định" (ví dụ, hãy xem "Zen-Of-Python" ).

Mặt khác, "cấu hình trên quy ước" ngược lại có xu hướng vi phạm "Đơn giản là tốt hơn phức tạp" và tệ hơn, nó vi phạm nguyên tắc DRY theo cách tinh tế, vì bạn cần lặp lại các tên được sử dụng trong mã của bạn trong cấu hình của bạn .


4
Đó là câu trả lời trực tiếp nhất cho câu hỏi!
Joachim Sauer

Đây là câu trả lời đúng thực tế trong số hai câu trả lời nhất.
Den

+1 cho "rõ ràng là tốt hơn ngầm"
Justin Ohms

12
Phần yêu thích của tôi về câu trả lời này là nó hoàn toàn làm nổi bật thực tế hơn các nguyên tắc phát triển phần mềm tốt thường gây căng thẳng với nhau. Kỹ thuật là về việc cân bằng những căng thẳng đó một cách thích hợp cho bối cảnh và ứng dụng cụ thể của bạn.
Chris Krycho

Câu trả lời tốt. Để mở rộng nhận xét của @Chris Krycho, điều tuyệt vời về các tiêu chuẩn hoặc nguyên tắc phần mềm là bạn có rất nhiều lựa chọn. :-)
user949300 3/03/2015

9

Một số "quy ước về cấu hình" chỉ thực hiện theo mặc định hợp lý. Bạn chỉ nên cấu hình một cái gì đó để sử dụng nó cho mục đích không chuẩn. Tôi phải so sánh Struts với Rails ở đây. Trong Rails, bạn phải đặt "hành động / màn hình" của mình vào một thư mục và sau đó chúng chỉ hoạt động. Trong Struts, bạn vẫn phải đặt chúng vào một thư mục, nhưng bạn cũng phải đưa ra một tên hành động VÀ một tệp tin VÀ một tên biểu mẫu VÀ một biểu mẫu và xác định cách ba thứ này hoạt động cùng nhau trong Struts-config. xml VÀ chỉ định rằng biểu mẫu thuộc về yêu cầu (RESTful). Nếu điều đó là không đủ, ánh xạ biểu mẫu / biểu mẫu-bean có phần riêng trong Struts-config, sau đó được ánh xạ độc lập với phần hành động trong cùng một tệp và tất cả đều dựa vào các chuỗi viết tay trong tệp JSP để hoạt động đúng cách Đối với mỗi màn hình, đó là ít nhất 6 điều bạn không nên làm và càng nhiều cơ hội để gây ra lỗi. Tôi nghĩ rằng bạn có thể thiết lập hầu hết hoặc tất cả những thứ đó theo cách thủ công trong Rails nếu bạn cần, nhưng 2/3 thời gian phát triển của Struts được đưa lên để xây dựng và duy trì các lớp phức tạp không cần thiết.

Nói một cách công bằng, Struts 1 được thiết kế khi mọi người chuyển các ứng dụng giữa máy tính để bàn và web. Tính linh hoạt mà Struts đã tạo ra giúp nó phù hợp với mọi thứ mà Rails làm, cộng với mọi thứ mà một ứng dụng máy tính để bàn sẽ cần. Thật không may, hàng núi cấu hình cho phép sự linh hoạt đó là một quả bóng và chuỗi khổng lồ cho một người chỉ cần viết một ứng dụng web hoặc chỉ một ứng dụng máy tính để bàn.

Tôi đã làm việc ở đâu đó rằng họ đã thực hiện bước tiếp theo và lập luận, "Cấu hình trên " nhưng đã thấy điều đó đến mức cực kỳ logic của nó, kết quả là cấu hình trở thành một ngôn ngữ mã hóa mới. Đó là một trò chơi vỏ mà sự phức tạp được đẩy xung quanh mà không được thuần hóa theo bất kỳ cách quan trọng nào. Và nó đã cho tôi một sự đánh giá cao đối với tất cả các loại kiểm tra kiểu và các lưới an toàn khác mà một ngôn ngữ lập trình được thiết kế tốt có. Một số định dạng tệp cấu hình nửa nướng mà không có thông báo lỗi nếu bạn thêm dấu cách hoặc dấu nháy đơn KHÔNG phải là một cải tiến đối với ngôn ngữ lập trình chất lượng có bộ công cụ chỉnh sửa và trình biên dịch chất lượng được viết cho nó.

Tôi không thể tưởng tượng rằng việc mặc định hợp lý sẽ vi phạm bất kỳ nguyên tắc lý thuyết nào về tính mở rộng và tính mô đun. Một lập trình viên Ruby / Rails sẽ sớm thu được một ván bài nóng trong mắt họ hơn là chuyển sang một khung như Struts 1 trong đó tất cả các cấu hình được thực hiện rõ ràng trong nhiều tệp XML. Tôi không tranh cãi Rails so với Struts IN CHUNG, nhưng quy ước đó có thể là một chiến thắng năng suất rất lớn. Hai công nghệ này là so sánh thực tế nhất mà tôi từng gặp.

Nếu bạn hoàn toàn làm việc với Java, hãy xem Joshua Bloch, "Java hiệu quả", Mục 2: "Hãy xem xét một Trình tạo khi gặp nhiều tham số của hàm tạo" trang 11-16. Đối với hầu hết các mục đích, một số tham số (cấu hình) là bắt buộc và một số là tùy chọn. Ý tưởng cơ bản là chỉ yêu cầu cấu hình cần thiết và chỉ khiến người dùng (có thể là một chương trình khác) chỉ định các tùy chọn bổ sung khi cần. Tôi đã dọn sạch một loạt các mã với mẫu này một tháng trước và nó tích cực lấp lánh.


7

Nói cách khác, chức năng của ứng dụng không hoàn toàn được giải thích bằng mã riêng của nó, mà còn bằng tài liệu của khung.

Chức năng của một ứng dụng sử dụng khung luôn phụ thuộc vào khung, quy ước về cấu hình không tạo ra sự khác biệt trong vấn đề đó.

Theo kinh nghiệm của tôi, quy ước về cấu hình không chỉ làm cho mã dễ đọc hơn mà còn giảm khả năng đưa ra các lỗi tinh vi (đặc biệt là lỗi sao chép-dán-lỗi).

Ví dụ: giả sử trong một số khung A, sự kiện FooBarkích hoạt lệnh gọi đến handleFooBar. Trong một khung công tác B khác, mối tương quan này được cấu hình ở đâu đó trong một tệp XML.

Vì vậy, trong A, nó chỉ đơn giản là

handleFooBar() {
   ...
}

và trừ khi bạn viết sai chính tả FooBar, nó sẽ được gọi bất cứ khi nào FooBar xảy ra.

Ở B, nó lại

handleFooBar() {
   ...
}

nhưng cũng

<eventconfiguration>
  <event>
    <type>FooBar</type>
    <handler>handleFooBar</handler>
  </event>
</eventconfiguration>

Với hàng trăm thứ để cấu hình theo cách này, thật quá dễ dàng để vô tình tạo ra một lỗi tinh vi như

<eventconfiguration>
  <event>
    <type>BarFoo</type>
    <handler>handleFooBar</handler>
  </event>
</eventconfiguration>

bởi vì sau khi sao chép, chúng tôi chỉ thay đổi <type>mà quên thay đổi <handler>.

Vì các tệp cấu hình đó lớn và đơn điệu, nên ít có khả năng ai đó sẽ tìm thấy lỗi bằng cách hiệu đính hơn là anh ta sẽ tìm thấy một lỗi tương tự trong mã chương trình thực tế.


1
1: tránh lặp đi lặp lại, nhàm chán-to-ghi, khó đọc, cấu hình gần như lúc nào cũng hiển nhiên là những lợi thế lớn của hội nghị-over-cấu hình.
Joachim Sauer

-1

Nó có thể vi phạm một vài nguyên tắc, nhưng đồng thời nó tuân theo một trong những nguyên tắc thiết kế cơ bản nhất, SRP (Nguyên tắc trách nhiệm duy nhất).


2
Sử dụng các quy ước không có gì để làm với trách nhiệm duy nhất. Tôi có thể sử dụng một quy ước và thực hiện 100 điều trong đó.
Suamere
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.