SlideShare a Scribd company logo
1 of 46
Download to read offline
Метаданные и
автогенерация кода.
SECON 2014.
Щеваев Павел, @pachash
Предыстория
Ye olde year of 2007
zveriki.com
■ Амбициозная и успешная MMO 3D игра с
целым зоопарком технологий:
○ Сервер: Linux, C++, MySQL, ассеты и конфиги в
файловой системе
○ Клиент: Shockwave Director (Lingo, JavaScript)
○ Портал: PHP
Клиент (Lingo,
JavaScript)
Сервер (C++)
Портал (PHP)
БД (MySQL)
Ассеты,
конфиги
Информационные потоки
Пример сущности
struct PetConfig {
Breed breed;
u16 max_health;
vector<u32> anim_ids;
};
struct Pet {
const PetConfig* config;
u32 id;
u16 health;
string name;
float x;
float y;
};
Загрузка конфигов
<pet>
<breed>bulldog</breed>
<max_health>100</max_health>
<anim_ids>2,4,6,7,8</anim_ids>
</pet>
Данные ассоциативны: key => value
Загрузка конфигов
int PetСonfig::read(const XmlFile& data) {
string breed_tmp;
if(int err = data.readString("type", breed_tmp)){
return err;
if(!Breed::lookupByStr(breed_tmp.c_str(), breed))
return ERR_BAD_ENUM;
}
if(int err = data.readU32("max_health", max_health))
return err;
string ids_tmp;
if(int err = data.readString("anim_ids", ids_tmp))
return err;
if(!explode(",”, ids_tmp, anim_ids))
return ERR_BAD_ARRAY;
}
Сохранение и загрузка в БД
id conf_id name x y health
10 128 K-9 128 126 5
20 165 Polkan 764 356 9
... ...
Данные ассоциативны: key => value
Сохранение и загрузка в БД
int Pet::read(const DbReader& data) {
if(int err = data.readU32("id", id)) return err;
if(int err = data.readString("name", name)) return err;
if(int err = data.readFloat("x", x)) return err;
...
}
int Pet::write(DbWriter& data) const {
if(int err = data.writeU32("id", id)) return err;
if(int err = data.writeString("name", name)) return err;
if(int err = data.writeFloat("x", x)) return err;
...
}
Передача по сети
■ Максимально компакное представление
■ Набор байтов
■ Данные представлены последовательно
id conf_id
health x y
name (size)
name
== 1 byte
Передача по сети
int Pet::read(const ByteBuffer& data) {
if(int err = data.readU32(id))
return err;
if(int err = data.readU32(conf_id))
return err;
if(int err = data.readU16(health))
return err;
if(int err = data.readFloat(x))
return err;
...
}
int Pet::write(ByteBuffer& data) const {
if(int err = data.writeU32(id))
return err;
if(int err = data.writeU32(conf_id))
return err;
if(int err = data.writeU16(health))
return err;
...
}
RPC (клиент)
И
ByteBuffer pckt;
pckt.writeU16(PACKET_MOVE_PET);
pckt.writeU32(pet.id);
pckt.writeFloat(pet.x);
pckt.writeFloat(pet.y);
net_send_packet(pckt, function(err) { … } );
RPC (сервер)
int handle_rpc(const ByteBuffer& data) {
u16 packet_type;
if(int err = data.readU16(packet_type))
return err;
switch(packet_type)
{
case PACKET_MOVE_PET:
return handle_move_pet(data);
...
}
}
Чот не прикольно
Проблемы
■ Отсутствие проверки структуры данных на
этапе компиляции для ассоциативных
данных
■ Строгий порядок следования инструкций
в сетевом протоколе
■ Громоздкая поддержка обработки ошибок
■ Дублирование кода для различных
платформ
■ Добавление новых RPC вызывов неудобно
■ etc, etc, etc
Решение, изменившее мою
жизнь
Пути решения
■ Найти готовое решение
○ Из всего глянулся Thrift (http://thrift.apache.org)
○ … но это была середина 2007 года: “никакая”
документация, запутанный код, ориентация
только на RPC и проч. и проч.
■ Придумать “нечто” свое
Придумать “нечто” свое
metagen
metagen
■ Простой декларативный мета формат
■ Поддержка ассоциативных и
последовательных источников данных
■ Новые форматы данных просто добавить
■ Парсинг и кодогенерация написаны на
PHP: относительно просто расширить
■ RPC, сохранение/загрузка в/из БД,
файловой системы
■ C++, AS3, PHP, JavaScript, Go (активно
пилится)
■ Максимальное исключение
“человеческого фактора”
■ Возможность быстро пусть и “грязно”
расширить для решения частной
проблемы
metagen
metagen: как это работает
■ Парсинг декларативного описания
■ Формирование промежуточной структуры
■ Кодонегерация под разные “таргеты” из
промежуточной структуры
struct DataPet
id : uint32
conf_id : uint32
x : float
y : float
end
<?php
class mtgMetaStruct {
}
class mtgMetaField {
}
...
PHP
C++
AS3 Go
metagen: простые типы и
структуры
struct ConfPoint
x : float
y : float
end
struct ConfShapeBase
points : ConfPoint[]
end
struct ConfShape extends ConfShapeBase
id : uint32
name : string
end
metagen: поддержка enum
enum EnumShape
UNDEFINED = 0
CIRCLE = 1
SQUARE = 2
end
struct DataShape
type : EnumShape
...
end
metagen: токены
struct DataPet
@POD @table:pet @id:id @owner:player_id
id : uint32
player_id : uint32
name : string @default:"K-9" @strmax:128
breed : EnumBreed @default:"BULLDOG"
health : uint32 @default:10
...
end
■ Структурные токены
■ Токены на отдельные поля
metagen : RPC
RPC 101 MATH_CALC(
op : OpType
x : float
y : float
)
error : uint32
answers : float[]
end
metagen: приятные мелочи
#комментарии поддерживаются
#...как и поддерживаются некоторые
#другие препроцессорные директивы, например
#include shared.meta
metagen: опциональные поля
struct DataPet
@POD @table:pet @id:id @owner:player_id
id : uint32
player_id : uint32
health : uint32
...
end
struct DataPet
@POD @table:pet @id:id @owner:player_id
id : uint32
player_id : uint32
health : uint32
...
#added in version 1.01
age : uint32 @optional @default:0
end
metagen: результат генерации
struct ConfPoint
x : float
y : float
end
metagen: результат генерации
struct ConfPoint : public MetaBaseStruct {
GAME_RTTI_EX(ConfPoint, MetaBaseStruct);
enum {
CLASS_ID = 230648249,
FIELDS_COUNT = 2,
};
ConfPoint(Allocator* = NULL);
virtual ~ConfPoint();
bool operator==(const ConfPoint&) const;
i32 x;
i32 y;
virtual size_t getFieldsCount() const { return FIELDS_COUNT; }
protected:
virtual DataError _read(DataReader&);
virtual DataError _write(DataWriter&) const;
};
metagen: результат генерации
DataError ConfPoint::_read(DataReader& reader) {
CHECK_READ(MetaBaseStruct::_read(reader), "Parent 'MetaBaseStruct' read
error");
CHECK_READ(reader.readI32("x", x), "x");
CHECK_READ(reader.readI32("y", y), "y");
return DATA_OK;
}
DataError ConfPoint::_write(DataWriter& writer) const {
CHECK_WRITE(MetaBaseStruct::_write(writer), "Parent 'MetaBaseStruct'
write error");
CHECK_WRITE(writer.writeI32("x", x), "x");
CHECK_WRITE(writer.writeI32("y", y), "y");
return DATA_OK;
}
metagen: использование
#include "autogen/ConfPoint.h"
ConfPoint pt;
{
JSONAssocReader r;
r.init("{x: 10, y: 20}");
pt.read(r);
}
{
JSONAssocWriter w;
pt.write(w);
game::string content;
w.dump(content);
print(content.c_str());
}
metagen: расширяемость
class DataReader {
public:
virtual ~DataReader(){}
virtual DataError readI32(const char*, i32& dest) = 0;
virtual DataError readU32(const char*, u32& dest) = 0;
virtual DataError readFloat(const char*, float& dest) = 0;
virtual DataError readString(const char*, string& dest) = 0;
virtual DataError beginArray(const char*, size_t* arr_size) = 0;
virtual DataError endArray() = 0;
};
metagen: расширяемость
class DataWriter {
public:
virtual ~DataWriter(){}
virtual DataError writeI32(const char*, const i32 source) = 0;
virtual DataError writeU32(const char*, u32 source) = 0;
virtual DataError writeFloat(float source) = 0;
virtual DataError writeString(const char*, const char* source, size_t
len) = 0;
virtual DataError beginArray(const char*, size_t size) = 0;
virtual DataError endArray() = 0;
virtual void dump(string& content) = 0;
};
metagen: расширяемость
function mtg_go_buf_read(mtgMetaInfo $info, $name, $super_type, $type,
$buf, array $tokens = array()) {
$str = '';
if($super_type == "scalar") {
if($type == 'float')
$str .= mtg_go_read($tokens, "{$buf}.ReadFloat(&$name, "$name")");
else if (strpos($type, "uint") === false)
$str .= mtg_go_read($tokens, "{$buf}.ReadI32(&$name, "$name")");
else
$str .= mtg_go_read($tokens, "{$buf}.ReadU32(&$name, "$name")");
$str .= "n";
} else if($super_type == "string") {
$str .= mtg_go_read($tokens, "{$buf}.ReadString($name, "$name");");
} else if($super_type == "struct") {
$str .= mtg_go_read($tokens, "({$name}.read($buf), "$name");");
} else if($super_type == "array") {
...
metagen : использование
enum EnumBreed
UNKNOWN = 0
BULLDOG = 1
SHEPHERD = 2
end
struct PetConfig
breed : EnumBreed
max_health : uint16
anim_ids : uint32[]
end
metagen : использование
struct PetData
conf_id : uint32
id : uint32
health : uint16
name : string
x : float
y : float
end
metagen : использование
struct Pet {
PetData data;
const PetConfig* config;
};
metagen: RPC
RPC 10 MOVE_PET(
pet_id : uint32
x : float
y : float
)
error : uint32
end
metagen: RPC (клиент)
static void on_move(RPCError err, RPCArgs args, void* user)
{
if(err.occured()) {
assert(0);
return;
}
RPC_EXTRACT_ARGS(MOVE_PET, args, req, resp);
printf("Result: %u", req->error);
}
RPC_NEW(MOVE_PET, req);
req->pet_id = 199;
req->x = 18;
req->y = 97;
rpc_call(req, &on_move);
metagen: RPC (сервер)
<?php
class RPC {
...
function RPC_MOVE_PET($in, $out) {
$pet = find_pet($in->pet_id);
if(!$pet) {
$out->error = 1;
return;
}
$out->error = 0;
$pet->setPos($in->x, $in->y);
}
...
}
metagen: минусы
■ Требуется настоящий лексер, а не regex
парсинг декларативного описания
■ Местами “стихийная” реализация в
кодогенерации
■ Пока нет поддержки по-настоящему
опциональных полей (data.x.set(10); if
(data.x.exists()) { … } )
■ Не является универсальным решением,
решает исключительно наши потребности
■ Сlosed source ;)
Альтернативы
■ Thrift (thrift.apache.org)
■ Protocol Buffers (code.google.
com/p/protobuf)
■ Avro (avro.apache.org)
■ Roll your own! :)
Вопросы?

More Related Content

What's hot

Михаил Давыдов - JavaScript. Асинхронность
Михаил Давыдов - JavaScript. АсинхронностьМихаил Давыдов - JavaScript. Асинхронность
Михаил Давыдов - JavaScript. АсинхронностьYandex
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
 
Подводные камни System.Security.Cryptography
Подводные камни System.Security.CryptographyПодводные камни System.Security.Cryptography
Подводные камни System.Security.CryptographyVladimir Kochetkov
 
Подводные камни прикладной криптографии, I
Подводные камни прикладной криптографии, IПодводные камни прикладной криптографии, I
Подводные камни прикладной криптографии, IVladimir Kochetkov
 
Boost.Algorithm: что, зачем и почему
Boost.Algorithm: что, зачем и почемуBoost.Algorithm: что, зачем и почему
Boost.Algorithm: что, зачем и почемуcorehard_by
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеPython Meetup
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...Alexey Paznikov
 
Практическое использование средств криптографии в .NET, Java и PHP
Практическое использование средств криптографии в .NET, Java и PHPПрактическое использование средств криптографии в .NET, Java и PHP
Практическое использование средств криптографии в .NET, Java и PHPVladimir Kochetkov
 
Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»e-Legion
 
Web осень 2013 лекция 2
Web осень 2013 лекция 2Web осень 2013 лекция 2
Web осень 2013 лекция 2Technopark
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JSFestUA
 
Asyncio для процессинга распределенной базы данных
Asyncio для процессинга  распределенной базы данныхAsyncio для процессинга  распределенной базы данных
Asyncio для процессинга распределенной базы данныхPyNSK
 
Cтрах и ненависть в MongoDB
Cтрах и ненависть в MongoDBCтрах и ненависть в MongoDB
Cтрах и ненависть в MongoDBDmitry Viskov
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...Alexey Paznikov
 
How to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longHow to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longTimur Shemsedinov
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в DjangoMoscowDjango
 

What's hot (20)

Михаил Давыдов - JavaScript. Асинхронность
Михаил Давыдов - JavaScript. АсинхронностьМихаил Давыдов - JavaScript. Асинхронность
Михаил Давыдов - JavaScript. Асинхронность
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Подводные камни System.Security.Cryptography
Подводные камни System.Security.CryptographyПодводные камни System.Security.Cryptography
Подводные камни System.Security.Cryptography
 
Подводные камни прикладной криптографии, I
Подводные камни прикладной криптографии, IПодводные камни прикладной криптографии, I
Подводные камни прикладной криптографии, I
 
Boost.Algorithm: что, зачем и почему
Boost.Algorithm: что, зачем и почемуBoost.Algorithm: что, зачем и почему
Boost.Algorithm: что, зачем и почему
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгирование
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
 
Практическое использование средств криптографии в .NET, Java и PHP
Практическое использование средств криптографии в .NET, Java и PHPПрактическое использование средств криптографии в .NET, Java и PHP
Практическое использование средств криптографии в .NET, Java и PHP
 
Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»
 
Web осень 2013 лекция 2
Web осень 2013 лекция 2Web осень 2013 лекция 2
Web осень 2013 лекция 2
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
 
MongoDB@addconf
MongoDB@addconfMongoDB@addconf
MongoDB@addconf
 
Asyncio для процессинга распределенной базы данных
Asyncio для процессинга  распределенной базы данныхAsyncio для процессинга  распределенной базы данных
Asyncio для процессинга распределенной базы данных
 
Cтрах и ненависть в MongoDB
Cтрах и ненависть в MongoDBCтрах и ненависть в MongoDB
Cтрах и ненависть в MongoDB
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 
How to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longHow to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life long
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в Django
 

Similar to SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода

200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кодаPositive Hack Days
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кодаAndrey Karpov
 
Web осень 2013 лекция 6
Web осень 2013 лекция 6Web осень 2013 лекция 6
Web осень 2013 лекция 6Technopark
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Andrey Karpov
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonovComputer Science Club
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Vladimir Kochetkov
 
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...Yandex
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кодаTatyanazaxarova
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаAndrey Karpov
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковSergey Platonov
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Yandex
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Hacking PostgreSQL. Обзор исходного кода
Hacking PostgreSQL. Обзор исходного кодаHacking PostgreSQL. Обзор исходного кода
Hacking PostgreSQL. Обзор исходного кодаAnastasia Lubennikova
 
Гирлянда для программистов
Гирлянда для программистовГирлянда для программистов
Гирлянда для программистовGetDev.NET
 
C++ refelection and cats
C++ refelection and catsC++ refelection and cats
C++ refelection and catscorehard_by
 

Similar to SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода (20)

200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
Web осень 2013 лекция 6
Web осень 2013 лекция 6Web осень 2013 лекция 6
Web осень 2013 лекция 6
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!
 
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
Rgsu04
Rgsu04Rgsu04
Rgsu04
 
Rgsu04
Rgsu04Rgsu04
Rgsu04
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Hacking PostgreSQL. Обзор исходного кода
Hacking PostgreSQL. Обзор исходного кодаHacking PostgreSQL. Обзор исходного кода
Hacking PostgreSQL. Обзор исходного кода
 
Гирлянда для программистов
Гирлянда для программистовГирлянда для программистов
Гирлянда для программистов
 
C++ refelection and cats
C++ refelection and catsC++ refelection and cats
C++ refelection and cats
 

More from Конференция разработчиков программного обеспечения SECON'2014

More from Конференция разработчиков программного обеспечения SECON'2014 (16)

SECON'2014 - Сергеев Антон - Асинхронные задачи в iFunny
SECON'2014 - Сергеев Антон - Асинхронные задачи в iFunnySECON'2014 - Сергеев Антон - Асинхронные задачи в iFunny
SECON'2014 - Сергеев Антон - Асинхронные задачи в iFunny
 
SECON.Посиделки #16: Cassandra (презентация)
SECON.Посиделки #16: Cassandra (презентация) SECON.Посиделки #16: Cassandra (презентация)
SECON.Посиделки #16: Cassandra (презентация)
 
SECON'2014 - Тимур Салюков - История одного кейса Gorussia2014.ru. Как добить...
SECON'2014 - Тимур Салюков - История одного кейса Gorussia2014.ru. Как добить...SECON'2014 - Тимур Салюков - История одного кейса Gorussia2014.ru. Как добить...
SECON'2014 - Тимур Салюков - История одного кейса Gorussia2014.ru. Как добить...
 
SECON'2014 - Максим Цепков - DDD: от требований до кода
SECON'2014 - Максим Цепков - DDD: от требований до кодаSECON'2014 - Максим Цепков - DDD: от требований до кода
SECON'2014 - Максим Цепков - DDD: от требований до кода
 
SECON'2014 - Кирилл Мокевнин - Формирование инженерной культуры
SECON'2014 - Кирилл Мокевнин - Формирование инженерной культурыSECON'2014 - Кирилл Мокевнин - Формирование инженерной культуры
SECON'2014 - Кирилл Мокевнин - Формирование инженерной культуры
 
SECON'2014 - Юрий Бушмелев - Эволюция системного администратора
SECON'2014 - Юрий Бушмелев - Эволюция системного администратораSECON'2014 - Юрий Бушмелев - Эволюция системного администратора
SECON'2014 - Юрий Бушмелев - Эволюция системного администратора
 
SECON'2014 - Алексей Кошкидько - Межконтинентальный опыт внедрения Agile
SECON'2014 - Алексей Кошкидько - Межконтинентальный опыт внедрения AgileSECON'2014 - Алексей Кошкидько - Межконтинентальный опыт внедрения Agile
SECON'2014 - Алексей Кошкидько - Межконтинентальный опыт внедрения Agile
 
SECON'2014 - Филипп Торчинский - Трансформация баг-трекера под любой проект: ...
SECON'2014 - Филипп Торчинский - Трансформация баг-трекера под любой проект: ...SECON'2014 - Филипп Торчинский - Трансформация баг-трекера под любой проект: ...
SECON'2014 - Филипп Торчинский - Трансформация баг-трекера под любой проект: ...
 
SECON'2014 - Сергей Цивин - Производительность веб-приложений
SECON'2014 - Сергей Цивин - Производительность веб-приложенийSECON'2014 - Сергей Цивин - Производительность веб-приложений
SECON'2014 - Сергей Цивин - Производительность веб-приложений
 
SECON'2014 - Дмитрий Швеенков - Рассылка push-уведомлений для мобильных платформ
SECON'2014 - Дмитрий Швеенков - Рассылка push-уведомлений для мобильных платформSECON'2014 - Дмитрий Швеенков - Рассылка push-уведомлений для мобильных платформ
SECON'2014 - Дмитрий Швеенков - Рассылка push-уведомлений для мобильных платформ
 
SECON'2014 - Антон Веретенников, Илья Семаков - Переход от коллбеков к событиям
SECON'2014 - Антон Веретенников, Илья Семаков - Переход от коллбеков к событиямSECON'2014 - Антон Веретенников, Илья Семаков - Переход от коллбеков к событиям
SECON'2014 - Антон Веретенников, Илья Семаков - Переход от коллбеков к событиям
 
SECON'2014 - Сергей Шпадырев - Разработка 3D-игры на Flash: едем с костылями...
SECON'2014 - Сергей Шпадырев -  Разработка 3D-игры на Flash: едем с костылями...SECON'2014 - Сергей Шпадырев -  Разработка 3D-игры на Flash: едем с костылями...
SECON'2014 - Сергей Шпадырев - Разработка 3D-игры на Flash: едем с костылями...
 
SECON'2014 - Андрей Устюжанин - Маленькие секреты больших данных
SECON'2014 - Андрей Устюжанин - Маленькие секреты больших данныхSECON'2014 - Андрей Устюжанин - Маленькие секреты больших данных
SECON'2014 - Андрей Устюжанин - Маленькие секреты больших данных
 
SECON'2014 - Александр Чистяков - Сравнение современных средств управления ко...
SECON'2014 - Александр Чистяков - Сравнение современных средств управления ко...SECON'2014 - Александр Чистяков - Сравнение современных средств управления ко...
SECON'2014 - Александр Чистяков - Сравнение современных средств управления ко...
 
SECON'2014 - Александр Бындю - Переход от монолитной архитектуры к распределе...
SECON'2014 - Александр Бындю - Переход от монолитной архитектуры к распределе...SECON'2014 - Александр Бындю - Переход от монолитной архитектуры к распределе...
SECON'2014 - Александр Бындю - Переход от монолитной архитектуры к распределе...
 
SECON'2014 - Команда CTRL-PNZ - Уязвимости для самых маленьких. Что это, как ...
SECON'2014 - Команда CTRL-PNZ - Уязвимости для самых маленьких. Что это, как ...SECON'2014 - Команда CTRL-PNZ - Уязвимости для самых маленьких. Что это, как ...
SECON'2014 - Команда CTRL-PNZ - Уязвимости для самых маленьких. Что это, как ...
 

SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода

  • 3. Ye olde year of 2007
  • 4. zveriki.com ■ Амбициозная и успешная MMO 3D игра с целым зоопарком технологий: ○ Сервер: Linux, C++, MySQL, ассеты и конфиги в файловой системе ○ Клиент: Shockwave Director (Lingo, JavaScript) ○ Портал: PHP
  • 5. Клиент (Lingo, JavaScript) Сервер (C++) Портал (PHP) БД (MySQL) Ассеты, конфиги Информационные потоки
  • 6. Пример сущности struct PetConfig { Breed breed; u16 max_health; vector<u32> anim_ids; }; struct Pet { const PetConfig* config; u32 id; u16 health; string name; float x; float y; };
  • 8. Загрузка конфигов int PetСonfig::read(const XmlFile& data) { string breed_tmp; if(int err = data.readString("type", breed_tmp)){ return err; if(!Breed::lookupByStr(breed_tmp.c_str(), breed)) return ERR_BAD_ENUM; } if(int err = data.readU32("max_health", max_health)) return err; string ids_tmp; if(int err = data.readString("anim_ids", ids_tmp)) return err; if(!explode(",”, ids_tmp, anim_ids)) return ERR_BAD_ARRAY; }
  • 9. Сохранение и загрузка в БД id conf_id name x y health 10 128 K-9 128 126 5 20 165 Polkan 764 356 9 ... ... Данные ассоциативны: key => value
  • 10. Сохранение и загрузка в БД int Pet::read(const DbReader& data) { if(int err = data.readU32("id", id)) return err; if(int err = data.readString("name", name)) return err; if(int err = data.readFloat("x", x)) return err; ... } int Pet::write(DbWriter& data) const { if(int err = data.writeU32("id", id)) return err; if(int err = data.writeString("name", name)) return err; if(int err = data.writeFloat("x", x)) return err; ... }
  • 11. Передача по сети ■ Максимально компакное представление ■ Набор байтов ■ Данные представлены последовательно id conf_id health x y name (size) name == 1 byte
  • 12. Передача по сети int Pet::read(const ByteBuffer& data) { if(int err = data.readU32(id)) return err; if(int err = data.readU32(conf_id)) return err; if(int err = data.readU16(health)) return err; if(int err = data.readFloat(x)) return err; ... } int Pet::write(ByteBuffer& data) const { if(int err = data.writeU32(id)) return err; if(int err = data.writeU32(conf_id)) return err; if(int err = data.writeU16(health)) return err; ... }
  • 14. RPC (сервер) int handle_rpc(const ByteBuffer& data) { u16 packet_type; if(int err = data.readU16(packet_type)) return err; switch(packet_type) { case PACKET_MOVE_PET: return handle_move_pet(data); ... } }
  • 16. Проблемы ■ Отсутствие проверки структуры данных на этапе компиляции для ассоциативных данных ■ Строгий порядок следования инструкций в сетевом протоколе ■ Громоздкая поддержка обработки ошибок ■ Дублирование кода для различных платформ ■ Добавление новых RPC вызывов неудобно ■ etc, etc, etc
  • 18.
  • 19. Пути решения ■ Найти готовое решение ○ Из всего глянулся Thrift (http://thrift.apache.org) ○ … но это была середина 2007 года: “никакая” документация, запутанный код, ориентация только на RPC и проч. и проч. ■ Придумать “нечто” свое
  • 22. metagen ■ Простой декларативный мета формат ■ Поддержка ассоциативных и последовательных источников данных ■ Новые форматы данных просто добавить ■ Парсинг и кодогенерация написаны на PHP: относительно просто расширить ■ RPC, сохранение/загрузка в/из БД, файловой системы ■ C++, AS3, PHP, JavaScript, Go (активно пилится)
  • 23. ■ Максимальное исключение “человеческого фактора” ■ Возможность быстро пусть и “грязно” расширить для решения частной проблемы metagen
  • 24. metagen: как это работает ■ Парсинг декларативного описания ■ Формирование промежуточной структуры ■ Кодонегерация под разные “таргеты” из промежуточной структуры struct DataPet id : uint32 conf_id : uint32 x : float y : float end <?php class mtgMetaStruct { } class mtgMetaField { } ... PHP C++ AS3 Go
  • 25. metagen: простые типы и структуры struct ConfPoint x : float y : float end struct ConfShapeBase points : ConfPoint[] end struct ConfShape extends ConfShapeBase id : uint32 name : string end
  • 26. metagen: поддержка enum enum EnumShape UNDEFINED = 0 CIRCLE = 1 SQUARE = 2 end struct DataShape type : EnumShape ... end
  • 27. metagen: токены struct DataPet @POD @table:pet @id:id @owner:player_id id : uint32 player_id : uint32 name : string @default:"K-9" @strmax:128 breed : EnumBreed @default:"BULLDOG" health : uint32 @default:10 ... end ■ Структурные токены ■ Токены на отдельные поля
  • 28. metagen : RPC RPC 101 MATH_CALC( op : OpType x : float y : float ) error : uint32 answers : float[] end
  • 29. metagen: приятные мелочи #комментарии поддерживаются #...как и поддерживаются некоторые #другие препроцессорные директивы, например #include shared.meta
  • 30. metagen: опциональные поля struct DataPet @POD @table:pet @id:id @owner:player_id id : uint32 player_id : uint32 health : uint32 ... end struct DataPet @POD @table:pet @id:id @owner:player_id id : uint32 player_id : uint32 health : uint32 ... #added in version 1.01 age : uint32 @optional @default:0 end
  • 31. metagen: результат генерации struct ConfPoint x : float y : float end
  • 32. metagen: результат генерации struct ConfPoint : public MetaBaseStruct { GAME_RTTI_EX(ConfPoint, MetaBaseStruct); enum { CLASS_ID = 230648249, FIELDS_COUNT = 2, }; ConfPoint(Allocator* = NULL); virtual ~ConfPoint(); bool operator==(const ConfPoint&) const; i32 x; i32 y; virtual size_t getFieldsCount() const { return FIELDS_COUNT; } protected: virtual DataError _read(DataReader&); virtual DataError _write(DataWriter&) const; };
  • 33. metagen: результат генерации DataError ConfPoint::_read(DataReader& reader) { CHECK_READ(MetaBaseStruct::_read(reader), "Parent 'MetaBaseStruct' read error"); CHECK_READ(reader.readI32("x", x), "x"); CHECK_READ(reader.readI32("y", y), "y"); return DATA_OK; } DataError ConfPoint::_write(DataWriter& writer) const { CHECK_WRITE(MetaBaseStruct::_write(writer), "Parent 'MetaBaseStruct' write error"); CHECK_WRITE(writer.writeI32("x", x), "x"); CHECK_WRITE(writer.writeI32("y", y), "y"); return DATA_OK; }
  • 34. metagen: использование #include "autogen/ConfPoint.h" ConfPoint pt; { JSONAssocReader r; r.init("{x: 10, y: 20}"); pt.read(r); } { JSONAssocWriter w; pt.write(w); game::string content; w.dump(content); print(content.c_str()); }
  • 35. metagen: расширяемость class DataReader { public: virtual ~DataReader(){} virtual DataError readI32(const char*, i32& dest) = 0; virtual DataError readU32(const char*, u32& dest) = 0; virtual DataError readFloat(const char*, float& dest) = 0; virtual DataError readString(const char*, string& dest) = 0; virtual DataError beginArray(const char*, size_t* arr_size) = 0; virtual DataError endArray() = 0; };
  • 36. metagen: расширяемость class DataWriter { public: virtual ~DataWriter(){} virtual DataError writeI32(const char*, const i32 source) = 0; virtual DataError writeU32(const char*, u32 source) = 0; virtual DataError writeFloat(float source) = 0; virtual DataError writeString(const char*, const char* source, size_t len) = 0; virtual DataError beginArray(const char*, size_t size) = 0; virtual DataError endArray() = 0; virtual void dump(string& content) = 0; };
  • 37. metagen: расширяемость function mtg_go_buf_read(mtgMetaInfo $info, $name, $super_type, $type, $buf, array $tokens = array()) { $str = ''; if($super_type == "scalar") { if($type == 'float') $str .= mtg_go_read($tokens, "{$buf}.ReadFloat(&$name, "$name")"); else if (strpos($type, "uint") === false) $str .= mtg_go_read($tokens, "{$buf}.ReadI32(&$name, "$name")"); else $str .= mtg_go_read($tokens, "{$buf}.ReadU32(&$name, "$name")"); $str .= "n"; } else if($super_type == "string") { $str .= mtg_go_read($tokens, "{$buf}.ReadString($name, "$name");"); } else if($super_type == "struct") { $str .= mtg_go_read($tokens, "({$name}.read($buf), "$name");"); } else if($super_type == "array") { ...
  • 38. metagen : использование enum EnumBreed UNKNOWN = 0 BULLDOG = 1 SHEPHERD = 2 end struct PetConfig breed : EnumBreed max_health : uint16 anim_ids : uint32[] end
  • 39. metagen : использование struct PetData conf_id : uint32 id : uint32 health : uint16 name : string x : float y : float end
  • 40. metagen : использование struct Pet { PetData data; const PetConfig* config; };
  • 41. metagen: RPC RPC 10 MOVE_PET( pet_id : uint32 x : float y : float ) error : uint32 end
  • 42. metagen: RPC (клиент) static void on_move(RPCError err, RPCArgs args, void* user) { if(err.occured()) { assert(0); return; } RPC_EXTRACT_ARGS(MOVE_PET, args, req, resp); printf("Result: %u", req->error); } RPC_NEW(MOVE_PET, req); req->pet_id = 199; req->x = 18; req->y = 97; rpc_call(req, &on_move);
  • 43. metagen: RPC (сервер) <?php class RPC { ... function RPC_MOVE_PET($in, $out) { $pet = find_pet($in->pet_id); if(!$pet) { $out->error = 1; return; } $out->error = 0; $pet->setPos($in->x, $in->y); } ... }
  • 44. metagen: минусы ■ Требуется настоящий лексер, а не regex парсинг декларативного описания ■ Местами “стихийная” реализация в кодогенерации ■ Пока нет поддержки по-настоящему опциональных полей (data.x.set(10); if (data.x.exists()) { … } ) ■ Не является универсальным решением, решает исключительно наши потребности ■ Сlosed source ;)
  • 45. Альтернативы ■ Thrift (thrift.apache.org) ■ Protocol Buffers (code.google. com/p/protobuf) ■ Avro (avro.apache.org) ■ Roll your own! :)