Tại sao REST Api không theo mẫu thiết kế Mặt tiền


9

Khi so sánh cấu trúc REST [api] với mô hình OO, tôi thấy những điểm tương đồng sau:

Cả hai:

  • Được định hướng dữ liệu

    • REST = Tài nguyên
    • OO = Đối tượng
  • Hoạt động xung quanh dữ liệu

    • REST = bao quanh ĐỘNG TỪ (Nhận, Đăng, ...) xung quanh các tài nguyên
    • OO = thúc đẩy hoạt động xung quanh các đối tượng bằng cách đóng gói

Tuy nhiên, các thực tiễn OO tốt không phải lúc nào cũng đứng trên apis REST khi cố gắng áp dụng mẫu mặt tiền: trong REST, bạn không có 1 bộ điều khiển để xử lý tất cả các yêu cầu VÀ bạn không che giấu sự phức tạp của đối tượng bên trong.

Quan hệ đối tượng đơn giản giữa 2 khái niệm

Tương tự giữa OO và REST

Ngược lại, REST khuyến khích xuất bản tài nguyên của tất cả các mối quan hệ với một tài nguyên và khác trên ít nhất hai hình thức:

  1. thông qua quan hệ phân cấp tài nguyên (Một liên hệ của id 43 bao gồm một địa chỉ 453): /api/contacts/43/addresses/453

  2. thông qua các liên kết trong phản hồi json REST:

>> GET /api/contacts/43
<< HTTP Response {
   id: 43, ...
   addresses: [{
      id: 453, ...
   }],
   links: [{
      favoriteAddress: {
          id: 453
      }
   }]
}

Độ phức tạp cơ bản được ẩn bởi objectA

Quay trở lại OO, mẫu thiết kế mặt tiền tôn trọng Low Couplinggiữa một objectA và ' objectB client ' của nó và High Cohesioncho objectA này và thành phần đối tượng bên trong của nó ( objectC , objectD ). Với objectA giao diện, điều này cho phép một nhà phát triển để tác động giới hạn về objectB của objectA thay đổi nội bộ (trong objectCobjectD ), miễn là objectA api (hoạt động) vẫn được tôn trọng.

Trong REST, dữ liệu (tài nguyên), các mối quan hệ (liên kết) và hành vi (động từ) được phát nổ trong các yếu tố khác nhau và có sẵn cho web.

Chơi với REST, tôi luôn có tác động đến thay đổi mã giữa máy khách và máy chủ của mình: Bởi vì tôi có High Couplinggiữa Backbone.jscác yêu cầu của mình và Low Cohesiongiữa các tài nguyên.

Tôi chưa bao giờ tìm ra cách để cho Backbone.js javascript applicationthỏa thuận của tôi với khám phá " tài nguyên và tính năng REST " được thúc đẩy bởi các liên kết REST. Tôi hiểu rằng WWW có nghĩa là được phục vụ bởi nhiều máy chủ và các yếu tố OO phải được phát nổ để được phục vụ bởi nhiều máy chủ trong đó, nhưng đối với một kịch bản đơn giản như "lưu" một trang hiển thị liên hệ với địa chỉ của nó, Tôi kết thúc với:

GET /api/contacts/43?embed=(addresses)
[save button pressed]
PUT /api/contacts/43
PUT /api/contacts/43/addresses/453

điều này dẫn tôi đến việc chuyển trách nhiệm giao dịch nguyên tử hành động tiết kiệm trên các ứng dụng trình duyệt (vì hai tài nguyên có thể được xử lý riêng).

Với suy nghĩ này, nếu tôi không thể đơn giản hóa sự phát triển của mình (các mẫu thiết kế mặt tiền không áp dụng) và nếu tôi mang lại sự phức tạp hơn cho khách hàng của mình (xử lý tiết kiệm nguyên tử giao dịch), thì lợi ích của việc RESTful là gì?


1
Hãy để tôi hiểu. Bạn đang nói rằng bạn phải cập nhật một Liên hệ với một địa chỉ được liên kết "được nhúng" (thành phần) bằng hai cuộc gọi REST, một cho Liên hệ và một cho Địa chỉ của nó. Bạn có một Mặt tiền để xử lý cập nhật danh bạ. Vấn đề với việc tạo PUT /api/contacts/43tầng các bản cập nhật cho các đối tượng bên trong là gì? Tôi đã có rất nhiều API được thiết kế như thế này (URL chính đọc / tạo / cập nhật "toàn bộ" và các url phụ cập nhật các phần). Chỉ cần đảm bảo rằng bạn không cập nhật địa chỉ khi không có thay đổi nào được yêu cầu (vì lý do hiệu suất).
Anthony Accioly

@AnthonyAccioly, bạn đã hiểu chính xác. Tôi đã cố gắng làm rõ câu hỏi của mình bằng cách thêm một số hình ảnh. Đề xuất của bạn là tốt và đó cũng là kết luận tôi đưa ra: kiểm soát thủ công yêu cầu của tôi và sử dụng một đối tượng nhúng để chỉ gửi một yêu cầu duy trì cập nhật nguyên tử của tôi. Tuy nhiên: Tại sao mọi thứ trong REST đẩy tôi ra khỏi các phẩm chất hoặc thực thi OO (đóng gói, ...) bằng cách làm phẳng mô hình của tôi (ngụ ý nhiều bộ điều khiển). Sử dụng giải pháp của bạn cung cấp cho 1 cập nhật nguyên tử. Không sử dụng giải pháp của bạn mang lại cho nhà phát triển trách nhiệm mới và không có quy tắc nào về api để ngăn anh ta làm điều đó.
Alain

Chỉ cần lưu ý: "quan hệ phân cấp tài nguyên" mà bạn đã đề cập là vấn đề làm thế nào người ta có thể quyết định mã hóa thông tin mối quan hệ trong một mã định danh (trong trường hợp này là URL). Tôi không chắc việc giải thích thông tin này là một phần của REST hoặc thứ gì đó mà nó quảng bá, chỉ là một quyết định mà người ta tự đưa ra khi đưa ra các URL của hệ thống. Nếu bạn tin khác, bạn có bất kỳ tài liệu tham khảo nào về Roy Fielding thảo luận về vấn đề này như là một phần của REST không?
Thiago Silva

Câu trả lời:


7

Tôi nghĩ các đối tượng chỉ được xây dựng chính xác xung quanh các hành vi mạch lạc chứ không phải xung quanh dữ liệu. Tôi sẽ kích động và nói rằng dữ liệu gần như không liên quan trong thế giới hướng đối tượng. Trên thực tế, đôi khi có thể có các đối tượng không bao giờ trả lại dữ liệu, ví dụ "nhật ký chìm" hoặc các đối tượng không bao giờ trả lại dữ liệu mà chúng được truyền, ví dụ: nếu chúng tính toán các thuộc tính thống kê.

Chúng ta đừng nhầm lẫn PODS , (ít hơn một chút so với cấu trúc) và các đối tượng thực sự có hành vi (như Contactslớp trong ví dụ của bạn) 1 .

PODS về cơ bản là một sự tiện lợi được sử dụng để nói chuyện với các kho lưu trữ và các đối tượng kinh doanh. Họ cho phép mã được loại an toàn. Không nhiều không ít. Mặt khác, các đối tượng kinh doanh cung cấp các hành vi cụ thể , như xác thực dữ liệu của bạn hoặc lưu trữ dữ liệu hoặc sử dụng dữ liệu đó để thực hiện tính toán.

Vì vậy, các hành vi là những gì chúng ta sử dụng để đo lường "sự gắn kết" 2 và đủ dễ dàng để thấy rằng trong ví dụ đối tượng của bạn có một số sự gắn kết, mặc dù bạn chỉ hiển thị các phương thức để thao tác các liên hệ cấp cao nhất và không có phương thức nào để thao tác địa chỉ.

Về REST, bạn có thể xem các dịch vụ REST dưới dạng kho dữ liệu. Sự khác biệt lớn với thiết kế hướng đối tượng là có (hầu như) chỉ có một lựa chọn thiết kế: bạn có bốn phương thức cơ bản ( HEADví dụ nhiều hơn nếu bạn tính ) và tất nhiên bạn có nhiều thời gian rảnh với các URI để bạn có thể thực hiện tiện lợi những thứ như vượt qua nhiều id và lấy lại cấu trúc lớn hơn. Đừng nhầm lẫn dữ liệu họ truyền với các hoạt động họ thực hiện. Sự gắn kết và khớp nối là về và không phải dữ liệu .

Rõ ràng, các dịch vụ REST có sự gắn kết cao (mọi cách để tương tác với một tài nguyên ở cùng một nơi) và khớp nối thấp (mọi kho lưu trữ tài nguyên không đòi hỏi kiến ​​thức về các tài nguyên khác).

Mặc dù vậy, thực tế cơ bản vẫn là một mẫu lưu trữ duy nhất cho dữ liệu của bạn. Điều này có hậu quả, bởi vì đó là một mô hình được xây dựng xung quanh khả năng tiếp cận dễ dàng trên phương tiện chậm, nơi có chi phí cao cho "độ chát": khách hàng thường muốn thực hiện càng ít thao tác càng tốt, nhưng đồng thời chỉ nhận được dữ liệu họ cần . Điều này xác định mức độ sâu của một cây dữ liệu bạn sẽ gửi lại.

Trong thiết kế hướng đối tượng (chính xác), bất kỳ ứng dụng không tầm thường nào cũng sẽ thực hiện các hoạt động phức tạp hơn nhiều, ví dụ như thông qua thành phần. Bạn có thể có các phương thức để thực hiện các hoạt động chuyên biệt hơn với dữ liệu - điều này phải như vậy, bởi vì trong khi REST là một giao thức API, thì 3M được sử dụng để xây dựng toàn bộ các ứng dụng mà người dùng phải đối mặt! Đây là lý do tại sao đo lường sự gắn kết và khớp nối là cơ bản trong OOD, nhưng hầu như không đáng kể trong REST.

Bây giờ rõ ràng là phân tích thiết kế dữ liệu với các khái niệm OO không phải là một cách đáng tin cậy để đo lường nó: nó giống như so sánh táo và cam!

Trên thực tế, hóa ra những lợi ích của việc trở thành RESTful (hầu hết) là những lợi ích được nêu ở trên: đó là một mô hình tốt cho các API đơn giản trong một phương tiện chậm. Nó là rất bộ nhớ cache, và shardable. Nó có kiểm soát hạt mịn đối với độ chát, vv

Tôi hy vọng câu trả lời này (khá nhiều mặt) của bạn :-)


1 Vấn đề này là một phần của một tập hợp lớn hơn các vấn đề được gọi là không khớp trở kháng đối tượng quan hệ . Những người đề xuất ORM thường ở trong trại tìm hiểu sự tương đồng giữa phân tích dữ liệu và phân tích hành vi, nhưng các ORM đã bị chỉ trích muộn vì dường như họ không thực sự giải quyết được sự không phù hợp trở kháng và được coi là trừu tượng rò rỉ .

2 http://en.wikipedia.org/wiki/Cohesion_(computer_science)


Bạn nói đúng, tôi đã có thời gian khó khăn để bùng nổ câu hỏi của mình ở nhiều khía cạnh, để đưa ra một điểm cụ thể, vì câu hỏi đưa ra kết luận "sai" dựa trên sự tích lũy của các khía cạnh này. Tôi sẽ cố gắng trả lời quan điểm của bạn trong nhiều bình luận.
Alain

[văn bản 1] Tôi đã sử dụng từ "dữ liệu" để trừu tượng từ thế giới OO và REST. Từ nào bạn sẽ sử dụng cho các thuộc tính trừu tượng trong OO và cấu trúc dữ liệu trong REST?
Alain

@Alain "dữ liệu" là tốt, nhưng quan điểm của tôi là không nhầm lẫn giữa PODS và các đối tượng kinh doanh. Khi chúng ta nói về OOD, chúng ta thường nói về thứ hai. Đầu tiên là một sự tiện lợi, và nó có thể dễ dàng nghĩ về từ điển hoặc cấu trúc hoặc tuple.
Sklivvz

Có, tôi đồng ý, tôi sử dụng Backbone.js trong đó việc lưu mô hình đang sử dụng cấu trúc json đơn giản. Đây là nơi văn bản phản ánh kinh nghiệm mã hóa thực tế của tôi.
Alain

[văn bản 3] Điều này là mới đối với tôi. Tôi nghĩ rằng sự gắn kết được đo bằng số phương pháp thời gian sử dụng một mối quan hệ cụ thể ... Tôi thích cách bạn xem nó.
Alain

1

Với suy nghĩ này, nếu tôi không thể đơn giản hóa sự phát triển của mình (các mẫu thiết kế mặt tiền không áp dụng) và nếu tôi mang lại sự phức tạp hơn cho khách hàng của mình (xử lý tiết kiệm nguyên tử giao dịch), thì lợi ích của việc RESTful là gì?

Câu trả lời cho "lợi ích của việc RESTful ở đâu?" được phân tích kỹ lưỡng và giải thích tại đây: http://www.ics.uci.edu/~fielding/pub/dissertation/top.htmlm

Mặc dù vậy, sự nhầm lẫn trong câu hỏi này không phải là về đặc điểm của REST và cách đối phó với chúng, nhưng giả sử thiết kế các URL bạn đưa ra cho hệ thống ví dụ của bạn có liên quan đến RESTful. Xét cho cùng, REST tuyên bố rằng có những thứ được gọi là tài nguyên và mã định danh nên được cung cấp cho những thứ cần được tham chiếu, nhưng điều đó không cho thấy rằng, các thực thể trong mô hình ER của bạn nên có 1-1 tương ứng với các URL bạn đã tạo (các URL không nên mã hóa tính chính xác của các mối quan hệ ER trong mô hình).

Trong trường hợp liên hệ và địa chỉ, bạn có thể đã xác định một tài nguyên cùng thể hiện các thông tin này dưới dạng một đơn vị, mặc dù bạn có thể muốn trích xuất và lưu các thông tin này trong các bảng DB quan hệ khác nhau, bất cứ khi nào chúng được PUT hoặc POST .


1

Đó là bởi vì mặt tiền là một 'bùn'; bạn nên xem 'trừu tượng api' và 'api xích'. Api là sự kết hợp của hai bộ chức năng: I / O và quản lý tài nguyên. Tại địa phương, I / O vẫn ổn nhưng trong một kiến ​​trúc phân tán (ví dụ: proxy, cổng api, hàng đợi tin nhắn, v.v.), I / O được chia sẻ và do đó dữ liệu và chức năng trở nên trùng lặp và vướng mắc. Điều này dẫn đến một mối quan tâm xuyên suốt kiến ​​trúc. Điều này gây ra TẤT CẢ các apis hiện có.

Cách duy nhất để giải quyết vấn đề này là chức năng I / O trừu tượng cho API cho trình xử lý trước / sau (như trình xử lý trong Spring / Grails hoặc bộ lọc trong Rails) để chức năng có thể được sử dụng như một đơn nguyên và được chia sẻ giữa các phiên bản và bên ngoài dụng cụ. Dữ liệu cho yêu cầu / phản hồi cũng cần được đưa ra ngoài trong một đối tượng để nó có thể được chia sẻ và tải lại.

http://www.sl slideshoware.net/bobdobbes/api-abstraction-api-chained


0

Nếu bạn hiểu dịch vụ REST của bạn, hoặc nói chung bất kỳ loại API nào, giống như một giao diện bổ sung được hiển thị cho khách hàng để họ có thể lập trình (các) bộ điều khiển của bạn thông qua nó, điều đó đột nhiên trở nên dễ dàng. Dịch vụ này không có gì khác ngoài một lớp bổ sung trên logic biz của bạn.

Nói cách khác, bạn không phải phân chia logic biz giữa nhiều bộ điều khiển, giống như bạn đã làm trong hình trên, và quan trọng hơn, bạn không nên. Các cấu trúc dữ liệu được sử dụng để trao đổi dữ liệu không cần phải khớp với cấu trúc dữ liệu bạn sử dụng bên trong, chúng có thể hoàn toàn khác nhau.

Đó là trạng thái của nghệ thuật, và được chấp nhận rộng rãi, rằng việc đưa bất kỳ logic biz nào vào mã UI là một ý tưởng tồi. Nhưng mỗi UI chỉ là một loại giao diện (I trong UI) để kiểm soát logic biz phía sau. Do đó, dường như rõ ràng đó cũng là một ý tưởng tồi khi đưa bất kỳ logic biz nào vào lớp dịch vụ REST hoặc bất kỳ lớp API nào khác.

Về mặt khái niệm, không có nhiều sự khác biệt giữa UI và API dịch vụ.


Tôi đồng ý với khái niệm lớp, nhưng ý bạn là gì khi "lập trình bộ điều khiển của bạn thông qua nó"?
Alain

1
Tôi muốn nhấn mạnh một thực tế rằng, chính bộ điều khiển là dịch vụ thực sự. Giao diện bao quanh toàn bộ chỉ đơn thuần là một phương tiện để đạt được một cái gì đó. Bất kỳ giao diện nào tồn tại để dễ dàng truy cập vào chức năng được bọc, bằng cách này hay cách khác. GUI thực hiện điều này cho người dùng, API dịch vụ được sử dụng bởi khách hàng. Cả hai đối tượng mục tiêu đều muốn đạt được điều gì đó với những thứ được bao bọc phía sau giao diện. Tôi đồng ý rằng "chương trình" có thể không phải là từ ngữ tốt nhất cho điều đó, nhưng "điều khiển bộ điều khiển" nghe có vẻ khó xử ;-)
JensG
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.