Так себе программист
86 subscribers
93 photos
1 video
1 file
130 links
Давай созидать. Разработчик, преподаватель, к.т.н о программировании и профессии.

Пишу desktop на C/С++, а когда никто не видит, то еще что-нибудь на python и js :)

Большие статьи тут: https://atrotsenko.hashnode.dev

Автор: Александр Троценко
Download Telegram
Troubleshooting

Траблшутингом мы занимаемся каждый день. Баг такой, баг сякой. Мы либо исправляем баг, либо создаем его 🐞👋 (не специально, конечно). Но в наших интересах сводить наши проблемы к минимуму.

Небольшой серией постов я хочу разобрать практические подходы, которые нам в этом помогут. Начнем сначала: как проблемы предупредить?

1. Не пессимизируйте преждевременно. Что бы вы тут не подумали, это значит "делайте сразу хорошо". Простой пример: если нужно использовать число 42, то определите его именованной константой, а не оставляйте болтаться "голым". Для любой технологии сообщество предлагает лучшие практики, безопасные подходы и прочие гайд-лайны. Время от времени посматривайте в подобные руководства, официальные или нет, и вы не заметите как начнете применять эти подходы автоматически.

2. Работайте с предупреждениями компилятора (или что у вас там). В пределе их не должно быть совсем. Игнорируя предупреждения, мы... См. пункт 1... Правильно, пессимизируем.

3. Используйте статические анализаторы. Это отличное усиление компилятора (или что у вас там). Множество проверок, в том числе проверок безопасности, поможет выявить косяки на раннем этапе.

Когда проблема зарегистрирована, но ее решение не очевидно, мы можем прибегать к пунктам 2 и 3. Проверьте, что включен максимальный уровень проверок компилятора (или что у вас там), а также ещё раз прогоните проблемные исходники через анализаторы. Есть шанс, что источник проблемы будет найден

Кто знает, какие еще есть способы предупреждать проблемы?

#Troubleshooting
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21🙏1
Troubleshooting. Метод деления пополам

Продолжаю серию постов по траблшутингу. Сегодня поговорим про локализацию проблемы методом деления пополам.

Метод деления пополам используется, например, в электротехнике ⚡️ для поиска обрыва в цепи. Для этого участок цепи визуально разбивается пополам и каждая половина проверяется на предмет наличия тока. Та половина, в которой тока нет, считается содержащей обрыв. Она в свою очередь снова разбивается пополам и половинки снова проверяются. Так продолжается до тех пор, пока мы не придём к проблемному месту.
А мы придём к нему в общем случае быстрее, чем если бы последовательно проверяли цепь по маленьким "кусочкам".

Вот такой итерационный метод можно использовать и при отладке программ.

Представим, что у нас в программе есть ошибка из-за дефектных данных в некоторой переменной. По-моему не сложно представить 😅
Наша задача состоит в том, чтобы найти в коде место, где данные становятся дефектными, то есть локализовать проблему:

1️⃣ Для начала выбираем большой участок программы от ее старта до места проявления ошибки. Мы уверены, что в начале выполнения программы наши данные корректные.

2️⃣ Теперь визуально делим выбранный участок программы пополам и проверяем корректность данных в месте разделения. Если данные корректные, то выбираем следующий по ходу участок программы. Если данные не корректные, то - предыдущий.

3️⃣ Продолжаем пункт 2 до тех пор, пока не "спустимся" к источнику проблемы.

Кстати, таким же методом можно искать ошибки не только по процессу выполнения программы, но и по истории коммитов.

Для этого нужно знать коммит, на котором проблемы еще не было, и коммит, на котором проблема была обнаружена. Тогда путем деления истории коммитов пополам можно быстро найти коммит, который занёс в код ошибку. В git, например, этот метод реализуется командой git bisect. Почитайте, если ещё не слышали.

#Troubleshooting
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Troubleshooting. Логирование

Если коротко: никогда не пренебрегайте логированием. Чем адекватнее логи, тем проще заниматься траблшутингом.

Что значит "адекватные логи"? Вообще термин "адекватность" относится к моделированию и означает совпадение свойств модели и моделируемого объекта. Так вот если принять процесс работы программы за моделируемый объект, а его логи за модель, то все становится понятно.

Как распознать неадекватные логи? Здесь надо исходить из основной функциональности или бизнес-логики программы. Если выполнение основной функциональности не попало в логи, то считаем адекватность логов слабой. Например, в случае с текстовым редактором основной функциональностью может быть открытие документа, и отсутствие записи об этом в логах осложнит восстановление общей картины процесса.

Отдельное внимание стоит уделить логированию ошибок. Здесь часто присутствует скудное описание, недосказанность. И если некоторые технологии обеспечивают нас трассировкой стека, что очень выручает, то в том же C++ о выводе подробностей ошибки надо заботиться самостоятельно. Ну встречали же такое: "File open error". И думай, что за файл, какой такой "error"? Никуда не годится. Хотя вся нужная информация есть, просто нам её не показали.

Ещё во время траблшутинга используют избыточное логирование. Это когда логируется чуть ли не каждая строка кода, что помогает разобраться с проблемой. Потом эти логи убираются. Хотя с этим лучше не спешить, а подумать, какие именно записи помогли нам, и, возможно, оставить их в логах навсегда. Некоторые ошибки имеют свойство повторяться со временем.

Логи - это "черный ящик", который мы получаем от пользователя в случае "аварии". От их качества нередко зависит успех операции)

Какие еще знаете и используете практики логирования?
Делитесь 👇

#Troubleshooting
🔥3
Troubleshooting. Упрощение задачи

В больших и сложных программах бывает трудно найти истинную причину бага. Проверяешь гипотезы одну за одной, а баг и ныне там.

Или бывает так, что последняя гипотеза срабатывает, но при откате предыдущих все снова ломается.
К этому времени подозреваешь уже все что угодно 👽

Вот тут то и надо задуматься о снижении сложности задачи.

Как снижать?

Нужно взять каждую гипотезу и проверить ее в минимальной простой программе. Словно в лаборатории.

🔽 Рассмотрим пример 🔽

Недавно я решал проблему с нерабочими горячими клавишами на панели инструментов в Qt. При анализе бага появилось несколько гипотез.

Первая гипотеза: проблема со стандартными кнопками QAction в самой Qt.
Для проверки гипотезы упрощаю задачу: делаю небольшую программу с единственной панелью инструментов. ➡️ В этой программе гипотеза не подтвердилась - все работало как надо.

Вторая гипотеза: проблема при переходе в режим полного экрана. ➡️ Дорабатываю свою небольшую программу - гипотеза снова не подтверждается.

Третья гипотеза: проблема при нестандартных масштабах экрана. ➡️ Проверяю в небольшой программе - опять мимо.

Четвертая гипотеза: проблема с кнопками QWidgetAction в самой Qt. ➡️ Проверяю, и, наконец-то, вот оно! Поймал!

Дошел бы я до этого в основной программе? Конечно дошел бы. Вопрос времени.

Однако, посмотрите на первые три гипотезы. Ну ничего общего с реальным багом! Но именно к ним я пришел при первоначальном анализе. А четвертая появилась уже потом, на маленькой программе.



А в прошлый раз в рубрике #Troubleshooting мы разбирали логирование. Вспоминайте, кто забыл.
🔥3👍1😁1
Как не утонуть в правках. Git-стратегия для сложных задач с риском откатов

Ситуация: пилите большую фичу, написали много кода и вдруг замечаете, что сломали то, что час назад работало. Что случилось, почему? Открываете git diff, а там правки не за последний час, а за последний день... Где была допущена ошибка? Начинаем вспоминать, запускаем отладчик и забываем про текущую работу.

🔸 Как не доводить до такой ситуации?

Правильно - чаще коммитить. Но как коммитить то, что еще не готово? Коммит же должен быть завершенным!

Решение есть у нас: промежуточные коммиты.
Мы просто коммитим все, что хотим и когда хотим, а по окончании работ "схлопываем" промежуточные коммиты в один, используя interactive rebase.

Промежуточные коммиты оформляются с префиксом WIP (от Work In Progress), чтобы потом их не пропустить. В git log получается примерно так:
WIP: что-то сделал
WIP: еще что-то сделал
WIP: убрал кое-чего
WIP: зарефакторил то-то


🔸 Когда делать промежуточный коммит?

Я руководствуюсь общим правилом: если мой следующий шаг приведет к правкам незакоммиченного кода, я делаю промежуточный коммит. У меня должна быть возможность быстро понять, где допущена ошибка, и откатиться.

Обычно такие коммиты случаются:
- при фиксировании логически завершенных правок,
- перед любым рефакторингом,
- в конце дня.

А чтобы вам проще было разобраться с подходом, я записал небольшое практическое видео. На простом примере показал как промежуточные коммиты помогают локализовать ошибку и как потом "схлопнуть" эти коммиты в один через interactive rebase. Ссылки здесь ⤵️

📱 Смотреть на YouTube

📱 Смотреть во ВКонтакте

#Troubleshooting
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1