Руководства по кодированию: как разделить большие исходные файлы?

Проект, над которым я работаю, только что набрал 4200 строк в основном файле C #, что заставляет IntelliSense реагировать на несколько секунд (иногда до 6 или около того), в течение которых Visual Studio блокируется. Мне интересно, как все остальные разделяют свои файлы и есть ли консенсус.

Я попытался найти руководства и нашел руководство Google по C ++, но Я ничего не видел в семантике, такой как размеры функций и файлы; может, он там - какое-то время не смотрел.

Так как же разделить файлы? Вы группируете свои методы по функциям, которые они обслуживают? По типам (обработчики событий, частные / публичные)? И в каком пределе размера вы разделяете функции?

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


person Nick Devereaux    schedule 03.03.2009    source источник
comment
Возможно, в качестве дополнительного вопроса вам следует опубликовать описание вашего проекта, что делает ваш основной файл C #, и, возможно, вы получите предложения о том, как люди будут его проектировать и какие методы они могут использовать. Это может быть для вас более поучительным, чем общие наставления «не делайте этого».   -  person Tim    schedule 04.03.2009
comment
Под продолжением вы подразумеваете как новый вопрос или редактировать мой текст здесь?   -  person Nick Devereaux    schedule 04.03.2009
comment
Просто добавьте Edit: внизу этого вопроса и добавьте к нему.   -  person Owen    schedule 04.03.2009


Ответы (14)


Я думаю, ваша проблема резюмируется с помощью термина, который вы используете: «Главный файл C #».

Если вы не имеете в виду main (как в методе main ()), для этой концепции нет места.

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

Обычно мои файлы представляют собой однозначное сопоставление классов.

Иногда классы, которые очень связаны, находятся в одном файле.

Если ваш файл слишком велик, это означает, что ваш класс слишком большой и слишком общий.

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

Иногда это экран, но он становится очень большим.

РЕДАКТИРОВАТЬ:

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

person Tim    schedule 03.03.2009
comment
Комментарий к основному файлу C # тоже меня достал. Выполняет ли он ровно 1 маленькую работу / управляет 1 концепцией? Если нет, найдите деталь, которая выполняет ровно одну небольшую работу, реорганизуйте ее в собственный класс, промойте, ополосните и повторите. - person Bill K; 04.03.2009

В классической книге "Структурированное программирование" однажды написал Дейкстра раздел, озаглавленный: «О нашей неспособности сделать многое». Его точка зрения была простой. Люди не очень умны. Мы не можем одновременно манипулировать несколькими концепциями в уме.

Очень важно, чтобы ваши классы и методы были небольшими. Когда метод превышает дюжину строк или около того, его следует разбить на части. Когда класс превышает пару сотен строк, его следует разбить на части. Это единственный способ сохранить код хорошо организованным и управляемым. Я программировал почти 40 лет, и с каждым годом я понимаю, насколько важно слово «маленький» при написании программного обеспечения.

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

person Uncle Bob    schedule 07.03.2009

Разделяйте типы там, где их естественно, но остерегайтесь типов, которые делают слишком много. Меня беспокоит около 500 строк (Java или C #). Примерно на 1000 строках я начинаю внимательно думать, следует ли разделять тип ... но иногда это просто невозможно / не должно быть.

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

Иногда для одного типа имеет смысл иметь множество методов, например _ 1_, но частичные классы могут помочь в таких случаях, если вы можете разбить тип на логические группы (в случае Enumerable группировка по агрегации / заданию операций / фильтрации и т. д. кажутся естественными). Однако, по моему опыту, такие случаи редки.

person Jon Skeet    schedule 03.03.2009

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

ИЗМЕНИТЬ

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

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

person Michael Meadows    schedule 03.03.2009

Не программируйте процедурно, и вы не получите 4200 строк в одном файле.

В C # рекомендуется придерживаться некоторых SOLID объектно-ориентированных принципы дизайна. У каждого класса должна быть одна и только одна причина для изменения. Основной метод должен просто запускать начальную точку для приложения (и настраивать контейнер внедрения зависимостей, если вы используете что-то вроде StructureMap).

Обычно у меня нет файлов с более чем 200 строками кода, и я предпочитаю их, если они меньше 100.

person Chris Holmes    schedule 03.03.2009
comment
Ух, 4200 кажется очень раздутым, о чем я догадывался, но это меня просто смущает. Если это поможет, то это было ошибкой, вот так, когда я сюда попал :) - person Nick Devereaux; 04.03.2009
comment
Примечание: это не считается объектно-ориентированным программированием, если у вас есть только один большой объект! - person Richard Ev; 04.03.2009
comment
cries на работе, у нас есть приложение с не менее чем 20+ объектами в бизнес-библиотеке, которые содержат более 10-30 тысяч строк в .cpp ... и все они находятся как минимум в 6 файлах .. ; _; - person uzbones; 04.03.2009
comment
@Richard E: В нем намного больше объектов, но этот со временем только раздувается (см. Мою правку). - person Nick Devereaux; 04.03.2009

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

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

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

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

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

person RossFabricant    schedule 03.03.2009


Каждый класс должен делать одно маленькое дело и делать это хорошо. Ваш класс - это форма? Тогда в нем не должно быть НИКАКОЙ бизнес-логики.

Представляет ли он единое понятие, например пользователя или состояние? Тогда в нем не должно быть рисования, загрузки / сохранения и т. Д.

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

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

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

Дайте мне найти хороший пост ... Просмотрите их, чтобы начать:

как-я-сломаю-мои-процедурные-привычки-кодирования < / а>

are-there-any-rules-for-oop

объектно-ориентированные-лучшие-практики-наследование-v-композиция- v-интерфейсы

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

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

Удачи.

person Bill K    schedule 03.03.2009

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

  • Все ли методы используются только в этом классе? Ищите методы поддержки, такие как проверка, манипуляции со строками, которые можно переместить в вспомогательные / служебные классы.

  • Вы используете какие-либо разделы #region? Логические группы связанных методов в #region часто поддаются разделению на отдельные классы.

  • Класс - это форма? Рассмотрите возможность использования пользовательских элементов управления для элементов управления формами или групп элементов управления формами.

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

person Leah    schedule 04.03.2009

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

Есть очень веские причины для разделения файлов классов на файлы меньшего размера (и не менее веские причины для перемещения файлов в разные проекты / сборки).

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

Кроме того, как уже упоминалось, термин, который вы используете: «Главный файл C #», просто пахнет тем, что у вас очень процедурное мышление. Я бы посоветовал остановиться, сделать шаг назад и быстро прочитать некоторые из следующих тем:

  • Общие принципы ООП
  • Домен-ориентированный дизайн
  • Модульное тестирование
  • Контейнеры IoC

Удачи в поисках.

person Owen    schedule 03.03.2009

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

person NotMe    schedule 03.03.2009
comment
Это похоже на лечение симптомов, а не возможных проблем дизайна. - person Jon Skeet; 04.03.2009
comment
Я не думал, что он заслуживает голоса против. Это делает файлы меньше ... - person Tim; 04.03.2009
comment
Нет, он не заслужил голоса против, хотя ответ был таким же невежественным, как и вопрос. - person Owen; 04.03.2009
comment
ОП здесь. Извините за то, что невежественен, но именно поэтому я пришел сюда :) Я сделал один файл класса как частичный, но почему это неправильный путь? Должен ли я быть подклассом? - person Nick Devereaux; 04.03.2009
comment
@alphabeat: Нет, вам, вероятно, не следует создавать подклассы - вы должны разделить функциональность на более мелкие типы. - person Jon Skeet; 04.03.2009
comment
Я бы предположил, что разделение большого класса на частичные классы примерно так же уместно, как использование #Regions для разделения большой функции: сокрытие проблемы, а не ее исправление. - person Richard Ev; 04.03.2009
comment
@alphabeat извините за глупое замечание, я не имел в виду обиду. Трудно сказать, что вы должны делать, не видя своего кода. Вы должны создавать подклассы, когда это логично, то есть несколько суперклассов, которые, казалось бы, должны быть производными от общего базового класса. - person Owen; 04.03.2009
comment
@ Оуэн Не беспокойся! Я хотел бы поделиться своим кодом, но мой босс убил бы меня дважды :) Спасибо за ваше предложение. - person Nick Devereaux; 04.03.2009
comment
Вы когда-нибудь пробовали ctrl + , использовать код с частичными данными? Я всегда оказываюсь не на том партиале. Прямо сейчас в процессе рефакторинга, чтобы избавиться от наших частичных файлов. Не используйте их. - person Dagrooms; 25.01.2017

Возможно, ОП может ответить: ваш проект использует объектно-ориентированное программирование? Тот факт, что вы используете слово «файл», предполагает, что это не так.

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

person John Saunders    schedule 04.03.2009

Синтаксический анализатор Intellisense в Visual Studio 2008 кажется значительно быстрее, чем парсер 2005 года (я знаю, что они специально проделали большую работу в этой области), поэтому, хотя вам обязательно стоит подумать о разделении файла в какой-то момент, как упоминали другие, Visual Studio 2008 может решить вашу немедленную проблему с производительностью. Я использовал его, чтобы без особых проблем открыть файл Linq to SQL размером более 100 тыс. Строк.

person tbreffni    schedule 04.03.2009
comment
Должен был прояснить, извините, но я использую VS2008. Проблема в том, что это такой большой проект, а код для основной формы такой гигантский. Думаю, это стало чем-то вроде свалки. - person Nick Devereaux; 04.03.2009

Разделите код так, чтобы каждый класс / файл / функция / и т. Д. делает только One Thing ™. Принцип единой ответственности - хорошее руководство для разделения функций на классы.

В настоящее время самые большие классы, которые я пишу, имеют длину около 200 строк, а методы в основном состоят из 1-10 строк.

person Esko Luontola    schedule 07.03.2009

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

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

Некоторые классы просто должны быть большими. Неплохой дизайн; они просто тяжелы для реализации.

person Jeremy Edwards    schedule 03.03.2009