Thiết kế API: phương pháp cụ thể so với trừu tượng - thực tiễn tốt nhất?


25

Khi thảo luận giữa các hệ thống API (vào mức độ kinh doanh) thường có hai quan điểm khác nhau trong đội ngũ của chúng tôi: một số người thích một nhiều hơn - chẳng hạn cho phép - generic phương pháp trừu tượng, một khác thẳng về phía trước "bê tông" cách tiếp cận.

Ví dụ: thiết kế API "tìm kiếm người" đơn giản. phiên bản cụ thể sẽ là

 searchPerson(String name, boolean soundEx,
              String firstName, boolean soundEx,
              String dateOfBirth)

Những người ủng hộ phiên bản cụ thể nói:

  • API là tài liệu tự
  • thật dễ hiểu
  • thật dễ dàng để xác nhận (trình biên dịch hoặc dưới dạng dịch vụ web: xác thực lược đồ)
  • HÔN

Một nhóm người khác trong nhóm của chúng tôi sẽ nói "Đó chỉ là một danh sách các tiêu chí tìm kiếm"

searchPerson(List<SearchCriteria> criteria)

với

SearchCritera {
  String parameter,
  String value,
  Map<String, String> options
}

với khả năng làm "tham số" của một số loại liệt kê.

Những người đề xuất nói:

  • mà không thay đổi (khai báo) API, việc triển khai có thể thay đổi, ví dụ: thêm nhiều tiêu chí hoặc nhiều tùy chọn hơn. Ngay cả khi không đồng bộ hóa một sự thay đổi như vậy tại thời điểm triển khai.
  • tài liệu là cần thiết ngay cả với các biến thể cụ thể
  • xác thực lược đồ được đánh giá quá cao, thường thì bạn phải xác nhận thêm, lược đồ không thể xử lý tất cả các trường hợp
  • chúng tôi đã có một API tương tự với một hệ thống khác - tái sử dụng

Đối số là

  • rất nhiều tài liệu về các tham số hợp lệ và kết hợp tham số hợp lệ
  • nỗ lực giao tiếp nhiều hơn bởi vì nó khó hiểu hơn đối với các đội khác

Có thực hành tốt nhất? Văn chương?


3
lặp đi lặp lại "String First / name, boolean soundEx" là một sự vi phạm rõ ràng về sự khô khan và gợi ý rằng thiết kế này không thể giải quyết được thực tế là tên đó sẽ đi cùng với soundEx. Đối mặt với những lỗi thiết kế đơn giản như vậy, thật khó để tiến hành phân tích tinh vi hơn
gnat

Trái ngược với "cụ thể" không phải là "chung chung", đó là "trừu tượng". Trừu tượng là rất quan trọng đối với một thư viện hoặc API và cuộc thảo luận này không thể đặt câu hỏi thực sự cơ bản, thay vào đó là một câu hỏi khá tầm thường về phong cách. FWIW, các đối số đối với tùy chọn B nghe giống như tải FUD, bạn không cần bất kỳ tài liệu hoặc giao tiếp bổ sung nào nếu thiết kế API thậm chí còn sạch sẽ và tuân theo các nguyên tắc RẮN.
Aaronaught

@Aaronaught cảm ơn vì đã chỉ ra điều đó ("trừu tượng"). Nó có thể là một vấn đề dịch thuật, "hào phóng" trong tiếng Đức vẫn ổn với tôi. "Câu hỏi thực sự cơ bản" đối với bạn là gì?
erik

4
@Aaronaught: Câu hỏi không phải là về trừu tượng. Sự điều chỉnh đúng sẽ là ngược lại với "chung chung" là "cụ thể", không phải "cụ thể".
Jan Hudec

Một phiếu khác cho điều này không phải là về chung chung so với trừu tượng, nhưng chung chung so với cụ thể. Ví dụ "cụ thể" ở trên thực sự cụ thể cho tên, FirstName và dateOfBirth, ví dụ khác là chung cho bất kỳ tham số nào. Không phải là đặc biệt trừu tượng. Tôi sẽ chỉnh sửa tiêu đề nhưng tôi không muốn bắt đầu một cuộc chiến chỉnh sửa :-)
matt freake

Câu trả lời:


18

Nó phụ thuộc vào số lượng lĩnh vực bạn đang nói và cách chúng được sử dụng. Bê tông thích hợp hơn cho các truy vấn có cấu trúc cao chỉ có một vài trường, nhưng nếu truy vấn có xu hướng ở dạng rất tự do, thì cách tiếp cận cụ thể nhanh chóng trở nên khó sử dụng với hơn ba hoặc bốn trường.

Mặt khác, rất khó để giữ một API chung. Nếu bạn thực hiện tìm kiếm tên đơn giản ở nhiều nơi, cuối cùng sẽ có người mệt mỏi lặp lại năm dòng mã giống nhau và họ sẽ bọc nó trong một chức năng. Một API như vậy luôn luôn phát triển thành một kết hợp của một truy vấn chung cùng với các trình bao bọc cụ thể cho các truy vấn được sử dụng phổ biến nhất. Và tôi không thấy có gì sai với điều đó. Nó cung cấp cho bạn tốt nhất của cả hai thế giới.


7

Thiết kế API tốt là một nghệ thuật. API tốt được đánh giá cao ngay cả sau khi thời gian trôi qua. Theo tôi, không nên có sự thiên vị chung trên dòng cụ thể trừu tượng. Một số tham số có thể cụ thể như các ngày trong tuần, một số yêu cầu phải được thiết kế để mở rộng (và khá ngu ngốc khi biến chúng thành cụ thể, ví dụ, một phần của tên hàm), nhưng một số khác có thể đi xa hơn và để có vẻ thanh lịch API một cần cung cấp các cuộc gọi lại hoặc thậm chí ngôn ngữ cụ thể của tên miền sẽ giúp chống lại sự phức tạp.

Có những điều mới hiếm khi xảy ra dưới Mặt trăng. Hãy xem nghệ thuật trước đây, đặc biệt là các tiêu chuẩn và định dạng đã được thiết lập (ví dụ: nhiều thứ có thể được mô hình hóa sau các nguồn cấp dữ liệu, mô tả sự kiện được xây dựng bằng ical / vcal). Làm cho API của bạn dễ dàng được thêm vào, trong đó các thực thể thường xuyên và có mặt ở khắp nơi là các phần mở rộng cụ thể và được hình dung là từ điển. Ngoài ra còn có một số mô hình được thiết lập tốt để xử lý các tình huống cụ thể. Ví dụ: xử lý yêu cầu HTTP (và tương tự) có thể được mô hình hóa trong API với các đối tượng Yêu cầu và Phản hồi.

Trước khi thiết kế API, hãy động não về các khía cạnh, bao gồm cả những khía cạnh sẽ không được bao gồm, nhưng bạn phải nhận thức được. Ví dụ như ngôn ngữ, hướng viết, mã hóa, ngôn ngữ, thông tin múi giờ và những thứ tương tự. Hãy chú ý đến những nơi có thể xuất hiện bội số: danh sách sử dụng, không phải giá trị đơn lẻ cho chúng. Ví dụ: nếu bạn mong muốn API cho hệ thống videochat, API của bạn sẽ hữu ích hơn nhiều, nếu bạn giả sử N người tham gia, không chỉ hai (mặc dù thông số kỹ thuật của bạn tại thời điểm này là như vậy).

Đôi khi, trừu tượng giúp giảm độ phức tạp mạnh mẽ: ngay cả khi bạn thiết kế một máy tính chỉ thêm 3 + 4, 2 + 2 và 7 + 6, việc triển khai X + Y sẽ đơn giản hơn nhiều (với các giới hạn khả thi về mặt kỹ thuật trên X và Y và bao gồm ADD (X, Y) vào API của bạn thay vì ADD_3_4 (), ADD_2_2 (), ...

Nói chung, chọn cách này hay cách khác chỉ là một chi tiết kỹ thuật. Tài liệu của bạn nên mô tả các trường hợp sử dụng thường xuyên một cách cụ thể.

Bất cứ điều gì bạn làm về phía cấu trúc dữ liệu, hãy cung cấp trường cho phiên bản API.

Tóm lại, API nên giảm thiểu độ phức tạp khi giao dịch với phần mềm của bạn. Để đánh giá cao API, mức độ phức tạp tiếp xúc phải đủ. Việc quyết định hình thức API phụ thuộc rất nhiều vào tính ổn định của miền vấn đề. Do đó, cần có một số ước tính về việc phần mềm và API của nó sẽ phát triển theo hướng nào, bởi vì thông tin này có thể ảnh hưởng đến phương trình về độ phức tạp. Ngoài ra, API desing có sẵn để mọi người hiểu. Nếu có bất kỳ truyền thống tốt nào trong lĩnh vực công nghệ phần mềm bạn đang ở, hãy cố gắng không đi chệch hướng nhiều từ chúng, vì nó sẽ giúp hiểu. Hãy tính đến người mà bạn viết. Người dùng cao cấp hơn sẽ đánh giá cao tính tổng quát và tính linh hoạt, trong khi những người có ít kinh nghiệm có thể thoải mái hơn với việc cụ thể hóa. Tuy nhiên, chăm sóc cho phần lớn người dùng API ở đó,

Về mặt văn học, tôi có thể đề nghị "Các quy tắc đẹp" Các lập trình viên hàng đầu giải thích cách họ nghĩ của Andy Oram, Greg Wilson, vì tôi nghĩ rằng cái đẹp là về nhận thức sự tối ưu tiềm ẩn (và sự phù hợp cho mục đích nào đó).


1

Sở thích cá nhân của tôi là trừu tượng, nhưng các chính sách của công ty đã khóa tôi thành cụ thể. Đó là kết thúc của cuộc tranh luận đối với tôi :)

Bạn đã hoàn thành tốt công việc liệt kê những ưu và nhược điểm cho cả hai phương pháp và nếu bạn tiếp tục đào bới, bạn sẽ tìm thấy nhiều lý lẽ có lợi cho cả hai bên. Miễn là kiến ​​trúc API của bạn được phát triển đúng cách - có nghĩa là bạn đã nghĩ về cách nó sẽ được sử dụng ngày hôm nay và cách nó có thể phát triển và phát triển trong tương lai - thì bạn cũng sẽ ổn thôi.

Đây là hai dấu trang tôi có với các quan điểm đối lập:

Lớp học trừu tượng ưa thích

Giao diện ưa thích

Hãy tự hỏi: "API có đáp ứng các yêu cầu kinh doanh của tôi không? Tôi có các tiêu chí được xác định rõ để thành công không? Nó có thể mở rộng không?". Những cách đó có vẻ như là những thực hành tốt nhất đơn giản để làm theo, nhưng thực sự chúng quan trọng hơn nhiều so với cụ thể so với chung chung.


1

Tôi không nói rằng một API trừu tượng nhất thiết phải khó xác thực hơn. Nếu các tham số tiêu chí đủ đơn giản và có ít phụ thuộc lẫn nhau, điều đó sẽ không tạo ra nhiều khác biệt cho dù bạn chuyển các tham số riêng rẽ hay trong một mảng. Bạn vẫn cần xác nhận tất cả. Nhưng điều đó phụ thuộc vào thiết kế của các tham số tiêu chí và chính các đối tượng.

Nếu API đủ phức tạp, có các phương thức cụ thể không phải là một tùy chọn. Tại một số điểm, có thể bạn sẽ kết thúc bằng một trong hai phương thức có nhiều tham số hoặc quá nhiều phương thức đơn giản không bao gồm tất cả các trường hợp sử dụng được yêu cầu. Theo kinh nghiệm cá nhân của tôi trong việc thiết kế API tiêu thụ, tốt hơn là nên có các phương pháp chung hơn ở cấp API và triển khai các trình bao bọc được yêu cầu cụ thể ở cấp ứng dụng.


1

Đối số thay đổi nên được loại bỏ với YAGNI. Về cơ bản trừ khi bạn thực sự có ít nhất 3 trường hợp sử dụng khác nhau sử dụng API chung khác nhau, rất có thể bạn sẽ thiết kế nó để nó sẽ không phải thay đổi khi trường hợp sử dụng tiếp theo xuất hiện (và khi bạn có sử dụng- trường hợp, bạn rõ ràng cần giao diện chung, thời gian). Vì vậy, đừng cố gắng và sẵn sàng cho sự thay đổi.

Thay đổi không cần phải được đồng bộ hóa để triển khai trong cả hai trường hợp. Khi bạn khái quát hóa giao diện sau này, bạn luôn có thể cung cấp giao diện cụ thể hơn để tương thích ngược. Nhưng trong thực tế, bất kỳ triển khai nào cũng sẽ có rất nhiều thay đổi mà bạn sẽ đồng bộ hóa nó bằng mọi cách để bạn không phải kiểm tra các trạng thái trung gian. Tôi cũng sẽ không coi đó là tranh luận.

Đối với tài liệu, một trong hai giải pháp có thể dễ sử dụng và rõ ràng. Nhưng nó là lập luận quan trọng. Thực hiện giao diện để nó sẽ dễ sử dụng trong các trường hợp thực tế của bạn. Đôi khi cụ thể có thể tốt hơn ans đôi khi chung chung có thể được.


1

Tôi sẽ ủng hộ cách tiếp cận giao diện trừu tượng. Để đặt một truy vấn cho các loại dịch vụ (tìm kiếm) đó là một vấn đề phổ biến và có thể sẽ xảy ra lần nữa. Hơn nữa, bạn có thể sẽ tìm thấy nhiều ứng viên dịch vụ phù hợp hơn để sử dụng lại giao diện chung hơn. Để có thể cung cấp giao diện chung mạch lạc cho các dịch vụ đó, tôi sẽ không liệt kê các tham số truy vấn hiện được xác định trong định nghĩa giao diện.

Như đã được chỉ ra trước đây - tôi thích cơ hội để thay đổi hoặc mở rộng việc thực hiện mà không cần sửa đổi giao diện. Thêm một tiêu chí tìm kiếm khác không được phản ánh trong định nghĩa dịch vụ.

Mặc dù không có vấn đề gì khi thiết kế các giao diện được xác định rõ ràng, ngắn gọn và xuất sắc, bạn sẽ luôn phải cung cấp một số tài liệu bổ sung. Thêm phạm vi định nghĩa cho các tiêu chí tìm kiếm hợp lệ không phải là một gánh nặng như vậy.


1

Tóm tắt tốt nhất mà tôi từng thấy là quy mô của Rusty, hiện được gọi là tuyên ngôn Thiết kế API của Rusty . Tôi chỉ có thể mạnh mẽ giới thiệu cái đó. Để hoàn thiện, tôi trích dẫn tóm tắt thang đo từ liên kết đầu tiên (tốt hơn ở trên, xấu hơn bên dưới):

API tốt

  • Không thể nào sai được.
  • Trình biên dịch / liên kết sẽ không cho phép bạn hiểu sai.
  • Trình biên dịch sẽ cảnh báo nếu bạn hiểu sai.
  • Việc sử dụng rõ ràng là (có thể) là chính xác.
  • Tên cho bạn biết làm thế nào để sử dụng nó.
  • Làm đúng hoặc nó sẽ luôn luôn bị hỏng khi chạy.
  • Thực hiện theo quy ước chung và bạn sẽ hiểu đúng.
  • Đọc tài liệu và bạn sẽ hiểu đúng.
  • Đọc thực hiện và bạn sẽ làm cho nó đúng.
  • Đọc chủ đề danh sách gửi thư chính xác và bạn sẽ hiểu đúng.

API xấu

  • Đọc chủ đề danh sách gửi thư và bạn sẽ hiểu sai.
  • Đọc việc thực hiện và bạn sẽ hiểu sai.
  • Đọc tài liệu và bạn sẽ hiểu sai.
  • Thực hiện theo quy ước chung và bạn sẽ hiểu sai.
  • Làm đúng và đôi khi nó sẽ bị hỏng khi chạy.
  • Tên cho bạn biết làm thế nào để không sử dụng nó.
  • Việc sử dụng rõ ràng là sai.
  • Trình biên dịch sẽ cảnh báo nếu bạn làm đúng.
  • Trình biên dịch / liên kết sẽ không cho phép bạn làm đúng.
  • Không thể nào đúng được.

Cả hai trang chi tiết ở đâyở đây đi kèm với một cuộc thảo luận sâu sắc về từng điểm. Nó thực sự phải đọc cho các nhà thiết kế API. Cảm ơn Rusty, nếu bạn đã từng đọc nó.


0

Theo cách nói của giáo dân:

  • Cách tiếp cận trừu tượng có lợi thế là cho phép xây dựng các phương pháp cụ thể xung quanh nó.
  • Cách khác là không đúng

UDP có lợi thế là cho phép bạn xây dựng các luồng đáng tin cậy của riêng bạn. Vậy tại sao hầu hết mọi người đều sử dụng TCP?
Svick

Cũng có sự xem xét của phần lớn các trường hợp sử dụng. Một số trường hợp có thể cần thiết thường xuyên đến mức có thể làm cho những trường hợp đó trở nên đặc biệt.
La Mã

0

Nếu bạn mở rộng SearchCriteriaý tưởng một chút, nó có thể cung cấp cho bạn sự linh hoạt như tiêu chí tạo AND, ORv.v. Nếu bạn cần chức năng như vậy, đây sẽ là cách tiếp cận tốt hơn.

Nếu không, thiết kế nó cho khả năng sử dụng. Làm cho API dễ dàng cho những người sử dụng nó. Nếu bạn có một số chức năng cơ bản cần thiết thường xuyên (như tìm kiếm một người theo tên của nó), hãy cung cấp trực tiếp cho họ. Nếu người dùng nâng cao cần tìm kiếm nâng cao, họ vẫn có thể sử dụng SearchCriteria.


0

Mã đằng sau API đang làm gì? Nếu đó là một cái gì đó linh hoạt thì một API linh hoạt là tốt. Nếu mã đằng sau API rất cụ thể thì việc đặt khuôn mặt linh hoạt lên nó chỉ có nghĩa là người dùng API sẽ thất vọng và khó chịu với tất cả những thứ mà API giả vờ là có thể nhưng thực tế không thể thực hiện được.

Ví dụ tìm kiếm người của bạn là tất cả ba lĩnh vực cần thiết? Nếu vậy thì danh sách tiêu chí là xấu vì nó cho phép vô số cách sử dụng mà chỉ đơn giản là không hoạt động. Nếu không thì yêu cầu người dùng chỉ định đầu vào không yêu cầu là xấu. Khả năng tìm kiếm theo địa chỉ sẽ được thêm vào V2 như thế nào? Giao diện linh hoạt giúp dễ dàng thêm hơn giao diện không linh hoạt.

Không phải mọi hệ thống đều cần phải cực kỳ linh hoạt, cố gắng làm mọi thứ cũng như Kiến trúc phi hành gia. Một cung linh hoạt bắn mũi tên. Một thanh kiếm linh hoạt cũng hữu ích như một con gà cao su.

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.