Как избежать гигантских клеевых методов?

21

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

В конечном итоге я получаю чистый API и никакой реальный способ связать все это вместе. Решение состояло в том, чтобы написать большой уродливый метод «склеивания» (обычно полный условных операторов), который в конечном итоге вызывает все мои «чистые» методы.

Склеивающий метод обычно оказывается краткой версией кода / данных, которые я пытался очистить. Обычно это более читабельно, но все равно раздражает.

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

cmhobbs
источник
3
API предназначены для использования. Из запутанного беспорядка, который вы получили, вы создали API, а затем перепутали его. Может быть, это просто деловое требование. Но вы добавили ценность, потому что кто-то другой может прийти и легко сделать другую функцию склеивания, используя ваш API. Не нужно скручивать руки ...
депутат Адитья
1
Мы вообще говорим об объектах или просто повсюду?
Эрик Реппен
3
Я не думаю, что это дубликат этого вопроса, я говорю немного более широко (и в большем масштабе, чем одна функция).
cmhobbs
1
Эрик - я говорю об объектах и ​​методах здесь. Я взял пару условных беспорядков и превратил их в API. Проблема возникает, когда пришло время вызвать API. Первый ответ здесь может быть именно тем, что я ищу, хотя.
cmhobbs
2
Как же это дубликат?
MattDavey

Ответы:

12

Я дам вам наш опыт рефакторинга LedgerSMB. Мы решили сделать что-то по-другому на ранней стадии и до сих пор делаем именно то, что вы описываете, но без большого количества методов склеивания (кстати, у нас есть несколько методов склеивания, но не очень много).

Жизнь с двумя кодовыми базами

LedgerSMB выжил с двумя кодовыми базами около 5 лет, и пройдет еще несколько, прежде чем старая кодовая база будет устранена. Старая кодовая база - настоящий ужас для созерцания. Плохой дизайн базы данных, Perl создает аналогично IS->some_func(\%$some_object);коду, который показывает, почему именно иногда используется метафора спагетти (пути выполнения блуждают между модулями и обратно, и между языками, без рифмы и причины). Новая кодовая база избегает этого, перемещая запросы базы данных в хранимые процедуры, имея более чистую структуру для обработки запросов и многое другое.

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

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

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

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

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

Крис Траверс
источник
Я думаю, что вы, возможно, ударили гвоздь по голове. Причина, по которой клей существует, может быть связана с кодом, который вызывает интерфейс, который я создал. Я собираюсь подождать еще несколько ответов, чтобы увидеть, если мы что-то упустили, но я считаю, что этот достаточно хорошо резюмирует.
cmhobbs
1
«пути выполнения извилистые между модулями и обратно, и между языками, без рифмы и причины» - это также напоминает мне некоторые современные методы ОО.
user253751
8

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

В конечном итоге я получаю чистый API и никакой реальный способ связать все это вместе. Решение состояло в том, чтобы написать большой уродливый метод «склеивания» (обычно полный условных операторов), который в конечном итоге вызывает все мои «чистые» методы.

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

MattDavey
источник
6

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

частокол
источник
2
Разве вы не получили дерево клея тогда?
Питер Б
3
@PieterB может быть, но легче извлечь разные зависимости, когда у вас разные задачи разными методами. Вы можете сделать еще один проход рефакторинга после извлечения новых методов.
Paling
1

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

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

Карл Билефельдт
источник
0

Похоже, вы реорганизуете API, просто думая о реализации API, но не задумываясь о коде, который использует API - то есть о «связующем коде», о котором вы говорите.

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

Ханс-Петер Стёрр
источник