Непозволительно высокая цена плохого API
В PostgreSQL есть конфиг с параметрами запуска СУБД — postgresql.conf. В нём параметры заданы в формате key = value. Например,
port = 5432 max_connections = 100 authentication_timeout = 1min
А ещё в PostgreSQL можно создавать расширения — по сути плагины. Если расширение хочет доставать из postgresql.conf какие-то свои параметры, оно должно определить их с помощью функции DefineCustomStringVariable. Вот пример из расширения basic_archive:
void _PG_init(void) { DefineCustomStringVariable( "basic_archive.archive_directory", "Archive file destination directory.", NULL, &archive_directory, "", PGC_SIGHUP, 0, check_archive_directory, NULL, NULL);
MarkGUCPrefixReserved("basic_archive"); }
Здесь задаётся название параметра, указатель на переменную, в которую надо записать его значение, хук проверки корректности значения и т.д. Главное, на что я хочу обратить ваше внимание, — этот вызов выглядит максимально декларативно. Начиная с названия — DefineCustomStringVariable — и заканчивая тем, что мы передаём туда пачку параметров, которые влияют на разные стадии времени жизни сервера СУБД. Видя такой вызов, я ожидаю, что он добавит это всё в какой-то список параметров конфига. А применяться это будет когда-то потом, когда мы будем парсить конфиг. Более того, если заглянуть в её реализацию, она, на первый взгляд, так и выглядит.
Зачем ты всё это рассказываешь?
postgresql.conf читается при старте сервера СУБД. Если в нём есть ошибки (например, указан путь к несуществующему файлу), надо аварийно прервать запуск сервера и сообщить об ошибке в лог. Кроме того postgresql.conf можно явно перечитать, когда сервер уже запущен. В этом случае об ошибках надо просто сообщить в лог, сохранив прежние значения параметров и продолжив работу.
У меня была задача реализовать такое поведение для параметра в моём расширении. Я был уверен, что DefineCustomStringVariable делает такое из коробки, потому что расширения для PostgreSQL создаются уже десятки лет...
Как же я был не прав... Я не буду перегружать вас, рассказывая весь свой путь, перейду сразу к финалу: 👉 у меня ушло примерно 2 часа — 2 часа, чтобы добавить поддержку нового параметра в конфиге, Карл! 👉 оказалось, что DefineCustomStringVariable сразу выполняет парсинг параметра из конфига, запуск всех хуков и инициализацию переменной, а не просто добавляет параметр в список. И важно, чтобы парсинг работал в режиме «сообщи об ошибке и продолжи со старым значением» 👉 чтобы парсинг падал при старте СУБД, нужно отдельно вручную вызывать его в режиме «fail fast»
Итого я считаю, что DefineCustomStringVariable — пример плохого API, который, во-первых, не позволяет решить простую типовую задачу быстро и легко, а во-вторых, требует детального понимания своей реализации, чтобы пользоваться им правильно.
Ок, а правильно-то как?
Мне в голову приходят две идеи. 1. Переименовать в DefineAndTryParseCustomStringVariable. Да, название перегружено, но оно хотя бы явно даёт понять, что парсить будем сразу. Это тут же поднимает вопрос, что происходит, если распарсить не удалось, и позволяет быстрее прийти к пониманию, что для «fail fast» надо писать отдельный код 2. Добавить отдельную функцию для use case «добавить параметр расширения» — AddExtenstionGuc(...). Внутри она бы делала DefineCustomStringVariable, а потом вызывала бы парсинг в режиме «fail fast». Неидеально, но решает пользовательскую задачу «добавь параметр конфига правильно».
❗️Итого, неудачный API design работы с параметрами конфига в расширениях стоил мне 2 часов рабочего времени, которые я мог бы уделить менее тривиальным задачам. Пока все программисты не превратились в тимлидов, у которых кода касаются только AI-агенты, за удобством и интуитивностью API всё ещё актуально следить.
· 15.04
А можно прикрутить плагин , который будет читать например json и пилить него в conf?
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён