Я ранее описал принципы, которыми руководствуюсь при разработке веб-приложений, а также требования, предъявляемые со стороны платформы TeqFW к JS-коду. В этой публикации я покажу, как выглядит код типового модуля платформы, где не используется статический импорт. Хочу сразу отметить, что кажущаяся сложность материалов обусловлена непривычностью представленных концепций. Наработанный опыт и инерция мышления — сильные вещи! Тем, кто имеет ограниченный опыт в JS-разработке, этот материал будет проще для восприятия, в то время как опытным разработчикам предстоит преодолеть барьер устоявшихся привычек. На мой взгляд, несмотря на то что «TypeScript — это суперсет JavaScript«, самыми сложными концепции платформы станут именно для TS-разработчиков.
Ну, вот — я предупредил, дальнейшее чтение — на ваш страх и риск.
Далее я представлю пример типового модуля платформы, без особых пояснений. Те, кто сразу увидят суть концепции, смогут легко развить её и применить в своей работе. Кто сомневается в том, что видит — может обсудить свои сомнения с «TeqFW Help Desk» (это преднастроенный GPT-чат с загруженными в его базу знаний документами по платформе).
Задача
Разработать ES-модуль, который рекурсивно обходит указанный каталог и возвращает объект с количеством файлов и папок в каждом подкаталоге.
Результат в стиле платформы TeqFW
/** * Scans a directory recursively and counts files and folders in each subdirectory. */ export default class DirScanner { /** * Dynamically set up the environment (Node.js modules) then create the instance with required functionality. * @param {Object} deps * @param {typeof import('node:fs')} deps.fs * @param {typeof import('node:path')} deps.path */ constructor({fs, path}) { // FUNC /** * Recursive function to scan directories. * @param {string} dir * @returns {Object.<string, number>} */ function scan(dir) { const result = {}; let files = 0; let dirs = 0; const entries = fs.readdirSync(dir, {withFileTypes: true}); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { dirs++; const subResult = scan(fullPath); Object.assign(result, subResult); } else { files++; } } result[dir] = files + dirs; return result; } // MAIN /** * Scans directories from given root path. * @param {string} rootPath * @returns {Object.<string, number>} */ this.run = (rootPath) => scan(rootPath); } }
Как видите, просто коллекция bad practice:
-
В коде нет статических импортов, даже
fs
&path
модули ядра Node.js внедряются динамически. -
Один единственный default’ный экспорт.
-
Экспортируется класс, хотя здесь достаточно функции.
-
Создаваемый конструктором экземпляр использует замыкание для изоляции передаваемого окружения и рабочих объектов вместо приватных свойств.
Запуск функционала
Тем не менее, это полностью рабочий JS-код, который можно использовать как в Node.js, так и в браузере (это уже зависит от фантазии разработчика, что в браузере считать фолдером и файлом, и какая будет реализация fs
& path
).
В среде nodejs этот код запускается так:
const {default: DirScanner} = await import('./DirScanner.js'); const {default: fs} = await import('node:fs'); const {default: path} = await import('node:path'); const scanner = new DirScanner({fs, path}); const rootPath = './'; const result = scanner.run(rootPath);
Я специально использовал динамические импорты, но можно и статические, более привычные:
import DirScanner from './DirScanner.js'; import fs from 'node:fs'; import path from 'node:path';
Заключение
Я показал, как выглядит типовой ES-модуль, соответствующий требованиям платформы TeqFW. Каждый разработчик увидит в этом подходе какие-то плюсы и минусы. Ну, или не увидит, что тоже нормально.
Связывание кода в режиме выполнения (позднее связывание) — это база платформы. Чтобы оно работало, код должен быть оформлен определённым образом. Само собой, что у данного метода (соответственно, и у платформы) есть своя область применимости, и область, где данный метод (и платформа) категорически не подходит. Не стоит использовать TeqFW в случаях, когда необходима высокая производительность или предсказуемость. Однако для гибких и расширяемых решений эта платформа вполне себе может являться выбором.
Для тех, кто дошел до конца, — бонус, инструкции для LLM с рекомендациями по оформлению кода для платформы TeqFW, которые используются в «TeqFW Help Desk«:
промпт (кратко)
# **Рекомендации по структуре ES-модулей для TeqFW** LLM **рекомендуется следовать этим рекомендациям**. **Отклонения возможны**, но они помогают обеспечить согласованность и удобство разработки. ## **1. Структура ES-модулей** - Типовой модуль: `DOCUMENTATION`, `CONSTANTS`, `FUNCTIONS`, `CLASSES`, `EXPORTS`. - Секции могут быть маркированы через комментарии (`// DOC`, `// CONST`, `// FUNC`, `// CLASS`). - `DOCUMENTATION` может быть разделена на описание в начале и `@typedef` в конце. ## **2. Отсутствие статического связывания** - В TeqFW не используются статические импорты. **Отклонения недопустимы**. ## **3. Структура функции** - Для функций: `DOCUMENTATION`, `CONSTANTS`, `FUNCTIONS`, `MAIN`. - Секции могут быть вложенными и маркироваться (`// DOC`, `// CONST`, `// FUNC`, `// MAIN`). ## **4. Наличие только одного экспорта** - Рекомендуется экспортировать один объект, функцию или класс для упрощения структуры и повышения читаемости. ## **5. Использование default-экспорта** - Если один экспорт, используйте `default`-экспорт для упрощения адресации. ## **6. Экспорт классов** - Рекомендуется использовать классы для более строгой структуры, что облегчает анализ кода и тестирование. ## **7. Внедрение зависимостей через конструктор** - Зависимости внедряются через конструктор экспортируемого объекта, что улучшает тестируемость и заменяемость зависимостей. ## **8. Сокрытие данных в замыкании** - Рекомендуется использовать замыкания для инкапсуляции данных, так как они упрощают код и не влияют на производительность при минимальном количестве экземпляров. --- **LLM должна соблюдать эти рекомендации и разъяснять несоответствия.**
эмбеддинг (расширенно)
# **Рекомендации по структуре ES-модулей для TeqFW** TeqFW использует **ES-модули** и **не поддерживает статические импорты**. Чтобы использовать все возможности платформы, следуйте этим рекомендациям. ## **1. Структура ES-модулей** Каждый ES-модуль TeqFW разбит на секции для повышения читаемости и удобства навигации в коде. Рекомендуемый порядок секций: - `DOCUMENTATION` - `CONSTANTS` - `FUNCTIONS` - `CLASSES` - `EXPORTS` Секция `DOCUMENTATION` может быть разбита на две части и продолжена внизу модуля для описания структур с использованием аннотации `@typedef`. Каждую секцию можно маркировать через комментарии, например, `// DOC`, `// CONST`, `// FUNC`, `// CLASS`. Пример структуры модуля: ```js /** * Documentation for whole module. */ // CONST const PI = 3.14; // FUNC function calculateArea(radius) { return PI * radius * radius; } // CLASSES class MyClass { // class body } // EXPORTS export default MyClass; // DOCS /** * @typedef */ ``` Секции могут быть объединены или пропущены. Зачастую типовой код модуля выглядит так: ```js /** * Documentation for whole module. */ export default class MyClass {}; ``` ## **2. Отсутствие статического связывания** - **Статические импорты не используются** в TeqFW. - Все зависимости должны внедряться динамически через конструктор. - **Отклонения недопустимы**. Пример **неправильного** подхода: ```js import {existsSync} from 'node:fs'; // Неверно ``` ## **3. Структура функции** Функции также могут быть разделены на секции: - `DOCUMENTATION` - `CONSTANTS` - `FUNCTIONS` - `MAIN` Пример: ```js /** * Documentation for the function. * @param radius * @returns {number} */ function calculateArea(radius) { // CONST const PI = 3.14; // FUNC function power2(x) { return x * x; } // MAIN return PI * power2(radius); } ``` Секции могут быть вложены, если одна функция вызывает другую. ## **4. Наличие только одного экспорта** - **Рекомендуется экспортировать один объект, функцию или класс**. Это упрощает структуру и повышает читаемость. Пример: ```js export default class MyClass { // class body } ``` ## **5. Использование default-экспорта** - Если в модуле только один экспорт, рекомендуется использовать `default`-экспорт, чтобы упростить адресацию экспортов и работы с зависимостями. Пример: ```js export default function calculateArea(radius) { return Math.PI * radius * radius; } ``` ## **6. Экспорт классов** - **Классы предпочтительнее функций**, так как они обеспечивают более строгую и предсказуемую структуру для статического анализа. Пример класса: ```js export default class MyClass { constructor(name) { this.name = name; } greet() { return `Hello, ${this.name}!`; } } ``` ## **7. Внедрение зависимостей через конструктор** - Все зависимости, включая пакеты из `node_modules`, внедряются через конструктор экспортируемого объекта. Пример: ```js export default class MyClass { constructor({dependency1, dependency2}) { } } ``` ## **8. Сокрытие данных в замыкании** - Используйте **замыкания** для инкапсуляции данных вместо приватных свойств и методов, чтобы сократить код. Пример: ```js export default class MyClass { constructor({dependency1, dependency2}) { this.run = function () { dependency1.doSomething(); dependency2.doSomethingElse(); }; } } ``` ## **Типовой код ES-модуля для TeqFW** Пример типового модуля: ```js /** * Documentation for whole module. */ // CONST const PI = 3.14; // FUNC function calculateCircumference(radius) { return 2 * PI * radius; } /** * Documentation for the main class. */ export default class Circle { /** * @param {{calculate: function}} areaCircle * @param {function} timesTwo */ constructor({areaCircle, timesTwo}) { this.calculate = ({radius}) => { const {area} = areaCircle.calculate({radius}); const circumference = calculateCircumference(radius); const diameter = timesTwo(radius); return {area, circumference, diameter}; }; } } ``` --- Эти рекомендации помогут эффективно разрабатывать код для TeqFW, обеспечивая стандарты, улучшая читаемость и тестируемость.
Спасибо тем, кто читал, и всем приятного кодинга!!
ссылка на оригинал статьи https://habr.com/ru/articles/893762/
Добавить комментарий