Как сделать рефакторинг в visual studio

Обновлено: 07.07.2024

  1. Есть ли способ заставить плагин Perforce делать правильные вещи в первую очередь?
  2. Если нет, есть ли способ примириться постфактум извне? (Будет ли у Perforce какой-либо способ распознавать файлы, которые были перемещены и, возможно, переименованы, и содержали ограниченные изменения содержимого?)
  3. Есть ли другой продукт управления версиями, который прозрачно справляется с этим?

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

Для интеграции с Visual Studio вы можете попробовать Git Extensions. Для интеграции оболочки Explorer см. TortoiseGit.

VS Макрос

С помощью этого макроса вы можете как минимум правильно переименовать файл в Visual Studio.
Я думаю, что невозможно правильно переименовать класс и файл сразу (как это делает, например, ReSharper), потому что переименование и изменение файла в одном списке изменений невозможно в Perforce.

FWIW, версия 1.74 VS2P4, выпущенная сегодня, имеет значительные улучшения производительности, особенно для решений с тысячами файлов.

Я попробовал VS2P4 с контекстной справкой ReSharper «Переименовать файл в соответствии с именем типа». А также.

Это не работает. Он показывает диалог

enter image description here

И если я нажму «Продолжить с изменением», он действительно выполнит то, о чем говорилось в предупреждении. Он удаляет и добавляет файлы, не сообщая об этом Perforce. Проверяется только файл проекта.

Вот запутанное решение, если вам действительно нужно сохранить эту информацию:

  1. Создайте клон Mercurial депо Perforce (или подраздела) с помощью расширения Perfarce.
  2. Установите подключаемый модуль VisualHg SCC, который является интеграцией Mercurial в VS
  3. Сделайте свой рефакторинг - VisualHg, я считаю, правильно справляется с переименованием. Это, безусловно, работает в случае ручного переименования файла из Visual Studio, поэтому я предполагаю, что Resharper тоже будет работать.
  4. Отправьте изменения из Mercurial обратно в Perforce. Это должно включать в себя необходимые вам операции ветвления и удаления (перемещения).

Обратите внимание: я не пробовал это, поскольку у меня нет Resharper, но ссылка Perforce-> Mercurial-> Perforce хорошо работает с Perfarce, а VisualHg значительно превосходит другие плагины SCC, которые я использовал. Так что, возможно, стоит попробовать. Вероятно, вы могли бы сначала быстро вывести ссылку Resharper / VisualHg, и если все пойдет хорошо, выполните шаг Perforce-> Mercurial.

Нет, я не в курсе. Обратитесь в службу поддержки Perforce.

Я бы не пошел по этому пути.

На самом деле это не другой продукт управления версиями, но вы можете попробовать VS2P4 вместо P4SCC, который, похоже, работает с классом переименования ReSharper. рефакторинг. Некоторое время назад я совершил переход, и он мне очень нравится, хотя в нем есть свои особенности. Доступно для установки через VS2010 Extension Manager.

Вы можете увидеть полную историю, посмотрев на график ревизий файла.

Шаги, которые необходимо предпринять: 1) Переименуйте файл 2) Щелкните правой кнопкой мыши и просмотрите историю только что названного файла 3) Он показывает только текущую версию, но, если вы щелкните правой кнопкой мыши на этой версии и выберите график ревизий, который вы можете увидеть полную историю со ссылкой, по которой происходит удаление / добавление. 4) Вы можете выбрать узлы на графике и выполнить сравнение, чтобы увидеть изменения между разными файлами.

Это дополнительный шаг и не очень очевидный, но он работает для меня.

В Perforce 2009.2 и более поздних версиях есть команда перемещения p4. Это не идеально, вы сохраняете историю в файлах, но при выборе папки история не отображается в p4v.

Новый плагин Perforce, P4VS, намного лучше справляется с управлением перемещенными / переименованными файлами в Visual Studio. Если вы пробовали только P4SCC и были разочарованы, попробуйте P4VS. Я обнаружил, что он делает «правильные» вещи в большинстве случаев, когда P4SCC просто не работает.

Это недостаток других систем управления версиями, а не только Perforce. TFS страдает той же проблемой.

В прошлую пятницу вышел релиз Visual Studio 2015 Preview, в котором были представлены новые возможности увеличения продуктивности разработки, в том числе рефакторинг кода на С++. В значительной мере на реализацию этого функционала повлияли отзывы комьюнити, которые были получены в ходе тестирования Visual Studio «14» CTPs, так что спасибо всем поучаствовавшим.

  • Переименование (Rename)
  • Извлечение функции (Extract Function)
  • Генерация заглушек чисто виртуальных методов (Implement Pure Virtuals)
  • Генерация объявлений/заглушек методов (Create Declaration/Definition)
  • Перемещение объявлений функций (Move Function Definition)
  • Преобразование в Raw-String (Convert to Raw-String Literal)

image

image

  • Вы можете отключить поиск переименовываемого символа в комментариях и строковых литералах в первом окне (галочка «Search comments/strings»)
  • Также вы можете включить просмотр найденных в комментариях и строках символов, но не переименовывать их (галочка «Rename comments/strings»)
  • Больше информации об этой фиче вы можете найти вот в этом видео

Извлечение функции было второй по количеству запросов фичей. Мы всё ещё в процессе работы над ней, так что пока что она реализована в виде расширения. После его установки выделите блок кода, который хотите выделить в отдельную функцию, затем правый клик и в меню «Refactor…» выберите «Extract Function/Method».

image

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

Генерация заглушек виртуальных методов позволяет создать тела всех чисто виртуальных методов в наследуемом классе. Поддерживается множественное наследование. Инструмент вызывается из контекстного меню объявления класса.

image

  • Инструмент генирирует объявления методов в заголовочном файле, а сами заглушки — в cpp-файле.
  • Вы можете вызвать генерацию заглушек только для одного из базовых классов, из контекстного меню названия этого класса в объявлении наследуемого класса:
  • Операция отмены (undo) удалит все сгенерированные заглушки, но не удалит cpp-файл, если он был создан на предыдущем шаге
  • Больше информации об этом инструменте вы можете найти в этом видео

Важный момент: все вышеперечисленные функции работают только при включенном IntelliSense.

Генерация объявлений/заглушек методов позволяет вам быстро сгенерировать недостающее объявление или заглушку тела метода.

image

image

  • Методы, имеющие тело, но не определённые в заголовочном файле будут подчёркнуты волнистой зелёной линией
  • Можно сгенирировать определения\заглушки сразу для нескольких методов (нужно выделить все и выбрать в контекстном меню «Refactor->Create Declaration/Definition»)
  • Больше информации об этом инструменте вы можете найти в этом видео

Перемещение объявлений методов позволяет быстро переместить тело метода из заголовочного файла в cpp-файл или наоборот.

image

  • Больше информации об этом инструменте вы можете найти в этом видео

Преобразование в Raw-String позволяет вам сконвертировать любую строку в Raw-String, что значительно улучшает читабельность строк с escape-последовательностями. Функция вызывается из контекстного меню в любом месте строки.

Компиляция практически всего коммерческого программного обеспечения на стадии отладки и на стадии подготовки окончательной версии продукта должна проводиться немного по-разному. Среда Visual Studio способна понимать это, поскольку сохраняет информацию обо всех параметрах, которые ей надлежит передавать компилятору. Для поддержки разных вариантов компоновки проекта Visual Studio потребуется сохранять подобную информацию в более чем одном экземпляре. Разные экземпляры такой информации называются конфигурациями. При создании проекта Visual Studio автоматически предлагает на выбор две таких конфигурации, которые называются, соответственно, Debug (Отладка) и Release (Выпуск):

Можно также определять собственные конфигурации. Это необходимо, например, для компоновки приложения с несколькими отличающимися версиями. Раньше из-за проблем, связанных с поддержкой кодировки Unicode в Windows NT, но не в Windows 95,для многих проектов на С++ было принято создавать две конфигурации — одну для Unicode,а вторую для MBCS (multibyte character set — набор многобайтных символов).

Рефакторинг и расширение кода проекта

Рефакторинг и расширение кода

Рефакторинг кода проекта

При создании приложений многие разработчики сначала заботятся об их функциональности, а когда она обеспечена, переделывают приложения таким образом, чтобы они были более управляемыми и удобочитаемыми. Это называется рефактарингом (refactoring). Под рефакторингом понимается процесс переделки кода для повышения удобочитаемости и производительности приложений, а также обеспечения безопасности типов и приведения кода к такому виду, в котором он лучше соответствует рекомендуемым приемам объектно-ориентированного программирования. К счастью, теперь в Visual Studio 2010 можно достаточно хорошо автоматизировать этот процесс.

За счёт использования меню Refactor (Рефакторинг), которое становится доступным при открытом файле кода, а также соответствующих клавиатурных комбинаций быстрого вызова, смарт-тегов (smart tags) и/или вызывающих контекстные меню щелчков, можно существенно видоизменять код с минимальным объемом усилий. В следующей таблице перечислены некоторые наиболее распространенные приемы рефакторинга, которые распознаются в Visual Studio 2010:

Чтобы увидеть процесс рефакторинга в действии, давайте модифицируем метод Main, добавив в него следующий код:

static void Main()

// Настраиваем консольный интерфейс (CUI)

Для этого выделите в окне редактора все содержащиеся внутри Main операторы, кроме последнего вызова Console.ReadLine(), и щёлкнем на выделенном коде правой кнопкой мыши. Выберем в контекстном меню пункт Refactor -> Extract Method (Рефакторинг -> Извлечь метод. ).

В открывшемся далее окне назначим новому методу имя MyConfigCUI:


Рис. 1. 1. Извлечение метода: создание нового метода из кода

После этого метод Main станет вызывать новый только что сгенерированный MyConfigCUI(), внутри которого будет содержаться выделенный ранее код:

static void Main()

private static void MyConfigCUI()

// Настраиваем консольный интерфейс (CUI)

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

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

Предлагаемые Visual Studio 2010 возможности рефакторинга представляют собой поистине замечательный способ для получения более чистого, удобочитаемого и лучше структурированного кода.

Расширение кода проекта

  • Шаблоны для вставки фрагментов кода (Code Snippet). Эти шаблоны позволяют вставлять общие блоки кода в месте расположения курсора мыши.
  • Шаблоны для окружения кода (Surround With). Эти шаблоны позволяют помещать блок избранных операторов в рамки соответствующего контекста.

Чтобы посмотреть на эту функциональность в действии, давайте предположим, что требуется обеспечить проход по поступающим в метод Main параметрам в цикле foreach.

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

Поместим курсор мыши после первой открывающей фигурной скобки в методе Main. Одним из способов активизации фрагмента кода является выполнение щелчка правой кнопкой мыши и выбора в контекстном меню пункта Insert Snippet (Вставить фрагмент. ) или Surround With (Разместить во фрагменте. ). Это приводит к отображению списка всех относящихся к данной категории фрагментов кода (для закрытия контекстного меню достаточно нажать клавишу Esc). В качестве клавиатурной комбинации быстрого вызова можно просто ввести имя интересующего фрагмента кода, которым в данном случае является foreach:


Рис. 2. 1. Вставка фрагмента кода

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

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

Конструктор классов

Конструктор классов

Для работы с этой утилитой сначала необходимо вставить новый файл диаграммы классов. Делать это можно несколькими способами, одним из которых является щелчок на кнопке View Class Diagram (Перейти к диаграмме классов) в правой части окна Solution Explorer (Обозреватель классов), как показано на рисунке ниже (при этом важно, чтобы в окне был выбран проект, а не решение):


Рис. 1. 1. Создание диаграммы классов для проекта LC_Console

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


Рис. 1. 2. Диаграмма классов проекта LC_Console

Эта утилита работает вместе с двумя другими средствами Visual Studio 2010 — окном Class Details (Сведения о классах), которое можно открыть путём выбора в меню View (Вид) пункта Other Windows (Другие окна), и панелью Class Designer Toolbox (Конструктор классов), которую можно отобразить выбором в меню View (Вид) пункта Toolbox (Панель элементов).

В окне Class Details не только отображаются детали выбранного в текущий момент элемента в диаграмме, но также можно изменять его существующие члены и вставлять новые на лету:


Рис. 1. 3. Окно «Сведения о классах» проекта LC_Console


Рис. 1. 4.Окно Конструктор классов»

Для примера давайте перетащим из панели Class Designer Toolbox в окно Class Designer новый элемент Class (Класс), в отрывшемся окне назначим ему имя MyСаr, а затем с помощью окна Class Details добавим в него общедоступное поле типа string по имени AutoName:


Рис. 1. 5. Добавление нового класса и поля для проекта LC_Console

Теперь давайте активизируем утилиту Class Designer еще раз и перетащим на поверхность конструктора новый элемент типа Class, присвоив ему имя MySportCar. Затем выберем в Class Designer Toolbox пиктограмму Inheritance (Наследование) и щёлкнем в верхней части пиктограммы MySportCar. Далее, не отпуская левую кнопку мыши, перетащим курсор мыши на поверхность пиктограммы класса MyСаr и отпустим её. Правильное выполнение всех перечисленных выше действий приведёт к тому, что класс MySportCar станет наследоваться от класса MyСаr:


Рис. 1. 6. Итоговая диаграмма классов проекта LC_Console

Чтобы завершить данный пример, осталось обновить сгенерированный MySportCar, добавив в него общедоступный метод с именем GetAutoName:

Вторая статья про рефакторинг в Python. Первую статью можно почитать здесь.


Рефакторинг в Python

Одна из старейших в мире подземных железных дорог, лондонское метро, было основано в 1863 году. Это было метро с деревянные вагонами с газовой подсветкой, перевозимые паровозами. И только в 1900 году появились электрические поезда.

К 1908 году лондонское метро расширилось до 8 железных дорог. Во время Второй мировой войны станции лондонского метро были закрыты для поездов и использовались в качестве бомбоубежищ. Современное лондонское метро перевозит миллионы пассажиров в день на более чем 270 станциях:


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

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

В этой статье вы узнаете, как безопасно проводить рефакторинг, используя тесты и современные инструменты. Вы также увидите, как использовать функцию рефакторинга в Visual Studio Code и PyCharm:


Избежание рисков с помощью рефакторинга: использование инструментов и проведение тестов

Если смысл рефакторинга состоит в том, чтобы улучшить внутреннюю часть приложения, не влияя на внешние, как узнать, что внешние элементы не изменились?

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

Если вы хотите узнать больше о тестировании в Python, почитайте эту статью Getting Started With Testing in Python.

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

Две наиболее распространенные задачи, которые вы будете выполнять при рефакторинге:

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

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

Использование rope для рефакторинга

rope можно использовать двумя способами:

  1. Используя плагин редактора, для Visual Studio Code, Emacs, или Vim
  2. Непосредственно путем написания скриптов для рефакторинга вашего приложения

Чтобы использовать rope в качестве библиотеки, сначала установите rope, выполнив команду pip:

Полезно работать с rope в REPL, чтобы вы могли изучить проект и увидеть изменения в режиме реального времени. Для начала импортируйте тип Project и создайте его экземпляр с указанием пути к проекту:

Переменная proj теперь может выполнять ряд команд, таких как get_files и get_file, чтобы получить конкретный файл. Получите файл api.py и назначьте его переменной api:

Если вы хотите переименовать этот файл, вы можете просто переименовать его в файловой системе. Однако любые другие файлы Python в вашем проекте, которые импортировали старое имя, теперь будут повреждены. Давайте переименуем api.py в new_api.py через rope:

Запустив git status, вы увидите, что rope внесла некоторые изменения в репозиторий:

Три изменения, сделанные с помощью rope, следующие:

  1. Удален requests/api.py и создан requests/new_api.py
  2. Изменен requests/__init__.py , в нем добавлен импорт new_api и удален импорт api
  3. Создана новая директория .ropeproject

Что бы сбросить все изменения вы можете запустить git reset .

Обо всем что можно сделать с rope можно почитать здесь.

Использование кода Visual Studio для рефакторинга

Visual Studio Code содержит небольшое подмножество команд рефакторинга, доступных в отдельном пользовательском интерфейсе.

С помощью его вы можете:

  1. Извлечь переменные из оператора
  2. Извлечь методы из блока кода
  3. Отсортировать импорт в логическом порядке

Вот пример использования команды «Извлечь методы» из палитры команд:

Использование PyCharm для рефакторинга

Если вы используете или планируете использовать PyCharm в качестве редактора Python, стоит обратить внимание на его мощные возможности рефакторинга.

Поиск вызывающих сущностей и использование функций и классов

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

Чтобы получить доступ к этой функции, выберите метод, класс или переменную, щелкнув правой кнопкой мыши и выберите «Найти использование»(Find Usages):

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

Использование инструментов рефакторинга PyCharm

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

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

Вот пример переименования того же модуля api.py, который вы переименовали ранее, с помощью rope в new_api.py:

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

Другим полезным рефакторингом является команда Изменить подпись (Change Signature). Она может быть использовано для добавления, удаления или переименования аргументов функции или метода. Эта команда ищет все случаи использования и обновляет их для вас:

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

Выводы

Анти-паттерны сложности

Теперь, когда вы знаете, как можно измерить сложность, как ее измерить и как реорганизовать ваш код, пришло время изучить 5 распространенных анти-шаблонов, которые делают код более сложным, чем нужно:


1. Функции, которые должны быть объектами

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

Возьмем для примера модуль для работы с изображениями. Логика в функциях была удалена для краткости:

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

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

Вот как может выглядеть вызывающий код:

Некоторые признаки кода, использующего функции, который может быть преобразованы в классы:

  • Подобные аргументы в разных функциях
  • Большее число уникальных операндов (Halstead h2)
  • Смешивание изменчивых (mutable) и неизменных (immutable) функций
  • Функции распределены по нескольким файлам Python

Переработанная версия этих трех функций, где происходит следующее:

  • .__init__() заменяет load_image() .
  • crop() становится методом класса.
  • get_image_thumbnail() становится свойством.

Переменная thumbnail_resolution стало свойством класса, теперь его можно изменить глобально или в конкретном случае:

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

Как теперь будет выглядеть измененный пример:

В полученном коде мы решили исходные проблемы:

  • Теперь понятно, что thumbnail возвращает эскиз, так как это свойство, и что он не изменяет экземпляр.
  • Код больше не требует создания новых переменных для операции обрезки (crop).

2. Объекты, которые должны быть функциями

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

Вот несколько признаков неправильного использования классов:

  • Классы с 1 методом (кроме .__init__ ())
  • Классы, которые содержат только статические методы

Возьмем этот пример класса аутентификации:

Было бы разумнее иметь простую функцию authenticate(), которая принимает имя пользователя и пароль в качестве аргументов:

Вам не нужно сидеть и искать классы, которые соответствуют этим критериям вручную: в pylint есть правило, согласно которому классы должны иметь как минимум 2 открытых метода. Чтобы узнать больше о PyLint и других инструментах проверки качества кода, вы можете почитать здесь Python Code Quality.

Чтобы установить pylint, введите в консоли следующую команду:

Этот вывод говорит нам, что auth.py содержит 2 класса, которые имеют только 1 открытый метод. Эти классы находятся в строках 72 и 100. Существует также класс в строке 60 models.py только с одним открытым методом.

3. Преобразование «Triangular» кода в плоский код

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

Один из принципов в дзен Python (Zen of Python) гласит:

Плоский код лучше вложенного “Flat is better than nested”

— Tim Peters, Zen of Python

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

Признаки сильно вложенного кода:

  • Высокая цикломатическая сложность из-за количества ветвей кода
  • Низкий индекс ремонтопригодности из-за высокой цикломатической сложности относительно количества строк кода

Возьмем этот пример, который просматривает аргумент data на наличие строк, которые соответствуют слову error. Сначала проверяется, является ли аргумент data списком. Затем он перебирает каждый из них и проверяет, является ли элемент строкой. Если это строка и значение соответствует слову «error», то возвращается True. В противном случае возвращается False:

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

Вместо этого мы можем реорганизовать эту функцию, так чтобы удалить уровень вложенности и вернув False, если значение data не указано в списке. Затем с помощью .count() объекта списка для подсчета наличия «error». Тогда возвращаемое значение будет оценкой того, что .count() больше нуля:

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

Этот код можно заменить более быстрым и эффективным генератором списка (list comprehension).

Преобразуйте последний пример в список с оператором if:

Этот новый пример меньше, имеет меньшую сложность и более производительный.

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

Itertools также содержит функции для фильтрации данных, такие как filterfalse() . Чтобы узнать больше об Itertools, ознакомьтесь с Itertools in Python 3, By Example.

4. Обработка сложных словарей с помощью инструментов запросов

Одним из самых мощных и широко используемых типов данных Python является словарь. Этот тип быстр, эффективен, масштабируем и очень гибок.

Если вы новичок в словарях, вы можете почитать Dictionaries in Python.

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

Возьмем этот пример данных, пример линий метро Токио, которые вы видели ранее:

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

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

Существуют сторонние инструменты для запроса словарей в Python. Одними из самых популярных являются JMESPath, glom, asq и flupy.

При работе со списками вы можете использовать квадратные скобки и предоставить запрос внутри. Что создать запрос «Все» просто используйте *. Затем вы можете добавить имя атрибута внутри каждого соответствующего элемента для возврата. Если вы хотите получить номер строки для каждой строки, вы можете сделать это:

Вы можете создавать более сложные запросы, такие как == или <. Синтаксис немного необычен для разработчиков Python, поэтому держите документацию под рукой.

Если мы хотим найти строку с номером 3, это можно сделать одним запросом:

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

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

5. Использование attrs и dataclasses для уменьшение кода

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

Что такое Boilerplate?

Если взять в качестве примера нашу сеть поездов, если бы мы преобразовали ее в типы, используя классы Python и подсказки типов Python 3, это могло бы выглядеть примерно так:

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

dataclasses

Введенный в стандартную библиотеку в Python 3.7, с пакетом backport для Python 3.6, модуль dataclasses может помочь удалить множество шаблонов для типов классов, где вы просто храните данные.

Чтобы преобразовать приведенный выше класс Line в dataclass, преобразуйте все поля в атрибуты класса и убедитесь, что они имеют аннотации типов:

Затем вы можете создать экземпляр типа Line с теми же аргументами, что и раньше, с теми же полями и даже с реализованными .__str__(), .__repr__() и .__eq__():

attrs

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

attrs может быть полезным пакетом для удаления стандартного (boilerplate) кода и проверки правильности ввода для классов данных.

Заключение

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

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

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

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