Почему Гений 1С берет дороже, чем рядовой?

Недавно столкнулся с ужасно написанным кодом, который в итоге привел у клиента к ошибкам. Сама потребность поменять код возникла в обработке загрузке таможенной декларации из ГТД, о которой я писал в прошлой статье.

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

Скажу пару слов о логике работы кода — там по номеру ГТД, прочитанному из файла создавался элемент справочника «Номера ТД» с кодом, соответствующему прочитанному ГТД, но с добавленным спереди пробел. Также создавалась группа с таким же кодом, но без пробела, и элемент справочника помещался в эту группу. Зачем создавать группы, не понятно. Логичнее было, наоборот, давать пробел в названии группы, потому что элемент используется в документах и логично именно ему давать соответствие ГТД.

Но сам по себе код ужасен, хотя и небольшой. Оцените:

// Создает элемент справочника "Номера ГТД"
//
Процедура СоздатьНомерГТД()
	Если ТипЗнч(НомерГТД) = Тип("Строка") Тогда
		// Создаем группу
		ссГруппаНомерГТД = Справочники.НомераГТД.НайтиПоКоду(НомерГТД);
		Если ЗначениеЗаполнено(ссГруппаНомерГТД) И Не ссГруппаНомерГТД.ЭтоГруппа Тогда
			// Нашли без пробела, но это не группа:
			// Добавляем пробел в код элемента
			обНомерГТД = ссГруппаНомерГТД.ПолучитьОбъект();
			обНомерГТД.Код = " " + НомерГТД;
			обНомерГТД.Записать();
			
			// И создаем группу без пробела в коде
			обГруппаНомерГТД = Справочники.НомераГТД.СоздатьГруппу();
			обГруппаНомерГТД.Код = НомерГТД;
			обГруппаНомерГТД.Записать();
			
			// Используем созданную группу в элементе
			обНомерГТД.Родитель = обГруппаНомерГТД.Ссылка;
			обНомерГТД.Записать();
			Возврат;
		КонецЕсли; 
		
		Если Не ЗначениеЗаполнено(ссГруппаНомерГТД) Тогда
			обГруппаНомерГТД = Справочники.НомераГТД.СоздатьГруппу();
			обГруппаНомерГТД.Код = НомерГТД;
			обГруппаНомерГТД.Записать();
			ссГруппаНомерГТД = обГруппаНомерГТД.Ссылка;
		КонецЕсли;
		
		обНомерГТД = Справочники.НомераГТД.СоздатьЭлемент();
		обНомерГТД.Код = " " + НомерГТД;
		обНомерГТД.Родитель = ссГруппаНомерГТД;
		обНомерГТД.Записать();
		НомерГТД = обНомерГТД.Ссылка;
	КонецЕсли; 
КонецПроцедуры

Группа создается два раза. Элемент не ищется, а сразу создается. Хотя справедливости ради, надо заметить, что при загрузке ГТД делается поиск по номеру ГТД в отдельной функции, так что если код есть, создаваться не будет:

	// Добавим пробел в номер ГТД при поиске номера ГТД				  
	ссНомерГТД = Справочники.НомераГТД.НайтиПоКоду(" " + НомерГТД);
	Если ЗначениеЗаполнено(ссНомерГТД) Тогда
		НомерГТД = ссНомерГТД;
	КонецЕсли;

Но это всё в разных местах, ужасно не прозрачно.

Я внес изменения в логику, пробел использую в группах, а элементы пишу без пробела. Это позволяет обходить обрезание пробела при записи элемента ГТД. В итоге я переписал функцию следующим образом:

&НаСервере
// Создает элемент справочника "Номера ГТД"
//
Процедура СоздатьНомерГТД()
	Если ТипЗнч(НомерГТД) = Тип("Строка") Тогда
		// Создаем группу
		ссГруппаНомерГТД = ДатьНомерГТД(НомерГТД, истина); //Группа
		ссНомерГТД = ДатьНомерГТД(НомерГТД, ложь); //Элемент
		НомерГТД = ссНомерГТД.Ссылка;
	КонецЕсли; 
КонецПроцедуры


&НаСервере
Функция ДатьНомерГТД(НомерГТД, ЭтоГруппа) Экспорт
	//Осипов 2021-07-13 доработал
	НомерГТДСПробелом = " " + СокрЛП(НомерГТД);;
	НомерГТДБезПробела = СокрЛП(НомерГТД);;
	Если ЭтоГруппа Тогда
		ИскНомерГТД = НомерГТДСПробелом; 
		КонтрИскНомерГТД = НомерГТДБезПробела; 
	Иначе
		ИскНомерГТД = НомерГТДБезПробела;
		КонтрИскНомерГТД = НомерГТДСПробелом; 
	КонецЕсли;
	
	ИскСсылка = ДатьНомерГТДСлуж(ИскНомерГТД, ЭтоГруппа);
	Если ЗначениеЗаполнено(ИскСсылка) Тогда
		Возврат ИскСсылка;
	КонецЕсли;
	
	//Поищем без пробела или с пробелом - по другому
	ИскСсылка = ДатьНомерГТДСлуж(КонтрИскНомерГТД, ЭтоГруппа);
	Если ЗначениеЗаполнено(ИскСсылка) Тогда
		О = ИскСсылка.ПолучитьОбъект();
		О.Код = ИскНомерГТД;
		//О.ОбменДанными.Загрузка = истина;
		О.Записать();
		ИскСсылка = О.Ссылка;
		Возврат ИскСсылка;
	КонецЕсли;
	
	//Не нашли, надо создавать
	Если ЭтоГруппа Тогда
		О = Справочники.НомераГТД.СоздатьГруппу();
		О.Код = НомерГТДСПробелом;
	Иначе
		О = Справочники.НомераГТД.СоздатьЭлемент();
		О.Код = НомерГТДБезПробела;
		О.Родитель = ДатьНомерГТД(НомерГТД, истина);
	КонецЕсли;
	//О.ОбменДанными.Загрузка = истина;
	О.Записать();
	ИскСсылка = О.Ссылка;
	Возврат ИскСсылка;
	
КонецФункции

&НаСервере
Функция ДатьНомерГТДСлуж(НомерГТД, ЭтоГруппа) Экспорт
	З = Новый Запрос(
	"ВЫБРАТЬ
	|	НомераГТД.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.НомераГТД КАК НомераГТД
	|ГДЕ
	|	НомераГТД.Код = &Код
	|	И НомераГТД.ЭтоГруппа = &ЭтоГруппа");
	З.УстановитьПараметр("Код", НомерГТД);
	З.УстановитьПараметр("ЭтоГруппа", ЭтоГруппа);
	Выборка = З.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Возврат Выборка.Ссылка;
	КонецЕсли;
КонецФункции


А код по поиску ГТД переписал так:

//Осипов 2021-07-13 ищем по номеру ГТД элемент, не группу
ссНомерГТД = ДатьНомерГТД(НомерГТД, ложь);
Если ЗначениеЗаполнено(ссНомерГТД) Тогда
	НомерГТД = ссНомерГТД;
КонецЕсли;

Рефакторинг, друзья мои! Поэтому Гении 1С стоят дороже, чем подмастерья!

Объем факт: 1 час. Среда: 8.3.17.2300, БП 3.0.96.35.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *