Как стать автором
Поиск
Написать публикацию
Обновить
31.91
Тензор
Разработчик системы Saby

Анатомия техдолга. Излечим ли пациент?

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров1.5K

Привет, Хабр! Меня зовут Евгений Старков, и я, как и вы, часто сталкиваюсь с техдолгом.

Пришло время рассказать, как я с ним справляюсь! Проблема не нова и встречается в любой компании, связанной с разработкой. Мне, по большей части, техдолг достался «в наследство». Первой задачей в Тензоре было разделение и рефакторинг большой части кодовой базы своей группы. Там попадались и суперклассы, и файлы с количеством строк, перевалившем далеко за 1000, и именование переменных по типу a, b, c.

Когда увидел кодовую базу, которая теперь твоя
Когда увидел кодовую базу, которая теперь твоя

Не так давно в мое владение перешел еще один функционал, в котором я снова столкнулся с данной проблемой. Пусть этот модуль станет пациентом, а я выступлю в роли терапевта для программного кода. Для начала давайте поймем – что такое технический долг?

Как я себя чувствовал, когда занимался данной задачей
Как я себя чувствовал, когда занимался данной задачей

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

Но мой пациент неживой, он не сможет напрямую сказать, что у него болит. Да и если у человека с его анатомией на каждую часть присутствует свой доктор, то в анатомии кода и долга специалист один – программист. А значит мне и решать все проблемы его частей. Выделим несколько из них:

  1. сам код (качество, стиль, чистота)

  2. исполнение в рантайме (скорость, оптимальность)

Соберем анамнез. Посмотрим, как было и потом сравним, спасли мы пациента или наоборот, сделали так, что он быстрее уйдет на покой.

Распилим пациента и посмотрим, что у него внутри
Распилим пациента и посмотрим, что у него внутри

Начнем с кода. Как выявить болячки здесь? Проведем диагностику. А в этом нам помогут линтеры, для предварительного диагноза. Начнем с pylint и проверим качество написания кода:

Плохо, но не критично. Тут в файлах заметно, что часть симптомов решили скрыть, отключив линтер:

Мы хотим знать объективную правду, срываем маски и видим, что пока сделали только хуже:

Начнем лечение того, что выявили:

  1. Один файл больше 1000 строк (1847). Решим немного позже, так как можем полечить его, избавившись от других.

  1. Дублирование кода, порой даже в пределах 100 строк. Вот пример:

Плюсом еще такое условие в 2х местах. Выносим в функцию и заменяем:

Создали отдельную функцию
Создали отдельную функцию
И используем уже ее
И используем уже ее

Подобным образом делаем для других повторов. Всего проблем с дублями 15 шт. Файл большой, поэтому выносим такие куски в отдельный файл, который будет хранить вспомогательный функционал. Мы избавились почти от 450 строк.

Результатом трудов стало улучшение состояния - мы делаем коду лучше.

  1. Следующая проблема – использование форматирования строки, вместо f-строк. Данная проблема появилась по причине развития языка и ярко отображает то, что идеальный код со временем может приобрести проблемы. А таких у нас 87.

Эти ошибки исправить просто – меняем формат на f-строку.

  1. Константы, шаблоны запросов и исключения затеряны в самом коде.

Это уменьшает читаемость. Все выносим в отдельные файлы.

  1. Большое количество ветвлений, принимаемых и неиспользуемых аргументов.

Большие функции на 200+ строк. По возможности избавляемся от ветвлений: одну из функций пришлось сделать классом (чтобы уменьшить ветвление), упростить сам код и сделать его лаконичней.

Теперь наш код здоров:

Как я себя чувствовал
Как я себя чувствовал

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

Поэтому назначаем еще одну диагностику, а именно mypy, и видим следующую картину:

Исправляем, правим типы или добавляем их, так же типизируем принимаемые параметры в функциях и получаем уже приятную глазу картину:

Теперь и читать приятно, и mypy не ругается
Теперь и читать приятно, и mypy не ругается
А ты юзаешь подсказки типов?
А ты юзаешь подсказки типов?

Но откуда же взялись эти проблемы?

Основные причины появления технического долга:

  1. низкая квалификация сотрудников и отсутствие надзора за их исполнением;

  2. отсутствие стандартов написания кода, проектирования функционала;

  3. отсутствие контроля за соблюдением правил, стилистики и архитектуры;

  4. жесткие временные рамки;

  5. плохая взаимосвязь или ее отсутствие между бизнесом и разработкой;

  6. ошибки проектирования или его отсутствие;

  7. изменения требований внутри компаний или переход на новый стек технологий, иногда, обновление сторонних библиотек.

Теперь само написание кода проблем не имеет, но пациент все равно нам всеми силами намекает: «что – то не так!». Простая задачка им выполняется слишком долго, как будто он делает много лишнего.

Идем смотреть, как все работает и видим эти симптомы.

Наш запрос выполняется очень долго, больше половины времени работы всего функционала. Смотрим план, ищем проблему. Оказалась, что нам нужно прочитать несколько записей (часто не больше 10), а мы вычитывали всю базу с кучей Join`ов и фильтраций. Добавляем условие для фильтрации по конкретным идентификаторам и получаем:

После правок SQL запроса
После правок SQL запроса

То есть прирост составил больше 95% во времени и сам запрос теперь занимает не больше 10% тайминга работы всего метода.

Но теперь у нас есть трата временного ресурса на работу языка, занимающая больше 500мс или почти 70% рабочего времени.

Начинаем смотреть и видим не оптимальность.

Здесь начинаем перебор записей и сборку из них другой записи с медленным методом Set, который рекомендуется использовать для установки одной записи. Переделаем на лучший вариант:

Пример локальный, но хорошо демонстрирует суть оптимизации
Пример локальный, но хорошо демонстрирует суть оптимизации

Массовое присвоение полей работает куда быстрее. Второй вариант схож с данной ситуацией, но усложнен тем, что перебор ведется в 2х циклах, которые можно было избежать. И вот видим хорошую картину:

Теперь среднее время работы составило не 1800мс, а всего лишь 160мс. То есть мы получили прирост в скорости больше чем на 90%.

Пациент спасен и теперь гордо трудится на радость клиентам, но таких как он, еще много.

Я справился!
Я справился!

Почти все ИТ-компании имеют технический долг, но не у каждой есть с ним сложности. Где же эта тонкая грань?

Данный вопрос становится проблемой, когда он либо бесконтрольный, либо проценты уже слишком высоки. «Долговая яма» очень сильно влияет на вовлеченность команды, особенно в случаях, когда данный код достается «в наследство». Сопровождение такого кода становится тяжелой, а иногда и невыполнимой задачей. Отсюда вытекают негативные последствия:

  1. Большие временные затраты

  2. Сложность внедрения новыx фич, которые могут увеличить сам долг.

  3. Снижение мотивации команды и общей комфортной среды внутри.

  4. Выгорание и отсутствие интереса.

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

Существуют и другие способы уменьшения долга:

  1. Стабильная реструктуризация и рефакторинг – создание небольших задач на оптимизацию, выделение времени в процессе доработок и внесение нового функционала.

  2. Приоритетность – вытекает из прошлого пункта. Если затраты времени неимоверно высоки, то в приоритете исправить ситуацию, нежели добавить новых фишек и, тем самым, увеличить %.

  3. Внедрение ревью (желательно многоступенчатого), стандартов написания и стиля кода, развитие команды и совместное обсуждение, встречи. Внедрение систем автоматической проверки кода.

  4. Разработка ТД, схем процессов, данных и архитектуры в целом. Помогает выявить проблемы на основе визуализированных и технических данных. Отличный вариант – проектирование полного бизнес-процесса на этапе создания функционала поможет избежать проблем в будущем при определённом уровне команды, поддержка актуальности документации позволит «новичкам» (не только уровень программирования, но и просто новая команда или сотрудник) вникнуть в процесс быстрее и проще. Но данный способ является больше утопией в современной разработке, чем повседневностью.

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

Подведем итоги

Сам долг не всегда является проблемой или чем-то плохим, он будет всегда. Но мы можем приложить определенные усилия для того, чтобы уменьшить его или избежать в будущем.

Вот и всё. Буду рад здравой критике и ярым обсуждениям.

Теги:
Хабы:
Всего голосов 11: ↑10 и ↓1+13
Комментарии3

Публикации

Информация

Сайт
saby.ru
Дата регистрации
Дата основания
Численность
5 001–10 000 человек
Местоположение
Россия