Кодовой базе Muse уже более 5 лет, в ней более 350,000 строк Swift, и я уверен, что в ней есть не мало ископаемого кода. Как и в любом стартапе (честно говоря, как и буквально в каждом кодовом проекте), трудно отсекать старый неиспользуемый код, поддерживая при этом скорость появления новых фич. Чистота кода — это всегда компромисс со скоростью, и часто она отходит на второй план. Вот почему я люблю инструменты, которые помогают автоматизировать эту медленную ручную работу.
Недавно мне рассказали о Periphery, инструменте командной строки для поиска неиспользуемого кода в проектах на Swift. Для чего нужен свободный от работы день, как не для того, чтобы весело поиграть с новым инструментом?
Для начала — установка:
$ brew install periphery
Боже, благослови brew, таки да.
Далее в README предлагается выполнить настройку для первого запуска:
$ periphery scan --setup Welcome to Periphery! This guided setup will help you select the appropriate configuration for your project. * Inspecting project... Select build targets to analyze: ? Delimit choices with a single space, e.g: 1 2 3, or 'all' to select all options 1 AppKitBridge 2 Muse 3 Muse Integration Tests 4 Muse Tests 5 MuseShare 6 SparklePlugin ...
Очень простая настройка, сплошное удовольствие! Я выбрал нужные мне цели, затем схемы. Далее он спрашивает о коде Objective-C, и я выбрал «Да», чтобы предположить, что используется код obj-c. В Muse его совсем немного, но некоторые взаимодействия с UIKit или AppKit все равно происходят на Objective-C.
Assume Objective-C accessible declarations are in use? ? Declarations exposed to the Objective-C runtime explicitly with @objc, or implicitly by inheriting NSObject will be assumed to be in use. Choose 'No' if your project is pure Swift. (Y)es/(N)o > y
Далее он предположил, что все public
объявления используются — что было бы очень полезно при создании фреймворка или библиотеки, но для приложения вроде Muse я ответил «Нет».
Assume all 'public' declarations are in use? ? You should choose 'Yes' here if your public interfaces are not used by any selected build target, as may be the case for a framework/library project. (Y)es/(N)o > n
Наконец, я сохранил конфигурацию в .periphery.yml
и запустил первое сканирование. К счастью, оно показало, что кодовая база чиста до безобразия! 😉
Я использую Sourcery для автоматической генерации некоторых файлов коннекторов между кастомной кодовой базой синхронизации Muse и кодовой базой приложения Muse. Также в кодовой базе осталось довольно много старого кода CoreData, чтобы очень старые библиотеки Muse можно было перенести в современный мир синхронизации. Для них мне не нужно, чтобы они были включены в вывод Periphery.
Чтобы удалить их, я использовал параметр командной строки --report-exclude
, чтобы удалить несколько путей, которые мне не нужны в отчете. Меня также не волнует избыточные public
, поэтому я включил опцию
--disable-redundant-public-analysis
. Наконец, меня не волнуют неиспользуемые параметры функций, поэтому я использовал --retain-unused-protocol-func-params
. Я запустил с параметром --verbose
, который показал изменения в конфигурации .yml, которые мне нужно было сделать, чтобы всегда запускаться с этими исключениями.
Наконец, я настроил цель Aggregate в Xcode, чтобы можно было запускать Periphery и видеть неиспользуемый код в навигаторе Issue. Я обновил настройки сборки, чтобы использовать iOS, добавил параметр User Defined для SUPPORTS_MACCATALYST=YES
и добавил фазу Run Script со следующими параметрами:
export PATH="$PATH:/opt/homebrew/bin" if which periphery >/dev/null; then periphery scan --config "${SRCROOT}/.periphery.yml" else echo "warning: periphery not installed, install from https://github.com/peripheryapp/periphery" fi
Теперь при построении агрегированной цели Periphery в Xcode я могу видеть весь неиспользуемый код прямо в Xcode.
Осталось только навести порядок!