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

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

Но ведь System.Configuration есть в виде пакета с поддержкой .NETStandard — использование xml конфигов — не стопер перехода на .NETStandard.

И если у вас 12 сервисов и есть необходимость динамического изменения конфигурации, то почему просто не использовать Consul или что-то подобное?
XML — далеко не единственное, что держит нас пока что от полного перехода на .NET Core всех серверов, хотя мы движемся в этом направлении. Сам по себе XML — да, не стопер.
При этом у читалки XML из стандартного пакета есть проблемы, которые в принципе усложняют работу с ним, связанные прежде всего с плохой реакцией на опечатки в XML (которые в силу многословности XML не так уж редки), которые как раз дополнительно простимулировали нас уходить от него.
Читалку из .NETStandard для XML мы, честно скажу, не проверяли. У нее с обработкой опечаток дела обстоят лучше?

Consul и т.п. сервисы — да, была такая идея, и она, собственно говоря, никуда не делась, в будущем вполне возможно перейдем на какое-то единое решение, которое, кроме прочего, позволит конфигурировать не только указанные 12 серверов, но и все остальные сервисы, разрабатываемые у нас в компании. Но прямо сейчас это потребовало бы, по ощущениям, сильно больше телодвижений, чем просто выкинуть один способ работы с файликами конфигурации и заменить его на другой, всё остальное трогать нам сейчас не пришлось.
Мы пользуемся «голым» XmlDocument, а обёрткой, которая маппит секции из app.config в объект конфигурации. Если в этом объекте пометить какое-то свойство, как обязательно, но на этапе чтения настроек всё развалится.
У нас чтение производилось с использованием XmlDocument, он в половине случаев опечатки молча проглатывал (если честно — не помню хотя бы раза, когда он не проглатил бы). Какие конкретно примеры — сходу не подскажу, посмотрю потом при случае.
Да с XmlDocument-то всё понятно. Он просто позволяет загрузить в память xml документ. А раз xml не накладывает особых ограничений на названия нод, то при чтении конфига типа
<config>
  <param name="a" value="b"/>
  <parameter name="a" value="b"/>
</config>

Просто будет документ в котором есть две ноды с разным названием.
Не то, чтобы я говорю, что вам не надо было переезжать на yaml, просто кажется что вы поменяли шило на мыло.
С другой стороны, если произошла унификация кода для работы с конфигами среди всех сервисов и проектов, то профит неоспорим.
я работал с конфигурациями, где размер конфигов в мегабайтах.
так вот XML, от корого вы отказались, спокойно можно прочитать.
json/YAML конфиги даже на 500 стр уже читать и редактировать нереально.
если вы не знаете, что XML расширяется своими типами как только угодно, и вам было просто лень открыть гугл, прочитать, и дописать свой тип, который легко настраивается потом, для парсинга в тип при чтении, то это другой вопрос.
<setting name="MCXSettings" serializeAs="String">
   <value>Inactive, ChartLen: 1000, PrintLen: 50, UseProxy: False</value>
</setting>

кто мешал сделать типа такого
<setting name="MCXSettings" serializeAs="String">
   <CustomType>
   <Inactive>
True
</Inactive>
   <ChartLen>
 1000 
</ChartLen>
   <PrintLen>
 50
</PrintLen>
   <UseProxy>
 False
</UseProxy>
</CustomType>
</setting>

?
это занялоб несколько часов, а не недели гугления и боли. я б на месте заказчика за такое самоволосьтво не платил.
В других проектах у нас конфиги были и есть на YAML, по нему отзывы были положительные: достаточно удобно читать и редактировать. Размеры файлов там разные, по несколько сотен строк тоже есть, но чаще — несколько десятков. Поэтому решили опробовать его и здесь.
В этом проекте после перехода на YAML лично у меня тоже скорее положительные ощущения. Конфиги стали сильно меньше, опечатки в них исчезли, все проблемы стали видны сразу на старте приложения. Единственный сайд-эффект, который я пока наблюдал, то, что по началу табы, которые иногда получались вместо пробелов, портили чтение файла, но это не большая проблема, т.к. такие ошибки, как я уже сказал, сразу же всплывали на старте сервиса, плюс сама проблема достаточно легко решилась настройкой в редакторе.
В варианте, который привели выше, опечатки, можно сказать, исключены, если пользоваться стандартным XmlSerializer — он если не найдёт нужный тип в объекте, то просто при десериализации развалится.
YAML позволит ужать по весу большие файлы, поскольку XML не самый экономный язык. Но на этом все преимущества и заканчиваются. Если раньше обрабатывался нетипизированный документ, и парсер проглатывал все синтаксически корректное (про список параметров внури значений я даже говорить не хочу), то и сейчас будет не лучше. YAML парсер так же будет глотать все опечатки, в лучшем случае ругаясь на совпадающие отступы.
Раньше парсер проглатывал несуществующие (неправильно написанные) тэги. Сейчас этого не происходит в силу предложенного решения сопоставлений ожидаемого конфига и файла-конфига «один-к-одному».
Я тут как раз на дня хотел объяснить людям почему JSON плох для конфигов/данных погуглил и выяснил что и YAML это мягко говоря странная штука, нашёл только один проект похожий на адекватный StrictYAML, как раз у них есть и аргументация против остальных форматов.
Как у вас обстоят дела с валидацией конфигов? Судя по тому, что жалуетесь на опечатки — никак. А зря. И вот по этой причине я бы посоветовал вам оставаться на XML, и сделать XSD схемы для всех конфигов (и прочих документов, если есть).

Я может быть отстал от жизни, но для JSON/YAML общепризнанных стандартных форматов схем документов пока нет вроде бы.

Т.е. оставайтесь на XML, но сделайте конвертеры XML to YAML и обратно. Вручную правьте YAML. Храните и используйте — XML. Ну может быть за редким исключением, когда размер имеет архиважное значение, ужимайте в YAML. Хотя по-моему если использовать ZIP архивацию — вообще без разницы практически, будет ли предварительная стадия XML to YAML.

Такой подход облегчит вам экспорт-импорт и визуализацию на любые случаи жизни. XML всё-таки более распространён пока. Больше возможностей по трансформации в любые форматы — см. XSLT. Опять же — а есть ли уже что-то подобное для JSON/YAML?
Т.е. вместо XML-ки с конфигами поддерживать еще и XSD-схемы для каждого вида серверов? Это усложнение работы, а не ее упрощение.
В решении с YAML в том виде, как оно реализовано, получилось реальное упрощение чтения конфига глазами + более прозрачная работа парсера, вываливающая все встречающиеся ошибки явным образом.
Простите, я может чего-то недопонимаю, но как ваш парсер «вывалит ВСЕ встречающиеся ошибки явным образом», не имея описания формата? Я как-то привык считать, что конфиг — это часть API. API должно быть явным образом описано, стандартизировано, иметь версию, описание должно иметь версию и должно быть сохранено в git (или типа того).

Наверняка вы имеет ввиду только ошибки YAML стандарта. Но опечатка в имени параметра этот фильтр пройдёт. И пропущенный обязательный параметр, и неправильное значение (вне диапазона, допустим) — это всё тоже пройдёт незамеченным.

Самое лучшее описание API — то, которое умеет читать какой-нибудь парсер. Который может проверить документ на соответствие описанному стандарту. Так вот я и спрашиваю — есть ли подобное для JSON/YAML?

А то, что описание API так или иначе надо поддерживать… Ну что тут поделаешь — да, можно смотреть на это как на усложнение работы. И не делать эту часть работы. Какое-то время. Но когда вы сами начнёте путаться в своих конфигах и их версиях — вы об этой невыполненной части работы вспомните. Вздохнёте глубоко… И начнёте её делать. Имхо.

В статье как раз описывается как реализована проверка полноты и корректности конфига. Ошибки yaml синтаксиса вываливает yaml-читалка, а ошибки вида "не хватает такого-то параметра" или "этот параметр я не знаю" вываливает наш код. Описание формата у нашего кода конечно же есть, иначе зачем нам вообще этот конфиг, если мы не знаем, что из него брать. См. класс AppSettings в статье.

Описание "ожидаемого содержимого конфига", а не формата, имел в виду

Насчёт схем формата, вынесенных в отдельный файл, наподобие xsd, я не задавался пока что таким вопросом, т.к. это было бы усложнение задачи поддержки конфигов. Нам в любом случае надо было бы и в коде поддерживать соответствие "такое-то поле мы используем вот здесь". Т.е. для добавления нового поля, например, нам потребовалось бы сделать это в xml, в xsd и в коде. Сейчас мы обходимся только добавлением в yml и в коде. Не вижу смысла усложнять работу

Т.е. вместо XML-ки с конфигами поддерживать еще и XSD-схемы для каждого вида серверов?

Желательно их автогенерировать, благо стандартный XmlSerializer это умеет. Впрочем, и в ручной поддержке актуальности схем я не вижу ничего страшного если новые настройки появляются не часто.

Прочитав статью я не совсем понял вашу аргументацию при отказе от XML в пользу YAML.
Да, XML многословен но не «плоский» как вы сказали а довольно легко поддерживающий иерархии.
У меня на проекте мы подумываем полностью отказаться от локальных конфигов в пользу централизованного сервиса. Да тот же Redis будет более удобен с минимальными настройками что бы хранить конфиги, а сервису /приложению нужно только знать как оттуда вычитать и какой десериализатор использовать (это может быть единственной настройкой которую как то нужно передать сервису). Локальные конфиг файлы будь-то XML/YAML/JSON/ini файл это большое зло.
Централизованный сервис мы тоже рассматриваем.
XML не «плоский», плоская та структура, которую мы ранее для него предусматривали. Реализовать в нем вложенную структуру, конечно же, вполне можно было, но монструозность конфигов сильно увеличилась бы.
Получившиеся у нас сейчас конфиги хорошо читаются глазами.
Аналогичные ощущения после прочтения статьи.
Схему автор не использовал.
Тоже думаю хранить конфиги централизовано. (Руки еще не дошли до прода)
Вот только вопросы с выбором формата и инструмента ( read\write) остаются.
Я смотрю в сторону простейшего UI который поможет быстро сделать конфиг и хранением этого в JSON виде в Redis или в чем то подобном.
В идеале хочется следующего — приложение знает один единственный URL или иную точку входа и знает свой собственный тенант идентификатор (у нас малтитенатси) и этого хватает что бы вычитать свой конфиг и запуститься.
Раз в X минут приложение перечитывает конфиг файл.
JSON удобен тем что можно для разных версий приложения добавлять новые настройки и пока не меняется схема то все работает. Но это только мой Proof Of Concept и бизнес может просто не дать денег на это следуя правилу — «оно и так работает а как припечет то может тогда».
ААА. Сути это не меняет.
(Я говорил про конфиг для инициализации. Думаю брать напрямую из базы или через кеш со временем жизни(типа redis), если вдруг будет не доступен сервис с конфигами)

В любом случае, имея централизованный конфиг, его можно деплоить по тем же правилам, что и сам сервис, но отдельно от сервиса. Можно откатывать.
Очень удобно, если все это реализовать. Нужно ли — не знаю.
Может вы это и так уже делаете…
Зарегистрируйтесь на Хабре, чтобы оставить комментарий