Фича, которую 'легко' сделать

Разработчиков передергивает, когда кто-то говорит, что фичу сделать "легко" или что фича "простая".

Можно разобрать кейс «простой» фичи на примере кликабельных таймкодов в моем приложении. Казалось бы, что тут сложного? Откуда 37 коммитов, 500 строк изменений, 173 коммента на пулл-реквесте и конфликт с СТО?

Первый камень преткновения был в том, нужно ли парсить таймкоды на бэкенде и давать фронтенду структурированный объект с таймкодами или парсить каждый раз на фронте для каждого пользователя, когда они открывают эпизод подкаста? Этот вопрос оставим в стороне, о нём я уже писал.

Мы выбрали пойти по простому пути и сделать всё на фронте. Но всё равно вышло 500 строчек кода изменений. Где мы недооценили сложность "простой фичи"?

Задача была в следующем — если видим в описании эпизода текст в формате (HH:)MM:SS, это таймкод. При нажатии на таймкод, играем эпизод с этого времени.

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

В итоге мы столкнулись с несколькими техническими проблемами, сделавшими из мухи слона:

  1. Пришлось дополнять и рефакторить виджет, который отображает описание эпизода.

    • Та-дааам... Типичная и очевидная проблема — виджет не "знал" ID эпизода, без которого не создашь ссылку. Пришлось добавлять дополнительные параметры и передавать их в виджет извне.
    • Виджет обрабатывал текст в формате HTML отдельно от неформатированного текста. В коде была развилка. Пришлось рефакторить, чтобы сначала сконвертировать любые входные данные в HTML, а потом уже обрабатывать их одним, общим способом.
  2. Пришлось рефакторить валидацию таймкодов в уже существующем модуле, который мы используем в другом месте. Там столкнулись с другими сложностями. Не хочу утомлять деталями (было связано с null safety в языке Dart), но с первого раза это не сработало, пришлось откатывать рефактор обратно и писать отдельный валидатор.

  3. Столкнулись с похожей проблемой в генерации внутренних ссылок. Пришлось рефакторить другой модуль.

  4. Пришлось измененять то, как мы открываем ссылки. Раньше все ссылки открывались во внутреннем браузере, а mailto: ссылки открывались в почтовом клиенте.

    • Таймкоды мы заменили ссылками в определенном формате и их нужно было перехватывать, чтобы открывать внутри приложения. Пришлось писать "перехватчик" (handler).
    • Так как описание эпизодов подкастов может содержать ошибки, нужна дополнительная валидация ID.
    • При нажатии на таймкод, поведение отличается:
      • Если эпизод уже играет, нам нужно просто поменять позицию воспроизведения в плеере.
      • Если эпизод не играет, нужно сначала загрузить эпизод в плеер, а потом уже поменять позицию воспроизведения.

Вот так.

Поэтому никогда не стоит говорить разработчику, что что-то "просто". Лучше спросить "как ты оцениваешь сложность?" а потом внимательно слушать.