PHP開発者のためのNode.js。 5 must-know pragmatic aspects with code examples

Node.js の人気が高まっている一方で、PHP の牽引力は低下しています。 そのような背景から、この記事では、PHP開発者がNode.jsを使用する際に必ず知っておくべき5つの実用的な側面について詳しく説明します。

  1. Node.js for PHP developers (not Node.js vs PHP)
  2. Node.js for PHP developers the practical side
    1. Node.js code execution is async and non-sequential
      1. Node.js code execution is async and non-sequential.Node.js the practical side.
      2. Node.js for PHP devers for Node.js for Node.js for PHP developmenters the practical side.jsは可能性を約束する
    2. Node.jsのプロセスはPHPと異なり、ロングランです
      1. メモ化の例
      2. MySQLでのコネクションプールの例
    3. デバックはNode.jsでは簡単です。
    4. Node.jsのメジャーバージョンアップはPHPよりシームレス
    5. Node.jsアプリケーションのドッカライズはPHPより簡単
  3. 結論

Node.js はPHPよりシンプルである

  • Node.Js>は、PHPよりシンプルである。js for PHP developers (not Node.js vs PHP) #

    この作品は、PHP 開発者として Node.js を効果的に使用するために知っておくべきこと、学ぶべきことをリストアップしたものです。 逆に、この投稿は、PHP がバッシングされるような Node.js vs PHP の書き出しではありません。 私は両方の言語を使ってきました。 私がNode.jsを多く書くようになったのは、2016年からです。 それ以前の7年以上、仕事でPHPに慣れていたため、始めた当初は困難に直面しました。 2012年末にPHP開発者向けにNode.jsを網羅した本が発売されました。

    このブログ記事は、PHPやNode.jsが何であるかについて話すつもりはありません、それについては他の記事で読むことができます。 また、ノンブロッキングI/Oやイベントループについてもあまり話しません。

    Node.js for PHP developers the practical side #

    PHP は 1995 年から存在し、W3tech が監視するウェブサイトの 79.% で使用されていると言われています (インターネット全体かどうかは分かりませんが)。 そのため、PHPを使用したり、PHPで書かれたものをデプロイしたことがある可能性は非常に高いです。 たとえば、

    WordPress は、コンテンツ管理システムがわかっているすべての Web サイトの 63.7% で使用されています。 これは、W3Techが監視しているすべてのWebサイトの39.0%です。

    一方、Node.jsは2009年にリリースされました。 Linked InやPaypalなどの大手テック企業は、マイクロサービスなどのさまざまな理由から2011年から2013年にかけて採用し始めました。 2020年のStack Overflowの開発者調査によると、

    2年連続でNode.jsがトップになり、回答者の半数が使用しています。

    過去5年間でNode.jsが非常に人気を集めているのは周知の通りです。PHP開発者として、優れたNode.jsソフトウェア技術者となるためには必ず知っておくべき5つの実践事項がこれです。

    Node.js のコード実行は非同期かつ非シーケンシャル #

    これは、多くの PHP 開発者を欺く動作と言えます。 PHP では、コードは最初に 1 行目、次に 2 行目というように順番に実行されます。 Javascriptや特にNode.jsでは、そうではないかもしれません。

    以下は、私のオープンソース通貨APIレポから引用した説明付きの修正コード例です:

    async function getExternal(fromCurrency, toCurrency, onDate) {
    const rate = await getRate(fromCurrency, toCurrency, onDate);
    db.query(
    `INSERT INTO exchange_rates (from_currency, to_currency, rate, on_date) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE rate = ?`,

    ).then(result => {
    if (result.affectedRows === 0) {
    console.error(`Exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} on ${onDate} could not be saved`);
    }
    }).catch(err => {
    console.log(`Error while writing to db: `, err);
    }); //this is done async for the API to respond faster
    console.log(`Fetched exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} of ${onDate} from the API`);
    return { fromCurrency, toCurrency, onDate, rate };
    }

    よく見ると、3 行目の db.query はバックグラウンドでプッシュされています。 つまり、以下のように実行されます。

    1. Get rate
    2. Run insert query in the background
    3. 挿入が実行されている間、関数はすでに rate
    4. 挿入クエリーに問題がある場合、それは catch

    PHP でこのように何かを行うアウトボックス方法は存在しないのです。 これは、PHP 開発者をつまずかせる最初のものです。 PHP開発者にとってNode.jsを理解するのが難しくなるのです。 この非同期コード実行の動作は、Node.js でエラーが発生した場合に正しいスタックトレースを見つけることも難しくします。

    正直に言うと、2020 では、非同期 await を簡単に使用することができます。 それは Promises の構文上の糖分であるにもかかわらず、非同期プログラミングを非常に簡単にするものです。 私がNode 4/6時代の2016年頃にコールバックとPromisesを始めたときは、全く別のボールゲームでした。 それでも、async-awaitを使わず、promise、then、catchで済ませる場合は注意が必要です(上記のような)。 しかし、その過程でプロミス地獄に巻き込まれないようにしましょう。 プロヒント: Node.js のどのバージョンでどの ES6 機能を使用できるかを知るには、node.green でチェックアウトしてください。 そのため、実稼働環境では 13 や 15 ではなく、Node 14 または 16 を使用してください。

    非連続実行についてもう少し深く掘り下げると、約束とそれが持つパワーがここで重要な役割を果たします。 同時実行の能力は、Node.js と javascript 一般で素晴らしいものです。

    Node.js promises possibilities #

    Promises being asynchronous, you can run them concurrently.The ability to do concurrent things are great in Node.js and in javascript general.

    Promise は非同期なので、並行して実行できます。 その方法はあります。 3つのプロミスを競争させ、最も速いものから結果を得ることができます。 promise.all1つのプロミスが拒否されたら、全体の処理を停止することもできます。 Promise.race, promise.all, promise.any については、この素晴らしい比較をお読みください。

    このことを念頭に置いて、プロミス並行処理を制限したり、プロミスを同時にフィルターするために他の NPM ライブラリを試すこともできます。 ReactPHP である程度はできます。 しかし、ネイティブのPHPには、PHP8にも含まれていません。 これは、PHP 開発者にとって Node.js で頭を悩ませる新しいことです。

    次のポイントに進みましょう。Node.js では PHP のようにプロセスが死ぬ必要はありません。

    Node.js プロセスは PHP とは異なり長時間実行されます #

    PHP は使われないという意味で死ぬというわけではないんだ。 すべての PHP プロセスが死ななければならないという意味においてです。 PHP は実際には長時間稼働するタスク/プロセス向けに設計されていません。 PHPでは、新しいHTTPリクエストが来たときに処理を開始し、レスポンスを返した後、プロセスを終了させます。 これがPHPの仕組みです。 そのため、FPMやその他のサーバーが必要になるのです。 PHPは20年以上前から設計上サーバーレスだったと主張することもできます。 6964>

    その一方で、Node.jsは長時間稼働するプロセスです。 これにより、同じサーバー/プロセスが複数のリクエストを処理するため、リクエスト間で情報を共有することができます。 長時間稼働するプロセスでは、メモリ上のメモ化やデータベースのコネクションプーリングなどを簡単に利用できます。 たとえば、そのプロセスでの同時リクエスト数をカウントするなど、他の可能性も開けます。

    メモ化の例 #

    メモ化を知らない場合。 これは、いくつかの遅い関数を速い関数に変えることができます。 初回の関数呼び出しの結果をキャッシュに保存するため、同じ引数で再度関数を呼び出すと、キャッシュから結果を見つけることができます。

    これは Node.js で使用できますが、PHP ネイティブでは使用できません。 PHPでは関数の戻り値をRedisに保存するなど、いくつかの回避策が可能です。

    以下は、p-memoizeを使ったexpressルートでのメモ化のコードサンプルです:

    const ONE_MINUTE_IN_MS = 60000;
    const options = {
    maxAge: ONE_MINUTE_IN_MS,
    cacheKey: (arguments_) => arguments_.join(','),
    };
    app.get('/api/products', async (req, res, next) => {
    try {
    const memGetProducts = pMemoize(products.getMultiple, options);
    res.json(await memGetProducts(req.query.page || 1, req.query.search));
    } catch (err) {
    next(err);
    }
    });

    これの明確な利点はデータストアの負荷が少ないということです。 1分間、同じパラメータに対して同じレスポンスを返します。 関数 products.getMultiple の出力は、1分間、メモリにキャッシュされます。 これにより、レスポンスは非常に速くなります。

    Connection Pool example with MySQL #

    もうひとつ、PHPでプロセスが死んでしまうためにできないことが、コネクションプーリングです。 Wikipedia:

    In software engineering, connection pool is a cache of database connections maintained so that the connections can be reused when future requests to the database are required. 接続プールは、データベース上でコマンドを実行する際のパフォーマンスを向上させるために使用されます。

    つまり、プール内に 5 つの接続があり、データベースに対して 5 つのクエリを実行する場合、それは同時に行うことができます。 これは、データベースへの接続とクエリの実行の両方の時間を節約します。 これは、Node.js では簡単にできますが、PHP ではなかなかできません。

    利用可能な接続数を意識して、接続プールのサイズを最適に保つようにしましょう。

    Time for a connection pool example with MySQL database with MySQL npm module:

    var pool = mysql.createPool({
    connectionLimit : 5,
    host : 'example.org',
    user : 'app',
    password : 'pass',
    database : 'schema'
    });
    for(var i=0;i<5;i++){
    pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
    if (err) {
    throw err;
    }
    console.log(rows.solution); //Shows 2
    });
    }

    The above code will run the same query 5 times in parallel with 5 MySQL connections taken from the connection pool.上記のコードは、同じクエリーを5回、接続プールから取り出したMySQL接続で並列に実行します。 私はこれを PHP ですぐにできればと思いました。

    私の経験では、Node.js は Mysql と非常によく動作します。

    With a long-running process as a developer you need to be more careful about memory leaks and doing the housekeeping stuff well.

    Node.js for PHP developersがコードの実行方法についてかなり考えをシフトする必要があるのはこのあたりでしょう。

    Debugging is easier in Node.js than in PHP #

    Line by line code debugging is a important part of developer experience for any programming language。 PHP コードをデバッグするには、いくつかの IDE 設定で X-Debug のようなアドオンを使用できます。 X-Debug は、控えめに言っても設定するのが難しいです。 インストールし、拡張機能を有効にする必要があります。 その後、PHPStorm のような IDE で適切に設定します。

    X-debug を実行させるには、基本的に、簡単というのが最後の言葉でしょう。 docker コンテナですべてうまく構成され、IDE の設定も簡単に読み込めるなら別ですが。

    一方、node native debugger や ndb さえ動かすのは PHP と X-debug に比べればずっと簡単です。 VS Code を使用すれば、Node.js アプリケーションのデバッグは、原始人でもできるほど簡単です。

    Preferences > Settings を開き、検索ボックスに “node debug” と入力します。 拡張機能タブの下に、「Node debug」というタイトルの拡張機能が一つあるはずです。 ここから、最初のボックスをクリックします。 デバッグ > ノード]をクリックします。 Auto Attach」をクリックし、ドロップダウンを「on」に設定します。 これでほぼ準備は整いました。

    次に、VS コードに index.js といったブレークポイントを設定し、ターミナルで node --inspect index.js と入力します。 あなたのステップバイステップの Node.js デバッガは、VS Code エディタ上でそれほど努力せずにうまく動作しています。 PHPとの良い違いは、プログラムをデバッグできるようにするために、別の拡張機能をインストールし、それを有効にし、設定する必要がないことです。

    次のポイントは、言語の複数のメジャーバージョンをアップグレードする際の、より良い開発者エクスペリエンスについてです。 PHP 5.x から PHP 7.x へのアップグレードは、プロジェクトのサイズと複雑さに応じて、1 週間から 1 か月のプロセスです。

    私個人の経験では、過去にバージョン 0.12 から 4 まで Node.js マイクロサービスをアップグレードしました。 最近、私はアプリケーションを Node.js 10 から 14 へとアップグレードしました。 私の Node.js のメジャー バージョン アップグレードはすべて簡単でした。

    いくつかのマイナーな package.json 変更が、私が遭遇した唯一の小さな問題でした。 デプロイ後、コードの互換性に関連する問題はほとんど発生しませんでした。 おまけに、メジャーバージョンをアップグレードすると、通常、パフォーマンスが向上しました。

    その一方で、PHP のアップグレードは簡単ではありませんでした。 アプリケーションを PHP 5.4 から 5.6 にマイナーバージョンアップするのは、それほど面倒ではありませんでした。 しかし、比較的大きなアプリケーションの PHP 5.6 から 7.2 へのアップグレードは苦痛でした。 時間がかかるし、composer.jsonを何度も変更する必要があったのです。 また、それをテストするのも大変な作業でした。 PHP のメジャー バージョンアップの良い面は、確実にパフォーマンスが向上したことです。

    ここで注意していただきたいのは、私が作業した PHP アプリケーションは、Node.js アプリケーションより古かったということです。

    Node.js アプリケーションの Dockerizing は、PHP に比べて簡単です。

    Docker の人気は過去 5 年間で着実に上昇しています。 そのリリース以来、私たちソフトウェアエンジニアの働き方を変えてきました。 ローカル開発でもDockerを使うべきでしょう。 そう考えると、PHPアプリケーションのDocker化は、コンポーネントの配置の仕方やアプリケーションの複雑さによっては、難しい作業になる可能性があります。

    以下は、Apacheを含むPHP LaravelアプリのDockerfileの例です。

    FROM composer:1.9.0 as build
    WORKDIR /app
    COPY . /app
    RUN composer global require hirak/prestissimo && composer install
    FROM php:7.3-apache-stretch
    RUN docker-php-ext-install pdo pdo_mysql
    EXPOSE 8080
    COPY --from=build /app /var/www/
    COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
    COPY .env.example /var/www/.env
    RUN chmod 777 -R /var/www/storage/ && \
    echo "Listen 8080" >> /etc/apache2/ports.conf && \
    chown -R www-data:www-data /var/www/ && \
    a2enmod rewrite

    このLaravel用のDockerイメージで良いことは、PHPとApacheが同じイメージにバンドルされていることです。 これは、PHPとApacheを2つのDockerイメージに分割するよりも良い方法であると主張することができます。 Composer のインストールは別のイメージで行われ、出力はメインのイメージにコピーされます。 もし、PHP-FPM と Nginx を別の docker イメージで使用していたら、もっと複雑になっていたことでしょう。

    Node.js Dockerfile を見てみましょう。

    FROM node:14-alpine as base
    WORKDIR /src
    COPY package.json package-lock.json /src/
    COPY . /src
    EXPOSE 8080
    FROM base as production
    ENV NODE_ENV=production
    RUN npm install
    CMD
    FROM base as dev
    ENV NODE_ENV=development
    RUN npm config set unsafe-perm true && npm install -g nodemon
    RUN npm install
    CMD

    Node.js には Web サーバーが組み込まれているので、Dockerfile はよりすっきりしています。 これにより、Docker ビルドの別の段階でパッケージをインストールする必要がなくなります。

    上記の Dockerfile では、多段階の docker ビルドを使用して、本番と開発の docker イメージを分離しています。 パッケージマネージャ (npm) をバンドルし、Web サーバを言語/ランタイムの一部として持つことは、PHP 開発者向けの Node.js とは異なるものです。 Node.js アプリケーションをステップバイステップでドッキングすることに興味があるなら、このチュートリアルをご覧ください。

    Conclusion #

    PHP 開発者が Node.js を使う場合、Node.js の力をうまく活用するために考え方を少し変えることが必要です。 Node.js は銀の弾丸ではありません。 欠点があり、コード実行の異なる方法に適応する必要があります。

    確かに、非同期プログラミングや並行処理のように、PHP 開発者が Node.js を使うことの利点はいくつかあります。 他の利点は、Node.js の機能から生じています。

    この投稿が、経験豊富な PHP 開発者として、あなたが Node.js をより活用するのに役立つことを願っています。

  • コメントを残す

    メールアドレスが公開されることはありません。