Pull to refresh
23
21.7

NodeJS и финтех

Send message
2020 дал заценить всем как это — работать удаленно.
P.S. Боже, как же я стар, 10 лет прошло…
Телепортировали меня в 2013, тогда как раз был популярен этот компилер и проекты с goog.
Но спираль всё же развернулась, теперь TS силен и много проектов на нем, вот и до Closure Compiler докаталась волна.
Вообще забавно, с одной стороны исходниками, а не каким-нибудь байт-кодом скрипты распространяются в том числе чтобы код видеть, но во благо оптимизации, а иногда обфускации, оно всё же пережимается в нечто среднее, из которого исходный код особо не восстановишь, особенно после этого интструмента, весить становится мало, да, но ощущение что где-то по пути мы обманули самих себя. А потом ещё когда map файлы… в общем спираль крутится.

Так всё просто — есть проблема с одинаковым окружением. Кстати, решение этой проблемы сделало docker таким популярным, например. Тут типа того — разные версии пакетов, иногда и минорно, могут иметь разное поведение. И единственный адекватный кейс — всегда устанавливать именно то окружением что задумывалось разработчиком, иначе это будет порождать пляски с бубном на продакшене и прочее такое. Это плохо, уж лучше пакетов побольше, но всё же стабильная работа.


Ну и вторая причина количества пакетов вообще — любовь к мелкой модульности без таскания целых библиотек. Более того — некоторые популярные библиотеки представляют цельную версию и к ней по модулю на каждую входящую функцию — чтобы разработчик мог взять только одну или несколько, а не тащить с собой 100500 функций ради использования лишь одной. Разве это плохо? Вроде как очень даже хорошо. Ну а то что на npm сайте так много модулей — ну и что, больше выбора наоборот же.


В общем какая-то злая статья без понимания механизмов почему так. Не, конечно некоторые разработчики некоторых пакетов могут лишнее таскать, качество пакетов может быть сомнительным, как и эффективность — но так то это и в любом другом бывает, будь то Ruby или .NET экосистема. А с общим механизмом пакетов всё вполне себе.

Спасибо, теперь стало яснее.
Какова цена за хранение одного гигабайта данных таким образом и что с доступностью?
Аналогичная проблема была лет 6 назад. Выводилась реклама, в том числе под свежеустановленным Linux, на всех страницах без https, правда с таким нюансом что на первом подключении ничего не было, но со второго и далее — баннеры, при этом судя по всему только на популярных сайтах в свободных от контента местах, ребята заморочились, да, возможно чтобы скрыть факт того что реклама не от реального сервиса. Проблема также оказалась в роутере, что-то туда было дописано извне, в моем случае был просто куплен новый, имелся в этом смысл, баннеры исчезли навсегда.

Возможно у автора аналогичная проблема, хотя всё же похоже больше на вмешательство провайдера.

А в NodeJS удобно использовать этот сайт — https://node.green/


Как только LTS версия ноды делает шаг вперёд — самое время проверять чего добавили и изучать если что было пропущено.


BigInt уже там давно и лично продакшн код с ним писал, а вот например штуки с опциональным чейнингом посвежее.


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


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

Тут выше упоминался golos.io и свободу слова. Увы, прилетающие запросы от Роскомнадзора приходится исполнять и запрещённый контент оттуда быстро исчезает… но исчезает из выдачи, оригиналы навечно остаются в блокчейне и доступны через просмотрощик блоков, включая всю историю правок и всё всё всё. Но у голоса было несколько сайтов что выводили контент, был что не скрывал запрещёнку. Закончилось просто баном на территории России.


К слову, вышла новая версия этой штуки, но уже для всего мира, на базе нового блокчейна (но той же линейки, тоже графен). commun.com


Могу что-либо рассказать о мире таких штук как собственно бывший разработчик Голоса.


Но а так, как верно выше заметили — простым людям это не нужно, а для не простых — уже есть десяток проектов на все случаи жизни, но что-то вот доминирующего, который победил бы всех и был на слуху, что-то вот нет. Возможно потому что оно и не нужно. А то «потому что могу» делать всегда хорошо, но лучше сначала понять какую проблему оно решает и для кого, только не взглядом идеалиста, а взглядом прагматика. Но как техническая задача — это весело. Но может лучше присоединиться к существующему проекту?

Очень большое отождествление NodeJS и Express, хотя в названии именно NodeJS. Ну и код в примерах от 2014 года и ранее, так уже не пишут, для веба 5 лет это много, тем более революция с ES6/2015 превратила язык в почти другой.
Очень старые советы, пожалуйста, не применяйте их бездумно.

Тогда мы точно с вами одинаково мыслим, просто по разному описываем.
Или устанавливают правила. Либо поручают машине исполнить договоренность, но чтобы она соответствовала указанным инструкциям. Ну и ещё есть всякие там голосования делегатов за форки. В результате, абстрактно, это взаимодействие и машин и людей в некоторых из квантов времени. Суммарно всё конечно исходит от людей и договариваются люди с людьми, но через посредников-машин. Но это уже философские темы получаются.
Да, это второй вариант развития когда у тебя достаточно средств и власти чтобы преодолеть консенсусный барьер, добраться до состояния когда ты владелец, а после, если твоя цель разрушение или сдерживание — сотворить что-то подобное. Правда вот какая штука — если разрушить, то есть шанс что появятся форки и подобные проекты, а вот если сдерживать, ломать неспешно — могут быть варианты и поинтереснее и поэффективнее.
У ETH:
~11 520M USD торговый оборот за сутки
~27 067M USD капитализация
— 400+ известных рынков
— Большинство бирж торгуют

Итого в 15 раз больше оборотов, в 31 раз больше капитализация, почти все биржы торгуют ETH и много, но не все ETC. Также проблемы с командой и цена токена ETH в 33 раза больше ETC.

То есть это да, не смерть форка, но разница на порядок.

У обычных людей не появилась, потому что как раз таки это и не нужно, есть другие инструменты. А вот у специфических и для специфических кейсов — да. В статье есть пример с Венесуэлой.

Да, похоже мне всё-таки стоит глубже изучить новые стандарты.
Спасибо за развернутый ответ.
Например вот так.
Не то чтобы божественный пример, но рабочий код, без вырезок, переживший несколько доработок и крутящийся на продакшене.
Можно было бы конечно что-то более стремящееся к треугольности в плане колбеков, но либо не безопасно, либо не ищется с ходу.
Отмечу что использую классовый движок ExtJS, но он никак не выпрямляет код, лишь помогает в ООП.
Если вот этот класс написать в треугольном стиле — прокрутка в бок была бы весьма велика, как и разброс кода и мест определения локальных переменных. Не говоря уже о путанице в тех что видны через скоп.
По поводу B.util.Function.queue — утилита просто вызывает по очереди функции, передавая скоп текущего класса и первым параметром отправляя ссылку на следующую функцию, в которой заранее проставлен скоп.
Про обработку ошибок — суть в том что каждый метод сам лучше знает а что у него не так, что поломалось, что необходимо выбросить в исключение, залогировать и т.п. и он сам вызывает метод с ошибкой или сразу отправляет что-то клиенту. Это избавляет от вложенных поимок, катчей уровнем ниже и прочих дебрей вглубь. В итоге — всё плоско и предсказуемо.
Впрочем, перфекционист найдет что здесь ещё можно было улучшить. Например вынести в отдельный субкласс «управляемый режим запуска», можно было бы ещё больше разложить и подоптимизировать код. Но это — полноценный продакшн, не вылизанный код и даже в таком виде он лучше пирамидок, треугольников и цепочек отлова ошибок.
В добавок к этому разделение на шаги позволяет проименовать шаги, что ведет к большему пониманию что происходит в каждый момент времени. Особенно полезно если над проектом работает не 1 человек, и просто необходимо если планируется что код будет поддерживаться годами.
Ну и ещё одна особенность, уже касательно организации асинхронных путей исполнения кода — в рамках одного класса/модуля/etc. должен быть 1 путь. Если в процессе исполнения шагов порождаются вложенные наборы шагов или ветвления — необходимо выносить это в отдельный класс/модуль/etc. Всё это позволит избавиться от непредсказуемости, треугольности и проблем с дебагом.
И всё это на ES3/ES5, то есть промисы добро и только дополняют решение, но в голом виде не решают проблем. А вот архитектура и организация кода — наше всё!
Пример
/**
 * Логика размещения компании клиента.
 */
Ext.define('B.biz.client.Release', {
    extend: 'B.AbstractRequestHandler',

    requires: [
        'B.biz.auth.util.Account'
    ],

    config: {

        /**
         * @cfg {Boolean} isDirectMode
         * В управляемом режиме релиз производится логину, указанному в {@link #directLogin}.
         */
        isDirectMode: false,

        /**
         * @cfg {Boolean} directCallback
         * В управляемом режиме вызывает эту функцию в момент завершения, вместо отправки клиенту данных.
         */
        directCallback: Ext.emptyFn,

        /**
         * @cfg {Boolean} directCallbackScope
         * Скоуп выполнения {@link #directCallback}.
         */
        directCallbackScope: null,
        
        /**
         * @cfg {Boolean} directErrorCallback
         * В управляемом режиме вызывает эту функцию в случае ошибки, вместо отправки клиенту данных.
         */
        directErrorCallback: Ext.emptyFn,

        /**
         * @cfg {Boolean} directErrorCallbackScope
         * Скоуп выполнения {@link #directErrorCallback}.
         */
        directErrorCallbackScope: null,

        /**
         * @cfg {String/Null} directLogin
         * Логин, по которому необходимо произвести релиз в управляемом режиме.
         */
        directLogin: null,
        
        /**
         * @cfg {Boolean} isSendSuccessIfPayDateIsExpired
         * Флаг, указывающий на то что необходимо отправить что всё прошло успешно
         * в случае если истек переиод оплаты,
         * не смотря на то что из-за этого релиз произведен не был.
         * Может быть использовано в кейсе когда аккаунт был создан только что,
         * данные вносятся клиентом, но оплата ещё не произошла.
         */
        isSendSuccessIfPayDateIsExpired: false,

        /**
         * @private
         * @cfg {Object} accountData Данные аккаунта.
         */
        accountData: null,

        /**
         * @private
         * @cfg {String[]} tagsData Массив данных для тегов.
         */
        tagsData: null,

        /**
         * @private
         * @cfg {String[]} tags Массив тегов.
         */
        tags: null,

        /**
         * @private
         * @cfg {Object} searchObject Объект поиска.
         */
        searchObject: null
    },

    constructor: function () {
        this.callParent(arguments);

        B.util.Function.queue([
            this.extractAccountStep,
            this.validateAccountStep,
            this.extractTagsDataStep,
            this.makeTagsStep,
            this.makeSearchObjectStep,
            this.writeSearchObjectStep,
            this.sendSuccess
        ], this);

    },

    /**
     * @protected
     * Модифицированная версия, не пытается отправить клиенту ошибку при управляемом запуске.
     * Вместо этого вызывает {@link #directCallback}.
     */
    sendSuccess: function () {
        if (this.getIsDirectMode()) {
            this.getDirectCallback().apply(this.getDirectCallbackScope(), arguments);
        } else {
            this.callParent(arguments);
        }
    },
    
    /**
     * @protected
     * Модифицированная версия, не пытается отправить клиенту ошибку при управляемом запуске.
     * Вместо этого вызывает {@link #directErrorCallback}.
     */
    sendError: function () {
        if (this.getIsDirectMode()) {
            this.getDirectErrorCallback().apply(this.getDirectErrorCallbackScope(), arguments);
        } else {
            this.callParent(arguments);
        }
    },

    privates: {

        /**
         * @private
         * @param {Function} next Следующий шаг.
         */
        extractAccountStep: function (next) {
            var key = null;
            var login = null;

            if (this.getIsDirectMode()) {
                login = this.getDirectLogin();
            } else {
                key = this.getRequestModel().get('key');
            }

            Ext.create('B.biz.auth.util.Account', {
                key: key,
                login: login,
                type: 'company',
                scope: this,
                callback: function (acc) {
                    var data = acc.getPrivateAccountData();
                    
                    if (data) {
                        this.setAccountData(data);
                        next();
                    } else {
                        this.sendError('Данные указанного аккаунта не найдены!');
                    }
                }
            });
        },

        /**
         * @private
         * @param {Function} next Следующий шаг.
         */
        validateAccountStep: function (next) {
            var data = this.getAccountData();
            var basic =   Ext.create('B.biz.client.model.BasicData');
            var summary = Ext.create('B.biz.client.model.Summary');
            var photo =   Ext.create('B.biz.client.model.Photo');
            var words =   Ext.create('B.biz.client.model.Words');

            if (this.isPayDateExpired()) {
                this.handlePayDateExpired();
                return;
            }
            
            data.key = true; // Модели требуют наличия ключа сессии.
            
            basic.set(data);
            summary.set(data);
            photo.set(data);
            words.set(data);

            if (!basic.isValid()) {
                this.sendError('Основные данные о компании ещё не заполнены.');
                return;
            }

            if (!summary.isValid()) {
                this.sendError('Описание компании ещё не заполнено.');
                return;
            }

            if (!photo.isValid()) {
                this.sendError('Фотографии ещё не заполнены.');
                return;
            }

            if (!words.isValid()) {
                this.sendError('Ключевые слова ещё не заполнены.');
                return;
            }

            next();
        },

        /**
         * @private
         */
        handlePayDateExpired: function () {
            var successIfExpired = this.getIsSendSuccessIfPayDateIsExpired();

            if (successIfExpired) {
                this.sendSuccess();
            } else {
                this.sendError('Невозможно выполнить действие - услуга ещё не оплачена.');
            }
        },

        /**
         * @private
         * @return {Boolean} Закончился ли оплаченый период.
         */
        isPayDateExpired: function () {
            return this.getAccountData().payDate < new Date();
        },

        /**
         * @private
         * @param {Function} next Следующий шаг.
         */
        extractTagsDataStep: function (next) {
            var data = this.getAccountData();

            this.setTagsData([
                data.name || '',
                data.word1 || '',
                data.word2 || '',
                data.word3 || '',
                data.word4 || '',
                data.word5 || '',
                data.word6 || '',
                data.word7 || '',
                data.word8 || '',
                data.word9 || '',
                data.word10 || '',
                data.address || '',
                data.summary || ''
            ]);
            
            next();
        },

        /**
         * @private
         * @param {Function} next Следующий шаг.
         */
        makeTagsStep: function (next) {
            Ext.create('B.biz.search.util.Tokens', {
                value: this.getTagsData(),
                scope: this,
                callback: function (self, value) {
                    this.setTags(value);
                    next();
                }
            });
        },

        /**
         * @private
         * @param {Function} next Следующий шаг.
         */
        makeSearchObjectStep: function (next) {
            var data = this.getAccountData();

            this.setSearchObject({
                company: B.Mongo.makeId(data._id),
                rating: 0,
                tags: this.getTags(),
                map: data.map,
                payDate: data.payDate
            });
            
            next();
        },

        /**
         * @private
         * @param {Function} next Следующий шаг.
         */
        writeSearchObjectStep: function (next) {
            var searchObject = this.getSearchObject();
            
            B.Mongo.getCollection('search').update(
                {
                    company: searchObject.company
                },
                searchObject,
                {
                    upsert: true
                },
                function (error) {
                    if (error) {
                        this.sendError(B.Mongo.requestErrorText);
                    } else {
                        next();
                    }  
                }.bind(this)
            );
        }
    }
});

Почему-то все кто пишут о минусах NodeJS всегда пишут о том что получается лапша из колбеков. Но… почему бы не писать эту лапшу? И почему считается что лапша решается использованием промисов? Ведь можно просто… делить шаги на отдельные функции/методы. А не пихать всё в один супер-метод с десятком колбеков, будь то просто функции или использование промисов. Думаю большинству тех кто пишет о таких проблемах необходимо срочно прочитать книгу Чистый код. И хоть речь там идет о Java — эта книга быстро вылечит от проблем с какими-то там вложенными колбеками, промисами и всем всем всем.
Пишу код на NodeJS и не имею проблем с колбек хэлом. При этом не использую ни промисы, ни генераторы, на обычном ES5 всё выглядит как аккуратные классы с методами, в которых нет пирамидок из колбеков и лапши из промисов. И всё работает. И это при логике, в которой по 5 различных обращений в БД за раз, множество колбеков и всего такого асинхронного. И код выглядит хорошо!
Ну и если эта книга, полностью прочитанная и осознанная, не спасет от колбек хэлла — возможно стоит задуматься о правильности выбранной архитектуры?
По сути то софт для государства пишется в том числе за счет налогов с граждан. В идеале во всех странах такой софт должен быть открытым и бесплатным, за исключением того что связано с безопасностью. Хороший вопрос конечно про софт, который был куплен у коммерческих компаний, но тем не менее — это шаг в будущее.
12 ...
36

Information

Rating
274-th
Works in
Registered
Activity