Платформа «1С: Предприятие» — что под капотом?
Привет, Хабр!
В этой статье мы начнем рассказ о том, как устроена внутри платформа «1С:Предприятие 8» и какие технологии используются при ее разработке.
Почему мы считаем, что это интересно? Во-первых, потому что платформа «1С:Предприятие 8» — это большое (более 10 миллионов строк кода) приложение на C++ (клиент, сервер и т.д.), JavaScript (веб-клиент), и, с недавних пор еще и Java. Большие проекты бывают интересны хотя бы в силу масштаба, ведь вопросы, незаметные в маленькой кодовой базе, в таких проектах встают в полный рост. Во-вторых, «1С:Предприятие» — это тиражируемый, «коробочный» продукт, а статей про такие разработки на Хабре совсем немного. А еще всегда интересно узнать, как там живут в других командах и фирмах.
Итак, приступим. В этой статье мы дадим обзор некоторых технологий, которые применяются в Платформе, обрисуем ландшафт, без глубокого погружения в реализацию. Ведь для многих механизмов подробный рассказ потянет на отдельную статью, а для некоторых — на целую книгу!
Для начала стоит определиться с базовыми вещами — что такое платформа «1С:Предприятие» и из каких компонентов она состоит. Ответ на этот вопрос не так прост, ведь под термином «Платформа» (для краткости будем называть ее именно так) понимают и средство разработки бизнес-приложений, и среду исполнения, и средства администрирования. Условно можно выделить следующие составляющие:
- кластер серверов
- «тонкий» клиент, способный подключаться к серверу по http и собственному бинарному протоколу
- клиент для работы в двухзвенной архитектуре с БД, размещенной на жестком диске или сетевой папке
- веб-клиент
- средства администрирования сервера приложений
- среда разработки (известная как Конфигуратор)
- среда исполнения для iOS, Android и Windows Phone (мобильная платформа 1С)
Все эти части, за исключением веб-клиента, написаны на C++. Кроме того, существует недавно анонсированный Конфигуратор нового поколения, написанный на Java.
Нативные приложения
Для разработки нативных приложений используется C++03. Под Windows в качестве компилятора используется Microsoft Visual C++ 12 (профиль совместимый с Windows XP), а под Linux и Android — gcc 4.8, для iOS — clang 5.0. Стандартная библиотека используется единая для всех ОС и компиляторов — STLPort. Это решение позволяет снизить вероятность ошибок, специфичных для реализации STL. Сейчас мы планируем переход на реализацию STL, поставляемую с CLang, так как STLPort прекратил свое развитие и несовместим с включенным режимом поддержки C++ 11 в gcc.
Кодовая база сервера при этом общая на 99%, клиента — процентов на 95%. Более того, даже мобильная платформа использует тот же C++ код, что и «большая», хотя там процент унификации несколько ниже.
Как большинство пользователей С++ мы не претендуем на использование 100% возможностей языка и его библиотек. Так, у нас практически не используется Boost, а из возможностей языка — динамическое приведение типов. При этом мы активно применяем:
- STL (в частности, строки, контейнеры и алгоритмы)
- множественное наследование, в т.ч. множественное наследование реализации
- шаблоны
- исключения
- умные указатели (собственная реализация)
За счет использования множественного наследования интерфейсов (полностью абстрактных классов) становится возможной компонентная модель, речь о которой пойдет ниже.
Компоненты
Для обеспечения модульности весь функционал разделен на компоненты, представляющие из себя динамические библиотеки (*.dll под Windows, *.so — под Linux). Всего компонентов более полутора сотен, приведем описания некоторых из них:
backend | Содержит «движок» метаданных платформы |
accnt | Объекты, которые прикладные разработчики используют для построения бухгалтерского учета (планы счетов и регистры бухгалтерии) |
bsl | Движок исполнения встроенного языка |
nuke | Собственная реализация аллокатора памяти |
dbeng8 | Движок файловой базы. Простая файл-серверная машина баз данных, основанная на ISAM, включающая также простой SQL-процессор |
wbase | Содержит базовые классы и функции для реализации пользовательского интерфейса Windows — оконные классы, доступ к GDI и т. п. |
Разделение на множество компонент полезно с нескольких точек зрения:
- Разделение способствует лучшему проектированию, в частности лучшей изоляции кода
- Из набора компонентов можно гибко собирать разные варианты поставки:
- Например, инсталляция тонкого клиента будет содержать wbase, но не будет backend
- а на сервере wbase, наоборот, не будет
- оба варианта будут, конечно, содержать nuke и bsl
Все нужные для данного варианта запуска компоненты загружаются при старте программы. Это, в частности, нужно для регистрации SCOM-классов, речь о которых пойдет ниже.
SCOM
Для декомпозиции на более низком уровне используется система SCOM — схожая по идеологии с ATL библиотека. Для тех, кто с ATL не работал, кратко перечислю основные возможности и особенности.
Для специально оформленного класса SCOM:
- Предоставляет фабричные методы, позволяющие создать класс из другой компоненты, зная только его название (без раскрытия реализации)
- Предоставляет инфраструктуру умных указателей с подсчетом ссылок. За временем жизни SCOM-класса не нужно следить вручную
- Позволяет узнать, реализует ли объект конкретный интерфейс, и автоматически привести указатель на объект к указателю на интерфейс
- Создать объект-сервис, всегда доступный через метод get_service и т.д.
Например, можно описать в компоненте json.dll вот такой класс для чтения JSON:
//////////////////////////////////////////////////////////////////////////////
// JSONStreamReader - Класс для чтения данных JSON
class ATL_NO_VTABLE JSONStreamReader :
public SCOM_ObjectRoot,
public SCOM_Class<JSONStreamReader, &SCOM_CLSIDOF(JSONStreamReader)>,
public IJSONStreamReader
{
public:
BEGIN_COM_MAP( JSONStreamReader)
COM_INTERFACE_ENTRY(IJSONReader)
COM_INTERFACE_ENTRY(IJSONStreamReader)
END_COM_MAP()
... члены класса ...
}
Классы, экземпляры которых можно создавать из других компонент, нужно зарегистрировать в SCOM-машине:
SCOM_CLASS_ENTRY(JSONStreamReader)
Этот макрос опишет специальный статический класс-регистратор, конструктор которого будет вызван при загрузке компоненты в память.
После это можно создать его экземпляр в другой компоненте:
IJSONStreamReaderPtr jsonReader = create_instance<IJSONStreamReader >(SCOM_CLSIDOF (JSONStreamReader ));
На основе компонентной модели SCOM реализована и бизнес-логика, и интерфейсная часть «1С:Предприятия».
Пользовательский интерфейс
Кстати, об интерфейсах. Мы не используем стандартные контролы Windows, наши элементы управления реализованы напрямую на Windows API. Для Linux-версии сделана прослойка, работающая через библиотеку wxWidgets.
Библиотека элементов управления не зависит от других частей «1С:Предприятия» и используется нами еще в нескольких небольших внутренних утилитах.
За годы развития 1С:Предприятие внешний вид контролов менялся, но серьезное изменение принципов произошло только один раз, в 2009 году, с выходом версии 8.2 и появлением «управляемых форм». Помимо изменения внешнего вида, фундаментально изменился принцип компоновки формы — произошел отказ от попиксельного позиционирования элементов в пользу flow-компоновки элементов. Кроме того, в новой модели элементы управления работают не напрямую с доменными объектами, а со специальными DTO (Data Transfer Objects).
Эти изменения позволили создать веб-клиент «1С:Предприятия», повторяющий С++ логику контролов на JavaScript. Мы стараемся поддерживать функциональную эквивалентность между тонким и веб клиентами. В том случае, когда это невозможно, например, из-за ограничений доступных из JavaScript API (например, возможности работы с файлами очень ограничены), мы часто реализуем нужную функциональность при помощи расширений браузеров, написанных на C++. На данный момент мы поддерживаем Internet Explorer (Windows), Google Chrome(Windows), Firefox (Windows и Linux) и Safari (MacOS).
Кроме того, технология управляемых форм используется для создания интерфейса мобильных приложений на платформе 1С. На мобильных устройствах отрисовка контролов реализована с использованием «родных» для операционной системы технологий, но уже для логики компоновки формы и реакции интерфейса используется тот же код, что и в «большой» платформе «1С:Предприятие».
Интерфейс 1С на ОС Linux
Интерфейс 1С на мобильном устройстве
Интерфейс 1С на ОС Windows
Интерфейс 1С — веб-клиент
Open source
Хотя мы и не используем стандартные для С++ разработчика библиотеки под Windows (MFC, контролы из WinAPI), не все компоненты мы пишем сами. Уже упоминалась библиотека wxWidgets, а еще мы используем:
- cURL для работы с HTTP и FTP.
- OpenSSL для работы с криптографией и установки TLS соединений
- libxml2 и libxslt для разбора XML
- libetpan для работы с почтовыми протоколами (POP3, SMTP, IMAP)
- mimetic для разбора сообщений электронной почты
- sqllite для хранения журналов работы пользователей
- ICU для интернационализации
Список еще можно продолжать.
Кроме того, мы используем сильно модифицированную версии Google Test и Google Mock при разработке юнит-тестов.
Библиотеки потребовали адаптации для совместимости со SCOM-моделью организации компонент.
Распространенность 1С делает Платформу отличной проверкой на прочность для используемых в ней библиотек. Разнообразие пользователей и сценариев быстро обнаруживает ошибки даже в самых редкоиспользуемых участах кода. Мы исправляем их у себя и стараемся отдавать обратно авторам библиотек. Опыт взаимодействия оказывается очень разный.
Разработчики cURL и libetpan быстро откликаются на pull-request, но патч, например, в OpenSSL нам так и не получилось отдать.
Заключение
В статье мы коснулись нескольких основных аспектов разработки Платформы 1С: Предприятие. В ограниченном объеме статьи мы затронули лишь некоторые интересные, на наш взгляд, аспекты. Какие темы были бы интересны Вам в следующих статьях?
Как реализована мобильная платформа 1С?
Описание внутреннего устройства веб-клиента?
Или, может быть, Вам интересен процесс выбора фич для новых релизов, разработки и тестирования?
Пишите в комментариях!