Статьи

Golang — Необязательные аргументы для API

Недавно я был направлен к статье Дэйва Чейни « Функциональные опции для дружественных API», где он делится своими мыслями о дизайне для дополнительных параметров в API. Дейв завершает предложение функциональных аргументов, которые необязательно передаются конструктору типов. Нет сомнений в том, что этот дизайн лучше, чем один конструктор с множеством аргументов.

Однако:

Дизайн Дейва является излишним для 99% случаев использования и накладывает ненужный налог как на сопровождающего, так и на потребителя этих API.

Разработчики, интегрирующиеся с этими API-интерфейсами, являются потребителями , равно как и читатели (так называемые рецензенты кода).

Мое предложение

Более простая альтернатива: два конструктора, один по умолчанию, другой принимает структуру конфигурации .

Вот мой предложенный проект для конструкторов Дейва в перспективе :

01
02
03
04
05
06
07
08
09
10
11
12
package term
 
// I identified just three options after a quick scan of the README:
// Baud rate, and either CBreakMode or RawMode.
type Options struct {
    CBreakMode bool  // Defaults to RawMode if false
    Baud               int
}
 
func Default(name string) (*Term, error) {...}
 
func Custom(name string, options Options) (*Term, error) {...}

Что мы получаем …

С точки зрения использования

Уменьшенное многословие: количество появлений term символа уменьшено. Величина этого преимущества увеличивается линейно с количеством необязательных параметров:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package consumer
 
import "github.com/pkg/term"
 
func DaveDesign() {
    // default
    term, err := term.Open("/dev/ttyUSB0")
 
    // custom
    term, err := term.Open(
        "/dev/ttyUSB0",
        term.Speed(57600),
        term.CBreakMode,
    )
}
 
func MyDesign() {
    // A ctor named 'Default' immediately conveys the possibility of
    // customization to a consumer
    term, err := term.Default("/dev/ttyUSB0")
 
    // custom
    term, err := term.Custom(
        "/dev/ttyUSB0",
        term.Options{
            Baud:               57600,
            CBreakMode: true,
        }
    )
}

С точки зрения обслуживания

Уменьшено количество юнит-тестов: сокращение набора опций для объекта-значения делает ненужными тесты для них.

Что мы теряем …

С точки зрения использования

Ничего, насколько я могу видеть.

Символ Default четко указывает на возможность использования пользовательских Term , так что разработчик, использующий этот API, будет искать альтернативы, если это необходимо. Это означает, что этот дизайн не имеет дополнительных запутанных аспектов.

С точки зрения обслуживания

N / A. Мы улучшаем ремонтопригодность, уменьшая количество артефактов, которые нам нужно проверить.

Любые проверки и / или вычисления могут быть извлечены в их собственные функции (статические или функции-члены) типа конструктора.

Опубликовано на Java Code Geeks с разрешения Джорджа Аристи, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Golang — Необязательные аргументы для API

Мнения, высказанные участниками Java Code Geeks, являются их собственными.