33
Детали разработки кроссплатформенного фреймворка. SPB TV, руководитель отдела перспективных разработок Никита Глушков

Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Embed Size (px)

Citation preview

Page 1: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Детали разработки кроссплатформенного фреймворка.

SPB TV, руководитель отдела перспективных разработок

Никита Глушков

Page 2: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Чем мы занимаемся

Page 3: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Условия разработки

• Историческое наследие • Кросс-платформенность• Продолжительные проекты

Page 4: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Технический долг

• Для продолжительных проектов поддержка кода много дороже его разработки.

• Стоимость поддержки может расти со временем.

• Плохой код – не синоним быстрого результата.

Page 5: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Технический дефолт*

• Разработчики время тратят, но новых фич больше не появляется.

• Всё время уходит на:– исправление проекта– попытки в нём просто разобраться– регулярное переписывание значительной части

функционала

* Попрощайтесь с отличным бизнесом

Page 6: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Архитектура

• Совокупность способов организации системы, которые позволяют после реализации очередного мейлстоуна, релиза или обновления сохранить относительно дешёвую возможность развивать продукты далее*

* После короткого рефакторинга

Page 7: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Структура нашего проекта

Page 8: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Представление

Переносимые графические примитивы

SceneGraph Animators

Шаблоны SceneGraph + DataBinding

💗

Page 9: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Модель данных

Источник данных

Методов

Событий

Машина состояний

Page 10: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Кстати, о С++

Page 11: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Указатели

• Аналог intrusive_ptr• Аналог weak_ptr• std::shared_ptr – антипаттерн.

class Foo : public Referenced {...}auto obj = make_shared<Foo>();shared_ptr<Foo> obj2 = this;

class IMyInterface {public:WEAK_REFERABLE( IMyInterface );

Page 12: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Указатели

Label

• Field 1• Field 2• Field 3

Shape

Group

Animator

weak_ptr

void*

Page 13: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Descriptors

• Структуры хранящие строковый буфер + длину.

• Позволяют работать с подстроками без выделения памяти.

TPtrC8 ptr("Test TPtrC");ptr.Length() == 10;ptr.Mid(1, 3) == "est";

std::string str( "string" );TPtrC8 ptr2( str.c_str(), 3 );ptr2 == "str";

Page 14: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Descriptors

• Комбинируют в одном int длину и флаги.• Полностью заменяют все записи вида char*,

const wchar_t* и т.п.

const char* const TDesC8&

• Можно распарсить xml или json без аллокации памяти под строки.

Page 15: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Strings

• Утино-типизированы с ATL/WTL::CString• Прозрачно работают с дескрипторами• Используют счётчик ссылок• std::string - антипаттерн

void Test( const TDesC8& desc );

CStringA str = "Test";str.Append( "2" );Test( str );

Page 16: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Strings

• Выполняется правило:– CStringA отображает строки необходимые для

работы системы– CStringW отображает строки, которые может

увидеть пользователь• Универсальные строковые преобразования:

size_t CastFromString( const TDesC8& str, SomeType& t );CStringA CastToString( SomeType );

Page 17: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

RTTI

• Позволяет идентифицировать классы в рантайме, содержит их базовое описание.

class variant_type{ const char* name; size_t size; size_t aligned_size;

func_constructor constructor; func_destructor destructor; func_copy_constructor copy_constructor;

Page 18: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

RTTI

• template<class T>static variant_type const* type_id(){ static variant_type static_type; return static_type.m_true_type;}

• Проблема – при работе с несколькими исполняемыми модулями может получаться несколько идентифицирующих указателей для одного типа.

Page 19: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Variant

• class variant: контейнер, в котором можно безопасно хранить объект (почти) любого типа

variant v1 = 1;variant v2 = "Test";variant v3 = myMegaObject;variant v4 = Calculate( "1 + 2 * ( 3 + GetInt('Settings.someValue') )", some_ctx );int i = variant_cast<CString>( v4 ); // Oops!

Page 20: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Variant

• Хранит указатель на структуру, содержащую счётчик, указатель на идентификатор RTTI и место под хранимый объект.

• При сохранении объекта используется только одна аллокация.

struct variant_info{variant_type const* m_type;int m_ref;};variant_info* m_pInfo;

Page 21: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Variant

• Один из ключевых элементов системы, поэтому ради оптимизации за милым интерфейсом прячутся страшные вещи:template<class T>void Store(T const& val){ variant_type const* type = variant_type::type_id<T>(); size_t size = type->align_size + sizeof(variant_info); m_pInfo = (variant_info*)SmallAlloc( size, SA_VARIANT ); m_pInfo->m_ref = 1; m_pInfo->m_type = type; new (GetValue()) T( val );}

Page 22: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Varianttemplate<class T>T& variant_cast(variant& var){ LCCHECKM( var.GetType() == variant_type::type_id<T>(), "Variant cannot be casted from: " << (var.IsEmpty() ? "'empty'" : var.GetType()->name ) << ", to: " << variant_type::type_id<T>()->name ); return *static_cast<T*>(var.GetValue());}

class IVariantSerializator{ virtual CStringA Save( const variant&, IReferencedToId& )=0; virtual variant Load( const TDesC8& str, IIdToReferenced& )=0;};

Page 23: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Variant

• Не хватает возможности автоматического приведения типов внутри контейнера.

TexturePtr texture;if ( it->m_Value.GetType() == rtti::type_id<Texture2DPtr>() ) ...else if ( it->m_Value.GetType() == rtti::type_id<TexturePtr>() ) ...else if ( it->m_Value.GetType() == rtti::type_id<IUniformSourceTexture2DPtr>() ) ... else ...

Page 24: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Serialization

• Маршалинг:– Из и в xml, json, binary– Конвертация в нативный формат– Оптимизация сцен

• Рефлексия:– Поиск объектов и их мемберов в иерархии– Модификация сцен аниматорами или

скриптами

Page 25: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Serialization

• Форма бралась из boost:

class AnimaControl : public Referenced{public:...template<class TArchive>void Serialize(TArchive& ar){ar & SERIALIZE_ITEM_EXT( m_CurrentTime, "Time", SER_ATTRIBUTE );ar & SERIALIZE_ITEM_EXT( m_PlayRate, "PlayRate", SER_ATTRIBUTE );ar & SERIALIZE_ITEM_EXT( m_Enabled, "Enabled", SER_ATTRIBUTE );ar & SERIALIZE_ITEM_EXT( m_Weight, "Weight", SER_ATTRIBUTE );...

Page 26: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Serialization

<Modify Element="MainView:Animator" Variable="AnimaControl:PlayRate" Value="-1"/>

<AnimaControl TimeEnd="0.5" PlayRate="0" ClampTime="1"/>

1.

2.

3. <Material> <Platform Name="OpenGL"> <UniformValues> <Texture Name="sampler"/> <Real Name="alpha" Value="MainView:Animator:AnimaControl:Time"/> </UniformValues> ...

Page 27: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Функторыclass FunctorImpl : public Referenced{public: virtual void operator()() = 0;};

class Functor : public shared_ptr<FunctorImpl>{ typedef shared_ptr<FunctorImpl> baseClass;public: template<class T, class TPtr> Functor( T ptr, TPtr func ) ...

Page 28: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Система запросов

• Запросы сетевые, к системе, внутренним процессам, пользователям.

RequestHandle RequestSomeInfo( CStringA someParam1, Function<void, Foo> on_success, Function<void, ErrorReason> on_fail );

class ITVService : public lc::ILcPlugin{public:virtual lc::RequestHandle TryToConnect( lc::Functor onSuccess, lc::Function<void, lc::ErrorReason> ) = 0;

Page 29: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Декларативные элементы

{ action1; scope_exit { cleanup1 }; scope_fail { rollback1 }; // nope action2; scope_exit { cleanup2 }; scope_fail { rollback2 }; // nope next2;}www.github.com/panaseleus/stack_unwinding

Page 30: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Процесс разработки

• Разработчики вольны выбирать наиболее удобную ОС для работы.

• UI в основном разрабатывается под Windows

• Модификация интерфейса и основных переходов происходит преимущественно без перезагрузки системы

Page 31: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Оформление кода

Page 32: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Комментарии в коде

• Хочешь понять код? Читай его.• Тянет написать комментарий? Потрать

время на рефакторинг.• Комментарии = дублирование кода = $$$.• Полезного комментария: // Google “3DDDA”• Осмысленные логи – совсем другое дело!• А так же – многочисленные юнит-тесты,

примеры и обзорные статьи

Page 33: Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков

Вопросы?