Руководство по Ревью Кода Scala

Содержание

Руководство по Ревью Кода Scala#

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

Метаописания и Структура Классов#

Именование классов#

Имя класса должно быть уникальным, на латинице в формате <Модуль>_<Имя> (единственное число, именительный падеж, например, Lbr_Book). Имена сущностей регистрозависимы и должны точно совпадать с ожиданиями фреймворка (CamelCase).

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

Именование атрибутов#

Атрибуты должны иметь осознанные имена, без транслита, соответствующие содержанию поля (camelCase).

Цель: Улучшить читаемость и документировать структуру данных, соответствовать стилю Scala и GSF.

Типы атрибутов#

Для каждого поля должно быть указано имя, тип данных и связь. Простые поля используют типы NLong, NNumber, NString, NDate и т.д.; ссылочные поля – Reference, VariableReference или GID. Проверьте, что все Reference указывают на существующий класс и тип правильный (например, GID для переменной ссылочности). Типы полей должны быть корректно указаны и соответствовать БД (например, NLong, NNumber, NBigDecimal, NString, NGid, NDate и т.п.).

Цель: Обеспечить корректную работу с null-значениями, безопасность типов, интеграцию с фреймворком и согласованность схемы БД и метаданных.

Соответствие БД и метаданных#

Названия и типы полей в метаданных должны совпадать с колонками в БД (NLong > bigint, NString > varchar/text, NDate > date). При джоинах убедитесь в совместимости типов (избегайте неявных преобразований идентификаторов и используйте корректные приведения).

Цель: Обеспечить корректную работу ORM, избежать ошибок типов и обеспечить производительность запросов.

Связи#

Проверить корректность внешних ключей/ссылок, отраженных в метаданных. Использовать GID для переменной ссылочности в одном поле. Убедиться, что все связи отражены в метаданных (поля помечены как Reference или VariableReference).

Цель: Обеспечить целостность данных, корректную навигацию по объектной модели и работоспособность связанных функций GSF.

Хранение и извлечение гибких структур данных#

Если используется динамическое расширение (JSONB), проверьте настройку контейнера (тип Json) и работающую схему ключ–значение. Также проверьте необходимость индексов.

Цель: Обеспечить эффективное хранение и извлечение гибких структур данных, при необходимости — повысить производительность поиска.

Отсутствие дубликатов#

Убедиться, что в метаописаниях нет дублирующих или неиспользуемых полей и неактуальных связей.

Цель: Улучшить читаемость метаданных, упростить поддержку, снизить вероятность логических ошибок и избыточной сложности модели.

project.yaml#

Конфигурация Модулей GSF#

Проверьте секции конфигурации проекта (версии Scala/Java, параметры сборки, список модулей). Например: scalaFeatureRelease, sbtPlugin, modules с описанием каждого модуля – имя, source (репозиторий), branch, флаг isPublish. Убедитесь, что указаны все нужные модули (например, calculation, source, target, custom при наличии) и их настройки верны.

  • Проверьте соответствие шаблонам проекта (src, resources, тесты), что бы зависимости между модулями были описаны явно, циклические зависимости отсутствовали.

  • Проверьте, что конфигурации сборки (например, sbt) и плагины были корректны. Названия модулей и подпроектов соответствуют соглашениям.

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

Структура каталогов#

Поддерживайте корректную структуру каталогов (как сгенерировано Configurator), включая папки src, resources, тесты и пр.

Цель: Облегчить навигацию по коду, упростить настройку IDE и сборочных скриптов, повысить согласованность между проектами.

Зависимости#

Зависимости между модулями должны быть описаны явно в build.sbt, а так же продублированы в module-info.xml как метаданные

Цель: Обеспечить корректную сборку, изоляцию модулей, избежать проблем при сборке и развертывании.

Конфигурации сборки/публикации#

Конфигурации сборки (например, sbt) и плагины должны быть корректны. Названия модулей и подпроектов должны соответствовать соглашениям.

Цель: Обеспечить стабильность и воспроизводимость процесса сборки и публикации, улучшить читаемость и поддержку проекта.

Использование стандартных компонентов GSF#

Использование сервисов GSF#

  • Встроенные сервисы фреймворка:

    • По возможности используйте готовые решения: аудит изменений, автонумерацию, группировку, поиск по шаблону, работу с прикреплёнными файлами и т.д.

    • Для фильтрации классов включайте «Универсальный фильтр» — он позволяет фильтровать по полям класса и его коллекций на уровне БД.

    • Группировка объектов должна реализовываться через механизмы группировки GSF.

  • Кэширование и запросы:

    • Если используется кэширование GSF (Shared-cache), для часто запрашиваемых сущностей настройте cache-index в ORM.

    • При запросах используйте .unique().

    • Применяйте объектные запросы (OQuery) с tryCacheQueryResults() там, где это целесообразно.

    • Обязательно проверьте стратегии инвалидирования кэша.

  • Логирование:

    • Для записи логов используйте LogTransaction.

    • При большом количестве записей применяйте commitByInterval().

Цель: Снизить вероятность ошибок, ускорить разработку, обеспечить единообразие функциональности, упростить поддержку и обновление.

Кэширование и запросы#

Если используется кэширование GSF (Shared-cache), убедитесь, что для часто запрашиваемых сущностей настроены cache-index в ORM и при запросах используется .unique(). Используйте объектные запросы (OQuery) с tryCacheQueryResults() там, где это целесообразно. Проверьте стратегии инвалидирования кэша.

Цель: Повысить производительность за счёт снижения обращений к БД, обеспечить актуальность данных в кэше.

Логирование#

Для записи логов в базу задействуйте встроенный LogTransaction (выделяет отдельную лог-сессию). При большом количестве записей выполняйте commitByInterval() (например, каждые 1000 записей). Такой подход изолирует логи от основной транзакции и снижает нагрузку на БД.

Цель: Изолировать логи от основной транзакции, избежать потери логов при откате, снизить вероятность конфликтов и нагрузку на БД.

Обработка Ошибок и Зависимости#

Прикладные исключения#

В коде обрабатывайте только «прикладные» исключения — наследники AppException. Системные исключения не перехватывайте, а выбрасывайте дальше, пропускайте (так фреймворк сможет корректно прервать сессию).

Цель: Чётко разделить бизнес-логику ошибок и системные сбои, предотвратить скрытие серьёзных проблем и нарушение целостности данных.

Объявление исключений#

Создавайте свои исключения как подклассы AppException и заводите для них фабрику (например, object ExceptionName extends ExceptionFactory(new ExceptionName(_))). Выбрасывайте исключения через throw AppException(…) или e.raise(…) (сохранит стек вызовов). При необходимости логирования ошибки используйте отдельную лог-транзакцию.

Цель: Обеспечить единообразие, упростить обработку, легко идентифицировать тип ошибки, гарантировать запись лога при откате основной транзакции.

Логирование ошибок#

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

Цель: Изолировать запись лога от основного процесса, избежать засорения логов, сохранить ключевую информацию для диагностики, сохранить причину исключения.

Транзакции и зависимые задачи#

Избегайте слишком длинных транзакций (несколько минут и более) – PostgreSQL плохо их переносит. Разбивайте большие операции на логические блоки и выполняйте session.commitWorkAuto() после каждой партии изменений. Например, при массовой загрузке в цикле вызывайте commitWorkAuto() через заданный интервал, чтобы регулярно сбрасывать пакет в БД. При этом используйте flush() / commit() осмотрительно: не делайте неожиданных коммитов внутри server-side методов, чтобы не прерывать ожидания отката.

Цель: Снизить вероятность конфликтов, рост WAL, улучшить общую производительность БД, уменьшить вероятность сбоев, облегчить откат, сохранить согласованность данных.

Требования к Структуре Scala-Кода#

Соглашения по стилю#

Соблюдайте стандарты именования Scala (классы – CamelCase, методы/переменные – camelCase) по руководству Scala. Global3-FrameWork регистрозависим, поэтому имена сущностей (классов, полей, методов) должны точно совпадать с тем, как они объявлены. Не используйте подчёркивания в именах (за исключением разделителя модуля и имени класса).

Цель: Обеспечить корректную работу фреймворка, повысить читаемость кода, облегчить его понимание и поддержку.

D/A-паттерн кода#

При генерации классов учтите, что фреймворк генерирует две иерархии: Domain- и Application-части. Доменные классы (ClassDpi, ClassDvi) перезаписываются при генерации и содержат «скелет» логики, а прикладные классы (ClassApi, ClassAvi) – расширяют их и используются для ручной бизнес-логики. Логика должна писаться только в прикладных классах (Api/Avi), доменные файлы не редактируйте.

Цель: Обеспечить стабильность при регенерации кода, изолировать бизнес-логику от автоматически генерируемого кода.

Null-типы GSF#

Для работы со значениями из БД используйте расширенные типы GSF (NLong, NNumber, NGid, NDate, NString, NBigDecimal и т.д.), которые безопасно обрабатывают null. Например, идентификаторы – NLong (фабрика nl), числовые поля – NNumber или NBigDecimal (фабрика nr). Важное правило: для финансовых расчётов используйте NBigDecimal (BigDecimal), чтобы избежать ошибок двоичной арифметики. При сравнении nullable-значений в скриптах GSF применяйте оператор === (предотвращает NPE) вместо стандартного ==.

Цель: Защитить от NullPointerException, обеспечить корректную обработку null, гарантировать точность вычислений для финансовых данных, обеспечить безопасность при сравнениях.

Общие Принципы и Стиль Кода#

Комментарии#

Код должен сопровождаться понятными комментариями.

Цель: Помочь другим разработчикам понять назначение и логику кода, поддерживать профессиональный стиль документации.

Именование#

Переменным и атрибутам необходимо давать осознанные имена, транслит необходимо избегать. Следуйте scala-конвенциям наименования сущностей.

Цель: Улучшить читаемость, документировать структуру данных, соответствовать стилю Scala и GSF.

Форматирование#

sql и scala код должны быть отформатированы и не превращаться в «кашу».

Цель: Улучшить читаемость, облегчить понимание и сопровождение кода.

Официальная документацию к API#

Писать scaladoc к методам, классам и переменным.

Цель: Предоставить официальную документацию к API, облегчить поддержку и использование кода другими разработчиками.

Безопасность и Надёжность#

Исключить использование null#

Использование null должно быть полностью исключено для всех ссылочных типов.

Цель: Предотвратить NullPointerException, использовать безопасные GSF-типы.

Обработка пустых значений#

Для значимых типов (AnyVal), таких как JObject, запрещено использовать null или его приведение (null.asInstanceOf[JObject]). Вместо этого необходимо использовать пустые экземпляры (например, JObject()), а проверку на наличие данных выполнять через .nonEmpty.

Цель: Предотвратить NullPointerException при работе с такими типами.

Безопасный доступ к данным#

Необходимо избегать использования head или get; вместо них следует использовать headOption или getOption, чтобы избежать NPE.

Цель: Обеспечить безопасную обработку отсутствия значения, сделать код более надёжным.

Обработка всех сценариев#

При ветвлении кода if-else необходимо указывать ветку else; для pattern-matching обязателен случай case _ =>.

Цель: Гарантировать обработку всех возможных сценариев, предотвратить MatchError, сделать код более надёжным.

Производительность#

Оптимизация работы с коллекциями#

При использовании нескольких комбинаторов подряд (например, arr.map.flatMap.filter) необходимо добавлять .view в начало, чтобы не создавались временные коллекции.

Цель: Улучшить производительность за счёт снижения расхода памяти.

Читаемость при обработке данных#

При использовании комбинаторов по карте необходимо применять pattern matching для деструктуризации кортежей.
Плохо: any_map.foreach { tpe => tpe._1 + tpe._2 }.
Хорошо: any_map.foreach { case (key, value) => key + value }.

Цель: Сделать код более выразительным, типобезопасным и читаемым.

Изменяемые коллекции#

В параметрах методов и возвращаемых значениях не должны использоваться изменяемые коллекции collection.mutable.

Цель: Повысить безопасность и предсказуемость кода, уменьшить вероятность ошибок.

Выбор эффективной коллекции#

Необходимо использовать ArrayBuffer вместо ListBuffer.

Цель: Обеспечить лучшую производительность для операций вставки и доступа по индексу.

Выбор коллекции#

При выборе коллекции (List, Array, Vector, ArrayBuffer) необходимо учитывать асимптотическую сложность операций (вставка, доступ по индексу), чтобы обеспечить оптимальную производительность.

Цель: Использовать подходящие структуры данных для ускорения выполнения операций.

Большие реестры#

Получение данных из больших реестров должно выполняться реляционными запросами в БД по максимальному количеству условий с предварительным session.flush(), чтобы не перегружать ОЗУ сервера.

Цель: Снизить нагрузку на память сервера приложений, повысить производительность за счёт фильтрации на уровне БД.

Работа с API и ROP#

HTTP-пакеты#

Прямое обращение к http пакетам запрещено; необходимо использовать btk_httppkg.

Цель: Обеспечить централизованное управление HTTP-вызовами, соблюдение стандартов безопасности и логирования.

Файлы#

При работе с файлами необходимо использовать стандартное api — btk_fileapi.

Цель: Гарантировать корректную обработку файлов, безопасность и совместимость с инфраструктурой.

Оптимизация расхода памяти#

Метод copyAro не должен использоваться, так как все данные провайдера строки копируются в оперативную память.

Цель: Предотвратить чрезмерный расход памяти, особенно при работе с большими объектами или в циклах.

Загрузка ROP по gid#

При загрузке ропов по gid необходимо использовать Btk_Pkg.loadByGid (обёрнутый в TryApp). Полученный rop должен матчиться с нужным API, например: case Btk_ClassApi(rop) =>.

Цель: Обеспечить безопасную загрузку объектов и правильную их типизацию.

Поиск по коду#

Для поиска по коду необходимо использовать методы ____Api().findByMnemoCode(""), а не прямые запросы. Объекты API должны быть объявлены через lazy val.

Цель: Использовать встроенные механизмы GSF, повысить читаемость и поддерживаемость кода.

Надёжность получения данных#

Вместо конструкции api().load(getVar("idAnyClass").asNLong) необходимо использовать метод get, так как нет гарантии, что getVar вернёт значение вместо null.

Цель: Обеспечить более безопасное и надёжное получение данных.

Использование source-generated конструкций#

Для доступа к атрибутам необходимо использовать конструкции, сгенерированные генератором источников (например, rop.get(_.attr)), а не методы getByAttrName и getAttrByName, так как последние используют рефлексию, ошибки которой могут быть обнаружены только во время выполнения.

Цель: Обеспечить безопасность на этапе компиляции, предотвратить ошибки, связанные с рефлексией.

Работа с Базой Данных и SQL (Дополнения)#

Вложенные циклы#

Запросы внутри вложенных циклов использовать нельзя.

Цель: Избежать экспоненциального роста числа запросов к БД, сохранить производительность.

Эффективное обновление кэша#

В onRefresh необходимо использовать refreshByKey(parent) вместо byKey(parent).

Цель: Обновить данные в кэше, повысить эффективность.

Предотвращение конфликтов сессии#

При необходимости использования onRefresh на основе selectStatement в детализации документа необходимо отключать @FlushBefore, чтобы избежать ошибок при создании документа с обязательными атрибутами.

Цель: Предотвратить конфликты сессии и ошибки при инициализации документа.

Архитектура и Дизайн#

Эффективная инициализация полей#

При объявлении переменных в классе необходимо использовать ключевое слово lazy, чтобы они инициализировались только при первом использовании.

Цель: Улучшить производительность, избежать ненужных вычислений.

Читаемость кода установки#

При регистрации типов, закладок, атрибутов, функциональных настроек, процедур в dataInstall необходимо добавлять lazy val с мнемокодами и id для зарегистрированных значений.

Цель: Улучшить читаемость и поддержку кода установки данных.

Изменение параметров#

При редактировании метода типы параметров не должны изменяться, это сохраняет обратную совместимость.

Цель: Критично для стабильности API, предотвратить ошибки в использующем коде.

Новые параметры#

Перед добавлением новых параметров в метод необходимо учитывать обратную совместимость. Новые необязательные параметры необходимо добавлять в конец сигнатуры метода.

Цель: Избежать необходимости изменять весь код, который вызывает этот метод.

Сложная логика в AVI#

Сложную логику не нужно расписывать в операции Avi, если она может быть вынесена в API/PKG. AVI-операция должна сводиться к вызову метода из API/PKG, это упрощает поддержку и минимизирует дублирование кода.

Цель: Улучшить поддерживаемость кода, разделить ответственности, тестировать бизнес-логику отдельно от UI-логики.

Scala-классы с компаньоном#

При создании структур Scala-классов с объектом-компаньоном необходимо использовать решение, позволяющее проектное переопределение: def list(): List = { new List {...} }.

Цель: Обеспечить более гибкую настройку поведения классов на уровне проекта.

Работа с Атрибутами и Полями (Дополнения)#

Source-generated доступ#

Для доступа к атрибутам необходимо использовать конструкции, сгенерированные генератором источников (например, rop.get(_.attr)), а не методы getByAttrName и getAttrByName, так как последние используют рефлексию, ошибки которой могут быть обнаружены только во время выполнения.

Цель: Обеспечить безопасность на этапе компиляции, предотвратить ошибки, связанные с рефлексией.

Безопасность на этапе компиляции#

В выборках при обращении к стандартным атрибутам необходимо использовать getSelfVar(A.idPerson.name) или просто A.idPerson.asNLong вместо getSelfVar("idPerson"), это позволяет поймать ошибки во время компиляции при удалении атрибута.

Цель: Обеспечить безопасность типов на этапе компиляции.

Хранимые поля в AVI#

Хранимые поля класса в AVI должны получаться через объект А, сгенерированный генератором источников, чтобы избежать ошибок времени выполнения при переименовании атрибута в классе.

Цель: Сделать код устойчивым к переименованиям атрибутов.

Корректность обновления данных#

В case class’ах, которые возвращаются в onRefresh, атрибуты должны быть мутабельными (var).

Цель: Обеспечить корректную работу с UI и обновление данных.

Строки и JSON#

Интерполяция строк#

При сборке строк из статических и динамических элементов необходимо использовать интерполяцию s"text${value}otherText" или многострочный вариант: s"""1-st line |2-nd line |.... |last line""".stripMargin. Интерполяция должна использоваться вместо конкатенации, так как она оптимальнее и более читаема.

Цель: Повысить читаемость, обеспечить оптимизацию компилятором.

Читаемость многострочных строк#

Для многострочных строк необходимо использовать | и .stripMargin, чтобы сохранить форматирование и структуру файла.

Цель: Улучшить читаемость многострочных строк в коде.

Эффективная работа со строками#

При сборке очень больших строк необходимо использовать StringBuilder вместо pos.map(s"...").mkString().

Цель: Обеспечить более эффективную работу с большими строками.

Выбор безопасных JSON-типов#

scala.util.parsing.json использовать нельзя, предпочтительнее JObject.

Цель: Использовать интегрированный с GSF и более безопасный тип.

Предотвращение несовместимости#

Использование Btk_JsonPkg необходимо избегать из-за зафиксированного разного поведения при его использовании с JObject.

Цель: Предотвратить неожиданное поведение и ошибки.

Специфика UI: AVI и Списочные Отображения#

Безопасное получение значений в списках#

В Avi.checkWorkAbility и других AVI-операциях списочных отображений значения полей необходимо получать через getVar, getSelfVar или A, а не через thisRop(), чтобы избежать ошибки load id = null в пустом списке.

Цель: Предотвратить ошибки при работе с пустыми списками.

Поля с большим объёмом данных#

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

Цель: Повысить производительность UI и улучшить пользовательский опыт.

Контроль сброса сессии#

В LookUp-отображениях для onRefresh необходимо добавлять аннотацию @FlushBefore(mode = FlushBeforeMode.Disabled).

Цель: Предотвратить нежелательные сбросы сессии при обновлении данных в LookUp.

Корректная деактивация операций#

Вместо oper.isActive = someCondition необходимо использовать DefaultRep#deactivateOper для деактивации операций при невыполнении условий, это обеспечивает корректную работу при различных перекрытиях.

Цель: Использовать встроенный механизм фреймворка для корректной деактивации операций.

Структурирование настроек выборки#

Сортировка по умолчанию и передача макросов фильтрации должны быть указаны в prepareSelectStatement, а не в selectStatement.

Цель: Улучшить структуру и читаемость кода настройки выборки.

Специфика UI: Кэширование, Логика и Настройки#

Переходы состояний#

Переходы состояний должны определяться сравнением nOrder и формированием условия из двух частей (из какого в какое), например: nvStateFrom < 100.nn && nvStateTo >= 100.nn, это обеспечивает работоспособность логики даже при удалении перехода.

Цель: Сделать логику переходов устойчивой к изменениям структуры состояний.

Синхронизация данных с интерфейсом#

Аннотация @Setter(refreshAfter = true) должна выполнять selection.refreshItem() в конце сеттера.

Цель: Обеспечить обновление UI после изменения значения.

Кастомные выборки#

Редактируемые кастомные выборки должны быть реализованы объектным запросом, чтобы собрать пул изменений и отправить их в БД одной транзакцией.

Цель: Повысить эффективность, обеспечить целостность данных.

Идентификатор в результатах выборки#

При реализации кастомных выборок на объектном запросе результат выборки должен содержать поле id для работы onRefreshExt.

Цель: Обеспечить корректную работу механизма обновления расширенных данных.

Предпочтительные способы получения данных#

Использование AdditionalInfo необходимо дважды обдумывать. Предпочтительнее получать данные через onRefreshExt.

Цель: Улучшить структуру и производительность, избегать избыточного кода.

Структура данных при переопределении#

При переопределении отображения, в котором уже используется AdditionalInfo, новые вычисляемые атрибуты не должны добавляться в новый AdditionalInfo2. В OnRefresh необходимо использовать несколько case-классов: thisApi().byParent(getIdMaster).map { rop => (rop, getAdditionalInfo(rop), getAdditionalInfo2(rop)) }.

Цель: Улучшить структуру и читаемость кода обновления данных.

Отражение (Reflection)#

Обоснование#

Использование reflection должно быть оправдано; в общем случае оно запрещено.

Цель: Повысить безопасность типов, производительность, упростить сопровождение кода.

Выбор стабильных библиотек ввода-вывода#

Использовать нельзя, предпочтительнее Java-классы.

Цель: Обеспечить лучшую стабильность и совместимость.

Специфика Модулей и Проектов#

Модуль STK#

Для получения остатков необходимо использовать ru.bitec.app.stk.Stk_Pkg#getRemainsMulti. Для получения цены необходимо использовать ru.bitec.app.stk.Stk_Pkg#getnPrCostConsSum.

Цель: Использовать стандартные, оптимизированные методы для получения данных из модуля STK.

Модуль ACT#

Запрос оборотов должен выполняться с учётом логовой таблицы изменений через union all, чтобы получить полную и актуальную информацию.

Цель: Гарантировать корректность и полноту данных об оборотах.

Проектные модули#

При открытии MR необходимо указывать соответствующую ветку с учётом проекта, на котором разрабатывается. Например, для проекта СНГ разработка ведётся на sng-internal-dev > ветка проектного модуля gs; pdev > dev.

Цель: Обеспечить правильную интеграцию изменений в проектную ветку.

Безопасность и Целостность Данных#

SQL-инъекции#

Все входные данные параметризованы, нет риска SQL-инъекций.

Цель: Защитить от SQL-инъекций, ускорить выполнение за счёт переиспользования планов.

Ограничения целостности#

Ограничения целостности (foreign key, unique) соответствуют метаданным.

Цель: Обеспечить корректность и согласованность данных на уровне БД.

Валидации#

Валидации на уровне приложения дублируют, но не заменяют БД-ограничения.

Цель: Обеспечить дополнительный уровень защиты и пользовательскую обратную связь.

Чувствительные данные#

Чувствительные данные маскируются в логах и не попадают в открытые сообщения об ошибках.

Цель: Защитить конфиденциальную информацию от утечки.

Соответствие Best Practices#

Документация#

Убедитесь, что код и конфигурации соответствуют рекомендациям из официального руководства (например, настройка логирования, работа с транзакциями, параллельные вычисления и т.д.). Всегда проверяйте разделы «Практика разработки» в документации GlobalFramework и сверяйтесь с примерами.

Цель: Повысить качество, поддерживаемость и безопасность кода, облегчить его понимание новыми разработчиками.

Чистота кода#

Код должен быть читабельным и понятным (часто читают больше, чем пишут). Держите методы короткими, избегайте дублирования. Имена должны ясно отражать назначение сущности. Следуйте общим принципам GSF: не используйте служебные символы (например, «!», «?», «@») в идентификаторах, оформляйте документацию и комментарии по необходимости.

Цель: Улучшить читаемость, облегчить понимание и сопровождение кода.

Критические ошибки#

Целостность данных при модификации#

DML (INSERT/UPDATE/DELETE) выполняется через ASQL. — Блокирующее

Цель: Предотвратить нарушение целостности данных из-за автокоммита ASQL.

Долгая транзакция#

Долгая транзакция, захватывающая большое число строк без разбивки. — Блокирующее

Цель: Избежать проблем с производительностью и блокировками БД.

Функции GSF в массовых выборках#

Массовое использование getattribute/getmnemocode/getheadline в больших выборках/отчётах. — Блокирующее

Цель: Избежать чрезмерной нагрузки на БД.

Арифметика с N-типами#

Арифметика с N-типами без проверки nullable (.isNotNull). — Блокирующее

Цель: Предотвратить NullPointerException и ошибки времени выполнения.

Конкатенация строк SQL#

SQL-строки формируются конкатенацией с пользовательскими данными. — Блокирующее

Цель: Предотвратить уязвимость к SQL-инъекциям.

Дублирование логики#

Необъяснимое и несогласованное дублирование логики в разных модулях. — Блокирующее

Цель: Упростить сопровождение, снизить вероятность ошибок, упростить внесение изменений.