Troubleshooting. Метод деления пополам
Продолжаю серию постов по траблшутингу. Сегодня поговорим про локализацию проблемы методом деления пополам.
Метод деления пополам используется, например, в электротехнике⚡️ для поиска обрыва в цепи. Для этого участок цепи визуально разбивается пополам и каждая половина проверяется на предмет наличия тока. Та половина, в которой тока нет, считается содержащей обрыв. Она в свою очередь снова разбивается пополам и половинки снова проверяются. Так продолжается до тех пор, пока мы не придём к проблемному месту.
А мы придём к нему в общем случае быстрее, чем если бы последовательно проверяли цепь по маленьким "кусочкам".
Вот такой итерационный метод можно использовать и при отладке программ.
Представим, что у нас в программе есть ошибка из-за дефектных данных в некоторой переменной. По-моему не сложно представить 😅
Наша задача состоит в том, чтобы найти в коде место, где данные становятся дефектными, то есть локализовать проблему:
1️⃣ Для начала выбираем большой участок программы от ее старта до места проявления ошибки. Мы уверены, что в начале выполнения программы наши данные корректные.
2️⃣ Теперь визуально делим выбранный участок программы пополам и проверяем корректность данных в месте разделения. Если данные корректные, то выбираем следующий по ходу участок программы. Если данные не корректные, то - предыдущий.
3️⃣ Продолжаем пункт 2 до тех пор, пока не "спустимся" к источнику проблемы.
Кстати, таким же методом можно искать ошибки не только по процессу выполнения программы, но и по истории коммитов.
Для этого нужно знать коммит, на котором проблемы еще не было, и коммит, на котором проблема была обнаружена. Тогда путем деления истории коммитов пополам можно быстро найти коммит, который занёс в код ошибку. В git, например, этот метод реализуется командой git bisect. Почитайте, если ещё не слышали.
#Troubleshooting
Продолжаю серию постов по траблшутингу. Сегодня поговорим про локализацию проблемы методом деления пополам.
Метод деления пополам используется, например, в электротехнике
А мы придём к нему в общем случае быстрее, чем если бы последовательно проверяли цепь по маленьким "кусочкам".
Вот такой итерационный метод можно использовать и при отладке программ.
Представим, что у нас в программе есть ошибка из-за дефектных данных в некоторой переменной. По-моему не сложно представить 😅
Наша задача состоит в том, чтобы найти в коде место, где данные становятся дефектными, то есть локализовать проблему:
Кстати, таким же методом можно искать ошибки не только по процессу выполнения программы, но и по истории коммитов.
Для этого нужно знать коммит, на котором проблемы еще не было, и коммит, на котором проблема была обнаружена. Тогда путем деления истории коммитов пополам можно быстро найти коммит, который занёс в код ошибку. В git, например, этот метод реализуется командой git bisect. Почитайте, если ещё не слышали.
#Troubleshooting
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Что такое инкапсуляция в терминах ООП?
Anonymous Quiz
16%
Реализация иерархии "родитель-потомок"
73%
Изоляция абстракции от её реализации
5%
Создание множества конструкторов одного типа
5%
Реализация разных форм одного типа
Zip-бомба и Qt Network
Zip-бомба - это архив, распаковка которого может вызвать нарушения в работе системы🥶
Как правило такой архив выглядит очень маленьким, но распаковывается в нечто огромное, заполняющее все свободное пространство в памяти или на носителе. Создается архив либо многократным архивированием данных, либо однократным, но с применением сильного сжатия.
Давайте проверим, что случится, если такой архив получит QNetworkAccessManager из модуля Qt Network. Есть ли там какая-то защита?
Так в действительности и происходит. Но в случае с zip-бомбой есть и хорошие новости. Многократно запакованный архив
А вот архив с сильным сжатием ожидаемо будет распакован.
В эксперименте архив размером 1,2Мб, содержащий 1,2Гб данных, был распакован
Такие пироги. Если Qt Network работает по незащищенному протоколу, то такой тип атаки можно ожидать. С защищенным протоколом (HTTPS) вероятность гораздо ниже.
Если интересно как еще проверить свою систему на прочность, читайте пост про выполнение DOS-атаки.
Zip-бомба - это архив, распаковка которого может вызвать нарушения в работе системы
Как правило такой архив выглядит очень маленьким, но распаковывается в нечто огромное, заполняющее все свободное пространство в памяти или на носителе. Создается архив либо многократным архивированием данных, либо однократным, но с применением сильного сжатия.
Давайте проверим, что случится, если такой архив получит QNetworkAccessManager из модуля Qt Network. Есть ли там какая-то защита?
QNetworkAccessManager умеет работать с HTTP-запросами и ответами. И если в HTTP-заголовке ответного сообщения будет установлено поле Content-Encoding: gzip, то QNetworkAccessManager должен автоматически разархивировать полученные данные.Так в действительности и происходит. Но в случае с zip-бомбой есть и хорошие новости. Многократно запакованный архив
QNetworkAccessManager распаковывает только один раз, рекурсивной процедуры там нет. По крайней мере в Qt5. Значит такого типа zip-бомб можно не опасаться.А вот архив с сильным сжатием ожидаемо будет распакован.
В эксперименте архив размером 1,2Мб, содержащий 1,2Гб данных, был распакован
QNetworkAccessManager-ом за несколько минут с потреблением в пике до 2,4Гб оперативки. Как минимум, это может привести к фризам приложения в процессе распаковки, а при определенных условиях и к падению.Такие пироги. Если Qt Network работает по незащищенному протоколу, то такой тип атаки можно ожидать. С защищенным протоколом (HTTPS) вероятность гораздо ниже.
Если интересно как еще проверить свою систему на прочность, читайте пост про выполнение DOS-атаки.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
За какое время выполнится код выше? Дайте ответ в О-нотации
Anonymous Quiz
12%
O( 1 )
69%
O( n )
8%
O( lg n )
12%
O( n * n )
Антипаттерны SQL: обязательный столбец ID
У меня отношения с базами данных (БД) примерно такие же как с английским: вроде бы нормально дружим, пока не попадется что-то серьёзнее Шерлока Холмса в оригинале. В теории все понятно, но нет-нет да и выкину что-нибудь эдакое.
И в этот раз при работе со схемой БД я заметил, что по умолчанию добавляю поле "ID" в каждую таблицу 🤔
Просто потому что, без оснований. По традиции что ли...
Так себе, да?
Да. И у этого есть название.
Я пал жертвой антипаттерна "ID required", вляпавшись в два его признака:
1️⃣ Несколько таблиц в моей БД безосновательно получили поле "ID" в качестве первичного ключа, хотя у каждой из этих таблиц уже было поле, которое могло бы им стать. Тем самым появилась избыточность данных.
2️⃣ Имя "ID" очень абстрактное, ни о чем не говорящее само по себе. Гораздо лучше было использовать не "ID", а какой-нибудь условный "ENTITY_ID".
Таким образом, после удаления поля "ID" и назначения первичным ключом другого подходящего поля, замысел созданной мной сущности и ее связей никак не изменился. Что хотел, то и получил.
Из самого описания антипаттерна "ID required" мне понравилась эта фраза:
То есть антипаттерн не говорит, что поле "ID" - это плохо, а только лишь указывает, что оно не обязательно.
📍 Karwin B - SQL antipatterns. Avoiding the pitfalls of database (2010)
У меня отношения с базами данных (БД) примерно такие же как с английским: вроде бы нормально дружим, пока не попадется что-то серьёзнее Шерлока Холмса в оригинале. В теории все понятно, но нет-нет да и выкину что-нибудь эдакое.
И в этот раз при работе со схемой БД я заметил, что по умолчанию добавляю поле "ID" в каждую таблицу 🤔
Просто потому что, без оснований. По традиции что ли...
Так себе, да?
Да. И у этого есть название.
Я пал жертвой антипаттерна "ID required", вляпавшись в два его признака:
Таким образом, после удаления поля "ID" и назначения первичным ключом другого подходящего поля, замысел созданной мной сущности и ее связей никак не изменился. Что хотел, то и получил.
Из самого описания антипаттерна "ID required" мне понравилась эта фраза:
If your table contains an attribute that’s guaranteed to be unique, is non-null, and can serve to identify the row, don’t feel obligated to add a pseudokey solely for the sake of tradition.
То есть антипаттерн не говорит, что поле "ID" - это плохо, а только лишь указывает, что оно не обязательно.
📍 Karwin B - SQL antipatterns. Avoiding the pitfalls of database (2010)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🔥1
Как расшифровывается аббревиатура принципа проектирования KISS?
Anonymous Quiz
7%
Keep intensive system solution
30%
Key interaction system solution
13%
Kind intelligence support system
50%
Keep it simple, stupid!
Как расшифровывается аббревиатура принципа проектирования DRY?
Anonymous Quiz
75%
Don't repeat yourself
4%
Don't read yourself
14%
Don't reply yes
7%
Don't rest yearly
Как расшифровывается аббревиатура принципа проектирования YAGNI?
Anonymous Quiz
14%
You able grant null indicator
21%
You able get null indicator
21%
Your architecture gives nothing interesting
43%
You ain’t gonna need it
В этот раз у нас серия из трех тестов! Аббревиатуры!
Я даже устал придумывать неправильные варианты) Вот здесь бы наверно нейросетка помогла. Или нет?
🔥 - если на все ответили правильно
🤓 - если попали в 1 - 2
🤷♂️ - если все мимо
Я даже устал придумывать неправильные варианты) Вот здесь бы наверно нейросетка помогла. Или нет?
🔥 - если на все ответили правильно
🤓 - если попали в 1 - 2
🤷♂️ - если все мимо
🔥7🤓6🤷♂4
Troubleshooting. Логирование
Если коротко: никогда не пренебрегайте логированием. Чем адекватнее логи, тем проще заниматься траблшутингом.
Что значит "адекватные логи"? Вообще термин "адекватность" относится к моделированию и означает совпадение свойств модели и моделируемого объекта. Так вот если принять процесс работы программы за моделируемый объект, а его логи за модель, то все становится понятно.
Как распознать неадекватные логи? Здесь надо исходить из основной функциональности или бизнес-логики программы. Если выполнение основной функциональности не попало в логи, то считаем адекватность логов слабой. Например, в случае с текстовым редактором основной функциональностью может быть открытие документа, и отсутствие записи об этом в логах осложнит восстановление общей картины процесса.
Отдельное внимание стоит уделить логированию ошибок. Здесь часто присутствует скудное описание, недосказанность. И если некоторые технологии обеспечивают нас трассировкой стека, что очень выручает, то в том же C++ о выводе подробностей ошибки надо заботиться самостоятельно. Ну встречали же такое: "File open error". И думай, что за файл, какой такой "error"? Никуда не годится. Хотя вся нужная информация есть, просто нам её не показали.
Ещё во время траблшутинга используют избыточное логирование. Это когда логируется чуть ли не каждая строка кода, что помогает разобраться с проблемой. Потом эти логи убираются. Хотя с этим лучше не спешить, а подумать, какие именно записи помогли нам, и, возможно, оставить их в логах навсегда. Некоторые ошибки имеют свойство повторяться со временем.
Логи - это "черный ящик", который мы получаем от пользователя в случае "аварии". От их качества нередко зависит успех операции)
Какие еще знаете и используете практики логирования?
Делитесь 👇
#Troubleshooting
Если коротко: никогда не пренебрегайте логированием. Чем адекватнее логи, тем проще заниматься траблшутингом.
Что значит "адекватные логи"? Вообще термин "адекватность" относится к моделированию и означает совпадение свойств модели и моделируемого объекта. Так вот если принять процесс работы программы за моделируемый объект, а его логи за модель, то все становится понятно.
Как распознать неадекватные логи? Здесь надо исходить из основной функциональности или бизнес-логики программы. Если выполнение основной функциональности не попало в логи, то считаем адекватность логов слабой. Например, в случае с текстовым редактором основной функциональностью может быть открытие документа, и отсутствие записи об этом в логах осложнит восстановление общей картины процесса.
Отдельное внимание стоит уделить логированию ошибок. Здесь часто присутствует скудное описание, недосказанность. И если некоторые технологии обеспечивают нас трассировкой стека, что очень выручает, то в том же C++ о выводе подробностей ошибки надо заботиться самостоятельно. Ну встречали же такое: "File open error". И думай, что за файл, какой такой "error"? Никуда не годится. Хотя вся нужная информация есть, просто нам её не показали.
Ещё во время траблшутинга используют избыточное логирование. Это когда логируется чуть ли не каждая строка кода, что помогает разобраться с проблемой. Потом эти логи убираются. Хотя с этим лучше не спешить, а подумать, какие именно записи помогли нам, и, возможно, оставить их в логах навсегда. Некоторые ошибки имеют свойство повторяться со временем.
Логи - это "черный ящик", который мы получаем от пользователя в случае "аварии". От их качества нередко зависит успех операции)
Какие еще знаете и используете практики логирования?
Делитесь 👇
#Troubleshooting
🔥3
Как исследовать exe-файлы с Cutter. Практика обратной разработки
Раз был проявлен интерес к обратной разработке, публикую небольшую статью ⬇️, которая рассказывает на практическом примере как исследуются и патчатся exe-файлы. Подходит для новичков.
Знания по обратной разработке необходимы разработчику для развития навыков построения относительно устойчивого ко взлому софта. Понимание таких практик позволит не допускать элементарных ошибок.
https://mediocre-developer.ru/kak-issledovat-exe-fajly-s-cutter-praktika-obratnoj-razrabotki
Раз был проявлен интерес к обратной разработке, публикую небольшую статью ⬇️, которая рассказывает на практическом примере как исследуются и патчатся exe-файлы. Подходит для новичков.
Знания по обратной разработке необходимы разработчику для развития навыков построения относительно устойчивого ко взлому софта. Понимание таких практик позволит не допускать элементарных ошибок.
https://mediocre-developer.ru/kak-issledovat-exe-fajly-s-cutter-praktika-obratnoj-razrabotki
🔥3
Выше дан код на C++. Что такое argc и argv?
Anonymous Quiz
85%
argc - количество аргументов командной строки, argv - массив этих аргументов
0%
argc - PID процесса, argv - имя файла программы
6%
argc - количество аргументов командной строки, argv - имя файла программы
9%
argc - PID процесса, argv - полный путь к файлу программы
Предлагаю отметить лишний рабочий день расслабляющей угадайкой! 🎉
Знаете, что это на картинке?
Определённо что-то из прошлого.
Ответ под спойлером:
Это перфокарты для электровикторины на знания правил дорожного движения. Фото прибора для считывания перфокарт скину в комменты.
🔥 - угадали
🤷♂️ - не угадали
Знаете, что это на картинке?
Определённо что-то из прошлого.
Ответ под спойлером:
🔥 - угадали
🤷♂️ - не угадали
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🤷♂2
Законы оптимизации по Фленову
Фленов М.Е. в своей книге "Программирование на C++ глазами хакера" выделил 9 законов оптимизации программ. И хоть сами законы определены немного размыто и многословно, из них можно выделить короткие правила.
1. Оптимизировать можно всё. Даже если вам кажется, что уже нельзя.
2. Первое, с чего нужно начинать, — это поиск самых слабых и медленных мест.
3. Следующим шагом нужно выявить повторяющиеся операции. Начинаем оптимизацию именно с них.
4. Оптимизировать одноразовые операции — это только потеря времени.
5. Старайтесь поменьше использовать вычисления с плавающей запятой. Любые операции с целыми числами выполняются в несколько раз быстрее.
6. При создании функций не обременяйте их большим количеством входных параметров. Перед каждым вызовом функции ее параметры прячутся в стек, а после выхода извлекаются оттуда. Чем больше параметров, тем значительнее расходы на общение со стеком.
7. Лучше передать адрес ячейки памяти, где хранятся данные, а внутри функции работать с этим адресом.
8. В самых критических ситуациях можно воспользоваться вставками кода на языке ассемблера. Но увлекаться этим не стоит.
9. Не используйте длинных указателей вроде:
10. Для сложных расчетов можно подготовить таблицы с заранее определенными результатами и потом использовать эти таблицы в реальном режиме времени.
11. Лишних проверок не бывает. Если вы думаете, что какая-то нестандартная ситуация может и не возникнуть, то она не возникнет только у вас.
12. Обязательно делайте проверки всего того, что вводит пользователь. Делайте это сразу же и не ждите, когда введенные данные понадобятся.
13. Внутри циклических операций не должно выполняться ничего лишнего, ведь это будет повторено много раз. Например, любые лишние операторы
14. Не переусердствуйте с оптимизацией. Слишком большие затраты на ускорение выполнения кода могут свести на нет приложенные усилия.
От себя отмечу важность последнего пункта. Не нужно заниматься оптимизацией, пока в этом не назрела необходимость. Причины могут быть разные: явные неадекватные тормоза, жалобы пользователей, несоответствие требованиям и т.п.
При этом преждевременно пессимизировать тоже не стоит.
📍 Фленов МЕ - Программирование на С++ глазами хакера (2009)
Фленов М.Е. в своей книге "Программирование на C++ глазами хакера" выделил 9 законов оптимизации программ. И хоть сами законы определены немного размыто и многословно, из них можно выделить короткие правила.
1. Оптимизировать можно всё. Даже если вам кажется, что уже нельзя.
2. Первое, с чего нужно начинать, — это поиск самых слабых и медленных мест.
3. Следующим шагом нужно выявить повторяющиеся операции. Начинаем оптимизацию именно с них.
4. Оптимизировать одноразовые операции — это только потеря времени.
5. Старайтесь поменьше использовать вычисления с плавающей запятой. Любые операции с целыми числами выполняются в несколько раз быстрее.
6. При создании функций не обременяйте их большим количеством входных параметров. Перед каждым вызовом функции ее параметры прячутся в стек, а после выхода извлекаются оттуда. Чем больше параметров, тем значительнее расходы на общение со стеком.
7. Лучше передать адрес ячейки памяти, где хранятся данные, а внутри функции работать с этим адресом.
8. В самых критических ситуациях можно воспользоваться вставками кода на языке ассемблера. Но увлекаться этим не стоит.
9. Не используйте длинных указателей вроде:
ClassName->SubClass->SubSubClass->Property. Если в функции происходит несколько обращений к такому свойству, то это будет неэффективно. Каждый раз компилятор должен развертывать эту длинную цепочку для получения адреса переменной. Намного эффективнее будет завести локальную переменную в начале функции, присвоить ей значение и использовать локальную переменную.10. Для сложных расчетов можно подготовить таблицы с заранее определенными результатами и потом использовать эти таблицы в реальном режиме времени.
11. Лишних проверок не бывает. Если вы думаете, что какая-то нестандартная ситуация может и не возникнуть, то она не возникнет только у вас.
12. Обязательно делайте проверки всего того, что вводит пользователь. Делайте это сразу же и не ждите, когда введенные данные понадобятся.
13. Внутри циклических операций не должно выполняться ничего лишнего, ведь это будет повторено много раз. Например, любые лишние операторы
if внутри цикла очень сильно влияют на производительность. Если возможно, их надо выносить за пределы цикла.14. Не переусердствуйте с оптимизацией. Слишком большие затраты на ускорение выполнения кода могут свести на нет приложенные усилия.
От себя отмечу важность последнего пункта. Не нужно заниматься оптимизацией, пока в этом не назрела необходимость. Причины могут быть разные: явные неадекватные тормоза, жалобы пользователей, несоответствие требованиям и т.п.
При этом преждевременно пессимизировать тоже не стоит.
📍 Фленов МЕ - Программирование на С++ глазами хакера (2009)
👍4
Чем отличается префиксный инкремент ++i от постфиксного инкремента i++ в языке C++?
Anonymous Quiz
9%
Ничем не отличается
6%
Префиксный инкремент не принят в C++
74%
Префиксный инкремент вернет инкрементированное значение, а постфиксный - значение до инкремента
11%
Префиксный инкремент добавляет биты в начало участка памяти, а постфиксный - в конец