Эта библиотека не входит в стандартный дистрибутив. Установить ее можно, например, выполнив команду
gem install ruby-breakpoint
.
Внесем несколько изменений в программу из листинга 16.4. Поместим в начало директиву
require 'breakpoint'
и добавим вызов метода
breakpoint
после обоих обращений к
gets
:
require 'breakpoint'
# ...
w2 = gets.chomp
breakpoint
# ...
Теперь
запустим ее. В следующем протоколе сеанса показано, как мы входим в
irb
, после чего можем делать все что угодно — в частности, вызывать ранее определенные методы и изменять значения переменных.
$ ruby myprog.rb
Give me a word: parental
Give me another word: prenatal
Executing break point at myprog.rb:23
irb(main):001:0> w1
=> "parental"
irb(main):002:0> w2
=> "prenatal"
irb(main):003:0> palindrome?(w1)
=> false
irb(main):004:0> palindrome?("detartrated")
=> true
irb(main):005:0> signature(w1)
=> "aaelnprt"
irb(main):006:0> quit
'parental' is not a palindrome.
'prenatal' is not a palindrome.
'parental' and 'prenatal' are anagrams.
Особенно подкупает, что отлаживаемая программа может быть не только командной или текстовой. Существует клиент drb (распределенный Ruby), который позволяет удаленно отлаживать программу Ruby, работающую в другом процессе.
Чтобы воспользоваться этой возможностью, нужно включить вызов следующего метода в отлаживаемую программу (естественно, до первого обращения к методу
# Запустить сервер на порту 2001 машины localhost.
Запустите клиент командой
breakpoint_client
. Каждые три секунды он будет пытаться установить соединение с сервером, пока это не получится или вы не завершите его принудительно.
$ breakpoint_client druby://localhost:2001
No connection to breakpoint service at druby://localhost:2001 (DRb::DRbConnError)
Tries to connect will be made every 3 seconds...
После установления соединения вы можете и не получить приглашение
irb
. Программа будет выполняться до точки прерывания — вот тогда-то вы и увидите приглашение.
Дополнительную информацию об этой библиотеке поищите в документации, которая входит в комплект поставки.
16.5. Измерение покрытия кода
Очень полезно знать, какие части программы не были протестированы, а следовательно, нуждаются в автономных тестах. Иногда и сам инструмент для замера покрытия может обнаружить ошибки. Допустим, в программе есть предложение
if
, которое «должно» исполняться примерно в половине всех случаев. Если
выясняется, что оно не исполняется никогда, значит, имеет место ошибка.
Командную утилиту
rcov
(и соответствующую библиотеку) написал Маурисио Фернандес (Mauricio Fernandez). Устанавливается она в виде gem-пакета.
В простейшем случае для ее запуска достаточно указать имя вашей программы в качестве параметра:
rcov myfile.rb
Одновременно с исполнением вашей программы
rcov
будет собирать статистику. По умолчанию она создает каталог
coverage
, в котором вы найдете HTML-файлы. В файле
index.html
представлены сводные результаты и ссылки на исходные тексты, где строки, которые хотя бы раз исполнялись, подсвечены.
Из-за цветового кодирования трудно привести черно-белый снимок с экрана. Но сам инструмент настолько прост, что, потратив пару минут, вы сможете увидеть все сами.
Хотя программа
rcov
полезна даже в стандартном режиме, она понимает порядка 30 различных параметров. Можно указать каталог для выходных файлов, образцы имен файлов, для которых собирать и не собирать статистику, задать режим сортировки по именам файлов и многое другое. Можно выводить результаты в текстовом виде и даже запросить цветную диаграмму покрытия. Рекомендую прочитать поставляемую документацию, запросить справку командой
rcov -h
и… получать удовольствие.
Можно использовать
rcov
и в качестве библиотеки для написания аналогичных инструментов анализа. Ее API состоит из трех основных классов:
•
Rcov::FileStatistics
позволяет отличить исполняемые предложения от комментариев (и тем самым уточнить статистику покрытия);
•
Rcov::CodeCoverageAnalyzer
применяется для трассировки выполнения, возвращает информацию о покрытии и счетчики выполненных предложений;
•
Rcov::CallSiteAnalyzer
нужен для того, чтобы понять, где определены методы и откуда они вызываются.
Обсуждение API далеко выходит за рамки этого раздела. Почитайте документацию и начинайте экспериментировать.
16.6. Измерение производительности
Я не люблю уделять слишком много внимания оптимизации скорости. В общем случае нужно правильно выбрать алгоритм и придерживаться здравого смысла.
Конечно, быстродействие имеет значение. Иногда даже очень большое. Однако начинать думать об этом на раннем этапе цикла разработки — ошибка. Как говорится, «преждевременная оптимизация — источник всех зол»; эту мысль впервые высказал Хоар (Hoare), а потом подтвердил Кнут (Knuth). Или, перефразируя, сначала пусть работает правильно, а уж потом быстро». На уровне отдельного приложения эта рекомендация обычно оказывается хорошим эвристическим правилом, хотя для больших систем она, быть может, и не так актуальна.
Я бы еще добавил: «Не оптимизируйте, пока не измерите».
Это не такое уж серьезное ограничение. Просто не приступайте к переработке ради скорости, пока не ответите на два вопроса: «Действительно ли программа работает медленно? Какие именно ее части снижают производительность?»
Второй вопрос важнее, чем кажется на первый взгляд. Программисты часто уверены, что и так знают, на что программа тратит большую часть времени, но специальные исследования убедительно свидетельствуют о том, что в среднем эти догадки имеют очень мало общего с действительностью. «Теоретическая» оптимизация для большинства из нас — плохая идея.