Gần đây tôi đã phát triển API của riêng mình và với sự quan tâm đầu tư vào thiết kế API, tôi đã rất quan tâm đến cách tôi có thể cải thiện thiết kế API của mình.
Một khía cạnh đã xuất hiện một vài lần là (không phải bởi người dùng API của tôi mà trong cuộc thảo luận quan sát của tôi về chủ đề này): người ta nên biết chỉ bằng cách xem mã gọi API đang làm gì .
Ví dụ, xem cuộc thảo luận này trên GitHub cho repo diễn ngôn , nó diễn ra như sau:
foo.update_pinned(true, true);
Chỉ cần nhìn vào mã (mà không biết tên tham số, tài liệu, v.v.) người ta không thể đoán nó sẽ làm gì - đối số thứ 2 có nghĩa là gì? Cải tiến được đề xuất là có một cái gì đó như:
foo.pin()
foo.unpin()
foo.pin_globally()
Và điều đó làm sáng tỏ mọi thứ (lập luận thứ 2 là liệu có nên ghim foo trên toàn cầu không, tôi đoán vậy), và tôi đồng ý trong trường hợp này sau này chắc chắn sẽ là một sự cải thiện.
Tuy nhiên tôi tin rằng có thể có các trường hợp trong đó các phương thức để đặt các trạng thái khác nhau nhưng có liên quan về mặt logic sẽ được hiển thị tốt hơn dưới dạng một cuộc gọi phương thức thay vì các phương thức riêng biệt, mặc dù bạn sẽ không biết nó đang làm gì chỉ bằng cách nhìn vào mã . (Vì vậy, bạn sẽ phải dùng đến việc xem xét các tên tham số và tài liệu để tìm hiểu - cá nhân tôi sẽ luôn làm bất kể điều gì xảy ra nếu tôi không quen với API).
Ví dụ: tôi trưng ra một phương thức SetVisibility(bool, string, bool)
trên FalconPeer và tôi thừa nhận chỉ nhìn vào dòng:
falconPeer.SetVisibility(true, "aerw3", true);
Bạn sẽ không biết nó đang làm gì. Nó đang thiết lập 3 giá trị khác nhau để kiểm soát "mức độ hiển thị" falconPeer
theo nghĩa logic: chấp nhận các yêu cầu tham gia, chỉ với mật khẩu và trả lời các yêu cầu khám phá. Việc chia nhỏ này thành 3 lệnh gọi phương thức có thể dẫn đến người dùng API đặt một khía cạnh của "khả năng hiển thị" mà quên đặt cho người khác mà tôi buộc họ phải suy nghĩ bằng cách chỉ đưa ra một phương thức để đặt tất cả các khía cạnh của "khả năng hiển thị" . Hơn nữa, khi người dùng muốn thay đổi một khía cạnh, họ hầu như luôn muốn thay đổi một khía cạnh khác và bây giờ có thể thực hiện điều đó trong một cuộc gọi.
setSize(10, 20)
không thể đọc được bằng setSize(width=10, height=20)
hoặc random(distribution='gaussian', mean=0.5, deviation=1)
. Trong các ngôn ngữ có các tham số được đặt tên bắt buộc, booleans có thể truyền tải chính xác cùng một lượng thông tin như sử dụng enum / hằng số được đặt tên, vì vậy chúng có thể tốt trong các API.
update
phương thức đơn giản :foo.update(pinned=true, globally=true)
. Hoặc :foo.update_pinned(true, globally=true)
. Vì vậy, câu trả lời cho câu hỏi của bạn cũng cần tính đến các tính năng ngôn ngữ, bởi vì API tốt cho ngôn ngữ X có thể không tốt cho ngôn ngữ Y và ngược lại.