From ddfcf6152d5c292b191e892711f3a500d1e64f39 Mon Sep 17 00:00:00 2001 From: Dmitriy Marmyshev Date: Fri, 11 Feb 2022 00:10:21 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=20=D1=82=D0=B8=D0=BF=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/checks/code_typification.md | 912 ++++++++++++++++++++++++------- 1 file changed, 702 insertions(+), 210 deletions(-) diff --git a/docs/checks/code_typification.md b/docs/checks/code_typification.md index 5711f7a2..e516de46 100644 --- a/docs/checks/code_typification.md +++ b/docs/checks/code_typification.md @@ -2,24 +2,188 @@ > Методическая рекомендация -[TOC text bullet hierarchy] +[TOC text numbered hierarchy levels=2-5] ## Цель -Снизить количество ошибок, выявляемых на этапе разработки, и исключить практику написания кода в режиме отладки за счет максимально возможной типизации кода для статического анализатора в 1C:EDT. +1. Снизить количество ошибок, выявляемых на этапе разработки +2. Исключить практику написания кода в режиме отладки за счет максимально возможной типизации кода для статического анализатора в 1C:EDT. +3. Более простой код для чтения человеком +4. Типизация кода позволит активнее применять различные средства анализа кода +5. Более качественный рефакторинг при модификации кода +6. Поддержка документирующих комментариев в актуальном (правдивом) состоянии +7. Применение инструментов автоматической обработки кода (авто-форматирование, авто-перевод кода и так далее). +8. Упрощение поддержки кода новыми разработчиками -Кроме того, типизация кода позволит активнее применять различные средства автоматической обработки кода (автоформатирование, рефакторинг, автоперевод кода и так далее). +## Как это работает -Следует использовать следующие возможности: -1. Динамический расчет типов, выполняемый в 1С:EDT на основе контекста 1С:Предприятия и метаданных конфигурации. -2. Статическое указание типов в документирующих/типизирующих комментариях, ссылки на функции-конструкторы и ссылки на входящие параметры. -3. Включение "строгой типизации" для модулей. +При изучении возможностей типизации следует учитывать, что: -## Включение строгой типизации +1. Язык исполнения 1С:Предприятия 8 (run-time) является/остается динамически-типизируемым +2. Все возможности вычисления типизации - это базовые возможности ядра 1C:EDT +3. Плагин `1С:Стандарты разработки V8` добавляет только контроль типов в 1C:EDT и проблемных ситуаций на основе базовых возможностей 1C:EDT + + +### Документация + +- [Документация EDT](https://its.1c.ru/db/edtdoc#content:330:hdoc) +- [Стандарт 1С: Описание процедур и функций](https://its.1c.ru/db/v8std#content:453:hdoc) +- [Доклад про систему расчета типов и многое другое...](https://youtu.be/Hwzn_O_oSow) +- [Доклад про систему валидации](https://developer.1c.ru/applications/Console/devcon/2-12.html) + +### Расчетная типизация + +Динамический расчет типов, выполняемый в 1С:EDT на основе контекста 1С:Предприятия и метаданных конфигурации. + +#### Отслеживание состояния типов переменных + +Система типизации кода 1C:EDT отслеживает тип переменных в зависимости от их использования (местоположения в коде) + +```bsl +МояПеременная = 10; +... +Если МояПеременная > 0 Тогда // В этом месте тип - Число +КонецЕсли; + +... +МояПеременная = Истина; +... +Если МояПеременная Тогда // В этом месте тип - Булево +КонецЕсли; +``` + +#### Отслеживание состояния типов свойств + +При анализе объектов данных (Data-flow analysis), создаваемых программно, система типизации 1C:EDT учитывает только те типы, которые были указаны в момент инициализации свойства в объекте данных. + +```bsl +Параметры = Новый Структура("МоеСвойство"); // Инициализация без указания начального типа +... +Параметры.МоеСвойство = 10; // Смена типа с Неопределено на Число не происходит +... +Если Параметры.МоеСвойство > 0 Тогда // В этом месте тип МоеСвойство - Неопределено +КонецЕсли; +... +Параметры.Вставить("ДругоеСтвойство", Ложь); // Свойство инициализируется с начальным значением + +Параметры.ДругоеСтвойство = 1; // Смена типа не происходит +... +Если Параметры.ДругоеСтвойство Тогда // В этом месте тип свойства - Булево +КонецЕсли; +... + +Если ТипЗнч(Параметры.ДругоеСтвойство) = Тип("Число") Тогда + Параметры.ДругоеСтвойство = Параметры.ДругоеСтвойство + 1; // В этом месте тип свойства - Булево +КонецЕсли; + +``` + +При фактической смене типа значения у свойства объекта, который допускает такое поведение в run-time `1С:Предприятия 8`, система типизации и анализа объектов данных в 1C:EDT не учитывает эту смену. + +В этом случае, правильным подходом является: указание начального типизированного значения, и не допускать сменя типа значения далее в коде. + +### Декларативная типизация + +Статическое указание типов в документирующих/типизирующих комментариях, ссылки на функции-конструкторы и ссылки на входящие параметры других методов. + +### Инструментарий + +Существуют стандартные инструменты в 1C:EDT и добавляемые расширениями (плагинами) инструменты, которые помогают типизировать код. + +#### Использование контекстного помощника ввода + +Документация по [Контекстной подсказке](https://its.1c.ru/db/edtdoc#content:323:hdoc) + +1. Для того, чтобы код был максимально типизирован изначально - при написании кода следует использовать контент-ассист (или контекстный помощник ввода) Ctrl+Space, который подсказывает все известные свойства и методы объекта. +2. При этом, если помощник ввода не подсказывает нужные свойства - следует сначала уточнить типы (исправить типы) для текущего объекта и продолжить набор текста по известным свойствам. +3. Использование типизации кода снижает потребность написания кода в режиме отладки с целью определения типов переменных, т.к. типы переменных подсказывает среда разработки. +4. Для проверки, того, что объект имеет статический или динамический тип - необходимо выделить нужный объект и нажать `F2` для отображения описания объекта - перед именем объекта должен отображаться его тип. + +> **Внимание!** Контекстный помощник ввода работает при наборе документирующих комментариев. + +#### Как диагностировать причины не типизированного кода + + +Диагностика проблемы: + +- при наведении мышкой на объект в коде - панель всплывающей подсказки не показывает тип, значит система типизации 1C:EDT не смогла его расчитать. +- в коде после точки обращения к свойству/методу вызвать контент-ассист (нажать `Ctrl+Space`) - подсказка ввода не показывает свойства в формате `Объект.Свойство <Тип свойства> ~ Тип объекта` + +> **Обратите внимание!** В подсказке ввода - после имени свойства указан тип свойства `<Тип свойства>` в фигурных скобках и после ` ~ Тип объекта` - тип, из которого это свойство получено, т.к. у объекта может несколько типов. + +Чтобы найти причины не типзированного кода, можно следовать некоторым пунктам: + +1. Необходимо найти самый первый объект в цепочке вызова в данной строке +2. Высянить есть ли у этого объекта тип - навести мышкой или нажать `F2` для вывода подсказки +3. Перейти к определению этого объекта - нажать `F3` и в месте определения выяснить тип +4. Определить тип слишком общим (абстрактным), например, `УправляемаФорма`, `ТаблицаЗначений`, `Массив`, `Структура`, `ДокументОбъект`, `СправочникСсылка` и т.д. без спецификации каких либо конкретных свойств к которым необходимо обращаться +5. Корректно ли написан типизирующий документирующий комментарий +6. Если типы корркетные - следует начиная от места определения объекта/переменной до места потери типа - проверить все места использования: пере-присвоения значения переменной, передача её в вызов метода и т.д. + +#### Генератор документирующих комментариев + +Документация по [Генератору документирующего описания методов](https://its.1c.ru/db/edtdoc#content:330:hdoc) + +1. Позволяет сформировать начальное документирующее описание метода, чтобы далее легче было до-редактировать +2. Заполняет известные типы входящих параметров или возвращаемых значений на основе расчетной типизации кода текущего модуля +3. Позволяет до заполнить отсутствующие секции или параметры в существующем документирующем комментарии и выполняет стандартное форматирование с учетом модели данных. Это позволяет увидеть ошибочно-написанные конструкции, которые не соответствуют формату документирующего комментария + +#### Панель структуры документирующего комментария + +Документация по [панели структуры документирующего комментария](../tools/bsl-doc-comment-view.md) + +Позволяет увидеть структуру данных документирующего комментария так как её считывает 1C:EDT, увидеть расхождения с тем что ожидал разработчик и тем что он написал. + +### Что такое "Строгая типизация" + +Кратко: это контроль (валидация) наличия всех типов, как декларативных, так и динамически-рассчитанных, в коде `1С:Предприятия 8`. Этот контроль предоставляется расширением "1С:Стандарты разработки V8" для 1С:EDT. + +Ключевые возможности: + +- Контроль наличия типов в месте создания объекта, переменной +- Контроль наличия типов в месте использования (обращение к свойствам или методам объекта) +- Контроль типов возвращаемых значений для функций, свойств объектов, переменных +- Запрет смены типов для переменных, и свойств объектов +- Пересечение типов при передаче объектов в параметры вызываемого метода +- Контроль декларируемых типов и типов из системы "анализа потока данных" ([Data-flow analysis](https://star-wiki.ru/wiki/Data-flow_analysis), DFA) для "пользовательских" объектов данных, т.е. специфичных структур и таблиц значений, создаваемых пользователем в коде +- Возможность включать "строгую типизацию" только в выбранных модулях, или для проекта в целом + +#### Чем не является "Строгая типизация" + +- Не ООП +- Не добавляется иерархия типов 1С, и не меняется если иерархия есть +- Не добавляется понятия абстрактных объектов, или "Интерфейсов" для общего поведения объектов и их "реализация" в конкретных объекта +- Не меняется система типов `1С:Предприятия 8` - только контролируется существющие типы + +#### Аналогия TypeScript и JavaScript + +У многих разработчиков `1С` возникает справедливая ассоциация с языком `TypeScript`. При разработке "Строгой типизации" мы действительно "подглядывали" в связку этих двух языков `TS + JS`. + +Подробнее про [TypeScript здесь](https://ru.wikipedia.org/wiki/TypeScript). + +В чем "Строгая типизация 1С" похожа на `TypeScript`: + +- Результирующий код 1С - всё так же исполняется в 1С:Предприятии, как `TypeScript` после компиляции исполняется в браузере +- Статическая типизация проверяется в языке `1С:Предприятия 8` +- Ошибки типизации отображаются только в IDE, при этом в run-time `1С:Предприятия 8` смена типа по-прежнему возможна +- В рамках одного приложения можно только в одном/некоторых модулях включить "Строгую типизацию" - остальные модули могут быть по-прежнему слабо-типизированными +- Взаимодействие модулей "Строгой типизации" с модулями без "строгой типизации" по прежнему возможно, аналогично как `TypeScript` взаимодействует с модулями JS + + +В чем отличие "Строгой типизации" от `TypeScript`: + +- Нет процесса трансляции/компиляции (Trans-piling) в язык 1С - модули со строгой типизацией исполняются "как есть" в run-time `1С:Предприятия 8` +- Не добавляется ООП в язык 1С, т.к. это противоречит идеологии языка `1С:Предприятия 8` +- Не добавляется поддержка "библиотек" (модулей), при этом понятие "модулей" в `1С:Предприятия 8` присутствует - тут 50/50, не стоит холиварить на эту тему. +- "Строгая типизация" не добавляет никаких функциональных возможностей в язык `1С:Предприятия 8` +- Не добавляются "Интерфейсы" в язык `1С:Предприятия 8` + + +#### Включение строгой типизации При использовании дополнительного расширения "1С:Стандарты разработки" для 1С:EDT рекомендуется для модуля включить строгую типизацию, которая будет контролировать, что все типы были созданы правильно, во всех местах используется жесткие ссылки на объекты-создатели, что нет смены типа у переменной. -Контроль типизации будет выполняться для всего модуля, включая не экспортные методы. Контролируется наличие типов всех переменных, используемых вызовов общих модулей, при обращении к полям/свойствам объектов контролируется их наличие и их типы. +Контроль типизации будет выполняться для всего модуля, включая не экспортные методы. Контролируется наличие типов всех переменных, используемых вызовов общих модулей, при обращении к полям/свойствам объектов контролируется их наличие и их типы. Для этого необходимо в заголовке модуля указать аннотацию до первого семантического объекта (области, процедуры, переменной): @@ -40,19 +204,504 @@ #### Применение строгой типизации -* Для всех новых конфигураций, не имеющих большого наследия не типизированного кода, для всех модулей следует включать строгую типизацию. +В каких случаях рекомендуется применять: -* Для существующих модулей рекомендуется сначала выполнить адаптацию кода и после включить строгую типизацию. +- Для всех новых конфигураций, не имеющих большого наследия не типизированного кода, для всех модулей следует включать строгую типизацию. +- Для существующих модулей рекомендуется сначала выполнить адаптацию кода и после включить строгую типизацию. -## Использование контекстного помощника ввода +Стандарт 1С [Описание процедур и функций](https://its.1c.ru/db/v8std#content:453:hdoc) п.2 требует наличие описания только программного интерфейса. Это означает, что: -1. Для того, чтобы код был максимально типизирован изначально - при написании кода следует использовать контент-ассист (или контекстный помощник ввода) Ctrl+Space, который подсказывает все известные свойства объекта. -2. При этом, если помощник ввода не подсказывает нужные свойства - следует сначала уточнить типы (исправить типы) для текущего объекта и продолжить набор текста по известным свойствам. -3. Использование типизации кода снижает потребность написания кода в режиме отладки с целью определения типов переменных, т.к. типы переменных подсказывает среда разработки. -4. Для проверки, того, что объект имеет статический или динамический тип - необходимо выделить нужный объект и нажать `F2` для отображения описания объекта - перед именем объекта должен отображаться его тип. +- для экспортных методов из области `"ПрограммныйИнтерфейс"` необходимо указывать описание смысла методов и параметров для программиста, так же обязательное указание типов +- для экспортных служебных методов (из любых других областей модуля) обязательно только указание типизирующих документирующих комментариев + +### Расширение типов + +Система типизации кода в 1C:EDT работает по принципу расширения типов, собирая информацию о типах из всех возможных источников. + +```bsl +МояПеременная = ФункцияРазличныхТипов(Ложь); // Булево - добавляем ещё тип + +Функция ФункцияРазличныхТипов(Флаг) + Если Флаг Тогда + Вовзрат ""; + Иначе + Вовзрат 10; + КонецЕсли; +КонецФункции +``` + +В данном примере, у переменной `МояПеременная` будет 2 расчетный и один декларативный тип: `Строка, Число, Булево`. + +### Сокращение типа локальной переменной или параметра + +- Можно безопасно сократить (или фактически установить для статического анализатора) тип локальной переменной метода, входящего параметра или переменной модуля (объекта, формы) метода через проверку типа: + +```bsl +Если ТипЗнч(МояПеременная) = Тип("СправочникОбъект.Товары") Тогда + МояПеременная.Артикул = ""; + МояПеременная.Записать(); +``` + +при этом внутри условия переменная будет указанного в проверке типа, как в рантайме, так и для статического анализатора. Условие проверки должно быть простым. -## Инициализация локальных переменных +## Возможности типизирующих документирующих комментариев + +- [Комментирование процедур и функций](https://its.1c.ru/db/edtdoc#content:330:hdoc) +- [Стандарт 1С: Описание процедур и функций](https://its.1c.ru/db/v8std#content:453:hdoc) + +Документирующие комментарии необходимы для 2х целей: + +1. Декларирование типов входящих параметров и возвращаемых значений функций +2. Описание назначения процедуры, параметров и полей для разработчиков + +1C:EDT поддерживает решение этих целей независимо друг от друга: можно писать описания без типов, или типы без описаний, или комбинация типов и описаний. + +### Описание структуры данных док.коммента + +Структуру данных документирующего комментария можно представить в следующем упрощенном иерархическом виде: + +```yml +Description: # Объект описания, состоящий из коллекции строк и ссылок + - TextPart # Текстовая строка описания + - LinkPart # Ссылка на сайт или на метод конфигурации + +ParameterSection: # Секция параметров метода, у секции может быть свою описание + Description: + - ... + ParameterDefinitions: # Список параметров + - FieldDefinition: + Name: ParameterName # Имя параметра + Description: # Описание параметра + - ... + TypeSections: # Список секций типов, может быть несколько + - TypeSection: + Description: + - ... + TypeDefinitions: # Список определений типов + - TypeDefinition: + TypeName: TypeName # Имя тип 1С + ContainTypes: # Список описаний типов элементов коллекций, если в определении указана колекция + - TypeDefinition: + ... + - TypeDefinition + FieldDefinitionExtension: # Возможность расширить тип полями (для структур, ТЗ и т.д.) + - FieldDefinition: + ... + + - TypeDefinition + - LinkContainsTypeDefinition # Определение типа содержащего ссылку на функцию или параметр + LinkPart: LinkPart + + - FieldDefinition: + ... + +CallOptionsSecton: # Секция параметров вызова + Description: + - ... + +ExampleSection: # Секция примеров использования метода + Description: + - ... + +ReturnSection: # Секция описания возвращаемого значения функции + Description: + - ... + ReturnTypes: # Список секций типов возвращаемых значений + - TypeSection: + Description: + - ... + TypeDefinitions: + - TypeDefinition: + ... + + - TypeSection: + ... +``` + +Рассмотрим подробнее на примерах возможности документирующих комментариев. + +Описание - многострочное, со ссылками + +```bsl +// В описании рекомендуется писать все ссылки на отдельной строке. +// ссылки на веб-страницы: +// См. https://1c.ru +// Ссылка на функцию в тексте описания +// См. ОбщегоНазначения.ФункцияМодуля +// +Процедура ОбработкаОбъекта(Объект) +``` + +В секции параметры, после ключевого слова - обязательно идет двоеточие + +```bsl +// Описание метода +// +// Параметры: +// Объект - СправочникОбъект.Товары +Процедура ОбработкаОбъекта(Объект) +``` + +Иначе секция параметров - превращается в описание метода + +```bsl +// Здесь все 3 строки являются описанием метода и не содержат декларации параметров +// Параметры +// Объект - СправочникОбъект.Товары +Процедура ОбработкаОбъекта(Объект) +``` + +Возможно описание поля/параметра без указания типа, но лучше так не делать + +```bsl +// Описание метода +// +// Параметры: +// У секции параметров может быть своё описание +// Объект - У параметра может быть описание без декларации типов +Процедура ОбработкаОбъекта(Объект) +``` + +Обычно, описание поля/параметра идет после секции определения типов + +```bsl +// Параметры: +// Объект - СправочникОбъект.Товары - Здесь описание для типа +Процедура ОбработкаОбъекта(Объект) +``` + +Возможно указание описания для каждого типа поля/параметра, когда каждый тип записан с новой строки, через дефис-минус. Не допускается использование различных видов "тире" (длинных, коротых, средних и т.д.) + +```bsl +// Параметры: +// Объект - СправочникОбъект.Товары - Здесь описание для типа +// - ДокументОбъект.РеализацияТоваров - Здесь описание для другого типа +Процедура ОбработкаОбъекта(Объект) +``` + +Простой вариант записи нескольких типов - через запятую + +```bsl +// Параметры: +// Объект - СправочникОбъект.Товары, ДокументОбъект.РеализацияТоваров - Здесь описание для списка типов +Процедура ОбработкаОбъекта(Объект) +``` + +В простом случае - описание поля/параметра может быть многострочным + +```bsl +// Параметры: +// Объект - СправочникОбъект.Товары - Здесь описание для типа +// Вторая строка описания параметра +Процедура ОбработкаОбъекта(Объект) +``` + +Описание единственного типа элементов коллекции + +```bsl +// Параметры: +// Объект - Массив из СправочникОбъект.Товары - Здесь единственный тип элементов +Процедура ОбработкаОбъекта(Объект) +``` + +Описание составного типа элементов коллекции через запятую + +```bsl +// Параметры: +// Объект - Массив из СправочникОбъект.Товары, ДокументОбъект.РеализацияТоваров - +Процедура ОбработкаОбъекта(Объект) +``` + +Возможность указывать расширение полей для типа, **строго после двоеточия** в конце однострочного описания + +```bsl +// Параметры: +// Объект - Структура - Здесь нельзя многострочное описание: +// * ПолеСтруктруы - ТаблицаЗначений - Описание поля структуры, после опять раширение уже для таблицы: +// ** ИмяКолонки - Число - описание колонки таблицы +Процедура ОбработкаОбъекта(Объект) +``` + +Можно не писать описание, оставлять только типы и обязательное двоеточие + +```bsl +// Параметры: +// Объект - Структура: +// * ПолеСтруктруы - ТаблицаЗначений: +// ** ИмяКолонки - Число +Процедура ОбработкаОбъекта(Объект) +``` + +Не всегда возможно правильно определять что сейчас "описание без типа" или "тип без описания", поэтом может требоваться указание дефиса после списка типов для явного опредлеения секции типов + +```bsl +// Параметры: +// Объект - Структура, ТаблицаЗначений - +Процедура ОбработкаОбъекта(Объект) +``` + +В этом случае без секция со списком типов превращается в просто текстовое описание + +```bsl +// Возвращаемое значение: +// Структура, ТаблицаЗначений +Функция ОбработкаОбъекта(Объект) +``` + +Декларацию списока типов возвращаемого значения нужно записывать явно с дефисом в конце или с но + +```bsl +// Возвращаемое значение: +// Структура, ТаблицаЗначений - +Функция ОбработкаОбъекта(Объект) +``` + +Декларацию списка типов возвращаемого значения можно записывать каждый с новой строки + +```bsl +// Возвращаемое значение: +// - Структура +// - ТаблицаЗначений +Функция ОбработкаОбъекта(Объект) +``` + +Бесполезная ссылка на функцию-конструктор в описании к параметру + +```bsl +// Параметры: +// Объект - ТаблицаЗначений - См. ОбщегоНазначения.НовыйОбъектДанных +Процедура ОбработкаОбъекта(Объект) +``` + +Ссылка на тип не кобминируется с описанием для текущего элемента, должны быть записаны вместо типа + +```bsl +// Параметры: +// Объект - См. ОбщегоНазначения.НовыйОбъектДанных +Процедура ОбработкаОбъекта(Объект) +``` + +В возвращаемом значении функции можно указывать ссылки на тип + +```bsl +// В возвращаемом значении функции можно указывать +// +// Возвращаемое значение: +// См. Справочник.Товары.ЕдиницыИзмерения +Функция ОбработкаОбъекта(Объект) +``` + +В возвращаемом значении функции можно указывать ссылки на локальные не экспортные функции конструткоры объектов данных, если функция должна возвращать заполненный объект, но модуль не должен позволять через API создавать новый пустой объект данных + +```bsl +// Экспорт из модуля типа объекта в функции, создающем объект и заполняющем значения, +// функция-конструктор остается не доступной для потребителей +// +// Возвращаемое значение: +// См. НовыйОбъектДанных +Функция ОбработкаОбъекта(Объект) Экспорт +``` + +### Ссылка на типы + +Система типизации 1C:EDT поддерживает ссылки на типы вместо их прямого указания. +Использовать ссылки на типы удобно для сокращения объема текста в документирующих комментариях. +Так же, это повышает точность описания типов при изменении сложных объектов данных и не требует модификаций при рефакторинге. + + +#### Ссылка на типы из объектов метаданных + +Множество различных объектов метаданных производят коллекции типов. +Документирующий комментарий позволяет ссылаться на этот тип. + +Рассмотрим различные примеры ссылок на такие типы. + +##### Ссылка на Табличную часть объекта + + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Объект - См. Справочник.Товары.ЕдиницыИзмерения +Процедура ОбработкаОбъекта(Объект) +``` + +##### Ссылка на Строку Табличной части объекта + +> Такая ссылка еще не поддерживается в 1C:EDT! + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Объект - СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения +Процедура ОбработкаОбъекта(Объект) +``` + +##### Ссылка на тип реквизита объекта или реквизита Табличной части объекта + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Реквизит1 - См. Справочник.Товары.Артикул +Процедура ОбработкаОбъекта(Реквизит1) +``` + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// РеквизитТЧ - См. Справочник.Товары.ЕдиницыИзмерения.Единица +Процедура ОбработкаОбъекта(РеквизитТЧ) +``` + +##### Ссылка на Форму + +Ссылка на форму указывается по полному имени формы + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Форма - См. Справочник.Товары.Форма.ФормаЭлемента +Процедура ОбработкаОбъекта(Форма) +``` + +##### Ссылка на Элемент Формы, Реквизит формы + +Ссылка тип реквизита формы + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Объект - См. Справочник.Товары.Форма.ФормаЭлемента.Объект +Процедура ОбработкаОбъекта(Объект) +``` + +Ссылка тип элемента формы + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Список - См. Справочник.Товары.Форма.ФормаСписка.Элементы.Список +Процедура ОбработкаОбъекта(Список) +``` + +##### Ссылка на Текущие данные динамического списка формы + +Использование ссылки на тип текущих данных динамического списка на форме не поддерживается в документирующих комментариях. +В место этого следует передавать сам элемент формы и далее обрабатывать `ТекущиеДанные` + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Список - См. Справочник.Товары.Форма.ФормаСписка.Элементы.Список +Процедура ОбработкаОбъекта(Список) + ЗначениеАртикула = Список.ТекущиеДанные.Артикул; + ... +``` + +##### Ссылка на Строку таблицы значений формы + +> Такая ссылка еще не поддерживается в 1C:EDT! + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// СтрокаТЗ - ДанныеФормыЭлементКоллекции: См. Справочник.Товары.Форма.ФормаСписка.Элементы.ТЗ +Процедура ОбработкаОбъекта(СтрокаТЗ) +``` + + +#### Ссылка на типы объектов кода + +В ссылка типизирующих комментариев можно пере-использовать описанные типы из возвращаемого значения функций или входящих параметров метода. + +##### Ссылка на тип параметра метода в модели менеджера, объекта, общем модуле + +Ссылка на тип параметра экспортного метода из модуля менеджера + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Список - См. Справочники.Товары.МетодМодуляМенеджера.Параметр1 +Процедура ОбработкаОбъекта(Список) +``` + +Ссылка на тип параметра экспортного метода из модуля объекта + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Список - См. СправочникОбъект.Товары.МетодМодуляОбъекта.Параметр2 +Процедура ОбработкаОбъекта(Список) +``` + + +### Наследование типов параметров по сигнатуре метода + +При размещении процедур в общих модулях (обычно "Переопределяемый") из общих процедуры могут быть вызваны наследники какого-либо механизма библиотеки. + +ПРАВИЛЬНО: + +```bsl +// Параметры: +// Список - См. СправочникОбъект.Товары.МетодМодуляОбъекта.Параметр2 +// Реквизит - См. Справочник.Товары.ЕдиницыИзмерения.Единица +// Объект - СправочникОбъект.Товары +Процедура ОбработкаОбъекта(Список, Реквизит, Объект) Экспорт + Документы.РеализацияТоваров.ОбработкаОбъекта(Список, Реквизит, Объект); + Документы.ПоступлениеТоваров.ОбработкаОбъекта(Список, Реквизит, Объект); + ... +``` + +В модуле менеджера соответствующих объектов можно сослаться на сигнатуру параметров метода, чтобы не описывать полностью все типы. +Необходимо указать только ссылку на метод, других комментариев или элементов документирующих комментариев быть не должно. + +ПРАВИЛЬНО: + +```bsl +// См. ОбщийМодульПодсистема1Переопределяемый.ОбработкаОбъекта +Процедура ОбработкаОбъекта(Список, Реквизит, Объект) +``` + +В этом случае будет выполнено сопоставление имен параметров текущего метода с именами параметров метода "интерфейса". + + +### Типизация локальной переменной в строке + +Для локальных переменных возможно указание типов в строке инициализации. + + +```bsl +Процедура ОбработкаФормы(Форма, ИмяРеквизита) +Данные = Форма[ИмяРеквизита]; // ПолеВвода - опциональное описание, почему переопределяем тип +``` + +Поддерживаются ссылки на типы: + +```bsl +Данные = ПолучитьИзВременногоХранилища(Адрес); // см. НовыйОбъектДанных +``` + +> **Внимание!** В целом, такой подход следует считать исключеним и не практиковать в коде, если возможно спроектировать код более прозрачно для вычисления типов. + +## Лучшие практики написания типизированного кода + +Здесь собраны примеры решения различных задач типизации. +Если вы не нашли здесь какой-либо случай, но самостоятельно разобрались как правильно решать - просим вас [добавить пример на эту страницу](https://github.com/1C-Company/v8-code-style/blob/master/docs/checks/code_typification.md) через [контрибутинг](../contributing/readme.md) в проект. + + +### Инициализация локальных переменных - Запрещается инициализация переменных через `Перем` т.к. такая переменная инициализируется с типом `Неопределенно` и дальнейшая смена типа значения может быть не видна для статического анализатора @@ -139,7 +788,7 @@ МояПеременная = Типизатор.ПривестиЗначение(Неопределено); ``` -## Инициализация переменных модуля +### Инициализация переменных модуля Переменные модуля объекта, формы, конфигурации, включая глобальные переменные (экспортные), следует объявлять со статическим указанием типа в комментарии. Также следует инициализировать переменную модуля начальным/пустым значением в коде модуля (после всех процедур и функций). Для модуля формы допускается инициализация начального/пустого значения в обработчиках событий `ПриСозданииНаСервере` для серверных переменных и в обработчике `ПриОткрытии` для клиентских переменных. @@ -187,19 +836,7 @@ ``` -## Сокращение типа локальной переменной или параметра - -- Можно безопасно сократить (или фактически установить для статического анализатора) тип локальной переменной метода, входящего параметра или переменной модуля (объекта, формы) метода через проверку типа: - -```bsl -Если ТипЗнч(МояПеременная) = Тип("СправочникОбъект.Товары") Тогда - МояПеременная.Артикул = ""; - МояПеременная.Записать(); -``` - -при этом внутри условия переменная будет указанного в проверке типа, как в рантайме, так и для статического анализатора. Условие проверки должно быть простым. - -## Инициализация ключей структуры +### Инициализация ключей структуры - Значения ключей структуры (как в конструкторе, так и при добавлении в структуру) должны быть инициализированы сразу с пустым значением того типа, который будет использоваться в последствии. Динамическая типизация не позволяет рассчитать смену типа свойства структуры и, если не указывать пустое значение нужного типа, свойство будет инициализировано с типом Неопределенно. - Смена типа значения ключа структуры - не допускается. @@ -308,7 +945,7 @@ ``` -## Описание массивов +### Описание массивов - В общем случае - запрещено создавать массив `Новый Массив;` без указания типа его значений, если далее в коде текущего модуля происходит обращение к элементам массива. @@ -356,7 +993,7 @@ - Если в функции создается массив и наполняется значениями, допустимо описывать возвращаемое значение типов элементов массива в описании функции, если в самой функции не происходит обращения к элементам массива. - В документирующих комментариях следует указывать тип элементов массива для параметров и возвращаемых значений. -## Описание таблицы значений, дерева значений +### Описание таблицы значений, дерева значений - Следует при описании объекта `ТаблицаЗначений`, `ДеревоЗначений` всегда описывать все колонки и их типы. @@ -428,9 +1065,10 @@ - Исключением являются методы обрабатывающие таблицу значений с неопределенным набором колонок, например "копирование таблицы в структуру", при этом код не обращается к колонкам напрямую `СтрокаТЗ.Номенклатура = ...` а использует для обращения список колонок, сформированный в рантайме `СтрокаТЗ[ИмяКолонки] = ...`. -## Описание строки таблицы или дерева значений +### Описание строки таблицы или дерева значений Следует использовать один из двух вариантов: + - прямое указание колонок, на которые рассчитывает код в данной процедуре НЕПРАВИЛЬНО: @@ -472,7 +1110,7 @@ .... ``` -## Описание соответствия +### Описание соответствия - Соответствие - это фактически сложный тип с фиксированным набором колонок (ключ и значение) или аналогичен массиву из структур с 2 колонками. При этом описание типов у ключа и значения есть по умолчанию - `Произвольный`, и необходимо создавать функцию конструктор которая инициализирует соответствие и описывает типы ключа и значения. - Следует избегать комбинации [различных типов в ключе и в значении соответствия](#ограничения-составных-типов). @@ -489,160 +1127,8 @@ ``` -## Ссылка на Табличную часть объекта - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Объект - См. Справочник.Товары.ЕдиницыИзмерения -Процедура ОбработкаОбъекта(Объект) -``` - -## Ссылка на Строку Табличной части объекта - -> Такая ссылка еще не поддерживается в 1C:EDT! - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Объект - СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения -Процедура ОбработкаОбъекта(Объект) -``` - -## Ссылка на тип реквизита объекта или реквизита Табличной части объекта - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Реквизит1 - См. Справочник.Товары.Артикул -Процедура ОбработкаОбъекта(Реквизит1) -``` - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// РеквизитТЧ - См. Справочник.Товары.ЕдиницыИзмерения.Единица -Процедура ОбработкаОбъекта(РеквизитТЧ) -``` - -## Ссылка на Форму - -Ссылка на форму указывается по полному имени формы - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Форма - См. Справочник.Товары.Форма.ФормаЭлемента -Процедура ОбработкаОбъекта(Форма) -``` - -## Ссылка на Элемент Формы, Реквизит формы - -Ссылка тип реквизита формы - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Объект - См. Справочник.Товары.Форма.ФормаЭлемента.Объект -Процедура ОбработкаОбъекта(Объект) -``` - -Ссылка тип элемента формы - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Список - См. Справочник.Товары.Форма.ФормаСписка.Элементы.Список -Процедура ОбработкаОбъекта(Список) -``` - -## Ссылка на Текущие данные динамического списка формы - -Использование ссылки на тип текущих данных динамического списка на форме не поддерживается в документирующих комментариях. -В место этого следует передавать сам элемент формы и далее обрабатывать `ТекущиеДанные` - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Список - См. Справочник.Товары.Форма.ФормаСписка.Элементы.Список -Процедура ОбработкаОбъекта(Список) - ЗначениеАртикула = Список.ТекущиеДанные.Артикул; - ... -``` - -## Ссылка на Строку таблицы значений формы - -> Такая ссылка еще не поддерживается в 1C:EDT! - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// СтрокаТЗ - ДанныеФормыЭлементКоллекции: См. Справочник.Товары.Форма.ФормаСписка.Элементы.ТЗ -Процедура ОбработкаОбъекта(СтрокаТЗ) -``` - -## Ссылка на тип параметра метода в модели менджера, объекта, общем модуле - -Ссылка на тип параметра экспортного метода из модуля менеджера - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Список - См. Справочники.Товары.МетодМодуляМенеджера.Параметр1 -Процедура ОбработкаОбъекта(Список) -``` - -Ссылка на тип параметра экспортного метода из модуля объекта - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Список - См. СправочникОбъект.Товары.МетодМодуляОбъекта.Параметр2 -Процедура ОбработкаОбъекта(Список) -``` - -## Наследование типов параметров по сигнатуре метода - -При размещении процедур в общих модулях (обычно "Переопределяемый") из общих процедуры могут быть вызваны наследники какого-либо механизма библиотеки. - -ПРАВИЛЬНО: - -```bsl -// Параметры: -// Список - См. СправочникОбъект.Товары.МетодМодуляОбъекта.Параметр2 -// Реквизит - См. Справочник.Товары.ЕдиницыИзмерения.Единица -// Объект - СправочникОбъект.Товары -Процедура ОбработкаОбъекта(Список, Реквизит, Объект) Экспорт - Документы.РеализацияТоваров.ОбработкаОбъекта(Список, Реквизит, Объект); - Документы.ПоступлениеТоваров.ОбработкаОбъекта(Список, Реквизит, Объект); - ... -``` - -В модуле менеджера соответствующих объектов можно сослаться на сигнатуру параметров метода, чтобы не описывать полностью все типы. -Необходимо указать только ссылку на метод, других комментариев или элементов документирующих комментариев быть не должно. - -ПРАВИЛЬНО: - -```bsl -// См. ОбщийМодульПодсистема1Переопределяемый.ОбработкаОбъекта -Процедура ОбработкаОбъекта(Список, Реквизит, Объект) -``` - -В этом случае будет выполнено сопоставление имен параметров текущего метода с именами параметров метода "интерфейса". - -## Функции-конструкторы сложных объектов данных +### Функции-конструкторы сложных объектов данных Для сложных типов, создаваемых на основе абстрактных платформенных типов (`Структура`, `Соответствие`, `ТаблицаЗначений`, `ДеревоЗначений` и др.), следует использовать функцию-конструктор данных. @@ -661,7 +1147,7 @@ - Конструктор данных может так же выполнять функцию заполнения данных т.е. предоставлять новый объект с заполненными данными. Например, функция выполняет запрос к БД и возвращает таблицу значений с колонками и данными. -### Указание ссылки на функцию-конструктор данных +#### Указание ссылки на функцию-конструктор данных При описании параметра метода следует указывать ссылку на функцию-конструктор данных без указания исходного базового типа данных (структура, таблица значений и т.д.). @@ -727,9 +1213,9 @@ Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт ``` -### Функции-получатели сложных объектов данных +#### Функции-получатели сложных объектов данных -При обработке более общих типов объектов в общих модулях может потребоваться получить заранее известный комплексный тип (`Структура`, `ТаблицаЗначений`, `ДеревоЗначений`), при этом, функции-конструктора таких данных может не существовать, например когда данные создаются объектом метаданных, формой, СКД и так далее. Для таких случаев следует использовать функцию-получатель, описывающую тип возвращаемого значения со всеми необходимыми свойствами/полями объекта. +При обработке более общих типов объектов в общих модулях может потребоваться получить заранее известный комплексный тип (`Структура`, `ТаблицаЗначений`, `ДеревоЗначений`), при этом, функции-конструктора таких данных может не существовать, например, когда данные создаются объектом метаданных, формой, СКД и так далее. Для таких случаев следует использовать функцию-получатель, описывающую тип возвращаемого значения со всеми необходимыми свойствами/полями объекта. Для клиентских процедур не рекомендуется использовать конструкторы из модулей с контекстом 'Сервер', но без контекста 'Вызов сервера'. НЕПРАВИЛЬНО: @@ -781,8 +1267,14 @@ Возврат Форма.РеквизитФормыВЗначение(ИмяЭлементаДерева); КонецФункции ``` +#### Ограничение на использование Функций-конструкторов -## Ограничение на использование в документирующих описаниях Массивов, ТЗ, Структур +- Не следует создавать фиктивные функции-конструкторы, лишь для целей ссылки на возвращаемые типы. Следует проектировать код таким образом, чтобы функции-конструкторы создавали или получали объекты. +- Функции-конструкторы данных являются частью работы какого-либо объекта метаданных или функциональной подсистемы - поэтому должны располагаться в коде модулей этих объектов/подсистем. +- Созданный объект данных в текущем модуле передается в другой модуль или возвращается экспортной функцией - является частью API этого модуля. + + +### Ограничение на использование в документирующих описаниях Массивов, ТЗ, Структур Для параметров экспортных методов рекомендуется указывать ссылку на функцию-конструктор таких объектов. @@ -790,13 +1282,13 @@ Допускается описание таких типов во входящих параметрах, если описывается часть объекта или программный интерфейс объекта, например несколько колонок `ТЧ.Товары` для которых выполняется расчет, при этом не существует одной единой функции-конструктора на которую можно сослаться в описании. -## Описание программных интерфейсов для реализации в прикладных объектах +### Описание программных интерфейсов для реализации в прикладных объектах Существует понятие "описания программного интерфейса объекта" и его реализация в прикладных объектах конфигурации. С применением библиотечного подхода к разработке конфигураций, библиотека может описывать некий программный интерфейс который должен быть реализован в прикладном объекте, для того чтобы библиотечный механизм имел доступ к объекту. Например, механизм "Свойства" из библиотеки БСП описывает интерфейс объекта: Наличие табличной части `ДополнительныеРеквизиты`, содержит колонки `Свойство`, `Значение`, `ТекстоваяСтрока` с определенными типами. Далее общий механизм библиотеки может обращаться к объекту например, при записи `УправлениеСвойствами.ПередЗаписьюНаСервере(ЭтотОбъект, ТекущийОбъект);` объекта из формы. -Следует описывать интерфейс входящего объекта для той части объекта, которая требуется для работы механизма. При этом, следует учитывать, что механизм расширений свойств в документирующих коментариях поддерживается для тех типов, у которых возможны пользовательские совойства. Например: элементы коллекции вместо самих коллекций - тип `ТабличнаяЧасть` не имеет пользовательских свойств, а тип `СтрокаТабличнойЧасти` может иметь; тип `ДанныеФормыКоллекция` не имеет пользовательских свойств, а тип `ДанныеФормыЭлементКоллекции` может иметь. +Следует описывать интерфейс входящего объекта для той части объекта, которая требуется для работы механизма. При этом, следует учитывать, что механизм расширений свойств в документирующих комментариях поддерживается для тех типов, у которых возможны пользовательские свойства. Например: элементы коллекции вместо самих коллекций - тип `ТабличнаяЧасть` не имеет пользовательских свойств, а тип `СтрокаТабличнойЧасти` может иметь; тип `ДанныеФормыКоллекция` не имеет пользовательских свойств, а тип `ДанныеФормыЭлементКоллекции` может иметь. НЕПРАВИЛЬНО: @@ -855,9 +1347,9 @@ ... ``` -## Описание используемых реквизитов и элементов форм для общего кода по работе с формами +### Описание используемых реквизитов и элементов форм для общего кода по работе с формами -- Допускается описание части формы, общие для нескольких форм или реализация некого интерфейса для общего механизма конфигурации. Например, части одного общего механизма подключенные к множеству объектов конфигурации (дополнительные реквизиты, контактная информация и т.д.). +- Допускается описание части формы, общие для нескольких форм или реализация некого интерфейса для общего механизма конфигурации. Например, части одного общего механизма, подключенные к множеству объектов конфигурации (дополнительные реквизиты, контактная информация и т.д.). ПРАВИЛЬНО: @@ -899,9 +1391,9 @@ .... ``` -## Получение и открытие формы +### Получение и открытие формы -- При использовании методов  `ПолучитьФорму()` и `ОткрытьФорму()` с присвоением возвращаемого значения формы после открытия - следует указывать строковый литерал с полным именем формы первым параметром. +- При использовании методов `ПолучитьФорму()` и `ОткрытьФорму()` с присвоением возвращаемого значения формы после открытия - следует указывать строковый литерал с полным именем формы первым параметром. - Не следует выносить строковый литерал в отдельную переменную т.к. в этом случае переменная форма будет содержать общий тип `ФормаКлиентскогоПриложения` а не конкретный тип формы справочника номенклатуры, и весь контекст формы не будет доступен. В 1C:EDT на текущий момент поддерживается полная типизация только для полных имен форм, ссылки на основные формы для объекта метаданного `ФормаОбъекта`, `ФормаСписка` и т.д. возвращают общий тип `ФормаКлиентскогоПриложения`, полная типизация может быть поддержана в будущих версиях. НЕПРАВИЛЬНО: @@ -919,17 +1411,17 @@ Форма = Справочники.Номенклатура.ПолучитьФорму("ФормаЭлемента"); ``` -## Экспортные процедуры и функции +### Экспортные процедуры и функции -- Все параметры методов и возвращаемые значения функций должны содержать описания типов, при этом пояснения к параметрам следует описывать в соответствии со стандартом [?] +- Все параметры методов и возвращаемые значения функций должны содержать описания типов, при этом пояснения к параметрам следует описывать в соответствии со [стандартом](https://its.1c.ru/db/v8std#content:453:hdoc) - Локальные процедуры и функции не обязаны содержать описаний типов в документирующих комментариях и могут быть полностью расчетными, если код написан прозрачно для статического анализатора. -## Разрыв прямого контекста выполнения кода +### Разрыв прямого контекста выполнения кода - В случае разрыва прямого вызова методов в рамках одного модуля (когда из одного метода напрямую вызывается другой метод) - следует описывать типы входящих параметров для не экспортных методов. -## Использование временного хранилища и других контейнеров +### Использование временного хранилища и других контейнеров - Поместить во временное хранилище и после получить из него - можно все что угодно, поэтому необходимо выделять функцию возвращающую тип помещенный во временное хранилище использовать на нее ссылку при получении: @@ -939,7 +1431,7 @@ - Аналогичный подход следует использовать при помещении пользовательского объекта внутрь другого объекта-контейнера, например `ДополнительныеПараметры` у объектов, или `Параметры` формы, пользовательские параметры элементов `СКД`, `ДополнительныеПараметры` у обработчиков оповещения и так далее. -## Использование строковых литералов в качестве имен +### Использование строковых литералов в качестве имен Не следует обращаться к элементу именованной коллекции, например `ВсеЭлементыФормы` и другие, через строковый индекс с именем элемента. Вместо этого следует обращаться напрямую к элементу так как в этом случае статический анализатор может контролировать наличие элемента, его тип. @@ -994,7 +1486,7 @@ ``` -## Ограничение на использование реквизитов формы с типом "Произвольный" +### Ограничение на использование реквизитов формы с типом "Произвольный" Реквизит формы с типом `Произвольный` в коде следует рассматривать как "черный ящик". Статический анализатор не отслеживает изменение типа реквизита формы, поэтому весь обслуживающий этот реквизит код должен использовать проверку типа значения. @@ -1032,12 +1524,12 @@ Ссылка = РеквизитПроизвольный().Ссылка; ``` -## Использование параметров формы +### Использование параметров формы - Запрещается использовать параметр с типом "Произвольный" для передачи структуры параметров для инициализации формы. - В редакторе формы на вкладке "Параметры" следует описывать все параметры, на которые опирается форма при открытии, включая необязательные. -## Выборка и выгрузка из результата запроса +### Выборка и выгрузка из результата запроса При типизации выборки/выгрузки из результата запроса следует использовать возможности: @@ -1105,7 +1597,7 @@ ... ``` -## Передача пользовательского объекта данных в другой модуль +### Передача пользовательского объекта данных в другой модуль Объекты данных созданные пользовательским кодом и использованные вне текущего модуля - должны быть описаны функцией возвращающей значение. @@ -1113,7 +1605,7 @@ 1. Экспортная функция, которая возвращает это значение вместе с данными (функция-получатель) - в ней нужно в возвращаемом значении указать функцию-конструктор 2. Реализация какого-либо интерфейса из переопределяемого модуля - в этом случае, можно использовать ссылку на параметр -## Описание типов макетов СКД и Табличного документа +### Описание типов макетов СКД и Табличного документа - В случае получения макета через универсальную процедуру - следует указывать в строке тип макета. @@ -1121,14 +1613,14 @@ Макет = УправлениеПечатью.МакетПечатнойФормы("Документ.РеализацияТоваровУслуг.ПечатнаяФорма"); //см. Документ.РеализацияТоваровУслуг.Макет.ПечатнаяФорма ``` -## Ограничение на создание пользовательских объектов-копий (Структуры, ТЗ) из платформенных объектов +### Ограничение на создание пользовательских объектов-копий (Структуры, ТЗ) из платформенных объектов - Существуют процедуры которые создают ТЗ или структуру аналогичную какому-нибудь объект метаданных, далее выполняется копирование значений для каждого свойства - Не рекомендуется, т.к. Необходимо будет описать весь объект самостоятельно - В исключительных случаях (каких?) можно сделать функцию-конструктор описывающую смешанный тип `Структура + СправочникОбъект.Номенклатура` чтобы не описывать весь тип. При этом можно добавить в описание дополнительные колонки, которые вводятся для технических целей (помощь при копировании, передача дополнительной информации с объектом). - Следует учитывать ограничение на описание строк ТЧ объектов метаданных. -## Ограничения составных типов +### Ограничения составных типов - В общем случае неправильно делать составные типы, которые мало похожи между собой. Например: - Строка и СправочникОбъект From 064d8baf1c762a8e943fd6cb9d94f61ed4b14fe4 Mon Sep 17 00:00:00 2001 From: Dmitry Sherstobitov Date: Sat, 12 Feb 2022 18:49:17 +0300 Subject: [PATCH 2/3] Update code_typification.md --- docs/checks/code_typification.md | 85 ++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/docs/checks/code_typification.md b/docs/checks/code_typification.md index e516de46..9617b504 100644 --- a/docs/checks/code_typification.md +++ b/docs/checks/code_typification.md @@ -64,23 +64,25 @@ Если Параметры.МоеСвойство > 0 Тогда // В этом месте тип МоеСвойство - Неопределено КонецЕсли; ... -Параметры.Вставить("ДругоеСтвойство", Ложь); // Свойство инициализируется с начальным значением +Параметры.Вставить("ДругоеСвойство", Ложь); // Свойство инициализируется с начальным значением -Параметры.ДругоеСтвойство = 1; // Смена типа не происходит +Параметры.ДругоеСвойство = 1; // Смена типа не происходит ... -Если Параметры.ДругоеСтвойство Тогда // В этом месте тип свойства - Булево +Если Параметры.ДругоеСвойство Тогда // В этом месте тип свойства - Булево КонецЕсли; ... -Если ТипЗнч(Параметры.ДругоеСтвойство) = Тип("Число") Тогда - Параметры.ДругоеСтвойство = Параметры.ДругоеСтвойство + 1; // В этом месте тип свойства - Булево +Если ТипЗнч(Параметры.ДругоеСвойство) = Тип("Число") Тогда + Параметры.ДругоеСвойство = Параметры.ДругоеСвойство + 1; // В этом месте тип свойства - Булево КонецЕсли; ``` При фактической смене типа значения у свойства объекта, который допускает такое поведение в run-time `1С:Предприятия 8`, система типизации и анализа объектов данных в 1C:EDT не учитывает эту смену. -В этом случае, правильным подходом является: указание начального типизированного значения, и не допускать сменя типа значения далее в коде. +В этом случае, правильным подходом является: указание начального типизированного значения, и не допускать изменения типа значения далее в коде. Т.е., фактически - есть два варианта у переменных: +1. Тип определен пользователем явно, и дальше он меняться не будет, а попытку изменения - можно будет отслеживать. +2. Если тип неопределен явно, то он ВСЕГДА будет неопределен и далее, и плагин будет во всех местах его считать именно неопределенным. Фактически - данный подход запрещает использовать конструкцию ```Перем``` без явного указания типа в комментарии. ### Декларативная типизация @@ -98,6 +100,7 @@ 2. При этом, если помощник ввода не подсказывает нужные свойства - следует сначала уточнить типы (исправить типы) для текущего объекта и продолжить набор текста по известным свойствам. 3. Использование типизации кода снижает потребность написания кода в режиме отладки с целью определения типов переменных, т.к. типы переменных подсказывает среда разработки. 4. Для проверки, того, что объект имеет статический или динамический тип - необходимо выделить нужный объект и нажать `F2` для отображения описания объекта - перед именем объекта должен отображаться его тип. +5. ВАЖНО! Типизирующие комментарии не могут переопределять типы, которые рассчитала EDT, а могут только их дополнять. Это значит, что если вы укажите в комментарии к функции что вы ожидаете на вход тип `ПолеВвода`, а в контекстной подсказке у вас показываются методы других типов, то это значит, что EDT нашла места вызова этой функции, в которых передается другой тип. И это убрать или переопределить типы - нельзя. > **Внимание!** Контекстный помощник ввода работает при наборе документирующих комментариев. @@ -178,6 +181,10 @@ - "Строгая типизация" не добавляет никаких функциональных возможностей в язык `1С:Предприятия 8` - Не добавляются "Интерфейсы" в язык `1С:Предприятия 8` +Если подвести итог: +- EDT сама старается рассчитывать типы, и если она смогла их рассчитать - изменить это вы уже не можете +- Если EDT что-то не смогла рассчитать, то, при помощи комментария в коде вы можете РАСШИРИТЬ или ОПРЕДЕЛИТЬ тип. Вы не можете через комментарии типизации изменить тип, или полностью его переопределить. +- Если некое свойство присутствует ХОТЯБЫ у одного типа, то даже если EDT рассчитает все типы кореектно - ошибки в этом месте не будет, например, EDT рассчитата что переменная может быть `Число|Массив`, то если вы напишите `Переменная.Количество()` - EDT не выдаст никакой ошибки, так как этот метод есть хотябы у одного найденого типа. #### Включение строгой типизации @@ -223,15 +230,15 @@ Функция ФункцияРазличныхТипов(Флаг) Если Флаг Тогда - Вовзрат ""; + Вовзрат Новый Массив; Иначе Вовзрат 10; КонецЕсли; КонецФункции ``` -В данном примере, у переменной `МояПеременная` будет 2 расчетный и один декларативный тип: `Строка, Число, Булево`. - +В данном примере - EDT сама рассчитает 2 типа - `Массив|Число`, и, при помощи коментария - мы расширим тип переменной `МояПеременная` до третьего типа - `Булево`. +Теперь - EDT позволит вам выполнять любые действия над этой перменной, если это действие можно выполнить хотябы над одним типом (рассчитанным EDT, или добавленным вами через типизирующий комментарий). ### Сокращение типа локальной переменной или параметра - Можно безопасно сократить (или фактически установить для статического анализатора) тип локальной переменной метода, входящего параметра или переменной модуля (объекта, формы) метода через проверку типа: @@ -244,6 +251,52 @@ при этом внутри условия переменная будет указанного в проверке типа, как в рантайме, так и для статического анализатора. Условие проверки должно быть простым. +Если есть задача переопределения типа, то тогда это надо делать явно. Переопределить типы через комментарии - не возможно! Где и когда это может быть полезно - например, есть некая функция, куда вы передаете объект документа, и внутри этой функции рассчитываются какие-то данные по реквизитам этого объекта, и там же идет вызов неких функций из этого объекта: +```bsl +// @strict-types +// Тут я где то по коду вызываю функцию, которая ниже. +Ответ = МакетПечати(Документы.Заказ.СоздатьДокумент()); + +// Тест. +// +// Параметры: +// Док - ДокументОбъект.Заказ - Это строка +// +// Возвращаемое значение: +// ТабличныйДокумент - Тест +&НаСервереБезКонтекста +Функция МакетПечати (Док) + Док.Автор = Справочники.Пользователи.ПустаяСсылка(); + Макет = Док.ВернутьМакет(); + Возврат Макет; +КонецФункции +``` +Все отработает корректно, никаких проблем не будет. НО! Как только в коде появится еще и вот такая строка: +```bsl +Ответ = МакетПечати(Документы.РасходТовара.СоздатьДокумент()); +``` +Тогда тогда, переменная `Док` будет уже иметь два расчетных типа. И самое важно - нигде в этом коде ошибок не будет. При этом - у документа `РасходТовара` нет реквизита `Автор` и нет функции в модуле объекта `ВернутьМакет`. При этом - никаких ошибок нигде не будет! Но что делать, если есть цель таки выяснить - будут ли проблемы при передачи нового типа в функцию? Да, возможность есть, если переписать код вот так: + +```bsl +Функция МакетПечати (Док) + // ТАК БЫЛО. Тут не будет никаких ошибок + Док.Автор = Справочники.Пользователи.ПустаяСсылка(); + Макет = Док.ВернутьМакет(); + + // ТАК СТАЛО. + Если ТипЗнч(Док) = Тип("ДокументОбъект.Заказ") Тогда + // Тут ошибок не будет, так как у заказа есть все функции и реквизиты + Док.Автор = Справочники.Пользователи.ПустаяСсылка(); + Макет = Док.ВернутьМакет(); + Если ТипЗнч(Док) = Тип("ДокументОбъект.РасходТовара") Тогда + // А вот тут уже будет ошибка, так как Док будет иметь только один тип, и у этого типа - нет реквизита и функции + Док.Автор = Справочники.Пользователи.ПустаяСсылка(); + Макет = Док.ВернутьМакет(); + КонецЕсли; + + Возврат Макет; +КонецФункции +``` ## Возможности типизирующих документирующих комментариев @@ -333,7 +386,7 @@ ReturnSection: # Секция описания возвращаемого з Процедура ОбработкаОбъекта(Объект) ``` -В секции параметры, после ключевого слова - обязательно идет двоеточие +В секции параметры, после ключевого слова `Параметры` - обязательно идет двоеточие ```bsl // Описание метода @@ -371,7 +424,7 @@ ReturnSection: # Секция описания возвращаемого з Процедура ОбработкаОбъекта(Объект) ``` -Возможно указание описания для каждого типа поля/параметра, когда каждый тип записан с новой строки, через дефис-минус. Не допускается использование различных видов "тире" (длинных, коротых, средних и т.д.) +Возможно указание описания для каждого типа поля/параметра, когда каждый тип записан с новой строки, через дефис-минус. Не допускается использование различных видов "тире" (длинных, коротких, средних и т.д.) ```bsl // Параметры: @@ -449,7 +502,7 @@ ReturnSection: # Секция описания возвращаемого з Функция ОбработкаОбъекта(Объект) ``` -Декларацию списока типов возвращаемого значения нужно записывать явно с дефисом в конце или с но +Декларацию списка типов возвращаемого значения нужно записывать явно с дефисом в конце или с новой строки ```bsl // Возвращаемое значение: @@ -474,7 +527,7 @@ ReturnSection: # Секция описания возвращаемого з Процедура ОбработкаОбъекта(Объект) ``` -Ссылка на тип не кобминируется с описанием для текущего элемента, должны быть записаны вместо типа +Ссылка на тип не комбинируется с описанием для текущего элемента, должны быть записаны вместо типа ```bsl // Параметры: @@ -492,7 +545,7 @@ ReturnSection: # Секция описания возвращаемого з Функция ОбработкаОбъекта(Объект) ``` -В возвращаемом значении функции можно указывать ссылки на локальные не экспортные функции конструткоры объектов данных, если функция должна возвращать заполненный объект, но модуль не должен позволять через API создавать новый пустой объект данных +В возвращаемом значении функции можно указывать ссылки на локальные не экспортные функции конструкторы объектов данных, если функция должна возвращать заполненный объект, но модуль не должен позволять через API создавать новый пустой объект данных ```bsl // Экспорт из модуля типа объекта в функции, создающем объект и заполняющем значения, @@ -595,7 +648,7 @@ ReturnSection: # Секция описания возвращаемого з ##### Ссылка на Текущие данные динамического списка формы Использование ссылки на тип текущих данных динамического списка на форме не поддерживается в документирующих комментариях. -В место этого следует передавать сам элемент формы и далее обрабатывать `ТекущиеДанные` +Вместо этого следует передавать сам элемент формы и далее обрабатывать `ТекущиеДанные` ПРАВИЛЬНО: @@ -622,7 +675,7 @@ ReturnSection: # Секция описания возвращаемого з #### Ссылка на типы объектов кода -В ссылка типизирующих комментариев можно пере-использовать описанные типы из возвращаемого значения функций или входящих параметров метода. +В ссылка типизирующих комментариев можно переиспользовать описанные типы из возвращаемого значения функций или входящих параметров метода. ##### Ссылка на тип параметра метода в модели менеджера, объекта, общем модуле From 1e968b42e2eac020a8bd106cb7174a05076d55a2 Mon Sep 17 00:00:00 2001 From: Dmitriy Marmyshev Date: Mon, 14 Feb 2022 15:57:49 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=20=D1=82=D0=B8=D0=BF=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/checks/code_typification.md | 94 ++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/docs/checks/code_typification.md b/docs/checks/code_typification.md index 9617b504..d2d17eaa 100644 --- a/docs/checks/code_typification.md +++ b/docs/checks/code_typification.md @@ -19,7 +19,7 @@ При изучении возможностей типизации следует учитывать, что: -1. Язык исполнения 1С:Предприятия 8 (run-time) является/остается динамически-типизируемым +1. Язык исполнения 1С:Предприятия 8 является/остается динамически-типизируемым 2. Все возможности вычисления типизации - это базовые возможности ядра 1C:EDT 3. Плагин `1С:Стандарты разработки V8` добавляет только контроль типов в 1C:EDT и проблемных ситуаций на основе базовых возможностей 1C:EDT @@ -100,7 +100,7 @@ 2. При этом, если помощник ввода не подсказывает нужные свойства - следует сначала уточнить типы (исправить типы) для текущего объекта и продолжить набор текста по известным свойствам. 3. Использование типизации кода снижает потребность написания кода в режиме отладки с целью определения типов переменных, т.к. типы переменных подсказывает среда разработки. 4. Для проверки, того, что объект имеет статический или динамический тип - необходимо выделить нужный объект и нажать `F2` для отображения описания объекта - перед именем объекта должен отображаться его тип. -5. ВАЖНО! Типизирующие комментарии не могут переопределять типы, которые рассчитала EDT, а могут только их дополнять. Это значит, что если вы укажите в комментарии к функции что вы ожидаете на вход тип `ПолеВвода`, а в контекстной подсказке у вас показываются методы других типов, то это значит, что EDT нашла места вызова этой функции, в которых передается другой тип. И это убрать или переопределить типы - нельзя. +5. **Важно!** Типизирующие комментарии не могут переопределять типы, которые рассчитала EDT, а могут только их дополнять. Это значит, что если вы укажите в комментарии к функции что вы ожидаете на вход тип, например `ПолеВвода`, а в контекстной подсказке у вас показываются методы других типов, например, `ГруппаФормы`, то это значит, что EDT нашла места вызова этой функции, в которых передается другой тип. И это убрать или переопределить типы - нельзя на текущий момент. > **Внимание!** Контекстный помощник ввода работает при наборе документирующих комментариев. @@ -181,18 +181,14 @@ - "Строгая типизация" не добавляет никаких функциональных возможностей в язык `1С:Предприятия 8` - Не добавляются "Интерфейсы" в язык `1С:Предприятия 8` -Если подвести итог: -- EDT сама старается рассчитывать типы, и если она смогла их рассчитать - изменить это вы уже не можете -- Если EDT что-то не смогла рассчитать, то, при помощи комментария в коде вы можете РАСШИРИТЬ или ОПРЕДЕЛИТЬ тип. Вы не можете через комментарии типизации изменить тип, или полностью его переопределить. -- Если некое свойство присутствует ХОТЯБЫ у одного типа, то даже если EDT рассчитает все типы кореектно - ошибки в этом месте не будет, например, EDT рассчитата что переменная может быть `Число|Массив`, то если вы напишите `Переменная.Количество()` - EDT не выдаст никакой ошибки, так как этот метод есть хотябы у одного найденого типа. - #### Включение строгой типизации При использовании дополнительного расширения "1С:Стандарты разработки" для 1С:EDT рекомендуется для модуля включить строгую типизацию, которая будет контролировать, что все типы были созданы правильно, во всех местах используется жесткие ссылки на объекты-создатели, что нет смены типа у переменной. Контроль типизации будет выполняться для всего модуля, включая не экспортные методы. Контролируется наличие типов всех переменных, используемых вызовов общих модулей, при обращении к полям/свойствам объектов контролируется их наличие и их типы. +Это означает, что для не экспортых методов необходимо писать типизирующие документирующие комментарии для входящих параметров и типы возвращемых значений функций, если код написан не прозрачно для анализа системы типизации 1C:EDT. Написание текстов описаний методов и параметров для других разработчиков - не является обязтельным в контексте типизации кода. -Для этого необходимо в заголовке модуля указать аннотацию до первого семантического объекта (области, процедуры, переменной): +Для включения строгой типизации, необходимо в заголовке модуля указать аннотацию до первого семантического объекта (области, процедуры, переменной): ```bsl //@strict-types @@ -239,6 +235,7 @@ В данном примере - EDT сама рассчитает 2 типа - `Массив|Число`, и, при помощи коментария - мы расширим тип переменной `МояПеременная` до третьего типа - `Булево`. Теперь - EDT позволит вам выполнять любые действия над этой перменной, если это действие можно выполнить хотябы над одним типом (рассчитанным EDT, или добавленным вами через типизирующий комментарий). + ### Сокращение типа локальной переменной или параметра - Можно безопасно сократить (или фактически установить для статического анализатора) тип локальной переменной метода, входящего параметра или переменной модуля (объекта, формы) метода через проверку типа: @@ -251,45 +248,63 @@ при этом внутри условия переменная будет указанного в проверке типа, как в рантайме, так и для статического анализатора. Условие проверки должно быть простым. -Если есть задача переопределения типа, то тогда это надо делать явно. Переопределить типы через комментарии - не возможно! Где и когда это может быть полезно - например, есть некая функция, куда вы передаете объект документа, и внутри этой функции рассчитываются какие-то данные по реквизитам этого объекта, и там же идет вызов неких функций из этого объекта: +Для задачи переопределения расчетных типов на основе кода, которые считает система 1C:EDT, необходимо указать в документирующих комментариях тип входящего параметра. + ```bsl // @strict-types -// Тут я где то по коду вызываю функцию, которая ниже. -Ответ = МакетПечати(Документы.Заказ.СоздатьДокумент()); -// Тест. -// +... +// Где-то в коде вызыв функции, которая ниже +Ответ = МакетПечати(Документы.Заказ.СоздатьДокумент()); +... + // Параметры: // Док - ДокументОбъект.Заказ - Это строка // // Возвращаемое значение: // ТабличныйДокумент - Тест &НаСервереБезКонтекста +Функция МакетПечати (Док) + Док.Автор = Справочники.Пользователи.ПустаяСсылка(); + Макет = Док.ВернутьМакет(); + Возврат Макет; +КонецФункции +``` + +Следует учитыать, что для метода система типизации 1C:EDT собирает все локальные вызовы в текущем модуле и анализирует типы передаваемые в вызов - внутри метода тип параметра будет расчетный, но при вызове локальной метода система строгой типизации будет отображать ошибку несоответствия типов: + +```bsl +... +// Здесь ошибка на несоотвествие типов +Ответ = МакетПечати(Документы.РасходТовара.СоздатьДокумент()); +... +``` + +В этом случае, переменная `Док` будет уже иметь два расчетных типа. Например, если у документа `РасходТовара` нет реквизита `Автор` и нет функции в модуле объекта `ВернутьМакет`, то в теле метода никаких ошибок. + +Если есть цель выяснить - будут ли проблемы при передачи нового типа в функцию, необходимо код писать безопасно, с проверкой типа параметра: + +БЫЛО: + +```bsl Функция МакетПечати (Док) Док.Автор = Справочники.Пользователи.ПустаяСсылка(); Макет = Док.ВернутьМакет(); Возврат Макет; КонецФункции ``` -Все отработает корректно, никаких проблем не будет. НО! Как только в коде появится еще и вот такая строка: -```bsl -Ответ = МакетПечати(Документы.РасходТовара.СоздатьДокумент()); -``` -Тогда тогда, переменная `Док` будет уже иметь два расчетных типа. И самое важно - нигде в этом коде ошибок не будет. При этом - у документа `РасходТовара` нет реквизита `Автор` и нет функции в модуле объекта `ВернутьМакет`. При этом - никаких ошибок нигде не будет! Но что делать, если есть цель таки выяснить - будут ли проблемы при передачи нового типа в функцию? Да, возможность есть, если переписать код вот так: + +СТАЛО: ```bsl Функция МакетПечати (Док) - // ТАК БЫЛО. Тут не будет никаких ошибок - Док.Автор = Справочники.Пользователи.ПустаяСсылка(); - Макет = Док.ВернутьМакет(); - - // ТАК СТАЛО. Если ТипЗнч(Док) = Тип("ДокументОбъект.Заказ") Тогда // Тут ошибок не будет, так как у заказа есть все функции и реквизиты Док.Автор = Справочники.Пользователи.ПустаяСсылка(); Макет = Док.ВернутьМакет(); Если ТипЗнч(Док) = Тип("ДокументОбъект.РасходТовара") Тогда - // А вот тут уже будет ошибка, так как Док будет иметь только один тип, и у этого типа - нет реквизита и функции + // В этой ветке следует определить другой алгоримт, + // так как Док будет иметь тип - где нет реквизита и функции: Док.Автор = Справочники.Пользователи.ПустаяСсылка(); Макет = Док.ВернутьМакет(); КонецЕсли; @@ -611,6 +626,37 @@ ReturnSection: # Секция описания возвращаемого з Процедура ОбработкаОбъекта(РеквизитТЧ) ``` +##### Ссылка на объект из пакета XDTO + + +```bsl +// Parameters: +// Объект - См. XDTOПакет.КонтактнаяИнформация.Адрес +Процедура ОбработкаОбъекта(Объект) +``` + +Явное использование типов объектов XDTO в коде при указании пространства имен и имени типа в строковом литерале: + +```bsl +ТипАдрес = ФабрикаXDTO.Тип("http://www.sample-package.org", "Адрес"); +Адрес = ФабрикаXDTO.Создать(ТипАдрес); +Адрес.Улица = "..."; +``` + +Иногда необходимо добавить сложную логику при создании объетов на основе фабрики: + +```bsl +// Зарашиваем имя пакета в зависимости от версии +ПространсвтоИмен = ПлучитьПространствоИмен(ВерсияПакета); + +// В этом месте реальный тип не вычисляется, т.к. точное имя пакета XDTO не известно +ТипАдрес = ФабрикаXDTO.Тип(ПространсвтоИмен, "Адрес"); + +// Указываем тип переменной со ссылкой на тип из конкретного пакета +Адрес = ФабрикаXDTO.Создать(ТипАдрес); // См. XDTOПакет.КонтактнаяИнформация.Адрес +Адрес.Улица = "..."; +``` + ##### Ссылка на Форму Ссылка на форму указывается по полному имени формы