Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Статический анализ

Оригинал: Static Analysis
Автор: Leah Hanson
Дата публикации: 22 сентября 2015
Перевод: Н.Ромоданов
Дата перевода: июль 2016 г.

Глава 4 из предварительной версии книги "500 Lines or Less", которая входит в серию "Архитектура приложений с открытым исходным кодом", том 4.

Creative Commons

Перевод сделан в соответствие с лицензией Creative Commons. С русским вариантом лицензии можно ознакомиться здесь.

Сегодня мы представляем четвертую главу предварительной публикации нашего нового сборника «500 строк или меньше». Глава написана Лией Хансон (Leah Hanson).

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

На наш взгляд, Лия в данной главе проделала потрясающую работу по демистификации природы методов, используемых в статическом анализе и интроспекции. Хотя ее работа выполнена конкретно для языка Julia, результаты этой работы применимы и для других языков.

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

Приятного чтения!

Это предварительная публикация главы из сборника «500 строк или меньше», четвертой книги из серии книг Архитектура приложений с открытым исходным кодом. Пожалуйста, сообщайте в нашем треккере GitHub о любых проблемах, которые вы обнаружите при чтении этой главы. Следите в блоге AOSA или в Твиттере за объявлениями о предварительных публикациях новых глав и окончательной публикацией.

Лия Хэнсон известная выпускница школы Hacker School; ей нравится помогать другим изучать язык Julia. Ее блог - http://blog.leahhanson.us/ и твитер @astrieanna.

Введение

Возможно, вам известна замечательная среда разработки IDE, подчеркивающая красным цветом те части кода, которые не компилируются. Может быть, вы запускали для своего кода специальное приложение — линтер (linter), выявляющее наличие проблем с форматированием или стилем кода. А, может быть, вы запускаете компилятор в супер-придирчивом режиме со всеми включенными предупреждениями. Все эти инструменты являются приложениями статического анализа.

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

Мы можем получить более конкретную информацию о том, что нужно, если опишем процесс как имеющий следующие три стадии:

1. Решаем, что хотим проверять

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

  • Поиск неправильно написанных имен переменных
  • Поиск состояний гонки (race conditions) в параллельном коде
  • Поиск вызовов нереализованных функций

2. Решаем, как конкретно проверять

Хотя мы сможем попросить приятеля выполнить одну из перечисленных выше задач, эти задачи недостаточно конкретны с тем, чтобы их можно было объяснить компьютеру. Например, чтобы разобраться с "неправильно написанными именами переменных", мы должны решить, что здесь означает неправильно написанные имена. Одним из вариантов можно было бы определить, что имена переменных следует составлять из английских слов, взятых из словаря; другим вариантом могут быть переменные, которые встречаются только один раз (тот раз, когда вы неправильно набрали переменную).

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

3. Детали реализации

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

Мы намереваемся пройти через все эти стадии для каждой отдельной проверки, которые мы будем выполнять в этой главе. На стадии 1 необходимо достаточное понимания языка, используемого при анализе проблем, с которыми сталкиваются пользователи. Весь код, который представлен в данной главе, является кодом на языке Julia, написанным для анализа кода на языке Julia.

Очень краткое введение в язык Julia

Язык Julia сравнительно новый язык, предназначенный для технических вычислений. Весной 2012 года была выпущена его версия 0.1; по состоянию на начало 2015 года, он достиг версии 0.3. В общем, язык Julia выглядит как язык Python, но с некоторыми дополнительными аннотациями типов и без использования каких-либо объектно-ориентированных элементов. Особенностью, которую большинство программистов посчитают новинкой в языке Julia, является множественная диспетчеризация, оказывающая влияние как на общую архитектуру API, так и на выбор в языке других проектных решений.

Ниже показан фрагмент кода на языке Julia:

# Увеличение значения на единицу
function increment(x::Int64)
  return x + 1
end

increment(5)

В этом коде определен метод функции increment, которая имеет один аргумент, называющийся x и имеющий тип Int64. Метод возвращает значение x + 1. Затем этот только что определенный метод вызывается со значением 5; и, как вы уже догадались, будет возвращено значение 6.

Int64 является типом данных, значения которого представляют собой знаковые целые числами, записываемые в памяти 64 битами; они являются целыми числами, которые понятны вашему аппаратному обеспечению в том случае, если в вашем компьютере есть 64-разрядный процессор. Типы в языке Julia определяют, как данные будут представлены в памяти, и, в добавок, оказывают влияние на диспетчеризацию методов.

Название increment относится к обобщенной функции (generic function — дженерик-функции), в которой может быть много методов. Мы только что определили для нее один метод. Во многих языках, термины "функция" и "метод" используются как взаимозаменяемые; в языке Julia, они имеют различные значения. В этой главе будет больше смысла в том случае, если вы будете более аккуратно иметь дело с понятием "функция" как с именованной коллекцией методов, а "метод" будете рассматривать как конкретную реализацию для сигнатуры конкретного типа.

Давайте определим еще один метод функции increment:

# Увеличение значения x на y
function increment(x::Int64, y::Number)
  return x + y
end

increment(5) # => 6
increment(5,4) # => 9

Теперь в функции increment есть два метода. Язык Julia, зная количество и типы аргументов, решает, какой метод следует запустить для данного вызова; эта технология называется динамической множественной диспетчеризацией вызовов (dynamic multiple dispatch):

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

Если рассматривать в контексте языков программирования, то, как вы уже знаете, в объектно-ориентированных языках используются одинарные или обычные вызовы, поскольку при их использовании рассматриваются только аргументы (в x.foo(y) первым аргументом является x).

Как при обычных вызовах, так и при множественных, учитываются типы аргументов. Аргумент x::Int64, показанный выше, используется исключительно при вызове функции. В системе динамического типа Julia вы можете во время вызова функции назначить аргументу x любое значение и ошибка не возникнет.

Мы, на самом деле, еще не видели примеров "множественности", но, что касается языка Julia, вы должны попробовать эту технологию самостоятельно. Мы должны перейти к нашей первой проверке.

Продолжение статьи смотрите здесь