Pull to refresh

Comments 54

все её данные надо держать одномоментно в памяти;

А если данных будут десятки гигабайт? Или предполагается запуск на мощных серверах с сотнями гигов ОЗУ? В памяти надо держать то, что необходимо в данный момент.

СУБД типа SQLite не даёт каких-то преимуществ (отпадают базы переписки в почте или мессенджере);

Отпадание баз переписки — это проблема конкретных мессенжеров, кривости рук их разработчиков (вы про Skype?). Сама СУБД тут ни в чем не виновата…

SQLite продвигает свой формат БД как формат документа. По-моему, из-за сложностей программирования с ним имеет смысл работать именно как с СУБД.

Не очень понятно, что в этом плохого. Библиотеки для SQLite есть для многих языков программирования. Расширяемость — вообще не проблема — добавляй новые столбцы в таблицу или создавай новые таблицы. Иерархическая структура данных — в виде реляционной БД. Файл целиком грузить в память не нужно. Вручную разбирать его тоже не нужно, запросами можно получать данные, необходимые именно в этом конкретном месте. Аналогично с записью. Формат файла документирован, достаточно стороних инструментов для его просмотра и редактирования, если будет такая необходимость.
Совершенно верно, вы сказали тот случай, когда СУБД более чем оправдана: данных много, и нет нужды держать все в памяти. Потому и сказал: отпадают базы переписки. Но что, мало прог, где реально всё держим в памяти?

Во-первых, в принципе работа с СУБД сложна, по опыту. Во-вторых, бывают и очень нелюбимы программистами изменения структуры файла — и на XML-то это противное дело, а на БД тем более.
Прелесть БД — бэкап из коробки, множественный доступ, согласованность, целостность.
Если программа пишется в одно лицо, и только одно приложение будет шариться по файликам — то да, россыпь файлов ограниченна только фантазиями разработчика.
Но данная лафа кончается, когда к данным необходимо ходить из нескольких модулей одновременно и появляется требование иметь хоть сколько нибудь не противоречивый бекап.
в принципе работа с СУБД сложна
Сарказм?

Исходя из п.4, вам оочень стоит рассмотреть SQLite как формат, убирающий большинство проблем с потерями. Поскольку при чтении-записи старые версии программы смогут работать со знакомыми им данными, не убивая старые при перезаписи части информации.

Вы, по-моему, что-то не так поняли. Пункты, на которые вы отвечаете, содержатся в разделе «Мы разрабатываем программу, которая...», т.е. это некоторые выставленные предусловия, для которых автор приводит решение. Одно из рассматриваемых предусловий — «все данные надо держать в памяти».
Автор не говорит что «всегда надо данные держать в памяти, а SQLite не дает преимуществ», автор говорит «рассмотрим случай, когда данные надо держать в памяти, в этом случае SQLite не даст нам преимуществ».
Отпадают — имеется в виду «не рассматриваем», «это не наш вопрос».
Первое — я не очень понял, но похоже на XML-лайт. Второе — сериализация через рефлексию, и, как я уже сказал, сэкономил работы рефлексией — молодец. Но, надеюсь, они позволили в сложных случаях забираться вручную в структуру тэга.
Второе — ключевая фраза «Protocol Buffers — структура данных, которая затем компилируется в классы».
Всё равно это разновидность рефлексии при компиляции. А что, разве только при выполнении она бывает? Главный недостаток рефлексии — при сложных изменениях структуры будут костыли.
Да. Когда объект знает о своём внутреннем устройстве.
Тогда обратите внимание: «рефлексия… означает процесс… во время выполнения». Так что:
только при выполнении она бывает?

ответ: Да. И «сэкономил работы рефлексией. [Google]— молодец»
Не только при исполнении. При компиляции тоже возможна. Гугли «compile-time reflection».
Но тогда Ваш ответ в 07:44 ложен. Увы, ухожу в оффлайн.
Но что, мало прог, где реально всё держим в памяти?

Для небольших программ, например, программ редактирования документов, вполне оправдано держать все в памяти. Но попробуйте, например, в LibreOffice открыть документ на десятки мегабайт — уже почувствуете боль. А если объем данных заранее неизвестен и может быть очень большим — тут нужны иные подходы.

Во-первых, в принципе работа с СУБД сложна, по опыту.

Достаточно будет выучить самые базовые вещи SQL, этого уже хватит для работы. Более сложные конструкции могут и не понадобиться.

Во-вторых, бывают и очень нелюбимы программистами изменения структуры файла — и на XML-то это противное дело, а на БД тем более.

Вот тут не согласен. В случае СУБД вообще нет никакой нужды лезть в структуру файла. Например, добавились новые колонки в таблицу. Один раз делаешь ALTER TABLE при миграции данных на новый формат (да, версионность нужна, куда без нее. Но даже версию можно хранить в БД в отдельной таблицу). Те места в коде, где эти колонки не используются, можно вообще не трогать, там все будет работать по-прежнему. Аналогично с добавлением новых таблиц. То есть ты в принципе не касаешься конкретной физической структуры файла, а работаешь непосредственно с данными.
Тут, получается, ALTER по любому чиху, даже если добавляем какой-то параметр.

Сложность работы с СУБД не столько в сложности SQL, сколько в промежуточном слое между программной логикой и обёрткой над СУБД, который генерирует гарантированно корректный SQL и инкапсулирует стандартную логику (то ли ORM, то ли горбушка попроще).
Если атрибутов много и часто меняется их набор, то в базе хранят их в виде obj_id + attr_key + attr_value, тогда alter не нужен.

re ORM: если полноценный орм тащить не хочется, то между ним и ручным написанием запросов есть ещё куча готовых промежуточных решений.

Можете уточнить, каких?

А мешает ли что-либо, для часто изменяющегося списка параметров, завести отдельную таблицу вроде Parameters, в которой делать insert/delete по необходимости?
Всё равно это разновидность рефлексии при компиляции. А что, разве только при выполнении она бывает?
В страшных костылях для обеспечения совместимости, как на этапе чтения, так и на этапе записи.

А вы не пробовали ini файлы? В Delphi их поддержка есть с незапамятных времён. А с некоторых пор даже json поддерживается стандартными классами.
В чём плюс ini по сравнению с sqlite — сразу есть вменяемый (типа CRUD) API, и скорость, как ни странно, в разы выше. Минусы — нет транзакционности из коробки, неэффективно хранение бинарных данных.

Кстати есть отличный формат toml — фактически ini файлы, только стандартизированные.

Если наложить определённые ограничения на TOML, будет неплохой XML-лайт. «Просто так» TOML не годится для потокового считывания.
Ну, например, программа фотопроявки под названием DxO Photolab, известная своим высокотехнологичным шумодавом, работает на INI-файлах. Но сколько там данных у программы фотопроявки, повторяю… Самый большой файл, который нашёл у себя, около 50K. А для больших объёмов INI плохо пригодны.
Кажется, автор попал в плен XML-дискурса. Ему подавай или XML, или XML-лайт, или бинарный XML. А ведь он изначально проектировался из соображений человекочитаемости (ну да, не получилось, но тем не менее).

Если требования человекочитаемости нет, то намного лучше делать свой формат, разумеется, бинарный, не придерживаясь идеологии иных форматов, которые делали с совершенно другими целями и исходя из других соображений. Например, вместо хранения ключей (названий параметров) в строковом виде, можно использовать числовые идентификаторы, а лучше хэши. Это упрощает формат и экономит место. Расширяемость формата обеспечивается попросту тем, что парсер игнорирует незнакомые ключи.

Когда не ограничиваешь себя изначально чужими парадигмами, можно создать формат, превосходно подходящий под свои конкретные задачи, «срезая углы» там, где это допустимо и акцентируя то, что требуется. Важно не стремиться чересчур сильно его обобщить.

Просто игнорировать незнакомые ключи может привести к отображению мусора для просмотрщиков и к испорченному файлу для редакторов. Нужны флаги как в PNG: public/private, safe to ignore, safe to copy.

Это всё из-за того произошло, что я в свою очередь тоже попал в плен своей парадигмы, в которой мне не нужно редактировать и сохранять файл с незнакомыми тегами. Что тоже в общем-то подтверждает главную мысль.
Таки у PNG это следствие того, что есть контент и его метаданные. Настройки немного про другое. Но в целом — да, есть шанс что настройки зависят друг от друга и просто игнорировать незнакомые может быть ломающим поведением.
Я попал в плен этого дискурса, потому что выяснилось самое ценное преимущество XML — древовидность.
Все пудели — собаки, но не все собаки — пудели. То, что в XML есть древовидность, вовсе не означает, что для древовидного формата нужен именно XML или что-то ему родственное.
Если требования человекочитаемости нет, то намного лучше делать свой формат, разумеется, бинарный

Зачем свой? Куча бинарных форматов тоже существует, не надо изобретать велосипед. Например, MessagePack, в котором поддерживаются расширения, древовидные структуры. Он быстрый и компактный.

Тут по обстоятельствам. Иногда готовый формат превосходно подойдёт, а иногда лучше всё-таки создать свой, хорошо приспособленный к конкретным требованиям.
JSON несколько проще в программировании, чем XML, но всё равно сложен. Плюс затруднено потоковое считывание: JSON различает объекты и массивы, и синтаксис JS говорит, что от перестановки атрибутов результат не меняется.

Попробуйте YAML

Автор написал про YAML. И он кстати значительно сложнее.
Сравните JSON grammar и YAML grammar. Формат описания разный, но общее представление о разнице в сложности, думаю, даёт.

В своё время использовал XML как простой вариант хранения настроек.
Когда XML конфиг вырос до мегабайт, начал тормозить запуск приложения, я переехал в БД. Самый бюджетный вариант — SQLite. Запуск снова выполняется быстро, конвертировать БД намного проще (т.к. есть куча готовых вариантов в интернетах), дополнительно на уровне БД теперь есть ограничения — нельзя как в текстовые конфиги забить невалидные данные, даже ссылочная целостность уже дает много плюсов.

Из вопросов к автору — что с сохрананием старых настроек в новый файл? Ну т.е. есть у меня приложение версии 10, есть приложение версии 20, и есть конфиг версии 15. Сделать чисто запуск версии 10 на конфиге версии 15 не так сложно, а вот чтобы ещё и работало сохранение настроек без даунгрейда до 10 версии — сложная работа, стоит ли, какие есть хорошие приемы? У меня чаще получается, что 10 перетирает конфиг на 10 версию, 20 обновляет до 20 (потому что он то знает как мигрировать).

ПС: json читабельнее xml, не понял минусов json-а в статье.

Ещё важное преимущество SQlite — файлы вообще говоря сложная штука. Нужно делать сложные трюки вроде копирования файла, записи изменений в временную копию, при сохранении нужно атомарно удалить старый файл и переименовать временный.
Тем временем в SQLite можно просто сделать BEGIN TRAN, изменения делать сразу в БД, а при нажатии кнопки сохранить делать COMMIT.
Если семантика реляционки не подходит, можно сделать либо Entity-Attribute-Value, либо каждый объект хранить в JSON / другом формате в строковом поле в БД, либо в бинарном в protobuf. Даже просто ради написанной за вас транзакционности я бы текстовые файлы не использовал.
Текстовый формат нужен в случае, если файл смотрит/пишет человек.

Не рассмотрены S-expressions (и их возможные вариации).

Расширяемый и компактный формат? ASN.1?
Ещё бы человекочитаемым был этот ASN.1 =)
Инструментов почти нет, довольно неудобная, имхо, штука.
ASN.1 XER — вполне читаем, прозрачно конвертируется в BER. Как нет инструментов? Куча стандартных либ. При том написанных для телекома, т.е. работающих, раз мы тут пишем всякое. Написал нотацию и вперед. Wireshark, громадное количество тулов.
Либы есть, но в блокноте не открыть, и вот визуально быстро глянуть — честно бесплатных тулов не видел хороших. Wireshark возможно ваш проф инструмент, я его видел давно и издали, поверю на слово.
Я в курсе что за формат, я в курсе как он работает, я смогу написать парсер даже сам, если вдруг что. Я больше к тому, что не сильно популярен он, в отличие от кучи других форматов, для которых найдется пяток бесплатных и удобных тулов для всего-всего.
В видео все так же вопросы заданные в статье актуальны. Формат вы предлагаете, но всё ещё нет ничего готового, нужно описать весь мир самому. Да и библиотек всё ещё нет.
В такой ситуации, JSON всё ещё заметно лучше.
Вот такой придумали XML-лайт. Верно, причина та же.
JSON придуман, кстати, по другой причине — если источнику данных доверяешь, на JS в две строчки разбирается.
Вместо SQLite можно взять NoSQL базу (ключ-значение), например LMDB или LevelDB. С ними не надо писать SQL запросы. Да и SQLite при желании можно превратить в key-value базу.
У базы данных преимущество в том, что вам не нужно парсить и заново сериализовывать всю сохранку, если требуется поменять одно единственное поле.

Не освещен вопрос возможности / удобства использования в системах контроля версий — тут SQLite и прочие бинарные форматы жестко проигрывают человекочитаемым.

Тут вопрос поставлен с ног на голову. СКВ предназначены как раз для человекочитаемых форматов. Если данные не предназначены для редактирования вручную, нет особого смысла ни делать формат человекочитаемым, ни контролировать версии через СКВ.

Ни в коей мере с этим не спорю. Это просто еще один фактор, который следует учитывать, решая, какой формат выбирать для сохранения данных. И лично я, в ходе размышлений, склонялся к SQLite, но невозможность эффективной работы в СКВ делает этот формат неприменимым в целом ряде случаев.

Sign up to leave a comment.

Articles