Что делать с исходным файлом на С++ 11000 строк?

Итак, у нас есть этот огромный (11000 строк огромный?) исходный файл mainmodule.cpp в нашем проекте, и каждый раз, когда я должен прикасаться к нему, я съеживаюсь.

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

Файл используется и активно изменяется в нескольких ( > 10) версиях обслуживания нашего продукта, поэтому его рефакторинг действительно сложно. Если бы я просто "разложил" его, скажем, для начала, в 3 файла, то слияние обратно изменений с версий обслуживания станет кошмаром. А также, если вы разделите файл с такой длинной и богатой историей, отслеживание и проверка старых изменений в истории SCC внезапно становится намного сложнее.

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

Что бы вы сделали в этой ситуации? Любые идеи о том, как перенести новые функции в отдельный исходный файл, не нарушая рабочий процесс SCC?

(Примечание по инструментам: мы используем С++ с Visual Studio; мы используем AccuRev как SCC, но я думаю, что тип SCC здесь не имеет особого значения: мы используем Araxis Merge для выполнения фактических сравнение и слияние файлов)

Ответ 1

  • Найдите некоторый код в файле, который относительно стабилен (не меняется быстро и не сильно отличается между ветвями) и может стоять как независимый блок. Переместите это в свой собственный файл и, если на то пошло, в свой класс, во всех ветвях. Поскольку он стабилен, это не приведет к (многим) "неудобным" слияниям, которые должны применяться к другому файлу из того, из которого они были сделаны первоначально, когда вы объединяете это изменение из одной ветки в другую. Повторить.

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

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

Это оставляет вам ядро ​​плохо управляемого кода - он нужен везде, но он различен в каждой ветке (и/или постоянно меняется, так что некоторые ветки работают за другими), и все же он в одном файле, который вы безуспешно пытаетесь слиться между ветвями. Перестань. Разделите файл навсегда, возможно, переименовав его в каждую ветку. Это уже не "главное", это "главное для конфигурации X". Хорошо, поэтому вы теряете возможность применить одно и то же изменение к нескольким ветвям путем слияния, но это в любом случае ядро ​​кода, в котором слияние не работает очень хорошо. Если вам все равно придется вручную управлять слияниями, чтобы справиться с конфликтами, то нет никакой потери, чтобы вручную применять их независимо друг от друга в каждой ветке.

Я думаю, вы ошибаетесь, говоря, что тип SCC не имеет значения, потому что, например, возможности слияния git, вероятно, лучше, чем инструмент слияния, который вы используете. Поэтому основная проблема "слияние трудно" происходит в разное время для разных ГТК. Однако вы вряд ли сможете изменить SCC, поэтому проблема, вероятно, не имеет значения.

Ответ 2

Слияние не будет таким большим кошмаром, как это будет, когда вы получите 30000 LOC файлов в будущем. Итак:

  • Остановить добавление большего количества кода в этот файл.
  • Разделить его.

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

Ответ 3

Мне кажется, что вы столкнулись с рядом кодовых запахов. Прежде всего, основной класс нарушает принцип open/closed. Это также звучит так, как будто обработка слишком много обязанностей. Из-за этого я предполагаю, что код будет более хрупким, чем нужно.

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

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

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

В любом случае это звучит как крупный проект, так что удачи:)

Ответ 4

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

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

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

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

Я знаю, что это не идеально, хотя я надеюсь, что это может помочь, и этот процесс должен быть адаптирован к вашим потребностям!

Дополнительная информация

Обратите внимание, что Git - это SCC, который может следовать фрагментам кода из одного файла в другой. Я слышал хорошие вещи об этом, поэтому он может помочь, пока вы постепенно двигаете свою работу.

Git строится вокруг понятия blobs, которые, если я правильно понимаю, представляют фрагменты файлов кода. Переместите эти фрагменты в разных файлах, и Git найдет их, даже если вы их измените. Помимо видео от Linus Torvalds, упомянутого в комментариях ниже, я не смог найти что-то ясно об этом.

Ответ 5

Конфуций говорит: "Первый шаг к выходу из ямы - это прекратить копать дыру".

Ответ 6

Позвольте мне угадать: Десять клиентов с расходящимися наборами функций и менеджером по продажам, который продвигает "настройку"? Раньше я работал над такими продуктами. У нас была по существу та же проблема.

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

Прежде чем пытаться разбить файл на части, вам нужно привести десять ветвей в синхронизацию друг с другом, чтобы вы могли сразу увидеть и сформировать весь код. Вы можете делать это по одной ветки за раз, проверяя обе ветки по одному и тому же основному кодовому файлу. Чтобы обеспечить соблюдение пользовательского поведения, вы можете использовать #ifdef и друзей, но лучше как можно больше использовать обычные if/else для определенных констант. Таким образом, ваш компилятор проверит все типы и, скорее всего, устранит "мертвый" код объекта в любом случае. (Однако вы можете отключить предупреждение о мертвом коде.)

Когда только одна версия этого файла разделяется неявно всеми ветвями, то легче начать традиционные методы рефакторинга.

#ifdefs в основном лучше для разделов, где затронутый код имеет смысл только в контексте других настроек каждой ветки. Можно утверждать, что они также предоставляют возможность для одной и той же схемы слияния ветвей, но не идут на свирепость. Один колоссальный проект за раз, пожалуйста.

В краткосрочной перспективе файл будет расти. Хорошо. То, что вы делаете, сводится к тому, что нужно вместе. Впоследствии вы начнете видеть области, которые явно одинаковы независимо от версии; они могут быть оставлены в покое или реорганизованы по желанию. Другие области будут явно отличаться в зависимости от версии. В этом случае у вас есть несколько вариантов. Один из методов заключается в деле делегировании различий между объектами стратегии для каждой версии. Другим является получение клиентских версий из общего абстрактного класса. Но ни одно из этих преобразований не возможно, если у вас есть десять "подсказок" развития в разных отраслях.

Ответ 7

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

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

Я думаю, у вас есть только следующие варианты:

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

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

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

Ответ 9

Я думаю, вам лучше всего создать набор классов command, которые сопоставляются с точками API mainmodule.cpp.

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

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

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

Update

Я бы предположил, что шаблон Command предпочтительнее для Facade.

Предпочтительно поддерживать/организовывать множество разных классов команд над (относительно) монолитным фасадом. Отображение одного фасада в файл 11 KLOC, вероятно, необходимо разбить на несколько разных групп.

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

Конечно, оба варианта лучше, чем один 11 KLOC и растущий файл.

Ответ 10

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

Один из способов может состоять в том, чтобы начать разделение наименее большой функции/части на свой собственный файл, а затем либо включить заголовок (таким образом, превратив main.cpp в список #includes, который сам по себе вызывает запах кода * я 'm не С++ Guru, хотя), но по крайней мере теперь он разбивается на файлы).

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

Другое: насколько вы можете пожелать сделать один большой проход при реорганизации всего за один раз, вы можете откусить больше, чем можете пережевывать. Возможно, просто выберите одну или две "части", запустите их во все выпуски, затем добавьте еще немного для своего клиента (в конце концов, Refactoring не добавляет прямое значение, так что это стоимость, которая должна быть оправдана), а затем выберите другую одна или две части.

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

Ответ 11

Rofl, это напоминает мне мою старую работу. Кажется, что, прежде чем я присоединился, все было в одном огромном файле (также С++). Затем они разделили его (в полностью случайных точках с использованием включений) примерно на три (все еще огромные файлы). Качество этого программного обеспечения было, как и следовало ожидать, ужасным. Проект составил около 40 тыс. LOC. (содержащий почти никаких комментариев, кроме LOTS дублированного кода)

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

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


изменить:

Размер оставался на уровне около 40 тыс. LOC, но новое приложение содержало гораздо больше функций и, предположительно, меньше ошибок в начальной версии, чем 8-летнее программное обеспечение. Одной из причин переписывания было то, что нам нужны были новые функции, а введение их в старый код было практически невозможно.

Программное обеспечение предназначено для встроенной системы - принтера для этикеток.

Еще один момент, который я должен добавить, это то, что в теории проект был С++. Но это не было OO вообще, это могло быть C. Новая версия была объектно-ориентированной.

Ответ 12

Хорошо, я понимаю вашу боль:) Я был в нескольких таких проектах, и это не очень. Для этого нет простого ответа.

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

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

Ответ 13

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

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

Два, вам нужно взять эту производственную версию и создать ветку, которая управляет сборками, используя директивы предварительной обработки, чтобы разделить большой файл. Разделение компиляции с использованием директив JUST preprocessor (#ifdefs, #includes, #endifs) проще, чем перекодировка API. Это определенно проще для ваших SLA и постоянной поддержки.

Здесь вы можете просто вырезать функции, относящиеся к определенной подсистеме внутри класса, и поместить их в файл, например mainloop_foostuff.cpp, и включить его в mainloop.cpp в нужном месте.

ИЛИ

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

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

Основная структура заключается в том, что ваш mainclass.cpp будет включать в себя новый файл MainClassComponents.cpp после блока выражений вроде следующего:

#if VARIANT == 1
#  define Uses_Component_1
#  define Uses_Component_2
#elif VARIANT == 2
#  define Uses_Component_1
#  define Uses_Component_3
#  define Uses_Component_6
...

#endif

#include "MainClassComponents.cpp"

Первичная структура файла MainClassComponents.cpp была бы там для разработки зависимостей внутри субкомпонентов, таких как:

#ifndef _MainClassComponents_cpp
#define _MainClassComponents_cpp

/* dependencies declarations */

#if defined(Activate_Component_1) 
#define _REQUIRES_COMPONENT_1
#define _REQUIRES_COMPONENT_3 /* you also need component 3 for component 1 */
#endif

#if defined(Activate_Component_2)
#define _REQUIRES_COMPONENT_2
#define _REQUIRES_COMPONENT_15 /* you also need component 15 for this component  */
#endif

/* later on in the header */

#ifdef _REQUIRES_COMPONENT_1
#include "component_1.cpp"
#endif

#ifdef _REQUIRES_COMPONENT_2
#include "component_2.cpp"
#endif

#ifdef _REQUIRES_COMPONENT_3
#include "component_3.cpp"
#endif


#endif /* _MainClassComponents_h  */

И теперь для каждого компонента вы создаете файл component_xx.cpp.

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

Использование препроцессора позволяет разбить вещи, не беспокоясь об изменениях API, которые являются кошмаром в производстве.

Как только вы закончите производство, вы сможете фактически работать над редизайном.

Ответ 14

Вы не должны беспокоиться о сокращении размера файла, а скорее о снижении размера класса. Это почти то же самое, но заставляет вас смотреть на проблему под другим углом (как предлагает @Brian Rasmussen , ваш класс, похоже, несет много обязанностей).

Ответ 15

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

Ответ 16

Это не ответ на большую проблему, а теоретическое решение для конкретной части:

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

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

  • Запустите script. Удалите исходный файл.

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

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

Ответ 17

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

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

Ответ 18

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

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

Ответ 19

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

  • Введите код для исчерпывающего тестирования функции в рассматриваемой программе. Похоже, у вас еще не будет этого в руке...
  • Определите код, который можно абстрагировать в класс helper/utilities. Не обязательно быть большим, просто что-то, что не является частью вашего "основного" класса.
  • Рефакторинг кода, указанного в 2. в отдельный класс.
  • Повторите тесты, чтобы убедиться, что ничего не сломалось.
  • Когда у вас есть время, перейдите 2. и повторите, как требуется, чтобы сделать код управляемым.

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

Я мог бы также добавить:

0: купить

Ответ 20

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

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

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

Ответ 21

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

  • удалить определенные строки до/во время конкатенации (например, включить охранники)
  • удалять другие данные с выхода diff при необходимости

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

Ответ 22

Мои 0,05 евроценты:

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

При разбиении на подсистемы проанализируйте места, которые больше всего изменились, и отделите их от неизменных частей. Это должно показать вам проблемы. Отделите большинство изменяющихся частей к их собственным модулям (например, dll) таким образом, чтобы API-интерфейс модуля мог быть сохранен в целостности, и вам не нужно постоянно прерывать BC. Таким образом, вы можете развернуть разные версии модуля для разных ветвей обслуживания, если это необходимо, при неизменном ядре.

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

Что касается истории исходного кода, мое мнение: забудьте о новом коде. Но сохраните историю где-нибудь, чтобы вы могли ее проверить, если это необходимо. Бьюсь об заклад, вам это не понадобится после начала.

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

Вот как я, по крайней мере, начну решать проблему.

Ответ 23

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

Ответ 24

Другая книга, которую вы можете найти интересной/полезной, Рефакторинг.

Ответ 25

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

Ответ 26

Я нашел это предложение наиболее интересной частью вашего сообщения:

> Файл используется и активно изменяется в нескольких ( > 10) версиях обслуживания нашего продукта, поэтому его действительно сложно реорганизовать.

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

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

Я чувствую, что ты уже съежился! Но либо ваш источник управления не работает для вашей ситуации из-за отсутствия функций, либо не используется правильно.

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

Я был бы немного обеспокоен тем, что у вас так много функций в main().

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

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

Наконец, в основном я также добавляю код обнаружения утечки в блоки препроцессора, которые обеспечивают его включение только в сборках DEBUG. Это все, что я хотел бы добавить к main(). Main() должен быть коротким!

Вы говорите, что

> Файл в основном содержит "основной класс" (основная внутренняя диспетчеризация и координация работы) нашей программы

Похоже, эти две задачи можно разделить на два отдельных объекта - координатор и рабочий диспетчер.

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

Если вы не в состоянии принять решение, сразитесь с ним и приложите к нему своего менеджера - ваше приложение нужно реорганизовать - и плохо по звукам! Не отвечайте за ответ!

Ответ 27

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

Ответ 28

"Файл в основном содержит" основной класс "(основная внутренняя диспетчеризация и координация) нашей программы, поэтому каждый раз, когда добавляется функция, она также влияет на этот файл и каждый раз, когда он растет".

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

    // declaration
    std::map<ID, ICommand*> dispatchTable;
    ...

    // populating using some loader
    dispatchTable[id] = concreteCommand;

    ...
    // using
    dispatchTable[id]->Execute();

Ответ 29

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

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

Ответ 30

Я думаю, что я бы сделал в этой ситуации бит бит и:

  • Выясните, как я хотел разбить файл (на основе текущей версии разработки).
  • Поместите административную блокировку в файл ( "Никто не коснется mainmodule.cpp после 17:00 пятницы!!!"
  • Проведите длинные выходные, применив это изменение к версиям обслуживания > 10 (от самых старых до новейших), вплоть до текущей версии.
  • Удалить mainmodule.cpp из всех поддерживаемых версий программного обеспечения. Это новый век - больше нет mainmodule.cpp.
  • Убедите Менеджмент, что вы не должны поддерживать более одной версии обслуживания программного обеспечения (по крайней мере, без большого контракта на поддержку $$$). Если каждый из ваших клиентов имеет свою собственную уникальную версию... yeeeeeshhhh. Я бы добавил директивы компилятора вместо того, чтобы пытаться поддерживать 10 + вилки.

Отслеживание старых изменений файла просто решается вашим первым комментарием, в котором говорится что-то вроде "split from mainmodule.cpp". Если вам нужно вернуться к чему-то недавнему, большинство людей запомнит это изменение, если через 2 года комментарий скажет им, где искать. Конечно, насколько ценно будет вернуться более двух лет, чтобы посмотреть, кто изменил код и почему?