Pull to refresh

Comments 17

Чёткие контракты взаимодействия. Разделение интерфейсов и реализаций снижает влияние изменений, сохраняя предсказуемость системы.

Маленький вопросик: о каких контрактах и интерфейсах идет речь, если у нас чистый ES6?

В целом, для меня, как кожаного мешка, статья выглядит полным буллшитом :) Потому что на практике отсутствие контроля типов со стороны языка в больших системах придется компенсировать разными, так сказать, ухищрениями. С которыми жизнь сильно не похожа на сказку из статьи.

Интерфейс, по факту, это документирование контракта: имена функций и описание входных-выходных аргументов. Вот пример описания интерфейса в ES6:

/**
 * Interface for user management in the application.
 *
 * This is a documentation-only interface (not executable).
 *
 * @interface
 */
export default class Fl64_OAuth2_Social_Back_Api_App_UserManager {
    /**
     * Creates a new user in the application's database.
     * @param {Object} params
     * @param {TeqFw_Db_Back_RDb_ITrans} [params.trx] - The transaction context.
     * @param {string} params.identity - Unique identifier assigned to the user by the provider.
     * @param {Object} [params.extras] - Additional user attributes (e.g., name, avatar).
     * @returns {Promise<{id: number}>} - The unique identifier of the created user.
     */
    async createUser({trx, identity, extras}) {}
}

И его имплементации:

/**
 * Implementation of the user management interface for the application.
 *
 * @implements Fl64_OAuth2_Social_Back_Api_App_UserManager
 */
export default class Svelters_Back_Di_Replace_Social_UserManager {
    /**
     * @param {Svelters_Back_Act_User_Create} actCreate
     */
    constructor(
        {
            Svelters_Back_Act_User_Create$: actCreate,
        }
    ) {

        /**
         * Creates a new user in the application's database.
         * @param {Object} params
         * @param {TeqFw_Db_Back_RDb_ITrans} [params.trx] - The transaction context.
         * @returns {Promise<{id: number|null}>} - The unique identifier of the created user.
         */
        this.createUser = async function ({trx: trxOuter}) {
            const {user} = await actCreate.run({trx: trxOuter});
            const id = user?.id;
            return {id};
        };

    }
}

Этот код работает прямо сейчас в одном из приложений.

Насчёт контроля типов со стороны языка вы абсолютно правы. Прежде чем писать без типов на JS нужно научится писать с типами, на той же Java. Я кодил с типами больше 10 лет. Мне уже можно без типов.

"Сказка в статье" - это построение когнитивного контекста для людей и LLM. Люди могут выбирать принимать этот контекст или нет. У LLM такого выбора нет :)

Каким образом вы контролируете отсутствие расхождений между кодом и документацией?

Если нет тотального описания типов, то даже очень умная IDE не сможет гарантировать, что каждая функция выполняет тот контракт, который описан в документации к этой функции. И таким образом (теоретически) автокомплит может начать вводить в заблуждение. Но это в теории. На практике этот эффект может проявиться сильно не сразу, в зависимости от размера проекта, самодисциплины его участников и т.п. Сталкивались ли Вы с тем, что анализатор IDE не справляется или ошибается? Если сталкивались, какие есть приемы борьбы? Если Вы делали большие системы в коллективе и не сталкивались с нарушениями контрактов, которые проглядела IDE - то я чего-то не понимаю, и могу только попросить высказать Вашу точку зрения, за счет чего Вам это удалось.

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

UPD. Для меня большие системы в данном контексте: когда общее число задокументированных контрактов начинается от 10 тысяч.

А Вы можете привести пример ЯП, который даёт такую гарантию на 10К контрактов? Причём не для теоретического "коня в вакууме", а для реального приложения со вводом-выводом, сетевым взаимодействием и пользовательскими данными? С учётом, что для веб-приложений это гарантия консистентности всего стека - от поля в форме на странице и до колонки в таблице в БД?

Нет, предлагаемый мной подход не даёт никому никаких гарантий. Пробуйте, если хотите, на свой страх и риск. Я долгое время имел дело с платформой Magento (порядка 4М SLOC во второй версии, и это без огромного количества плагинов к ней). Она никому ничего не гарантировала, но при этом как-то работала. На популярных use-case'ах - очень хорошо, на экзотических - очень плохо. Зачастую, после обновлений, приходилось брать в руки "напильник" (отладчик) и находить и править баги (не все, а только те, которые мешали жить пользователям). Я это называю "Magento way". В том числе и поэтому у меня любовь к "неизменённому коду" - приходилось отказывать от хороших, но обфусцированных плагинов, из-за невозможности оперативно интегрировать их в приложение в случае изменений (а они есть всегда) платформы или других плагинов.

Более того, я гарантирую, что когнитивный контекст каждого участника разработки уникален и отличается от контекста другого участника. Поэтому и нужны все эти митинги и документация, чтобы хоть как-то приводить все эти контексты в хоть какое-то соответствие. Лично для меня "источником правды" является код - что он делает, то и есть (отладчик в помощь, если непонятно). Да и то - нужно ещё посмотреть на окружение, в котором запускается этот код. А в документации может быть написано что угодно. Хорошая документация лишь помогает понять код "от общего к частному" (иерархически выстраивает когнитивный контекст, который адекватен текущей ситуации и помогает понять существующий код).

Да и вообще, я не считаю добром "тотальное описание типов". Я считаю добром "эволюционную устойчивость кода". Думаю, что это в какой-то мере антонимы, особенно на больших системах с кол-ом контрактов 10K+.

На второй взгляд, то, что описано в статье, очень похоже на повседневную реальность fullstack веб-программиста, только описанную однобоко: если про использование достоинств js тут в целом хорошо сказано, то про борьбу с недостатками - вообще ничего. Но нельзя же делать вид, что ее нет.

Так уж получилось, что я - веб-программист и именно fullstack. Я писал статью для людей со схожими интересами :) Про недостатки JS (и про многое другое) я не написал, потому что это не является моей целью. Мне важно было сформулировать наиболее значимые принципы, которые я использую в веб-программировании, а не достоинства-недостатки языка.

Тут, похоже, я неточно выразился. Я не призываю описывать недостатки JS. Но мы все знаем, что типизация в js - это едва ли не самое критикуемое из слабых мест языка. А из принципов, на которых должна строиться разработка, трудно извлечь конкретику, как же этот недостаток может быть преодолен. Этому внимание уделено весьма вскользь: JSDoc, контракты. Причем в размытых формулировках, из которых лично мне было мало что понятно, пока Вы не добавили уточнений в комментариях.
Тут логика очень простая: вот я, например, тоже фуллстек и тоже пишу на js. Относительно небольшие проекты я совершенно точно буду писать на js. А большие, где сделать качественный code review в одно лицо уже точно не получится (для меня это примерно 10 тысяч сущностей, у Вас может быть больше, но где-то этот порог все равно есть), сопряжены с компромиссами, болью и костылями. Может я такие проекты просто не умею готовить? Возможно. Но и в предложенной статье рецепта приготовления я не увидел. И будь в ограничениях к принципам сказано что-то еще про размер проектов, на которых это работает - придраться, пожалуй, было бы не к чему.

В этом документе я попытался сформулировать базовые принципы, на которых я строю свою разработку. ESM и без транспиляции - вот это база. Детализация этих принципов "ещё в пути".

Если коротко, то чтобы можно было строить достаточно большие JS-приложения (для меня это 100-200 таблиц в БД) нужна декомпозиция всей кодовой базы на достаточно малые фрагменты (желательно два-три экрана кода без документации), описание интерфейсов этих фрагментов и инструмент по склейке всех фрагментов обратно в единую кодовую базу с учётом описанных интерфейсов (у меня это - Контейнер Объектов). Не надо держать в голове сразу всю кодовую базу, достаточно отдельных рабочих фрагментов и их зависимостей. Контейнер ориентируется по их идентификаторам и сообщит при старте, если чего-то там ой.

Если есть какой-то небольшой проект на JS, могу помочь настроить Контейнер Объектов, чтобы он автоматически находил нужные исходники, и объяснить, какие идентификаторы зависимостей указывать, чтобы Контейнер возвращал нужный объект в нужном lifestyle. Для начала желательно чистый nodejs - будет сильно проще. Также опыт работы с DI в других ЯП сильно приветствуется. Но нужно будет "сменить веру" - вообще отказаться от статических импортов в своём коде ;) Даже для node'вских модулей и пакетов. Статикой подгружается только сам Контейнер. Дальше всё через динамический импорт. Все привычные инструменты, завязанные на статических импортах, придётся выкинуть.

Свои проекты публично показать не могу, поэтому, если Вы действительно хотите поделиться своими идеями с сообществом, можете показать свой пример реализации Контейнера Объектов. У Вас, как я понял, все лежит в публичных репозиториях? Можно просто накидать ссылок, где какие части реализации смотреть, на что стоит обратить особое внимание, и т.д.

Сам контейнер здесь - @teqfw/di Там описание на английском, но должно быть понятно, как стартануть. Если не понятно - спрашивайте (можете здесь, можете в личку). Там же и ссылки есть на примеры.

Вот старая документация (на английском), но там довольно подробно объяснена архитектура самого контейнера. Есть схема последовательности действий при создании новой зависимости по её ID:

А это схема компонентов библиотеки:

Вот в этой статье на Хабре объясняется в очень простом виде концепция внедрения зависимостей в ES. Старался описать популярно, а не как у меня сделано. Но архитектурно - один в один. Разница в реализации.

Надеюсь, этого хватит. Если нет - стучите.

Да, я тут сделал кастомный GPT-чат "TeqFW Help Desk" - добавляю в него LLM-инструкции по мере появления. Думаю, что со временем он сможет давать более-менее квалифицированную консультацию, но пока ещё довольно общими фразами отвечает и часто неточно. Я не знаю, насколько это здравая идея и куда это может вырулить. Пробую.

Поразмышлял на досуге над подходом. Что, на мой взгляд, однозначно интересно: если взять за аксиому отказ от тотальной типизации и поставить вопрос о том, как может выглядеть разумная частичная типизация, то в первую очередь на ум приходят именно контракты на границах сервисов, библиотек, модулей. Причем это даже не будет стоить сильно дорого, т.к. документировать и тестировать эти границы все равно надо, и речь только о том, чтобы делать это понятным в т.ч. и для IDE способом. Идею, как Вы это сделали в своем проекте я понял, думаю, у себя ее воспроизвести тоже смогу, когда дозрею.

В любом случае, спасибо за публикацию своих идей! Последующие публикации на тему пока не смотрел, но, видимо, еще посмотрю :)

Спасибо за обратную связь! :)

Tequila Framework использует современный JavaScript (ES6+) без понижения версии и без строгой типизации TypeScript. Код остаётся в исходном виде, что делает его прозрачным, доступным и удобным в сопровождении

Может что не так понял, но впервые вижу, как отсутствие строгой типизации приводит к прозрачному, доступному и удобному в сопровождении коду)

Но вообще, подход выглядит довольно интересно и, думаю, будет иметь своё место для проектов на полтора разработчика (LLM + js'ер, и тут сами решайте, кто в таком подходе идёт за половину разработчика).

Код остаётся в исходном виде. И это делает его "прозрачным, доступным и удобным в сопровождении". Вы просто начинаете мыслить в тех же категориях, что и среда исполнения, а не среда написания.

Да, возможность написания плагинов "в одно лицо" (в полтора - с применением LLM), а потом объединение различных плагинов от различных лиц в одно приложение - один из фокусов развития платформы. Архитектурно - чистая калька с Magento, на которой я довольно долго сидел. А уж сколько я тамошних плагинов заинтегрировал друг с другом...

Sign up to leave a comment.

Articles