Cualquiera que haya trabajado con el código de otra persona en 1C, al menos una vez ha experimentado la misma sensación: abres un módulo y hay un procedimiento de 800 líneas con el nombre «ProcesarDatos». Sin comentarios. Con las variables «a», «b» y «Tiempo». Y entiendes que en seis meses tu propio código puede provocar exactamente las mismas emociones en alguien.
Veamos cómo escribir procedimientos y funciones en 1C para que el código permanezca legible, predecible y fácil de mantener, incluso después de años.
Procedimiento vs. función: ¿cuál es la diferencia fundamental?
A primera vista, todo es simple: la función devuelve un valor, el procedimiento no. Pero detrás de esta simplicidad se esconde un importante principio de diseño.
Función es una pregunta. Le preguntas algo al sistema y obtienes una respuesta. No debe cambiar el estado de la base de datos, no debe mostrar mensajes al usuario. Simplemente cuenta y devuelve el resultado.
Функция РассчитатьСуммуСоСкидкой(Сумма, ПроцентСкидки)
Возврат Сумма - Сумма * ПроцентСкидки / 100;
КонецФункцииProcedimiento — es un comando. Le pides al sistema que haga algo: guardar un documento, enviar una carta, completar una tabla. Realiza una acción y no devuelve el resultado.
Процедура ЗаполнитьЦеныВТабличнойЧасти(ТабличнаяЧасть, ТипЦен)
Для Каждого Строка Из ТабличнаяЧасть Цикл
Строка.Цена = ПолучитьЦенуНоменклатуры(Строка.Номенклатура, ТипЦен);
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
КонецПроцедурыSi te encuentras con que una función escribe datos y devuelve un resultado, es una señal de que vale la pena dividir la lógica en dos partes.
Nombramiento: tu código lo leen personas, no un compilador
El nombre de un procedimiento o función es un contrato con quien leerá el código después de ti. Un buen nombre hace que el comentario sea innecesario.
Nombres malos — son nombres que no dicen nada sobre el propósito:
// ¿Qué procesa? ¿Qué datos? ¿Por qué?
Процедура ОбработатьДанные()
// ¿Qué es lo que comprueba exactamente? ¿Qué documento?
Функция Проверка(Док)
// «Ejecutar» es la palabra más inútil en el títuloроцедура ВыполнитьОперацию()Buenos nombres contienen un verbo y describen una acción específica:
Процедура РассчитатьСебестоимостьПоПартиям(ДокументОбъект)
Функция ПолучитьОстатокНоменклатурыНаСкладе(Номенклатура, Склад, Дата)
Функция ЕстьПравоНаСкидку(Контрагент, СуммаЗаказа)Algunas reglas que realmente funcionan:
Las funciones-pregunta deben comenzar con las palabras «Obtener», «Calcular», «Encontrar», «Hay» (para valores booleanos).
Los procedimientos de comando comienzan con las palabras «Rellenar», «Grabar», «Enviar», «Eliminar», «Establecer».
No tengas miedo de los nombres largos. «RecibirImporteDePagoPorPeriodoPorContraparte» es más claro que «RecibirImporte».
Parámetros: menos es mejor
Si tu procedimiento tiene más de cinco parámetros, algo ha salido mal. No es solo una cuestión de estética: un gran número de parámetros significa que el procedimiento hace demasiado o que los datos están mal estructurados.
Problema:
Процедура СоздатьЗаказ(Контрагент, Склад, Менеджер, ДатаОтгрузки,
ТипЦен, ВалютаДокумента, Организация, Комментарий, Приоритет)
// ...40 líneas de creación de documentos
КонецПроцедурыSolución — estructura:
Функция НовыеПараметрыЗаказа()
Параметры = Новый Структура;
Параметры.Вставить("Counterparty");
Параметры.Вставить("Warehouse");
Параметры.Вставить("Manager");
Параметры.Вставить("Date of shipment", ТекущаяДата());
Параметры.Вставить("PriceType");
Параметры.Вставить("Currency");
Параметры.Вставить("Organization");
Параметры.Вставить("Comment", "");
Параметры.Вставить("Priority", 0);
Возврат Параметры;
КонецФункции
Процедура СоздатьЗаказ(ПараметрыЗаказа)
// Limpio, claro, ampliable
КонецПроцедурыEl patrón «función de constructor de parámetros» es una de las técnicas más útiles en 1C. Permite añadir nuevos parámetros sin romper las llamadas existentes.
Principio de responsabilidad única
Este es quizás el principio más importante que se viola en el código 1C con mayor frecuencia. Un procedimiento debe hacer una cosa.
Antipatrón: «procedimiento combinado»:
Процедура ОбработатьДокумент(ДокументОбъект)
// Comprobación de cumplimentación: 50 líneas
// Cálculo de importes — 30 líneas
// Formación de movimientos — 100 líneas
// Envío de notificación: 20 líneas
// Actualización del estado de la contraparte: 25 líneas
// Registro — 15 líneas
КонецПроцедурыEste procedimiento no se puede probar, es difícil de depurar, y cuando algo se rompe, y se romperá, volverás a leer las 240 líneas.
El enfoque correcto:
Процедура ОбработатьДокумент(ДокументОбъект)
ОшибкиЗаполнения = ПроверитьЗаполнениеДокумента(ДокументОбъект);
Если ОшибкиЗаполнения.Количество() > 0 Тогда
ВывестиОшибкиЗаполнения(ОшибкиЗаполнения);
Возврат;
КонецЕсли;
РассчитатьСуммыДокумента(ДокументОбъект);
СформироватьДвижения(ДокументОбъект);
ОтправитьУведомление(ДокументОбъект);
ОбновитьСтатусКонтрагента(ДокументОбъект.Контрагент);
КонецПроцедурыAhora cada operación está aislada. Si necesita cambiar la lógica de cálculo de las cantidades, sabe exactamente dónde buscar. Si el envío de notificaciones se ha interrumpido, no es necesario volver a leer el código de cálculo.
Gestión de errores: no ocultes los problemas
Uno de los errores más comunes es la aceptación tácita de excepciones.
Cómo no se debe hacer:
Процедура ОтправитьДанныеВоВнешнююСистему(Данные)
Попытка
// ...enviando
Исключение
// Vacío. Bueno, no se ha enviado y está bien.
КонецПопытки;
КонецПроцедурыTres meses después, el contador viene y dice: «Los datos no se han movido desde el verano pasado». Y en los registros, silencio.
Cómo hacerlo correctamente:
Процедура ОтправитьДанныеВоВнешнююСистему(Данные)
Попытка
// ...enviando
Исключение
ТекстОшибки = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("IntegrationExternalSystem",
УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
ВызватьИсключение "Failed to send data: " + ТекстОшибки;
КонецПопытки;
КонецПроцедурыRegla de oro: detecta solo los errores que sabes cómo manejar. El resto, regístralo y pasa a un nivel superior.
Exportación: no lo hagas todo público
En 1C existe la tentación de poner "Exportar" en cada función, por si acaso es útil. Esto hace que el módulo se convierta en un vertedero donde es imposible entender qué es una API pública y qué es una cocina interna.
La regla es simple: un procedimiento o función recibe el modificador "Exportar" solo cuando otros módulos realmente lo necesitan. Todo lo demás es una implementación privada que puedes cambiar como quieras.
// Esta es la API pública del módulo: un contrato bien documentado y estable
Функция РассчитатьСтоимостьДоставки(Параметры) Экспорт
// ...
КонецФункции
// Esta es una parte interna de la implementación, sin exportación
Функция ПолучитьТарифнуюЗону(АдресДоставки)
// ...
КонецФункцииValores devueltos: sea predecible
La función siempre debe devolver un valor de un tipo. Si una función puede devolver una cadena, un número o un valor indefinido según la situación, cada código de llamada se convierte en un detective.
Mal:
Функция НайтиКонтрагента(ИНН)
Запрос = Новый Запрос("...");
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат Ложь; // A veces booleano
КонецЕсли;
Возврат Результат.Выгрузить()[0].Контрагент; // A veces, el enlace
КонецФункцииBien:
// SIEMPRE devuelve un enlace. Enlace vacío = no encontrado.
Функция НайтиКонтрагентаПоИНН(ИНН)
Запрос = Новый Запрос("...");
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат Справочники.Контрагенты.ПустаяСсылка();
КонецЕсли;
Возврат Результат.Выгрузить()[0].Контрагент;
КонецФункцииComentarios: explica el «por qué» y no el «qué»
Un buen código apenas necesita comentarios: se explica a sí mismo a través de nombres comprensibles. Pero a veces los comentarios son necesarios: cuando es necesario explicar una regla de negocio no obvia o la razón de una solución no estándar.
Comentario inútil:
// Obteniendo la fecha
Дата = ТекущаяДата();Comentario útil:
// Utilizamos la fecha de inicio del próximo mes, porque las tarifas
// se actualizan el primer día del mes y la facturación debe calcularse según los nuevos precios
ДатаРасчёта = НачалоМесяца(ДобавитьМесяц(ТекущаяДата(), 1));Para las funciones de exportación, asegúrate de añadir una descripción de los parámetros y el valor devuelto. Esto no es una formalidad, es la documentación de tu API:
// Calcula el coste de envío en función de la zona y el peso.
// // Parámetros:
// Dirección de entrega - Línea - dirección completa en formato FIAS
// PesoGramo - Número - peso del envío en gramos
// // Valor devuelto:
// Número: coste de envío en rublos, 0 si el envío es gratuito
// Función CalcularCosteDeEnvío(DirecciónDeEnvío, PesoGramos) ExportarSi quieres profundizar tus conocimientos de programación y aprender sobre las tecnologías modernas, echa un vistazo a la aplicación Kodik. Es una plataforma educativa con cursos de Python, JavaScript, HTML, CSS y otros lenguajes, donde las cosas complejas se explican en un lenguaje sencillo y la teoría se apoya inmediatamente en la práctica.
Y en nuestro Canal de Telegram te espera una comunidad amistosa de más de 2000 desarrolladores, donde siempre puedes hacer una pregunta, obtener apoyo y encontrar personas de ideas afines. Únete — ¡crecer juntos en la profesión es mucho más fácil!
