Một phương pháp có nên được tha thứ với các đối số được truyền vào không? [đóng cửa]


21

Giả sử chúng ta có một phương thức foo(String bar)chỉ hoạt động trên các chuỗi đáp ứng các tiêu chí nhất định; ví dụ, nó phải là chữ thường, không được để trống hoặc chỉ có khoảng trắng và phải khớp với mẫu [a-z0-9-_./@]+. Các tài liệu cho phương pháp nêu các tiêu chí này.

Phương pháp nên từ chối bất kỳ và tất cả các sai lệch so với tiêu chí này, hay phương pháp nên tha thứ hơn về một số tiêu chí? Ví dụ: nếu phương thức ban đầu là

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
    }
    this.bar = bar;
}

Và phương pháp tha thứ thứ hai là

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        bar = bar.toLowerCase().trim().replaceAll(" ", "_");
        if (!bar.matches(BAR_PATTERN_STRING) {
            throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
        }
    }
    this.bar = bar;
}

Tài liệu nên được thay đổi để nói rằng nó sẽ được chuyển đổi và được đặt thành giá trị được chuyển đổi nếu có thể, hoặc phương pháp nên được giữ đơn giản nhất có thể và từ chối bất kỳ và tất cả các sai lệch? Trong trường hợp này, barcó thể được đặt bởi người dùng của một ứng dụng.

Trường hợp sử dụng chính cho trường hợp này sẽ là người dùng truy cập các đối tượng từ kho lưu trữ bằng một mã định danh chuỗi cụ thể. Mỗi đối tượng trong kho lưu trữ nên có một chuỗi duy nhất để xác định nó. Các kho lưu trữ này có thể lưu trữ các đối tượng theo nhiều cách khác nhau (máy chủ sql, json, xml, nhị phân, v.v.) và vì vậy tôi đã cố gắng xác định mẫu số chung thấp nhất phù hợp với hầu hết các quy ước đặt tên.


1
Điều này có lẽ phụ thuộc rất nhiều vào trường hợp sử dụng của bạn. Một trong hai có thể hợp lý và thậm chí tôi đã thấy các lớp cung cấp cả hai phương thức và khiến người dùng quyết định. Bạn có thể giải thích về phương pháp / lớp / lĩnh vực này được cho là để làm gì, vì vậy chúng tôi có thể cung cấp một số lời khuyên thực sự?
Ixrec

1
Bạn có biết tất cả những người gọi phương thức này? Như trong, nếu bạn thay đổi nó, bạn có thể xác định đáng tin cậy tất cả các khách hàng? Nếu vậy, tôi sẽ cho phép và tha thứ khi mối quan tâm về hiệu suất cho phép. Tôi cũng có thể xóa tài liệu. Nếu không, và đó là một phần của API thư viện, tôi chắc chắn rằng mã được triển khai chính xác API được quảng cáo, vì nếu không thì việc thay đổi mã để khớp với tài liệu trong tương lai là có thể tạo báo cáo lỗi.
Jon Chesterfield

7
Bạn có thể lập luận rằng Tách biệt các mối quan tâm nói rằng nếu cần thiết, bạn nên có một foochức năng nghiêm ngặt, nghiêm ngặt trong những đối số mà nó chấp nhận và có chức năng trợ giúp thứ hai có thể cố gắng "làm sạch" một đối số được sử dụng foo. Theo cách này, mỗi phương thức có ít việc phải làm hơn và chúng có thể được quản lý và tích hợp sạch hơn. Nếu đi xuống tuyến đường đó, có lẽ cũng sẽ hữu ích khi di chuyển khỏi một thiết kế ngoại lệ; Optionalthay vào đó, bạn có thể sử dụng một cái gì đó giống như , và sau đó có các hàm tiêu thụ foongoại lệ ném nếu cần thiết.
gntskn

1
Điều này giống như hỏi "ai đó đã sai tôi, tôi có nên tha thứ cho họ không?" Rõ ràng có những trường hợp mà cái này hoặc cái kia là phù hợp. Lập trình có thể không phức tạp như các mối quan hệ của con người, nhưng nó chắc chắn đủ phức tạp để một đơn thuốc như thế này sẽ không hiệu quả.
Kilian Foth

2
@Boggin Tôi cũng sẽ chỉ cho bạn xem Nguyên tắc mạnh mẽ được xem xét lại . Khó khăn đến khi bạn cần mở rộng việc thực hiện và việc thực hiện tha thứ dẫn đến một trường hợp mơ hồ với việc thực hiện mở rộng.

Câu trả lời:


47

Phương pháp của bạn nên làm những gì nó nói.

Điều này ngăn ngừa lỗi, cả từ việc sử dụng và từ người bảo trì thay đổi hành vi sau này. Nó tiết kiệm thời gian vì người bảo trì không cần mất nhiều thời gian để tìm hiểu chuyện gì đang xảy ra.

Điều đó nói rằng, nếu logic được xác định không thân thiện với người dùng, có lẽ nó nên được cải thiện.


8
Đây là chìa khóa. Nếu phương thức của bạn thực hiện chính xác những gì nó nói, thì bộ mã hóa sử dụng phương thức của bạn sẽ bù cho trường hợp sử dụng cụ thể của chúng. Đừng bao giờ làm điều gì đó không có giấy tờ với phương pháp chỉ vì bạn nghĩ rằng nó hữu ích. Nếu bạn cần thay đổi nó, hãy viết một thùng chứa hoặc thay đổi tài liệu.
Nelson

Tôi muốn thêm vào nhận xét của @ Nelson rằng phương pháp không nên được thiết kế trong chân không. Nếu các lập trình viên nói rằng họ sẽ sử dụng nó nhưng sẽ bù lại và phần bù của họ có giá trị mục đích chung, hãy xem xét biến họ thành một phần của lớp. (Ví dụ: có foofooForUncleanStringphương thức mà cái sau thực hiện chỉnh sửa trước khi chuyển nó cho cái trước.)
Blrfl

20

Có một vài điểm:

  1. Việc thực hiện của bạn phải làm những gì trong hợp đồng được ghi lại và không nên làm gì thêm.
  2. Đơn giản là quan trọng, cho cả hợp đồng và thực hiện, mặc dù nhiều hơn cho trước đây.
  3. Cố gắng sửa chữa cho đầu vào sai lầm làm tăng thêm sự phức tạp, phản trực giác không chỉ hợp đồng và thực hiện mà còn sử dụng.
  4. Lỗi chỉ nên được phát hiện sớm nếu điều đó cải thiện khả năng sửa lỗi và không ảnh hưởng đến hiệu quả quá nhiều.
    Hãy nhớ rằng có các xác nhận gỡ lỗi để chẩn đoán lỗi logic trong chế độ gỡ lỗi, phần lớn làm giảm bớt mọi lo ngại về hiệu năng.
  5. Hiệu quả, theo thời gian có sẵn và tiền cho phép mà không ảnh hưởng đến sự đơn giản quá nhiều, luôn luôn là một mục tiêu.

Nếu bạn triển khai giao diện người dùng, các thông báo lỗi thân thiện (bao gồm các đề xuất và trợ giúp khác) là một phần của thiết kế tốt.
Nhưng hãy nhớ rằng API dành cho lập trình viên, không phải người dùng cuối.


Một thử nghiệm thực tế trong việc mờ và cho phép với đầu vào là HTML.
Điều đó dẫn đến việc mọi người thực hiện nó hơi khác nhau, và thông số kỹ thuật, bây giờ nó được ghi lại, là một cuốn sách ma mút đầy những trường hợp đặc biệt.
Xem luật của Postel (" Hãy thận trọng trong những gì bạn làm, tự do trong những gì bạn chấp nhận từ người khác. ")một nhà phê bình chạm vào điều đó ( Hoặc một điều tốt hơn nhiều MichaelT làm cho tôi biết ).


Một tác phẩm quan trọng khác của tác giả của sendmail: Nguyên tắc mạnh mẽ được xem xét lại

15

Hành vi của một phương thức nên rõ ràng, trực quan, có thể dự đoán và đơn giản. Nói chung, chúng ta nên rất do dự để xử lý thêm trên đầu vào của người gọi. Những dự đoán như vậy về những gì người gọi dự định luôn có rất nhiều trường hợp cạnh tạo ra hành vi không mong muốn. Xem xét một hoạt động đơn giản như tham gia đường dẫn tập tin. Nhiều chức năng tham gia đường dẫn tệp (hoặc thậm chí là hầu hết) sẽ âm thầm loại bỏ mọi đường dẫn trước nếu một trong các đường dẫn được nối dường như được root! Ví dụ, /abc/xyztham gia với /evilsẽ dẫn đến chỉ /evil. Đây gần như không bao giờ là điều tôi dự định khi tôi tham gia các đường dẫn tệp, nhưng vì không có giao diện nào không hoạt động theo cách này, tôi buộc phải có lỗi hoặc viết thêm mã bao gồm các trường hợp này.

Điều đó nói rằng, hiếm khi có ý nghĩa cho một phương pháp là "tha thứ", nhưng nó phải luôn nằm trong khả năng của người gọi để quyết định khi nàoliệu các bước xử lý này có áp dụng cho tình huống của họ hay không. Vì vậy, khi bạn đã xác định một bước tiền xử lý phổ biến mà bạn muốn áp dụng cho các đối số trong nhiều tình huống khác nhau, bạn nên hiển thị các giao diện cho:

  • Các chức năng thô, mà không có bất kỳ tiền xử lý.
  • Các bước tiền xử lý của chính nó .
  • Sự kết hợp của chức năng thô và tiền xử lý.

Cuối cùng là tùy chọn; bạn chỉ nên cung cấp nó nếu một số lượng lớn các cuộc gọi sẽ sử dụng nó.

Phơi bày chức năng thô cung cấp cho người gọi khả năng sử dụng nó mà không cần bước tiền xử lý khi họ cần. Việc tự bộc lộ bước tiền xử lý cho phép người gọi sử dụng nó cho các tình huống mà họ thậm chí không gọi hàm hoặc khi họ muốn xử lý trước một số đầu vào trước khi gọi hàm này (như khi họ muốn chuyển nó sang hàm khác trước). Việc cung cấp kết hợp cho phép người gọi gọi cả hai mà không gặp rắc rối nào, điều này rất hữu ích nếu hầu hết người gọi sẽ sử dụng nó theo cách này.


2
+1 để dự đoán. Và +1 khác (tôi muốn) cho đơn giản. Tôi muốn bạn giúp tôi phát hiện và sửa chữa lỗi lầm của mình hơn là cố gắng che giấu chúng.
John M Gant

4

Như những người khác đã nói, làm cho chuỗi phù hợp "tha thứ" có nghĩa là giới thiệu thêm độ phức tạp. Điều đó có nghĩa là nhiều công việc hơn trong việc thực hiện phù hợp. Bây giờ bạn có nhiều trường hợp thử nghiệm hơn, ví dụ. Bạn phải làm thêm công việc để đảm bảo không có tên bằng nhau về mặt ngữ nghĩa trong không gian tên. Sự phức tạp hơn cũng có nghĩa là có nhiều sai lầm hơn trong tương lai. Một cơ chế đơn giản hơn, chẳng hạn như xe đạp, đòi hỏi ít bảo trì hơn so với một cơ chế phức tạp hơn, chẳng hạn như xe hơi.

Vì vậy, chuỗi phù hợp có giá trị tất cả chi phí thêm? Nó phụ thuộc vào trường hợp sử dụng, như những người khác đã lưu ý. Nếu các chuỗi là một loại đầu vào bên ngoài mà bạn không có quyền kiểm soát và có một lợi thế nhất định để phù hợp với sự khoan hồng, thì nó có thể có giá trị. Có lẽ đầu vào đến từ người dùng cuối, những người có thể không có ý thức về các ký tự không gian và viết hoa và bạn có động lực mạnh mẽ để làm cho sản phẩm của bạn dễ sử dụng hơn.

Mặt khác, nếu đầu vào đến từ, giả sử, các tệp thuộc tính được lắp ráp bởi những người kỹ thuật, những người nên hiểu điều đó "Fred Mertz" != "FredMertz", tôi sẽ có xu hướng làm cho phù hợp chặt chẽ hơn và tiết kiệm chi phí phát triển.

Tuy nhiên, tôi nghĩ rằng trong mọi trường hợp đều có giá trị trong việc cắt xén và coi thường các không gian hàng đầu và dấu vết - Tôi đã thấy quá nhiều giờ lãng phí khi gỡ lỗi các loại vấn đề đó.


3

Bạn đề cập đến một số bối cảnh mà câu hỏi này xuất hiện.

Do đó, tôi sẽ có phương thức thực hiện một điều duy nhất, nó xác nhận các yêu cầu trên chuỗi, để nó thực thi dựa trên điều đó - tôi sẽ không cố gắng chuyển đổi nó ở đây. Giữ nó đơn giản và giữ cho nó rõ ràng; ghi lại nó và cố gắng giữ tài liệu và mã đồng bộ với nhau.

Nếu bạn muốn chuyển đổi dữ liệu xuất phát từ cơ sở dữ liệu người dùng theo cách dễ tha thứ hơn, hãy đặt chức năng đó vào một phương thức chuyển đổi riêng và ghi lại chức năng gắn với nó .

Tại một số điểm, các yêu cầu của chức năng cần được đáp ứng, ghi lại rõ ràng và việc thực hiện phải tiếp tục. "Sự tha thứ", theo quan điểm của anh ấy, hơi câm, đó là một quyết định thiết kế và tôi sẽ tranh luận về chức năng không làm thay đổi lập luận của nó. Có chức năng đột biến đầu vào ẩn một số xác nhận sẽ được yêu cầu của khách hàng. Có một chức năng thực hiện đột biến giúp khách hàng hiểu đúng.

Sự nhấn mạnh lớn ở đây là sự rõ ràng và để ghi lại những gì mã làm .


-1
  1. Bạn có thể đặt tên cho một phương thức theo hành động như doS Something (), TakeBackUp ().
  2. Để dễ bảo trì, bạn có thể giữ các hợp đồng và xác nhận chung trên các quy trình khác nhau. Gọi cho họ theo trường hợp sử dụng.
  3. Lập trình phòng thủ: quy trình của bạn xử lý phạm vi đầu vào rộng bao gồm (Những điều tối thiểu là các trường hợp sử dụng phải được bảo vệ bằng mọi cách)
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.