文理のこうさてん

人文科学と自然科学のこうさてんを目指していきたい。

Promise.allを実装してみる

Promise.allとは

このメソッドは複数のプロミスの結果を集約するのに便利です。このメソッドは、コード全体が正常に動作するために依存している複数の関連する非同期タスクがあり、コードの実行を続ける前にそれらすべてを履行させたい場合によく使われます。

実務ではnextjsでSSRをする際、必要な処理を一括で実行する場合などで利用したことがある。 互いに独立した非同期処理を実行する場合、Promise.allを利用すると並列実行されるので、全体処理が完了するまでの時間が短くなる。

developer.mozilla.org

interface

インプットについては待機状態のpromiseの配列、例えば以下のような感じ

const promise1 = fetch1()
const promise2 = fetch2()
const promises = [promise1, promise2]

返り値について、実行された非同期処理の結果を配列に格納した形で返却される

const promise1 = fetch1()
const promise2 = fetch2()
const promises = [promise1, promise2]

const res = await Promise.all(promises)
res = [promise1の返り値, promise2の返り値]

コード実装

配列の中身を一つずつ取り出し、全部の処理が終了したらresolve、何か一つでも失敗したらrejectをする関数を記述する。

function promiseAll(arr) {
  return new Promise((resolve, reject) => {
    const results = new Array(arr.length);
    let unresolved = arr.length;

    if (unresolved === 0) {
      resolve(results);
      return;
    }

    arr.forEach(async (item, index) => {
      try {
        const value = await item;
        results[index] = value;
        unresolved -= 1;

        if (unresolved === 0) resolve(results);
      } catch (err) {
        reject(err);
      }
    });
  });
}

状態管理に関しての知識整理

状態管理について、概念的にまとめた自分用メモ。

状態管理とは

コンポーネント間共通で管理したいデータを扱う手法のこと。  

状態管理の手法

useStateで管理してprops経由でバケツリレーをする

基本的な状態管理方法であるuseStateを用いる手法。複数感コンポーネントで状態をシェアしたい場合は、propsによるバケツリレーを行わないといけない。パフォーマンス観点から再レンダリングをコントロールしにくいという観点と、また責務の観点(単一責任の原則)から好まれる方法ではない。

useContextを使う

useContextは、親から子に状態を渡す場合に限って、propsバケツリレーを回避することができる。 そういえばflutterでアプリ開発をしていた時はChangenotifier&providerパターンで状態を管理していた。

propsによるバケツリレーの心配は無くなったが、ステートが複雑になった場合の管理が煩雑になる可能性がある。例えば、userに関する情報とquestionに関する情報を管理したいとなった時に、providerを二つ用意せねばならない(管理したい対象に応じて、n個ずつproviderが増えていく』)。代替案として、複数のproviderを用いずに単一のproviderを用いるという方法もあるが、パフォーマンスの低下が代償となる。

状態管理ライブラリを導入する

ステート管理のライブラリを導入する方法。代表的なものと、業務で使用しているものを整理する。

react-redux

一つのstoreにまとめて状態を管理する。 selecter経由でstoreから値を取得し、action経由でstoreに対して変更をdispatchする。storeが更新されたとしても、selecterで取得される値に変化がなければ、storeに接続しているコンポーネントは再レンダリングされない。また、useDispatchを使うことで、特定のコンポーネントが更新のみに責務を持つことができ、再レンダリングのコントロールをすることができる。 uhyoさんによると特有の点は以下。

React-reduxに特有の点としては、(グローバルに共有される)すべてのステートを一つのStoreで管理し、selectorによってそこから必要なものだけを取り出すというインターフェースが特徴となります。特に、selectorの型が(state: 全てのステート) => 必要なステートのような型となり、ステートの使用者は常に全体のステートを意識させられます(適宜カスタムフックを用意することでこの点はある程度緩和できますが)。

recoil

reduxをは異なるインターフェースを持った新興のステート管理ライブラリ。状態を管理するAtomと状態を取り出すSelectorのRecoilStateから成り立つ。 全てのステートが一箇所にまとまっていないのが特徴。reduxと異なり、statoのcode splittingが成立する。 uhyoさんまとめは以下。個人的に、良くも悪くもアーキテクチャを最初に固めないといけないので、ある程度経験がある人がチームにいる時に採用したほうがいい気もする。

まとめると、RecoilはAtom・Selectorというシンプルな概念をベースとし、特定のアーキテクチャを強制することなくグローバルなステート管理の部品を提供してくれる点が特徴です。subscriptionの管理などの面倒な部分をRecoilに任せつつ、思いのままのアーキテクチャでステート管理を行うことができるでしょう。

apollo client

今本業で使っている。graphqlサーバーからのdata fetchingだけでなく、cache機構も備えており、状態管理を実現することもできる。 apollo client経由でqueryを叩く際、初回のリクエストはgraphql serverに問い合わせるが、2回目以降はcacheに対して問い合わせるようになる。またcacheの値以外を管理したい場合、Reactive valiablesを用いれば、追加で値を管理することができる。

個人的には、クエリの結果と+アルファを管理したい場合には、apollo clientのcache機構をそのままステート管理に用いていいと思うが、呼び出し時に特別な処理や副作用を起こしたい場合、apollo clientで対処するのは難儀なので、何かしらの状態管理ライブラリに寄せていったほうがいいと思う。

uhyoさんの考察。

これらのライブラリはキャッシュされたデータを識別するための「キー」という概念を持ち、データは末端のコンポーネントが好き勝手に追加できることから、ステート管理のアーキテクチャとしてはRecoilに近いものです。一方で、これらのライブラリは使い勝手を第一に置いたハイレベルなAPIに重きを置いており、ローレベルなAPIを中心とするRecoilとは対照的です。 これらのライブラリによるステート管理は自己完結的5であり、もしデータフェッチングとは関係ないステートも多くある場合、ふたつのステート管理を融合させた状態で最適なパフォーマンスを得るのは難しいと思われます。ここに最適なパフォーマンスが必要な場合は、React QueryやuseSWRなどを使わずにRecoilなどに寄せる選択肢も考える余地があるでしょう。

まとめ

頭の中が整理できてよかった。現状apollo clientのcache機構を本業で、useContextによる管理を副業で使っているが、状況に応じて最適な状態管理をしていきたい。

参考記事

blog.uhy.ooo

blog.uhy.ooo

www.apollographql.com

react-query.tanstack.com

Reactのパフォーマンスを図る際に気をつけなければいけないことをまとめる

Reactにおけるパフォーマンスチューニングの知見について、色々と調べたのでまとめる。

 

方針

無駄な計算を抑えて、出来るだけ再レンダリングしないようにする。

 

計測方法

react dev toolを使用する

コンポーネントがコミットされる時間、および、レンダリング回数に注目するのが良さそう。

 

パフォーマンス改善方法

React.memo

propsの値が等価か否かに応じて再レンダリングを決定する。等価であれば再レンダリングをせずにメモ化したコンポーネントをreturnする。

 

React.useMemo

メモ化された値を返すフック。

コンポーネントの再レンダリング時に値を再利用できる。値の不要な再計算をスキップすることでパフォーマンスの向上が期待できる。第二引数に依存引数を指定し、その配列の値によって、メモ化した値を返すか否かが決定する。

 

React.useCallback

React.memoでメモ化したコンポーネントuseCallbackでメモ化したコールバック関数を Props として渡すことで、コンポーネントの不要な再レンダリングをスキップできる。依存配列の値によって、メモ化した関数を返すか否かが変化する。

 

useCallbackReact.memoと併用するもの。以下のような使い方をしても不要な再レンダリングを防ぐことができない可能性があるので注意。

  • React.memoでメモ化をしていないコンポーネントuseCallbackでメモ化をしたコールバック関数を渡す

 

逆に言うと、子供のコンポーネントに対して関数を渡すようなことがなければ、特に useCallback を使う意味はないということです。(厳密に言うと PureComponent のように Props の変化に対して shallow equal で再描画判定を行うような場合限定なのですが、親が子のコンポーネントがどうやって再描画判定しているのかを気にするのも不自然な話なので、子に関数を渡している場合は useCallback で包んでおけばいいと思います。)

その他

レンダリングの方式をページに合わせて最適な形にするのが良さそう。最近だとSSGでもISRを用いて動的コンテンツに対応できたりするから、ページやサービスの要件に合わせて、最適なレンダリング方式を選定していく。

 

参照記事

zenn.dev

zenn.dev

qiita.com

qiita.com

times.hrbrain.co.jp

ja.reactjs.org

お盆に取り組んだことをまとめる

概要

今年のお盆は新型コロナウイルスの影響で帰省もできず、また旅行等もしづらかったので、普段時間が足りなくてインプットできていない事柄を一斉にインプットすることにしました。 どのような知識をインプットしたかをまとめていきたいと思います。

技術

知識補充

以下の項目に関して、ドキュメントや記事を読み漁りました。

  • Reactにおけるパフォーマンスチューニングに関して(React.memo、React.useMemo、React.useCallback、React dev toolの使い方等)
  • 状態管理に関して(recoilとredux toolkitのtutorialとその比較、そもそも状態管理がなぜ必要なのかを言語化)
  • apollo client仕様周りの確認(特にcache、local state周り)
  • 最新の動向のキャッチアップ(native esm周りとか)

自分は今エンジニア歴だいたい3年目くらいで、今はフロントエンドエンジニアとして仕事をしています。 しかし、最初の2年くらいは弱小フルスタックエンジニアとして仕事をしていたので、フロントエンド領域の深い造詣を持ち合わせているわけではありません。

そこで、お盆では「本業で現在使っている」かつ「深い部分まで理解ができていない」分野として、「パフォーマンス」と「状態管理」に主に焦点を当てて情報を収集していました。これらに関しては、今知見をブログにまとめているところなので、後ほど公開していきたいです。

上記調べている中で、最近Native ESM周りが熱いとの情報を得ましたが、大枠の話はなんとなく理解はできても、腹落ちはまだ全然できてないです。どこかでviteとかsnowpackのtutorialとかをやりながら具体的な部分と抽象的な部分の理解を進めていきたいです。

Native ESMについてはこの辺の記事を参考に周辺知識を見ていきました。 zenn.dev

zenn.dev

コンピュータサイエンス学習

recursionに取り組んでました。とはいえども進捗はあまりうめませんでした(約5%進捗を生んだくらい、他の知識のインプットが楽しくなってしまって時間使いすぎた)。

recursionとは、コンピューターサイエンスの知識を体系的に学ぶことができるオンラインプラットフォームで、今年の4月くらいから登録しています。僕の出身が私立文系で、コンピューターサイエンス関連の知識不足に対してコンプレックスを抱いていることから学習を開始しました。

今は上級の55%で、スタックやキュー、ツリー構造について学んでいます。この辺は自分でもudemyを使って学んでいたので、概要は知っていたつもりなのですが、おそらく実際に手を動かしてアウトプットすることが少なかったため、具体的にコードを書く場面になるとまだ戸惑う場面が多いです。

今後はrecursion中心に学習を進めていって、ひとまずは学部卒業レベルのコンピューターサイエンス知識を持っていると自負できるようにしていきたいです(ひとまずはrecursionを完璧に理解すればある程度目的は達成できると考えている)。

recursionist.io

読書・映画

一番時間を使っていたかもしれません。小説は読者にトピックやストーリーに対して、多大な解釈の余地を与えてくれ、そこに対して考察を巡らせたりするのが好きでやめられません。

小説

以下の作品を読了しました。

最近地元の本屋さんで行われている「村上春樹ブッククラブ」に通っている関係で、毎日村上春樹さんの小説を読んでいます。村上春樹さんはもともと大好きで、ほぼ全ての中長編は読んだことがあったのですが、改めて読み直してみると新しい発見があったり、また読書会参加者から自分が気づきもしなかった知見を分けてもらえたりして、とても楽しいです。

最近は小説からもっと知見を広げていきたいなと考えていて、村上春樹さん周辺の作家さんが書いた本を読んだりとか、小説に出てくる音楽を聴いたりとかするのにはまっています。

ビジネス本

お試しでflierというサービスに登録してみました。

www.flierinc.com

このサービスに登録すると、あらゆる本の要約を読むことができます。ビジネス本の内容は「主張 -> 根拠 -> 例示」の繰り返しだと思うので、だったら要約でよくねってなり、また、最近ビジネス本全然読めてないという課題から登録をしました。 以下のプロセスで合計10冊以上の本を読みました。

  • flierで要約を読む
  • amazonとかで本の目次を確認
  • 誰かが書いた解説を見てみる
  • 読書メーターに本に対する自分の感想を記入する

知識補填の観点からいうと、今のところとても有能と考えています。とりあえず1ヶ月継続してみようかと。

映画

以下の映画を観ました。

『シン・エヴァンゲリオン劇場版』に関して、一応新劇場版は全て観てから、最新の映画を観たのですが、正直全く理解できませんでした。Youtubeの解説動画をみてもその解説動画が欲しくなるくらい難解だったので、少しずつ理解していこうかと(こういう理解できないものを理解しようとする行為はすごく好きです)。

『持たざる者が全てを奪う』に関しては、パソコン一つで人生を変えていく話はエンジニアの僕にとってやはり魅力的でした。『ソーシャルネットワーク』とか『シリコンバレー』とかも結構好きで、今後も関連の映画を探っていきたいと思いました。

投資

このお盆で一気に知識をインプットして、少額から投資を開始しました。やったこととしては以下です。

  • 目標を決める
  • 『両学長リベラルアーツ大学』やトウシルなどのメディアから、投資をする際の基本情報を入手する
  • 既に運用を開始していてある程度実績を出している友人から運用の方法についてヒアリングする
  • 楽天証券で個別株を購入してみる
  • 楽天証券で積み立てNISA口座を開設して、積み立て設定をする

お金周りの知見は学校で教わっているわけでもないので、自分から情報を取りにいかないと一生身につきません。しかも知っているのと知らないのでは将来にかなり大きな差ができる分野なので、このお盆で一気に情報収拾をしてアクションまでつなげることができたのは非常によかったです。

両学長のyoutubeチャンネルはかなり有用です。

www.youtube.com

英語

英語勉強方法を見直しました。以下の手順で見直しました。

  • 英語を学ぶ目的を再定義・意識付け
  • 学習法調査
  • 実践

色々調べた結果、新井リオさんの学習方法がとても良さそうと思ったので、今週からそれを真似する形で学習しています。具体的には以下の感じです。継続すれば効果かなり出そうなので続けていきたいです。また、下記とは別で、ELSAというアプリを利用しているのですが、発音の矯正には最適だと感じています。

  • 日記を日本語で書く
  • 日記を英語にする
  • DMM英会話で日記を見てもらい、フィードバックをもらう
  • 復習する

新井リオさんのブログはこちら。

arairio.com

筋トレ・ランニング

継続的に行っていました。これまでは「モチベーションの維持」と「トレーニングメニューの最適化」が課題だったので、8月からは以下のアクションに取り組んでいます。

  • nike run clubを利用してランニングをする。具体的にはランニングの記録と、ナイキ側で提供しているチャレンジに挑戦している。
  • PPL(push, pull, leg)法に従って、トレーニングを分割する。

去年の8月から筋トレを開始しているのですが、成果として、体重を15kg落とすことに成功しています。次の1年で狙うのは体脂肪率を14%以下にして腹筋を割ることです。引き続き頑張っていきます。

まとめ

久しぶりに気になっていた分野の情報収拾をまとめてできたので非常に満足なお盆でした。

自分流学習方法の手順をまとめてみる

概要

お盆に色々な分野のインプットをした。 その中で自分に適した学習方法を体系的に整理できた気がするので、文字として残しておく。

モチベーション

今後インプット学習をするときに自分が困らないように、学習のプロセスを言語化しておきたい。

方法

学習のゴールを設定する

どのような目的に対してインプットを行うのかを定義する。ここをきちんと定義しないと、その後に学習する時間が非常に非効率になるので、この定義が一番重要。定性的な目標と、できれば定量的な目標を双方定義する。

ひたすらにインプットする

とにかくインプットする。インプットの手段はgoogle検索とYoutube、あとは本。 適切なクエリで検索をかけた後に、上位記事 or 動画をひたすら見まくる。第一ソースがあればもちろん第一ソースもみる。 観ているうちに、調べていることの大体の概要が入ってくる。技術とかに関しては細部は実際に触ってみないとわからないので、チュートリアルとかがあったらやってみる。

自分流にアウトプットする

上記で得た情報を整理してアウトプットする。手段はブログでもツイッターでも、はたまた自分しか見ないメモ帳とかでもなんでもいい。 自分の中で整理して、目に見える形を残すことが重要。このプロセスを挟まない場合は大抵理解度が低くなる気がする。

プロからフィードバックをもらう

自分が出したアウトプットに対して、その分野のプロからフィードバックをもらう。 ここが多分かなり重要、なぜなら、自分の努力の方向が正しいものかどうかが一人だとわからないので。自己流も大事だが、型を身につけることの方が大事。

修正する

プロからいただいたフィードバックに対して、改善できそうなところは改善を試みる。大体素直に助言を聞いた方がうまくいく気がする。

PDCAを回す

3~5を繰り返しながら、PDCAを回す。

まとめ

これまではそこまで意識はできていなかったけど、学ぶときは上記サイクルを回せばうまくいくような気がする。

LeetCode学習メモ: 20. Valid Parentheses

昨年からコンピュータサイエンスの自己学習を始めていて、leetcodeやらrecursionやらudemyに取り組んでいる。インプットは継続的に行なっているのだが、アウトプットの機会がほぼなく、自分の中で腹落ちして理解するために学習ログを残すこととする。

概要

Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.

An input string is valid if:

Open brackets must be closed by the same type of brackets. Open brackets must be closed in the correct order.

引用元: https://leetcode.com/problems/valid-parentheses/

方針

stackとhashmapを復習できる良問。 事前に「閉じる方のbracket」をkeyとして、「始まる方のbracket」をvalueとしたhashmapを用意する。 また、stackを用意して、stackの中にcharactersをpushしていく。

givenされたcharactersを展開して、「閉じる方のbracket」が出てきたとき、stackからpopした値が「始まる方のbracket」であればTrue、そうでなければFalseを返す。

コード

def isParenthesesValid(characters):
    stack = []
    hashmap = {")": "(", "}": "{", "]": "["}

    for c in characters:
        if c in hashmap:
            top_element = stack.pop() if stack else ''
            if top_element != hashmap[c]:
                return False
        else: stack.append(c)
    return True

【前編】論理的思考力を鍛える方法 ~ インプット ~

 去年の就活時に、「論理的思考力足りないよね」って何回も何回も言われまくった経験をした。

 

それが悔しくて悔しくて、去年の秋頃から、ひたすらに思考力鍛える訓練をしてきたわけなんだが、最近、過去自分比較でだいぶましに物事を考えることができるようになってきた気がする。

 

「同じように感じている人とかいるのかな?」とふと思ったのと、振り返りも兼ねて、自分が去年の秋頃から今までしてきたことについて振り返ってみる。

 

基本的に物事はインプットとアウトプットの繰り返しで習得していくものだと思うので、前編ではインプットで何をしたかを述べて、後編でアウトプットで何をしたかについて述べていく。

 

インプット方法について

インプットに関してはひたすら書籍を読みまくっていたので、その書籍を紹介する。

 

  • 思考論理分析 

    「正しく考え、正しく分かること」の理論と実践

 これは本当に名著。自分の思考のプロセスを非常にわかりやすく具体化してくれている本。一度この書籍を読んでおけば、その他の書籍の理解度も格段に上がると思うので、一番最初に読むのがおすすめ。

bookmeter.com

 

  • 考える技術

かの有名な大前研一さんが書かれた書籍。「一つの現象を予測するときに最初は因数分解をする」姿勢と、「ありふれた日常の中に考える材料を見つけること」って言葉が頭の中に残っている。途中無駄な部分(確か当時の政権批判をしていた箇所があったような)が数カ所あった気がするのでそこま飛ばしても良い。

bookmeter.com

 

  • 仮説思考 BCG流 問題発見・解決の発想法

物事を始めるときには何事もまず仮説から始めろということを強く主張している本。仮説を考える際に大事な3つの考え方、「反対側から考える」「両極端に考える」「ゼロベースで考える」は非常に参考になっている。

 

これは文系の人とか特に読んだ方がいいかも。文系って仮説を考えて検証するって癖がない人たちが多い気がしてるから、ある人たちにとっては読んだだけでブレイクスルーになると思う。

bookmeter.com

 

これまた有名なロジカルシンキング本。メッセージの条件として「課題」「答え」「相手に期待する反応」が必要であると記載されていて、それは今もかなり意識していたりする。

bookmeter.com

 

  • イシューからはじめよ - 知的生産の「シンプルな本質」

これまた名著。仮説の精度上げてこーぜー的な話(だった気がする)。個人的には「悩む」と「考える」の違いが一番頭に残っている。

bookmeter.com

 

とりあえず繰り返し読むこと

上記一応5冊紹介したが、それ以外にも「鬼速PDCA」や「思考の整理学」、「地頭力を鍛える」、「世界一優しい問題解決の授業」とかとか、いろんな本を読んできた。(鬼速と思考の整理学は少し違うけど)

 

んで、大体数冊読めばわかってくるんだけれど、大体どの本も大筋は同じことを言ってる。

 

結局大事なのって、問題の本質を探ること、縦の構造と横の構造を把握すること、正確な仮説を持つこと、それを実行することだと思うので(この辺感覚的な部分があるからまだ分解しきれてないけど)、その辺の肌感がつかめればひとまずいいのかなと。

 

なんかすごく雑に書いている記事なので、何か質問等あれば直接聞いていただきたい。

 

後編では上記本を使って得た知識をどのようにアウトプットしたかについて書いていこうと思う。