Ускоряем дебаг в разы. Зачем и как использовать брейкпоинты

Всем привет! Меня зовут Вадим Джибалов, и я Android-разработчик в AGIMA. Свою первую статью на Хабре я посвящаю простой, но важной теме — брейкпоинты. Пишу я её для джуниоров, которые только знакомятся с отладкой. Мы уделяем много внимания развитию наших стажеров и росту специалистов. А когда только начинаешь программировать, найти даже элементарные вещи бывает нелегко. Мы готовы помочь.

958e1282e871e047d6e11fc1586e4060.png

Почему брейкпоинты — это круто

Когда я только начинал заниматься Android-разработкой, я не понимал истинную силу брейкпоинтов. Отладку я делал всегда через Timber и чувствовал себя прекрасно. Но однажды друг показал мне их истинную силу, и я понял, что зря их не ценил.

Сейчас я покажу эту силу и вам.

Но сначала разберемся, какие преимущества есть у брейкпоинтов по сравнению с отладкой через Timber, Log и подобные вещи:

  1. Нет необходимости писать код и импортировать новые библиотеки там, где это не нужно.

  2. Не нужно открывать консоль, чтобы проверить значение переменной или что-то ещё.

  3. Во время «заморозки» брейкпоинта мы можем прочитать значение абсолютно любой переменной, доступной в нашем потоке.

  4. Поставить брейкпоинт — это очень быстро.

  5. Брейкпоинты можно ставить в рантайме — об этом расскажу ниже.

И это далеко не всё.

Чтобы понять, насколько это удобно, разберем пример. Сначала простой, где брейкпоинты не особо нужны и можно воспользоваться Timber, а потом кейс поинтереснее.

Допустим, у нас есть сценарий получения числа с бэка, проведения с ним каких-то операций и отображения на экране. Для симуляции получения числа используем простенькую функцию. Что она возвращает, мы, по идее, не знаем.

67a49e2a223dc65b63dd05eea9b86627.png

Далее нам это число нужно умножить на 2. Для этого мы тоже пишем отдельную функцию, которую в дальнейшем будем отлаживать. Ошибка допущена специально.

f37279c1befaab4b993df5568f5b5af4.png

Выводим результат на экран и видим, что мы получили 220 вместо 20.

49c726b340f2b855095a97dce0a3f479.png

Давайте посмотрим, как бы примерно выглядела отладка без брейкпоинтов.

55507318a7fe9e2a3b2104fd6ca44522.png

После этого мы бы открыли консоль и увидели неверный результат на втором логе. 

Как выглядела бы отладка через брейкпоинты в данном случае?

a16d99498faa37d3d1cddcd337c0776e.png

Просто нажимаем один раз рядом с номером строки, и у нас выставляется брейкпоинт. Брейкпоинта нет на поле number, потому что на 15-й строке мы и так сможем прочесть её значение.

Запускаем программу и видим, что number у нас показывается, а formattedNumber неизвестен.

cbec572f49ef84623405faa7af4eb80f.png

Вычислить любое выражение нам поможет Evaluate Expression. Нажимаем Alt + F8, и у нас выскакивает окно, в котором и происходит вся магия. Вписываем туда значение multipleBy2(number) и видим результат:

852712d1d51308d7c3faf9df04bd016e.png

Мы поняли, что ошибка в функции multipleBy2, и закончили отладку.

Теперь разберём пример с большим количеством операций. Допустим, во время отладки мы зашли на экран и видим, что из-за неверных вычислений поехала вся вёрстка. Создадим функции a, b, c, d, e, которые будут вызываться друг за другом. Их общий результат будет влиять на состояние экрана. Они будут условно отвечать за разные компоненты на макете, и нам нужно выяснить следующее:

  1. Какой метод ломает верстку.

  2. На каком этапе это происходит (на какой строке).

Снова разберём 2 варианта отладки: с брейкпоинтами и без. 

Если не использовать брейкпоинты, процесс будет примерно таким:

Удалять все методы из кода по порядку, пока не наткнемся на нужный > Вывести в консоль все данные из метода по порядку.

Этот вариант плох по нескольким причинам. Во-первых, нам нужно будет каждый раз пересобирать приложение. Большие проекты могут собираться более 10 минут, и это съедает невероятно много времени. Во-вторых, нужно будет писать код, импортировать библиотеки и т. д.

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

76db3f3f78d52cf930338a861411802b.png

Возможности брейкпоинтов

Представим, что у нас есть viewModel и кнопка, по нажатию на которую отправляется количество нажатий на кнопку. Вся эта картина будет выглядеть примерно так:

ebcdf4a506be724910e7920e39b5af8d.png

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

  1. Поставить брейкпоинт внутри функции calculateData.

  2. Поставить field WatchPoint на поле count.

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

Давайте поставим брейкпоинт внутрь calculateData и посмотрим. что выйдет:

fee8dfcfd7c6af3c9aaea699fa02633a.pngeebf63a011223def25773bcb1bda6016.png

Заходим в приложение и видим, что функция calculateData вызывается моментально из непонятного места. Двойной клик по второй строчке (run:41, MainActivity…) укажет нам на фрагмент кода, который вызывает функцию calculateData.

d2cc40cf28605e0d63d24eb286bb96c6.png

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

Что такое Kotlin Field Watchpoint

Но что, если наша переменная менялась за пределами функции calculateData?

На помощь придёт field WatchPoint. Около переменной count попробуйте поставить брейкпоинт, и перед вами встанет выбор, что вам нужно:

a252ac888f7968e14e3aee0f5ea61e05.png

Kotlin Field Watchpoint — это тот же самый брейкпоинт, но с одним отличием. Он будет останавливать работу кода при изменении переменной, а не при ее инициализации. Давайте проверим его работу.

Удалим метод calculateData в onStart и заменим его на count += 1

f4870dc51b0b7f456eede3995516940b.png

Теперь при запуске приложения через то же самое окно мы можем увидеть, откуда изменялась переменная.

f6204d9714e943e6426f2f77570cb521.png

Что об этом почитать:

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

© Habrahabr.ru