Как вы читаете чужой код? (legacy)  Публичный пост

Маленькой предисловие:
Недавно перешёл на новую работу (стартап), и с головой окунулся в чтение чужого кода.
То что я уже опробовал:

-Не работает:

  • Тактика чтения в лоб, помогает мало, так как через несколько вложенных функций уже забывается, что было в исходной. А если всё наxодится в разные либах, то мозг вскипает!
  • Расставлять break points и смотреть состояния переменных, не всегда возможно, так как всё крутится в облаках ( ну либо у меня не достаточно опыта).

-Работает:

  • Читать документацию, там где она конечно есть.
  • Бьютилизировать json'ы click .
  • Звонить коллегам, которые писали этот код ( если они ещё есть в команде).
  • Чашечка кофе и музыка.

Kак у Вас происходит процесс вкатывания в legacy?

Связанные посты
36 комментариев 👇
Pavel Ditenbir, Эксперт в области видео, стриминга, кодеков и OTT | разработчик, менеджер 30 июня в 17:04

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

  Развернуть 1 комментарий
Миша Гусаров, Инженегр-погромист 30 июня в 13:59

Эта тема будет неполной без этой книги: https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

  Развернуть 1 комментарий

@dottedmag, только ни в коем случае не покупайте её в русском переводе. Его вообще невозможно читать! Там коры встречаются чуть ли не на кажной странице

  Развернуть 1 комментарий

@telichkin, Уф, спасибо за ценное дополнение, даже и в голову не пришло, что перевод есть, да ещё и плохой :)

  Развернуть 1 комментарий

@telichkin, работа эффективно с шифрами наследия

  Развернуть 1 комментарий
Dima Ollyak, софтваре инжениир 30 июня в 15:03

Примерно в таком порядке:

  • Бегло пролистываю все-все.
  • Ищу доки.
  • Ищу тесты.
  • Иду от вызова, рисуя на бумажке схемку, как оно все устроено.
  • Если есть возможность запустить это все, то запускаю. А потом выкидываю огромные куски, чтобы понять, как оно друг к другу крепится.
  • Пытаюсь приделать какие-нибудь тесты, чтобы зафиксировать текущее состояние.

Для меня самая боль — это легаси код с кучей абстракций. От людей, которые обчитались всякого про DRY и SRP, но поняли это все так странно, что вся логика размазана мелкими мазками по всему проекту и никак не складывается в логичную историю. По сравнению с этим код в процедурном стиле с методами по несколько тысяч строк читается легко и запросто рефакторится.

  Развернуть 1 комментарий

@ollyak, а что, действительно бывало, что находили доки и тесты?

  Развернуть 1 комментарий

@alexpyzhianov, да, конечно.

  Развернуть 1 комментарий
Dmitry Kasyanov, Java Software Developer 30 июня в 11:08

Нередко приходится читать код сквозь слёзы…

А вообще, для начала пробую ознакомиться с докой фичи/проекта. Потом уже с кодом. Если просто ознакомления с кодом недостаточно - ищу товарища, который собсно писал этот проект фичу.

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

  Развернуть 1 комментарий

Не хочу сказать, что я тут самый идеальный в мире программист) Наверняка, и мой код читали/читают тоже сквозь слезы)

  Развернуть 1 комментарий

@shoom, хорошая идея с тестами!

  Развернуть 1 комментарий
Alexey Buravov, Разработчик 30 июня в 12:01

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

старт -> получение данных из Х (тут список полей) -> условие - получение данных из У (список полей) -> завершение; иначе -> модификация -> возврат данных.

без каких-либо конвенций типа UML, просто как мне удобно.

  Развернуть 1 комментарий

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

Пожалуй, я как-нибудь запилю статью на эту тему, но мой посыл - не надо (НЕ НАДО, ПОЖАЛУЙСТА!) использовать интерфейс, если у вас нет сейчас и совершенно точно не планируется подмены реализации в течение ближайшего месяца-двух (я пишу на go, но для других языков тоже актуально). Это никак не улучшит код, а только усложнит его для других.
Вот когда появится как минимум две сущности с одинаковыми методами - тогда и надо добавлять, и не раньше.

  Развернуть 1 комментарий

@nightlord189, вот это у джавашников подорвёт пуканы, давай пиши!!!

  Развернуть 1 комментарий

@ganqqwerty, у джавашников есть нормальная IDE которая все реализации покажет

  Развернуть 1 комментарий

@nightlord189, Обнимемся. Я периодически отстреливаю на ревью ненужные интерфейсы (тоже на Go).

  Развернуть 1 комментарий

@dottedmag, можно небольшое объяснение, когда интерфейс не нужен?

  Развернуть 1 комментарий

@nightlord189,

не надо (НЕ НАДО, ПОЖАЛУЙСТА!) использовать интерфейс, если у вас нет сейчас и совершенно точно не планируется подмены реализации в течение ближайшего месяца-двух (я пишу на go, но для других языков тоже актуально)

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

Туда же неуемная жажда абстракций и DRY.

  Развернуть 1 комментарий

@AleksandrLiadov, Очень простое правило: есть runtime-полиморфизм — интерфейс нужен. Нет runtime-полиморфизма — интерфейс не нужен.

  Развернуть 1 комментарий

@ganqqwerty, кстати нет, мена как джависта самого корежит с подхода "сервис-интерфейсов", когда делают сервис с кучей методов, и типа такие абстрагируют его за интерфейсом, называя это инверсией контроля. Абсолютно отвратительно.

  Развернуть 1 комментарий

@skapral, дак в этом же и идея изолировать Вас как клиента от работы сервиса, дав только интерфейс, разве нет?

  Развернуть 1 комментарий

@AleksandrLiadov, идея верная, но ее осмысление в виде джавовых сервис-интерфейстов мне не импонирует ни на грош.

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

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

Отсюда же вытекает и пагубная практика, которая бесит @nightlord189 - иметь одну имплементацию на интерфейс. Неудивительно - имплементировать нестабильный интерфейс повторно всегда либо больно, либо не имеет смысла.

  Развернуть 1 комментарий

@skapral, у меня нет опыта на java.
А что значит нестабильный интерфейст? Его часто переписывают и надо адаптироваться?

  Развернуть 1 комментарий

@AleksandrLiadov, да, под нестабильностью я имею ввиду нужду частых изменений в сорцах.

  Развернуть 1 комментарий
Дима Черненьков, делаю страховое моделирование для ФО, педалю digital transformation 30 июня в 15:19

С трудом :D

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

  Развернуть 1 комментарий

Сначала можно почитать https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

Она слегка opinionated, но все равно, есть что оттуда надергать из подходов.

Во-вторых, читать надо активно. То есть либо строить схемы какие-то (что как с чем соотносится) либо рисовать какие-то code flow, чтобы понимать как идёт исполнение. В итоге у меня на новых проектах обычно есть пачка каких-то схем, от разных точек входа (например, отдельно для запросов юзера, отдельно для старта приложения и тд и тп)

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

  Развернуть 1 комментарий

@soider, по поводу схем.
Как они выглядят можно пример?
В чем рисуете?

  Развернуть 1 комментарий

@AleksandrLiadov, да пофиг, чё есть под рукой. С блокнота начинаю, если дальше есть какая-то дока куда можно внести, рисую в том, в чем там принято. Если для себя, то plantuml (не потому что я фанат uml, я даже не умею в него, а потому что там кодом диаграмму описать можно)

  Развернуть 1 комментарий

В целом я стараюсь избегать начинать знакомство с проектом с чтения кода в пользу большей практики:

  • осознаю для себя, какую задачу решает этот проект, и какие задачи он не решает
  • разбираюсь как деплоить проект
  • настраиваю IDE/редактор для разработки/отладки, нахожду точку входа, иду с нее по шагам, или беру какое-нибудь пользовательское действие, нахожу код, который за него отвечает, ставлю breakpoint и прохожу несколько шагов, чтобы посмотреть, что в этом участвует
  • читаю документацию, дописываю документацию о том, что я узнал про задачи и деплоймент (как правило то что есть уже слегка устарело)
  • понимаю, как запускать тесты, запускаю, и, если это не выглядит неподьемным, пытаюсь починить те тесты, которые фейлятся
  • пишу какую нибудь небольшую фичу/чиню баг чтобы начать разбираться в проекте
  • участвую в митингах, связанных с проектом, и задаю глупые вопросы

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

  Развернуть 1 комментарий
Anatoly Shipitsin, Специалист по НЕХ 30 июня в 11:54

Что работает

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

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

  Развернуть 1 комментарий
Артемий Утехин, Full-stack crutch developer 30 июня в 12:04

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

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

  Развернуть 1 комментарий
Pavel Galeev, SW Embedded Designer 30 июня в 13:45

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

Потому иду итерациями

  • работает? хорошо если да
  • работает как должно?
  • тесты есть?
  • работают как должны?
  • пошли разбирать код по исполнению с записями
  • рефакторим/меняем
  • добавляем комменты
  • повторяем сначала
  Развернуть 1 комментарий

@gapel, с записями на листочек или начинаете писать документацию?

  Развернуть 1 комментарий

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

  Развернуть 1 комментарий
Roman Musin, Señor Developer 30 июня в 14:53

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

  Развернуть 1 комментарий
Mironov George, Программист 30 июня в 16:08

Ну как бы для чего именно мне надо читать это легаси?

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

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

  Развернуть 1 комментарий

😎

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

Что вообще здесь происходит?


Войти  или  Вступить в Клуб