Pull to refresh
Московский кредитный банк
Банк, где понимают клиента

Применение статического анализатора кода SwiftLint в iOS мобильных приложениях банка

Reading time5 min
Views2.4K
Олег Иванов, руководитель направления центра компетенций дистанционных каналов обслуживания



Всем привет! Как и обещал в статье «Мобильный банк от МКБ: история развития», хочу сегодня поговорить о статических анализаторах кода и об опыте их применения в iOS мобильных приложениях банка.

Давайте поставим цель, которую мы хотим достичь, используя этот инструментарий:

  • раннее выявление ошибок и недочётов;
  • Code Style (стандарт оформления кода — набор правил и соглашений, используемых при написании кода программы).

Распространённым способом достижения поставленных нами целей является ручная проверка кода – Обзор кода (Code review).

Проверяющий или группа проверяющих внимательно изучают проверяемый код, далее они выявляют ошибки или участки кода, которые могут стать ошибочными в будущем, и дают рекомендации по его улучшению через комментарии к коду, которые через некоторое (!) время будут проанализированы и исправлены разработчиком. Как мы видим, вырисовывается долгий и дорогостоящий процесс проверки кода. Плюс всегда есть человеческий фактор – некоторые ошибки могут быть просто-напросто пропущены проверяющими.

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

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

Статические анализаторы кода – это не панацея и не замена ручного Сode review, но являются отличным инструментом, позволяющим снизить время на проведение проверки и оперативно найти шаблонизированные ошибки. Актуальность использования статических анализаторов со временем будет только расти.

В качестве статического анализатора кода в своих iOS проектах мы используем SwiftLint.

SwiftLint — это утилита автоматической проверки Swift-кода, работающая на этапе сборки проекта. Утилита содержит набор правил с возможностью дополнения этого набора своими custom правилами. Инструмент также применяется для соблюдения Code Style.

Почему в приложении важно соблюдать Code Style?
Когда вы один разработчик на проекте – всё просто: вы пишете в своём стиле и можете позволить себе код в подобном виде:



Но когда вы работаете в большой команде разработчиков. важным фактором является скорость понимания и нахождения места вставки доработок в чужой код.
И здесь приходится принимать всеми членами команды соглашения и правила написания кода. Но как проверить их соблюдение? Опять нам поможет статический анализатор кода SwiftLint. И наш код примет приятный вид, который поймёт каждый член команды:



Для знакомства с инструментом рекомендую почитать официальную документацию.

Установка SwiftLint проста:

  1. Добавляем pod ‘SwiftLint' в Podfile проекта
  2. Добавляем новый «Run Script Phase» к проекту

    "${PODS_ROOT}/SwiftLint/swiftlint"
  3. Определяемся с набором правил SwiftLint и записываем их в конфигурационный файл .swiftlint.yml
  4. Добавивляем конфигурационный файл .swiftlint.yml в каталог, из которого будем запускать SwiftLint

Если проект встраивания SwiftLint уже содержал код, придётся запастись терпением и планомерно исправить все рекомендации SwiftLint. Их он формирует через привычные error и warning отображения c исчерпывающими подсказками о рекомендации.



Также в скобках он выведет имя правила, которое инициировало рекомендацию (operator_usage_whitespace).

В данном случае это:

Operator Usage Whitespace
Операторы должны быть окружены одним пробелом.

Правильный код:




Код вызывающий рекомендацию:



Каждое правило имеет набор атрибутов:

Идентификатор: operator_usage_whitespace
Включено по умолчанию: отключено
Поддерживает автокоррекцию: да
Вид: стиль
Правило анализатора: Нет
Минимальная версия компилятора Swift: 3.0.0
Конфигурация по умолчанию: предупреждение

Обращайте внимание на «Минимальная версия компилятора Swift» – соотносите использование правил с этим атрибутом и с настройками вашего проекта.

Атрибут «Конфигурация по умолчанию» показывает, как правила с этим атрибутом будут восприниматься: или обычное предупреждение, или ошибка компиляции, как например, правило Force Cast (Конфигурация по умолчанию: ошибка)

Все правила можно посмотреть в очень удобной и иллюстрированной документации.

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

Мы разделили все правила на функциональные и стилистические – да-да-да и один пробел внутри каждой фигурной скобки, и параметры закрытия должны быть в той же строке, что и открывающая скобка, и… :). Правила не расписываю, информацию о них вы легко найдёте, воспользовавшись ссылкой выше.

Функциональные:

— private_outlet
— force_unwrapping
— force_cast
— force_try
— strong_iboutlet
— private_action
— block_based_kvo
— contains_over_first_not_nil
— discarded_notification_center_observer
— discouraged_direct_init
— discouraged_object_literal
— discouraged_optional_boolean
— discouraged_optional_collection
— duplicate_imports
— dynamic_inline
— empty_count
— empty_parameters
— empty_parentheses_with_trailing_closure
— empty_string
— explicit_enum_raw_value
— function_default_parameter_at_end
— generic_type_name
— identical_operands
— implicit_getter
— is_disjoint
— notification_center_detachment
— nsobject_prefer_isequal
— redundant_set_access_control
— unused_capture_list

Cтилистические:

— unneeded_parentheses_in_closure_argument
— let_var_whitespace
— yoda_condition
— colon
— comma
— closure_parameter_position
— closure_spacing
— collection_alignment
— leading_whitespace
— mark
— opening_brace
— operator_usage_whitespace
— operator_whitespace
— protocol_property_accessors_order
— return_arrow_whitespace
— switch_case_alignment
— statement_position
— trailing_comma
— trailing_newline
— unneeded_break_in_switch
— custom_rules
— closure_end_indentation
— file_name_no_space
— unowned_variable_capture
— no_space_in_method_call
— contains_over_filter_count
— contains_over_filter_is_empty
— contains_over_range_nil_comparison
— duplicate_enum_cases
— empty_collection_literal

Также под цель работы SwiftLint мы выбрали только каталог с нашей кодовой базой, добавив соответствующую настройку в конфигурационный .swiftlint.yml файл:

included:

— <каталог кодовой базы>


Мы создали своё правило для недопустимости использования функции print. print — достаточно тяжелая операция. Через конфигурационный .swiftlint.yml файл:

custom_rules:
  disable_print:
    included: ".*\\.swift"
    name: "print usage"
    regex: "((\\bprint)|(Swift\\.print))\\s*\\("
    message: "Prefer os_log over print"
    severity: error

Это правило побудило нас написать свою функцию логирования (с уровнем логирования). Данное логирование используется разработчиками для быстрой отладки, к примеру, логи с параметрами, телом запроса/ответа нужны для любого разбора ошибок, для разработки. Для Release уровень лога в нашем варианте .none. Остальные же использования функции print приведут к ошибке сборки проекта.

func logApp(level: Constants.LogLevel, items: Any...) {
    if Constants.logLevel == .none {
        return
    }
    
    if level.rawValue <= Constants.logLevel.rawValue {
        // swiftlint:disable disable_print
        if let strings = items as? [String] {
            for string in strings {
                print(string)
            }
        } else {
            print(items)
        }
        // swiftlunt:enable disable_print
    }

Но для использования функции принт нам пришлось закрыть её вызов в нашей функции логирования средствами SwiftLint для игнорирования собственных правил на помеченном специальной инструкцией блока кода.

// swiftlint:disable disable_print
// swiftlunt:enable disable_print

SwiftLint имеет возможность игнорирования собственных правил:

// swiftlint:disable <rule1 [rule2 rule3…]>
<код, который игнорируется SwiftLint для правил rule1 [rule2 rule3…]>
// swiftlunt:enable <rule1 [rule2 rule3…]>

Или

// swiftlint:disable all
<код, который игнорируется SwiftLint для всех правил>
// swiftlint:enable all

Используйте эту возможность, полностью отдавая себе отчёт, что это необходимо!

В заключении статьи отмечу: применение SwiftLint в нашей команде снизило стоимость ручного Code review на 20%. Теперь наши проверяющие не обращают внимание на типичные ошибки (Force Cast и др.), Code Style и могут в полной мере сосредоточиться на проверке нового кода. Что значительно повысило эффективность работы команды в целом (не нужно исправлять подобные ошибки, проверяющие – это квалифицированные сотрудники, чьё время очень важно).

Всё! Теперь SwiftLint навсегда с вами :)

Tags:
Hubs:
+3
Comments3

Articles

Information

Website
mkb.ru
Registered
Founded
Employees
5,001–10,000 employees
Location
Россия
Representative
Chitanava