Что такое легаси в программировании

Добавил пользователь Дмитрий К.
Обновлено: 08.08.2024

Недавно у нас вышел подробный материал о том, что такое статические сайты. Вот короткая версия:

  • На статических сайтах вся информация представлена в виде уже готовых документов, словно отлитых в бетоне.
  • По запросу сервер моментально отдаёт уже готовую страницу, поэтому такие сайты работают очень быстро.
  • По сути, такой сайт — это просто набор HTML-файлов, каждый из которых отвечает за отдельную страницу.
  • Такие сайты просто хостить и переносить на другой сервер и сложно взломать, потому что там нечего особо взламывать.

Есть три способа сделать такой сайт:

Пропаганда действий, описанных в п. 3, запрещена на территории РФ статьёй 6.21 КоАП, а вот п. 2 очень даже инновационный, нанотехнологичный, и программисты вас за него не поругают. Поэтому сегодня речь о генераторах статических сайтов.

Принцип работы

Чаще всего в основном генераторы сайтов работают по такому принципу:

  1. С одной стороны лежит контент. Это могут быть десятки и сотни текстовых документов, размеченных каким-то образом.
  2. С другой стороны лежат шаблоны — это правила, по которым оформляются страницы. Например, может быть шаблон для главной страницы, шаблон для статьи, общий шаблон для шапки сайта и подвала.
  3. Собственно, генератор берёт контент, преобразовывает его в HTML, вклеивает в нужный шаблон, сохраняет как HTML-файл, обвязывает всё навигацией и аккуратно укладывает получившуюся массу HTML-файлов в папочку.
  4. Всё это до ужаса быстро.

Это маркдаун (скорее всего)

Большая часть генераторов статики просят, чтобы контент им давали в разметке Markdown. Это такая технология работы с текстом, когда для обозначения разных частей текста используются не HTML-теги, а простые символы:

Ещё Markdown умеет так же понятно вставлять ссылки, картинки, добавлять примеры кода и оформлять таблицы. Получается, что таким образом мы можем быстро разметить наш документ так, чтобы он остался читаемым для человека и был понятен любому Markdown-редактору.

На примере

Допустим, у нас есть такой документ с разметкой:

Это простенький Markdown: заголовок выделен решёткой, ссылка — скобками

Это простенький Markdown: заголовок выделен решёткой, ссылка — скобками

Когда мы отдадим этот файл генератору статических сайтов, вот что он сделает:

В результате работы генератора у нас получится такой код:

А вот как это будет выглядеть в браузере, когда мы откроем готовую страницу. Шаблончик пока что максимально простой, но при должном рвении ничто не помешает нам сделать его более изощрённым:

Что такое статические сайты

Что такое статические сайты

Плагины

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

Например, плагины могут добавить:

  • поддержку тегов и ключевых слов для страниц,
  • галерею для картинок,
  • кнопки соцсетей и так далее.

Зачем это нужно

Идеальное применение генераторов статики — для сайтов, где должно быть много контента, который редко меняется и который пишут отдельные люди. Например, для сайтов службы поддержки, справочников, энциклопедий, электронных книг. Как тогда будет устроен процесс:


Автор — Николас Карло, веб-разработчик в Busbud (Монреаль, Канада). Специализируется на легаси. В свободное время организует митап Software Crafters и помогает с конференциями SoCraTes Canada и The Legacy of SoCraTes.


В своей книге Майкл пишет своё определение:

Почему Физерс так считает? Потому что по его многолетнему опыту без тестов обычно трудно узнать всё, что код умеет. Если тестов нет, то для понимания, что код делает, вам нужно внимательно его прочитать, воспроизвести программу в своей голове и представить все возможные сценарии. Потом вы поменяете код и нужно снова представить все сценарии. Или проверить их вручную, но всегда есть шанс что-то сломать.

Это хорошее определение: чаще всего тесты отсутствуют, так что это хорошее начало. Но это ещё не всё — есть нюансы.

Код с тестами также может быть легаси. Если вы читаете тесты, но не можете понять, что должен делать код — они отстой. Плохие тесты только мешают: тестируемый код так же трудно отрефакторить, как если бы у него не было тестов, а может даже и сложнее!

Тестов может и не быть, но код всё ещё легко можно отрефакторить. Возможно, вы поддерживаете небольшую кодовую базу без тестов, которую легко понять и рефакторить. Хотя, по моему опыту, это аномалия. Эту кодовую базу можно было бы проверить, но отсутствие автоматизированных тестов всё же не позволяет квалифицировать его как легаси.

Перейдём к моему определению легаси.

Легаси — это ценный код, который вы боитесь менять.

Например, мы ищем первопричину ошибки или выясняете, куда вставить свою функцию. Мы хотим поменять код, но это трудно, потому что непонятно как не нарушить существующее поведение. Готово — у нас легаси!

Мы переоцениваем сложность незнакомого кода. Поэтому мы думаем, что код, который писали не мы — устаревший. Это работает и с нашими прошлыми проектами, когда мы не можем понять, что закладывали и имели в виду, когда писали эту мешанину на экране.

Хорошие тесты помогают легко менять незнакомый код. А плохие тесты не помогают. Отсюда и определение Физерса.

С легаси помогает время. Парадоксально: обычно время превращает любой код в легаси, но чтобы его понять нам также помогает время. Если вы начали работать над легаси и это трудно — подождите. Да, большая часть кода ужасна, но вы привыкнете и лучше поймете его причуды и особенности.

Легаси не виновато в том, что оно такое. Большая часть кода ужасна, потому что это результат работы многих людей в течение долгого времени с противоречивыми требованиями и под давлением дедлайнов. Это Рецепт Устаревшего Кода™. Когда мало времени и недостаточно знаний — рождаются костыли (ну вы знаете). В конце концов, мы достигнем состояния, когда каждое движение приводит к ошибке, а реализация любой функции занимает целую вечность.

А теперь один из важнейших нюансов.

Легаси — это код, который мы изо всех сил пытаемся понять, чтобы поменять.

В итоге мы получаем, что легаси это:

который мы пытаемся понять, чтобы отрефакторить;

Как же эффективно работать с легаси?

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

Добавить тесты, а затем внести изменения

Но чтобы запустить тесты, мы должны поменять код. Возникает парадокс легаси. Мы обречены? Нет. Поменяем как можно меньше кода для тестов:

Первые два пункта самые сложные, а как только доберёмся до тестов, мы знаем, что делать.

Есть и другие виды швов. Если язык позволяет изменять поведение кода без изменения исходного кода, у нас есть точка входа в написание тестов. Кстати о тестах…

Напишем unit-тесты

Чтобы избежать путаницы, Майкл даёт четкое определение того, что такое НЕ unit-тест:

он не работает быстро (< 100ms / test);

он взаимодействует с инфраструктурой, например, базой данных, сетью, файловой системой, переменными;

Напишите максимум тестов, которые обладают этими 2 качествами, при этом неважно, как вы их назовёте.

Иногда трудно написать такие тесты, потому что не понятно, что код должен делать. Тогда используйте специальную технику.

Тесты для определения характеристик

Это тесты, которые формализуют фактическое поведение части кода.

Вместо того чтобы писать комплексные модульные тесты, мы фиксируем текущее поведение кода — делаем снимок того, что он делает. Тест гарантирует, что это поведение не изменится!

Это мощная техника, потому что:

В большинстве систем то, что код делает важнее того, что он должен делать.

Мы можем быстро покрыть легаси с помощью этих тестов. Так мы подстрахуемся для рефакторинга.

Но обычно на всё это очень мало времени.

Когда совсем нет времени на рефакторинг

Несколько советов, если предыдущие не подходят.

Это всего лишь 3 if: тяжело себя убедить, что нужно потратить на них 2 дня, хотя и должны. Что делать, если действительно нет времени писать тесты для этого класса? Используйте техники Sprout (прорастание), Wrap (обёртывание) и скретч-рефакторинг.

Sprout

Напишите код в другом месте, сделайте один тест, определите, где вы должны вызвать этот код из существующего кода (точка вставки), и вызовите свой код из легаси.

Рассмотрим на примере:

Переименуем старый метод, который хотим обернуть.

Создадим новый с тем же именем и подписью, что и старый.

Вызовем старый метод из нового.

Поместим новую логику до/после вызова другого метода.

Ещё один способ решить эту проблему — это обернуть её, поэтому мы переходим к postEntries(), списку записей, из которых мы удалили дубли.

В тестах мы бы изменили проблему postEntriesThatAreUnique(), чтобы проверить, работает ли логика удаления дубликатов. Разница может быть ещё больше.

Эти методы не идеальны, и у них есть недостатки. Но это полезные инструменты при работе с легаси. А при необходимости можно даже немного нарушить правила.

Скретч-рефакторинг

Выводы

Похожие и интересные статьи:

О том, над чем в целом мы тут работаем: монолит, монолит, опять монолит.

Кратко об истории Open Source — просто развлечься (да и статья хорошая).

Больше новостей про разработку в Додо Пицце я пишу в канале Dodo Pizza Mobile. Также подписывайтесь на чат Dodo Engineering, если хотите обсудить эту и другие наши статьи и подходы, а также на канал Dodo Engineering, где мы постим всё, что с нами интересного происходит.

А если хочешь присоединиться к нам в Dodo Engineering, то будем рады — сейчас у нас открыты вакансии iOS-разработчиков (а ещё для Android, frontend, SRE и других).

Legacy-код – это большое НЕТ


Хотя, кто я такой, чтобы нести подобную чушь? Я никогда не поддерживал большой проект с кучей заинтересованных сторон и саппортом, который развивается супермедленно и делает всех счастливыми. Насколько долго он делается и как работает не важно, ведь потенциально он может работать в 100 раз безопасней и в 1000 раз быстрее, верно? Не совсем. Моим самым большим ребенком был сайт крупного издателя со сложным бекендом на ZF1.

Если вы когда-нибудь делали проекты на ZF1 , то знаете, этот фреймворк — вихрь из костылей и анти-паттернов. Когда приложение начало показывать признаки ухудшения из-за увеличения трафика, я перестроил фронтенд наиболее интенсивно используемой части приложения полностью на работу через ajax и вызовы API. Нагрузка резко упала и этим мы купили себе достаточно времени для переноса всех остальных частей приложения на Zend Framework 2 . Тем, кто делал что-то подобное известно, что это все та же смесь из костылей и анти-паттернов, но чуть менее плотная.

Я пытаюсь сказать, что большие изменения и рефакторинг может произойти лишь в том случае, когда за ними стоят способные люди. Если все что вы делаете — это сплошные agile-митинги и мозговые штурмы, то никакое количество LTS контрактов не может помешать вам глупо выглядеть в течение пяти лет.

Даже если вы делаете бесплатную и/или open source работу, конечно же вы не должны ломать совместимость для X-1 пользователей. Делая им одолжение, развивая старые версии, при глобальном обновлении вы можете столкнуться с потенциальной потерей обратной совместимости. Просто усвойте одну вещь — они должны либо приспособиться, либо умереть.

Так все же почему мы должны изгнать legacy-код из современных систем?

Бесконечное LTS проклятие


Эти пользователи — мертвый груз, они должны быть уничтожены вне зависимости от того сколько денег они вам приносят. Дайте им возможность перехода и двигайтесь дальше, если они способны, то догонят вас. Если же нет, то они того не стоят.

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

Вы отчуждаетесь и негативно влияете на продвинутых пользователей

В последний раз я сталкивался с отчаянным legacy-кодом, когда устанавливал CMS , что оказалось очень трудным занятием в среде Vagrant — не только из-за проблем с symlink , которые сейчас широко известны всем (даже создателю Vagrant ), но и с тем, что многие оставляют устаревшие версии CMS , т.к. часть модулей/плагинов еще не выпустили свои обновления. Раз нет обновлений модулей, то к чему обновлять ядро? Зачем торопить события, если ты к ним не готов?

Оставляя legacy-код в новой версии, вы в конечном итоге получаете монстра Франкенштейна, который вроде как по-прежнему работает, но плохо, и новый код, имеющий потенциал, не может его развить из-за беспорядка в унаследованной кодовой базе. Такой подход хоть и делает работу компаний-разработчиков, которые все еще застряли где-то в 90-х, проще, но в тоже время продвинутым пользователям становится сложнее работать с продуктом. Решениями, принятыми для толпы, которая уже давно и безнадежно отстала от технологий, вы отчуждаете и негативно влияете на продвинутых пользователей, способных принести гораздо большие деньги.


Вы же знаете как это бывает: тратите слишком много времени на поддержку функционала в устаревших браузерах, а в итоге никто из пользователей даже не пользуется этими фичами. То же самое касается и пользователей библиотек или систем управления контентом — тех, кто не заботится об устаревшей CMS , не волнует, что вы делаете в новых версиях, так что не парьтесь с черезмерной поддержкой старых версий больше, чем это нужно в реальности.

Неудачи иногда предвещают успех


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

Приложения vs Библиотеки/Пакеты


Библиотеки, получившие бамп X+1 , должны четко следовать пути к прогрессу — с момента, когда ваша версия библиотеки стала публично доступна, поддерживайте только багфиксы последней.

Приложения, которые используют такие библиотеки, находятся в более сложной ситуации из-за их зависимости от API, которые, возможно, могут измениться. Разумный подходом будет ждать отзывов из комьюнити о стабильности, прежде чем начать переход. В течении переходного периода, как старая, так и новая версии библиотеки/фреймворка могут оставаться в использовании, и после того, как все необходимые части будут модернизированы, старая версия должна быть удалена. Ведь это не займет много времени, правда?

Не бывает достаточно большого приложения

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

Схема обновления

Как правильнее всего обновляться? Есть только один приемлимый вариант обновления программного обеспечения, которого должны придерживаться разработчики независимо от популярности их приложения/библиотеки:

  1. Создайте новую ветку для новой версии
  2. Пометьте старую версию/ветку как deprecated
  3. Публично заявите, сколько вы еще будете поддерживать старую версию
  4. Предупредите всех пользователей старой версии
  5. Внедряйте новые функции ТОЛЬКО в новой ветке, в старой — багфиксы
  6. Когда время жизни старой версии истечет, обрывайте все концы. Не исправляйте, не советуйте, вообще удалите упоминание о старой версии из документации. Убейте ее.

Один из проектов, следущий этому пути — Guzzle. У него есть 3+ версия и 4+, для тех, кто хочет жить в ногу со временем и всегда быть на пике прогресса.

Вывод

Как веб-разработчик, я твердо уверен, legacy-код должен быть выброшен, когда речь заходит о новых фичах или мажорном обновлении версии. Если у вас есть большой проект, которое использует код версий, вышедших два или более месяцев назад, то вы должны прекратить все действия с ним и переписать под свежую версию, особенно, если продукты, которыми вы пользуетесь, критически важны для бизнеса. Нет в мире достаточно больших приложений, которым нужно более двух месяцев для полного перехода, а если и есть, то они должны быть переписаны с нуля — веб намного проще, чем вы всегда предполагали.

А что думаете вы? Следует ли legacy-код хранить неограниченное время? Определенное число версий? Возможно не все? Как вы относитесь к legacy-коду в сторонних проектах? Должен ли разработчик волноваться о проблемах с legacy в библиотеках, которыми он пользуется? Ошибся ли я в этой статье? Данным постом я хотел начать дискуссию об этом — в конце концов, мои взгляды на проблемы и переживания — лишь моя точка зрения. Дайте знать в комментариях ниже.


  1. TDD — то есть тесты ДО кода.
  2. Чистый код (и чистые тесты).


— С чистым кодом понятно. А при чём тут TDD? Код без багов — это ведь не то же самое, что хороший код?

Все думают, что TDD — это про тесты, а значит, это скучно.
Ерунда!
TDD — это про разработку (test driven DEVELOPMENT). Это способ создания кода таким, чтобы он был НЕ legacy. Таким, чтобы его было возможно поддерживать: отлаживать, исправлять, рефакторить, дорабатывать. На данный момент это единственный известный человечеству способ. Всё остальное — от лукавого, не дайте себя обмануть.

— Есть мнение, что TDD — для слабаков, а сильным разработчикам достаточно просто хорошенько пораскинуть мозгами и продумать код заранее. Тогда и багов не будет.

— В продолжение разговора о тестировании — на ваш взгляд, какие тесты корректны и в каких ситуациях, например, юнит-тесты?

Начнём с юнит-тестов. Они необходимы в каждом проекте, тут без вариантов.

Конечно, важны и остальные виды тестов: интеграционные, UI, тесты производительности. Это уже в разных проектах по-разному. Важно одно: их должно быть на порядок меньше, чем юнит-тестов. Про пирамиду тестирования все в курсе, надеюсь.

Безусловно, нужно стремиться к максимальному покрытию. Все эти разговоры про 30% или 70% покрытие — от непонимания. Надо стремиться к 100% (хоть это и недостижимый предел).

— Сколько времени нужно уделить созданию юнит-тестов, и на каком этапе проекта они играют ключевую роль?

Если делать всё правильно, вы никогда не сможете ответить на вопрос, сколько времени занимает написание юнит-тестов. Это часть разработки. Никто же не спрашивает, сколько времени занимает намазывание кирпича раствором, а сколько — укладка. Это всё необходимые шаги, и всё тут. Нельзя выкинуть один из них, иначе твоя стена развалиться на второй день, и ты получишь кучу legacy-кирпичей.

— Как у вас выглядит процесс написания тестов?

Ты пишешь красный тест 10 минут, делаешь его зелёным 10 минут, рефакторишь 10 минут. Никто, конечно, не замеряет это время точно — иногда это 5:30:0, а иногда 180:5:60. Неважно. Важно, что ты с таким же темпом, с предсказуемой скоростью сможешь менять код и через месяц, и через год. Постоянная скорость в долгосрочной перспективе гораздо важнее высокой мгновенной скорости на старте.


— Андрей, если TDD так полезен, почему его так мало используют?

Всё просто. TDD — это дисциплина. Это как спорт: все знают, что спорт полезен, но ленятся. Самые честные признают, что им лень, остальные находят отговорки, а особо отъявленные начинают придумывать объяснения, почему спорт, оказывается, даже вреден. Так же и с TDD.

Забавная разница в том, что люди, лежащие на диванах, не называют себя спортсменами. Тут всё честно. А кодеры не пишут тестов и при этом называют себя разработчиками. Невероятно, правда? Но заканчивается это всегда одинаково. Спортсмен, пропускающий тренировки, быстро проигрывает соревнования. Так же и код, написанный не через тесты, моментально становится legacy. Тут всё честно.

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

TDD — это теорема, которую надо доказывать каждый день.

— Мы обсудили вопросы, касающихся покрытия тестами. Важно затронуть и другие проблемы legacy, например, совместимости. Встречаются проекты, где код не изменяют ради совместимости с еще более древними библиотеками. Если проводить аналогии с автомобилестроением, вам не кажется, что попытки использования устаревших узлов и агрегатов в новых конструкциях — губительны, так и средний уровень кода в проекте должен соответствовать ожиданиям времени?

Тут нет единого ответа. Можно ежедневно обновлять все зависимости и относиться к этому как к необходимой гигиене. Можно даже попросить Maven или Gradle делать это автоматически. А можно сделать fork оригинальной библиотеки и сидеть двадцать лет на старой версии. Пожалуй, это зависит от зависимостей. Если я сильно завишу от Selenium, использую новые фичи, то я его часто обновляю. Если я никак не завишу от новых фич log4j, я сижу на древней версии. Всё ж работает.

Так что не всё то новьё, что обмазано солидолом.

— В вашей практике встречались подобные ситуации (дополнительно к предыдущему вопросу)? Как вы выходили из подобных ситуаций? Какой стратегии вы придерживаетесь, переписать всё (часто используется термин — greenfield) или сделать рефакторинг?

Насчёт greenfield я довольно скептично настроен.
Конечно, плох тот солдат, который не мечтает всё переписать с нуля.
Но я за всю свою жизнь ни разу не видел, чтобы систему переписали с нуля и стало лучше. Обычно получается так же или хуже. Переписывальщик начинает с большим азартом, потом сталкивается с одной проблемой, с другой; понимает, что уже не успевает… Оставляет технический долг в одном месте, в другом — и вот у вас уже legacy-код в новом проекте, хотя ещё и половины-то не написано.

Чтобы что-то переписать с нуля, у вас должно быть очень чёткое понимание, как именно и засчёт чего вы сможете сделать лучше. И почему у ваших предшественников это не получилось.

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


— Как вы думаете, legacy-код может тормозить развитие всей системы?

Конечно, может! И тормозит!
Собственно, это самое главное, что обычно тормозит. Каждое следующее изменение вносить всё сложнее, риск что-то сломать всё больше.

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

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

Чинить legacy-код — безусловно, крайне полезное упражнение. Отлично прокачивает скиллы аналитического мышления, рефакторинга и понимание хорошего кода. Как упражнение — советую.

Поэтому если вы чините legacy-код, всерьёз надеясь улучшить что-то в проекте — удачи, здоровья и хорошего настроения. Что-то где-то подпилите, но по большому счёту ничего не изменится. Это тот самый случай, когда надо лечить на симптом, а болезнь. Не прыщик выдавливать, а идти на улицу бегать. Разберитесь, в чём на самом деле проблема. Почему у вас в команде пишут плохой код? Люди слишком спешат? Не понимают архитектуру? Конфликтуют между собой? Не умеют договариваться? Всё это я встречал в реальных проектах с умными взрослыми людьми. И вот это надо лечить, а не переменные переименовывать.

— Вы придерживаетесь мнения, что красота кода — это ещё не показатель legacy-статуса?

— Можно ли утверждать, что нарушение стандартного соглашения по оформлению кода — это legacy?

Стандартные соглашения полезны, но не стоит их переоценивать. Любые соглашения о коде становятся legacy ещё быстрее, чем сам код. Их же никто никогда не читает. У лебедя, рака и щуки были верёвки стандартной длины — и сильно им это помогло?

И не стоит ради них тратить свои силы. Настройте один раз IDE всех участников проекта, чтобы она сама форматировала код как надо, и больше не думайте об этом.

— В рамках legacy мы обсудили вопросы тестирования, производительности, зависимостей в проектах, красоты кода и затронули тему развития. Ваше мнение о legacy-коде и причинах его возникновения не менялось с течением времени?

О да. О да!
Вот я тут вещаю, такой умный, про legacy-код, а у меня самого есть open-source проект Selenide, который legacy-кодом зарос по самое не моргну. Нет, он отлично работает, пользователи довольны, но мне его менять со временем всё сложнее. Есть тикеты, которые висят уже пару лет, потому что мне реально сложно их сделать. Поменяешь в одном месте — ломается в другом. Да, там есть интеграционные тесты, благодаря которым я не боюсь что-то сломать. Но от них нет помощи в том смысле, что менять-то код не получается.

Однажды я понял: ключевая проблема в том, что в этом проекте я изначально не писал юнит-тесты. Казалось, зачем тесты, если эта библиотека сама предназначены для написания тестов? Она и так будет протестирована вдоль и поперёк. А оказалось — вон оно что, Михалыч! Юнит-тесты нужны для избежания legacy-кода.

Ну я так и делаю: раз в полгода-год сажусь и переписываю какой-нибудь модуль к чертям собачьим. Поскольку это хобби, я прусь от этого. Но если б это было работой и выражалось в деньгах — стоило бы переписывать? Ох, не знаю…

—Как вам кажется, в каких оттенках стоит воспринимать legacy-код? В каких случаях оправдано его наличие?

У меня есть простой рецепт. Отвлекитесь на секунду от лямбд и скобочек и представьте себя на месте клиента. Это здорово прочищает мозги.

А знаете, что сделает самый худший механик? Промолчит. Сделает только то, что просили.

— Андрей, TDD, юнит-тесты — всё это звучит хорошо, но вы же понимаете, что для 99% наших читателей это неподъёмно в силу самых разных причин, часто от них не зависящих. А можете напоследок дать простой рецепт, как бороться с legacy-кодом?

Вы хотите рецепт, но когда я даю рецепт — проверенный, надёжный, вы говорите, что у вас нет на это времени. И продолжаете жаловаться на legacy-код. Вы что же от меня ждёте, красной пилюли — выпил, и ты уже в матрице? Не будет пилюли.

Люди как люди. Любят торопиться, но ведь это всегда было… Человечество любит простые рецепты… В общем, напоминают прежних… микросервисный вопрос только испортил их…

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

Спасибо и вам за приглашение.
А я воспользуюсь положением и приглашу всех читателей в гости к нам в Таллинн. У нас красивый средневековый город, хорошее крафтовое пиво и отличные мероприятия для айтишников, куда любой желающий может прийти бесплатно: devclub.eu

Спасибо за внимание и за терпение!


Больше интересных докладов, технических, хардкорных, вы найдете в программе Joker 2016. Если вы работаете с легаси, вам стоит обратить внимание на следующие доклады:

Что такое легаси

  1. Команда делает продукт, внутри много разных возможностей.
  2. Часть функций со временем оптимизируется, а часть остаётся неизменной в виде старого кода, потому что и так работает.
  3. Некоторое время спустя в команде не остаётся тех, кто писал старый код.
  4. Текущая команда не знает, почему старый код написан именно так.
  5. В этих кусках сложно что-то поменять или разобраться, потому что всё остальное написано уже по-другому.
  6. Этот старый код, который сложно поддерживать и сложно разбираться — это и есть легаси.

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

Откуда берётся легаси

Причин появления легаси может быть несколько:

  • команда перешла на другой фреймворк, но части программы остались на старом;
  • часть программы написана на старой версии языка;
  • старая команда не задокументировала свой код;
  • код написан в одном стиле, а команда давно перешла на другой стиль программирования.

Легаси — это не какое-то преступление, а часть жизни любой живой ИТ-компании. Рано или поздно у любого продукта появится легаси. И чем крупнее проект, тем больше его будет. Например, в исходном коде Windows 10 до сих пор остаются фрагменты кода, написанные ещё 20 лет назад для Windows 3.1.

Легаси — это плохо?

Легаси — это просто старый код, который нужно поддерживать наравне с новым. Если он работает — отлично, пусть живёт. Другое дело, что команде, например, было бы удобнее, чтобы код был написан не на старом фреймворке, а на новом, который знают все.

Получается, главный минус легаси-кода не в том, что он работает плохо, а в том, что его неудобно поддерживать.

Например, в старом коде для запроса к серверу идёт сначала адрес, а потом номер запроса. Спустя 10 лет требования сервера изменились, поэтому сначала должен идти запрос, а потом уже адрес. Значит, нужно изменить порядок полей в коде.

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

Что делать с легаси-кодом

Если легаси-код работает и не требует вмешательства и поддержки — то можно пока ничего не делать, пусть работает. Будет время — перепишем на новый фреймворк, а если нет, то и так пока поработает.

Читайте также: