Предисловие
Существует большое количество статей, посвященных статическим анализаторам для С/С++/С#, Java и т.д. Что касается исследований применения различных статических анализаторов для нативной разработки под MacOS/iOS, то им уделено гораздо меньше внимания.
Предлагается разбор применения статических анализаторов кода, используемых в различных проектах на ObjC и Swift. При этом, это не обзор, а скорее некоторые заметки применения различных инструментов, позволяющих находить ошибки того или иного рода в коде, начиная от утечек памяти и заканчивая поиском уязвимостей. Однако данные не претендуют на объективность и полноту сделанных выводов, а также на глубину анализа полученных результатов по каждому инструменту.
Вступление
Несколько лет назад, ещё будучи начинающим iOS разработчиком, я столкнулся с проблемой верификации качества кода, написанного на ObjC для iOS приложения. К сожалению, не всегда удавалось найти ошибки и обсудить код с более квалифицированными коллегами за неимением таковых. Первые негативные отзывы хоть и воспринимались конструктивно, но, все – таки, приводили к потере клиентов, которые желали оценить примеры кода разработчика перед заключением контракта. В результате этого возникла потребность использования инструментов, выявляющих максимум дефектов кода перед демонстрацией его заказчику. Отмечу, всегда было актуально иметь отчёты о качестве кода в Continuous Integration после всех комитов для выявления потенциальных проблем в разрабатываемом продукте.
Работать приходилось в различных командах с разными проектами от сольных до распределённых, с командой, находящейся на разных континентах. Уровень квалификации коллег варьировался от начального уровня до архитектора. Состав команд аналогично постоянно претерпевал изменения и это при том, что каждый год появлялись новые версии Swift, да и ObjectiveC не стоял на месте.
Все эти факторы стимулировали поиски инструментов, позволяющих выявить максимальное количество ошибок и сделать код более консистентным и легко читаемым.
Clang Static Analyzer
Это первый встроенный анализатор, с которым встречается любой пользователь XCode. Для того, чтобы анализировался код при каждом запуске приложения, необходимо произвести настройки, описанные здесь. Данные рекомендации следует использовать всем пользователям как первую ступень проверки кода перед каждым его коммитом.
Отсутствие поддержки Swift весьма ограничивает области его применения. Конечно, в XCode имеется Address Analyzer и Thread Sanitizer, которые поддерживают Swift – однако эти инструменты не являются статическими анализаторами и могут использоваться только при запуске приложения, то есть в run time.
Подходит для превентивного поиска потенциальных memory-leaks и ошибок в структуре кода.
Faux Pas
Faux Pas (неверный шаг– фр.) — первый сторонний статический анализатор, с которым пришлось столкнуться, имеющий полноценный как GUI так и CLI. После начала его использования качество кода стало заметно выше. Он помог выявить в моих проектах на ObjC от 20% до 50% скрытых баг. Самое курьёзное было то, что инструмент при первом же его запуске выявил именно те ошибки, на которые указал заказчик. Это являлось основным аргументом, почему, собственно, и было решено приобрести данный инструмент за личные средства разработчика, а не ждать пока вся компания примет его на вооружение.
К сожалению, не все коллеги приняли данный инструмент позитивно — некоторые считали, что анализатор должен быть бесплатным, другие — сетовали на большое количество настроек, не желая в них разбираться.
Главный недостаток – это отсутствие поддержки Swift, однако разработчики обещают его поддержку, хоть пока и не анонсируют дату.
Менее значимая проблема — это то, что workspaces поддерживаются не напрямую — проверять приходиться либо через командную строку (конфигурировать проверку workspace), либо по отдельности каждый проект, что, в свою очередь, не всегда удобно.
Тем не менее, Faux Pas находит проблемные участки кода, которые противоречат Apple Coding Guidelines. Например, использование self.propety в init и dealloc, напоминает про использование Modern ObjC syntax, Missing NSNotificationCenter observer detachment и так далее. Легко интегрируется в CI.
Генерируемый отчёт в Json или plist лучше конвертировать в нечто более читаемое. Отчет содержит подробное описание проблемы, в нем также даются внешние ссылки на правила. Несмотря на то, что, временами, попадаются ссылки на stackoverflow, а не на официальную документацию, это, всё – же, не является существенным недостатком.
Пример результата работы инструмента приведен ниже. Для запуска анализатора в XCode, для предметного обнаружения проблем, можно использовать CLI.
Для анализа отчёта, представленного в JSON было написано небольшое приложение, генерирующее отчет в Excel с выборкой по каждой проблеме в представлении в похожем на GUI FauxPas.
Что касается конфигурирования анализатора, то инструмент конфигурируется через:
GUI, Аргументы CLI и конфигурационные файлы. Способа создания собственных правил не обнаружено.
OCLint
Впервые анализатор встретился в небольшом, но долго живущем проекте зарубежной компании написанном на ObjC. Разработчики этой фирмы были весьма консервативны и не желали переходить на Swift, из-за сложности миграции на все новые версии этого языка.
Несмотря на то, что OCLint позволяет менять и добавлять правила через Scaffolding, это, однако, требует много времени. По процессу разработки в данной компании код не будет комититься в репозиторий, пока не исправят все предупреждения анализатора. Некоторые из правил проверки обрабатывались не всегда корректно. Для устранения всех предупреждений анализатора приходилось использовать обходные приемы (костыли), что заставило команду в конечном итоге отказаться от поддержки этого анализатора.
Тем не менее анализатор позволяет выявить:
- Пустые операторы if/else/try/catch/finally без выражений,
- Неиспользуемые локальные переменные и параметры
- Сообщает о высокой цикломатической сложности
- Реагирует на избыточный код с оператора if и не используемые скобки
- Позволяет обнаружить инвертируемую логику и переназначение переменных
Время анализа небольшого проекта достаточно велико (по сравнению с Clang анализатором), и если в вашем проекте ранее не применялся данный инструмент, он может выдать огромное количество предупреждений, что затруднит первичный анализ. Поэтому, если желание проверять всю кодовую базу и получать огромный список предупреждений отсутствует, то можно написать небольшой скрипт, который проверяет только изменённые файлы перед комитом, что актуально для любого анализатора.
Стандартно интегрируется в XCode через build Script.
Инструмент достаточно гибкий, но, тем не менее, хотелось бы более продвинутого эвристического анализа кода, так как данный инструмент существует довольно давно. В настоящее время назрела потребность в плагине расширения для XCode этого анализатора, что заметно упростило бы его использование.
Codebeat
Облачный анализатор Codebeat поддерживает как ObjC, так и Swift, что являлось критически важным, когда данный продукт выбирался для использования в конкретном проекте. Одним из недостатков было то, что проверка производилась только после того, как commit попадал на GitHub перед pull request, что делало процесс разработки слегка не структурированным в нашем случае. На момент написания статьи разработчики обещали выпустить утилиту автоматического код ревью для того, чтобы полностью минимизировать участие разработчиков в этом процессе. Это является актуальной задачей, в связи с нерегулярными или невнимательными проверками кода в командах разработчиков в некоторых проектах с человеческим ревью.
Поддерживается Swift + Obj-C, Python и Ruby, что весьма удобно для мобильной разработки.
Анализ ObjC кода работает не вполне удовлетворительно. Это связано с тем, что компания ориентируется в основном на анализ кода на Swift, а работа с ObjC добавлена недавно и требует дальнейшей доработки.
Относительно поддержки продукта, то она на высоте. Всегда была возможность связаться со службой поддержки в течение дня, и даже в выходные предоставлялась необходимая помощь.
Что касается конфигурирования метрик, то это можно сделать, создав свой json файл и изменив правила проверки. Тем не менее, возможность создавать новые правила проверки или модифицировать существующие отсутствует. Однако, как заверили меня разработчики, в будущем такая возможность планируется.
Данный инструмент бесплатен для opensource проектов, а для приватных репозиториев цена не так уж высока, к тому же пробный период длиться 3 месяца, что можно считать достаточно демократичным.
Infer
Продукт facebook, который открыл собственный анализатор кода, подходит не только для анализа проектов на iOS, но и для Android/Java разработки.
Сразу запустить этот анализатор в командной строке для тестового проекта не удалось, но после создания запроса на Github меня посвятили в некоторые тонкости его настройки. Мне даже удалось интегрировать его в XCode с помощью “Run build script”.
Для запуска анализатора была создана дополнительная scheme – Infer в Xcode по аналогии с другими анализаторами, использующими CLI. В частном случае большой пользы от его применения выявлено не было. Возможно, имеет смысл применять данный инструмент в других более крупных кроссплатформенных сложных проектах.
SwiftLint
Очень популярный среди Swift разрабочиков анализатор, который имеет плагин plugin для XCode, что являляется весьма удобным.
В качестве базововых правил взят GitHub's Swift Style Guide. Существует возможность создания regex-based собственных правил проверки. В частности, очень удобно создавать правила, касающиеся рефакторинга, когда новая функциональность добавляется в расширения классов инструментов, например, функция NSLocalizedString() становиться просто полем в NSString (или String) раширении класса.
В конкретном случае команды работали на распределенных бранчах, на которых не проводился рефакторинг. С помощью опции «autocorrect» можно легко привести код к единому стилю, когда код мержился на единый бранч.
SwiftLint использовался в большом гибридном проекте, содержащем как ObjC, так и Swift код. Автор идеи его внедрения в проект, к сожалению, не прочел статью о превратностях использования — «autocorrect» опции и вставил проверку в «Run Script» в Xcode. Разумеется, в больших проектах с командой, не имеющей общей точки синхронизации, не все установили этот инструмент сразу. Одновременно с этим шла миграция на Swift 3.0, что, несомненно, добавило путаницы при новых коммитах.
Начиная с версии 0.16.0, появились некоторые правила ложного срабатывания, например, c large_tuple проекты перестали компилироваться через build script. Вдобавок не все правила обрабавтываются корректно, что свойственно многим анализаторам и это вынуждает использовать обходные приемы, от которых страдает качество кода. Эта проблема заставила аккуратнее относиться к внесению SwiftLint в “Build phases script” для каждого проекта.
Данный инструмент также был интегрирован в Jenkins, что, очевидно, улучшило контроль над кодовой базой проекта.
Tailor
Tailor это кросплатформенный статический анализатор для Swift. Весьма необычным является тот факт, что поддерживается платформа Windows.
Применялся как альтернатива SwiftLint на пилотных проектах. Однако на данный период времени он поддерживает только Swift 2, что немного не соответствует современным требованиям. Тем не менее существует issue enchantment на поддержку Swift 3.0.1. Поддерживает правила code style для The Swift Programming Language, GitHub, Ray Wenderlich, и Coursera.
Для поддержки pods и workspace рекомендуется использовать следующую рекомендацию.
Возможность создавать собственные правила не обнаружена, хотя вероятность, что она существует, есть, однако в этом следует тщательно разобраться.
Интегрируется в Xcode через “Build Script”. Чтобы подавить предупреждения типа trailing-whitespace, которые сразу начинают доставлять неудобства при первом же его использовании,
Рекомендуется использовать ключи:
tailor --except=brace-style,trailing-whitespace
Отчет при желании можно вывести в HTML, JSON или в формате XCode, что достаточно удобно для применения в CI при публикации результатов на web сервере.
Форматирование в Swift Style
Говоря об анализаторах нельзя не упомянуть о “форматерах” кода для определенного style guide.
Несмотря на то, что они не являются статическим анализаторами кода, а форматируют код к Swift Style, тем не менее, они служат той же цели выявления ошибок путем приведения кода к единому стилю, позволяющей лучше воспринимать код программистом, а, следовательно, быстрее выявлять проблемные участки кода.
SwiftFormat
Удобен тем, что дает возможность создавать собственные правила для удовлетворения code style конкретной команды. Конфигурирование происходит через CLI, что может понравиться далеко не всем. Тем не менее, он может быть установлен как плагин в XCode.
Swimat
Инструмент может быть использован как CLI, так и Xcode extension. Это, действительно, неплохой инструмент, хоть он и содержит несколько критичных баг, которые приводят к падению XCode при его использовании. Однако разработчик оперативно их устраняет. Возможность добавления собственных правил проверки присутствует.
В частном случае использовался для форматирования кода небольшого проекта, где зарекомендовал себя с лучшей стороны в плане удобства и выдаваемого результата.
Оба форматерра комфортно применять в качестве расширения для XCode, и в настоящее время поддерживаются и улучшаются.
Checkmarx
На практике, временами, встречаются проекты от заказчиков, критично относящихся к безопасности выпускаемого продукта. Для таких проектов лучше воспользоваться Static Application Security Testing (SAST) решением по аудиту исходного кода от компании Checkmarx.
Это облачное решение, то есть инструмент, может располагаться либо на локальном сервере для разработки, либо на сервере компании Checkmarx. Достаточно продвинутый анализатор, использующий собственные запатентованные технологии. У Checkmarx, которая ранее тесно сотрудничала с министерством обороны США, очень много интересных наработок касательно исследований всевозможных уязвимостей. Поддерживает Swift, но в конкретном случае анализировался ObjC проект. К сожалению, не имеет плагина расширения для Xcode.
Система отчетов является очень информативной и презентабельной. Одна из страниц приведена ниже.
Информативный отчет может содержать от 10 до 300 страниц в зависимости от вашего проекта. Также в отчете даются пояснения о том, как исправить проблемы, и даже приводятся примеры. Общей ошибкой для всех проектов, которые подвергались анализу было “Third Party Keyboard Enabled”, что связано с возможной уязвимостью при установке сторонних клавиатур для iOS (правда, одно из анализируемых приложений не содержало полей ввода с клавиатуры).
Послесловие
С некоторыми инструментами статического анализа кода все ещё хотелось бы познакомиться на практике, например, Sonar. Однако из-за дороговизны продукта и сложности его установки такой возможности пока не представилось. В то же время для некоторых проектов интересно попробовать Solar inCode для поиска уязвимостей в коде для заказчиков, волнующихся о безопасности своих приложений. К моему сожалению, этот продукт получить не удалось даже в Demo-версии.
Многие из выше приведенных инструментов помогли сделать создаваемые продукты стабильнее и устойчивее к различным уязвимостям в коде. В принципе, любой анализатор — это непредвзятый судья, которому вы безразличны и у вас нет персональных претензий к нему, что делает всю работу более объективной и упорядоченной.
Тем не менее, очевидно, что идеальных инструментов не бывает, и даже применение все существующих средств анализа кода не является панацеей. Не говоря, о тех случаях ложного срабатывания иструментов когда приходиться пользоваться обходными приемами, чтобы удовлетворить требованиям анализатора. В связи с этим, человеческое ревью всегда будет актуально, чтобы хотя бы выявлять смысловые ошибки типа dragState, вместо drugState или cacheData, вместо cashData (правда можно настроить автозамену …).
Полезные ссылки
- Static Analysis with OCLint
- Устройство и принципы работы статического анализаторы
- Guide for Static Analysis.
- Getting the most out of static analyzers
- «Watch Your Language!»: The Road to Cleaner Code with SwiftLint
- Thread Sanitizer and Static Analysis
- About Debugging with Xcode
- Контролируем качество кода с помощью платформы SonarQube
- Регулярное использование статического анализа кода в командной разработке
Автор: evgzor