ぴよがち

技術的な話をします。みんなで強くなりましょう。

急に思い立って、社会人が修士を受けた話(一般受験RTA)

早稲田の情報理工の修士(一般受験)に受かったので、2023年4月から働きながら学生もやることになりました。

出願RTAを含めてまあまあ稀有な体験をしたので、衝動的に大学院に行きたくなった後世の人のためにスケジュール感と注意点を書き残しておきます。

だいたいエンジニア向け。

TL; DR

  • スケジュール感
    • 出願締切の14日前に思い立ったところ、少し余裕を持って出願できました。
      • 少しでも院に行きたいと感じた日に、まずTOEFL の受験を申し込みましょう。受験までに2日から1週間、その後スコアの開示までに4-8日はかかります。
      • できるだけ早く教授に連絡を取り、研究室を見学しに行きましょう。(教授と仲良くなっておくのは非常に重要です。)
    • 専門科目だけであれば、出願後の1ヶ月間に仕事の後で学習すれば何とかなります。
      • 受けてないですが、東大の院は一般教養の数学までやる必要があります。出願前にも1-2ヶ月くらい学習する時間があると良いと思います。
  • 注意点
    • 普段から英語力は身につけておきましょう。
      • 日本国内の大学院を受ける分には90点あればいいので、GitHub などの開発者コミュニティや YouTube あたりで Reading と Listening だけ鍛えてれば大丈夫です。
    • 出願締切の10日前までにはTOEFLを申し込めなかった場合は、その回の受験は難しいです。
      • 多くの場合、社会人枠や冬季受験枠など複数回チャンスがあります。調べましょう。
    • 普段から教授との縁を作れるように、心がけておきましょう。

前提条件

  • 普段の仕事: ソフトウェア開発エンジニア
    • 仕事としては 4年目。高校生くらいから色々作ってました。
    • 普段は Google検索 が主なお仕事。
      • フロントエンドとバックエンドでフルスタック気味にいろんな案件で開発しています。
  • 経済学士(19年卒)
    • GPA は1.67で、だいぶ低いです。
    • 学部で多少 CS 関連の単位を取っており、それらは全てGPA3か4の評価でした。
      • 経済学だけのGPAどんだけ低いんだ...

出願を考え始めた時期と理由

時期:2022年5月末。

そろそろ転職して給料爆上げしたいなと思って探し始めましたが、まともな求人は軒並み CS の学位が Must 条件だったので出願を決意しました。

出願対象の選定

ソフトウェア工学を取り扱っていそうな研究科で、手の届きそうなところを探しました。

検討したのは、以下の2つです。

どちらも6月第1週の締切でかなりギリギリでしたが、最速でTOEFLさえ受ければ間に合う日程でした。

結局、

  • 試験範囲
    • 早稲田の方が一般教養の数学がない分簡単そうだった
  • 教授とのコネ
    • 知り合いの知り合いな教授がいて、取っ掛かりを作りやすかった
  • 卒業の大変さ
    • 働きながら修士の学位を取る予定なので、あまり大変な環境に行くと何年かかるかわからない

の3点の理由で、早稲田に出願することにしました。

日記

2022年5月27日(木) 外国人とおしゃべり

そろそろ転職しようかと思ってLinkedInで連絡してきた方とお話してみましたが、まともそうな求人は軒並み CS の学位が Must 条件でした。

大学院に行きたくなりました。

2022年5月28日(土) 出願を決意

マッチングアプリで出会った人と昼に水族館に行ってきましたが、そんなに好きでもない人間と会って話すより勉強したいと改めて感じたので、お別れして院試に集中できる体制を作りました。

その日の夜に修士のプロ(3周くらい修士課程をやっているはず)であるところの 多動卿 @mouroutai の家に押しかけさせていただいて、
TOEFL の申し込みと出願候補校の出願・試験スケジュールを確認しました。

ついでに参考書まで借りてきました。圧倒的感謝🙏🙏🙏

5月29日(日)

ねじを買ってきて、明日のTOEFLに備えました。

オンサイト版のTOEFLは1週間後くらいにしか受けられず、出願に間に合わないリスクが高かったので Home Edition で受験しました。翌々日には受けられて神です。

家で試験を受けるには机を片付ける必要がありますが、普段使っている机の上を片付けるのは不可能なので、折りたたみの机を引っ張り出してきました。

すると、ボルトがどこかに行っていたので、買いに行く必要がありました。
調べると、秋葉原の「西川電子部品」さんが色々なネジを取り扱っているとのことだったので、机の脚を1つ持って出かけました。

店員さんに相談すると実際に試しながら5分くらいで完璧なネジを探し当てることができ、無事購入することができました。
価格も1本30円くらいで、想像よりだいぶ安く済みました。

パンクしていた自転車を修理に出し、電車で秋葉原に行きネジを買った後で自転車を回収する完璧な立ち回りができてとても気持ちよかったです。

帰宅してからは、TOEFL公式の模擬テスト を受けて、明日の試験に備えて20時ごろ就寝しました。

5月30日(月) TOEFL受験

いつもの如く9時から仕事なので、朝3時すぎに起きて試験を受けました。

かなり長丁場で色々トラブルはありましたが、何とか完了することができました。

6月2日(木) 研究室見学

先週の土曜日にメールして教授にアポを取っていたので、この日の夕方にゼミを見学させていただきました。

かなり歓迎してもらえて、研究室の皆様とも色々話せてとても楽しかったです。

具体的にどんな研究をしていきたいかの目星もつけることができたので、教授に出願するのでよろしく〜、とメールしておきました。

6月7日(火) 出願

6日の午前中にTOEFLの結果が出たので、余裕を持って7日に出願できました。

勉強がんばりましょう!

6月中頃まで

とりあえず離散数学分野の知識が全然なかったので、参考書を1冊読みました。
多動卿おすすめのこの本はかなりいい感じでした。

www.amazon.co.jp

また、仕事終わってから過去問をぼちぼち解いていきました。

職場では受かった時に便宜を図ってもらえるように、部課長に対して話をしておきました。

最近弊社では、従業員のリカレントを推進している(多分中年層の社員に対してでしょうけれども)こともあり、割とすんなり受け入れてもらうことができました。

6月後半〜7月中頃まで 仕事が忙しい

6月から始まっていた案件がいよいよ忙しくなり、勉強する時間をあまり取れなくなってしまいました。

こういう忙しい時にも頑張る気力が欲しいところですが無いものねだり。。

結局、

  • 試験前週の土日でパワポ作成
  • 7月13日(水)〜15日(金)で過去問4年分を復習

って感じで試験に臨むことになりました。

7月15日 試験1日目

1日目は筆記試験でした。

大問1 の「ハノイの塔」の問題を完答でき、それ以外も割といい感じでした。

電気回路は白紙、論理回路もXORの回路記号がわからなくて変な記号で書いた気がしますが、それ以外は割と人間並の回答を書けました。

かなり上振れした気がします。

7月15日 試験2日目

2日目は面接でした。
担当教授を含めた4人の面接官とお話ししました。

持ってきたパワポで研究計画を説明し、その後質疑応答という流れでした。

プレゼンでは、「開発現場での実務経験を活かした視点!」とか、「業務で鍛えた実装力!」とかでアピールしながら研究計画を話しました。
パワポやプレゼンの構成を考える上では、以下が参考になりました。

研究計画の発表について

質疑応答では、「仕事しながら研究、大丈夫?」みたいな質問をされましたが、「頑張ります!」で押し通しました。

試験が終わった後で、しおん君たちと温泉に行きました。とても気持ちよかったです。

7月29日 合格発表

なんか受かっていました。

上振れ最高!

まとめ

というわけで、大学院受験 RTA に際しては、

  • 出願で一番日程がシビアなのは英語の試験です。
    • TOEFL iBT Home Edition なら、申し込みの翌々日受験→翌週出願が可能なので、11日前に思い立てば間に合う可能性が高いです。
    • TOEFL受験時の身分証明書はマイナンバーカードでも大丈夫ですが、日本語の文書は確認に手間取るのでパスポートがあるとより良いです。
  • 学習は、意外と何とかなります。
    • 専門科目は、範囲が狭いです。
      • 寄り道も大事。
        • 過去問やった時に漸化式の考え方を思い出しておいたり、ハノイの塔のWebアプリで遊んでいたのが本番でも生きました。
    • 一般教養も、追加で数ヶ月あれば対策できる程度の範囲です。
  • 文系学部卒でGPAが1.6台でも、実務経験がマッチすれば入れてくれます。
    • 実装力は重要だと思います。少なくとも何かしら研究室に貢献してくれそう、と思ってもらえれば入れてもらえる可能性が上がるかと思います。

という感じの気づきを得ることができました。


というわけで、みなさんもぜひ軽率に大学院を受験してみましょう!

ご質問などあれば、いつでもこのブログや Twitter @lagyu_piyo にコメントください。

twitter.com

ご拝読ありがとうございました。

React / Reduxの推奨するテストの書き方の変遷まとめ

ここ数年の、React / Redux でユニットテストよりインテグレーションテストを重視するようになった背景についての日本語の情報が少なかったので書きます。

この記事の内容は、Redux公式ドキュメントの内容とそのコミットログ、またReactコミュニティ Reactiflux のDiscordでの会話などを参考に執筆したものです。

主に参考にしたページ・ディスカッション:

TL; DR:

  • Redux のドキュメントでは、2021年中ごろまでは Redux のロジックや selector を React コンポーネントから分離して 単体でテストすることを公式ドキュメントで標準とされていた。*1
  • 2021年7月以降は、React コンポーネントと可能な限り一体で(「インテグレーション」で)テストすることを推奨している。*2
    • Redux 単体のユニットテストを書いてもいいが、まずはインテグレーションテストでテストできないかを考えるべき、という方針。*3

時期ごとのまとめ

2018年(React Testimg Library(以下、RTL)は2018年3月リリース)ごろまで

  • Reactでのテストは、テストランナー(jest/mocha)+ アサーションライブラリ(chai) + enzyme が主流。

基本的には、コンポーネントShallow Rendering でテストし、Redux や メソッド*4 などのロジックは

Discordさかのぼった感じ、RTLリリース前の時点ではインテグレーションテストは「コストが高く見合わない」という意見が多かったみたいです。*5
また、インテグレーションテストを実装することでユニットテストが不要になるというアイデアに対しては、概して否定的なコメントが寄せられています。*6

RTLリリース後(2018年後半~)

React Testing Library(RTL)は、Reactのインテグレーションテストを実装するためのライブラリです。2018年3月にリリースされました。
RTLにより、インテグレーションテストの実装コストが大きく下がりました。

これにより、Kent C. Doddsさんの提唱する Testing Trophy のインテグレーションテスト・ユニットテスト比を実現しやすくなりました。

kentcdodds.com kentcdodds.com

Redux では、2021年までには*7 ユーザが実際に利用するコンポーネントのUIこそがテスト対象であり、それ以外の Redux (や Hooks) はすべて実装の詳細として扱うのを原則とすべき、と公式ドキュメントでも明記されるようになりました。*8

  • コンポーネントを介さない、純粋なユニットテストを書きたい場合は容易に書くことができます。ただし、本当にそれが必要かを考えてから書いてください。」ドキュメントでは念押しされています。*9
  • RTLのメンテナ達の間では、インテグレーションテストで確かめられる内容をユニットテストで実装することは悪だと考えている人もいます*10 が、Kent C. Dodds さんは必ずしもそういうわけではない*11 みたいです。

2022年時点でのReduxのテスト実装方針

Reduxコミュニティがインテグレーションテストをメインで実装することを推奨しているわけなので、原則インテグレーションテストのみを実装することにすればよいかと思います。
ユニットテストは、複雑で、インテグレーションテストでカバーするのが難しい部分においてのみ適用するのが良いでしょう。

実際のところ、ここ数年のRedux Toolkit (以下、RTK) と RTK Query の発展も、ユニットテストの省略を後押ししてくれているのではないかと思います。

従来フロントエンドのロジックといえば、バックエンドAPIと通信しデータを適切にキャッシュすることでした。
RTK と RTK Query がこのキャッシュ管理のロジックのかなりの部分を吸収してくれるようになった現代フロントエンドでは、ロジックの大部分は自前で実装するものではなく、RTK・RTK Query をビジネス要件に合う形で適切に呼び出すものへと変化してきているように感じられます。

このように薄くなったフロントエンドのロジックに対してユニットテストを書く意味はあまりなく*12、インテグレーションテストとしてコンポーネントを介してビジネス要件を満たすことができているかを確かめることに時間を使うほうがかなり有意義だと私は考えています。

*1:https://github.com/reduxjs/redux/pull/4116

*2:https://redux.js.org/usage/writing-tests

*3:https://redux.js.org/usage/writing-tests#guiding-principles

*4:当時はClass Component全盛期で、Function Componentが使われるようになるには 2019年2月のHooksの実装 を待つ必要があった。

*5:https://discord.com/channels/102860784329052160/105703173393485824/423150735354494986

*6:https://discord.com/channels/102860784329052160/105703173393485824/423143978536402944 ここでの会話の結論: ユニットテストとインテグレーションテストの確認するポイントが異なっており、どちらもあるに越したことはない。

*7:https://github.com/reduxjs/redux/pull/4116

*8:https://redux.js.org/usage/writing-tests

*9:https://redux.js.org/usage/writing-tests#guiding-principles

*10: このIssueのプルリクでは、hookのユニットテストを書くこと自体がやり玉に挙げられている。結局使えなくなった。

*11:どっちでもよさそう です。How to test custom React hooks にあるように、色々考慮した結果ユニットテストにしよう、ってのは全然ありだと思っていそうです。

*12:ビジネス要件に対して「適切に」呼び出していることを確かめたいのに、ユニットテストでは内部実装に対して「適切に」呼び出していることを確認することしかできません。

フロントエンドのテストについて

同僚とフロントエンドのテストをどう扱うべきか議論になったので、考えをまとめるためにメモ。

私の意見としては、原則インテグレーションテストとして、APIと外部サービスだけmockした状態でコンポーネントのテストだけ書くのが一番メンテしやすいんじゃね、って感じです。

React Testing Library / Redux もそのテスト方針を推奨しているし、多分ベストだと思うんだけどなぁ。。

前提

  • React での開発(多分Vueでもほぼ同じかと思います。)
  • Redux (Redux Toolkit) を利用。
  • static な実装のテストには、TypeScriptを利用する想定。

原則

  • インテグレーションテストを旨とするべし
  • プロジェクト内の実装はできる限りmockしない
    • Writing Tests | Redux
    • 認証など、外部通信などが絡むライブラリは必要に応じて mock する。
  • APIとの通信は msw あたりでいい感じに mock する
  • コンポーネントから分離したロジックに関しては、境界値の判定やテストの実装コストの問題もあるため、ユニットテストを併用してもよい。

反論など

  • Testing Pyramid 提唱側の Martin Fowler による、インテグレーション重視の風潮に対する記事

感想

プロジェクトごとに実装方針を変えたりしながらフロントエンドを実装してきましたが、個人的には

  • インテグレーションテストを各コンポーネントに対して(Reduxや内部の関数は原則mockせずに)実装し、テストしづらい項目がある場合のみユニットテストを書く

という方針でいくのが、リファクタリングしやすく実装の妥当性について十分に確信を持てて良い、と現状考えています。

同僚にはユニットテストをもっと重視すべきと主張している人もいるので、また考えが変わったら書こうと思います。

Redux Toolkit Query、便利すぎだろ!

Redux Toolkit(以下、RTK)と RTK Query が、Reduxの面倒な部分を全部いい感じに解消してくれて感動したので共有します。

TL; DR:

RTKとRTK Query、特にRTK Query最高すぎ!!!
ぜひ一度RTK Queryを使ってみてください。誰でもいい感じにReactとReduxのパワーを使いこなせるようになり、超おすすめです。

使い方(公式): redux-toolkit.js.org

Redux Toolkit Query の紹介

以前はTypeScriptで真面目にReduxを使おうとすると、ActionやStateのboilerplate的な定義ばかりでコードが埋め尽くされて非常に難解な感じになりがちでした。

それがなんと!

最近GAされたRTK Queryを使うことで、私たちはただ、createApi()APIを定義し、定義から自動生成された便利なメソッドたち を使うだけでよくなるのです!

redux-toolkit.js.org

従来 axios や thunk、SWR などを組み合わせて頑張っていい感じなAPIアクセスを実現していましたが、RTK Queryを使えば、もはやAPIからのレスポンスを管理するのに頑張りは不要になります。

それどころか、Reduxを使っていることすら意識する機会がかなり減りそうです。
2020年ごろの React / Redux と比べると、無限の隔世の感がありますね。

まとめ

だまされたと思って、一回 Redux Toolkit・RTK Query を使ってみてください!
きっとご満足いただけるはずです。

redux-toolkit.js.org

Windowsで最新のGCC(開発版のSnapshot)を使いたいときのメモ

C++23の機能を使いたいけど、自分で定期的にビルドするスクリプト組むのは面倒だなーって思って都合よくGCCのバイナリが落ちてないか探したら、見つけたのでメモ。

WinLibs - GCC+MinGW-w64 compiler for Windows

↑の「Snapshot versions」に置いてありました。 大体月一くらいで更新してくれてるみたい。

海外ニキ非常に助かる。。

追記

こっちも有名っぽい。

http://www.equation.com/servlet/equation.cmd?fa=fortran

毎週更新らしいので、最初のやつより更新頻度高そう

【C++】参照とポインター完全に理解した

色々試したのでメモ。

用意したもの

以下の 4 種類の関数を用意した。

  1. 値渡し(何もつけずに書いたやつ)

    #include <iostream>
    
    int sum(int in1, int in2) {
        return in1 + in2;
    }
    
    int main() {
        int input1, input2;
        std::cin >> input1 >> input2;
        int result = sum(input1, input2);
        std::cout << result << std::endl;
        return 0;
    }
    
  2. 参照渡し

    #include <iostream>
    
    int sum(int& in1, int& in2) {
        return in1 + in2;
    }
    
    int main() {
        int input1, input2;
        std::cin >> input1 >> input2;
        int result = sum(input1, input2);
        std::cout << result << std::endl;
        return 0;
    }
    
  3. ポインタ渡し(move)

    #include <iostream>
    #include <memory>
    
    int sum(std::unique_ptr<int> in1, std::unique_ptr<int> in2) {
        return *in1 + *in2;
    }
    
    int main() {
        std::unique_ptr<int> input1(new int (0)), input2(new int (0));
        std::cin >> *input1 >> *input2;
        int result = sum(std::move(input1), std::move(input2));
        std::cout << result << std::endl;
        return 0;
    }
    
  4. ポインタ参照渡し

    #include <iostream>
    #include <memory>
    
    int sum(std::unique_ptr<int>& in1, std::unique_ptr<int>& in2) {
        return *in1 + *in2;
    }
    
    int main() {
        std::unique_ptr<int> input1(new int (0)), input2(new int (0));
        std::cin >> *input1 >> *input2;
        int result = sum(input1, input2);
        std::cout << result << std::endl;
        return 0;
    }
    

それぞれの挙動

  1. 値渡し
    • コピーが渡る。
      • でかいデータをコピーすると時間がかかるので、用法に注意。
      • コピーなので、参照先で変数を変更・再代入しても当然参照元には影響しない。
    • 参照先を変更しても、参照元の変数には影響なし。
  2. 参照渡し
    • 参照が渡る
      • 参照先で読み書きができる。
    • 参照先で変更すると、参照元が変更される。
  3. ポインタ渡し(move)
    • ポインタが渡る
      • 参照先で読み書きができる。
    • 参照元の変数は、利用できなくなる。 (unspecified state になる。参考:std::move - cppreference.com
  4. ポインタ参照渡し
    • ポインタの参照が渡る
      • 参照先で読み書きができる。
    • 参照先で変更すると、参照元が変更される。

所感

C++なんもわからんので、ぼちぼち学んでいきたいところです。 Rustの方が怪しい書き方した時に警告出してくれがちなので現状すき。

おまけ

アセンブリで挙動追いかけてみた。 ほんとに上記の通りになってて面白い(当たり前)

アセンブリを表示したスクショ