Когда у вас появляется свободное время, всегда полезно провести рефакторинг. Не правда ли?

Недавно занимался рефакторингом основного функционала приложения. Это музыкальный проигрыватель с множеством функций, таких как перекрестное затухание треков, специальные звуковые эффекты во время воспроизведения, обрезка песен, пауза после песни и возможность воспроизводить песни только на одном устройстве за раз. Также источник музыки может отличаться для разных песен, включая локальные, размещенные и Spotify (или, возможно, даже Apple Music в будущем). Есть несколько мелких проблем, которые нужно исправить, и мне пришлось провести рефакторинг в основном из-за функции Spotify.

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

1. Подумайте еще раз, что вам нужно.

Я начал с создания модуля и размышлений о фреймворках / внешних зависимостях, которые необходимы для работы плеера. Вот что мне действительно было нужно:

  1. AVFoundation, для поддержки локальной и размещенной музыки, а также воспроизведения звуковых эффектов
  2. Spotify-iOS просто очевидный выбор библиотеки для воспроизведения музыки из Spotify
  3. RxSwift, не требуется для его работы, но лично мне нравится реактивное программирование, и это упрощает некоторые задачи.

И это все! Не так уж и много, правда? Пришло время для второго шага.

2. Используйте протоколы вместо реализаций.

Опять же, правило простое: напишите протоколы, чтобы определить свои потребности, оставив реализацию другим модулям или абстракциям. Чтобы заставить работать модуль плеера, я закончил около 20 протоколов.

Но на мой взгляд, это нормально. Я разделил такие задачи, как предоставление URL, авторизация, сеанс отдельного устройства, аналитика, отчетность и многое другое, для других модулей, поэтому игрок несет ответственность только за воспроизведение и использование этих функций. Также модуль плеера ничего не знает о моделях и JSON. Поступая так, вы можете сосредоточиться на том, что хотите реорганизовать, не перемещая все остальное. Определив протоколы, вы также получите тестируемость, что очень важно.

3. Удалите код запаха.

Шаг третий: удалите код запаха. Для этого сначала мы должны ответить на вопрос, что такое код запаха? Для меня это патч, который вы применили, чтобы что-то работало, не задумываясь над этим. Но чтобы было понятно, вот лишь несколько примеров, основанных на рефакторинге проигрывателя.

public func play() {
   . . .
   isPlaying = true
   player?.play()
}

Здесь код запаха - это логический флаг isPlaying. Вам всегда следует избегать установки таких флагов. В основном из-за очень многих мест, где вы должны установить это значение true или false, и даже тогда его значение может не соответствовать фактическому состоянию игрока.

let currentItemProgress
let currentItemRealProgress
let playlistProgress
var explicitSongProgressObservable
var explicitSongProgress

Легко ли сказать, что означают эти переменные? Конечно, нет. Это действительно код запаха, и его будет трудно поддерживать в будущем.

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

4. Напишите тесты.

Фактически, после этого вы сможете понять всю логику модуля / функции. Всегда полезно показать это кому-нибудь, выпить чашку кофе и немного поговорить об этом, спросить коллегу, понимает ли он это полностью и правильно. Но, на мой взгляд, даже если он это сделает, остается еще один шаг: тесты.

Написание тестов в конце концов, вероятно, вызовет еще один рефакторинг (наверняка меньший, чем исходный). Во время рефакторинга плеера и написания тестов с охватом 75% я реорганизовал один и тот же код примерно три раза, но теперь он довольно ясен и прост для понимания, и, конечно же, он работает должным образом.

Это действительно небольшая статья, но я думаю, что очень важно время от времени реорганизовывать код, когда он начинает пахнуть 🤔. Если вы можете предоставить функциональные возможности для отдельных модулей / абстракций, просто сделайте это! В конце концов, тесты являются важной частью разработки, их написание должно помочь вам охватить случаи, воспроизведение которых на устройстве занимает много времени или которые могут зависеть от некоторых сбоев API, таких как получение неавторизованной ошибки 401 при попытке воспроизведения музыки. Написание тестов также может улучшить качество вашего кода и сделать приложение более стабильным.

Оставьте аплодисменты, если вам это нравится 🙌