У меня есть проект. В этом проекте я хотел реорганизовать его, чтобы добавить функцию, и я рефакторинг проекта, чтобы добавить функцию.
Проблема в том, что когда я закончил, оказалось, что мне нужно было сделать небольшое изменение интерфейса, чтобы приспособиться к нему. Так что я сделал изменения. И тогда класс потребления не может быть реализован с его текущим интерфейсом в терминах нового, поэтому ему также нужен новый интерфейс. Сейчас три месяца спустя, и мне пришлось исправлять неисчислимые, практически не связанные с этим проблемы, и я смотрю на решение проблем, которые планировались в течение года или просто указаны в списке, которые не будут исправлены из-за трудностей, прежде чем объект будет скомпилирован очередной раз.
Как я могу избежать такого рода каскадных рефакторингов в будущем? Является ли это просто симптомом моих предыдущих занятий, которые слишком сильно зависят друг от друга?
Краткое редактирование: в этом случае рефактором была особенность, так как рефактор увеличил расширяемость определенного фрагмента кода и уменьшил некоторую связь. Это означало, что внешние разработчики могли делать больше, и именно эту функцию я хотел предоставить. Таким образом, сам по себе оригинальный рефакторинг не должен был быть функциональным изменением.
Большие изменения, которые я обещал пять дней назад:
До того, как я начал этот рефакторинг, у меня была система, в которой у меня был интерфейс, но в реализации я просто dynamic_cast
прошел через все возможные реализации, которые я поставил. Это, очевидно, означало, что вы, во-первых, не могли просто наследовать от интерфейса, а во-вторых, что никто не имел бы возможности без доступа к реализации реализовать этот интерфейс. Поэтому я решил, что хочу решить эту проблему и открыть интерфейс для общего пользования, чтобы любой мог его реализовать, и что реализация интерфейса - это весь контракт, который требуется - очевидно, улучшение.
Когда я находил и убивал огнем все места, где я это делал, я обнаружил одно место, которое оказалось особой проблемой. Это зависело от деталей реализации всех различных производных классов и дублированных функций, которые уже были реализованы, но лучше где-то еще. Вместо этого он мог бы быть реализован с точки зрения открытого интерфейса и повторно использовать существующую реализацию этой функциональности. Я обнаружил, что для правильной работы требуется определенный фрагмент контекста. Грубо говоря, вызов предыдущей реализации выглядел примерно так
for(auto&& a : as) {
f(a);
}
Однако, чтобы получить этот контекст, мне нужно было изменить его на что-то вроде
std::vector<Context> contexts;
for(auto&& a : as)
contexts.push_back(g(a));
do_thing_now_we_have_contexts();
for(auto&& con : contexts)
f(con);
Это означает, что для всех операций, которые раньше были частью f
, некоторые из них должны быть включены в новую функцию, g
которая работает без контекста, а некоторые из них должны быть сделаны из части теперь отложенной f
. Но не все методы f
вызывают или нуждаются в этом контексте - некоторые из них нуждаются в отдельном контексте, который они получают отдельными средствами. Таким образом, для всего, что f
заканчивается вызовом (а это, грубо говоря, почти все ), я должен был определить, какой контекст им нужен, если таковой имеется, откуда они должны его получить и как разделить их со старого f
на новое f
и новое. g
,
И вот как я оказался там, где я сейчас. Единственная причина, по которой я продолжал идти, - это необходимость рефакторинга по другим причинам.