SlideShare a Scribd company logo
1 of 101
Download to read offline
Привiт!
gem "rutils"
gem "gilenson"
gem "russian"
gem "ru_propisju"
gem "timecode"
gem "edl"
"и это тоже".mb_chars.upcase
gem "prorate"
gem "activerecord_autoreplica"
gem "format_parser"
gem "zip_tricks"
gem "apiculture"
gem "tracksperanto"
WeTransfer
Много файлов, много клиентов, много Ruby и JS
Амстердам
❌❌❌
• ≈ 881000 велосипедов - правда-правда!
• на ≈ 800000 жителей
Основная модель для местности
• Один торомоз - педальный задний. Передний ручной -
скорее баловство
• Навесное оборудование - звонок (иногда, пугать туристов) и
свет (без него оштрафуют)
• Иногда багажники
И нету
• Ручных тормозов
• Сликов
• Клипс
• Амортизаторов
• Переключения скоростей
• Cумок и бардачков
Это не изобретение
• Это решение разных задач
• Это исследование
• Это поиск и творчество
• Это доводка того что вам не подходит до того состояния, в
котором оно вам подойдет
Кейс первый. zip_tricks
Как-бы "еще одна" ZIP-библиотека для Ruby.
Зачем это было нужно
У нас есть сервер для скачивания файлов. Он тащит данные с
S3 и подшивает их на ходу в ZIP. Ну примерно как mod_zip для
nginx. Но нам еще надо отправлять оповещение о том что
скачивание закончено. А еще...
• Какого размера будет ZIP после скачки?
• А рестартовать скачку с определенного места?
• А Zip64?
• А юникодные имена файлов?
Например, хочется вот так:
exact_archive_size = ArchiveLibrary.estimate_size do |arch|
arch.add_file(name: "File.doc", size_in_archive: 1586215)
arch.add_file(name: "TOC.xml", size_in_archive: 1452)
end
А самое главное - хочется вот так:
ArchiveLibrary.write(socket) do |arch|
arch.add_local_file_header(name: "File.doc", size_in_archive: 1586215)
IO.copy_stream(remote_file_contents, arch)
end
socket не может seek и rewind
То есть - интеграция чужой библиотеки
нам видится так:
(потому что ООП и модули и кумбайя)
Вспоминаем ZIP формат
На самом деле zip_tricks начался как патч для rubyzip. И ох -
если бы можно было его таким оставить.
class ZipTricks::OutputStreamPrefab < ::Zip::OutputStream
def initialize(io, stream_flag=false, encrypter=nil)
super StringIO.new, stream_flag=true, encrypter=nil
@output_stream = io
end
def put_next_entry(entry_name, size, crc)
new_entry = ::Zip::Entry.new(@file_name, entry_name)
new_entry.compression_method = Zip::Entry::STORED
new_entry.crc, new_entry.size = crc, size
new_entry.compressed_size = size + new_entry.calculate_local_header_size
super(new_entry, nil, nil, new_entry.compression_method, level=Zlib::NO_COMPRESSION)
end
# We never need to update local headers, because we set all the data in the header ahead of time.
# And this is the method that tries to rewind the IO, so fuse it out and turn it into a no-op.
def update_local_headers
nil
end
end
Есть вариации похожего (библиотека zipline):
def finalize_current_entry
if current_entry
entry = current_entry
super
write_local_footer(entry)
end
end
def write_local_footer(entry)
@output_stream << [ 0x08074b50, entry.crc, entry.compressed_size, entry.size].pack('VVVV')
end
Тупик.
module Zip
# placeholder to reserve space for a Zip64 extra information record, for the
# local file header only, that we won't know if we'll need until after
# we write the file data
class ExtraField::Zip64Placeholder < ExtraField::Generic
HEADER_ID = ['9999'].pack('H*') # this ID is used by other libraries such as .NET's Ionic.zip
register_map
def initialize(_binstr = nil); end
def pack_for_local
"x00" * 16
end
end
end
Ну и соответственно
• ZIP - хитрозаковыристый формат
• В rubyzip реализация этого формата размазана тонким
слоем по десятку-двум отдельных модулей
Как это можно сделать по-
другому?
• Находим все мелкие детальки спецификации формата ZIP
• Собираем их в один обьект с visitor paCern
• Люто тестируем во всех направлениях, и только его,
побайтово
writer.write_local_file_header(io:, filename:, compressed_size:,
uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:)
writer.write_central_directory_file_header(io:, local_file_header_location:, gp_flags:,
storage_mode:, compressed_size:, uncompressed_size:, mtime:, crc32:, filename:)
writer.write_data_descriptor(io:, compressed_size:, uncompressed_size:, crc32:)
writer.write_end_of_central_directory(io:, start_of_central_directory_location:,
central_directory_size:, num_files_in_archive:, comment: ZIP_TRICKS_COMMENT)
• 430 строк с обильными комментариями
• EFS (UTF-8 имена файлов) автоматом и только если надо
• Zip64 автоматом и только если надо
• Data descriptor (футеры для записи CRC32 и размеров
"после" файла)
• Keyword arguments для всего
• Внятная "простыня" вместо равиоли
И еще всякие плюшки
• Чтение ZIP-файлов по HTTP с доступом к отдельным
файлам в архиве
• Size esCmator (потому что можно создать "виртуальный" зип
без файлов)
• Параллельная компрессия на нескольких серверах сразу
• YARD для всего
Наблюдения
• Начинать всегда с доработки напильником и изучения
предмета
• Отслеживаем, когда клеммы отваливаются и шунты горят.
• "Еще одна" библиотека это нормально. Даже в cargo
библиотек для zip две.
Нету социального протокола
Для ситуации "Все это хорошо бы переделать, давайте
придумаем как."
Или?
Кейс 2 : LaunchDarkly
LaunchDarkly держит на своих серверах таблицу features и
таблицу AB-экспериментов. Библиотека внутри вашего
приложения скачивает их периодически, и позволяет
распределять посетителей в определенные
"корзины" (функциональность включена/выключена и так
далее). LaunchDarkly предоставляет gem которым можно
пользоваться.
Ничто не предвещало беды.
При этом API который "свисает наружу" предельно маленький:
# в конфиге приложения
ld_client = LaunchDarkly::LDClient.new("YOUR_SDK_KEY")
# и далее где надо
show_feature = ld_client.variation("your.flag.key", {key: "user@test.com"}, false)
if show_feature
# ....
end
Стандартный способ получения таблицы - простой HTTP-
запрос. Все ок.
• А еще они открывают SSE-соединение (EventSource) со
своим сервером. Из каждого руби-процесса. Чтобы получать
апдейты этой таблицы с задержкой меньше секунды.
• А еще они генерят эвенты при просчете флага и отправляют
эти эвенты на свой сервер.
Каждый процесс периодически выполняет два HTTP запроса,
и держит постоянно открытым HTTP соединение.
Ничего что у нас теперь будет 200
постоянно открытых сокетов в
интернет чтобы у нас были
feature flags? С каждого сервера?
Но дело даже не в этом. А в том что для того чтобы это
обеспечить, в самой библиотеке должен быть либо thread,
либо event-реактор.
Повторяем. Чтобы сделать вот это:
rng = Random.new(derive_numeric_seed(user_id))
rng.rand < rollout_ratio
spec.add_runtime_dependency "json", "~> 1.8"
spec.add_runtime_dependency "faraday", "~> 0.9"
spec.add_runtime_dependency "faraday-http-cache", "~> 1.3.0"
spec.add_runtime_dependency "thread_safe", "~> 0.3"
spec.add_runtime_dependency "net-http-persistent", "~> 2.9"
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0.4"
spec.add_runtime_dependency "hashdiff", "~> 0.2"
spec.add_runtime_dependency "ld-celluloid-eventsource", "~> 0.10.0"
spec.add_runtime_dependency "celluloid", "~> 0.18.0.pre" # transitive dep; specified here for more control
if RUBY_VERSION >= "2.2.2"
spec.add_runtime_dependency "nio4r", "< 3" # for maximum ruby version compatibility.
else
spec.add_runtime_dependency "nio4r", "~> 1.1" # for maximum ruby version compatibility.
end
spec.add_runtime_dependency "waitutil", "0.2"
То есть у нас будет и concurrent-ruby (потоки) и сelluloid (event
loop с актерами), который занимается этим самым EventSource
Желание иметь и Celluloid и потоки в какой-то момент
привело к тому что LD просто был несовместим с нашей
версией Ruby.
Эвенты которые создаются при просчете флагов запускаются в
Queue, и таск работающий в фоне (для этого им нужен
concurrent-ruby) их оттуда забирает, трансформирует,
агрегирует и отправляет...
Предлагается правда прокси-сервер на Go чтобы ваше
приложение подсоединялось к нему, а не к серверу LD в
Америке.
• Puma / unicorn
• Sidekiq worker
• Faye / Ac6onCable
• Никаких синглтонов
• Никаких потоков
• Очередь с событиями для отправки - в Redis
• Флаги тоже в Redis
# Ставим его в приложение
config.middleware.use "Lad::RackMiddleware", redis: config.redis_connection_pool
# и используем из контроллера
def ld_client
request.env['lad.client']
end
И в фоновом режиме
На одном сервере два cron job'а
• "Забрать эвенты из Redis и отправить их в LaunchDarkly"
• "Загрузить флаги из LaunchDarkly в Redis"
Крутятся раз в пять секунд.
А что дальше?
У нас теперь есть свой велосипед, который нужно патчить,
поддерживать и всячески смазывать и перебирать. А upstream
на месте не стоит.
Все интересно
• Celluloid они оттуда выпилили и заменили на socketry/async
• Concurrent-ruby еще не выпилили
Socketry/async тоже непрост
Мы с ним наелись в другом приложении.
• Иногда подтекает память
• Текут сокеты
• SSL-соединения виснут
• Библиотеки обновляются раз в неделю
Но есть подстраховка
show_feature = ld_client.variation("your.flag.key", {key: "user@test.com"}, false)
if show_feature
# ....
end
Социальный протокол пришлось
придумать на ходу
• LD - коммерческая организация, и у их клиентов другие
заботы
• Они предоставляют Ruby-библиотеку и уже это подвиг
• У нас не цель показать что писать Java на Ruby не надо. У нас
цель - иметь работающие feature flags
Мы решили наши трейдоффы - а также мои личные взгляды
на то как надо (и не надо) писать библиотеки - из избы не
выносить. Потому что отношения с поставщиками /
партнерами важнее.
И это нормально!
Не все надо опенсорсить, особенно если это может вызвать
скандалы. Но можно рассказать об этом историю. Например -
всем вам
!
Наблюдения
• Начинать всегда с доработки напильником и изучения
предмета
• Отслеживаем, когда клеммы отваливаются и шунты горят (у
нас перегорело все до старта), и только потом...
• "Еще одна" библиотека это нормально, но открыто поливать
оригинал не надо.
А у нас не все гладко
Очень много чего на Ruby в приличном варианте просто нет.
• Machine learning
• GPU
• Байндинги для Qt
• async/await
• UI
• Транспиляции в JS
Каждый раз когда мы, улюлюкая, даем кому-то понять что он
занят глупостями - мы теряем контрибьюторов. А язык и так
усыхает и завядает.
Вы хотите продолжать писать на
Ruby? Я - да.
Вместе с вами.
У нас есть работа
h"ps://wetransfer.homerun.co
Изобретайте велосипеды и не стесняйтесь.
• h#ps://github.com/WeTransfer
• h#ps://github.com/julik
• twi#er / @julikt

More Related Content

What's hot

Алексей Федоров
Алексей ФедоровАлексей Федоров
Алексей ФедоровCodeFest
 
Дмитрий Стогов
Дмитрий СтоговДмитрий Стогов
Дмитрий СтоговCodeFest
 
Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...
Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...
Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...Ontico
 
Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)
Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)
Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)Ontico
 
MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...
MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...
MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...Ontico
 
Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)
Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)
Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)Ontico
 
"Fault tolerant workflow orchestration on PHP", Anton Tsitou
"Fault tolerant workflow orchestration on PHP", Anton Tsitou"Fault tolerant workflow orchestration on PHP", Anton Tsitou
"Fault tolerant workflow orchestration on PHP", Anton TsitouFwdays
 
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Ontico
 
Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...
Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...
Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...Oleg Tsarev
 
Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo)
 Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo) Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo)
Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo)Ontico
 
Docker в работе: взгляд на использование в Badoo через год
Docker в работе: взгляд на использование в Badoo через годDocker в работе: взгляд на использование в Badoo через год
Docker в работе: взгляд на использование в Badoo через годBadoo Development
 
Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)
Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)
Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)Ontico
 
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...it-people
 
Андрей Акиньшин
Андрей АкиньшинАндрей Акиньшин
Андрей АкиньшинCodeFest
 
Docker & Puppet: как их скрестить и надо ли вам это?
Docker & Puppet: как их скрестить и надо ли вам это?Docker & Puppet: как их скрестить и надо ли вам это?
Docker & Puppet: как их скрестить и надо ли вам это?Anton Turetsky
 
Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)
Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)
Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)Ontico
 
Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)Ontico
 
Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14Vasil Remeniuk
 
Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)
Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)
Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)Ontico
 
Scala performance под капотом
Scala performance под капотомScala performance под капотом
Scala performance под капотомRoman Grebennikov
 

What's hot (20)

Алексей Федоров
Алексей ФедоровАлексей Федоров
Алексей Федоров
 
Дмитрий Стогов
Дмитрий СтоговДмитрий Стогов
Дмитрий Стогов
 
Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...
Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...
Docker в работе: взгляд на его использование в Badoo через год / Турецкий Ант...
 
Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)
Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)
Как устроена MySQL-репликация, Андрей Аксенов (Sphinx)
 
MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...
MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...
MyRocks Табличный Движок для MySQL / Алексей Майков (Facebook) / Сергей Петру...
 
Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)
Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)
Язык Lua — секреты производительности / Ник Заварицкий (Mail.ru)
 
"Fault tolerant workflow orchestration on PHP", Anton Tsitou
"Fault tolerant workflow orchestration on PHP", Anton Tsitou"Fault tolerant workflow orchestration on PHP", Anton Tsitou
"Fault tolerant workflow orchestration on PHP", Anton Tsitou
 
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
 
Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...
Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...
Асинхронная репликация без цензуры: архитектурные проблемы MySQL, или почему ...
 
Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo)
 Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo) Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo)
Отладка производительности приложения на Erlang / Максим Лапшин (Erlyvideo)
 
Docker в работе: взгляд на использование в Badoo через год
Docker в работе: взгляд на использование в Badoo через годDocker в работе: взгляд на использование в Badoo через год
Docker в работе: взгляд на использование в Badoo через год
 
Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)
Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)
Производительность WebGL-приложений / Дмитренко Кирилл (Яндекс)
 
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
 
Андрей Акиньшин
Андрей АкиньшинАндрей Акиньшин
Андрей Акиньшин
 
Docker & Puppet: как их скрестить и надо ли вам это?
Docker & Puppet: как их скрестить и надо ли вам это?Docker & Puppet: как их скрестить и надо ли вам это?
Docker & Puppet: как их скрестить и надо ли вам это?
 
Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)
Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)
Оптимизация производительности фронтенда / Игорь Алексеенко (HTML Academy)
 
Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)
 
Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14Работа с Akka Сluster, @afiskon, scalaby#14
Работа с Akka Сluster, @afiskon, scalaby#14
 
Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)
Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)
Производительность Unity3D: подводные камни / Алексей Чубарь (BIT.GAMES)
 
Scala performance под капотом
Scala performance под капотомScala performance под капотом
Scala performance под капотом
 

Similar to Reinventing the wheel - why do it and how to feel good about it - Julik Tarkhanov | Ruby Meditation 28

Сергей Житинский, Александр Чистяков (Git in Sky)
Сергей Житинский, Александр Чистяков (Git in Sky)Сергей Житинский, Александр Чистяков (Git in Sky)
Сергей Житинский, Александр Чистяков (Git in Sky)Ontico
 
SmartOS/Solaris app tuning tools/technologies on HL++ 2013
SmartOS/Solaris app tuning tools/technologies on HL++ 2013SmartOS/Solaris app tuning tools/technologies on HL++ 2013
SmartOS/Solaris app tuning tools/technologies on HL++ 2013Alex Chistyakov
 
Git in Sky presentation @ HighLoad++ 2013
Git in Sky presentation @ HighLoad++ 2013Git in Sky presentation @ HighLoad++ 2013
Git in Sky presentation @ HighLoad++ 2013Serguei Gitinsky
 
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...PavelKonotopov
 
ekbpy'2012 - Данила Штань - Распределенное хранилище
ekbpy'2012 - Данила Штань - Распределенное хранилищеekbpy'2012 - Данила Штань - Распределенное хранилище
ekbpy'2012 - Данила Штань - Распределенное хранилищеit-people
 
CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...
CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...
CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...CodeFest
 
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013Unigine Corp.
 
How to cook a blockchain and not get burned
How to cook a blockchain and not get burned How to cook a blockchain and not get burned
How to cook a blockchain and not get burned Alexander Syrotenko
 
CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...
CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...
CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...CodeFest
 
Hosting for forbes.ru_
Hosting for forbes.ru_Hosting for forbes.ru_
Hosting for forbes.ru_drupalconf
 
Node.js введение в технологию, КПИ #ITmeetingKPI
Node.js введение в технологию, КПИ  #ITmeetingKPINode.js введение в технологию, КПИ  #ITmeetingKPI
Node.js введение в технологию, КПИ #ITmeetingKPITimur Shemsedinov
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Yandex
 
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...CodeFest
 
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)Ontico
 
PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...Arvids Godjuks
 
Другая виртуализация
Другая виртуализацияДругая виртуализация
Другая виртуализацияYandex
 
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...Yandex
 
Не превращайте ваши логи в клинопись
Не превращайте ваши логи в клинописьНе превращайте ваши логи в клинопись
Не превращайте ваши логи в клинописьAndrey Rebrov
 
Опыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событияхОпыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событияхVasil Remeniuk
 
Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)
Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)
Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)Ontico
 

Similar to Reinventing the wheel - why do it and how to feel good about it - Julik Tarkhanov | Ruby Meditation 28 (20)

Сергей Житинский, Александр Чистяков (Git in Sky)
Сергей Житинский, Александр Чистяков (Git in Sky)Сергей Житинский, Александр Чистяков (Git in Sky)
Сергей Житинский, Александр Чистяков (Git in Sky)
 
SmartOS/Solaris app tuning tools/technologies on HL++ 2013
SmartOS/Solaris app tuning tools/technologies on HL++ 2013SmartOS/Solaris app tuning tools/technologies on HL++ 2013
SmartOS/Solaris app tuning tools/technologies on HL++ 2013
 
Git in Sky presentation @ HighLoad++ 2013
Git in Sky presentation @ HighLoad++ 2013Git in Sky presentation @ HighLoad++ 2013
Git in Sky presentation @ HighLoad++ 2013
 
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
 
ekbpy'2012 - Данила Штань - Распределенное хранилище
ekbpy'2012 - Данила Штань - Распределенное хранилищеekbpy'2012 - Данила Штань - Распределенное хранилище
ekbpy'2012 - Данила Штань - Распределенное хранилище
 
CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...
CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...
CodeFest 2012. Сидельников А. — Опыт создания DSL на Ruby. Где применить, как...
 
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
 
How to cook a blockchain and not get burned
How to cook a blockchain and not get burned How to cook a blockchain and not get burned
How to cook a blockchain and not get burned
 
CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...
CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...
CodeFest 2014. Круглов И. — События на каждом углу. Путешествие в мир системн...
 
Hosting for forbes.ru_
Hosting for forbes.ru_Hosting for forbes.ru_
Hosting for forbes.ru_
 
Node.js введение в технологию, КПИ #ITmeetingKPI
Node.js введение в технологию, КПИ  #ITmeetingKPINode.js введение в технологию, КПИ  #ITmeetingKPI
Node.js введение в технологию, КПИ #ITmeetingKPI
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
 
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
 
PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...
 
Другая виртуализация
Другая виртуализацияДругая виртуализация
Другая виртуализация
 
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
 
Не превращайте ваши логи в клинопись
Не превращайте ваши логи в клинописьНе превращайте ваши логи в клинопись
Не превращайте ваши логи в клинопись
 
Опыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событияхОпыт использования Spark, Основано на реальных событиях
Опыт использования Spark, Основано на реальных событиях
 
Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)
Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)
Асинхронная репликация без цензуры, Олег Царёв (Mail.ru Group)
 

More from Ruby Meditation

Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30Ruby Meditation
 
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...Ruby Meditation
 
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29Ruby Meditation
 
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...Ruby Meditation
 
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28 How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28 Ruby Meditation
 
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28Ruby Meditation
 
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...Ruby Meditation
 
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...Ruby Meditation
 
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...Ruby Meditation
 
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27Ruby Meditation
 
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26Ruby Meditation
 
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26Ruby Meditation
 
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...Ruby Meditation
 
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26Ruby Meditation
 
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25Ruby Meditation
 
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...Ruby Meditation
 
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...Ruby Meditation
 
Rails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan GusievRails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan GusievRuby Meditation
 
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23Ruby Meditation
 
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...Ruby Meditation
 

More from Ruby Meditation (20)

Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
 
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
 
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
 
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
 
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28 How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
 
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
 
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
 
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
 
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
 
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
 
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
 
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
 
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
 
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
 
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
 
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
 
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
 
Rails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan GusievRails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan Gusiev
 
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
 
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
 

Reinventing the wheel - why do it and how to feel good about it - Julik Tarkhanov | Ruby Meditation 28

  • 2. gem "rutils" gem "gilenson" gem "russian" gem "ru_propisju" gem "timecode" gem "edl" "и это тоже".mb_chars.upcase
  • 3. gem "prorate" gem "activerecord_autoreplica" gem "format_parser" gem "zip_tricks" gem "apiculture" gem "tracksperanto"
  • 4.
  • 5. WeTransfer Много файлов, много клиентов, много Ruby и JS
  • 6.
  • 8.
  • 9. • ≈ 881000 велосипедов - правда-правда! • на ≈ 800000 жителей
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15. Основная модель для местности • Один торомоз - педальный задний. Передний ручной - скорее баловство • Навесное оборудование - звонок (иногда, пугать туристов) и свет (без него оштрафуют) • Иногда багажники
  • 16. И нету • Ручных тормозов • Сликов • Клипс • Амортизаторов • Переключения скоростей • Cумок и бардачков
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23. Это не изобретение • Это решение разных задач • Это исследование • Это поиск и творчество • Это доводка того что вам не подходит до того состояния, в котором оно вам подойдет
  • 24. Кейс первый. zip_tricks Как-бы "еще одна" ZIP-библиотека для Ruby.
  • 25.
  • 26.
  • 27. Зачем это было нужно У нас есть сервер для скачивания файлов. Он тащит данные с S3 и подшивает их на ходу в ZIP. Ну примерно как mod_zip для nginx. Но нам еще надо отправлять оповещение о том что скачивание закончено. А еще...
  • 28. • Какого размера будет ZIP после скачки? • А рестартовать скачку с определенного места? • А Zip64? • А юникодные имена файлов?
  • 29. Например, хочется вот так: exact_archive_size = ArchiveLibrary.estimate_size do |arch| arch.add_file(name: "File.doc", size_in_archive: 1586215) arch.add_file(name: "TOC.xml", size_in_archive: 1452) end
  • 30. А самое главное - хочется вот так: ArchiveLibrary.write(socket) do |arch| arch.add_local_file_header(name: "File.doc", size_in_archive: 1586215) IO.copy_stream(remote_file_contents, arch) end
  • 31. socket не может seek и rewind
  • 32. То есть - интеграция чужой библиотеки нам видится так: (потому что ООП и модули и кумбайя)
  • 33.
  • 34.
  • 35.
  • 36.
  • 38.
  • 39.
  • 40.
  • 41. На самом деле zip_tricks начался как патч для rubyzip. И ох - если бы можно было его таким оставить. class ZipTricks::OutputStreamPrefab < ::Zip::OutputStream def initialize(io, stream_flag=false, encrypter=nil) super StringIO.new, stream_flag=true, encrypter=nil @output_stream = io end def put_next_entry(entry_name, size, crc) new_entry = ::Zip::Entry.new(@file_name, entry_name) new_entry.compression_method = Zip::Entry::STORED new_entry.crc, new_entry.size = crc, size new_entry.compressed_size = size + new_entry.calculate_local_header_size super(new_entry, nil, nil, new_entry.compression_method, level=Zlib::NO_COMPRESSION) end # We never need to update local headers, because we set all the data in the header ahead of time. # And this is the method that tries to rewind the IO, so fuse it out and turn it into a no-op. def update_local_headers nil end end
  • 42. Есть вариации похожего (библиотека zipline): def finalize_current_entry if current_entry entry = current_entry super write_local_footer(entry) end end def write_local_footer(entry) @output_stream << [ 0x08074b50, entry.crc, entry.compressed_size, entry.size].pack('VVVV') end
  • 43.
  • 44.
  • 45. Тупик. module Zip # placeholder to reserve space for a Zip64 extra information record, for the # local file header only, that we won't know if we'll need until after # we write the file data class ExtraField::Zip64Placeholder < ExtraField::Generic HEADER_ID = ['9999'].pack('H*') # this ID is used by other libraries such as .NET's Ionic.zip register_map def initialize(_binstr = nil); end def pack_for_local "x00" * 16 end end end
  • 46. Ну и соответственно • ZIP - хитрозаковыристый формат • В rubyzip реализация этого формата размазана тонким слоем по десятку-двум отдельных модулей
  • 47.
  • 48. Как это можно сделать по- другому?
  • 49. • Находим все мелкие детальки спецификации формата ZIP • Собираем их в один обьект с visitor paCern • Люто тестируем во всех направлениях, и только его, побайтово
  • 50. writer.write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:) writer.write_central_directory_file_header(io:, local_file_header_location:, gp_flags:, storage_mode:, compressed_size:, uncompressed_size:, mtime:, crc32:, filename:) writer.write_data_descriptor(io:, compressed_size:, uncompressed_size:, crc32:) writer.write_end_of_central_directory(io:, start_of_central_directory_location:, central_directory_size:, num_files_in_archive:, comment: ZIP_TRICKS_COMMENT)
  • 51. • 430 строк с обильными комментариями • EFS (UTF-8 имена файлов) автоматом и только если надо • Zip64 автоматом и только если надо • Data descriptor (футеры для записи CRC32 и размеров "после" файла) • Keyword arguments для всего • Внятная "простыня" вместо равиоли
  • 52. И еще всякие плюшки • Чтение ZIP-файлов по HTTP с доступом к отдельным файлам в архиве • Size esCmator (потому что можно создать "виртуальный" зип без файлов) • Параллельная компрессия на нескольких серверах сразу • YARD для всего
  • 53. Наблюдения • Начинать всегда с доработки напильником и изучения предмета • Отслеживаем, когда клеммы отваливаются и шунты горят. • "Еще одна" библиотека это нормально. Даже в cargo библиотек для zip две.
  • 54. Нету социального протокола Для ситуации "Все это хорошо бы переделать, давайте придумаем как."
  • 56. Кейс 2 : LaunchDarkly
  • 57. LaunchDarkly держит на своих серверах таблицу features и таблицу AB-экспериментов. Библиотека внутри вашего приложения скачивает их периодически, и позволяет распределять посетителей в определенные "корзины" (функциональность включена/выключена и так далее). LaunchDarkly предоставляет gem которым можно пользоваться. Ничто не предвещало беды.
  • 58. При этом API который "свисает наружу" предельно маленький: # в конфиге приложения ld_client = LaunchDarkly::LDClient.new("YOUR_SDK_KEY") # и далее где надо show_feature = ld_client.variation("your.flag.key", {key: "user@test.com"}, false) if show_feature # .... end
  • 59. Стандартный способ получения таблицы - простой HTTP- запрос. Все ок.
  • 60. • А еще они открывают SSE-соединение (EventSource) со своим сервером. Из каждого руби-процесса. Чтобы получать апдейты этой таблицы с задержкой меньше секунды. • А еще они генерят эвенты при просчете флага и отправляют эти эвенты на свой сервер.
  • 61. Каждый процесс периодически выполняет два HTTP запроса, и держит постоянно открытым HTTP соединение.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66. Ничего что у нас теперь будет 200 постоянно открытых сокетов в интернет чтобы у нас были feature flags? С каждого сервера?
  • 67. Но дело даже не в этом. А в том что для того чтобы это обеспечить, в самой библиотеке должен быть либо thread, либо event-реактор.
  • 68. Повторяем. Чтобы сделать вот это: rng = Random.new(derive_numeric_seed(user_id)) rng.rand < rollout_ratio
  • 69. spec.add_runtime_dependency "json", "~> 1.8" spec.add_runtime_dependency "faraday", "~> 0.9" spec.add_runtime_dependency "faraday-http-cache", "~> 1.3.0" spec.add_runtime_dependency "thread_safe", "~> 0.3" spec.add_runtime_dependency "net-http-persistent", "~> 2.9" spec.add_runtime_dependency "concurrent-ruby", "~> 1.0.4" spec.add_runtime_dependency "hashdiff", "~> 0.2" spec.add_runtime_dependency "ld-celluloid-eventsource", "~> 0.10.0" spec.add_runtime_dependency "celluloid", "~> 0.18.0.pre" # transitive dep; specified here for more control if RUBY_VERSION >= "2.2.2" spec.add_runtime_dependency "nio4r", "< 3" # for maximum ruby version compatibility. else spec.add_runtime_dependency "nio4r", "~> 1.1" # for maximum ruby version compatibility. end spec.add_runtime_dependency "waitutil", "0.2"
  • 70. То есть у нас будет и concurrent-ruby (потоки) и сelluloid (event loop с актерами), который занимается этим самым EventSource
  • 71. Желание иметь и Celluloid и потоки в какой-то момент привело к тому что LD просто был несовместим с нашей версией Ruby.
  • 72. Эвенты которые создаются при просчете флагов запускаются в Queue, и таск работающий в фоне (для этого им нужен concurrent-ruby) их оттуда забирает, трансформирует, агрегирует и отправляет...
  • 73.
  • 74.
  • 75.
  • 76. Предлагается правда прокси-сервер на Go чтобы ваше приложение подсоединялось к нему, а не к серверу LD в Америке.
  • 77. • Puma / unicorn • Sidekiq worker • Faye / Ac6onCable
  • 78.
  • 79.
  • 80. • Никаких синглтонов • Никаких потоков • Очередь с событиями для отправки - в Redis • Флаги тоже в Redis
  • 81. # Ставим его в приложение config.middleware.use "Lad::RackMiddleware", redis: config.redis_connection_pool # и используем из контроллера def ld_client request.env['lad.client'] end
  • 82. И в фоновом режиме На одном сервере два cron job'а • "Забрать эвенты из Redis и отправить их в LaunchDarkly" • "Загрузить флаги из LaunchDarkly в Redis" Крутятся раз в пять секунд.
  • 83. А что дальше? У нас теперь есть свой велосипед, который нужно патчить, поддерживать и всячески смазывать и перебирать. А upstream на месте не стоит.
  • 84. Все интересно • Celluloid они оттуда выпилили и заменили на socketry/async • Concurrent-ruby еще не выпилили
  • 85. Socketry/async тоже непрост Мы с ним наелись в другом приложении. • Иногда подтекает память • Текут сокеты • SSL-соединения виснут • Библиотеки обновляются раз в неделю
  • 86. Но есть подстраховка show_feature = ld_client.variation("your.flag.key", {key: "user@test.com"}, false) if show_feature # .... end
  • 88. • LD - коммерческая организация, и у их клиентов другие заботы • Они предоставляют Ruby-библиотеку и уже это подвиг • У нас не цель показать что писать Java на Ruby не надо. У нас цель - иметь работающие feature flags
  • 89. Мы решили наши трейдоффы - а также мои личные взгляды на то как надо (и не надо) писать библиотеки - из избы не выносить. Потому что отношения с поставщиками / партнерами важнее.
  • 90. И это нормально! Не все надо опенсорсить, особенно если это может вызвать скандалы. Но можно рассказать об этом историю. Например - всем вам !
  • 91. Наблюдения • Начинать всегда с доработки напильником и изучения предмета • Отслеживаем, когда клеммы отваливаются и шунты горят (у нас перегорело все до старта), и только потом... • "Еще одна" библиотека это нормально, но открыто поливать оригинал не надо.
  • 92.
  • 93.
  • 94. А у нас не все гладко Очень много чего на Ruby в приличном варианте просто нет.
  • 95. • Machine learning • GPU • Байндинги для Qt • async/await • UI • Транспиляции в JS
  • 96. Каждый раз когда мы, улюлюкая, даем кому-то понять что он занят глупостями - мы теряем контрибьюторов. А язык и так усыхает и завядает.
  • 97. Вы хотите продолжать писать на Ruby? Я - да.
  • 99.
  • 100. У нас есть работа h"ps://wetransfer.homerun.co
  • 101. Изобретайте велосипеды и не стесняйтесь. • h#ps://github.com/WeTransfer • h#ps://github.com/julik • twi#er / @julikt