Контекст: я корпоративный разработчик в магазине MS.
Кто-нибудь может порекомендовать хороший способ объективного измерения ремонтопригодности фрагмента кода или приложения?
Почему ремонтопригодность : я устал от «качественных» показателей в моей группе, вращающихся только вокруг количества ошибок и покрытия кода. Обе метрики просты в игре, особенно если вы не измеряете ремонтопригодность. Недальновидность и сроки приводят к огромному техническому долгу, который никогда не решается.
Почему умение объективно измерять : я работаю в большой группе предприятий. Если вы не можете объективно измерить это, вы не можете заставить людей отвечать за это или заставить их стать лучше в этом. Субъективные измерения либо не происходят, либо не происходят последовательно.
Я смотрю на метрики кода VS2010 , но мне интересно, есть ли у кого-нибудь другие рекомендации.
Ответы:
Реальность такова, что, если у вас нет конкретных доказательств того, что код не может быть исправлен, как ... то есть ... исправление ошибки вызвало N часов ненужного времени из-за неисправимого кода; тогда иметь ногу на ногу будет сложно. В этом примере это могло быть вызвано тем, что использовалась слишком сложная методология, когда чего-то гораздо более простого было бы достаточно. Вхождение в область, где вы пытаетесь измерить методологии, парадигмы и лучшие практики, становится все труднее с минимальными или нулевыми выгодами.
Идти по этому пути, к сожалению, путь в никуда. Сосредоточьтесь на выявлении корневых проблем, которые имеют существенную ценность и не связаны с личными чувствами по поводу такой проблемы, как отсутствие соглашений о присвоении имен по всей базе кода, и найдите способ измерить успехи и неудачи вокруг этой корневой проблемы. Это позволит вам начать собирать набор строительных блоков, из которых вы сможете начать формулировать решения вокруг.
источник
Ну, мера, которую я использую, или, как мне кажется, я использую, заключается в следующем:
Для каждого независимого, единственного, однострочного, функционального требования типа «возьми или оставь» сделайте снимок базы кода перед его реализацией. Затем осуществите это, включая поиск и исправление ошибок, допущенных в процессе. Затем запустите
diff
между кодом базы до и после.diff
Покажет вам список всех вставок, удалений и модификаций , которые реализованы изменения. (Например, вставка 10 последовательных строк кода - это одно изменение.) Сколько было изменений? Как правило, чем меньше это число, тем более понятен код.Я называю это избыточностью исходного кода, потому что это похоже на избыточность кода с исправлением ошибок. Информация содержалась в 1 чанке, но была закодирована как N чанков, которые должны быть выполнены вместе, чтобы быть последовательными.
Я думаю, что это идея DRY, но она немного более общая. Причина, по которой хорошо, что этот счет является низким, заключается в том, что если для реализации типичного требования требуется N изменений, и, как ошибочный программист, сначала вы выполняете только N-1 или N-2 из них правильно, вы помещаете 1 или 2 ошибки. В дополнение к программированию O (N), эти ошибки должны быть обнаружены, найдены и устранены. Вот почему маленький N это хорошо.
Поддерживаемость не обязательно означает читабельность для программиста, который еще не изучил, как работает код. Оптимизация N может потребовать выполнения некоторых вещей, которые создают кривую обучения для программистов. Вот пример. Одна вещь, которая помогает, - это если программист пытается предвидеть будущие изменения и оставляет инструкции в комментариях к программе.
Я думаю, что когда N уменьшается достаточно далеко (оптимум равен 1), исходный код читается больше как предметно-ориентированный язык (DSL). Программа не столько «решает» проблему, сколько «излагает» проблему, потому что в идеале каждое требование просто повторяется как отдельный фрагмент кода.
К сожалению, я не вижу людей, которые учатся делать это очень много. Скорее, они, кажется, думают, что ментальные существительные должны стать классами, а глаголы - методами, и все, что им нужно сделать, - это повернуть ручку. По моему опыту, это приводит к коду с N или более 30.
источник
Ремонтопригодность на самом деле не так измерима. Это субъективный взгляд на человека, основанный на его опыте и предпочтениях.
Для придания куска кода придумайте идеальный дизайн.
Затем для любого отклонения реального кода от идеального уменьшите значение 100 на некоторое число. От чего именно зависит последствия выбора неидеального подхода.
Пример:
Часть кода считывает и импортирует некоторый формат данных и может показать сообщение об ошибке, если что-то не так.
Идеальное решение (100) будет содержать сообщения об ошибках в одном общем месте. Если в вашем решении они жестко запрограммированы как строковые константы непосредственно в коде, вы берете, скажем, 15. Таким образом, ваш показатель ремонтопригодности становится 85.
источник
Одним из результатов кода, который трудно поддерживать, является то, что вам потребуется больше времени (в среднем) для исправления ошибок. Таким образом, на первый взгляд может показаться, что одна метрика - это время, необходимое для исправления ошибки с момента ее назначения (т. Е. Исправление начато) до момента, когда она «готова к тестированию».
Теперь это действительно будет работать только после того, как вы исправите разумное количество ошибок, чтобы получить «среднее» (что бы это ни значило) время. Вы не можете использовать эту цифру для какой-либо конкретной ошибки, так как то, насколько сложно ее отследить, зависит не только от "ремонтопригодности" кода.
Конечно, когда вы исправляете больше ошибок, код становится «легче» поддерживать по мере того, как вы делаете его лучше (или, по крайней мере, так и должно быть), и вы все больше знакомитесь с кодом. В противовес этому факту ошибки будут более неясными и, следовательно, их будет еще труднее выследить.
Это также страдает от проблемы, заключающейся в том, что если люди будут стремиться срочно исправлять ошибки, чтобы получить более низкий балл, то есть либо они будут вызывать новые ошибки, либо некорректно исправлять существующую, что приведет к еще большей работе и, возможно, к еще худшему коду.
источник
Я нахожу метрики кода Visual Studio вполне подходящими для обеспечения быстрой метрики "ремонтопригодности". 5 основных метрик:
Индекс ремонтопригодности - это тот, который мне удобен. Это составной индекс, основанный на:
Иногда я смотрю на мои методы с низким индексом ремонтопригодности (низкий = плохой для этого). Практически в обязательном порядке методы в моем проекте с самым низким индексом ремонтопригодности наиболее нуждаются в переписывании и труднее всего читать (или поддерживать).
См. Белую книгу для получения дополнительной информации о расчетах.
источник
Два, которые будут иметь смысл, это цикломатическая сложность и классовая связь. Вы не можете устранить сложность, все, что вы можете сделать, это разделить ее на управляемые части. Эти 2 меры должны дать вам представление о том, где может быть расположен сложный в обслуживании код или, по крайней мере, где искать наиболее сложный код.
Цикломатическая сложность - это показатель количества путей в коде. Каждый путь должен быть проверен (но, вероятно, нет). Что-то со сложностью выше 20 должно быть разбито на более мелкие модули. Модуль с цикоматической сложностью 20 (можно дублировать его с 20 последовательными
if then else
блоками) будет иметь верхнюю границу 2 ^ 20 путей для тестирования.Связывание классов является мерой того, насколько тесно связаны классы. Пример плохого кода, с которым я работал у моего предыдущего работодателя, включает компонент «слой данных» с около 30 элементами в конструкторе. Человек, в основном «ответственный» за этот компонент, продолжал добавлять бизнес-параметры и параметры уровня пользовательского интерфейса в вызовы конструктора / открытия, пока он не стал действительно большим шариком грязи. Если память мне не изменяет, было около 15 различных новых / открытых вызовов (некоторые больше не использовались), все с немного разными наборами параметров. Мы ввели обзоры кода с единственной целью помешать ему делать больше подобных вещей - и чтобы не было похоже, что мы его выделяем, мы рассмотрели код каждого в команде, поэтому мы потратили около полдня на 4-6 люди каждый день, потому что мы не
источник
В итоге ремонтопригодность действительно может быть измерена только после того, как требуется, а не до . То есть, вы можете только сказать, является ли часть кода ремонтопригодной, когда вам нужно ее поддерживать.
Относительно очевидно, насколько легко было приспособить кусок кода к изменяющимся требованиям. Это почти невозможно измерить заранее, как он будет реагировать на изменения требований. Это будет означать, что вы должны прогнозировать изменения в требованиях. И если вы можете сделать это, вы должны получить нобелевскую цену;)
Единственное, что вы можете сделать, - это согласовать с вашей командой набор конкретных правил (таких как принципы SOLID), которые, как вы все считаете, в целом повышают удобство обслуживания.
Если принципы выбраны правильно (я думаю, что начать с SOLID было бы хорошим выбором для начала), вы можете совершенно ясно продемонстрировать, что они нарушаются, и привлечь к ответственности авторов.
Вам будет очень тяжело, пытаясь продвигать абсолютную меру ремонтопригодности, при этом постепенно убеждая свою команду придерживаться реалистичного согласованного набора установленных принципов.
источник
А как насчет технического долга, который "настигает события"?
Я пишу дерьмовый код и запускаю его в производство.
Вы замечаете - правильно - что это не поддается ремонту.
Этот код, однако, является последним набором функций для продуктовой линейки, который будет выведен из эксплуатации, поскольку правовой контекст изменился, и у продуктовой линейки нет будущего.
«Технический долг» устраняется законодательным изменением, которое делает его устаревшим.
Показатель «ремонтопригодности» изменился с «плохого» на «неактуальный» из-за внешних факторов.
Как это можно измерить?
источник
Следующая лучшая вещь для обзоров одноранговых кодов - это создать работоспособную архитектуру до кодирования единицы или продукта. Красно-зеленый-рефакторинг - это довольно аккуратный способ сделать это. Пусть старший парень соберет работоспособный интерфейс и поделится работой. Каждый может взять свой кусочек пазла и красно-зеленый путь к победе. После этого будет проведен обзор и рефакторинг кода. Это сработало чертовски хорошо в прошлом главном продукте, над которым я работал.
источник
Анкета
Как насчет создания анонимной анкеты для разработчиков, чтобы заполнить один раз в месяц или около того? Вопросы будут примерно такими:
(Не стесняйтесь добавлять дополнительные вопросы, которые, по вашему мнению, были бы полезны для оценки ремонтопригодности в комментариях, и я добавлю их.)
источник
Я могу придумать два способа взглянуть на ремонтопригодность (я уверен, что есть еще надежда, что другие могут придумать хорошие определения).
Модификация без понимания.
Может ли средство исправления ошибок войти в код и исправить проблему, не понимая, как работает вся система?
Это может быть достигнуто путем предоставления комплексных модульных тестов (регрессионных тестов). Вы должны быть в состоянии проверить, что любое изменение в системе не меняет того, как система ведет себя, с любым конкретным хорошим входом.
В этой ситуации средство исправления ошибок должно быть в состоянии прийти и исправить (простую) ошибку с минимальным знанием системы. Если исправление работает, то ни один из регрессионных тестов не должен пройти неудачно. Если какие-либо регрессионные тесты не пройдены, вам нужно перейти к этапу 2.
Модификация с пониманием.
Если исправление ошибки становится нетривиальным, и вам необходимо понять систему. Тогда какова документация системы. Мы не говорим о документации внешнего API (они относительно бесполезны). Что нам нужно понять, так это то, как работает система, где используются какие-то хитрые (читайте хаки) трюки в реализациях и т. Д.
Но документации недостаточно, код должен быть ясным и понятным. Чтобы измерить понятность кода, мы можем использовать небольшую хитрость. После того, как разработчик закончит кодирование, дайте ему / ей месяц на работу над чем-то другим. Затем попросите их вернуться и документировать систему до такой степени, чтобы мол теперь мог понять систему. Если код относительно прост для понимания, он должен быть быстрым. Если он написан плохо, им потребуется больше времени, чтобы разобраться в том, что они создали, и написать документацию.
Так что, возможно, мы могли бы придумать некоторую меру этого:
источник
Я часто нахожу, что «самое короткое эквивалентное» решение имеет тенденцию быть наиболее приемлемым.
Здесь самый короткий означает наименьшее количество операций (не строк). И эквивалентный означает, что более короткое решение не должно иметь худшую временную или пространственную сложность, чем предыдущее решение.
Это означает, что все логически похожие повторяющиеся шаблоны должны быть извлечены в соответствующую абстракцию: Похожие блоки кода? Извлеките это, чтобы функционировать. Переменные, которые, кажется, встречаются вместе? Извлеките их в структуру / класс. Классы, члены которых отличаются только типом? Вам нужен универсальный. Вы, кажется, пересчитываете одно и то же во многих местах? Рассчитайте в начале и сохраните значение в переменной. Выполнение этого приведет к сокращению кода. Это принцип СУХОЙ в принципе.
Мы также можем согласиться с тем, что неиспользуемые абстракции должны быть удалены: классы, функции, которые больше не нужны, являются мертвым кодом, поэтому его следует удалить. Контроль версий запомнит, если нам когда-нибудь понадобится восстановить его.
То, что часто обсуждается, это абстракции, на которые ссылаются только один раз: функции без обратного вызова, которые вызываются только один раз, без причины, чтобы их вызывали более одного раза. Универсальный объект, который создается с использованием только одного типа, и нет никаких причин, по которым он когда-либо будет создаваться с другим типом. Интерфейсы, которые реализуются только один раз, и нет никакой реальной причины, чтобы это было когда-либо реализовано любым другим классом и так далее. Мое мнение, что эти вещи не нужны и должны быть удалены, это в основном принцип ЯГНИ.
Таким образом, должен быть инструмент, который может обнаружить повторение кода, но я думаю, что эта проблема сродни поиску оптимального сжатия, что является проблемой сложности Колмогорова, которая неразрешима. Но с другой стороны, неиспользуемые и недостаточно используемые абстракции легко обнаружить по количеству ссылок: проверка для этого может быть автоматизирована.
источник
Все это субъективно, и любое измерение, основанное на самом коде, в конечном итоге не имеет значения. В конце концов, все сводится к вашей способности удовлетворять потребности. Можете ли вы по-прежнему предоставлять запрашиваемые функции и, если можете, как часто эти изменения будут возвращаться вам, потому что что-то еще не совсем правильно, и насколько серьезны эти проблемы?
Я просто (пере) определил ремонтопригодность, но она все же субъективна. С другой стороны, это может не иметь большого значения. Нам просто нужно удовлетворить нашего клиента и наслаждаться им, вот к чему мы стремимся.
Очевидно, вы чувствуете, что должны доказать своему боссу или коллегам, что нужно что-то сделать, чтобы улучшить состояние кодовой базы. Я бы сказал, что вам должно быть достаточно сказать, что вы разочарованы тем фактом, что для каждой мелочи, которую вы должны изменить или добавить, вам нужно исправить или обойти 10 других проблем, которых можно было бы избежать. Затем назовите печально известную область и составьте кейс, чтобы перевернуть его. Если это не вызывает поддержки в вашей команде, вам может быть лучше где-то еще. Если окружающие вас люди не заботятся, то доказательство своей точки зрения не изменит их мнение.
источник