| 35. Сериализация: «за» и «против» | |
| В этой статье я не буду рассматривать детали реализации сериализации (…выдра бодро ядра кедра…). Скорее, это будут простые рассуждения на тему «за» и «против». | |
| Вообще говоря, отношение общества к сериализации довольно неоднозначное. В этом вы можете легко убедиться — попробуйте остановить десять случайных прохожих и спросить их, как они относятся к сериализации. Уверен, мнения будут самые разнообразные. И на это есть определенные причины. Сериализация как паттерн (если ее можно назвать паттерном), действительно, имеет массу как хороших свойств, так и плохих. Я постараюсь рассказать и о том и о другом максимально объективно. | |
| | |
| Хорошо | |
| Сериализация позволяет отображать практически любые пользовательские данные, выраженные типами C++, в любые внешние пространства данных. | |
| Сериализация, при соответствующей реализации, позволяет четко разделить обязанности на логическую и физическую интерпретации данных. Одной и той же логической интерпретации (например — XML) можно дать любое физическое обличие. Например, сохранение на диск, вывод на консоль или передача по сети. Верно и обратное. Логическая и физическая интерпретация полностью независимы друг от друга и могут прекрасно уживаться в любых комбинациях. | |
| Сериализация, в принципе, при правильном подходе прекрасно комбинируется и интегрируется практически с любыми механизмами ввода-вывода. | |
| | |
| Плохо | |
| Половина всех неприятностей, доставляемых сериализацией, обязаны тому, что язык C++ не имеет такого механизма как «reflection». Сериализацию невозможно автоматизировать. Во время компиляции вы не располагаете достаточным количеством информации о пользовательских типах данных, чтобы автоматизация была возможна. Да, можно ввести вспомогательные макросы, проверки уровня компиляции на полноту сериализации типа, и так далее, однако, это все не более чем «полуавтомат». При изменении структуры пользовательского типа, придется внести изменение по крайней мере в одном дополнительном месте. Это плохо, хотя от этого никуда и не деться. | |
| | |
| Сериализация очень не любит нестатические структуры. Например, структуры, некоторые поля которых являются опциональными. Мы ведь не можем в рантайме выкидывать или добавлять поля в языковые типы (можно конечно внутри каждого поля хранить признак, присутствует поле или отсутствует, но это не решит всех проблем, и опять же, является полным ахтунгом). Это плохо, поскольку большинство общепринятых форматов данных, имеющих древовидную структуру, являются динамическими. Попробуйте представить себе сериализацию HTML-документа. | |
| Вообще говоря, сериализация — это костыль. И она будет костылем до тех пор, пока в C++ не появятся полноценный reflection и виртуальные конструкторы. Нужна ли она в принципе — вопрос спорный. В качестве альтернативы сериализации можно легко использовать кодогенерацию, которая, кстати говоря, дает гораздо более широкие возможности. | |
| | |
| Вердикт | |
| Где же ее, несчастную сериализацию, собственно, стоит использовать? Мое скромное мнение заключается в том, что в принципе, идеальная программа не должна содержать сериализации. Но это должна быть слишком идеальная программа, такая идеальная, каких в жизни не бывает. | |
| Могу сказать точно, что не нужно использовать сериализацию для данных, работа с которыми не является критичной с точки зрения производительности. Например, аутентификация по протоколу kerberos предполагает структурирование пакетов данных по спецификации ASN1. Аутентификация по kerberos — это обмен несколькими пакетами размером несколько сот байт. Ничего критичного с точки зрения производительности в ней нет. Вместо того, чтобы использовать сериализацию для отображения типов C++ в формат ASN1, гораздо удобнее написать конвертор из XML в ASN1 и обратно, и работать через XQuery и XPath. Это значительно упростит и клиентский код и отладку приложения, поскольку все средства для работы с XML уже давно изобретены. | |
| Другое дело, если обработка данных критична с точки зрения производительности, и этих данных у вас очень много. Предположим, вам нужно рассчитать упругую деформацию при столкновении двух объемных тел, представленных несколькими миллионами (или миллиардами) полигонов. Конечно, никакой XML + XQuery/XPath здесь не канает. В этом случае сериализация вроде бы и имеет право на существование. Но стоит запомнить, что в данном случае сериализация — это лишь одно из возможных решений, ни в коем случае не являющееся наилучшим. | |
| Постарайтесь не использовать сериализацию для полиморфных типов. Ограничьтесь сериализацией базовых типов, открытых структур в стиле Plain C, а также STL- и boost-контейнеров. Эти типы данных наиболее близки к универсальным. В противном случае ваша программа обрастет такой гадостью как фабрики, и прочими излишествами нехорошими. | |
| boost::serialization? Да, есть такая библиотека. Да, она умеет сериализовать все подряд. Да, стоит разобраться, как она работает. Но не стоит сразу же хвататься за нее обеими руками и использовать везде, где это только возможно. Если вы научитесь обходиться без сериализации, не потеряв при этом изящества кода и скорости разработки, то это будет гораздо более ценное умение, нежели умение использовать boost::serialization. | |
| Если вы все же решили воспользоваться сериализацией в серьезном проекте, то обязательно разработайте ограничения, накладываемые на сериализуемые типы и отразите их в кодинг-гайдлайнах. | |
| Как говорится, «семь раз отмерь, один раз отрежь». Лично я стараюсь избегать использования сериализации. По мере сил. | |
| | |