DevCrm 08 — Когда MainViewModel стал 1300+ строк

Когда MainViewModel стал 1300+ строк
Когда MainViewModel стал 1300+ строк

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

У меня этот момент случился с MainViewModel.cs. Открываешь его, а там всё намешано. Авторизация, клиенты, пользователи, задачи, чат, экспорт. Команды, свойства, фильтры, видимость элементов. Всё в одной куче, и понять, где что начинается и где заканчивается, можно только если ты сам это писал неделю назад. А если вернуться через месяц?

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

public ICommand AddCommand { get; private set; } = null!; public ICommand SaveCommand { get; private set; } = null!; public ICommand DeleteCommand { get; private set; } = null!; public ICommand ClearCommand { get; private set; } = null!; public ICommand RefreshCommand { get; private set; } = null!; public ICommand ExportExcelCommand { get; private set; } = null!; public ICommand ExportPdfCommand { get; private set; } = null!; public ICommand LoginCommand { get; private set; } = null!;

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

Надо было что-то делать. И тут пригодился partial.

Partial-класс позволяет разбить один класс на несколько файлов. Для компилятора это всё тот же MainViewModel, ничего не меняется. А для разработчика появляются аккуратные разделы, каждый со своим назначением.

Объявление класса остаётся одно:

public partial class MainViewModel : INotifyPropertyChanged { ... }

А дальше в каждом файле своя часть.

public partial class MainViewModel { public bool IsManager => _userService.IsManager(); ... }

Я разбил MainViewModel на несколько файлов:

  • MainViewModel.cs — ядро, конструктор, общие свойства, команды.
  • MainViewModel.Auth.cs — вход и выход, IsAuthenticated, смена пароля.
  • MainViewModel.Clients.cs — загрузка, сохранение, удаление, корзина.
  • MainViewModel.Users.cs — управление пользователями и ролями.
  • MainViewModel.Tasks.cs — задачи.
  • MainViewModel.Chat.cs — чат.
  • MainViewModel.Export.cs — экспорт в Excel, Word, PDF.
  • MainViewModel.Commands.cs — команды.
  • MainViewModel.Visibility.cs — видимость вкладок и панелей.

После этого работать стало проще. Если нужно разобраться с чатом, я открываю Chat.cs. Если проблема с экспортом, открываю Export.cs. Не нужно листать полторы тысячи строк в поисках одного метода.

Но важно понимать: partial это не панацея, а скорее промежуточное решение. Файлы стали меньше, но класс как был большим, так и остался. Разбиение по файлам не заменяет настоящей декомпозиции, когда логика выносится в отдельные сервисы и вьюмодели. Эту работу я делал уже потом, постепенно. И она оказалась куда важнее, чем просто раскладывание по коробочкам.

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

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