Có phải đó là thực tế mã hóa xấu để tạo ra một cái gì đó trong một get nếu nó không tồn tại?


17

Vì vậy, tôi có một dịch vụ web có một cái gì đó giống như getAccountnơi nó sẽ trả lại một mã định danh cho tài khoản nếu có nó, nếu không thì sẽ có một ngoại lệ. Khách hàng sẽ luôn muốn tạo một tài khoản nếu một ngoại lệ được đưa ra với cùng thông tin mà việc nhận được thực hiện.

Tôi đang tạo một thư viện tiện lợi cho các khách hàng sẽ xử lý tất cả các cuộc gọi dịch vụ web bên trong để họ không cần biết cách tự thực hiện các cuộc gọi.

Điều tôi băn khoăn là trong thư viện này nếu tôi tạo một getAccount(accountName)tài khoản sẽ lấy tài khoản nếu nó tồn tại, và nếu nó không tạo ra nó và trả lại thông tin, đó có phải là một điều xấu không? Tôi có nên để nó cho khách hàng để xử lý các trường hợp ngoại lệ hoặc chỉ đơn giản là đặt tên cho nó một cái gì đó như getOrCreateAccount? Có vấn đề gì không?

Có phải thực tế xấu để tạo ra một cái gì đó trong một hoạt động có được?


9
Ít nhất, tôi sẽ đặt tên cho nó getOrCreateAccounthoặc tương tự.
Telastyn

4
Có vẻ hợp lệ trong bối cảnh khởi tạo lười biếng. Tuy nhiên, nó phụ thuộc nếu bạn có nhu cầu sử dụng mẫu đó trong thư viện của bạn.
Chris C

1
Tôi thích động từ acquire, thích acquireAccount. Nó không có ý nghĩa hiện có trong bất kỳ giao thức chính nào mà tôi đã gặp phải và nó có một vòng bắt buộc phù hợp với nó. "Làm bất cứ điều gì bạn phải làm để có được một trong những thứ này cho tôi. Yêu cầu nó, xây dựng nó, giả mạo nó, đánh cắp nó, tôi không quan tâm, chỉ cần lấy cho tôi một cái hoặc chết."
Dan Ross

2
"Khách hàng sẽ luôn muốn tạo một tài khoản" - điều đó có vẻ rất bất thường. Nếu tôi không thể có được tài khoản vì người dùng nhập sai tên người dùng của họ, tôi chắc chắn không muốn tạo một tài khoản với tên bị nhầm.
gnasher729

Theo thông số kỹ thuật javabean oracle.com/technetwork/articles/javaee/spec-136004.html getSomething() dành cho getters và setSomething()dành cho setters. Imo bất cứ điều gì mà làm điều gì đó hữu trí tuệ hơn phải gọi là cái gì khác, tức là fetchSomething, obtainSomething, computeSomething, hoặc doSomethingElse, vv
ccpizza

Câu trả lời:


31

Vâng, nó quan trọng. Theo tôi, nói chung, đó là một cách thực hành tồi để tạo ra một cái gì đó trong một quy trình không được ghi nhận là có sức mạnh của sự sáng tạo. Đặt tên cho thủ tục getOrCreate...hoặc có một create...quy trình riêng và sau đó nếu bạn thực sự muốn, hãy getOrCreate...thử lần đầu tiên get...và nếu thất bại, hãy gọi create...và sau đó gọi get....

Người dùng của thư viện có thể sẽ không mong đợi get...thủ tục tạo nếu thao tác get không thành công. Nếu họ đột nhiên phát hiện ra rằng các cuộc gọi thử nghiệm của họ để get...tạo ra cả tấn dữ liệu, có lẽ họ sẽ khá ngạc nhiên. Và làm thế nào để họ làm sạch nó? Điều gì sẽ xảy ra nếu họ viết mã nghĩ rằng họ sẽ gặp lỗi nếu get...thất bại và họ muốn xử lý theo cách của họ ?


Cảm ơn, tạo thực sự trả về id rằng get cũng sẽ trở lại vì vậy tôi sẽ không phải làm get... create... get...hai cái đầu tiên. Tôi sẽ nói chuyện với khách hàng về việc họ có yêu cầu khả năng gọi một cách đơn giản getmà không muốn tạo hay không
Mike

6
@Mike: Tôi vẫn nghĩ nó nên có createtên, chỉ cần rõ ràng 100% về những gì đang xảy ra.
Thất vọngWithFormsDesigner

Có, tôi đồng ý, tôi đã lên kế hoạch biến nó thành một thứ gì đó dọc theo dòng getOrCreate bởi vì suy nghĩ ban đầu của tôi chỉ là để có được nhưng tôi nhận ra rằng không phải ngay lập tức rằng nó cũng đang tạo ra một thứ gì đó trong nền
Mike

1
Điều này là siêu muộn nhưng getOrCreateđã được ưu tiên trong một khung web phổ biến: docs.djangoproject.com/en/1.10/ref/models/querysets/ Lỗi
tex

18

Không, đó không phải là "thực hành xấu". Miễn là bạn và các nhà phát triển khác đồng ý rằng bạn muốn nó hoạt động như thế nào, nó vẫn ổn. Rốt cuộc, nó sẽ trả lại một tài khoản, đó là những gì bạn muốn. Tài khoản được tạo 'dưới mui xe' không liên quan đến người gọi.


10
Chỉ có ngoại lệ là nếu đó là một API có sẵn công khai. Cộng đồng lớn hơn đã đồng ý rằng GET là không cần thiết và vô giá trị; nói cách khác, cùng một hành động được thực hiện mỗi lần và đó là một phương pháp an toàn không làm thay đổi trạng thái của máy chủ. Đây là trong Wiki Wiki . Bên cạnh đó, nếu API chỉ tồn tại trong thế giới nhỏ bé của riêng bạn, hãy làm bất cứ điều gì được nhóm của bạn chấp nhận.
jmort253

9
Tôi không đồng ý, ngay cả đối với một API công khai cũng không sao - miễn là nó có ý nghĩa trong bối cảnh của bất kỳ API nào cần phải làm. Có rất ít điểm trong việc tạo nhiều mục trong API khi một mục sẽ thực hiện thủ thuật.
GrandmasterB

Đối với hồ sơ, đây là một thư viện hoàn toàn nội bộ và tôi có khả năng chỉ cho nhóm sử dụng nó hoạt động như thế nào
Mike

1
@ jmort253: Một dịch vụ là nullipotent nếu nó không có tác dụng phụ cho khách hàng . Các máy chủ có thể làm như nó làm hài lòng.
kevin cline

1
@kevincline, tôi đoán tôi đã suy nghĩ về điều đó, giả sử, tính phí thẻ tín dụng của tôi. Nếu máy chủ tính phí thẻ của tôi dựa trên yêu cầu GET nhưng vẫn cho tôi kết quả như "bị từ chối" mỗi khi tôi chạy nó, cảm giác như nó đi ngược lại tinh thần của GET. Với những gì đã nói, tôi thấy quan điểm của bạn. Máy chủ có thể đếm số lượng yêu cầu GET và khóa tôi sau 3 truy vấn, do đó tỷ lệ giới hạn tôi, nhưng không thay đổi bất kỳ chi tiết nào trong tài khoản của tôi. Tôi nghĩ đó là một sự khác biệt quan trọng khi người ta nói trạng thái máy chủ không được sửa đổi. Có lẽ tôi nên nói "trạng thái máy khách trên máy chủ" thay vào đó
jmort253

10

Nếu getAccount()luôn có thể trả về một tài khoản, thì theo quan điểm của người gọi, tài khoản đó tồn tại và luôn tồn tại. Không cần phải getAccount()'tạo' bất cứ điều gì. Tài khoản không phải được lưu trữ ở bất cứ đâu cho đến khi nó khác với tài khoản mặc định.


+1 Nói chung, GetOrCreatelà ngữ nghĩa sai nhưng việc lấy một đối tượng có thể "tồn tại" một cách hợp lý cho dù nó tồn tại hay không tồn tại là tốt. Ví dụ, một mảng thưa của các mục có thể thay đổi có thể không có bất kỳ lưu trữ nào được phân bổ cho phần tử 1.841.533, nhưng vẫn cho phép phần tử đó được "truy xuất" bằng cách tạo một đối tượng mới, lưu trữ và trả về tham chiếu.
supercat

4

Nó có ý nghĩa nhất để tạo ra 3 phương thức:

getAccount -> Mà chỉ cần có tài khoản.

createdAccount -> Tạo một tài khoản.

getAccountAndCreate IfNeeded -> Chọn cách đặt tên của riêng bạn;)

Tại sao tách: Bạn có một phương pháp đơn giản để nhận và tạo. Đó là một phương pháp thử nghiệm rõ ràng cho cả hai. Đối với getAccount, không tìm thấy tài khoản. Vì vậy, chỉ cần trả lại sai hoặc một cái gì đó như thế, nó được mong đợi.

Sau đó, bạn có thể sử dụng giá trị trả về đó trong hàm được nhóm của mình: getAccountAndCreate IfNeeded hiện có thể kiểm tra được, nó sẽ luôn trả về một tài khoản. Bất cứ điều gì bạn yêu cầu.

Tất cả 3 phương pháp này đều rõ ràng, chính xác là rõ ràng những gì họ làm và những gì họ trả lại. Bạn có thể thực hiện các thỏa thuận ngay bây giờ với nhóm của mình nhưng loại ngoại lệ này là khủng khiếp về lâu dài. Chỉ cần làm cho họ rất rõ ràng và bạn sẽ không có vấn đề.


Ngoài ra, từ Clean Code: "Nếu phương thức của bạn không thể thực hiện được tên của nó, thì hãy ném Ngoại lệ." Tôi sẽ có một khối Thử / Bắt bên trong 'GetOrCreate Ifneeded', ném vào một GET không thành công và sau đó có 'createdAccount' bên trong Ném cho bất kỳ loại ngoại lệ nào quay trở lại cho nhận thất bại.
Graham

Tôi có thể đề xuất một phương pháp thứ tư : getAccountIfExists, sẽ có một tài khoản hoặc chỉ ra rằng nó không tồn tại mà không tạo một tài khoản mới. Bản getAccountthân phương thức sẽ giả định rằng tài khoản tồn tại và ném ngoại lệ nếu không.
supercat

2

Nó phụ thuộc vào hoàn cảnh.

Ví dụ: bạn có thể sử dụng nó để lười tải / khởi tạo, trì hoãn việc tải dữ liệu hoặc tạo một thể hiện cho đến khi thực sự cần thiết. Điều này thường hợp lý vì nó tiết kiệm tài nguyên mà bạn có thể không cần (nếu lớp / dữ liệu không bao giờ cần thì nó không bao giờ được tải).

Tuy nhiên, trong trường hợp cụ thể này, tôi muốn nói rằng có một phương thức gọi là getAccount sẽ tạo một tài khoản mới nếu nó không tồn tại sẽ không phải là một thực tiễn tốt. Nếu người dùng đã cung cấp một số thông tin xác thực để xác định một tài khoản cụ thể và tài khoản đó không thể được tìm thấy, điều đó có nghĩa là người dùng chưa phải là khách hàng và nên tạo một tài khoản cho họ hoặc điều đó có nghĩa là thông tin đăng nhập bị nhầm và người dùng cần được yêu cầu xác minh rằng họ đã nhập những gì họ muốn nhập?

Nếu bạn có một phương thức getAccount tạo tài khoản mới nếu nó không thể xác định một tài khoản, thì bạn không có lựa chọn nào khác trong vấn đề này. Nếu bạn phân chia việc tạo tài khoản và thoát ra khỏi các phương thức riêng biệt, thì bạn sẽ linh hoạt hơn rất nhiều trong việc quyết định những việc cần làm nếu một nỗ lực để có được một tài khoản thất bại.

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.