Legacy что нужно знать о работе с чужим кодом


Оглавление (нажмите, чтобы открыть):

stokito on software

Несколько хороших и обязательных к просмотру лекций про то как разрабатывать и сопровождать старые легаси проекты.
Кстати тут нужно сказать что legacy — это переводится не просто как «наследство» а как некий дар, например когда бабушка передаёт внучке кольцо. Авторы термина хотели заложить какое-то позитивное значение ��

На эту тему почти на всех конференциях рассказывает Виктор Полищук:

Примечательна также классификация которую Виктор использует:

  • Very old projects, had been written long long ago.
  • The Highlander: Old mature projects, had been written ages ago. Optimization required.
  • Paragon: Die Hard Nobody knows why it is still alive.
  • Fashion or market victims: Nobody wants this sh%t anymore.
  • Problem Child: Nobody loves it. Sentenced Customer tired of supporting it, everything is up to you.
  • Apathetic: Nobody cares

What is usually NOT…

  • Badly written projects which are not in production.
  • Low quality designed projects.
  • Small projects.
  • Every project you don’t understand.

Виктор Полищук — Все что вы хотели знать о Legacy-коде, но стеснялись спросить

Виктор Полищук — Legacy: как победить в гонке

И этот доклад вдохновил ребят из ДатаАрта сделать свой доклад:

И продолжение «Travel, Legacy and SWAT. Q&A Session»

Презентация Michael Feather, автора книги Работа с унаследованным кодом:

Дмитрий Миндра: Refactoring Legacy Сode

Virtual JUG: Testing and Refactoring Legacy Code

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

Статья Практика рефакторинга в больших проектах в сотый раз о вечном. Для тех кто ещё халтурит и не прочёл замечательную книгу Working Effectively with Legacy Code

Небольшой конспект с добавлениями моих мыслей.
1. На легаси проекте всегда есть несколько параллельных подходов и технологий. В разное время были попытки и не всегда законченные сделать что-то правильно не выкидывая старого. Например если у вас был старый API и вы решили сделать новый — то у вас есть новый АПИ но клиенты всё равно используют старый потому что в нём были фичи которые вы в новый переносить не будете или ещё не решили как его сделать правильно. Точно также если у вас был JSF и вы решили переписать на Spring MVC то теперь у вас половина кода на Спринге и половина на JSF.
На моём текущем проекте живут одновременно чисто сервлеты, чисто JSP, JSF, JSP + Tiles, немного Velocity, Spring 3.0.7 и мы даже не можем перейти на Спринг 3.1, куча контролеров на Tapestry 4 (к которому уже даже документации не найдёшь), и Tapestry 5.0 который по сути совсем другой фреймворк и мы не можем даже переписать на Tapestry 5.3, просто потому что уже никто его не знает.
Всё это живёт одновременно и активно используется. Всё находится в полупереходном состоянии потому что пока начали переписывать и делать новые ошибки, вдруг выяснилось что чего-то сделать на новом практически невозможно и вообще уже наделали новых ошибок что уже и переписывать так пожалуй не стоит. Всё это устарело и затраты на обновление больше чем на переписывания с ноля.
Из-за версионного просака обновится невозможно. И иногда нужно просто смириться что это останется таким навсегда (привет Кобол программистам).
2. На лагаси проекте очень многое можно просто выкинуть. Очень много нуждается в оптимизации. Но как понять что можно менять а что нет? Как найти проблему? Т.е. здесь на первый план выходит и самое принципиальное это знать как используется программа: вам нужен мониторинг, вам нужно сборка и визуализация логов (logstash+elastic+kibana), или статистика юзаджей, вам нужен доступ к базе на продакшене, вам нужен доступ ко всем конфигам а то и вовсе к серверам. Насколько только это возможно. Именно с этого и следует начинать первым делом.
Допустим ты ковыряешься в коде и видишь кучу проблем связанных с тем что у вас регистрозависимые (case sensitive) логины пользователей, т.е. User и user это два разных пользователя. Потому что дальше ваша система шлёт эти юзернеймы через АПИ в другую систему которая их не поддерживает. И ты должен иметь возможность прямо сейчас посмотреть в конфигах включена ли эта возможность, посмотреть в базе как много пользователей с дублицироваными юзернеймами. Нужно погрепать логи как много пользователей столкнулось с этими проблемами.
Нужно поискать по истории ревизий кода когда добавлялся этот функционал и зачем. Нужно расспросить всех коллег кто что-то знает про это.
Т.е. на легаси проекте для того чтобы сделать какое либо изменение порой требуется настоящее и полноценное исследование, расследование, с допросами и большой археологической работой по изучения пластов кода и поиском то ишью трекеру.
Какая нибудь заброшенная страничка на Вики тебя может реально выручить. Отсюда следует следующий пункт…
3. Всё что только можно нужно записывать и потом никогда не выбрасывать. Желательно любые обсуждения и митинги потом записывать хотя бы тезисно и рассылать по почте, и её, корпоративную почта нужно беречь и лелеять. Возможно даже вам следует хранить логи и бекапы бд баз хотя бы за год. «Чем больше бумаги тем чище жопа». И не бойтесь что создаёте мусор — археологи по мусорным кучам восстанавливают знание о целых эпохах цивилизаций.
Просто поймите — даже самые очевидные для вас вещи следует записывать потому что команда совершенно точно поменяется полностью. Это всё равно что представьте что послезавтра весь ваш код, всю вики, все письма, весь репозиторий просто передадут на разработку в другую компанию.
4. На Вики писать и перечитывать\переписывать\обновлять статьи это абсолютно обязательная работа ничуть не меньшая чем писать код. Тикеты в ишью трекере периодически нужно проходить и перечитывать. Реально очень многие проблемы, уж поверьте, давно известны и даже были попытки их исправить. Это нудное занятие вам сэкономит кучу времени. Но читать их следует только после того как вы уже хоть немного разобрались с проектом, иначе вы не поймёте о чём там вообще идёт речь.
Дело в том что на легаси проекте из-за большого числа джира тикетов по закону больших чисел вы практически наверняка там точно есть практически все баги и проблемы, и вы можете достаточно точно оценить ситуацию с разными компонентами системы.
В совокупности с письмами из сапорта и логами это даёт хорошую картину на весь проект. Это важная метрика которая вам поможет вам понять размер трагедии.
5. На любом легаси проекте почти наверняка есть огромные проблемы со сборкой проекта. Обычно она не тривиальная, требуется ANT и Maven конкретной версии, собирается проект почти наверняка только под шестую джаву, требуются ручные действия. Билд долгий, тесты blinking (то падают то нет) и очень много из низ вообще отключены через @Ignore. Есть самодельно пропатченные версии библиотек. И это вам очень сильно повезёт если проект мавенизирован и зависимости вообще известны и доступны с Maven Central репозитория.
Из-за того что у вас много либ (а их наверняка много) а у вас нет возможности дать каждой свой classpath, у вас точно есть куча проблем с конфликтующими или дублирующимися зависимостями.
И для успешной жизни на проекте вам следует опустится вот это вот болото Мавена и стабилизировать билд. Это второе по важности после логов и мониторинга и метрик что следует сделать.
6. Любой код без тестов автоматически становится легаси. Ваша задача любой ценой покрыть код тестами. На каждый баг — покрываете то место тестами. Вплоть до драконовского правила не принимать новый код без тестов хотя и без фанатизма. Да, вам придётся замокать пол мира, написать кучу фикстур и стабов, написать долгие интеграционные тесты которые пол базы загрузят, но без этого вообще никак. Когда создавалось множество легаси проектов тогда тестирование ещё не было принято как промышленная практика или фреймворки которые были тогда не очень были рассчитаны на то что их нужно будет как-то тестировать. Сами тестовые библиотеки и техники с тех пор прошли большой и мучительный путь, и в каждом фреймворке уже изначально идёт куча вспомогательных классов и стабов и документации о том как тестировать.
Поэтому на легаси проекте это совершенно нормальная практика когда функционал написанный\исправленный за час вы в три раза дольше покрываете тестами. Постепенно самое гадкое вы всё таки покроете тестами а ваша архитектура всё таки начнёт постепенно становится лучшей для тестирования. Это трудозатратный путь, но он оправдан и рано или поздно принесёт плоды, просто верьте.
7. Дальше нужно улучшить логирование — подчистить лог от огромных стектрейсов и пофиксить то что их продуцирует. Дописать логи везде где только нужно, все входящие и выходящие реквесты в АПИ тоже логировать. При этом нужно сделать так чтобы логирование имело смысл по максимуму. Также в логах у вас почти наверняка будет множество секьюрной информации: пароли пользователей и ключи от АПИ, номера кредитных карт или что нибудь ещё такое чего там не должно быть. Представьте что ваши логи взломали хакеры — вы должны максимально им усложнить жизнь.
8. Улучшить мониторинг — через JMX пробросить все важные метрики: количество активных сессий или реквестов. Повключать всякие опции JVM для мониторинга. Об этом Виталий Тимчишин рассказывал в клубе анонимных программистов презентация, видео (часть 1), видео (часть 2) но лучше новую инфу поискать, особенно про FlightRecorder.
9. Билд нужно ускорить и улучшить насколько это возможно. У вас должен быть самый лучший CI tool — TeamCity. Собираться в нём должно всё что только может быть собрано.
10. Вам нужно ввести версионирование БД и db migration tool — DBMaintain, FlywayDB, LiquiBase.
11. Грамотно разнести тесты как в Гугле поделить их по времени выполнения. Тут ключевой момент в том что если для TDD разработки ваш тест должен отрабатывать быстро (максимум 15 секунд) иначе она не приживётся. Сам билд в CI тоже нужно ускорить как только можно (запуск тестов в параллели, использовать in-memory file system).
12. У вас совершенно точно будут множество проблем с базой данных — конекшен пул будет забиваться, будет множество проблем с уровнем изоляции транзакций, запросы будут долго тупить, N + 1 проблемы, данные будут неконсистентными итд. Эти проблемы нужно чётко методично разруливать — обновить либу Tomcat JDBC Connection Pool, загнать всю работу с базой строго в рамки DAO, самые используемые и статические данные закешировать и сделать так чтобы кеш можно было сбросить через JMX или JavaMelody.
13. Саму базу тоже как правило следует подчистить и хорошенько нормализировать. Делать это нужно очень аккуратно и осознано и обязательно основываясь на реальной статистике. Для PostgreSQL есть утилита pg_stats. По ней можно определить как данные используются и сравнив с кодом можно понять свойства данных: как часто они изменяются, как часто они инсертятся или они read only. Где нужно натянуть индексы. Это очень принципиально потому что даёт нормальный прирост скорости и вообще от данных следует отталкиваться.
14. Дальше вам следует возвести китайскую стену между старым кодом и новым, как рассказывал Витя Полищук. У вас должно быть чёткое понимание что в этой части системы мы пытаемся создать островок удачи и везения, где всё прилично и правильно и после этого перетащить на этот остров весь функционал из плохого кода. Этот островок может быть совершенно отдельным модулем\микросервисом отделённым чётким API и интерфейсами. И жёстко следить за тем чтобы в нём был порядок.
У меня например на проекте например даже уволили сотрудника за то что он не стал переписывать старый функционал а за уши притянул его скопипастив код в островок удачи. Теперь нам оставшимся сцыкотно там гадить.
15. Всё что только можно резать на модули, модули выделять в микросервисы которые общаются по простому протоколу типа REST или JSON-RPC.
У вас наверняка есть часть системы и код который никогда уже не перепишешь и всё что можно с этим сделать — только выделить эту гангрену в отдельный модуль.
16. Memento mori — вам следует честно и сразу думать даже о новом функционале как о выброшенном позже и заранее думать о том как его убрать. Микросервисы как раз неплохо решают эту проблему.
17. Стоит максимально улучшить процесс деплоя — для начала достичь zero downtime но конечно в идеале вообще continuous deployment, но даже не мечтайте �� Даже без zero downtime ваш цикл комит — старт сервера должен быть максимально маленьким. Суть в том что если вы начнёте что-то менять то вам придётся постоянно выкатывать хотфиксы которые фиксят баги после ваших фиксов багов. Если вы начнёте наводить порядок на легаси проекте, да даже просто что-то делать особо ничего не трогая, всё равно у вас будут всплывать проблемы и их нужно будет фикисть по горячему.
18. Если у вас есть внешний API то вам следует проксировать его через фасад где чётко вести статистику кто его дёргает и как. Далее если ваш АПИ будет меняться вам следует самим сделать SDK где вы его сами заимплементите. Всё таки это относительно редкость когда клиенты вашего АПИ используют что-то другое кроме PHP, Java или JavaScript, ну или что там у них. Поэтому вы можете сами написать или попросить клиентов поделится с вами их обвёртками над вашим АПИ и сделать его своим официальным. Далее вы можете менять и экспериментировать с АПИ при этом каждый раз выкатывать новую версию SDK. Т.е. это вам даёт дополнительный рычаг гибкости.
Кроме того попытаться заимплементить ваше собственное АПИ очень хорошо поможет вам понять как мучаются ваши клиенты и заметить частые ошибки.
19. После этого можете пробовать постепенно обновлять ваши библиотеки зависимостей на новые версии, тщательно и внимательно просматривая их чейнджлоги и ища всякие баги которые есть с этой версией. Реально в интернете вы уведите много релевантной информации. Первым делом обновлять следует тестовые библиотеки, особенно моки (EasyMock, Mockito) потому что они изменяют байткод. Проверить что тесты проходят как и ранее и не сломались.
Далее следует обновлять сами плагины Мавена — это тоже довольно опасная операция как оказалось на практике.
После этого утильные либы: Apache Commons Lang, Apache Commons Collections, Guava, JodaTime, Jackson, итп.
Потом можно попробовать проайпдейтить Quartz который в основном используется для джоб и другие либы типа Apache POI чья поломка для пользователей пройдёт почти незаметно.
Потом нужно проадейтить те либы которые делают инструментацию байткода и всякую магию: Hibernate и куча всего другого. Это самое злобное.
После этого можно пробовать перейти на новую джаву.
После перехода на новую джаву можно выкинуть JodaTime и JodaMoney и кучу другого хлама. И обновить остальные либы типа Спринга.

Работа с легаси-системами: стабилизация, мониторинг, управление

На самом деле, по-хорошему статью следовало бы назвать так: «Как работать с легаси-системами и сохранять психическое здоровье». Любой, кто имеет с ними дело, меня поймет. Эта статья — попытка обобщения многолетнего опыта знакомства с легаси-системами в виде набора подходов и практических советов. Примеры буду приводить из собственного опыта — в частности, работы с унаследованной Java-системой. Кстати, материалов о работе с легаси в структурированном виде почти нет — оба источника, посвященных именно ей, приведены в конце материала. И это при том, что на легаси приходится чуть ли не половина всего аутсорсинга.

Что такое legacy или унаследованная система

Легаси — в переводе с английского «наследство», и наследственность эта тяжелая. Почти всем доводилось, придя в проект, получить код десятилетней давности, написанный кем-то другим. Это и есть унаследованный код — то есть код исто(е)рический, который часто бывает ужасен настолько, что оказывается вообще непонятно, как с ним работать. И если нам достается легаси-система, то мы, кроме старого кода, также имеем:

  • устаревшие технологии;
  • неоднородную архитектуру,
  • недостаток или даже полное отсутствие документации.

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

На самом деле, легаси-система — это не так уж страшно, и вот почему. Если система жила все эти десять лет и до сих пор работает, значит, какой-то толк от нее есть. Может быть, она приносит хорошие деньги (в отличие от вашего последнего стартапа на новейших технологиях). Кроме того, код такой системы относительно надежен, если он смог так долго выживать в продакшне. Поэтому вносить в него изменения нужно с осторожностью.

Прежде всего, нужно понять две вещи:

  1. Мы не можем неуважительно относиться к системе, которая зарабатывает миллионы, или к которой обращаются тысячи людей в день. Как бы плохо она ни была написана, этот отвратительный код дожил до продакшна и работает в режиме 24/7.
  2. Раз эта система приносит реальные деньги, работа с ней сопряжена с большой ответственностью. С самого начала ясно, что это не стартап в стол, а то, чем пользователи будут работать уже завтра. Это подразумевает и очень высокую цену ошибки, причем дело здесь не в претензиях клиента, а в реальном положении вещей.

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

Что со всем этим делать

Для успешной работы с унаследованными системами нам придется много пользоваться приемами reverse engineering.

Прежде всего, нужно внимательно читать код, чтобы точно понимать, как именно он работает. Это обязательно — ведь достаточной документации у нас, скорее всего, не будет. Если мы не поймем хода мыслей автора, мы будем делать изменения, последствия которых окажутся не вполне предсказуемыми. Чтобы обезопасить себя от этого, нужно вникать еще и в смежный код. И при этом двигаться не только вширь, но и вглубь, докапываясь до самого нутра. Откуда вызывается метод с ошибкой? Откуда вызывается вызывающий его код? В легаси-проекте “call hierarchy” и “type hierarchy” используется чаще, чем что бы то ни было другое.

Конечно, придется проводить много времени с отладчиком — во-первых, чтобы находить ошибки, и во-вторых, чтобы понять, как все работает — потому что логика обязательно будет такой, что по-человечески прочитать ее мы не сможем. Собственно говоря, дебажить нужно будет вообще все, в том числе и open source-библиотеки. Даже если проблема где-то в Spring, значит, придется отлаживать и, возможно, пересобирать Spring, если возможности его обновить не окажется. Именно так нам неоднократно приходилось делать, причем не только со Spring.

Что касается документации, не лишним будет прибегнуть к тому, что я бы назвал промышленной археологией. Очень полезно бывает откопать где-нибудь старую документацию и поговорить с теми, кто помнит, как писался доставшийся вам код. Возможно, где-то есть старый Confluence, возможно, хотя бы дамп его базы, где вы что-то, может быть, и найдете. Иногда это бывает проще, чем сидеть с дебаггером. Но нередко там окажутся только документы, не имеющие прямого отношения к коду, например, руководства по настройке серверов, которые все в принципе боятся трогать.

Используя эти приемы, рано или поздно вы начнете более или менее понимать код. Но чтобы ваши усилия не пошли прахом, вы должны обязательно сразу же документировать результаты своих изысканий — для этого я советую рисовать блок-схемы или диаграммы последовательности (sequence diagrams). Конечно, вам будет лень, но делать это точно нужно — через полгода без документации вы сами в этом коде будете копаться как в первый раз. А если через полгода с кодом будете работать уже не вы, ваши последователи будет очень благодарны вам за имеющуюся документацию. Кстати, зачастую для себя и для бизнеса документацию нужно готовить разную: в вашей, рассчитанной на инженеров, представители бизнеса ничего не поймут. Им потребуется что-то понятное, описывающее функционирование системы на верхнем уровне. И наконец, нужно не забывать самим пользоваться этой документацией и читать ее. Однажды, решив проблему после двух дней героической борьбы, мы обнаружили собственный документ, подробно описывающий точно такой же случай.

А руками?

Не переписывать!

Теперь поговорим собственно о разработке. Самое важное здесь — вовремя бить себя по рукам и не пытаться переписать весь код заново. Прикиньте, сколько человеко-лет для этого потребуется – вряд ли заказчик захочет потратить столько денег на переделывание того, что уже и так работает. Это касается не только системы в целом, но и любой ее части. Вам, конечно, могут дать неделю на то, чтобы во всем разобраться, и еще неделю на то, чтобы что-то исправить. Но вряд ли дадут два месяца на написание части системы заново.

Вместо этого реализуйте новый функционал в том же стиле, в каком написан остальной код. Другими словами, если код старый, не стоит поддаваться соблазну использовать новые красивые технологии — такой код потом будет очень тяжело читать. Например, вы можете столкнуться с ситуацией, которая была у нас — часть системы написана на Spring MVC, а часть — на голых сервлетах. И если в части, написанной на сервлетах, нужно дописать еще что-то, то дописываем мы это так же — на сервлетах.

Бизнес-интересы и рефакторинг

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

Тестирование


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

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

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

Мастер Йода рекомендует:  Карьерный рост в чем разница между Junior, Middle и Senior

DevOps и релиз

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

Релизная процедура может быть, например, следующей. Когда заканчивается разработка и пройдены две или три фазы тестирования, мы пишем письмо DevOps-команде за 36 часов до предполагаемого времени релиза. После этого созваниваемся с девопсами и обсуждаем все изменения окружений (мы сообщаем им обо всех изменениях в БД и конфигурации). На каждое изменение у нас есть документ (тикет в Jira). Затем во время релиза все причастные к этому собираются вместе, и каждый говорит, что он сейчас делает: «Мы залили базу!», «Мы перезапустили такие-то серверы!», «Мы пошли прогонять регрессионные тесты в рабочем окружении!». Если же что-то идет не так, запускается процедура отката релиза, точно описанная в изначальном документе на релиз — без такого документа мы обязательно что-нибудь забудем или напутаем (вспомните, в какое время суток обычно происходят релизы).

Организация кода

Очень важно выстроить правильную branching strategy. Основные модели бренчинга давно описаны на сайте того же Atlassian, их можно адаптировать под ваши нужды. Главное — ни в коем случае не коммитить изменения сразу в транк: должны быть stable trunk и feature branches. Я советую делать релизы из релизных веток, а не из транка. То есть у вас есть транк, от которого отходят ветки на конкретные фичи, соответствующие тикетам в Jira. Когда вы закончили разработку в спринте, вы собираете отдельную релизную ветку из готовых фич и ее сертифицируете. Если же что-то пойдет не так, из такой ветки можно будет легко устранить то, что по какой-то причине из релиза в итоге выпадает. Когда же релиз произошел, релизная ветка вливается в stable trunk.

Контроль качества кода

И наконец, code review — это, казалось бы, достаточно очевидная практика, к которой прибегают почему-то далеко не во всех проектах. Очень хорошо, если каждая часть кода проверяется более чем одним человеком. Даже в очень сильной команде в процессе code review обязательно обнаруживаются какие-то косяки, а если смотрят несколько человек, количество выявленных косяков возрастает. Иногда самое страшное находит третий или четвертый reviewer. Но во избежание как саботажа, так и излишнего фанатизма, необходимо договориться, сколько review достаточно для того, чтобы считать фичу готовой.

Для проверки можно использовать пул-реквесты (конечно, если у вас Git), далее есть Crucible и FishEye — оба прикручиваются к Jira. И наконец существует очень удобный инструмент Review Board, который работает и с SVN, и с Git. Он позволяет послать запрос на проверку кода, который соберет в себе все изменения в данном feauture branch.

Как этим управлять

Подбор команды

Самое первое, что должен помнить Team Lead или PM при наборе людей в проект — далеко не всем разработчикам подходит работа с легаси-системами. Даже если человек пишет замечательный код, не факт, что он сможет целыми днями сидеть с дебаггером или документировать чужой код. Для работы с легаси, кроме технических навыков, требуются еще определенные личностные качества — хорошее чувство юмора, самоирония и, конечно же, терпение. На эти качества нужно обращать внимание при подборе людей в команду, а если кто-то не сошелся с легаси характерами, то не воевать с ним, а заменять. Замена человека в проекте в подобном случае не волчий билет, а облегчение и для него, и для команды.

Глупые вопросы

Тимлид не должен стесняться задавать команде «глупые» вопросы и напоминать обо всех вышеперечисленных приемах работы. «Я накатил свежий код, и теперь ничего не работает!» — «А какую ветку ты взял? А базу обновил? А что в логах? А дебажил?» Несмотря на всю свою простоту такие диалоги — неотъемлемый элемент нашей работы, и в особенности с легаси-проектами. Нужно удерживать все в голове и не уставать снова и снова напоминать о каких-то очевидных и не очень очевидных вещах. Без этого, поверьте, не обойтись!

Процесс, или «Здесь так принято»

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

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

Что касается эстимэйта (вы же используете Planning Poker, правда?), то оценивать всегда нужно с запасом, чтобы быть готовым к сюрпризам — как мы уже говорили, влияния в незнакомом нам коде зачастую неясны, и порой может вылезать что-то совершенно неожиданное и в неожиданных местах. Так, у нас в проекте был случай, когда изменения в простом CSS сломали часть бизнес-логики: кто-то поставил в JS проверку на цвет элемента интерфейса.

Бизнес, tech debt и SWAT

При работе с легаси-системами нужно стараться противостоять потоку бизнес-требований, которые заказчик будет вам непрерывно поставлять. Заказчик не всегда осознает риски, связанные со стабильностью системы, поэтому вам придется постоянно о них напоминать. Бороться с этими рисками можно двумя способами: балансированием бизнес и стабилизационных задач в каждом спринте или отдельными стабилизационными проектами. Оптимальным кажется баланс 70 на 30, когда 30 % времени каждого спринта вы занимаетесь стабилизацией. Впрочем, заказчик скорее всего не даст вам сделать все, что вы хотите — поэтому записывайте технический долг по мере обнаружения. Из этого tech debt вы будете брать задачи на вышеупомянутые 30 %. А может, заказчик согласится на стабилизационный проект, особенно если вы покажете ему tech debt в ответ на вопрос, почему все в очередной раз упало.

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

Примеры оптимизации

А теперь вкратце расскажу о способах оптимизации, которыми мы пользовались в разное время.

Во-первых, нужно уйти от традиции ежедневных перезапусков, если так было принято в проекте. Однако делать это нужно, конечно, с осторожностью — продолжать проверять логи и следить за всем, что может привести к падению системы, и бороться с этим. У нас была система, которые перезапускалась каждую ночь, т. к. не могла прожить и двух суток из-за memory и других leaks — теперь же она совершенно стабильно работает от релиза до релиза две-три недели (за редкими исключениями, о которых мы обычно узнаем в 4 утра).

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

Очень важный момент — проход по всем логам и составление отдельного эпика. Бывают, конечно, заказчики, которые долго не дают доступа к продакшн-логу. У нас, например, так продолжалось полгода, после чего случился переломный момент, когда нас самих попросили посмотреть логи продакшна. Просмотр затянулся на всю ночь. В системе, работавшей, как считалось, штатно и стабильно, нормальные логи попадались лишь иногда — в основном же записи были со сдвигом вправо и начинались с “at”. Это были сплошные стектрейсы, и их набиралось на десятки мегабайт в сутки. Конечно, мы завели эпик в Jira и создали тикеты на отдельные exceptions. Затем нам пришлось несколько месяцев выбивать время на стабилизационный проект. В итоге мы исправили множество ошибок, о которых никто не догадывался, и сделали логи информативными. Теперь любой стектрейс в них — действительно признак нештатной ситуации.

Еще советую обращать внимание на третьесторонние зависимости как на front-end (Google Tag Manager, Adobe Tag Manager и т. п.), так и на back-end. Например, если у нас на странице есть JavaScript со сторонних ресурсов, нужно посмотреть, завернуты ли эти скрипты в try..catch блоки. У нас были случаи, когда сайт падал из-за того, что ломался какой-то скрипт на стороне. Также важно предусматривать возможность недоступности любых внешних ресурсов.

Ну и последнее: следите за всем, за чем только можно, и грамотно агрегируйте логи. Ведь у вас может быть 12 продакшн-серверов, и вас могут попросить их логи посмотреть, что точно нужно делать не через tail. Мы использовали ELK — связку Elastic search – Logstash – Kibana. Очень полезен мониторинг: мы навесили Java Melody на все серверы и получили огромное количество новой информации, на основании которой многое исправили, осчастливив заказчика.

Subaru Legacy 2.0 GT ТвинСкролТурбо › Бортжурнал › Скрытые возможности Легаси №2

У Legacy оказывается есть возможность открывания дверей по коду, хотя кодонаборной панели нет.

Комбинация вводится с помощью поднятий ручки двери водителя…

Если кому интересно, то делается это следующим образом:

А. Подготовка к регистрации кода

1. Откройте машину с брелка, открываем водительскую дверь. (ключ в замок зажигания вставлять не надо, а тем более поворачивать в какое либо положение!)
2. С внешней стороны двери поднимите ее ручку вверх на 6 сек.
3. Начинает звучать зуммер.
4. Чтобы остановить зуммер, во время писка нажимаем на брелке кнопку открыть двери (именно во время писка, это очень важно!) писк исчезает и можно программировать…

На этом подготовка к регистрации закончена.

Б. Регистрация кода

1. Минимальная регистрируемая цифра это 1. Для ее регистрации нужно поднять и опустить ручку.
2. Если зуммер начинает звучать прерывисто, повторите регистрацию еще раз до окончания промежутка в 30сек.
3. Регистрация прошла успешно, если зуммер дает длинный гудок продолжительностью, примерно, 1 сек.

ПРИМЕР РЕГИСТРАЦИИ КОДА 3246

1. Поднимите ручку 3 раза и дождитесь короткого зуммера (пи-пи).
2. Поднимите ручку 2 раза и дождитесь короткого зуммера (пи-пи).
3. Поднимите ручку 4 раза и дождитесь короткого зуммера (пи-пи).
4. Поднимите ручку 6 раз.
5. Если после регистрации последней цифры зуммер начинает звучать прерывисто, регистрация прошла неудачно и ее следует начать снова до истечения 30 сек.
6. Регистрация прошла успешно, если после ввода 4-ой цифры прозввучат два последовательных пик-кик то нужно сразу же повторить тот код какой вы набрали в предыдущем разе…
Если все сделали правильно, то она в конце один раз пикнет и замки атоматически закроются и откроются…

*Если Вы ошиблись при регистрации, закройте водительскую дверь, чтобы отменить регистрации и повторите все пункты из раздела А.
*Регистрация кодов 0000,1111,2222,…9999, 1234 невозможна для защиты от воровства. Не используйте простые коды 1112, 1212 и т.п.
*Для цифры 0 ручку нужно поднять 10 раз.
*При попытке регистрации кода 2222 стирается старый код и Вы уже не можете открыть дверь с помощью ручки до тех пор, пока не введете новый код.
*При регистрации нового кода дверь должна быть открыта.


ДЛЯ ОТКРЫВАНИЯ ЗАМКА С КОДОМ 3246
1. Поднимите ручку 3 раза, звучит длинный зуммер пи-
2. Поднимите ручку 2 раза, звучит длинный зуммер пи-
3. Поднимите ручку 4 раза, звучит длинный зуммер пи-
4. Поднимите ручку 6 раз, звучит щелчок замка. Теперь дверь можно открыть.

ВАЖНЫЕ СОВЕТЫ
*Если Вы ошиблись при отпирании двери, отпустите ручку и не менее чем через 5 сек повторите процесс отпирания с самого начала.
*С целью защиты от воров замок блокируется после 5 последовательно выполненных неудачных попыток открывания двери, при этом включается зуммер, который звучит 5 мин.

Абсолютные истины джуниора, от которых пришлось отучиваться

1. Я старший разработчик

Когда я впервые попыталась устроиться на работу, мне было 19 лет. Вакансия называлась «студент веб-мастер». Это довольно удивительное название работы, потому что вы считаетесь и «студентом», и «мастером» одновременно. В наши дни все хотят быть «инженерами», потому что это звучит более модно, но по мне «мастер» — более подходящее слово для этого ремесла. В любом случае, моя работа состояла в том, чтобы писать PHP и MySQL и поддерживать наш сайт на Drupal, а также создавать некоторые внутренние инструменты.

Поскольку перед этим я несколько лет кодировала в своей спальне, то была уверена, что эти годы считаются за «годы опыта». Поэтому, когда меня спросили о том, сколько у меня опыта написания на PHP, я уверенно ответила: «3 или 4 года!»

Я думала, что много знаю о SQL, потому что умею делать outer join’ы (внешние объединения).

А когда я погуглила, то выяснила, что три-четыре года опыта означают большую кучу денег.

Перейдём к моей последней работе, которую я получила после пяти лет «комбинированного» студенческого и профессионального опыта (который я считала обычным опытом). В то время мой код практически никогда не проходил код-ревью. Я запускала ssh на сервере и делала git pull. Уверена, что никогда не видела ни одного пулл-реквеста. Не поймите меня неправильно, на первых двух работах я узнала массу потрясающих вещей, просто никогда не работала с другими разработчиками в той же кодовой базе. И всё же я подала заявку на должность «старшего инженера фронтенда», получила предложение и приняла его.

Так я стала старшим разработчиком в зрелом возрасте 24 лет.

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

Что я в итоге поняла

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

Вот почему так важны наставники, а ваша команда гораздо важнее, чем разница в пару долларов в зарплате. Не соглашайтесь на должность джуниора, где вы будете работать в одиночку! И не выбирайте первую работу (или, честно говоря, любую работу) только на основе зарплаты. Команда — вот где настоящая ценность.

Я также узнала, что названия должностей ничего не означают сами по себе. Позиция CTO может быть в команде из 5 человек, 50 или 500 человек. Это совершенно разная работа, хотя название идентично. Так что мой титул «сеньора» вовсе не делал меня ведущим программистом. Кроме того, иерархические титулы по своей сути ущербны и их трудно сравнивать между собой. Я поняла, что важно не зацикливаться на названиях и не стоит использовать их в качестве какой-то внешней проверки.

2. Все пишут тесты

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

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

Потому что… ну, это же бесплатно.

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

Короче говоря, я ушла из института с большими ожиданиями.

Ожиданиями относительно того, как работает индустрия. Автоматические деплои. Пулл-реквесты и код-ревью. Это будет великолепно! Наконец-то качество кода, о котором я мечтала! Но кроме качественного кода с надлежащими стандартами и лучшими практиками, я твёрдо верила, что в софтверной индустрии все пишут тесты.

Так что представьте моё удивление, когда в первый рабочий день в стартапе я не нашла никаких тестов. Никаких тестов в интерфейсе. Никаких тестов в бэкенде. Вообще никаких тестов.

Нда. Ничего. Ноль. NaN. Тесты отсутствуют как явление.

Не только не было тестов, но, казалось, никто не испытывал из-за этого проблем! С некоторой наивностью я предположила, что причина в том, что люди просто не знали, как писать тесты для AngularJS. Если я их научу, всё наладится — и мы начнём проводить тесты. Ошибка! В общем, только спустя несколько лет мы внедрили в код автоматические тесты, и это было не так просто, как я думала.

Но не потому, что люди не умеют их писать.

Они либо никогда не испытывали проблем от отсутствия тестов, либо испытывали проблемы от наличия старых тестов. Две вещи, с которыми я никогда не сталкивалась.

Что я в итоге поняла

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

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

Быть чрезмерно самоуверенным в вопросах, по которым вам не хватает реального опыта, довольно высокомерно. Я выступила ТАКОЙ всезнайкой, настаивая на повсеместном внедрении тестов, почти не имея опыта, как это действительно реализовать в большом масштабе. Не повторяйте моих ошибок. Важно иметь принципы, но важно ещё быть открытым и по-настоящему заинтересованным, чтобы воспринимать опыт и взгляды других людей.

3. Мы настолько отстали от всех остальных (aka техническая версия синдрома упущенной выгоды )

Это тесно связано с темой модульного тестирования. Моя компания не проводила тестов, но, конечно, все остальные компании их делали, верно?

Я прочитала кучу постов в блогах. Просмотрела массу выступлений с конференций на YouTube. Чёрт возьми, я непрерывно читаю «тот оранжевый сайт» [вероятно, имеется в виду Hacker News — прим. пер.]. Кажется, что все пишут суперсложные и высококачественные приложения с отличной производительностью и модными анимациями, в то время как я просто делаю заплатки, пытаясь успеть к дедлайну.

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

Что я в итоге поняла

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

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

4. Качество кода очень важно

В былые времена я могла сделать очень жёсткое код-ревью.

По крайней мере, я была весьма придирчива к стилю. Мой стиль оказался модифицированной версией стиля руководства по стилю JavaScript от Airbnb, но соответствует моим личным вкусам. Такие вещи, как отступы, форматирование, именование — не дай бог вы сделаете это иначе. Совершенно невозможно было пройти код-ревью без единого комментария от меня: вам пришлось бы освоить навыки чтения мыслей и вдобавок выиграть в лотерею.

Представьте более 50 комментариев к вашему пулл-реквесту с перечислением всех точек с запятой, которые вы пропустили!

Потому что у меня глаза как у орла — и этот орёл хочет получить все свои высококачественные точки с запятой!


(К счастью, после многих лет работы за компьютером зрение как у орла пропало, так что теперь вам не о чем беспокоиться — #шуткибезшуток)

Что я в итоге поняла

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

Архитектура важнее, чем придирки. Хотя какую-то строчку можно улучшить, но главные проблемы — архитектурного порядка. Лучше сразу сосредоточиться на структуре приложения, а не на отдельных крошечных фрагментах кода.

Качество кода важно, не поймите меня неправильно. Но качество кода — это не то, что я думала. Это не линтинг, форматирование или какой-то стиль, о котором рассказано в последней прочитанной мною статье.

5. Всё должно быть задокументировано.

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

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

Итак, как я справилась с тем фактом, что 300 строк незнакомого кода заставили меня почувствовать, что я тону?

Я начала комментировать всё, чтобы попытаться найти смысл. Аннотации для каждой функции, до которой я могла добраться.

Я выучила весь этот причудливый Angular-специфичный синтаксис JSDoc. Мой код всегда был в два раза длиннее, потому что у него было столько документации и комментариев.

Что я в итоге поняла

Документация иногда врёт. Легко думать, что документация решает все вопросы. «Нам нужны доки!» Хотя документация — это тяжёлая работа, но её нужно делать. Просто следует документировать правильные вещи правильным образом. Чрезмерное документирование ненужных вещей, как правило, мешает людям, которые пытаются решить реальную проблему.

Мастер Йода рекомендует:  Qeexo анонсировала технологию определения угла касания для сенсорных экранов

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

6. Технический долг — это плохо

Если после прошлого пункта вы посчитали меня невротиком, просто почитайте этот! Какое-то время в моей карьере я считала техническим долгом любой «грязный» код. Технический долг — забавный термин, потому что если вы попросите привести пример, назовывают очень разные вещи.

Поскольку я считала любой «неупорядоченный» код техническим долгом, я немедленно пыталась устранить его с максимальной строгостью!

Однажды я буквально провела выходные, вручную исправляя 800 ошибок линтинга.

Вот каким невротиком я была.

(Отказ от ответственности: это было до того, как появились автоматические исправления).

Что я в итоге поняла

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

Иметь некоторый технический долг — это нормально. Иногда мы сокращаем путь, потому что нужно выполнить работу срочно, и ради этого «одалживаем» часть времени в будущем. Наличие фрагментов кода, которые являются реальным «техническим долгом», нормально, если вы признаете, что вам, вероятно, придётся его вернуть. Если ваша кодовая база, на ваш взгляд, свободна от технического долга, скорее всего, вы переоцениваете внешний вид в ущерб доставке. И боже мой, как я его переоценивала!

7. Чем выше должность программиста, тем лучше он программирует

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

Долгое время я думала, что именно в этом суть ведущего разработчика.

Вроде бы всё сходится? Ведь должность называется «ведущий разработчик», а не «ведущий коммуникатор» или «ведущий менеджер проекта». Я действительно не понимала, сколько ещё навыков нужно развить, чтобы стать по-настоящему «ведущим».

Что я в итоге поняла

Старшим инженерам придётся освоить много навыков, кроме программирования. Если сравнить с началом карьеры, мне пришлось развить астрономическое количество навыков. Коммуникация, управление зависимостями, совместное использование контекста, управление проектами, оценка сроков выполнения проекта и сотрудничество с коллегами, которые не являются разработчиками. Эти навыки с трудом поддаются количественной оценке и требуют много проб и ошибок, прежде чем будут усвоены надлежащим образом.

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

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

Бонус: мне очень понравилась статья «Быть ведущим программистом». Отличная вещь, если в какой момент вы задаётесь вопросом, что подразумевает эта работа.

Литература

Что полезно почитать по этой и подобным темам.

Комментарии

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

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

Спасибо за комментарий, я согласен, в принципе. Разве что такой детальный подход уже тема отдельной статьи или даже книги. Впрочем, книга на такую тематику уже есть — Working Effectively with Legacy Code, в ней как раз рассматриваются вопросы именно кода (со всех сторон, включая, тестирование, анализ и т.п.). А я старался подойти к теме со стороны менеджера проекта, стратегический подход с небольшими вкраплениями практики.

Что такое legacy code?

Не могу найти перевод. Можете объяснить в двух словах что это такое? Что за понятие?

Legacy code — тяжелая наследственность : ) Устаревший код, который более не поддерживается и не обновляется, но используется. Второе значение — код от сторонних разработчиков, или из старых версий.

Суммирорав все определения, которые встречались, для себя вывел следующее.

Legacy code — код, подпадающий под один или несколько признаков:


  • написан другими разработчиками, возможно, уже недоступными для контакта;
  • не покрыт юнит-тестами;
  • сохранён для совместимости с предыдущими версиями системы;
  • устарел и/или более не поддерживается в связи с развитием системы (написан на предыдущем языке, под старую архитектуру, аппаратную платформу, операционную систему и т.д.).

@sergiks все написал верно, но все таки уточню: вообще термин Legacy в программировании означает прилагательное означающее принадлежность к традиционному. Скажем, Legacy Driver — означает драйвер от производителя и т.д.

Как работать с legacy-системами

На самом деле, по-хорошему статью следовало бы назвать так: «Как работать с legacy-системами и сохранять психическое здоровье». Любой, кто имеет с ними дело, меня поймет. Эта статья — попытка обобщения многолетнего опыта знакомства с legacy-системами в виде набора подходов и практических советов. Примеры буду приводить из собственного опыта — в частности, работы с унаследованной Java-системой.

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

Особенности legacy

Legacy — в переводе с английского «наследство», и наследственность эта тяжелая. Почти всем доводилось, придя в проект, получить код десятилетней давности, написанный кем-то другим. Это и есть унаследованный код — то есть код исто(е)рический, который часто бывает ужасен настолько, что оказывается вообще непонятно, как с ним работать. И если нам достается legacy-система, то мы, кроме старого кода, также имеем:
— устаревшие технологии;
— неоднородную архитектуру;
— недостаток или даже полное отсутствие документации.

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

На самом деле, legacy-система — это не так уж страшно, и вот почему: если система жила все эти десять лет и до сих пор работает, значит, какой-то толк от нее есть. Может быть, она приносит хорошие деньги (в отличие от вашего последнего стартапа на новейших технологиях). Кроме того, код такой системы относительно надежен, если он смог так долго выживать в продакшне. Поэтому вносить в него изменения нужно с осторожностью.

Прежде всего, нужно понять две вещи:
1. Мы не можем неуважительно относиться к системе, которая зарабатывает миллионы, или к которой обращаются тысячи людей в день. Как бы плохо она ни была написана, этот отвратительный код дожил до продакшна и работает в режиме 24/7.
2. Раз эта система приносит реальные деньги, работа с ней сопряжена с большой ответственностью. С самого начала ясно, что это не стартап в стол, а то, с чем пользователи будут работать уже завтра. Это подразумевает и очень высокую цену ошибки, причем дело здесь не в претензиях клиента, а в реальном положении вещей.

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

Обратный инжиниринг

Для успешной работы с унаследованными системами нам придется много пользоваться приемами reverse engineering.

Прежде всего, нужно внимательно читать код, чтобы точно понимать, как именно он работает. Это обязательно — ведь достаточной документации у нас, скорее всего, не будет. Если мы не поймем хода мыслей автора, то будем делать изменения, последствия которых окажутся не вполне предсказуемыми. Чтобы обезопасить себя от этого, нужно вникать еще и в смежный код. И при этом двигаться не только вширь, но и вглубь, докапываясь до самого нутра. Откуда вызывается метод с ошибкой? Откуда вызывается вызывающий его код? В legacy-проекте «call hierarchy» и «type hierarchy» используется чаще, чем что бы то ни было другое.

Конечно, придется проводить много времени с отладчиком — во-первых, чтобы находить ошибки, и во-вторых, чтобы понять, как все работает — потому что логика обязательно будет такой, что по-человечески прочитать ее мы не сможем. Собственно говоря, дебажить нужно будет вообще все, в том числе и open source-библиотеки. Даже если проблема где-то в Spring, значит, придется отлаживать и, возможно, пересобирать Spring, если возможности его обновить не окажется. Именно так нам неоднократно приходилось делать, причем не только со Spring.

Что касается документации, не лишним будет прибегнуть к тому, что я бы назвал промышленной археологией. Очень полезно бывает откопать где-нибудь старую документацию и поговорить с теми, кто помнит, как писался доставшийся вам код. Возможно, где-то есть старый Confluence, возможно, хотя бы дамп его базы, где вы что-то, может быть, и найдете. Иногда это бывает проще, чем сидеть с дебаггером. Но нередко там окажутся только документы, не имеющие прямого отношения к коду, например, руководства по настройке серверов, которые все в принципе боятся трогать.

Используя эти приемы, рано или поздно вы начнете более или менее понимать код. Но чтобы ваши усилия не пошли прахом, вы должны обязательно сразу же документировать результаты своих изысканий — для этого я советую рисовать блок-схемы или диаграммы последовательности (sequence diagrams). Конечно, вам будет лень, но делать это точно нужно — через полгода без документации вы сами в этом коде будете копаться как в первый раз. А если через полгода с кодом будете работать уже не вы, ваши последователи будут очень благодарны вам за имеющуюся документацию.

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

Процесс разработки

Итак, что нужно и что не нужно делать:

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

Вместо этого реализуйте новый функционал в том же стиле, в каком написан остальной код. Другими словами, если код старый, не стоит поддаваться соблазну использовать новые красивые технологии — такой код потом будет очень тяжело читать. Например, вы можете столкнуться с ситуацией, которая была у нас — часть системы написана на Spring MVC, а часть — на голых сервлетах. И если в части, написанной на сервлетах, нужно дописать еще что-то, то дописываем мы это так же — на сервлетах.

Соблюдать бизнес-интересы. Нужно всегда помнить, что любые задачи обусловлены прежде всего ценностью для бизнеса. Если вы не докажете заказчику необходимость тех или иных изменений с точки зрения бизнеса, этих изменений не будет. А для того, чтобы убедить заказчика, вы должны попробовать встать на его место и понять его интересы. В частности, если вам хочется провести рефакторинг только потому, что код плохо читается, вам не дадут этого сделать, и с этим нужно смириться. Если совсем уж невмоготу, реорганизовывать код можно по-тихому и понемногу, размазывая работу по бизнес-тикетам. Либо убедить заказчика в том, что это, например, сократит время, необходимое для поиска ошибок, а значит, в конечном итоге сократит расходы.

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

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

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

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

Релизная процедура может быть, например, следующей. Когда заканчивается разработка и пройдены две или три фазы тестирования, мы пишем письмо DevOps-команде за 36 часов до предполагаемого времени релиза. После этого созваниваемся с девопсами и обсуждаем все изменения окружений (мы сообщаем им обо всех изменениях в БД и конфигурации). На каждое изменение у нас есть документ (тикет в Jira). Затем во время релиза все причастные к этому собираются вместе, и каждый говорит, что он сейчас делает: «Мы залили базу», «Мы перезапустили такие-то серверы», «Мы пошли прогонять регрессионные тесты в рабочем окружении». Если же что-то идет не так, запускается процедура отката релиза, точно описанная в изначальном документе на релиз — без такого документа мы обязательно что-нибудь забудем или напутаем (вспомните, в какое время суток обычно происходят релизы).

Выстроить branching strategy. Основные модели бренчинга давно описаны на сайте того же Atlassian, их можно адаптировать под ваши нужды. Главное — ни в коем случае не коммитить изменения сразу в транк: должны быть stable trunk и feature branches. Я советую делать релизы из релизных веток, а не из транка. То есть у вас есть транк, от которого отходят ветки на конкретные фичи, соответствующие тикетам в Jira. Когда вы закончили разработку в спринте, вы собираете отдельную релизную ветку из готовых фич и ее сертифицируете. Если же что-то пойдет не так, из такой ветки можно будет легко устранить то, что по какой-то причине из релиза в итоге выпадает. Когда же релиз произошел, релизная ветка вливается в stable trunk.

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

Для проверки можно использовать пул-реквесты (конечно, если у вас Git), далее есть Crucible и FishEye — оба прикручиваются к Jira. И наконец существует очень удобный инструмент Review Board, который работает и с SVN, и с Git. Он позволяет послать запрос на проверку кода, который соберет в себе все изменения в данном feauture branch.

Управление проектом

Подбор команды. Самое первое, что должен помнить Team Lead или PM при наборе людей в проект — далеко не всем разработчикам подходит работа с legacy-системами. Даже если человек пишет замечательный код, не факт, что он сможет целыми днями сидеть с дебаггером или документировать чужой код. Для работы с legacy, кроме технических навыков, требуются еще определенные личностные качества — хорошее чувство юмора, самоирония и, конечно же, терпение. На эти качества нужно обращать внимание при подборе людей в команду, а если кто-то не сошелся с legacy характерами, то не воевать с ним, а заменять. Замена человека в проекте в подобном случае не волчий билет, а облегчение и для него, и для команды.

Глупые вопросы. Тимлид не должен стесняться задавать команде «глупые» вопросы и напоминать обо всех вышеперечисленных приемах работы. «Я накатил свежий код, и теперь ничего не работает!» — «А какую ветку ты взял? А базу обновил? А что в логах? А дебажил?» Несмотря на всю свою простоту, такие диалоги — неотъемлемый элемент нашей работы, и в особенности с legacy-проектами. Нужно удерживать все в голове и не уставать снова и снова напоминать о каких-то очевидных и не очень очевидных вещах. Без этого, поверьте, не обойтись!

Процесс, или «здесь так принято». В силу американской текучки кадров новые менеджеры со стороны заказчика приходят в проект чаще, чем нам хотелось бы. И многие из них, еще не разобравшись в специфике legacy, пытаются внедрять практики и решения из своего предыдущего опыта. Им нужно терпеливо объяснять, почему здесь принято именно так, а не по книжке. Сначала такие вещи донести бывает трудно, но в конечном итоге либо заказчик согласится с вами, либо вы вместе придете к компромиссному решению.

В работе с legacy-системами действительно важен правильно выстроенный, понятный и прозрачный процесс: Jira (или аналог) обязательно должна отражать реальное положение дел в данный момент. Все требования должны быть ясно сформулированы, а процессы четко прописаны. Вся эта Jira-бюрократия точно окупится, сильно снизив степень энтропии в проекте. Так, когда к вам придет заказчик и потребует срочно сделать новую фичу, вы сможете просто показать заполненное расписание. Тогда он легче сможет понять, что чем-то придется пожертвовать.

Что касается эстимэйта (вы же используете Planning Poker, правда?), то оценивать всегда нужно с запасом, чтобы быть готовым к сюрпризам — как мы уже говорили, влияния в незнакомом нам коде зачастую неясны, и порой может вылезать что-то совершенно неожиданное и в неожиданных местах. Так, у нас в проекте был случай, когда изменения в простом CSS сломали часть бизнес-логики: кто-то поставил в JS проверку на цвет элемента интерфейса.

Бизнес, tech debt и SWAT. При работе с legacy-системами нужно стараться противостоять потоку бизнес-требований, которые заказчик будет вам непрерывно поставлять. Заказчик не всегда осознает риски, связанные со стабильностью системы, поэтому вам придется постоянно о них напоминать. Бороться с этими рисками можно двумя способами: балансированием бизнес и стабилизационных задач в каждом спринте или отдельными стабилизационными проектами. Оптимальным кажется баланс 70 на 30, когда 30% времени каждого спринта вы занимаетесь стабилизацией. Впрочем, заказчик скорее всего не даст вам сделать все, что вы хотите — поэтому записывайте технический долг по мере обнаружения. Из этого tech debt вы будете брать задачи на вышеупомянутые 30%. А может, заказчик согласится на стабилизационный проект, особенно если вы покажете ему tech debt в ответ на вопрос, почему все в очередной раз упало.

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

Примеры оптимизации

А теперь вкратце расскажу о способах оптимизации, которыми мы пользовались в разное время.

Во-первых, нужно уйти от традиции ежедневных перезапусков, если так было принято в проекте. Однако делать это нужно, конечно, с осторожностью — продолжать проверять логи и следить за всем, что может привести к падению системы, и бороться с этим. У нас была система, которые перезапускалась каждую ночь, так как не могла прожить и двух суток из-за memory и других leaks — теперь же она совершенно стабильно работает от релиза до релиза две-три недели (за редкими исключениями, о которых мы обычно узнаем в 4 утра).


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

Очень важный момент — проход по всем логам и составление отдельного эпика. Бывают, конечно, заказчики, которые долго не дают доступа к продакшн-логу. У нас, например, так продолжалось полгода, после чего случился переломный момент, когда нас самих попросили посмотреть логи продакшна. Просмотр затянулся на всю ночь. В системе, работавшей, как считалось, штатно и стабильно, нормальные логи попадались лишь иногда — в основном же записи были со сдвигом вправо и начинались с «at». Это были сплошные стектрейсы, и их набиралось на десятки мегабайт в сутки. Конечно, мы завели эпик в Jira и создали тикеты на отдельные exceptions. Затем нам пришлось несколько месяцев выбивать время на стабилизационный проект. В итоге мы исправили множество ошибок, о которых никто не догадывался, и сделали логи информативными. Теперь любой стектрейс в них — действительно признак нештатной ситуации.

Еще советую обращать внимание на третьесторонние зависимости как на front-end (Google Tag Manager, Adobe Tag Manager и т. п.), так и на back-end. Например, если у нас на странице есть JavaScript со сторонних ресурсов, нужно посмотреть, завернуты ли эти скрипты в try..catch блоки. У нас были случаи, когда сайт падал из-за того, что ломался какой-то скрипт на стороне. Также важно предусматривать возможность недоступности любых внешних ресурсов.

Ну и последнее: следите за всем, за чем только можно, и грамотно агрегируйте логи. Ведь у вас может быть 12 продакшн-серверов, и вас могут попросить их логи посмотреть, что точно нужно делать не через tail. Мы использовали ELK — связку Elastic search — Logstash — Kibana. Очень полезен мониторинг: мы навесили Java Melody на все серверы и получили огромное количество новой информации, на основании которой многое исправили, осчастливив заказчика.

Мастер Йода рекомендует:  Доступ к базам данных под управлением СУБД POSTGRES95

Legacy: что нужно знать о работе с чужим кодом

Группа: Главные администраторы
Сообщений: 14349
Регистрация: 12.10.2007
Из: Twilight Zone
Пользователь №: 1

Разработка*
Коллеги, у меня для вас есть замечательная новость, мы получили чудесный проект, его несколько лет писали неизвестные нам разработчики, адрес которых мы вряд ли узнаем (чтобы «поделиться обратной связью»), писали очень давно и не известно под чем, и нам предстоит его поддерживать и развивать. Проект сейчас находится на пике своей производительности и мы скоро упремся, любые неаккуратные изменения могут его положить, но мы будем его развивать. Ура!

Согласитесь, странно звучит? Как бред больного на голову программиста. Кто же любит legacy? Это же всегда говнокод (ведь только мы сами пишем идеально), в нем полно багов (а мы сами пишем без ошибок), ужасные решения (ведь только мы сами выбираем подходящую архитектуру), и почти всегда его сложно читать (ведь только мы сами пишем понятно и красиво).

Я знаком с этой страшилкой столько, сколько вообще знаком с областью разработки. Пугание legacy-кодом -­­ это универсальная страшилка для программистов, как для детей история про серого волчка, который придет и укусит за бочок.

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

Сразу оговорюсь, что мы сейчас говорим про код, и только про него. Не про красивые офисы, привлекательных HRов, крутых лидов и большой PR. Код.

Допустим вы разработчик на PHP, и вам бы сказали «Приходи к нам на проект, мы уже пишем этот код на PHP несколько лет, у нас сотни мегабайт кода, почти никакого ООП и функциональное программирование». Как-то сомнительно звучит в разрезе legacy? А если бы вам сказали «Приходи кодить vk?». Разница есть, и она значительна.

Зайдем с другой стороны.

Вам бы сказали: «Слушай, у меня есть для тебя отличная возможность, мне нужно чтобы ты применил все паттерны которые тебе знакомы, можешь использовать любые фреймворки и технологии, можешь написать все с нуля, сделай мне просто домашний блог для моей собачки». Никакого legacy, полный простор мысли и свобода действий. Все можно сделать идеально красиво на модном node.js, прикрутить ajax и comet, поставить кеши на redis, добавить RT поиск с морфологией на elastic’e, но… зачем?

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

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

Раскрою вам секрет — невозможно писать код, если ты не «художник». Но и художники не сразу могут написать красивые полотна. Они учатся более гармонично подбирать цвета, отображать перспективу, сочетать элементы и т.д. Программисты точно также учатся подбирать решения, видеть будущее проекта и делать все максимально удобным, поддерживаемым, эффективным, и в рамках доступных ресурсов. А если в процессе жизни картины к ней появляются новые требования ­в€’ «А давайте сделаем что теперь вечер. А еще пусть по небу летит дракон. А еще на самом деле сейчас зима, а не лето. И пусть на заднем плане будет Дайнерис убивающая Джорджа Мартина» в€’ в такие моменты сложно сохранить изначальный творческий, в чем-то прекрасный, замысел автора.

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

Какой бы не был проект, в его основе тоже лежит картина, может мазки на ней уже не так гармонично сочетаются, но картина была. И пока вы читаете legacy, вы, как исследователь, можете восстановить ее в своей голове, и мало того, вы, как профессионал, можете сделать ее действительно красивой. Грамотно добавить недостающих деталей, дорисовать то, что получилось очень красиво у предыдущих «мастеров», и получить новую картину, уже вашу, и только в ваших силах сделать ее еще лучше, чем она может быть даже была изначально.

«Legacy» не значит «некрасиво». Это шанс сделать еще красивее.

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

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

Хочу только заметить, что меня в этом поймут только те, кто любит находить новые подходы, кто любит думать не по шаблону. Встречаются разработчики, которые, скорее в силу своей неопытности, встречаясь со старыми проектами, готовы брать знамена и кричать «Да тут сплошной говнокод, все это на самом деле пишется по-другому на %my_favorite_framework%, он идеален, он решает все проблемы, все переписать. ».

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

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

Legacy — это отличный учебник того, как надо, и как не надо делать.

Вы когда-нибудь читали книги, которые были очень сложны для вашего восприятия? Возьмите, к примеру, для сравнения стихи Данте, или рассказы Германа Гессе, или Айн Рэнд, или вообще хоть какой-нибудь кодекс РФ. Знакомо ощущение, когда шестеренки мыслительного процесса начинают ломать друг об друга зубья уже на второй странице? Но разве это каким-либо образом принижает смысловую ценность произведения?

Так вот чтение чужого кода порой может быть не менее зубодробительным. Конечно, уже давно придумали такое понятие, как CodeStyle. Однако, почему-то у многих legacy ассоциируется с чем-то, что очень сложно прочитать, что написано в нарушение всех правил очень давно. На самом же деле тот, кто писал этот код, просто следовал «тем» правилам, и научиться читать код в любом стиле не так уж и сложно.

Legacy не так сложно читать, даже если нарушен CodeStyle. К тому же, основные современные IDE уже научились на достойном уровне поддерживать автоформатирование кода.

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

Каково же было мое удивление, когда я обнаружил копипаст запуска простого контроллера с одним view-файлом, в котором и был расположен весь(!) код проекта. Человек сделал проект «на модном фреймворке», но как(!) сделал. Если бы этот код отлежался годик-другой, и достался кому-то на поддержку, то он бы с ужасом в глазах сказал бы «Да что это за legacy?!». Но для меня этому коду не было и «недели отроду». Это был обычный, банальный говнокод.

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

«Legacy» не равно «говнокод».

Случалось ли с вами, что открывая проект за давностью нескольких лет, вы видите код и чувствуете легкое дежа-вю? Как будто из тумана постепенно начинают проявляться очертания чего-то до боли знакомого, почти родного. И дабы развеять последние сомнения в ход идет blame и annotate, и тут все встает на свои места. Он. Он самый. И в голове начинают крутиться мысли вроде «Да как я такое мог написать?! Эххх, зеленый был. О, а вот это я круто сделал, простенько и со вкусом. Так так, а вот это надо быстро поправить пока никто не увидел». Знакомо?

Так вот многие почему-то думают что legacy это что-то, что бывает с кем-то другим. Что вы либо никогда не будете смотреть на свой код через несколько месяцев/лет, либо даже не допускаете той мысли, что сейчас пишете что-то, что будет выглядеть как legacy (или уже выглядит так?). Тем не менее, это не так.

Вы тоже пишете Legacy.

Резюмируя все вышесказанное, хотелось бы сказать, что как таковой термин legacy не заслуживает чести быть «страшилкой». В нем есть свои замечательные стороны, и лишь неопытность разработчиков, притом не только тех, кто написал код, а порой и тех, кто собирается с ним работать, создает ему такую славу. Много legacy кода прошло через мои руки, и с большинством из него мне действительно было приятно работать. Разбираться как он работает, пытаться понять замысел автора, находить более подходящие решения или наоборот убеждаться в том, что решение автора хоть и не было очевидным, но оказывалось весьма эффективным. Дорабатывать уже то, что работает, чем пользуются, делать это лучше — это отличный опыт. Нельзя научиться писать код хорошо, если писать его или всегда по шаблону, или всегда с нуля. Человек все познает в сравнении, и чем больше источников для сравнения, тем лучше вы пишете.

Успехов вам на просторах разработки и побольше хорошего, добротного Legacy-кода! Надеюсь, теперь для вас эта фраза воспринимается иначе, чем до начала статьи: )

Бонус ввиде списка книг, если еще не прочли:

Что делать, если в наследство достался некачественный код — отвечают эксперты

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

«Что делать, если в наследство достался некачественный код?»

За разъяснениями мы обратились к нашим экспертам, а полученные ответы предоставляем вашему вниманию.


Николай Лопин , преподаватель курса профессия frontend-разработчик университета онлайн-профессий Нетология

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

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

Если после недели чтения кода и документации все ещё ничего непонятно, то, кажется, код действительно «не очень». В этот момент нужно понять, как вы будете взаимодействовать с этим кодом. Вам его дали на поддержку? Или нужно его развивать?

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

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

Когда все заинтересованные лица поняли проблему и согласились ее исправлять, нужно подготовить план действий. Я участвовал в нескольких таких проектах — хуже всего при переработке системы уйти на полгода писать новый код. Такой подход проваливается в подавляющем большинстве случаев. Самый удачный вариант — переписывать частями. Выделять модули из существующей системы, покрывать тестами, а затем менять реализацию внутри модуля. Обязательно показывать промежуточные результаты всем заинтересованным и слушать обратную связь. Так вы победите!

Иван Шмаков , Senior VoIP Software Developer

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

Если код действительно плохого качества, важно понять, можно ли закрыть на него глаза. Толерантность к чужому коду — важный скилл. Если нельзя, стоит определить:
– Какова трудоемкость переписывания кода (оценка трудоемкости — это сложно, есть риск просчитаться на целые месяцы);
– Хорошо ли ты понимаешь код, который планируешь переписать;
– А сможешь ли ты написать более качественный код;
– Если проблемный код не покрыт тестами (а так, скорее всего, и будет), то есть риск, что новый код создаст регрессию в проекте. Готов ли ты взять на себя ответственность за результат?

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

Если все же остается желание переписать код, могу дать несколько советов:
– Максимально декомпозируй код — чем меньше кусок переписываемого кода, тем лучше.
– Используй методы рефакторинга, покрой код тестами, если их нет.
– Не трать много времени на переписывание, оно не должно мешать основной работе.

Александр Кравцов , старший разработчик ПО SibEDGE

В первую очередь нужно разделить понятия наследия и некачественного кода. Legacy code — устойчивое выражение, обозначающее, что код, попавший в руки, был написан достаточно давно. И тут нужно учесть, что, возможно то, что было написано 10 лет назад очень актуально для своего времени. Назвать такой код некачественным — вряд ли, устаревшим — вполне. Это может быть вполне поддерживаемая, масштабируемая система, просто сейчас никто таких не делает. С таким кодом можно продолжить работу в определенной парадигме.

А некачественный код мог быть написан буквально вчера. И это уже совсем другой — более тяжелый случай. Если в случае Legacy code возможна дальнейшая поддержка и надстройка, то когда тебе достается откровенно плохая работа, есть смысл задуматься о рентабельности проекта в целом. В этом случае придется, скорее всего, переписывать с нуля. И тут очень важно понять, на каком этапе находится проект: если это старт, то переписать код достаточно легко, если уже заключительный этап — то проще доделать как есть, хотя риск, что в итоге система не будет работать велик. Важно объяснить это заказчику.

Анна Ухова , инженер-разработчик Роспартнер

Наверно, каждый разработчик на своем программистском поприще рано или поздно сталкивался с ситуацией, когда смотришь на чужой код и думаешь: «Это что, шутка?»

Что же делать, когда открываешь код и на глаза, кроме слез, ничего не попадает? Как не впасть в панику и не положить заявление на стол?

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

0-ой уровень:
проблема с переменными. Это очень абстрактное понятие, но если обобщить, то сюда попадает интуитивно непонятное наименование переменной (ar1, ar2, item), лишние переменные, которые нигде не используются, подтягивание одних и тех же данных несколько раз и т.д. Решить данную проблему достаточно просто, хоть и не доставит особого удовольствия. Переименовать переменные в интуитивно понятный вид (array_for_organization, obuv_items, users_telephones), удалить лишние вызовы, присваивания и переменные.

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

2-ой уровень:
этот «грех» уже серьезнее, чем первые два и может доставить очень много неприятностей. Неоптимизированная выборка, зацикливание и прочее. Что-то, что может повесить систему или страницу (если говорим про веб). Данная ситуация также поправима при наличии головы на плечах, однако куски кода с неоптимальной выборкой придется переписать практически полностью, т.е. придется переделывать работу предыдущего человека, а это долго и вообще очень неприятно.

3-ий уровень:
практически самый серьезный. Отсутствие документации. Очень часто встречаю ситуацию, когда на одной странице вызывается множество различных методов, констант и прочего, но абсолютно непонятно, где все это хранится и что там лежит. Проблема для вас будет заключаться в выявлении возможных ошибок и поиске методов, если код достаточно объемный. Здесь вам на помощь придет поиск и составление собственной документации. Конечно, чем дольше работаешь на одном проекте, тем проще ориентироваться, однако для упрощения жизни себе и другим разработчикам неплохо бы все же составлять краткую выжимку, что где и откуда.

4-ый уровень:
самый серьезный. «Грех» четвертого уровня обычно совершают новички, не особенно знакомые с продуктом, с которым работают. Правка файлов, которые не следует править. Поясню на примере CMS для веб-разработки, т.к. я занимаюсь именно веб-разработкой. Каждая CMS основана на неком ядре, на основе которого разработчик создает нечто свое, но использует те методы, модули и классы, которые изначально заложены ядром. Так вот самый большой грех это правка файлов этого ядра. Этот «грех» очень сложно выявить, практически невозможно устранить и в процессе может доставить очень много неприятных моментов.

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

Всем хорошего дня и побольше качественного кода!

Андрей Черабаев , разработчик в Mediasoft

Если вам «прилетел» плохой код, начните с прямого вопроса заказчику, насколько ему важно сохранить код в текущем состоянии. Если очень важно, можно попытаться доступно и без лишних эмоций объяснить минусы этого решения. В частности, донести до клиента, что низкое качество кода неизбежно увеличивает расходы на дальнейшее развитие продукта. Какие аргументы можно привести?

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

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

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

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

Напоминаем, что вы можете задать свой вопрос экспертам, а мы соберём на него ответы, если он окажется интересным. Вопросы, которые уже задавались, можно найти в списке выпусков рубрики. Если вы хотите присоединиться к числу экспертов и прислать ответ от вашей компании или лично от вас, то пишите на experts@tproger.ru, мы расскажем, как это сделать.

События и курсы

Вакансии

Поздравляем!

Вы успешно подтвердили свою подписку на «Аргументы и функции».

Ждите первое письмо, оно придёт уже совсем скоро!

Legacy: что нужно знать о работе с чужим кодом

Этот вопрос беспокоит подавляющую часть разработчиков. Ведь только успел написать код и он через месяц (а у некоторых и раньше) превращается в какашку legacy код. Этот процесс неизбежен, ведь наши знания и опыт устаревает, в это время технологии продолжают бежать вперед и код просто неизбежно превращается в устаревший делающий свою работу кусок г..на. Все бы ничего, но через годик-другой вам выпадает честь разбираться с очередной проблемой и вы наталкиваетесь на такой код. Он естественно не покрыт тестами, а если и покрыт, то вы в них точно ничего не можете разобрать. Но вам нужно сделать изменения в коде и ничего не поломать. Знакомо?

Мне всегда казалось, что это очень типичная картина. Но я знаю человека, которому в кайф работать с legacy кодом. Это Виктор Полищук. Нам посчастливилось работать вместе на одном проекте и этот человек действительно знает много о вышеописанных проблемах. При этом, он с радостью берется за проекты с такими трудностями и справляется с ними. Мы просто не могли не взять его доклад “Legacy projects: how to win the race” в программу XP Days Ukraine 2014.

Но мы пошли дальше и решили добавить еще один доклад на эту тему – “Refactoring Legacy Сode” от Димы Миндры. Дима – опытнейший разработчик, который за свою карьеру какого только кода не повидал. И не выбрасывал его на свалку, а находил пути жить с ним в мире и согласии, добавляя туда свои изменения по мере надобности. Как именно он это умудрялся делать, Дима расскажет в своем докладе.

Мы также добавили расширенную практическую версию этого доклада, где участники смогут на практике поработать с legacy кодом, изменять его, реструктурировать, добавлять свои изменения и при этом не ломать. Это дорогого стоит. Тренинг называется “Working With Legacy Code in C#” и, как понятно из названия, рассчитан прежде всего на .NET разработчиков. Регистрация уже открыта и количество мест весьма ограничено.

Что касается конференции XP Days Ukraine 2014, то тут вам стоит поторопиться – в продаже осталось меньше 100 билетов и их разбирают достаточно быстро. В этом году программа получилась ну очень уж интересная. Присоединяйтесь!

Добавить комментарий