Было бы любопытно глянуть на изолированный пример: как выглядел код на Go и как его пришлось переписать на C++. Такой контраст наверняка интересен и был бы очень показателен.
Аргументация в статье местами кажется несколько "размытой":
«…возникают тысяча и один вопрос, например как garbage collector Go будет всё это обрабатывать. И кажется, именно поэтому в Prometheus такой подход пока не используют, хотя попытки были. Мы решили эти проблемы, изменив формат работы с WAL.»
Проблема, по сути, обозначается как “много вопросов” и “кажется, что так не делают”, но без конкретики — непонятно, какие именно сложности возникли и пробовали ли их решать средствами Go. В C++ действительно проще с ручным управлением памятью, но остаётся ощущение, что вопрос до конца не раскрыт.
Ну да, проблему "много вопросов" и "кажется" C++ действительно решает. Но осталось неясным:
Как именно Go будет всё это обрабатывать (может, и хорошо справится)?
Можно ли оптимизировать эту задачу средствами Go (возможно, и можно)?
Впрочем, понятно одно — как сделать это в C++ обычно очевиднее :)
Отличная работа по оптимизации! Было бы здорово увидеть decision matrix в начале статьи - когда FastCGo оправдан, а когда лучше остаться с CGo. Это помогло бы инженерам быстрее понять применимость решения в их контексте.
Статья интересная, и весьма. Понравился, например, приём - не спрашивать, что такое SOLID, а попросить рассказать, где принцип открытости/закрытости реально тебе помог. Или наоборот — не помог. Почему?
У этого вопроса, как мне видится, несколько уровней ответа.
Есть встречный вопрос - есть ли основания считать, что такая методика имеет объективное, измеряемое преимущество перед какими-то другими? Может, просто "химии" вполне достаточно?
Ну, там, пять-десять минут поговорили о том, о сём, о житейском, о техническом - и вроде как и ясно всё.
Вот такая методика точно хуже, и по какому критерию?
Систему сопровождают администраторы (не разработчики) первой линии сопровождения, после обращений пользователей изучают проблему по документации, регистрируют дефект и отправляют разработчикам. А если документации нет, они не понимают, как система работает, не могут её ни сопровождать, ни консультировать по ней.
Документация в виде требований к системе должна же быть? Каков уровень проработки требований, там нет примерных указаний на то, как система работает и сопровождается?
Можно оценить затраты времени с разбивкой по типам задач — Bug / QA / Story. Это даёт прозрачность того, сколько часов команда тратит на исправление дефектов, тестирование и разработку новых фич а также динамику этой метрики. Чего не достать просто из списка выполненных задач.
Было бы круто, если бы в трекере была простая кнопка: начал работать над задачей — закончил работать над задачей. Это можно было бы даже совместить с техникой Pomodoro (тогда не нужна кнопка "Закончил работу") - чтобы разработчику не приходилось вручную логировать время.
В разделе "Нефункциональные требования" не увидел Consistency (которая consistency в CAP). Какие операции чтения значения должны получать значение из его последнией записи (strict serializable)? В каких случаях допустимо применение eventual consistency? Такие вот вопросы я бы задал (так как их приходится постоянно решать).
Так же в "Перфоманс" я бы явно указал Lanetcy (время отклика) и Throughput (пропускная способность).
Первые два бота писались примерно по одинакой схеме: ты просто говоришь "а напиши мне бота" и описываешь функционал. ... Ты ей говоришь "вот ты скачиваешь курсы валют, тебе не надо это делать каждый раз при старте, положи их в кеш вместе с временем скачивания и только если разница во времени больше пяти часов, качай заново" ... 1)В архитектуру LLM не умеет.
К такому выводу, как мне кажется, нужны пояснения. Вот такой prompt для claude (моделька 3.5 Sonnet):
Придумай архитектуру для: Бот-конвертер валют (тоже в тг). Ждет в личку или в чате сообщение с "100 евро" и реплаит на него с несколькими сконвертированными валютами. Питон.
На этом этапе можно посмотреть, понять, местами простить и далее принять архитектуру уровня C3.
Далее продолжаем помодульно слать запросы для уровня C4.
Квоты на выполнение запроса - в данном случае по созданию кодовой базы целиком - приводят к тому, что искомая база таки генерируется, но она низкого качества ("не умеет в архитектуру"). Всех много, а всего (вычислительных ресурсов) мало - поэтому всего на всех не хватает.
Отсюда правило (капитанское, конечо) - надо декомпозировать и "брать" частями.
Схема красивая и по-своему логичная. Однако, замечу, что джепсен использует определение Serializability, согласно которому:
The requirement for a total order of transactions is strong—but still allows pathological orderings. For instance, a serializable database can always return the empty state for any reads, by appearing to execute those reads at time 0. It can also discard write-only transactions by reordering them to execute at the very end of the history, after any reads. Operations like increments can also be discarded, assuming the result of the increment is never observed.
Т.е. тут как раз с тем, что у Вас называется Distributed Constraints, пересечения нет, и мухи от котлет отделены.
🍺 Часть 2 будет ближе к вечеру. Интересно, у Вас открывается scratchpad? Стало глючить (подвисает на Loading worker...), неужели так бысто "хабрэффект" наступил...
величина её наверняка будет ничтожной для ощутимого эффекта
Если взять палатку 6x6x5 то, при разности температур в 60 C [-40, +20] разница в плотностях воздуха будет где-то 1.53 - 1.2 ~= 0.33 кг/м^3. Что даст "тягу" в 0.33 * 180 ~= 60 кгс.
Плотность ткани Оксфорд 240 den - 115гр/м2. Что дает массу верха (6x5x4 + 6x6)*0.115 ~= 18 кг.
// any request to "/search/*" endpoint will
// automatically receive an array with two book objects
cy.intercept('/search/*', [{ item: 'Book 1' }, { item: 'Book 2' }]).as(
'getSearch'
)
cy.get('[data-testid="autocomplete"]').type('Book')
// this yields us the interception cycle object
// which includes fields for the request and response
cy.wait('@getSearch').its('request.url').should('include', '/search?query=Book')
cy.get('[data-testid="results"]')
.should('contain', 'Book 1')
.and('contain', 'Book 2')
Результаты этих тестов нужно было где-то хранить. Для такой задачи решили использовать Allure.
В cypress хранение "из коробки", при этом можно повторно "проигрывать" тесты, Test Replay
Спасибо за детальное объяснение! Насколько я понял, оптимизация здесь делится на две части:
Оптимизация хранения лейблов (labelsets)
Оптимизация хранения точек (временных рядов)
Колоночное хранение, DeltaOfDelta, union'ы для in-place значений
Интересно было бы понять границы возможного: какого уровня экономии памяти можно было достичь, используя "обычный" Go.
Вот, например, энкодер/декодер для ID
https://go.dev/play/p/dGYuyrVCoCf
По первой части пока не вижу очевидной необходимости перехода — или я что-то упускаю?
Дык я согласен про числодробилки, но какое отношение это имеет к проблеме:
"например как garbage collector Go будет всё это обрабатывать"
"И кажется, именно поэтому в Prometheus такой подход пока не используют, хотя попытки были"
?
Было бы любопытно глянуть на изолированный пример: как выглядел код на Go и как его пришлось переписать на C++. Такой контраст наверняка интересен и был бы очень показателен.
Аргументация в статье местами кажется несколько "размытой":
Проблема, по сути, обозначается как “много вопросов” и “кажется, что так не делают”, но без конкретики — непонятно, какие именно сложности возникли и пробовали ли их решать средствами Go. В C++ действительно проще с ручным управлением памятью, но остаётся ощущение, что вопрос до конца не раскрыт.
Ну да, проблему "много вопросов" и "кажется" C++ действительно решает. Но осталось неясным:
Как именно Go будет всё это обрабатывать (может, и хорошо справится)?
Можно ли оптимизировать эту задачу средствами Go (возможно, и можно)?
Впрочем, понятно одно — как сделать это в C++ обычно очевиднее :)
Отличная работа по оптимизации! Было бы здорово увидеть decision matrix в начале
статьи - когда FastCGo оправдан, а когда лучше остаться с CGo. Это помогло бы
инженерам быстрее понять применимость решения в их контексте.
Статья интересная, и весьма. Понравился, например, приём - не спрашивать, что такое SOLID, а попросить рассказать, где принцип открытости/закрытости реально тебе помог. Или наоборот — не помог. Почему?
У этого вопроса, как мне видится, несколько уровней ответа.
Есть встречный вопрос - есть ли основания считать, что такая методика имеет объективное, измеряемое преимущество перед какими-то другими? Может, просто "химии" вполне достаточно?
Ну, там, пять-десять минут поговорили о том, о сём, о житейском, о техническом - и вроде как и ясно всё.
Вот такая методика точно хуже, и по какому критерию?
Любопытная статья, спасибо. Есть пара вопросов.
Документация в виде требований к системе должна же быть? Каков уровень проработки требований, там нет примерных указаний на то, как система работает и сопровождается?
Каков примерно объём документируемого кода?
Чисто теоретически.
Можно оценить затраты времени с разбивкой по типам задач — Bug / QA / Story. Это даёт прозрачность того, сколько часов команда тратит на исправление дефектов, тестирование и разработку новых фич а также динамику этой метрики. Чего не достать просто из списка выполненных задач.
Было бы круто, если бы в трекере была простая кнопка: начал работать над задачей — закончил работать над задачей. Это можно было бы даже совместить с техникой Pomodoro (тогда не нужна кнопка "Закончил работу") - чтобы разработчику не приходилось вручную логировать время.
В разделе "Нефункциональные требования" не увидел Consistency (которая consistency в CAP). Какие операции чтения значения должны получать значение из его последнией записи (strict serializable)? В каких случаях допустимо применение eventual consistency? Такие вот вопросы я бы задал (так как их приходится постоянно решать).
Так же в "Перфоманс" я бы явно указал Lanetcy (время отклика) и Throughput (пропускная способность).
Спасибо, будет.
Диаграмка к статье
К такому выводу, как мне кажется, нужны пояснения. Вот такой prompt для claude (моделька 3.5 Sonnet):
В результате таки есть кeширование:
Currency converter
Core business logic component
Maintains exchange rates cache
Performs currency conversions
Interfaces with external exchange rate API
Implements retry logic and error handling
Exchange rate provider
Abstracts exchange rate API interactions
Fetches current exchange rates
Updates local cache periodically
Handles API errors and timeouts
Supports multiple fallback providers
На этом этапе можно посмотреть, понять, местами простить и далее принять архитектуру уровня C3.
Далее продолжаем помодульно слать запросы для уровня C4.
Квоты на выполнение запроса - в данном случае по созданию кодовой базы целиком - приводят к тому, что искомая база таки генерируется, но она низкого качества ("не умеет в архитектуру"). Всех много, а всего (вычислительных ресурсов) мало - поэтому всего на всех не хватает.
Отсюда правило (капитанское, конечо) - надо декомпозировать и "брать" частями.
Схема красивая и по-своему логичная. Однако, замечу, что джепсен использует определение Serializability, согласно которому:
Т.е. тут как раз с тем, что у Вас называется Distributed Constraints, пересечения нет, и мухи от котлет отделены.
🍺 Часть 2 будет ближе к вечеру. Интересно, у Вас открывается scratchpad? Стало глючить (подвисает на
Loading worker...
), неужели так бысто "хабрэффект" наступил...Если взять палатку 6x6x5 то, при разности температур в 60 C [-40, +20] разница в плотностях воздуха будет где-то
1.53 - 1.2 ~= 0.33 кг/м^3
. Что даст "тягу" в0.33 * 180 ~= 60 кгс
.Плотность ткани Оксфорд 240 den - 115гр/м2. Что дает массу верха
(6x5x4 + 6x6)*0.115 ~= 18 кг
.Ну т.е. + 40 кгс.
Зачем же нужна эта независимость?
Да QIP был хорош...Ностальгия.
А как же...
В cypress хранение "из коробки", при этом можно повторно "проигрывать" тесты, Test Replay
Неплохо?
А если все ядра уже заняты полезной вычислительной работой, разве асинхронная обработка не повлияет на производительность?
Пожалуй. Это стоило бы осветить в статье, КМК.