Как стать автором
Обновить

Комментарии 24

Спасибо Вам за совет — обязательно ознакомлюсь с опытом фэйбука.

Заменять комментарии на аннонтацию @Description — это что-то новенькое. И в чем смысл?

Смысл в том, что очень полезно вносить описание параметров в конфигурационный файл — потому что когда редактируешь файл, то исходников под рукой нет, чтобы посмотреть, что это за параметр. А с помощью reflection нельзя прочитать javaDoc-и — остаётся аннотация.
Properies можно заставить работать c UTF-8 если ему подсовывать кастомный StreamReader. Совершенно не проблема же.
Не знал — спасибо за подсказку.
Можно конечно использовать конфигурационный сервер, и даже кто-то это делает (вроде), но это как-то напряжно — хочется что-нибудь проще, но эффективно.

Запилить свой велосипед проще конечно. А потом научить его хранить конфиги в zookeeper и ядексе. Вероятно, скоро вы скажете: а давайте хранить конфиги в гите, чтобы иметь над ними хоть какой-то контроль. И придете к конфигурационному серверу. Таким простым и не напряжным способом.

P.S. Кстати, а чем стандартный способ конфигурирования (configMap) в kubernetes не понравился?
Вы будете смеяться, но у нас есть реализация чтения из гита — просто мы её не вынесли в библиотеку. По поводу configMap в kubernetes-е — мы им пользуемся, но только для сторонних программ, а свои по привычке через zookeeper — просто все наши распределённые проекты имеют Apache Kafka — поэтому zookeeper у нас на халяву есть — к тому же мы привыкли корректировать конфиги на горячую — это удобно. Да, я знаю про rollout restart и всё такое, но горячие конфиги — это удобно
Кто ж конфиг файлы без имени бина делает.
Этих batchSize в приложении два десятка может быть. И все разные. А классы одинаковые под ними.

В вашем случае стоит сделать такой конфиг. Автоконвертация снейк в кемел предполагается.
<insert_to_pg_properties>
  <batchSize>100</batchSize>
</insert_to_pg_properties>


Не нравится xml, тоже самое легко на yaml пишется. Будет модненько.
Из-за одного параметра делать абстрактный базовый класс — я не вижу рациональности в этом. Из опыта получается, что общие параметры встречаются редко — у нас ни разу не возникало желание наследовать конфигурационные интерфейсы друг-от-друга.
Это вам везло.
Допустим у нас 3 разных базы. Ну как разных, имена разные и сервера местами разные. Сделать общий класс для конфигурации подключения просто напрашивается.
А придумать разные имена для трех одинаковых наборов параметров так себе удовольствие.

А уж threadpool'ы конфигурить так вообще оптом надо. И у них у всех есть poolSize. Называть его везде по разному запутаешься уже через год. А уж при рефакторинге забыть и получить одинаковые имена или перепутать парочку прям 100% гарантия.

И без привязки к действиям. У вас в приложении сколько раз retryCount и timeout с batchSize встречаются?
Да, наверное нам повезло. Если имеются куча разных баз данных, и они ещё к тому-же со временем прибывают, да и у каждой по своему настраиваемый пул коннектов, то да — там будут общие вещи и наследование конфигом станет уместным.

У нас много «retryCount и timeout с batchSize», но мы их не пытались объединять — порознь с ними работать удобнее, как нам кажется. Хотя может у Вас другое мнение. И я согласен — библиотека должна позволять это делать.

В Спринге это проблема.
Есть ещё spring cloud режим с refresh аннотацией, но без cloud было бы проще.
Бин пересоздать та ещё проблема. Потому через базу разве что читать.


Вообще в системах уже как бы 12factor app и best way хранить в env properties и 3 replicas для rolling update изменений без этих велосипедов.
Единственная сложность это шифрование. Нужно будет заморочиться над интеграцией в vault или aes для secrets, который по дефолту не включён.

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

Автообновление без рестарта вообще сомнительная вещь. Тот же batchSize из статьи. Он скорее всего уже передан в ThreadPoolExecutor и поменять его с гарантиями без пересоздания пула уже никак. И будет при старте одно, обновлено другим, а работает с первым. И наблюдать мы можем только второе. Что там внутри приложения а кто ж его знает?

Лучше сделать софт так чтобы его можно было рестартить когда угодно без любых спецэффектов. Так надежнее в конечном итоге.
да, поэтому я выше написал, что реплики и будет zero down time при обновлении переменных.

про наблюдаемость, сейчас пришли к понятию configmap в kubernetes, довольно удобная вещь, можно удобно просматривать переменные, работать с gitops итд, формировать их хоть руками, хоть через ansible и переопределять для контейнера, но не секьюрно конечно же, особенно если это настройки подключения к системам
Мы бины никогда не пересоздаём — полностью с Вами согласен — это та ещё проблема. Мы просто используем Supplier-ы для чтения параметров, и тогда ничего пересоздавать не нужно, и всё меняется на горячую.
Чуток критики — Образцовый, чисто «программисткий»(не хейт — есть и среди Программистов очень даже инженерно мыслящие люди) подход к процессу — «Мы не проектируем мы творим....», — конкретно — параметры не проектируются и не продумываются, да и увязывать с бизнес потребностями и инфраструктурными возможностями, похоже, люди смысла не видят…
Я благодарен за Вашу критику. Да мы заранее параметры конфигов и их сами не проектируем — они произвольно появляются на этапе разработки, но чаще на этапе сопровождения — в принципе проблем это у нас не вызывало. Рулит аннотация Description.

А чем не устраивает например http://www.cfg4j.org/ или http://owner.aeonbits.org/ ??? Тот самый фатальный недостаток?


В вашей библиотеке, насколько я могу судить, отсутствуют следующие важные вещи:


  • Зачастую конфиги имеют иерархическую структуру, поэтому нужно иметь возможность, чтобы пропертями могли быть другие Config-классы.
  • А как быть со пропертями-списками?
  • А что насчет других типов пропертей? Например LocalDate, URL, Duration, etc… Поэтому нужны дефолтные и кастомные конвертеры.
  • Если уж вы упомянули возможность горячего изменения пропертей, то необходим механизм, позволяющий "слушать" эти изменения. Например singleton-бины должны корректно апдейтнуть конфигурацию, если изменился релевантный параметр, а сервисы — еще и рестартнуться на горячую.
Спасибо Вам за Ваш конструктивный ответ, и в частности за эти ссылки — мы реально не знали, что они есть — нужно было изобрести свой велосипед, потом его несколько лет интенсивно эксплуатировать — потом написать статью про него в хабре (моя первая в жизни статья на хабре) — и только после этого получить ссылку на cfg4j и aeonbits. Только вот теперь дилемма — что использовать дальше в качестве конфигурации?

По поводу четырёх пунктов — часть из них уже есть, а части нету. И если будет принято решение развивать эту библиотеку, то они будут реализованы. По поводу разных типов параметров — я давно хотел сделать какой-нибудь кастомный конвертер, но всё руки не доходили.
Хочу ещё сказать пару слов про пресловутый «Фатальный недостаток». Я никогда не стремался создавать свои велосипеды — излишне злоупотреблять этим конечно нельзя — очень вредно для производства. Но в истории очень много новых велосипедов, которые оказались лучше оригиналов, самый яркий пример — Chrome Browser. Я конечно не претендую, что greetgo conf — станет лидером конфигурации Java систем во всём мире; но тот опыт, который уже получен в этом, думаю, стоит свеч.
А чем не подошёл typesafe config? Вполне расширяется для работы с тем же амазоном (parameter store/secrets manager)
Мы просто не знали про неё — спасибо Вам за информацию
Хочу обратиться ко всем комментаторам — спасибо Вам большое за Ваши комментарии — они оказались для нас очень полезными, хотя я совру, если скажу, что моё самолюбие не было задето.

Огромная благодарность команде habr-а за то, что Вы есть — мы намерены продолжать печататься здесь (у нас есть ещё пару «велосипедиков»!)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации