SlideShare a Scribd company logo
Парсим и кодогенерируем с
использованием clang
Антон Наумович
Юрий Ефимочев
О нас
Разрабатываем бэкап-решение
Антон Наумович
Тимлид в LogicNow
В прошлом: разработчик в
Microsoft (Hyper-V)
Специализация:
производительность,
отладка, дизайн
Юрий Ефимочев
Архитектор в LogicNow
Специализация:
высоконагруженные
отказоустойчивые
системы на C++
Кодогенерация
Классическое разделение
1. Пассивная – разовая, с ручными правками
2. Активная – автоматическая, регулярная, без
ручных правок
Частые релизы проекта
Вызовы
● быстрая реакция на изменение требований
● минимизация человеческих ошибок
● высокое покрытие тестами
Microservice-архитектура
Рутинные задачи
● создание сетевых протоколов
● создание слоя хранения данных
● тесты, тесты, тесты
Как генерируют протоколы
Минусы
● нет контроля над процессом генерации
● генерированные исходники “чужеродны” для
проекта
● дублирование кода (“родные” сущности
сосуществуют с генерированными)
Protobuf: пример
// Types.proto
message CustomerInfo
{
required int32 id = 1;
required string name = 2;
required string email = 3;
}
⇓
class CustomerInfo : public ::google::protobuf::Message {
public:
static const ::google::protobuf::Descriptor* descriptor();
static const CustomerInfo& default_instance();
void Swap(CustomerInfo* other);
// implements Message ----------------------------------------------
CustomerInfo* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
void CopyFrom(const CustomerInfo& from);
void MergeFrom(const CustomerInfo& from);
void Clear();
bool IsInitialized() const;
... только декларация 113 строк кода!
gsoap: пример
// Types.gsoap.h
class CustomerInfo
{
public:
int id 1:;
string name 0:;
string email 0:;
};
⇓
И это только декларации, сериализация еще похлеще :)
class SOAP_CMAC CustomerInfo
{
public:
int id;
std::string *name;
std::string *emailAddress;
public:
virtual int soap_type() const { return 38; } /* = unique id
SOAP_TYPE_CustomerInfo */
virtual void soap_default(struct soap*);
virtual void soap_serialize(struct soap*) const;
virtual int soap_put(struct soap*, const char*, const char*) const;
virtual int soap_out(struct soap*, const char*, int, const char*) const;
virtual void *soap_get(struct soap*, const char*, const char*);
...
Single Source of Truth?
Single Source of Truth!
// CustomerInfo.h
struct CustomerInfo
{
int Id;
string Name;
CustomerType Type;
};
Сущности Интерфейсы
// ICustomerManager.h
class ICustomerManager
{
virtual int CreateCustomer(CustomerInfo const& customer) = 0;
virtual void UpdateCustomer(CustomerInfo const& customer) = 0;
virtual void DeleteCustomer(int customerId) = 0;
virtual CustomerInfo GetCustomer(int customerId) const = 0;
virtual ICustomerInfoIteratorPtr EnumerateCustomers() const = 0;
virtual ~ICustomerManager() {}
};
Декларации на С++ и есть самодостаточное
базовое мета-описание протокола
Что возможно с clang?
Инструменты на основе clang:
● clang-format
● clang-check
● clang-tidy
● статический анализ, индексирование кода, подсветка синтаксиса
ClangTool: парсер С++ деклараций
Template: ICustomerInfoIterator
Method: EnumerateCustomers
Template: ICustomerInfoIteratorPtr
Struct: CustomerInfo
Type: int
Enum: CustomerType
Type: std::string
Class: ICustomerManager
Method: CreateCustomer
Method: UpdateCustomer
Method: DeleteCustomer
Method: GetCustomer
Вход ClangTool:
struct CustomerInfo
{
int Id;
std::string Name;
CustomerType Type;
};
typedef IIterator<CustomerInfo> ICustomerInfoIterator;
typedef std::unique_ptr<ICustomerInfoIterator>
ICustomerInfoIteratorPtr;
class ICustomerManager
{
public:
virtual int CreateCustomer(CustomerInfo const& curstomer) = 0;
virtual void UpdateCustomer(CustomerInfo const& customer) = 0;
virtual void DeleteCustomer(int customerId) = 0;
virtual CustomerInfo GetCustomer(int customerId) const = 0;
virtual ICustomerInfoIteratorPtr EnumerateCustomers() const = 0;
virtual ~ICustomerManager() {}
};
Реализация: ~500 строк кода
ClangTool: результат (schema)
{
"Interface" : "ICustomerManager",
"Enums" :
[
{ "Name" : "CustomerType", "Values" : [ "Undefined", "Managed", "Unmanaged" ] }
],
"Structs" :
[
{
"Name" : "CustomerInfo",
"Fields" :
[
{ "Name" : "Id", "Type" : "int" },
{ "Name" : "Name", "Type" : "std::string" },
{ "Name" : "Type", "Type" : "CustomerType::Enum" }
]
}
],
"Methods" :
[
{
"Name" : "AddCustomer",
"Arguments" : [ { "Name" : "CustomerInfo", "Type" : "CustomerInfo" } ],
"ReturnType" : "void"
},
...
{
"Name" : "EnumerateCustomers",
"Arguments" : [],
"ReturnType" : "ICustomerInfoIteratorPtr"
}
]
}
Cхема кодогенерации
Шаблоны кодогенерации пишутся разово под класс задач
ClangTool Schema TemplateTool Generated.h/cppInput.h/cpp
Templates
Реализация: TemplateTool
// StructSerialization.gen
void CppToJson(<%struct.Name%> const& native, Json::Value& json)
{
json["typename"] = "<%struct.Name%>";
<%foreach field in struct.Fields%>
CppToJson(native.<%field.Name%>, "<%field.Name%>", json);
<%end%>
}
TemplateTool – кодогенератор на основе шаблонов
// CustomerInfoSerialization.cpp
void CppToJson(CustomerInfo const& native, Json::Value& json)
{
json["typename"] = "CustomerInfo";
CppToJson(native.Id, "Id", json);
CppToJson(native.Name, "Name", json);
CppToJson(native.Type, "Type", json);
}
⇓
Общая схема компиляции
Code Generator = ClangTool + TemplateTool
CodeGenerator Generated.h/cppInput.h/cpp
Templates
Compiler
Binary
JSONAPI_BEGIN(ManagementApi)
...
JSONAPI_ADD_INTERFACE
(
NAME
CustomerManager
INTERFACE
ICustomerManager
INTERFACE_HEADER
Interface/ICustomerManager.h
INCLUDES
Interface/CustomerInfo.h
Core/Iterators/IIterator.h
)
...
JSONAPI_END()
Конфигурация кодогенератора (CMake)
Пример использования протокола
// Server.cpp
#inculude "Management/CustomerManager.h"
#inculude "ManagementApi/Generated/CustomerManagerDispatcher.h"
int main()
{
CustomerManager customerManager;
JsonApiService apiService;
apiService.Register<CustomerManagerDispatcher>(customerManager);
apiService.Start(ports);
}
// Client.cpp
#include "ManagementApi/Generated/CustomerManagerClient.h"
int main()
{
JsonApiClient apiClient("https://domain/jsonapi");
ICustomerManagerPtr customerManager(new CustomerManagerClient(apiClient));
CustomerInfo const info = customerManager->GetCustomer(42);
}
Базы данных
// CustomerInfo.h
struct CustomerInfo
{
int Id;
CustomerType Type;
string Name;
};
// CustomerInfo.ddl
CREATE TABLE CustomerInfo
(
Id INT(4) NOT NULL,
CustomerType INT(4),
Name CHAR(20)
)
уже описанным
способом
⇒
1. Преобразуем С++ декларации в SQL (DDL)
2. Генерируем также и Object-Relational Mapping слой
Базы данных: шаг дальше
С++ 98/2003 (комментарии)
// CustomerInfo.h
struct CustomerInfo
{
int Id;
CustomerType Type; // FK: CustomerType.Id
string Name;
};
Если недостаточно синтаксиса по умолчанию
С++ 11/14 (атрибуты)
// CustomerInfo.h
struct CustomerInfo
{
int Id;
[[FK: CustomerType.Id]]
CustomerType Type;
string Name;
};
// CustomerInfo.ddl
CREATE TABLE CustomerInfo
(
Id INT(4) NOT NULL,
CustomerType INT(4) NOT NULL
REFERENCES CustomerType(Id),
Name CHAR(20),
KEY CustomerType (CustomerType)
)
⇒
Что еще пригодно для генерации?
● Типовые юнит-тесты (для протоколов, баз данных)
● Клиенты для протоколов (на любых языках!) - к
примеру, для авто-тестов:
<%foreach method in Methods%>
@step(log_output=False)
def <%method.Name%>(<%foreach param in method.InputParams%><%param.Name%>, <%end%>):
return __send_post_request('<%method.Name%>'
<%foreach param in method.InputParams%>,<%param.Name%>=<%param.Name%><%end%>)
<%end%>
<%foreach struct in Structs%>
class <%struct.Name%>(JSONStruct):
def __init__(self<%foreach field in struct.Fields%>, <%field.Name%>=None<%end%>):
<%foreach field in struct.Fields%>
self.<%field.Name%> = <%field.Name%>
<%end%>
def __repr__(self):
return str(serialize(self))
<%end%>
- клиент на Python
Генерация дизайн паттернов *
Задача:
● Есть семейство типовых интерфейсов
● Требуется всему семейству добавить поведение
(например, права доступа, потокобезопасность и т.д.)
class ThreadSafe<%persistencyName%>Persistency :
public I<%persistencyName%>Persistency
{
public:
ThreadSafe<%persistencyName%>Persistency(I<%persistencyName%>PersistencyPtr
decoratee, std::mutex& mutex);
private:
<%foreach method in Methods%>
virtual <%method.ReturnType%> <%method.Name%>(<%foreach param in
method.Params%><%if !param.IsFirst%>, <%end%><%param.ExactType%>
<%param.Name%><%end%>)<%if method.IsConstant%> const<%end%>;
<%end%>
private:
I<%persistencyName%>PersistencyPtr m_decoratee;
std::mutex& m_mutex;
};
Итого
Выгоды
● Устранение рутинной работы
● Минимизация человеческих ошибок
● Решение типового набора задач “за
бесплатно”
● Более высокий уровень абстракции
Проблемы
● Версионность (реакция на изменения кода)
● Сопряжение с рукописным кодом
● Сложность конфигурации генератора
Спасибо! Вопросы?
Антон Наумович
Anton.Naumovich@LogicNow.com
Юрий Ефимочев
Yury.Efimochev@LogicNow.com

More Related Content

PPT
Юнит-тестирование и Google Mock. Влад Лосев, Google
PPTX
Когда в C# не хватает C++ . Часть 2.
PPTX
Когда в C# не хватает C++
PPTX
Когда в C# не хватает C++ . Часть 3.
PPTX
CodeFest 2012. Сошников Д. — Разработка мобильных приложений на платформе Mic...
PPTX
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
PPTX
Основы и применение статического анализа кода при разработке лекция 1
PDF
О сложностях программирования, или C# нас не спасет?
Юнит-тестирование и Google Mock. Влад Лосев, Google
Когда в C# не хватает C++ . Часть 2.
Когда в C# не хватает C++
Когда в C# не хватает C++ . Часть 3.
CodeFest 2012. Сошников Д. — Разработка мобильных приложений на платформе Mic...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Основы и применение статического анализа кода при разработке лекция 1
О сложностях программирования, или C# нас не спасет?

What's hot (11)

PDF
Программирование на языке C Sharp (СИ решетка) ПРАКТИКУМ
PDF
Droidcon Moscow 2015. NFC-платежи в Android. Антон Курицын - Кошелек
PDF
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
PDF
Шишки, набитые за 15 лет использования акторов в C++
PPTX
Современный статический анализ кода: что умеет он, чего не умели линтеры
PDF
Возможности и проблемы FFI в Haskell. Александр Вершилов
PDF
Разница в подходах анализа кода компилятором и выделенным инструментом
PPTX
Автоматическая генерация патчей для уязвимого исходного кода
PPTX
Unit tests final
PDF
Основы ооп на языке C#. Часть 2. базовый синтаксис.
PPTX
Code Contracts ABC 16.04.2011
Программирование на языке C Sharp (СИ решетка) ПРАКТИКУМ
Droidcon Moscow 2015. NFC-платежи в Android. Антон Курицын - Кошелек
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Шишки, набитые за 15 лет использования акторов в C++
Современный статический анализ кода: что умеет он, чего не умели линтеры
Возможности и проблемы FFI в Haskell. Александр Вершилов
Разница в подходах анализа кода компилятором и выделенным инструментом
Автоматическая генерация патчей для уязвимого исходного кода
Unit tests final
Основы ооп на языке C#. Часть 2. базовый синтаксис.
Code Contracts ABC 16.04.2011
Ad

Similar to Парсим и кодогенерируем для С++ с использованием clang (20)

ODP
GetDev.NET: Снова Эрланг
PDF
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
PPTX
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
PPTX
о некоторых вопросах бинарной совместимости в C++
PDF
Акторы на C++: стоило ли оно того?
PDF
Язык параллельного программирования Cray Chapel
PDF
Павел Артёмкин — Разработка C++ API для реализации алгоритмов на больших графах
PDF
Ekb 2013 artemkin(1)
PDF
Practical Language for Extracting Data from Source Codes and Preparing Them f...
PDF
Шаблоны C++ и базы данных. Сергей Федоров. CoreHard Spring 2019
PDF
Архитектура в Agile: слабая связность
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
PDF
Расширение библиотеки STL для С++. Наборы и итераторы
PPTX
Статический и динамический полиморфизм в C++, Дмитрий Леванов
PDF
Предметно-ориентированные языки программирования (DSL)
PDF
Hacking PostgreSQL. Обзор исходного кода
PPTX
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
PPTX
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
PDF
доклад про Llvm
PPTX
Эффективный C++
GetDev.NET: Снова Эрланг
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
о некоторых вопросах бинарной совместимости в C++
Акторы на C++: стоило ли оно того?
Язык параллельного программирования Cray Chapel
Павел Артёмкин — Разработка C++ API для реализации алгоритмов на больших графах
Ekb 2013 artemkin(1)
Practical Language for Extracting Data from Source Codes and Preparing Them f...
Шаблоны C++ и базы данных. Сергей Федоров. CoreHard Spring 2019
Архитектура в Agile: слабая связность
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Расширение библиотеки STL для С++. Наборы и итераторы
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Предметно-ориентированные языки программирования (DSL)
Hacking PostgreSQL. Обзор исходного кода
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
доклад про Llvm
Эффективный C++
Ad

More from corehard_by (20)

PPTX
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
PPTX
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
PDF
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
PPTX
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
PPTX
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
PPTX
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
PPTX
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
PPTX
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
PPTX
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
PDF
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
PDF
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
PDF
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
PPTX
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
PDF
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
PDF
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
PDF
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019

Парсим и кодогенерируем для С++ с использованием clang

  • 1. Парсим и кодогенерируем с использованием clang Антон Наумович Юрий Ефимочев
  • 2. О нас Разрабатываем бэкап-решение Антон Наумович Тимлид в LogicNow В прошлом: разработчик в Microsoft (Hyper-V) Специализация: производительность, отладка, дизайн Юрий Ефимочев Архитектор в LogicNow Специализация: высоконагруженные отказоустойчивые системы на C++
  • 3. Кодогенерация Классическое разделение 1. Пассивная – разовая, с ручными правками 2. Активная – автоматическая, регулярная, без ручных правок
  • 4. Частые релизы проекта Вызовы ● быстрая реакция на изменение требований ● минимизация человеческих ошибок ● высокое покрытие тестами
  • 5. Microservice-архитектура Рутинные задачи ● создание сетевых протоколов ● создание слоя хранения данных ● тесты, тесты, тесты
  • 6. Как генерируют протоколы Минусы ● нет контроля над процессом генерации ● генерированные исходники “чужеродны” для проекта ● дублирование кода (“родные” сущности сосуществуют с генерированными)
  • 7. Protobuf: пример // Types.proto message CustomerInfo { required int32 id = 1; required string name = 2; required string email = 3; } ⇓ class CustomerInfo : public ::google::protobuf::Message { public: static const ::google::protobuf::Descriptor* descriptor(); static const CustomerInfo& default_instance(); void Swap(CustomerInfo* other); // implements Message ---------------------------------------------- CustomerInfo* New() const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const CustomerInfo& from); void MergeFrom(const CustomerInfo& from); void Clear(); bool IsInitialized() const; ... только декларация 113 строк кода!
  • 8. gsoap: пример // Types.gsoap.h class CustomerInfo { public: int id 1:; string name 0:; string email 0:; }; ⇓ И это только декларации, сериализация еще похлеще :) class SOAP_CMAC CustomerInfo { public: int id; std::string *name; std::string *emailAddress; public: virtual int soap_type() const { return 38; } /* = unique id SOAP_TYPE_CustomerInfo */ virtual void soap_default(struct soap*); virtual void soap_serialize(struct soap*) const; virtual int soap_put(struct soap*, const char*, const char*) const; virtual int soap_out(struct soap*, const char*, int, const char*) const; virtual void *soap_get(struct soap*, const char*, const char*); ...
  • 10. Single Source of Truth! // CustomerInfo.h struct CustomerInfo { int Id; string Name; CustomerType Type; }; Сущности Интерфейсы // ICustomerManager.h class ICustomerManager { virtual int CreateCustomer(CustomerInfo const& customer) = 0; virtual void UpdateCustomer(CustomerInfo const& customer) = 0; virtual void DeleteCustomer(int customerId) = 0; virtual CustomerInfo GetCustomer(int customerId) const = 0; virtual ICustomerInfoIteratorPtr EnumerateCustomers() const = 0; virtual ~ICustomerManager() {} }; Декларации на С++ и есть самодостаточное базовое мета-описание протокола
  • 11. Что возможно с clang? Инструменты на основе clang: ● clang-format ● clang-check ● clang-tidy ● статический анализ, индексирование кода, подсветка синтаксиса
  • 12. ClangTool: парсер С++ деклараций Template: ICustomerInfoIterator Method: EnumerateCustomers Template: ICustomerInfoIteratorPtr Struct: CustomerInfo Type: int Enum: CustomerType Type: std::string Class: ICustomerManager Method: CreateCustomer Method: UpdateCustomer Method: DeleteCustomer Method: GetCustomer Вход ClangTool: struct CustomerInfo { int Id; std::string Name; CustomerType Type; }; typedef IIterator<CustomerInfo> ICustomerInfoIterator; typedef std::unique_ptr<ICustomerInfoIterator> ICustomerInfoIteratorPtr; class ICustomerManager { public: virtual int CreateCustomer(CustomerInfo const& curstomer) = 0; virtual void UpdateCustomer(CustomerInfo const& customer) = 0; virtual void DeleteCustomer(int customerId) = 0; virtual CustomerInfo GetCustomer(int customerId) const = 0; virtual ICustomerInfoIteratorPtr EnumerateCustomers() const = 0; virtual ~ICustomerManager() {} }; Реализация: ~500 строк кода
  • 13. ClangTool: результат (schema) { "Interface" : "ICustomerManager", "Enums" : [ { "Name" : "CustomerType", "Values" : [ "Undefined", "Managed", "Unmanaged" ] } ], "Structs" : [ { "Name" : "CustomerInfo", "Fields" : [ { "Name" : "Id", "Type" : "int" }, { "Name" : "Name", "Type" : "std::string" }, { "Name" : "Type", "Type" : "CustomerType::Enum" } ] } ], "Methods" : [ { "Name" : "AddCustomer", "Arguments" : [ { "Name" : "CustomerInfo", "Type" : "CustomerInfo" } ], "ReturnType" : "void" }, ... { "Name" : "EnumerateCustomers", "Arguments" : [], "ReturnType" : "ICustomerInfoIteratorPtr" } ] }
  • 14. Cхема кодогенерации Шаблоны кодогенерации пишутся разово под класс задач ClangTool Schema TemplateTool Generated.h/cppInput.h/cpp Templates
  • 15. Реализация: TemplateTool // StructSerialization.gen void CppToJson(<%struct.Name%> const& native, Json::Value& json) { json["typename"] = "<%struct.Name%>"; <%foreach field in struct.Fields%> CppToJson(native.<%field.Name%>, "<%field.Name%>", json); <%end%> } TemplateTool – кодогенератор на основе шаблонов // CustomerInfoSerialization.cpp void CppToJson(CustomerInfo const& native, Json::Value& json) { json["typename"] = "CustomerInfo"; CppToJson(native.Id, "Id", json); CppToJson(native.Name, "Name", json); CppToJson(native.Type, "Type", json); } ⇓
  • 16. Общая схема компиляции Code Generator = ClangTool + TemplateTool CodeGenerator Generated.h/cppInput.h/cpp Templates Compiler Binary
  • 18. Пример использования протокола // Server.cpp #inculude "Management/CustomerManager.h" #inculude "ManagementApi/Generated/CustomerManagerDispatcher.h" int main() { CustomerManager customerManager; JsonApiService apiService; apiService.Register<CustomerManagerDispatcher>(customerManager); apiService.Start(ports); } // Client.cpp #include "ManagementApi/Generated/CustomerManagerClient.h" int main() { JsonApiClient apiClient("https://domain/jsonapi"); ICustomerManagerPtr customerManager(new CustomerManagerClient(apiClient)); CustomerInfo const info = customerManager->GetCustomer(42); }
  • 19. Базы данных // CustomerInfo.h struct CustomerInfo { int Id; CustomerType Type; string Name; }; // CustomerInfo.ddl CREATE TABLE CustomerInfo ( Id INT(4) NOT NULL, CustomerType INT(4), Name CHAR(20) ) уже описанным способом ⇒ 1. Преобразуем С++ декларации в SQL (DDL) 2. Генерируем также и Object-Relational Mapping слой
  • 20. Базы данных: шаг дальше С++ 98/2003 (комментарии) // CustomerInfo.h struct CustomerInfo { int Id; CustomerType Type; // FK: CustomerType.Id string Name; }; Если недостаточно синтаксиса по умолчанию С++ 11/14 (атрибуты) // CustomerInfo.h struct CustomerInfo { int Id; [[FK: CustomerType.Id]] CustomerType Type; string Name; }; // CustomerInfo.ddl CREATE TABLE CustomerInfo ( Id INT(4) NOT NULL, CustomerType INT(4) NOT NULL REFERENCES CustomerType(Id), Name CHAR(20), KEY CustomerType (CustomerType) ) ⇒
  • 21. Что еще пригодно для генерации? ● Типовые юнит-тесты (для протоколов, баз данных) ● Клиенты для протоколов (на любых языках!) - к примеру, для авто-тестов: <%foreach method in Methods%> @step(log_output=False) def <%method.Name%>(<%foreach param in method.InputParams%><%param.Name%>, <%end%>): return __send_post_request('<%method.Name%>' <%foreach param in method.InputParams%>,<%param.Name%>=<%param.Name%><%end%>) <%end%> <%foreach struct in Structs%> class <%struct.Name%>(JSONStruct): def __init__(self<%foreach field in struct.Fields%>, <%field.Name%>=None<%end%>): <%foreach field in struct.Fields%> self.<%field.Name%> = <%field.Name%> <%end%> def __repr__(self): return str(serialize(self)) <%end%> - клиент на Python
  • 22. Генерация дизайн паттернов * Задача: ● Есть семейство типовых интерфейсов ● Требуется всему семейству добавить поведение (например, права доступа, потокобезопасность и т.д.) class ThreadSafe<%persistencyName%>Persistency : public I<%persistencyName%>Persistency { public: ThreadSafe<%persistencyName%>Persistency(I<%persistencyName%>PersistencyPtr decoratee, std::mutex& mutex); private: <%foreach method in Methods%> virtual <%method.ReturnType%> <%method.Name%>(<%foreach param in method.Params%><%if !param.IsFirst%>, <%end%><%param.ExactType%> <%param.Name%><%end%>)<%if method.IsConstant%> const<%end%>; <%end%> private: I<%persistencyName%>PersistencyPtr m_decoratee; std::mutex& m_mutex; };
  • 23. Итого Выгоды ● Устранение рутинной работы ● Минимизация человеческих ошибок ● Решение типового набора задач “за бесплатно” ● Более высокий уровень абстракции Проблемы ● Версионность (реакция на изменения кода) ● Сопряжение с рукописным кодом ● Сложность конфигурации генератора

Editor's Notes

  • #4: Мы с вами поговорим сегодня о кодогенерации, как она облегчает жизнь и о том для каких классов задач она применима. Я расскажу о своем опыте применения кодогенерации для С++. Пару слов о терминологии - классичеси, кодогенерация делится на 2 класса: пассивная (разовая, с ручными правками) и активная (автоматически, регулярно, без ручных правок). Мой доклад будет об активной кодогенерации.
  • #5: Одним из самых критичных для бизнеса аспектов является сейчас скорость выхода продукта на рынок и сопутствующее этой скорости качества. По ряду причин так сложилось, что в доменах для которых применяется С++, этот показатель не самый высокий по сравнению с другими технологиями. Не буду говорить, что предложу панацею, но кодогенерация в некоторых областях решает все три эти проблемы.
  • #6: Перейдем к конкретике. Один из широко распространенных вариантов архитектурных решений сегодня - архитектура, основанная на микросервисах. Микросервисы - это разбиение большого монолитного приложения на маленькие сервисы, каждый из которых выполняет небольшой четко оговоренный набор задач Микросервисы коммуницируют между собой, и безусловно имеют слой хранения данных.
  • #7: В мета-описание входят сообщения протокола и форматы удаленных вызовов. Сообщения преобразуются в классы-сущности, удаленные вызовы - в функции/методы
  • #8: Вход описывается на DSL
  • #10: Можно ли приравнять мета-описание протокола к исходникам на С++?
  • #11: Говоря математически, можно установить биекцию Reflection времени компиляции для С++
  • #16: Шаблоны (темплейты) - комбинация “статического” С++ кода и динамического наполнения (по аналогии с Java Server Pages, где комбинируется HTML и java-код)
  • #24: Серебряной пули не существует