Недавно я занимался разработкой своего собственного API, и с таким большим интересом к разработке API меня очень интересовало, как я могу улучшить свой дизайн API.
Один аспект, который возник несколько раз: (не пользователями моего API, а в моем наблюдении за обсуждением этой темы): нужно просто взглянуть на код, вызывающий API, что он делает .
Например, посмотрите это обсуждение на GitHub для диско- репо, оно выглядит примерно так:
foo.update_pinned(true, true);
Просто взглянув на код (не зная имен параметров, документации и т. Д.), Невозможно догадаться, что он собирается делать - что означает второй аргумент? Предлагаемое улучшение должно иметь что-то вроде:
foo.pin()
foo.unpin()
foo.pin_globally()
И это проясняет ситуацию (я полагаю, 2-й аргумент был о том, стоит ли связывать foo глобально), и я согласен, что в этом случае последующее, безусловно, будет улучшением.
Однако я полагаю, что могут быть случаи, когда методы для установки другого, но логически связанного состояния будут лучше представлены как один вызов метода, а не как отдельные, даже если вы не узнаете, что он делает, просто взглянув на код . (Таким образом, вам придется прибегнуть к просмотру имен параметров и документации, чтобы выяснить - что лично я всегда делал бы независимо от того, что, если я не знаком с API).
Например, я раскрываю один метод SetVisibility(bool, string, bool)
на FalconPeer и подтверждаю, что просто смотрю на строку:
falconPeer.SetVisibility(true, "aerw3", true);
Вы бы не знали, что он делает. Он устанавливает 3 различных значения, которые управляют «видимостью» falconPeer
в логическом смысле: принимать запросы на соединение, только с паролем и отвечать на запросы на обнаружение. Разделение этого на 3 вызова метода может привести к тому, что пользователь API установит один аспект «видимости», забыв указать другим, о которых я заставляю их думать, только выставив один метод для установки всех аспектов «видимости» . Кроме того, когда пользователь хочет изменить один аспект, он почти всегда захочет изменить другой аспект и теперь может сделать это за один вызов.
setSize(10, 20)
не так читабельно, как setSize(width=10, height=20)
или random(distribution='gaussian', mean=0.5, deviation=1)
. В языках с принудительными именованными параметрами булевы значения могут передавать точно такой же объем информации, что и использование перечислений / именованных констант, поэтому они могут быть полезны в API.
update
методе:foo.update(pinned=true, globally=true)
. Или:foo.update_pinned(true, globally=true)
. Таким образом, ответ на ваш вопрос должен также учитывать особенности языка, потому что хороший API для языка X может не подходить для языка Y и наоборот.