Выше дан код C++. Какой вывод будет у программы?
Anonymous Quiz
29%
1 4 5 7 9
33%
1 5 7 9
14%
1 4 7 9
24%
Неопределенное поведение
Как не утонуть в правках. Git-стратегия для сложных задач с риском откатов
Ситуация: пилите большую фичу, написали много кода и вдруг замечаете, что сломали то, что час назад работало. Что случилось, почему? Открываете git diff, а там правки не за последний час, а за последний день... Где была допущена ошибка? Начинаем вспоминать, запускаем отладчик и забываем про текущую работу.
🔸 Как не доводить до такой ситуации?
Правильно - чаще коммитить. Но как коммитить то, что еще не готово? Коммит же должен быть завершенным!
Решение есть у нас: промежуточные коммиты.
Мы просто коммитим все, что хотим и когда хотим, а по окончании работ "схлопываем" промежуточные коммиты в один, используя interactive rebase.
Промежуточные коммиты оформляются с префиксом WIP (от Work In Progress), чтобы потом их не пропустить. В git log получается примерно так:
🔸 Когда делать промежуточный коммит?
Я руководствуюсь общим правилом: если мой следующий шаг приведет к правкам незакоммиченного кода, я делаю промежуточный коммит. У меня должна быть возможность быстро понять, где допущена ошибка, и откатиться.
Обычно такие коммиты случаются:
- при фиксировании логически завершенных правок,
- перед любым рефакторингом,
- в конце дня.
А чтобы вам проще было разобраться с подходом, я записал небольшое практическое видео. На простом примере показал как промежуточные коммиты помогают локализовать ошибку и как потом "схлопнуть" эти коммиты в один через interactive rebase. Ссылки здесь ⤵️
📱 Смотреть на YouTube
📱 Смотреть во ВКонтакте
#Troubleshooting
Ситуация: пилите большую фичу, написали много кода и вдруг замечаете, что сломали то, что час назад работало. Что случилось, почему? Открываете git diff, а там правки не за последний час, а за последний день... Где была допущена ошибка? Начинаем вспоминать, запускаем отладчик и забываем про текущую работу.
🔸 Как не доводить до такой ситуации?
Правильно - чаще коммитить. Но как коммитить то, что еще не готово? Коммит же должен быть завершенным!
Решение есть у нас: промежуточные коммиты.
Мы просто коммитим все, что хотим и когда хотим, а по окончании работ "схлопываем" промежуточные коммиты в один, используя interactive rebase.
Промежуточные коммиты оформляются с префиксом WIP (от Work In Progress), чтобы потом их не пропустить. В git log получается примерно так:
WIP: что-то сделал
WIP: еще что-то сделал
WIP: убрал кое-чего
WIP: зарефакторил то-то
🔸 Когда делать промежуточный коммит?
Я руководствуюсь общим правилом: если мой следующий шаг приведет к правкам незакоммиченного кода, я делаю промежуточный коммит. У меня должна быть возможность быстро понять, где допущена ошибка, и откатиться.
Обычно такие коммиты случаются:
- при фиксировании логически завершенных правок,
- перед любым рефакторингом,
- в конце дня.
А чтобы вам проще было разобраться с подходом, я записал небольшое практическое видео. На простом примере показал как промежуточные коммиты помогают локализовать ошибку и как потом "схлопнуть" эти коммиты в один через interactive rebase. Ссылки здесь ⤵️
#Troubleshooting
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
YouTube Analyzer 5.0
Мы выпустили новую версию YouTube Analyzer - анализатора поисковой выдачи YouTube на Python / PySide6 (Qt).
Из интересного в коде по сравнению с предыдущей версией:
🔜 Добавлены рабочие пространства. Теперь можно открыть неограниченное количество пространств во вкладках и работать одновременно с поиском, трендами и пр. Под капотом стандартные QTabWidget.
🔜 Реализована система плагинирования. Разные типы рабочих вкладок могут быть загружены из плагинов. Например, сейчас так работает autocomplete_plugin.
🔜 Добавлена галерея превью (на скрине). Ютуб-менеджеры используют ее для выявления трендов в превью видео. Реализовано на QListView с включенным режимом
—
YouTube Analyzer - это desktop-приложение, написанное на Python / PySide (Qt).
Его решения можно использовать как шаблон для своих приложений на Python / PySide или на C++ / Qt.
Мы выпустили новую версию YouTube Analyzer - анализатора поисковой выдачи YouTube на Python / PySide6 (Qt).
Из интересного в коде по сравнению с предыдущей версией:
QListView.ViewMode.IconMode.—
YouTube Analyzer - это desktop-приложение, написанное на Python / PySide (Qt).
Его решения можно использовать как шаблон для своих приложений на Python / PySide или на C++ / Qt.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
#include <iostream>
void foo(int a, int b) {
std::cout << a << " " << b;
}
int main() {
int count = 0;
foo(++count, ++count);
return 0;
}
Выше дан код C++. Какой вывод будет у программы?
Anonymous Quiz
63%
1 2
8%
2 1
8%
0 1
21%
Неопределенное поведение
🤯2
Корректное или принудительное завершение работы
Сегодня речь пойдет о завершении работы программы.
Корректное завершение (graceful shutdown) — это когда система закрывается правильно. То есть сохраняет все данные, освобождает ресурсы, завершает процессы в правильном порядке.
Принудительное завершение (hard shutdown) — это резкое закрытие процесса, минуя стандартную процедуру. Словно вызвали "
На практике не стоит забывать, что программа может завершиться неправильно. Но повторный запуск при этом не должен быть нарушен. Может остаться какой-то мусор, незакрытые соединения, битые файлы. Нам это все нужно "переварить", корректно запуститься и восстановить целостность данных.
Вот так все просто на словах 😊
—
Ранее в сериале #Словарь : Синтаксис или семантика
Сегодня речь пойдет о завершении работы программы.
Корректное завершение (graceful shutdown) — это когда система закрывается правильно. То есть сохраняет все данные, освобождает ресурсы, завершает процессы в правильном порядке.
Принудительное завершение (hard shutdown) — это резкое закрытие процесса, минуя стандартную процедуру. Словно вызвали "
kill -9" или выдернули шнур из розетки.На практике не стоит забывать, что программа может завершиться неправильно. Но повторный запуск при этом не должен быть нарушен. Может остаться какой-то мусор, незакрытые соединения, битые файлы. Нам это все нужно "переварить", корректно запуститься и восстановить целостность данных.
Вот так все просто на словах 😊
—
Ранее в сериале #Словарь : Синтаксис или семантика
🔥2
Luanti. Хранение карты в опенсорсном Minecraft
Luanti - это опенсорсный аналог Minecraft, написанный на C++. Мощный проект, к которому можно заглянуть под капот ⤵️
Мне в первую очередь было интересно как хранятся данные мира. Ведь мир свободный и большой. Казалось, простых решений тут быть не может. Но на самом деле решение довольно элегантное.
🔸 Какая структура данных?
В Luanti данные мира хранятся в единственной базе данных SQLite в единственной таблице blocks:
Каждая строка таблицы - это чанк (множество блоков) размером 16х16х16 блоков. Информация о состоянии каждого из 4096 блоков чанка хранится в специальной структуре в поле
🔸 Как и когда данные записываются в базу?
Мир в Luanti генерируется динамически по мере его исследования игроком. Каждый сгенерированный чанк сразу же сохраняется в базу данных. Это нужно для поддержания целостности мира, чтобы при следующей загрузке он выглядел так же. При изменении мира игроком сохранение в базу данных происходит с задержкой через определенный интервал времени. Оптимизация, куда без неё 🙂
🔸 Как и когда данные читаются из базы?
Чтение мира из базы данных тоже выполняется чанками. Если чанк существует в базе, то он загружается, если нет - генерируется. При движении игрока по миру чанки автоматически подгружаются или генерируются.
🔸 Изменение структуры данных в 2025 году
Начиная с версии 5.12, координаты чанков хранятся в отдельных полях
Свое решение разработчики объясняют упрощением запроса чанков по координатам, а также уходом от сложной логики свертки координат. Кому интересно, вот этот пулл-реквест.
—
В перспективе сделаю еще посты с занимательными решениями из опенсорса. Предыдущий был про условное логгирование в quagga (почти 2 года назад 😳) #ЖизньДругих
Luanti - это опенсорсный аналог Minecraft, написанный на C++. Мощный проект, к которому можно заглянуть под капот ⤵️
Кто не в курсе, Minecraft (и Luanti) - это компьютерная игра с открытым миром из кубических блоков, где можно свободно строить свои миры.
Мне в первую очередь было интересно как хранятся данные мира. Ведь мир свободный и большой. Казалось, простых решений тут быть не может. Но на самом деле решение довольно элегантное.
🔸 Какая структура данных?
В Luanti данные мира хранятся в единственной базе данных SQLite в единственной таблице blocks:
CREATE TABLE "blocks" (
"pos" INT NOT NULL PRIMARY KEY,
"data" BLOB);
Каждая строка таблицы - это чанк (множество блоков) размером 16х16х16 блоков. Информация о состоянии каждого из 4096 блоков чанка хранится в специальной структуре в поле
data. А поле pos хранит свёртку координат x, y, z, определяющих положение данного чанка в пространстве.🔸 Как и когда данные записываются в базу?
Мир в Luanti генерируется динамически по мере его исследования игроком. Каждый сгенерированный чанк сразу же сохраняется в базу данных. Это нужно для поддержания целостности мира, чтобы при следующей загрузке он выглядел так же. При изменении мира игроком сохранение в базу данных происходит с задержкой через определенный интервал времени. Оптимизация, куда без неё 🙂
🔸 Как и когда данные читаются из базы?
Чтение мира из базы данных тоже выполняется чанками. Если чанк существует в базе, то он загружается, если нет - генерируется. При движении игрока по миру чанки автоматически подгружаются или генерируются.
🔸 Изменение структуры данных в 2025 году
Начиная с версии 5.12, координаты чанков хранятся в отдельных полях
x, y, z таблицы blocks. От свертки координат pos отказались:CREATE TABLE "blocks" (
"x" INTEGER, "y" INTEGER, "z" INTEGER,
"data" BLOB NOT NULL,
PRIMARY KEY ("x", "z", "y")
);
Свое решение разработчики объясняют упрощением запроса чанков по координатам, а также уходом от сложной логики свертки координат. Кому интересно, вот этот пулл-реквест.
—
В перспективе сделаю еще посты с занимательными решениями из опенсорса. Предыдущий был про условное логгирование в quagga (почти 2 года назад 😳) #ЖизньДругих
🔥2👏1
#include <iostream>
int main() {
constexpr int a = 3 - 2;
switch (a) {
case 1:
std::cout << "1";
case 2:
std::cout << "2";
break;
case 3:
std::cout << "3";
break;
default:
std::cout << "0";
}
return 0;
}
Без права на ошибку
Жутко не люблю сверлить отверстия в стенах. Просверлил не там, ошибся, и уже не отменишь.
Недавно мне нужно было повесить тумбочку на стене в определенном месте. Дело осложнялось потайными креплениями. Нужно было точно вымерить место креплений, просверлить отверстия, установить крепеж и только после этого повесить тумбочку.
Вот уж воистину "семь раз отмерь, один раз отрежь".
Ошибаться нельзя: стены чистовые, на виду. Мне повезло, я не ошибся. Но дискомфорт, который возник при этом, меня удивил.
🔽
Получается, что работа программиста приучила меня к мысли, что ошибаться можно? Да, ошибаться можно - исправим. Не сработало - починим. Все можно отменить, все можно быстро переделать.
Конечно, я говорю о коде, о низком уровне. Гораздо "больнее" ошибаться в проекте, в задании, в требованиях, в цели. Чем выше уровень, тем больше это похоже на сверление отверстия в стене.
Да, и неправильное отверстие можно заделать, и требования исправить. Только какой ценой?
Но как же хорошо иметь право на ошибку! Как же хорошо!
Жутко не люблю сверлить отверстия в стенах. Просверлил не там, ошибся, и уже не отменишь.
Недавно мне нужно было повесить тумбочку на стене в определенном месте. Дело осложнялось потайными креплениями. Нужно было точно вымерить место креплений, просверлить отверстия, установить крепеж и только после этого повесить тумбочку.
Вот уж воистину "семь раз отмерь, один раз отрежь".
Ошибаться нельзя: стены чистовые, на виду. Мне повезло, я не ошибся. Но дискомфорт, который возник при этом, меня удивил.
🔽
Получается, что работа программиста приучила меня к мысли, что ошибаться можно? Да, ошибаться можно - исправим. Не сработало - починим. Все можно отменить, все можно быстро переделать.
Конечно, я говорю о коде, о низком уровне. Гораздо "больнее" ошибаться в проекте, в задании, в требованиях, в цели. Чем выше уровень, тем больше это похоже на сверление отверстия в стене.
Да, и неправильное отверстие можно заделать, и требования исправить. Только какой ценой?
Но как же хорошо иметь право на ошибку! Как же хорошо!
👍2👏2
Немного не обычно, но зато всем подходит 😊⤵️
не (A или B или C)
(не A) и (не B) и (не C)
Равны ли два логических выражения выше (дают одинаковый результат)?
Anonymous Quiz
56%
Равны
44%
Не равны
Базы данных в Obsidian
Уже год как я мигрировал с Notion в Obsidian. Не сказать, что я полностью адаптировался. Многое пришлось переосмыслить.
⛔️ Одна из фишек Notion, от которой пришлось отвыкать - это таблицы.
Да, в Obsidian есть dataview - мощный инструмент для представления заметок в виде таблиц. Но в нем не хватает интерактивности.
С интерактивностью помог плагин Projects. Но он очень глючный, тормозит на больших представлениях, приводил к проблемам, да и больше не поддерживается. Пришлось от него отказаться.
А вместе с Projects отказаться и от интерактивных таблиц.
✅ И тут с последним обновлением в Obsidian появляется встроенный модуль Bases (на скрине).
Ух и вау! Таблицы! Наглядные как в dataview и интерактивные как в Notion.
Ну где они были раньше!
На первый взгляд - удобно! Большие представления работают плавно, есть гибкие настройки фильтров.
Короче, осваиваю и очень активно, так как в августе во всю веду подготовку заданий на семинар к новому учебному году 🎓
Уже год как я мигрировал с Notion в Obsidian. Не сказать, что я полностью адаптировался. Многое пришлось переосмыслить.
⛔️ Одна из фишек Notion, от которой пришлось отвыкать - это таблицы.
Да, в Obsidian есть dataview - мощный инструмент для представления заметок в виде таблиц. Но в нем не хватает интерактивности.
С интерактивностью помог плагин Projects. Но он очень глючный, тормозит на больших представлениях, приводил к проблемам, да и больше не поддерживается. Пришлось от него отказаться.
А вместе с Projects отказаться и от интерактивных таблиц.
✅ И тут с последним обновлением в Obsidian появляется встроенный модуль Bases (на скрине).
Ух и вау! Таблицы! Наглядные как в dataview и интерактивные как в Notion.
Ну где они были раньше!
На первый взгляд - удобно! Большие представления работают плавно, есть гибкие настройки фильтров.
Короче, осваиваю и очень активно, так как в августе во всю веду подготовку заданий на семинар к новому учебному году 🎓
👍4
С предыдущим тестом отдохнули и снова во все тяжкие ⤵️😟
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec { 1, 2, 3, 4, 5, 6 };
for (auto i = vec.size() - 1; i >= 0; --i) {
std::cout << vec[i] << ' ';
}
return 0;
}
Выше дан код C++. Какой вывод будет у программы?
Anonymous Quiz
9%
Никакой
41%
6 5 4 3 2 1
23%
5 4 3 2 1
27%
Неопределенное поведение
Разделители разрядов в C++
Чтобы нам было проще воспринимать большие числовые константы, в C++ существуют разделители разрядов (digit separators).
С ними непонятно число
превращается в понятные сто тысяч!
✅ В качестве разделителя используется символ одинарной кавычки (
Смотрите, как получается:
Но есть пара ограничений:
⛔️ разделитель не может стоять в начале или конце числа:
⛔️ разделитель не может стоять после точки:
Разделители разрядов доступны, начиная с C++14. До этого читаемость констант улучшали разными способами. Например, я использовал:
- научный вариант записи, вроде
- выражения, вроде
Честно говоря, я в своей практике не помню, чтобы использовал разделители. Последнее время не попадалось задач, где бы пришлось заводить большие константы.
—
А вы использовали разделители?
🔥 - ага
🤷♂️ - не доводилось
😁 - ох уж этот ваш C++
Чтобы нам было проще воспринимать большие числовые константы, в C++ существуют разделители разрядов (digit separators).
С ними непонятно число
long a = 100000;
превращается в понятные сто тысяч!
long a = 100'000;
✅ В качестве разделителя используется символ одинарной кавычки (
'). Мы сами можем выбирать, где ставить разделитель и на сколько разрядов делить число. Компилятор все равно разделители не учитывает.Смотрите, как получается:
int a = 122'302;
long b = 10'823'013'000;
double pi = 3.141'592'6535;
uint8_t mask = 0b1010'1101;
uint32_t transparent_red = 0x80'FF'00'00;
Но есть пара ограничений:
⛔️ разделитель не может стоять в начале или конце числа:
'100, 10'⛔️ разделитель не может стоять после точки:
1.'003Разделители разрядов доступны, начиная с C++14. До этого читаемость констант улучшали разными способами. Например, я использовал:
- научный вариант записи, вроде
1e-5- выражения, вроде
10 * 1000 * 1000 (что скорее экзотика).Честно говоря, я в своей практике не помню, чтобы использовал разделители. Последнее время не попадалось задач, где бы пришлось заводить большие константы.
—
А вы использовали разделители?
🔥 - ага
🤷♂️ - не доводилось
😁 - ох уж этот ваш C++
🤷♂3😁2👍1🔥1
Кто считается автором языка C?
Anonymous Quiz
62%
Бьёрн Страуструп
24%
Деннис Ритчи
14%
Райан Гослинг
0%
Стив Джобс
🔼 Кстати, продолжая тему истории программирования, напоминаю про серию тестов по датам создания языков программирования.
Отличная возможность освежить знания)
Отличная возможность освежить знания)
Media is too big
VIEW IN TELEGRAM
Объединение коммитов в TortoiseGit
В последнем видео про WIP-коммиты я рассказывал, что коммиты можно объединять с помощью операции rebase. Но оказывается, что в TortoiseGit есть более простой способ.
В логе коммитов есть пункт меню "Combine to one commit", который объединяет выделенные коммиты, позволяя отредактировать сообщение.
Подробнее смотрите в коротком видео ⤵️
📱 Смотреть на YouTube
📱 Смотреть в VKVideo
—
Как вам формат вертикальных видео?
Мне кажется неплохо. Но какая же запара впихнуть горизонтальный экран в вертикальный ролик 😅
В последнем видео про WIP-коммиты я рассказывал, что коммиты можно объединять с помощью операции rebase. Но оказывается, что в TortoiseGit есть более простой способ.
В логе коммитов есть пункт меню "Combine to one commit", который объединяет выделенные коммиты, позволяя отредактировать сообщение.
Подробнее смотрите в коротком видео ⤵️
—
Как вам формат вертикальных видео?
Мне кажется неплохо. Но какая же запара впихнуть горизонтальный экран в вертикальный ролик 😅
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4