超一流を目指す新入社員の学習理論 ~個性を持つことの大切さ~

はじめに

こんにちは。情報セキュリティ部SMO2G・兼務イノベーションセンターテクノロジー部門MetemcyberPJの千坂知也と申します。今年新卒入社した一年目です。よろしくお願いいたします。

MetemcyberPJではOSSコントリビューターとして開発の業務に参加し、特にWebUI側の開発業務に多く携わってきました。

もともと大学院では、Pythonを使ってシミュレーション(厳密にいうとアルゴリズムの評価関数)のコードを書いていたもののWebUI系の開発言語は書いたことがなかったため、OJT先で一から学んだことになります。 言うまでもなく超一流のエンジニアではありませんが、OJTで気づいた(あるいは自分なりに感じた)学びや参考になった学習理論について特に学生、新入社員向けにまとめてみようかと思います。もし何か感じ入るものがあれば幸いです。

開発部署へのOJTとしての挑戦

初期配属として情報セキュリティ部に所属し、7月まで新入社員として研修を受けておりました。インシデントハンドリングや脆弱性に関する体系的な知識を会得する研修が多いなか、Webアプリ開発という研修があり、もともとモノ作りが好きだったことも相まって開発業務に興味を持ったのが始まりです。

情報セキュリティ部での一通りの研修が終わったのち、OJTとして新規事業開発しているイノベーションセンターに行ってみないかと打診され、これは良い機会だということでSBOM管理ソリューション「Threatconnectome」1の開発チームに参加させていただきました。大学院までPythonを使ってコーディングをした経験はあったものの、WebUI系の開発言語に触れたことはほとんどなく、一からのスタートでした。

まずは、自らが望んで行ったOJT先でぶつかった壁について紹介していきたいと思います。

実際の開発業務でぶつかった壁

開発規模が大きい

実際にイノベーションセンターに来て開発業務に携わり、まず最初に感じたことは「あたりまえだがWebアプリ開発研修のときと開発規模が違いすぎる」ということ。

既存機能を修正しようと思ったものの、まず該当のファイルがどこにあるのか分からない。ようやくそれっぽいファイルを見つけてもどこが該当のコードか分からない。該当のコードを見つけてもどう修正すればよいか分からない。とりあえず周りのコードを眺めつつ何とか真似できないかと試行錯誤してみました。修正できたものの単純な修正に1日かかってしまいました(今なら15分くらいで終わる気がします)。

レビュアーにとって分かりやすいコードを書けない

大学院生のときに書いていたコードってめちゃくちゃだったんだと今更反省した記憶があります。あのレベルのコードを業務で書いていたら、製品になりません。 コードの品質をあげるための機能としてPR(Pull Request:開発者のローカルリポジトリでの変更を他の開発者に通知する機能。機能追加や改修など、作業内容をレビュー・マージ担当者やその他関係者に通知し、レビューしてもらう機能)があります。

ここで大事だと感じたのがコードをレビュー側の人間の立場になって書くということ。レビュアーが読んで理解できないコードを書いたり、そもそも読む気にならないコードを書いたりしたらその時点でアウトです。私だと条件分岐が多すぎて複雑すぎるという理由ではねかえされたことがありました。

読みやすいコードを書くって今まで意識してこなかったのですが、これがすごく難しいわけです。自分なりに読みやすく書いてみたつもりでも、これどういう意味?って言われることもしばしばあります。

WebUIの開発において自分の想定と違う挙動になることがある

WebUIの開発では自分のイメージしていたものと違う挙動になることが多いと感じました。Pythonでシミュレーションのコードを書いていた時は数値計算のみを行っていたので想定通りの挙動になることがほとんどでしたが、WebUI系のコードは見た目に関わる部分を実装するため想定外の挙動になることが多くありました。例えば、ここのtoggle buttonのこの部分だけ背景色を変えたいなって思っても違う部分が変わるなどがありました。

勉強方法の確立の難しさ

上記の壁にぶつかって感じたのが、やはり知識をつけないことには始まらないということ。どうやら少しだけ調べてみると、より簡潔にコードを書く方法だったり、特殊な挙動をするコードの書き方などがあるようでした。そのような知識がないため、壁にぶつかったときの対処法の手段が乏しく、途方に暮れたことが何度もあったため、手持ちの武器を増やす必要があると感じました。

MetemcyberPJではWebUI側の開発言語としてJavaScript、フロントエンドライブラリとしてReactとReduxというものを用いているため、まずはReactやReduxなどの公式ドキュメントを見てみようと思いました。最初に感じたのは「難しい」。公式ドキュメントは分量が多いうえに全体的に同じテンションで書いてあるため、どこが重要なのかなど初見ではいまいち分かりませんでした。かといって全部読むってなると量が多すぎました(まぁ甘えですが)。

ちなみにReactとReduxに関して本記事の末尾でどんな技術なのかを簡潔にご紹介しております(詳しい内容になるととても収まらない分量になるので割愛します)。 興味のある方はご一読ください。

学習方法を確立する必要性

ReactとReduxの概要を見ると、学生さんなどで使ったことのない方だとなんのこっちゃって感じかと思います。 ただ先に述べた通り、実際にはこれよりはるかに細かい機能や理解しなければならない事柄を製品は多く含み、 かつそれを適切な箇所で適切に利用することで「コードの品質」は向上し、製品として成り立ちます。 少なくとも超一流と呼ばれるエンジニアの方々は当たり前のようにそれらを実践しています(もちろん、開発言語がJavaScriptとは限りませんが)。

さて、では私のように全くコードを書いた経験のない人間はどのように技術に関して理解していかなくてはいけないのでしょうか? そもそもどのような姿勢で学んでいけばよいのでしょうか?

実をいうと学生時代の勉強方法や(多くの学生や新入社員がやりがちな)資格取得のための勉強はあまり効率的な学習方法とは言えないと考えています。 それは現在の(基礎的な)IT技術と呼ばれるものが思っている以上に広範囲であり、かつ各技術が相互に関係しているため、横断的に取得していかなければならないからです。

以上のことから私自身が効率的に知識を習得するために一から学習方法を見直す必要があると感じました。 そのなかで、参考になった学習方法や学習理論、あるいはあまり良くない学習方法と感じたものを紹介していきたいと思います。

学習において大事だと感じたこと

私自身がOJTを通して大事だと思ったあるいは非効率的に感じた学習方法や参考になった学習理論についてご紹介します。

IT技術を体系的に(教科書的に)学ぶことは古い

従来の教科書的な勉強方法はIT業界では古いかもしれないということです。

学生時代は教科書を机の上に広げて、そこに書いてある理論なり公式なりをノートに書き写して学ぶのが一般的かと思います。 資格勉強でも何百ページもある参考書を広げて大事だと思われるポイントをノートにとるなり、マーカーをつけるなりするのかもしれません。

しかしこのような勉強法でIT技術を学ぶにはいくらかの問題点があるように感じます。 まず学生時代の勉強法に関しては、「学校の先生」という強力な解説つきなのと文部科学省の検定済教科書という あらかじめ体系立てて勉強できるように内容(適切な難易度の練習問題があるなど)、分量ともに精査された教材を使っているという点です。 資格勉強に関しても単一の分野(IT分野ならネットワーク、セキュリティなど)を決められた試験範囲内の内容に絞って記述されているだけなので、 実際の業務に直結するかというと実はそうではありません。資格に関しては自身が保持している能力の証明方法の一種であり、勉強の手段としてはあまり適していないと思います。 すなわちこのような勉強法は間違っているとまでは言いませんが、超一流になるためには遠回りすぎる気がします。

事実、ReactやReduxの公式ドキュメントを読んだところで、練習問題があるわけでもないし、そもそも分量が多すぎてよほどの英才でもなければ短時間であれだけを読んでその全体概要を理解するのは困難です。

また先に述べた通りIT技術というのはそのそれぞれが相互に関係しており、複雑につながりあっています。セキュリティ製品を作っているはずなのに、RTKqueryというデータキャッシングの技術を使わなくてはいけなくなったり、alembicというデータベース移行ツールを利用する必要があったりします。つまり極めて広い分野を横断的に習得する必要があり、そのための学習方法として学生時代のやり方などは非効率的であるということです。

効率的な学習方法

さて、では超一流になるための効率的な学習方法とは何なんでしょうか。 少なくとも現段階で私が効果あったと考えているのは、真似ること、恐怖心を持たないこと、(見知らぬ)多くの人と議論を交わすことになります。

まず、真似ることに関してです。多くの開発業務の現場では(開発以外の仕事でもそうですが)いわゆる超一流の方が一定数居ます。その分野の業務に長年従事し精通している方々です。 そういった方々は少なくともそれでお金を稼ぎ、ご飯を食べ続けているのですから、それ相応の成果を出し続けている方々なわけです。 まず(プライドを捨てて)この人たちのやり方を真似ることが重要になります。 はっきりいって公式ドキュメントや資格の勉強を丸一日行うより、1時間そういった方々の業務をみて、真似て作業したほうがはるかに有益かと思います。 よく言いますが、バタフライの泳法を覚えるのに一日中Youtubeでバタフライの動画を見るより、バタフライで泳げる人の真似を1時間した方が良いのと一緒です。 こうすることで、どういった手順で業務にあたり、どういった点に留意し、どういった知識が直接的に必要なのかを体験できます。

次に恐怖心を持たない(怖気づかない)ことが重要になります。 学生の頃や新入社員の頃だと、自分の立場や能力のせいでなかなか意見を言えなかったり、質問ができないという方が多いと思います(少なくとも私はそうでした)。 「こんな初歩的で未熟な質問して見下されないか」、「あの先輩(上司)忙しそうだし質問したらダメだよな」、「こんなこと言ったら(会社内での)自分の立場が悪くなる」 みたいなノイズが入って、理解が不十分なことをそのままにしておいたりタスクを適当にこなそうとするケースが多いのでないでしょうか。 でも考えてみると、 学生に関していうとプロ(超一流、即戦力)レベルの人間なんてごくごく一部のよほど優秀な方以外いません。 なので新入社員なんて(当然私も含めて)ほぼ全員未熟です。未熟で当然なんです。 あと先輩(上司)なんて全員何時でも忙しいです。役職が上がれば上がるほど忙しいはずです。 自分なりの意見を述べて、会社内での立場が悪くなるのだったら、さっさと転職しましょう。 要するに学生だと教授、新入社員だと先輩・上司という「教師」がいるはずなのに、それを利用しないという人間が多いのだと思います。 という風に考えるとそもそもそんなノイズのために自分の理解が不十分なままなのはもったいないというか、愚策であることが分かります。 (1つ注意なのが、あくまで言葉遣いには気を付けるべきかと思います。積極的に質問、意見を通すことと口汚いことは全く別です。)

最後に多くの人と議論を交わすこと。 実際の業務遂行にフォーカスした外部の研修の受講機会や何らかのイベントへの参加を促されたら積極的に挑戦することです。 実際の開発現場にいても、普段は慣れ親しんだ方々としか会話や議論をしません。それもすでにチーム内で凝り固まりつつある価値観のもとでです。 全く出会ったこともない人と議論を交わすことで、想定もしていないような観点からの指摘や意見を受けることができ、新たな知見を得ることが多くあります (学生だと学会がこれにあたるのかもしれません)。

私自身、OJTでMetemcyberに来て、直接的に成長につながったと感じたのは上記の3つです。

ところでこのように学ぶためには実をいうとマインド(学ぶ姿勢)が重要だと考えています。 というのもそもそもの話としてある程度の学習意欲やバイタリティがないと上の3つなんて実行しうるわけがないのです。 超一流になるための学習意欲の根底部分を支えるのはマインドです。 次は、このマインドについて私なりに学ぶことが多かった学習理論を将棋と野球の話を交えてしてみようかと思います。

学習の高速道路

完全に私事なんですが将棋が好きで、さまざまな棋士の対局を見るのが趣味の1つです。棋士の中でも2017年に永世七冠を達成されたまごうことなき大レジェンド羽生善治九段はその人柄まで含めて大ファンなのですが、彼は2006年にIT企業の経営コンサルタント梅田望夫氏のベストセラー「ウェブ進化論」のなかで 「学習(知)の高速道路」という言葉を用いて現代将棋の学習環境の在り様を表現しています[1]。 これはIT技術の進歩とインターネットの普及が進んだことにより、従来は対局機会を得ることが困難であった優れた対戦相手と多くの対戦をこなす機会が得られるようになったことで 誰でも効率的な学習環境で将棋を学ぶことができる、ということを指した言葉です。

しかしその後、羽生九段は「高速道路を走り抜けた先では大渋滞が起きている」とも述べています。これは誰でも簡単に効率的な学習環境の中で学ぶことができるため、ある程度の学習を積んだもの同士の間だと、他者よりも抜きんでることが困難になっていることを表した言葉です。 そして彼は2009年に同じく梅田望夫著「シリコンバレーから将棋を観る」のなかで以下の式を示しました[2]。

$超一流 = 才能 × 対象への深い愛情ゆえの没頭 × 際立った個性$

右辺の三要素が超一流になるため必要なものであり、なかでも際立った個性が重要だと羽生九段は説いています。つまり他者よりも抜きんでるためには誰にもない際立った個性が必要なわけです。そしてこの式は将棋以外のどの分野にも当てはまるとも述べました。

際立った個性

別の例を1つだけ挙げますと、今や世界的スーパースターであるMLBのロサンゼルス・ドジャース所属の大谷翔平選手も際立った個性を持った人物と言えます。 大谷選手は近代プロ野球において極めて稀な投手と野手を兼任する、いわゆる二刀流の選手です。 当初こそ多くの野球有識者やプロ野球OBの方々は二刀流に関して反対をしていました。 しかしNPBで唯一3度の三冠王を獲得した落合博満氏は大谷選手がプロ野球選手になりたての2013年にNHKのサンデースポーツという番組にて、「二刀流をやることに大賛成。 これほどの個性を持った選手は少なくともここ30~40年出てきていない」と述べました。 大谷選手は言うまでもなく類まれな才能の持ち主であり、誰よりも深い野球への愛情を持ち、それでいて誰にも負けない際立った個性があったからこそ、超一流のプロ野球選手になれたのではないでしょうか。 まさに先に羽生九段が述べた超一流の式になぞらえているわけです。

高速道路の高速化

一方で羽生九段は2017年に自身著の「人工知能の核心」のなかで「学習の高速道路を走るなかで、大量の情報を得ることに追われて、かえって自分の頭で課題を解決する時間がなくなっていくことを懸念している」とも述べています[3]。 実をいうと、生成AIが出現してからこの懸念はますます深まったように思います。「AIが何でも課題解決してくれるから自分の頭で考える必要はない」と盲信している方が多いのではないでしょうか。 生成AIの出現以後、学習の高速道路はさらに高速化したように思います。

正直なことを申し上げますと、私自身もいわゆるChatGPT、GitHub Copilotなどはよく利用します。といいますか利用しない日はないといっても良いくらいです。 単純な処理を行うコードやその場に適した文脈などを素早く考えることは自分がやるより、もはやAIにやらせた方が効率的だと感じているからです。 他方で、あくまで出力結果を人間の目で精査する必要はあります。生成AIは要求や質問に対し、優れた回答を素早く出力するところまでは高い精度でできるようになっていますが、 それでも絶対ではありません。さらに言うとそもそも複雑な状況下ではその要求や質問自体ができないケースもあります(AIに正確な指示を与え、期待する出力を得るためのプロンプトを設計・改善するプロンプトエンジニアリングというのはありますが)。

そのため、「AIが何でも課題解決してくれるから自分の頭で考える必要はない」という盲信は些か危険を帯びている気がします。 AIを完全に信じ切ってしまうと、その出力結果の正誤を判断できずに結果として想定と全く違った挙動をおこなうシステムを構築しかねません。 つまり、ここでも知識を十二分に備えたうえで出力結果の正誤を判断し、AIを適切に利用する能力を身に着ける必要があるということです。

言い換えれば、少なくとも現在のIT業界における超一流と呼ばれる人たちは巧にAIを活用できる人材であり、生成AIの使い方まで一流な人間になります。 恐らくこの能力は、IT業界に関わらず、これから先の世の中で超一流と呼ばれるために確実に保持しなくてはならないものだと思われます。

AIを盲信せず、むしろAIを巧みに利用できる人材になる必要があるわけです。

超一流・一流になるために目指すべき人物像

よく学校の先生や会社の先輩、上司がさまざまな事柄(学校なら勉強、仕事なら今自分が従事している業務)に対して努力・研鑽せよ、なんて言います。でも思うのですが、上の式の右辺のいずれもが欠けている状況で誰が努力なんてできるのでしょうか? その分野に関する才能もなく、愛情や興味もなく、個性らしい個性もない状況で努力ができるとしたらきっとその人はある意味で人知を超えた強靭な精神力の持ち主だと思います(学校の勉強に関しては多くの場合において、それが強要されてしまっているのが現状ではありますが)。

そういう意味で言うと、3つとも携えるのがもちろん良いのでしょうが、そうはいかないのが現実でもあります。個人的にはできるだけ愛情、興味を持てる分野を探すこととその中で自分だけの個性を作り出すことが重要なのだと感じています。才能に関しては自分で制御できない部分が多いと思っているのが正直なところなので、せめて対象への深い愛情ゆえの没頭と際立った個性を持てるように意識してみるわけです。そうするときっと超一流とまではいかなくとも一流にはなれるのではないでしょうか?

NTTコミュニケーションズが与える学習の機会

まず私が感謝したいのはOJTという形でMetemcyberPJに参加させていただいて開発業務の学びの機会を頂いたということ。 先の式において、私自身に自負できるほどの対象への深い愛情があるかは定かではありませんが、好きなこと(興味のあること)を挑戦する機会を提供してくれる会社であることは間違いないです。

1つだけ誤解しないでいただきたいのは簡単な道を選ばせてくれるというわけではないという会社ではないということです。 むしろ自ら険しい山を登ることを奨励し賛同してくれる場所だと感じました。

おわりに

非常に拙くかつ偉そうな文章となってしまいましたが、最後までお読みいただきありがとうございます。 開発系の業務に携わってみたいと思いつつも、いざやってみると難しいことだらけ。それでも今学んでいることがおぼろげながらでも自分の未来につながっているという実感を得ています。

向学心があり、好きなことをとことん突き詰めたいという方はぜひNTTコミュニケーションズの門戸を叩いてみてはいかかでしょうか。

以上で、NTT Communications Advent Calendar 2024 11日目を終わらせていただきます。

補足資料:ReactとRedux

Reactとは

Reactは、UIを小さな再利用可能な「コンポーネント」という単位に分割して開発できるフロントエンドJavaScriptライブラリです[4]。 コンポーネントとはUIを構成する要素で、例えばクリックするとユーザー名を表示するという処理を行うコンポーネントなどがあげられます。 また、Reactではコンポーネントごとに「状態(state)」というものを管理し、状態が変更されるたびに自動的にUIが再描画されるという特徴があります。 ここで状態とは、簡単に言うとコンポーネントが持つデータのことです。 例えば、+のボタンを押すとカウンターの数字が1ずつ増えるという簡単なアプリを例にすると、 画面が描画されている状態ではカウンターの数字は0である必要があります。この「カウンターの数字」をReactでは「状態 (state)」と呼びます。 そして、+のボタンが1回押されるごとにカウンターの数字に1を足すという処理を行い、状態を更新する必要があります。 この状態の更新は、状態に変化があるたびに行われます。

Reactは状態とUIの同期が自動で行われるため、手動でDOM操作(ユーザーの操作に応じて動的にコンテンツを更新したりすること)を行う必要がないという利点があります。

では、ChatGPTに提案してもらったJavaScriptのみの場合と、Reactを導入した場合の簡単なコード例を見てみましょう。

JavaScriptのみの場合

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JavaScript Only Example</title>
</head>
<body>
  <div>
    <!-- 初期状態のテキスト -->
    <p id="text">Click the button</p>
    <!-- ボタン -->
    <button id="button">Click me</button>
  </div>

  <script>
    // ボタンとテキスト要素を取得
    const textElement = document.getElementById('text');
    const button = document.getElementById('button');

    // ボタンのクリックイベント
    button.addEventListener('click', function() {
      // テキストを変更
      textElement.innerText = "Hello, World!";
    });
  </script>
</body>
</html>

JavaScriptのみの場合では、DOM操作する際、 どのタイミングでどのように変更するかを明示的に記述する必要があり、 コードが複雑になりやすいというデメリットがあります。 また、状態が変更された際にUIを手動で更新する必要があります。

// ボタンのクリックイベント
button.addEventListener('click', function() {
  // テキストを変更
  textElement.innerText = "Hello, World!";
});

本コードでは上記の部分が該当の箇所になります。巨大な開発規模になると、 このように手動でDOMを直接操作するのは非常に大きなコストとなります。

次に同じ処理を行うReactのコードを見てみましょう。

Reactを導入した場合

import React, { useState } from "react";

function MyComponent() {
  const [text, setText] = useState("Click the button");

  const handleClick = () => {
    setText("Hello, World!");
  };

  return (
    <div>
      <p>{text}</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

このコードでは、MyComponentという名前のコンポーネントを定義しています。 useState("Click the button")という部分にて初期値(初期状態)として「Click the button」という文字列を設定し、 textという変数にその状態を保持させます。 setTextはtextの状態を更新するための関数であり、 この場合ボタンをクリックしたときにhandleClickという関数が実行され、そのなかでsetTextが実行されることでtextの状態を更新しています。 今回の場合、setText("Hello, World!")にてtextの状態を「Hello, World!」に更新します。

Reactを使ってみた個人的な感想

最初こそ全く意味が分かりませんでしたが、ある程度の理解ができた後だとなるほどReactを導入したほうが確かに直感的で分かりやすい。 useStateを使った状態管理ができない状況でコードを書くというのがもはや想像できない状況ですらあります。 しかしながら、Reactだけだと各状態はそのコンポーネント内部で完結しており、親コンポーネントや他のコンポーネントと状態を共有するために プロパティ(props)を介して渡す必要があります。これは大規模な開発になればなるほど、状態管理が複雑化することを意味しています。 そのデメリットを克服したのがReduxというライブラリです。

Reduxとは

Reduxは、状態をコンポーネント内ではなく、アプリケーション全体で一元管理するためのフロントエンドJavaScriptライブラリです[5]。 Redux自体はReactとは独立した別のライブラリですがReactとの相性が良く、ほとんどの場合においてReactと組み合わせて使われます。

Reduxを導入することでReactのコンポーネントは、 Reduxストア(アプリケーション全体の状態を一元管理するためのオブジェクト)というところから必要なデータを取得し、 状態を変更するためのアクションをディスパッチ(dispatch)するということを行います。 ディスパッチとはアクションをストアに送るためのメソッドのことで、アクションは状態を更新するための指示を含んだオブジェクトになります。 これをストアに送ることで、リデューサー(アクションに基づいてアプリケーションの状態を更新する関数)が実行され、新しい状態が作られます。 このようにReduxでは、状態の変更をReduxストア内のリデューサーによって管理します。 Reduxは状態のグローバル管理するライブラリということになります。

では、こちらもChatGPTに作成してもらった簡単なコードを見てみましょう。

Reactのみを使った場合

import React, { useState } from 'react';

// Counterコンポーネント:useStateを使ってカウントを管理
function Counter() {
  const [count, setCount] = useState(0); // 状態変数countとその更新関数setCountを定義

  const handleIncrement = () => {
    setCount(count + 1);
  };

  const handleDecrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>Increment</button>
      <button onClick={handleDecrement}>Decrement</button>
    </div>
  );
}

// Appコンポーネント:Counterコンポーネントを表示
function App() {
  return (
    <div>
      <h1>Counter Example (Without Redux)</h1>
      <Counter />
    </div>
  );
}

export default App;

このコードでは、Counterコンポーネントというものを含んでいるAppコンポーネントが最初に表示されます。 Counterコンポーネントは、countという変数によって状態を管理し、その状態を表示するものです。

Incrementボタンをクリックすると、handleDecrement関数コンポーネントが呼び出され、 setcountによってcount変数の値が1増えます。同様にDecrementボタンがクリックされると、handleIncrement関数コンポーネントが呼び出され、 setcountによってcount変数の値が1減るという処理を行っています。

状態が更新されるたびに、Counterコンポーネントは再レンダリングされ、新しいcountの値が画面に反映されます。 次にReduxを利用した場合のコードを見てみましょう。

Reduxを導入した場合

// actions.js
export const increment = () => ({
  type: 'INCREMENT'
});

export const decrement = () => ({
  type: 'DECREMENT'
});

// reducer.js
const initialState = {
  count: 0
};

export const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

// store.js
import { createStore } from 'redux';
import { counterReducer } from './reducer';

export const store = createStore(counterReducer);

まず、こちらはアクション(actions.js)、リデューサー(reducer.js)、ストア(store.js)を定義したコードとなります。 今回の場合、actions.jsにてincrementとdecrementという状態を更新するためにディスパッチするアクションを作成する関数を定義しています。 reducer.jsでは現在の状態とアクションを受け取って、新しい状態を返すcounterReducerを定義しており、この場合カウントを増減させるためのロジックを含んでいます。 store.jsのcreateStoreでストアを作成し、リデューサーを引数として渡して状態を管理します。ストアは状態を保持し、 アクションが送られるとリデューサーを通じて状態を更新するという処理が行われます。

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';

function Counter() {
  // Reduxの状態(store)のcountを取得
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  const handleIncrement = () => {
    dispatch(increment()); // INCREMENTアクションをディスパッチ
  };

  const handleDecrement = () => {
    dispatch(decrement()); // DECREMENTアクションをディスパッチ
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>Increment</button>
      <button onClick={handleDecrement}>Decrement</button>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Counter Example (With Redux)</h1>
      <Counter />
    </div>
  );
}

export default App;

こちらのコードは実際のUI部分を実装しているコードになります。 Counterコンポーネント内のボタンをクリックすると、handleIncrementやhandleDecrementが呼ばれ、 それぞれincrement()やdecrement()アクションがディスパッチされます。 これらのアクションは、Reduxストアに送信されます。

ストアは、送られてきたアクション(INCREMENTやDECREMENT)に基づいて状態を更新します。 この処理は、counterReducerというリデューサーによって行われることになります。 ストアの状態(count)が更新されると、useSelectorフックを使って最新の状態がCounterコンポーネントに反映され、 画面に表示されるカウントが増減されます。

Reduxを使ってみた個人的な感想

こちらはReactよりも初見はさらに意味が分からないかったというのが正直なところです。 ただ状態管理をグローバルで行うことができるため、MetemcyberPJのように大規模な開発になると使った方が 明らかにコードの保守性や拡張性が向上するのかと思います。 実はこのReduxにはToolkit(公式ライブラリ)としてデータフェッチング(データの取得)、キャッシュ管理を簡潔かつ分かりやすく行う RTKqueryというものもありますが、こちらの内容まで書き出すとものすごい分量になるので、今回は割愛させていただきます。

参考文献

  1. 梅田望夫, 『ウェブ進化論 本当の大変化はこれから始まる』, ちくま新書, 2006.
  2. 梅田望夫, 『シリコンバレーから将棋を観る―羽生善治と現代』,中央公論新社, 2009.
  3. 羽生善治, 『人工知能の核心』, NHK出版, 2017.
  4. Meta, 『React Webとネイティブユーザーインターフェースのためのライブラリ』(https://ja.react.dev/learn/describing-the-ui), 2024.
  5. Dan Abramov and the Redux documentation authors, 『Redux A JS library for predictable and maintainable global state management』(https://redux.js.org/tutorials/essentials/part-1-overview-concepts), 2024.

  1. 開発プロダクトの内容に関しては今回の記事の本旨から外れるため割愛させていただきます。
© NTT Communications Corporation 2014