「初めてのGraphQL」を読んでサンプルアプリをTypeScript + React + typeorm + type-graphql + graphql-code-generatorで作ってみた
最近、GraphQL を勉強するために「初めての GraphQL」という本を読んで、理解のために自分でも本の中で実装されているサンプルアプリを作ってみました。
作ったのがこれ: https://github.com/danimal141/learning-graphql-ts
ただ写経するだけだとしっかり理解できない + 面白くないので本は雑に読みつつ、色々と魔改造しながら作ったのでそのメモを残しておきます。
全体
- 本のサンプルアプリは JavaScript で書かれているが、全て TypeScript で書いた
- GraphQL がせっかく型システムを持っているのだから実装側も型がほしい
- ディレクトリ構成は Monorepo で yarn workspaceを使ってバックエンドとフロントエンドの package を良い感じに管理できるようにした
- npm-run-allを導入してコマンドをパラレルでコマンド一発で実行するようにした
- バックエンド、フロントエンド、GraphQL のスキーマを元に型を吐いてくれるやつとか色々立ち上げるやつがいたので
- lint-stagedとhuskyを使って、コミット時に Prettier をかませるようにした
- その他、ESLint などは適当に入れた
- テストは
だるかったので書いていません、すみませんすみません
Backend
- 基本的には本の中で実装されているみたいに express や apollo-server-express を使い、playground 上で GraphQL のリクエストを確認できる感じにした
途中で面倒になったので本の中で実装されているが実装できていない Resolver とかあるかも
- Mongo ではなく MySQL を Docker で立ち上げるようにした
- 使ってみたかったのでtypeormとtype-graphqlを導入して DB と GraphQL のスキーマ定義するようにした
- あまりよく理解せずノリで使っていたが、途中で typeorm が Migration 機能持っていることに気づき導入してみた (最初は
synchronize: true
で乗り切っていた)
Frontend
- create-react-appを使って TypeScript のアプリのベースを作った
途中で面倒になったので作ったのはユーザ一覧表示とユーザログイン部分機能だけ- 本の中の React はちょっと古い感じだったので Hooks を使いまくってモダンっぽくした
- graphql-code-generatorを導入して、バックエンドで type-graphql が生成したスキーマを元に型ファイルを生成するようにした
- クエリを投げまくるのを気にして、なるべくルートのコンポーネントがクエリを組み立ててリクエスト -> 子コンポーネントはフラグメントで欲しい情報を宣言し、レンダリングするみたいなのを意識した (Fragment Colocation と言う? 参照)
- ログインする所は初めて Mutation をフロントエンドで実装したので若干悩んだ
- 本の中では
Mutation
コンポーネントとか使ってたけど、Hooks で書き直した時にuseMutation
が variables 空で呼ばれてしまってエラーになったりしてちょっとハマった
- 本の中では
まとめ
- GraphQL と TypeScript は良い感じに型システムを使えるので相性かなり良さそう
- typeorm は悪くないけど、個人的には正直 ActiveRecord のほうが早く実装できる
- Rails ヤメラレナイ...
参照
- https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/
- https://github.com/mysticatea/npm-run-all
- https://github.com/okonet/lint-staged
- https://github.com/typicode/husky
- https://github.com/typeorm/typeorm
- https://github.com/MichalLytek/type-graphql
- https://github.com/nestjs/nest
- https://github.com/facebook/create-react-app
- https://github.com/dotansimha/graphql-code-generator
- https://gist.github.com/Quramy/566ea87d0121ceb8cd97ad9d14b63fd8
GraphQL Schema Design @ Scale (Marc-André Giroux)メモ
最近は GraphQL やっていきな感じです。ただスキーマ設計が色々と悩ましく、設計の参考にするためにGraphQL Schema Design @ Scale (Marc-André Giroux) を観たのでかなり雑にメモ。
※ 英語のプレゼン動画をさくっと観ただけなので、正しく理解できていない所もあるかもしれません。
なぜ GraphQL を使うのか
GraphQL スキーマデザインについての誤解
- 複雑なアプリケーションにおいて、GraphQL はそのまま DB のインターフェースになることはめったにない
- GraphQL スキーマは既存の REST API のリソースにマッチする必要はない
- UI と 1:1 でマッピングされる必要はない
GraphQL の真の力
良い GraphQL スキーマをつくるための 2 つのポイント
- アプリケーションのドメインのエキスパートになり、知識を身につける
- GraphQL 特有の設計のエキスパートになる
そしてこれらを同じ人間が担当することはめったにない。
GitHub のアプローチは
Guiding Principles
データよりも振る舞いやユースケースを重視した設計
type PullRequest { title: String! description: String! ciStatus: CIStatus! reviews: [Review!]! }
クライアントがこの PR がマージ OK かどうか知りたい場合、以下のようなチェックが必要になるはず。
fun mergeable?(pr) pr.ciStatus == CI_STATUSES.GREEN && pr.reviews.all? { |r| r.approved }
でもクライアントはただマージできるのかどうか知りたいのでスキーマ的には以下のような形で十分。
type PullRequest { title: String! description: String! ciStatus: CIStatus! reviews: [Review!]! isMergeable: Boolean! }
マージ OK の条件が今後変わっても、それはサーバ側で吸収することでクライアントはただマージできるかどうか見ていればよい。
スマートで汎用的なフィールドよりも高度に最適化されたフィールド
type Query { user(id: ID, login: String): User }
nullable なid
かlogin
を受け取れるような設計より、それぞれのアプローチに最適化されたクエリを定義して型の恩恵を受けたほうがよい。
type Query { userById(id: ID!): User userByLogin(login: String!): User }
Tips
SDL のチェック
$ bin/dump-graphql-schema > config/schema.public.graphql $ git add config/schema.public.graphql
みんなスキーマをどんどん更新していくが、GitHub はgraphql-ruby
を使っているのでスキーマにどのような変更があったのかぱっと見てわかりにくい。上記のようなアプローチによって
スキーマ設計ミスった時や breaking changes を入れたい場合
@deprecated
を使うoldField (@deprecatedつき)
,newField
をメンテする- GitHub ではすべての@deprecated をあつめて breaking changes ページに公開してメンテしている
deprecated( start_date: ..., reason: ..., superseded_by: .... ) type Repository { databaseId: ID! @deprecated(reason: ...) }
RailsのマイグレーションでPostgreSQLのCREATE INDEX CONCURRENTLYする
最近、PostgreSQL を使用している Rails プロジェクトでCREATE INDEX CONCURRENTLY
する機会があったのでメモ。
CREATE INDEX CONCURRENTLY とは
通常のインデックス作成処理では、処理が完了するまで対象テーブルへの書き込みはロックされる(読み取りはロックされない)。
そしてテーブルのレコードが大量にある場合、インデックス作成に数時間かかることも考えられるので、その間ずっと書き込みがロックされるのはツラい。
PostgreSQL は CREATE INDEX
でCONCURRENTLY
というオプションをサポートしており、書き込みのロックを行わずにインデックスを作成することが可能。
ただし、これはサービスのダウンタイムが回避できる代わりに、通常よりも処理に時間がかかり、負荷も上がることが考えられる。
またここでは CREATE INDEX CONCURRENTLY
が実際どのようにワークするのかといったことには言及しない (知らん)ので、そういった所に興味のある方はこちらのような記事を読むのが良いと思います。
Rails のマイグレーションで実行する
こんな感じで指定できる:
class AddIndexToUsersActive < ActiveRecord::Migration disable_ddl_transaction! def change add_index :users, :active, algorithm: :concurrently end end
disable_ddl_transaction!
はCREATE INDEX CONCURRENTLY
したい場合は必須。すべてのマイグレーションはデフォルトでトランザクション下で実行されるようになっているので、それを無効にするためのもの。
またこれは指定したファイルでのみ適用され、他のマイグレーションは各自のトランザクションで実行される。
そして PostgreSQL のCREATE INDEX CONCURRENTLY
に該当するのが algorithm: :concurrently
の部分。これを指定しておくことで今回期待するインデックス処理が実行されるようになる。
まとめ
- Rails ではマイグレーションで
disable_ddl_transaction!
とalgorithm: :concurrently
を指定するだけで容易に PostgreSQL のCREATE INDEX CONCURRENTLY
を実行することができる - ダウンタイムを避けることができる代わりに通常よりも処理に時間がかかる、負荷が上がるなどのデメリットもあると思うのでメリット、デメリットをちゃんと考慮して使ったほうが良いかも
参照
プロセス置換 (Process Substitution)について
bash や zsh にはプロセス置換 (Process Substitution)という機能があるのだが、あまり使うことがなく頻繁に忘れるのでメモ。
プロセス置換 (Process Substitution)とは
コマンドの結果をファイルのように扱うことができる機能。以下のように書く。
<(list)
- リストの結果を入力ファイルに置き換える
>(list)
- リストの結果を出力ファイルに置き換える
これはリストの結果をもう一方のプロセスに送るために/dev/fd/<n>
のファイルディスクリプタを使っているっぽい。
使用例
例えば comm
というコマンドがある。これは comm file1.txt file2.txt
のようにしてファイル 1 と 2 を良い感じに比較したりできるが、プロセス置換を使えばファイルを用意せず使用することができる。
$ comm <(ls -l) <(ls -la) total 0 -rw-r--r--@ 1 username staff 0 Jun 6 17:29 file1.txt drwxr-xr-x 3 username staff 96 May 18 2019 tmp total 16 drwx------+ 6 username staff 192 Jun 6 17:29 . drwxr-xr-x+ 132 username staff 4224 Jun 6 16:25 .. -rw-r--r--@ 1 username staff 0 Jun 6 17:29 .secret.txt -rw-r--r--@ 1 username staff 0 Jun 6 17:29 file1.txt drwxr-xr-x 3 username staff 96 May 18 2019 tmp
またディレクトリ間の差分を見たい場合など、diff
コマンドをよく使うがこれも以下のようにプロセス置換を使うことができてよい。
$ diff <(ls $first_directory) <(ls $second_directory)
他にも例えば、k8s のドキュメントでも bash や zsh の自動補完の項で echo 'source <(kubectl completion bash)' >>~/.bash_profile
のようにプロセス置換を使っていたり。
まとめ
ファイルしか受け付けないようなコマンドでもプロセス置換を使えば一時ファイルを作成する必要がないので便利。>(list)
の方は使い道あまり思いつかなかった w
参照
英語で1on1ミーティングができるようになるまでにやったこと
今、自分の所属する会社では外国籍のエンジニアも働いていて、彼らとは普段英語でコミュニケーションを取っています。
具体的には Slack 上でのチャットや彼らが参加するミーティング、1on1 などを英語で行っていて、全く流暢ではないですが、現状問題なくコミュニケーションは取れていると思います。
初めて海外からエンジニアをチームに迎え入れたのが約 1 年半前。当初から分かっていたことではあったけど、特にリスニングとスピーキングが大きな課題となり、ミスコミュニケーションによって開発に支障をきたすようなケースもありました。
ただ色々と試行錯誤を繰り返し、今日なんとか 30 分~1 時間程度の 1on1 ミーティングぐらいであれば英語でもこなせるようになりました。
今回はこれまでどのようにして自分が英語を勉強してきたかをざっくり書いてみたいと思います。「TOEIC900 点です」みたいな定量的な実績も残していないし、誰かの参考になるかは分からないけど「英語、意外となんとかなるよ」的なメッセージを少しでも伝えられたらと思います。
はじめに
対象読者と当初の自分の英語力は以下のような感じ。
対象読者
- 仕事で英語が必要な人、もしくはこれから積極的に使っていきたい人
- これはあくまでエンジニア同士の会話のように、ある程度コンテキストが共有されている前提でのコミュニケーションを想定している (必要最低限の英単語や言い回しさえ知っていれば、それなりに会話ができるような状況)
- 海外ドラマや海外映画のようなレベルの英会話を達成するには今回書いているような勉強量では不十分だと思います、すみません
当初の英語力
- 留学経験とか一切なし
- TOEIC スコアは多分 550 ぐらい
- 受験したのは 5 年以上前、院試で必要だっただけ
- 英語のドキュメントは必要であれば読んでた
- Git のコミットメッセージやコードコメント、テストの Description 程度は英語で書いてた
- 英語を話すこと自体に特に抵抗はなかった
- 恥ずかしくて話せないみたいなメンタリティではなかった
準備編
ここからは海外から同僚がジョインするまでの数ヶ月 (Visa の発行とかあるので)でどのような英語対策を行ったかという話。
文法の復習
「日本人は英語を話すことに抵抗がある、間違ってもいいからまずは話せ」みたいな意見をよく聞く一方で、「文法を捨てて英会話に特化して勉強していると、いずれ成長が鈍化する」みたいな記事をどこかで見た気がして、まずは中高 6 年で習ったであろう文法をざっくり復習してみることにした。
選んだ本はこちら。
この本は英文法について「ネイティブがどのような感覚でそれを使っているか」みたいな視点で解説されているということで選んだのだが、当たりだった。受験で高得点を取るためではなく、純粋に英語を話せるようになるための本だった。
例文も This is a pen. みたいな何の役にも立たなそうなものではなく、もっと日常で出てきそうなものばかりで大変参考になった。
ただしこの本、辞書みたいに分厚くて何度も繰り返し読むのは非常にツラいので、2 週間ぐらいかけて読みながら各文法の要点を Evernote にまとめていき、エビングハウスの忘却曲線に沿った周期でそのノートを何度もチェックするようにした。
英語上達完全マップとの出会い
次に色んな人の英語勉強法を検索する中で、英語上達完全マップというサイトを発見した。
自分も今まで受験向けの英語教育しか受けてこず、実際に英語を使う (特にスピーキング)経験が圧倒的に不足しているという所に課題感を持っていたので、ここで書かれていた内容は腑に落ちた。
自分はこちらに書かれている、音読パッケージと瞬間英作文を重点的にやっていこうと決めた。文法に関しては、1 億人の英文法ですでにちょっと復習していたので、それ以上は特に何もしていない。
音読パッケージ
まずは音読パッケージの本を 1 冊買って、それを何度も繰り返すことにした。
選んだ本はこちら。
上記の完全マップの人が書いた本だったので、まあ間違いないだろうという感じで選んだ。学習方法は完全マップや本の中で説明されているので、素直にそれに従った。
毎朝、会社に行く前の 2~30 分で 1 セクション進めるようにして、それを 5 周ぐらいは続けたと思う。ただ実際はそんなストイックなものではなく、だるい日や少し寝坊した日は本能に従って休んだりも結構した。
そのうち丸暗記に近い感じになって飽きてきたので、別のシリーズも買って、同じように進めた。今でも継続している。
瞬間英作文
音読パッケージと合わせて瞬間英作文のトレーニングもスタートした。
選んだ本はこちら。
こちらも受験英語的な例文ではなく、より生の会話に近いような例文が多い印象だったので選んだ。進め方はこれまた上述の完全マップを完全に参考にした。
家ではすでに音読パッケージの学習をしていたので、気分を変えたいなと思い、こちらは通勤時、駅まで歩く間とかジョギングしながらとか、動きながら進めるようにした。周囲に人がいない時はちょっと声に出して発音の練習をしたりもした。
これは多分日本人に一番足りていないスキルで、ストレスなく英語が出てくるようになるまでかなり苦労したので 10 周ぐらいした。今は忘れてきたなという頃にたまに復習する程度で、以下の本あたりを検討中。
実践編
音読パッケージと瞬間英作文を 1 周終えたぐらいの時期、Visa を無事取得した同僚がジョインして、実践形式での英語コミュニケーションがスタートした。
日々の Slack の開発チャンネルや GitHub でのレビューなどがすべて英語と化し、開発環境の構築を英語でサポートするなど、「英語話せないとガチでヤバい」という状況が整った。
正直、これが一番最高なトレーニングであることは間違いないので、オンライン英会話を始めるとか英語のミートアップに参加するとか、何かしら実践できる環境を見つけることが上達への近道だと思う。
読み書きのためのツール
英語を読み書きする機会が増えてからは、以下のツールにはとてもお世話になっている。
-
- 精度も日々向上しているし、もはや「メインエディタかよ」ってぐらい使っている
- 自分はいつも英文は Google 翻訳上で書いていて、自分の書いた英文の日本語訳が意味不明じゃなければコピーアンドペーストみたいな感じで、バリデーション用途で使用している
- Slack のようなチャットでのコミュニケーションだと、さすがにそんな悠長なことやってられないので時と場合による
発音
実際に英語で話す中でたまに発音が思ったように通じないことがあったため、発音も改めて勉強してみることにした。
発音の勉強にはこちらのサイトを参考にした。
タイトルにもある通り、3 時間でざっと学習できるのでオススメ。これは 3 周ぐらいやって、あとはたまに自分の発音が通じなかった時とかに復習している。
あと、これも日本語の弊害で例えば genre という単語は日本語で「ジャンル」と読みがちだが、実際は「ジョンラ」みたいな発音だったり、既存の日本語知識が邪魔をしてくるケースもあるので、新しく英単語を覚える時は必ず発音やアクセントを確認したほうが良いと思う。
よく英語ペラペラの日本人が英単語の部分だけ英語ネイティブっぽく発音しているのをイキってるだけだと思っていたけど、そういう言語間の発音の違いを吸収するのが大変だっただけなのかな?なんて思ったりした。
英語の Podcast を聴く
音読パッケージと瞬間英作文をそれぞれ 2~3 周ぐらい終え、ちょっと実践的な英語にも慣れてきたタイミングで英語の Podcast をたまに聴くようになった。
自分はソフトウェアエンジニアなので、テック系の Podcast の中で面白そうなもの、そして中でも興味のあるトピックの回を何度も繰り返し聴いたりした。日本語で聴いてもよくわからないようなものは絶対に英語でも理解できないので、自分が使い慣れた技術について語っているようなものがオススメ。
元々よく聞いていたRebuild.fmの英語回やThe Changelog, GCP の Podcast などを好んで聴いた。
一言一句完璧に聴き取るのは基本的に不可能だし、聴き取れない部分は何度聴いても聴き取れなかったりするので、文字起こしがある (もしくは購入できる)ものを選ぶのがオススメ。聴き取れなかった箇所を確認しながら聴くのが良いと思う。
会話から学んだ英単語や言い回しをストックする
実際に日常で飛び交った英単語を都度調べて単語帳にストックするようにした。自分はWeblioを使っていて「同僚が使っていて自分が知らなかった単語を調べる -> 単語帳に登録 -> 夜寝る前とか暇な時に見返す」みたいにして覚えている。
これは学校の単語テストの前に頑張って暗記した時のような雑な記憶ではなく、実際に単語が使用されたシチュエーションとともにエピソード記憶として残りやすいので結構定着した。
仕事でエンジニアリングについての議論をする程度であれば、例えば loose coupling とか technical debt みたいな技術的な単語は一度使ったら結構忘れないものだし、It makes sense! みたいなよく使う言い回しとかも何度か使っていれば英語として自然に出てくるようになった。
If I were a bird, ... みたいなメルヘンチックな言い回しとか業務内でめったに使わないだろうし、シンプルで便利な言い回しだけ覚えておけばコミュニケーションは十分取れると思う。
Twitter で著名な海外のエンジニアのツイートをチェックする
Twitter のリスト機能を使って有名な OSS のコミッターなど、著名な海外のエンジニアの方を追加しまくって、英語の技術情報だけが流れてくるタイムラインを用意した。
1 投稿あたりの文字数が少ないので、洋書を読むとかよりも格段にハードルが低く、フランクなネイティブらしい言い回しなども目にすることができるので良かった。
どちらかというと英語の勉強というよりは情報収集のために見ている感じ。英語のリーディングに関しては普段ドキュメントなどを読む機会も多いので、あまり力は入れていない。
英語でブログを書いてみる
すでにコードレビューやチャットで英語のライティングの機会はあったが、よりアウトプットの場を増やすべく英語のテックブログも始めた。わりと海外で使われていそうなdev.toを利用した。
ただ超大作みたいな記事は心が折れて書けないので、簡単な技術メモ程度の記事をたまに書くようにしている。
まとめ
色々と書いてきたけど、結局英語上達するには以下のことに尽きるかなという気がしました。
- 日々の習慣の中に英語学習を組み込んで、地道に反復練習を継続することが重要
- モチベーションを継続するために「英語ができないとやばい」環境に身を置いたり、英語力を向上する目的 (アメリカ人の恋人がほしいとか)を明確化するのが重要
- 実際に英語を使うことが最も重要
「いや英語使う環境なんてねーよ」というエンジニアの方、Twitterとかでご連絡いただければ自分の会社のことも含め、色々とお話できるのでお気軽にどうぞ。
この記事が何かしらの参考になれば幸いです。