Сравнение происходит вручную, например, при помощи git diff. Вообще, там все довольно минималистично, должно совпасть с точностью до пробелов, но на практике именно в таком виде это не нужно, суть в самой возможности добавления обратной связи.
Если у вас обновление только через pipline - можно использовать migration first, генерировать модель автоматически из временной БД, к которой применилась миграция - и можно быть уверенным, что модель соответствует текущей схеме, а схема текущей миграции, т.к. прод меняется только миграциями. Или можно как и у вас - править модель вручную, по ней генерировать миграции - результат одинаковый, вы всегда можете сгенерировать одно из другого (по крайней мере если придерживаться некоторых правил организации кода).
Если же на проде несколько слабозависимых служб со своими миграциями, или админы вручную что-то меняют - можно выкачать из прода схему, сгенерировать по ней модель (можно фильтровать по именам таблиц), при помощи git посмотреть, что изменилось, что-то может нужно поправить вручную или может откатить - а затем можно сгенерировать миграцию по новым сущностям, и автоматически привести тестовую среду в к соответвию как модели, так и проду.
Единственное, я пока не уверен, насколько надежно генерируются миграции по модели - seaorm 2 еще не релизнулся, эта возмодность на уровне обзоров. Но вы как раз демонстрируете, что этот подход работает хорошо, а генерация модели по схеме БД в seaorm изначально хорошо работает.
Мне в этом плане понравился подход, который сейчас внедряется в seaorm 2. Изначально там был подход migration first - миграции пишутся отдельно на специальном dsl, затем применяются к БД, и из живой БД генерируются сущности, используемые для запросов. Расхождения кода с БД устраняется уже на этом этапе, но далее добавляется обратная связь: вручную меняем сгенерированные сущности, по ним автоматически генерируется новая миграция. Ну и для корректности можно применить миграцию к БД, сгенерировать из нее сущности, до этого написанные вручную, и убедиться, что все совпало.
Не понимаю, почему постоянно идут разговоры про тупую рефлексию (а на деле даже не про рефлексию, а про интроспекцию, т.к. рефлексия позволяет кодогенерациию в рантайие). Рефлексия и интроспекцич позволяет работать только со стандартными языковыми конструкциями. Для реальных задач этого недостаточно. Нужна возможность описать и исследовать структуру данных в форме, специфичной для задачи. Обычно это означает, что нужно описать не только тип и список его членов, но и некоторые дополнительные атрибуты этих членов, и, возможно, типов. Например, для задачи сериализации нужна возможность описать полиморфные типы, как-то их перечислить, и указать, в какое поле записывать имя полиморфного типа. Для сериализации в xml нужно различать атрибуты и теги, для сериализации массивов зачастую нужно указывать разные теги для самого массива и элементов массива. Для бинарной сериализации иногда нужно явно указывать порядок байт для конкретного члена, хотя обычно это можно сделать за счёт выбора нужного сериализатора.
В то же время самому языку программирования эти атрибуты не нужны, поэтому для описания атрибутов нужна какая-то кодогенерация, в виде макросов или ещё чего-то. В случае c++ полноценным решение будут метоклассы, но и без них можно реализовать более полезные способы описания структур, чем указаны в статье.
Есть что-то вроде u64::from_be_bytes и from_le_bytes, и обратно. Там проблема только с размером, для оптимизации нужно assert расставлять. Ссылка не нужна, компилятор сам оптимизирует чтение и запись, заодно решая проблему выравнивания, вылезающую в случае unsafe.
Не уверен, как работает mimalloc, но использование пулов фиксированного размера в аллокаторе общего назначения не кажется логичным, т.к. увеличение количества пулов приведет у замедлению поиска нужного пула. Впрочем, в эффективности подхода автора я также сомневаюсь, так как используется по сути такое же общее состояние. Но в таком случае хотя бы общим состоянием будут пользоваться более ограниченное количество объектов.
Сообщество все ещё рекомендует писать frontend при помощи web-фрейморков, backend на Rust. При таком подходе можно и в редакторе формочки рисовать.
Если хотите чистый Rust - смотрите https://areweguiyet.com/ . Пока что ситуация с gui не радует, о редакторах форм речи даже не идёт. Разве что можно попробовать поискать привязки к библиотекам на других языках.
Большинство gui фреймворков не имеют интеграции с async/await и т.п, а разработчики асинхронных экосистем редко думают о gui.
Я недавно экспериментировал с волокнами (fibers) на c++ и qt. Получилось довольно интересно: в потоке gui можно использовать асинхронные каналы, мьютексы, future и promise, что позволяет явно написать алгоритм вида: "заблокировать кнопку перехода на следующую страницу" - "асинхронно загрузить страницу, в процессе выполняя асинхронные сетевые запросы" - "разблокировать кнопку перехода на следующую станицу". Это действительно удобно, но есть одна проблема: при нажатии кнопки "завершить программу", она не завершается. В асинхронных экосистемах механизма отмены обычно либо нет, либо он слишком неудобен, чтобы считать асинхронный код простым. Конечно, можно найти/написать свой планировщик, более подходящий для gui, но для этого как минимум нужно знать и понимать, какие проблемы он должен решать, какие решить не может, и учитывать нюансы вроде удаления вложенных виджетов при удалении родительского в qt. Простой frontend разработчик обычно это сделать не сможет, по крайней мере так, чтобы код оставался понятным. Нужна согласованная экосистема.
Если я вас правильно понял, проблема с указателями решаема, https://github.com/Ariox41/tmdesc . Интерфейс указатели не даёт, но технически вытащить можно. Все constexpr
Справедливости ради, AstraLinux сертифицирована для министерства обороны, и именно на него рассчитана. Брать её цену в качестве характеристики всего отечественного ПО не вполне корректно.
Если искать по количеству запросов в [google trends](https://trends.google.com), по 'С++' будет в три раз больше запросов, чем по 'Java', у 'Python' немного меньше, чем у 'Java'. Но если искать по темам «язык программирования ...» — результат обратный.
При этом у меня, например, в большинстве запросов не встречается 'C++', зато встречается 'Qt', 'Qt5', отдельные классы Qt без упоминания самого Qt и различные другие библиотеки. Я сильно сомневаюсь, что можно реально оценить, какие запросы к какому языку относятся.
Ошибка в метаклассе аналогична ошибке в метафункции, но тут хотя бы можно писать нормальные сообщения времени компиляции. Хуже точно не станет, если только вы не запрещаете использование шаблонны библиотек в своих проектах.
А вот на счет отладки использующего метакласс класса действительно возникает вопрос. Но если метаклассы будут добавлять реализации функций — на этих реализациях можно будет ставить точку останова, как на привычных шаблонных функциях (почему нет?), а добавление новых членов, как в примере с актором, принципиально не отличается от шаблонных аналогов, наподобие std::bind. Да и тот же std::bind на метаклассах, на мой взгляд, можно сделать более отлаживаемым как во время компиляции, так и во время выполнения.
Участвую в разработке довольно большого проекта с использованием qmake (QtCreator), и мечтаю о дне, когда целевая ОС обновится и будет поддерживать CMake 3+. У CMake, конечно, хватает недостатков — но вылезают они в основном при использовании нестандартных инструментов, и решаются путем написания собственных скриптов, ну или поиском на форумах. Справляться с недостатками qmake куда сложнее — в лучшем случае придется наплодить кучу pri-файлов и вручную подключать их во всех дочерних модулях, но и это не всегда помогает. Возможно, «я просто не умею его готовить», но с CMake у меня проблемы возникают реже и решаются быстрее. Правда, в крупных проектах я его пока не использую — возможно, еще передумаю.
Подобный механизм имеет смысл только в случае необходимости нескольких виртуальных методов. std::function как обертка для лямбд на gcc 5.4 часто работает быстрее, чем виртуальные функции.
У spark-shell вроде есть зависимость от Scala, причем определенной версии, а у самого Spark есть зависимость от некоторых частей Hadoop (т.е. надо скачивать пакет с Pre-built for Hadoop 'version'). Я на разных машинах с разными ОС запускал, проблемы с запуском возникли разве что под Windows, там какую то либу от Hadoop надо отдельно скачивать.
А в чём проблема? Мне понадобилось самостоятельно указать только 4 параметра: SPARK_WORKER_MEMORY, SPARK_EXECUTOR_MEMORY, SPARK_DAEMON_MEMORY и SPARK_WORKER_CORES. Работников можно запускать вручную на локальных машинах, если через start_slaves.sh не получается, больше там вроде проблем и нет, разве что еще log4j настроить надо.
«Расстояние между тестовым терминалом и антенной не превышало 5 м». И какой смысл в таком «эксперименте»? Есть простое правило: чем выше частота несущей волны, тем меньше дальность распространения сигнала без потери информации, при прочих равных условиях. Если бы там хотя бы метров 30 было, еще можно было бы о чем-то говорить, а 5 метров в идеальных условиях — это совсем несерьезно.
Судя по исходникам, from возвращает тот же диапазон, но алгоритмы работы с ним жестко зашиты в его методах, и предназначены только для forward-only/input iterators. Концепция Ranges в этом плане более универсальна, ограничения на итераторы задается на уровне алгоритма, а не диапазона. И синтаксис подобный синтаксису из статьи поддерживается: auto res = data | transform([](auto&&){...})
Информация
В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Сравнение происходит вручную, например, при помощи git diff. Вообще, там все довольно минималистично, должно совпасть с точностью до пробелов, но на практике именно в таком виде это не нужно, суть в самой возможности добавления обратной связи.
Если у вас обновление только через pipline - можно использовать migration first, генерировать модель автоматически из временной БД, к которой применилась миграция - и можно быть уверенным, что модель соответствует текущей схеме, а схема текущей миграции, т.к. прод меняется только миграциями. Или можно как и у вас - править модель вручную, по ней генерировать миграции - результат одинаковый, вы всегда можете сгенерировать одно из другого (по крайней мере если придерживаться некоторых правил организации кода).
Если же на проде несколько слабозависимых служб со своими миграциями, или админы вручную что-то меняют - можно выкачать из прода схему, сгенерировать по ней модель (можно фильтровать по именам таблиц), при помощи git посмотреть, что изменилось, что-то может нужно поправить вручную или может откатить - а затем можно сгенерировать миграцию по новым сущностям, и автоматически привести тестовую среду в к соответвию как модели, так и проду.
Единственное, я пока не уверен, насколько надежно генерируются миграции по модели - seaorm 2 еще не релизнулся, эта возмодность на уровне обзоров. Но вы как раз демонстрируете, что этот подход работает хорошо, а генерация модели по схеме БД в seaorm изначально хорошо работает.
Мне в этом плане понравился подход, который сейчас внедряется в seaorm 2. Изначально там был подход migration first - миграции пишутся отдельно на специальном dsl, затем применяются к БД, и из живой БД генерируются сущности, используемые для запросов. Расхождения кода с БД устраняется уже на этом этапе, но далее добавляется обратная связь: вручную меняем сгенерированные сущности, по ним автоматически генерируется новая миграция. Ну и для корректности можно применить миграцию к БД, сгенерировать из нее сущности, до этого написанные вручную, и убедиться, что все совпало.
Не понимаю, почему постоянно идут разговоры про тупую рефлексию (а на деле даже не про рефлексию, а про интроспекцию, т.к. рефлексия позволяет кодогенерациию в рантайие). Рефлексия и интроспекцич позволяет работать только со стандартными языковыми конструкциями. Для реальных задач этого недостаточно. Нужна возможность описать и исследовать структуру данных в форме, специфичной для задачи. Обычно это означает, что нужно описать не только тип и список его членов, но и некоторые дополнительные атрибуты этих членов, и, возможно, типов. Например, для задачи сериализации нужна возможность описать полиморфные типы, как-то их перечислить, и указать, в какое поле записывать имя полиморфного типа. Для сериализации в xml нужно различать атрибуты и теги, для сериализации массивов зачастую нужно указывать разные теги для самого массива и элементов массива. Для бинарной сериализации иногда нужно явно указывать порядок байт для конкретного члена, хотя обычно это можно сделать за счёт выбора нужного сериализатора.
В то же время самому языку программирования эти атрибуты не нужны, поэтому для описания атрибутов нужна какая-то кодогенерация, в виде макросов или ещё чего-то. В случае c++ полноценным решение будут метоклассы, но и без них можно реализовать более полезные способы описания структур, чем указаны в статье.
Есть что-то вроде u64::from_be_bytes и from_le_bytes, и обратно. Там проблема только с размером, для оптимизации нужно assert расставлять. Ссылка не нужна, компилятор сам оптимизирует чтение и запись, заодно решая проблему выравнивания, вылезающую в случае unsafe.
Не уверен, как работает mimalloc, но использование пулов фиксированного размера в аллокаторе общего назначения не кажется логичным, т.к. увеличение количества пулов приведет у замедлению поиска нужного пула. Впрочем, в эффективности подхода автора я также сомневаюсь, так как используется по сути такое же общее состояние. Но в таком случае хотя бы общим состоянием будут пользоваться более ограниченное количество объектов.
Сообщество все ещё рекомендует писать frontend при помощи web-фрейморков, backend на Rust. При таком подходе можно и в редакторе формочки рисовать.
Если хотите чистый Rust - смотрите https://areweguiyet.com/ . Пока что ситуация с gui не радует, о редакторах форм речи даже не идёт. Разве что можно попробовать поискать привязки к библиотекам на других языках.
Большинство gui фреймворков не имеют интеграции с async/await и т.п, а разработчики асинхронных экосистем редко думают о gui.
Я недавно экспериментировал с волокнами (fibers) на c++ и qt. Получилось довольно интересно: в потоке gui можно использовать асинхронные каналы, мьютексы, future и promise, что позволяет явно написать алгоритм вида: "заблокировать кнопку перехода на следующую страницу" - "асинхронно загрузить страницу, в процессе выполняя асинхронные сетевые запросы" - "разблокировать кнопку перехода на следующую станицу". Это действительно удобно, но есть одна проблема: при нажатии кнопки "завершить программу", она не завершается. В асинхронных экосистемах механизма отмены обычно либо нет, либо он слишком неудобен, чтобы считать асинхронный код простым. Конечно, можно найти/написать свой планировщик, более подходящий для gui, но для этого как минимум нужно знать и понимать, какие проблемы он должен решать, какие решить не может, и учитывать нюансы вроде удаления вложенных виджетов при удалении родительского в qt. Простой frontend разработчик обычно это сделать не сможет, по крайней мере так, чтобы код оставался понятным. Нужна согласованная экосистема.
Если я вас правильно понял, проблема с указателями решаема, https://github.com/Ariox41/tmdesc . Интерфейс указатели не даёт, но технически вытащить можно. Все constexpr
При этом у меня, например, в большинстве запросов не встречается 'C++', зато встречается 'Qt', 'Qt5', отдельные классы Qt без упоминания самого Qt и различные другие библиотеки. Я сильно сомневаюсь, что можно реально оценить, какие запросы к какому языку относятся.
А вот на счет отладки использующего метакласс класса действительно возникает вопрос. Но если метаклассы будут добавлять реализации функций — на этих реализациях можно будет ставить точку останова, как на привычных шаблонных функциях (почему нет?), а добавление новых членов, как в примере с актором, принципиально не отличается от шаблонных аналогов, наподобие std::bind. Да и тот же std::bind на метаклассах, на мой взгляд, можно сделать более отлаживаемым как во время компиляции, так и во время выполнения.