UnityのHttpWebRequestで自己署名証明書のローカルHTTPSサーバに通信したらいろいろハマった時の記録(結局ローカルやめてFaaSにした)
あるUnityアプリのテストのためにローカルにHTTPのAPIサーバを立てていたのだけど、 ある日うまく通信ができなくなってしまい、原因を探った時の記録。
事象1
エラー
E/Unity(20792): java.io.IOException: Cleartext HTTP traffic to xxx.xxx.xxx.xxx not permitted
HTTPなんか信頼できないから繋ぎたくないよ!と仰っています。
Android 9 (pie)になって、基本的にHTTPSへの接続しか許可されなくなったことによるエラーらしい。
Android 9(Pie)でHTTP通信を有効にする - Qiita
Android側でHTTP接続を許可する道もあるけど、本番APIはHTTPSだしセキュリティ的にもイマイチだなーということで、ローカルAPIサーバをHTTPS化する方針で。
対処:mkcertで自己署名証明書を作る
mkcertで簡単にオレオレ証明書を発行する – RE:ENGINES
mkcert
このGitHubのReadMeに従って作業したら、難なく作れてしまった。。
FastAPIでHTTPSサーバを起動する
通常起動はuvicorn main:app
だが、HTTPSサーバとして起動する場合はuvicorn main:app --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem
となる。
で、ビルドしたUnityアプリから接続してみる。
事象2
エラー
E/Unity(14330): javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
自己証明書は信頼できないので繋ぎたくないよ!と駄々をこねています。
対処:UnityWebRequestのcertificateHandlerに自己証明書に対応した独自ロジックを追加
※最終的に自分ではうまくいかなかった方法になりますので参考までに。
こちらの内容を参考に。
How to accept self signed certificate - Unity Answers
自前CertificateHandlerのコードは以下。
PUB_KEYに指定するのは、certificateファイル中のpublic keyのDER形式のバイナリを文字列で16進表記したもの。
using UnityEngine.Networking; using System.Security.Cryptography.X509Certificates; using UnityEngine; public class MyCertificateHandler : CertificateHandler { private static string PUB_KEY = @"my pub key"; protected override bool ValidateCertificate(byte[] certificateData) { X509Certificate2 cert = new X509Certificate2(certificateData); string pk = cert.GetPublicKeyString(); Debug.Log(cert.ToString()); if (pk.Equals(PUB_KEY)) return true; return false; } }
ValidateCertificateがtrueを返すと信頼、というロジックを組めるようです。
※常にtrueを返す実装は絶対やっちゃダメ!
UnityWebRequestを使う部分ではこのように指定。
UnityWebRequest www = UnityWebRequest.Post(url, formData); // 自己証明書に対応するため、自作の証明書確認ロジックを追加 www.certificateHandler = new MyCertificateHandler(); yield return www.SendWebRequest();
とやったんだけど、最終的に自分の証明書のpublic keyと、Unityで取得した証明書のpublic keyの値がどうしても一致せず、この実装は断念・・・(原因不明)
根本対処:FaaSを使う
今回自分の目的としては、Unityアプリのデバッグのために決まりきった内容のレスポンスを返すHTTPSのAPIがほしかっただけ。
なので、代わりにGCP Cloud Functionsを使うことにした。
で、30分くらいでできた。
共同開発者にも使ってもらえるしこれでええやん。クラウド最高。
AWS Summit Tokyo 2019 3日目午後に参加したメモ(コンテナ・サーバレス)
3日目の午後だけAWSSummitに参加してきた。
たまたまなんだけど、コンテナとサーバレス関連のセッションを立て続けに聞いてきて、概要把握に役立ったので、レポートしておく。
12:00-12:40 【初級】AWS コンテナサービス入門
コンテナの復習
コンテナの特徴
- アプリが依存するものをひとまとめにして可搬性を持たせる仕組み
- 仮想マシンと違い、実体は(環境隔離した)プロセスなので起動が早い
dockerの責務は一台のマシン上でのコンテナライフサイクル管理なので、複数マシンへのデプロイなどは範疇外。 そこで、コンテナオーケストレーションの出番。
コンテナオーケストレーション
ECSを使ったコンテナオーケストレーション
- できること
- EC2クラスタ作成
- デプロイ、AZ指定、LB接続などなど
- リリース当時はマネージドサービスとしてコンテナオーケストレーションできるサービスはなかった
- windowsコンテナもサポート
k8s(EKS)を使ったコンテナオーケストレーション
ECR
- コンテナイメージのレジストリ
- ローカルからも使える
Fargate
- ECSを使っても、実行環境としてのEC2の管理が必要
- ECS Agentの導入や、パッチあて、スケール管理などなど
- Fargateは、コンテナ実行環境もマネージドサービスとして提供する
なお、Fargateの課金体系は
Amazon ECS の場合、AWS Fargate の料金は、コンテナイメージのダウンロード (docker pull) を開始した時点から Amazon ECS タスクが終了するまでに使用された vCPU およびメモリリソースに基づいて計算され、最も近い秒数に切り上げられます。1 分の最低料金が適用されます。
となっている。
その他、コンテナにまつわる話題
CloudMap
- サービスディスカバリのためのマネージドサービス
- マイクロサービスにおけるDNS的なもの
- Lambdaなど、arnで管理されるものの名前解決も行う
AppMesh
- APレベルのネットワーク
- サービスメッシュ
CloudwatchのContainer Insights
- コンテナ専用モニタリングサービス
設定値管理
- AWS Systems ManagerのParameterStoreを使って、DB接続用パスワード等の秘匿情報を渡すことが簡単にできる
所感
AWSでコンテナを使うためにどのサービスを使えばよいのか俯瞰して理解できた。
Fargateについては、コンテナが動いている間だけの課金ということでEC2で動かすよりも少しは節約できそう。
GCPのCloudRunとFargateの違いを考えていたのだけど、FargateにECRのイメージをイベントドリブンでpull→runができたら同等になるイメージなのかな?
13:00-13:40 Kubernetes on AWS (Amazon EKS実践入門)
AWSでk8sつかってみたいけどまだ踏み切れてない人向けのセッション。
コンテナ復習
kubernetes(k8s)
CNCFのgraduatedプロジェクト
人気の理由
機能
- ノードにコンテナを自動配置
- セルフヒーリング
- オートスケール
- オートアップデート
- ストレージマウント
- 通信相手の名前解決
- ・・・などなど
VMwareをやっていた時代で止まっていた身としては、vCenterServerを思い出しつつ、よりアプリ目線での管理項目が増えている印象。コンテナってアプリのプロセスそのものの存在なので、当然っちゃ当然か。
構成要素
- マスターサーバ群=コントロールプレーン
- 動作のために多くのプロセスが存在する
- k8sの動作の根幹機能のため、冗長構成が必要
- つまり構築も管理も大変!
- ノード群=データプレーン
- Podを配置する先のリソース
- Pod
- デプロイの最小単位
- 1つ以上のコンテナで構成される
- Pod内のコンテナはIPアドレスやストレージ等を共有する
- Service
- Podを名前解決により発見する
- 例) myapp → namespace: production
- LB(L3/L4)機能を提供
- Podを名前解決により発見する
- Deployment
- Podを維持、コントロールするレプリカセットの管理
- ローリングアップデート、世代管理
設定・管理方法
yaml(マニフェスト)で宣言型の設定を行う。
コントロールプレーンのAPI Serverに適用すると、内部で設定どおりの構成になるよう、よしなに動いてくれる。
k8sについてはもっと中身を詳しく学んでおいたほうがよさそう・・・
k8sとAWS
通常はコントロールプレーンもデータプレーンもEC2で構築するが、特にコントロールプレーンはアップデートとか冗長化とか、構築も管理も大変。なのでマネージドサービス。
EKS
k8sのコントロールプレンをマネージドサービスで提供したサービス。
コントロールプレーンはAWS側のVPCに構築され、ユーザからはkubectlで操作する形になる。
使うメリット
- コントロールプレーンの運用から解放
- k8s運用支援機能
- バージョンアップ、コントロールプレーンのログ集約、などなど
- AWSのサービスとスムーズな連携
- データプレーンの選択性
- AMIやインスタンスタイプを選べる
使い方
デモ
Sock shopというデモ用のアプリで動作のデモ。
実はk8sマニフェストでAWSリソースを管理できちゃうので、想像以上に機能性や自由度が高い。
ユースケースとAWS連携
HTTP[S]対応LBを使いたい
ログ集約
- FluentdのDaemonsetでやる
- [New] Cloudwatch Container Insightsを使う
オートスケール
デプロイ効率化
- CodeCommit/CodeBuild/CodePipelineでCI/CD
- buildトリガーでLambdaでマニフェスト?のコンテナイメージのタグのバージョンを書き換えるらしい。ここはよく理解できなかった。
堅牢なデータストアを使いたい
- マネージド系DBの使用がおススメ
ラーニングパス
より詳しく学ぶには、BlackBeltやEKS Workshopを活用ください。
所感
k8sの役割とEKSを使うメリットについて理解できた。
k8sコントロールプレーンの構成を見ていると、マネージドサービスを使う利点は考えるまでもなく大きい気がする。
これだけコンテナ環境をお手軽に使えるようになってくると、いよいよ爆発的に流行りそう。
14:00-14:40 サービスメッシュは本当に必要なのか、何を解決するのか
サービスメッシュってなに?
Monolithなアプリとは
- Does Everything
- 課題
- 関係者調整のオーバーヘッド
- 変更による影響範囲の広さ
- モジュール構造維持の難しさ
- 非効率なスケーリング
- テスト・ビルドに要する時間の長さ
マイクロサービス
- モノリシックなアプリの課題を解決するために考案された
- Does one thing
- Polyglot(-able) => 複数の言語を使って実装できる
monolithの考察
マイクロサービス
- 通信状況を可視化するとヤバい複雑
- 課題
Reliability確保のための策
ネットワーク状況・対向サービス状況による失敗がありうる。そこで、防御的実装の必要性が生じる。
防御的実装とは以下のような事象に対応する実装のこと。
- 呼び出し先サービスの位置が変わる → サービスディスカバリ
- 一時的呼び出しの失敗 → リトライ
- 継続した呼び出しの失敗 → サーキットブレーカー
- 呼び出し先パフォーマンス悪化 → タイムアウト
- 呼び出し元システムの不具合 → スロットリング
Observability確保のための策
エラーがどこでなぜ起きたのか分析できる必要がある。
- ログ・メトリクス・トレース情報出力
- これらが各サービスでちゃんとやられてる??
- 出力フォーマットは整っている??
- たとえ個別実装できていたとしても、システム全体の観測に不向きな実装となりうるため、一貫性のある実現方法が必要。
一貫性のある防御的実装の実現策
- ありがちな「共通ライブラリ」は密結合になるため、ことマイクロサービス開発においては不向き
- マイクロサービスの開発体制においては、疎結合な実装、自律的チーム関係の維持が成功の秘訣
- プロキシへのオフロード
- 共通的実装が必要なレイヤを下層におき、処理をオフロードする
- これをサービスメッシュという!
- (共通ライブラリ機能を一つの(分散型)マイクロサービスとして提供するイメージ?)
サービスメッシュ
Envoy Proxy
- 特徴
- 設定ファイルがあるとやっぱり密結合になるのでは?
- アプリと一緒にプロキシもデプロイしないといけないんですか? →AppMeshが解決!
AppMesh
- AppMeshの特徴
- 機能詳細
あなたのシステムにとってサービスメッシュは本当に必要なのか?
システム規模や要件に応じて、どこまで導入すべきか検討の余地がある。
- XRayやALBで十分なケース
- Envoyの利用で十分なケース
- 動的なサービスメッシュがいるなら、AppMesh
所感
サービスメッシュの正体がいまいちつかめていなかったので、ぼんやりとでもイメージできるようになったので大変有用なセッションだった。
マイクロサービスにおいてはサービス間通信がアプリケーションの関心ごととなり、かつ規模が大きいと複雑化するので、そのレイヤにおいて共通的な非機能面をカバーするプロダクトが必要で、それがサービスメッシュだ、とざっくり理解した。
(2019/6/21追記)それがサービスプロキシで、サービスメッシュはそれらを統合管理するレイヤ、っぽい。Envoyがサービスプロキシ、AWS AppMeshやIstioがサービスメッシュ。(追記ここまで)
おそらくこれまでも大規模システム開発の現場ではこういったAPの共通的非機能レイヤを受け持つ部隊はあったと思うが、市場全体でみるとレアケースだったのか、あるいはアーキテクチャとして定型化されていなかったかで共通的な名称はなかったが、マイクロサービスという定型化されたものに乗っかって名前が与えられた、という感がある。
セッションの話の流れも、従来のモノリシックなシステムからマイクロサービスへの変遷、それによる課題の移り変わり、と順を追って進み、サービスメッシュが解決する課題がマイクロサービスの課題の何にあたるのかがイメージしやすかった。
たぶん今回参加して一番ためになったセッション。
15:00-15:40 サーバレスアプリケーションのためのセキュリティアーキテクチャ
サーバレスアプリの構成要素
サーバレスアプリをセキュアに設計する
- Well-Architected Framework - Serverless Application Lens
- セキュリティの柱
- IDとアクセス管理
- 発見的統制
- インフラ保護
- データ保護
- インシデントレスポンス
IDとアクセス管理
APIアクセスの認証認可をどうするか?
LambdaファンクションがアクセスできるAWSサービスをどう保護するか?
- Cognito User Pools
- マネージドユーザーディレクトリ
- 多要素認証のサポート等、拡張されたセキュリティ機能を提供
- 3通りの方法
- 発見的統制
- インフラ保護
- データ保護
- 機密性の高い情報をどう保護するか
- 入力値バリデーションの方法
- SystemManager Parameter Store
- 設定データの安全なストレージ
- Secrets Manager
- DB管理者の鍵などを保管
- ローテーションも自動化
- 侵入テスト
- 事前申請なくできるようになった
- Lambda、APIGatewayとかも
- WAFセキュリティオートメーション
- WAFフルログ送信→Firehose→S3→Athenaで分析→WAFルール更新
- 事前申請なくできるようになった
所感
サーバレスアプリケーションにおける認証認可の方式について細かい話を聞けるかと思っていたけど、もっと広く浅い話だった。
でもこういった切り口の話はAWS公式ドキュメントでもまとまっている資料があまりない印象なので、サーバレスの組み方として大変参考になった。
そもそもAWSにおけるサーバレスの構成要素となるサービスについてちゃんと把握していなかったんだなあと実感。「Well-Architected Framework - Serverless Application Lens」は英語だから何となく敬遠していたけど、目を通したほうがいいのかも。。
16:00-16:40 目指せサーバーレスプロフェッショナル
AWS芸人な方のセッション。
開発、テスト、フレームワーク
開発環境
- Cloud9
- 東京リージョンも使用可となった
- 各種エディタのプラグインがある
- AWSSAM
- AWS SAM CLI (旧 SAM local)
- ローカルテストツール
- レスポンスやログ確認が可能
- Lambda実行環境をシミュレートしたDockerイメージを提供
- サンプルアプリ作成
sam init --runtime nodejs8.10
- イベント作成
sam local generate-event s3 --bucket hogeBucket --key hogekey > s2event.json
- Lambda呼び出し
sam local invoke hogeFunction -e s3event.json
- APIローカル実行
sam local api
- などなど
- サンプルアプリ作成
複数環境、CI/CD
複数環境
CI/CD
- Codeシリーズ
- CodeStarを使うと代表的パイプラインをテンプレートで提供してくれる
- 段階的デプロイメント
- DeploymentPreferenceにカナリヤ・リニアなどのパラメータを指定する
- アラームとフックを指定可能
- APIGatewayもカナリヤリリース可能
- A/Bテストとかにも使える
再利用
- SAM/CloudFormationを使う
- Serverless App Repositoryを使う
- CodePipeline SAR Auto-Publishで自動化できる
監視、モニタリング
- 基本Cloudwatchに統合されている
- X-Ray使う
- トレース
- サービスマップ
- 各サービスの呼び出し結果を色で分類して割合を円グラフにして可視化
- 平均レイテンシ、トレース数、など
デザインパターン
- 12のデザインパターンが紹介されているので、参考に。
所感
盛りだくさんのセッションだった。
サーバレスはどうやってテストやCI/CDすればよいのかイメージがついていなかったけど、SAMのようなツールを使ったり、各サービスの環境変数にあたる機能を駆使すればローカル開発・テスト含めて実現できることがわかった。
以前書いた記事で抱いた課題感への答えになりそう。
しかしそれでも、こういった開発周辺ツールも含めてサーバレス環境はベンダロックイン感がどうしてもぬぐえない。
別セッションだったかもしれないけど、「サーバレス」-「コンテナ」-「仮想マシン」という3種類の環境を目的や背景に応じて使い分けることが重要、という話だったので、今後もそれぞれのメリデメ把握を続けるのが大事だと感じた。
今のところコンテナが、アジリティもポータビリティもあって万能のように感じてしまうけど。。
サーバレスシングルページアプリケーションについて
サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス
- 作者: Ben Rady,吉田真吾,笹井崇司
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/06/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
この本を読んで、学んだことや思ったことをまとめてみた。
SPAとは?
SPA(SinglePageApplication)とは、ユーザから見て、Webページ全体をサーバから取得するような更新を行うことなく、部分的な更新をクライアントサイドで行うことで動的コンテンツを提供するWebアプリケーションのこと。
従来のWebアプリはサーバサイドでHTMLを生成してクライアントサイドに送信するのが基本だが、SPAではページの一部のデータのみについて最新の状態を取得し、ページを部分的に書き換えるのが基本となる。
これにより、ネイティブアプリに近い使用感をWebアプリで提供できる。
SPAの要素
SPAを開発するにあたっての基本要素は以下の通り。
コンポーネント
まとまった機能を提供する単位にまとめたビューを作ると、画面の部分的な更新や差し替えの見通しが良くなる。このまとまった単位をコンポーネントと言う。
HTMLだけでなく、後述のカスタムイベント、およびCSSまで含むことがあるが、どこまでを含めるかはフレームワークや設計によりけり。
ルーティング
SPAにおいては画面の切り替えはビューコンポーネントの差し替えであり、クライアントサイドで処理することになる。
画面切り替えだけなら単純であるが、ユーザエクスペリエンスを考慮すると、URLとページの状態を紐付けたり、ブラウザの戻るボタンを有効に機能させるためにhistory APIを活用したりする必要がある。
書籍で紹介されていた実装パターン
書き換え先のページはURLで示すが、サーバへリクエストを送らない単一ページ内のリンクとして動作させるために、ハッシュURLを使う。
ハッシュURLに対応するHTML構造をテンプレートとして保持しておき、要求されたURLに応じたテンプレートからDOMを構築し、現在のHTMLツリーの書き換え対象エレメントの中身を入れ替える。
データバインディング
バックエンドのAPIから得たデータを使ってページを部分更新する際、毎度ページ全体を再構築すると通常のアプリと変わらなくなってしまう。また、データが書き換わったときに改めてDOM操作をするのは、あらゆる状態に対して「変更」操作を記述する必要があり、複雑な状態遷移を持つ場合に課題があった。
そこで、「唯一信じられるデータソース」を持ち、書き換えたい対象のエレメントにデータを紐付けておき、データソースが書き換わったら対応するビューも書き換える(ことを裏で自動で行う)仕組みが発明され、これをデータバインディングという。
データバインディングには単方向と双方向があり、データソース→ビュー方向の同期のみ行うのが単方向データバインディング、ビュー→データソース方向の同期も行うのが双方向データバインディング。
単方向は読み取り専用データ、双方向はフォームなどの編集可能データに使われる。
カスタムイベント
ビューをコンポーネントとして管理すると、コンポーネントというまとまった単位として扱うイベントを定義したくなる。これをカスタムイベントと言う。
書籍で紹介されていた実装パターン
jQueryではbind関数とtrigger関数を使うことで任意のイベントを登録・発火できる。
これを利用して、あるビューがロードされたときにbindでカスタムイベントを登録し、他からtriggerで発火することで、ビューに対する独自イベントを作れる。
SPAフレームワーク
フレームワークは上記のような要素を実装する手助けをしてくれる。それに加え、以下のような特徴を持つ。
リアクティブ
=宣言的。DOMエレメントをあれこれいじって形を変えてビューを作るのではなく、「このデータならこのビュー」というあるべき姿を宣言しておき、データを変更すると裏で宣言したとおりにビューを作ってくれる、という考え方。
インフラ屋さんからすると、「sedで設定ファイルを手続き的に書き換えるのではなく、Puppet等の構成管理ツールを使うイメージ(yamlに定義したあるべき姿の通りに裏で設定が変更される)」と言うとわかりみがあるかもしれない。
なんでそんなことになったのかって言うと、端的には、大規模なUIをいちいちエレメント操作して作ってると大変だから、だと思う。
ところでそもそもどうして大規模なUIを作る必要が生まれたんでしょう?
ユーザエクスペリエンスの向上を目指してたらフロントエンドへの要求が肥大化してきた、というのはあるかもしれないけど、他にもバックエンドとの関係性の変化もあると思う。
後述の通り、サーバレスアーキテクチャはいわゆるImmutable Infrastructureの考え方のもとに成り立っており、基本的にステートレスである。
するとバックエンドではなるべくアプリの状態を保持しないため、特にビューに関する状態などはフロントエンドに任せる必要が生じる。この流れが加速してSPAの重要性が増しているのではと考える。
ここ最近のトピック
状態管理
SPAの規模が大きくなってくると、ビューの状態を示すデータの扱いに一定の設計指針が必要となってくる。
Fluxや、それをもとにしたReduxが有名。
最近のフレームワークでは、個別に対応した状態管理用フレームワークがある(React~ReduxやVuexなど)。
最もデファクトに近いのはReduxのイメージだが、Reduxはそれなりに規模が大きなアプリでないとオーバースペックな設計思想のため、より幅広い層に受け入れられそうな設計思想が模索されている様子。
ReactではContext API、FlutterではBLoCやScopedModel(Provider)のようなものも出てきている。
これからも変遷が続くと思われる。
webコンポーネント
フレームワークではなく標準仕様としてコンポーネントを記述する方法がWebComponentsとして定義されつつある。
最近やっと主要ブラウザがサポートし始めたらしい。
https://html5experts.jp/shumpei-shiraishi/24239/
サーバレスアーキテクチャとは?
以前書いた記事でざっくりと。
要は「自前で面倒を見ないといけないサーバ(ハードウェア、仮想マシンやインスタンス)を持たずにシステムを動作させるアーキテクチャ」ということになる。
インフラリソースの管理の煩雑さを解決する動きのひとつにImmutable Infrastructureという考え方があり、自分が思うにサーバレスアーキテクチャは現状におけるその最たる例である。
サーバーレスアーキテクチャでは基本的にステートレスとなる。バックエンドではアプリの状態を保持しない。それによりサーバが停止しても使い捨てて新しいサーバを自動的に立ち上げることで復旧できる。
サーバーレスアプリケーションの開発
本書では、認証にCognito、データ保管にDynamoDB、サーバサイドロジックにLamdaを使ったサーバーレスアプリケーションの例を示している。
最近では、AWS Amplifyを使うことで、より簡便にサーバーレスサービスを扱えるようになっている。(mBaaS。GCPのFirebaseに相当する)
各サービスの詳細は割愛。
サーバレスに関して調べたこと
サーバレスというキーワードについて、一度しっかり調査しておきたいと思い、 調べたことをまとめてみた。
自分は基本的にクラウドサービスはAWSしか知らないのでところどころAWSを意識した記述になっていると思いますが悪しからず。
サーバレス概要
- FaaS(Function as a Service)、およびその他のマネージドサービスを組み合わせて構築されるシステムのこと
- 開発者目線でサーバーが隠蔽されるので、サーバーレスと言う
- AWSで言うと、Lambda(FaaS)、S3(ストレージ)、DynamoDB(DocumentDB)、Cognito(認証)、API Gateway(APIプロキシサーバ)、SQS(メッセージング)、Kinesis(大量データストリーミング)、などのサービスで構成されるアーキテクチャ
- 各サービスが動作するサーバ自体はサービス内に隠蔽され、クラウドベンダ側が運用保守を請け負う
自分のイメージ
- インフラ管理から解放される
- Infrastructure as Codeをサービスに組み込んだイメージ。最初からリソース操作がコード化されているから、勝手にImmutable Infrastructureになる
- 結果的に、インフラはステートレスとなる
- マイクロサービス的になる
- FaaSが提供する機能が小さい単位になるので基本がマイクロサービス的設計に落ちていく
- コンテナ環境と比較はされるが、コンテナのサーバーレスサービス使えばお互いのメリットを活かせる気がする
- 下回りがコンテナでもマネージドサービスでも、開発者目線で見たらサーバーレスに違いない
- 主にモバイルアプリ開発の文脈で聞くことが多い気がする(mBaaSは基本的にサーバレスだからかと)
サーバレスのメリット
記事後半の参考にした記事をもとにまとめたサーバレスのメリット。
- コスト削減
- 基本的に利用した分だけの課金になる。待機状態には課金されない。
- スケーラビリティ
- 特段の設定などしなくても、負荷に応じてオートスケールする。
- とはいえいろいろ考慮することはあるはず、と思う
- 特段の設定などしなくても、負荷に応じてオートスケールする。
- フルマネージド(管理不要)
- いわゆる従来の「インフラ管理」が不要となる
- 監視、アップグレードやパッチ適用、性能・拡張性担保、アプリ以外(ミドルやOS層)のログ管理、あたりは不要となる。
- 依然として必要なのは、セキュリティ管理
- 考え方が変わるのは、ログ管理(サービスのログを管理する)、性能担保(ボトルネックがどこかわかりにくそう)
- いわゆる従来の「インフラ管理」が不要となる
サーバレスのデメリット
自分が実際にAWSでおもちゃアプリを作ってみて感じたことも含む。
- 管理する対象が多くなる、散らばる
- システム構成要素が散らばるので、サーバーレス向けサービスの構築自体もCode管理するなどして管理しやすくすべき(当たり前か
- コードやアーキテクチャがベンダ依存になり、個々のサービスについて知識が必要
- 何の要素技術をどうマッピングしたサービスなのか把握して、設定方法を学ばないといけない
- セキュリティ(アクセス制御)を考慮する場所が増えて煩雑
- 各サービスの繋ぎ方がベンダ依存だったりするので、セキュリティ設定の方法もベンダ依存だったりする
- セキュリティ(アクセス制御)の実装方法がベンダ依存になる
- デバッグしにくい
- マネジメントコンソールをぽちぽちしながらは開発したくない
- インフラコードも合わせて書いて、どかんとデプロイしたい
- ローカルでもある程度はテストできるといい
- AWS SAM CLIなど、ローカル開発できるツールもあるっぽい
- 設計とテストをどうやるべきなのか、あまり想像つかない
- システムのできることがサービス仕様に縛られるのにどこか不安を感じる
- 今は動くけど、この先やりたいことが増えたとき、同じサービス上でできるのか?
- 自前コンテナで動かしている分にはやればできることが多いと思うが
参考にした記事とサマリ
- サーバレスの流れは、インフラのお守りにかけるお金よりアプリ開発のお金を重視する流れにより発展してきた。
- システムインフラのお守りのコストは30〜40%あり、サーバレスならそれが削減できる。スケーラビリティもインフラではなくアプリの設定としての関心事となる。
- コンテナとサーバレスの比較
- コミュニティの違い:コンテナはインフラ管理、サーバレスはアプリ開発の話題が多い
- サーバレスの特徴
- 個々のサービスのリソース制限が厳しい
- そのため機能単位が小さく、従来のモノリシックなシステムの複雑なロジックを実装するのは困難が伴う
- 個々のサービスのリソース制限が厳しい
- サーバレス導入にあたり
- コンテナオーケストレーションツールとしてはk8sがほぼデファクトとなった
- コンテナ実行環境のサーバーレス化が進んでいる
- podレベルでのサーバレスを実現するKnativeやOpenFaaS,Kubeless,Osiris
- ノードレベルでのサーバレスを実現するVirtual Kubelet
- podがオートスケールしても、下回りのノードがスケールしないと、結局サービスの起動時間が仮想マシンの起動時間ほどかかってしまう
- ノードをサーバーレスで提供するServiceを各クラウドベンダが提供している
- これらのサービス上でk8sを使えるようになってきていて、始まった感がある
- サーバーレスの基本的なメリットは、コスト削減とオートスケール能力であり、ことスタートアップにとっては本来魅力的である
- しかしサーバーレス関連サービスを駆使して適切にシステムを構築することは、自前でOSSなどを使って実装するよりも技術習得コストが高くなるケースがままある
- そのため多くのスタートアップは初期にそのようなコストを避ける傾向があるのは当然である
- ただしサーバーレスコンピューティングサービス(AWSにおけるLambda)やそれに類するマネージドサービス(AWSにおけるCognitoなど)を使う利点には、自前で保守する必要のあるコード(技術的負債)を減らす効果もある
- 開発チームを最適化するのに許される期間が月〜年単位なのであれば、サーバーレスアーキテクチャで準備することにメリットがある
- サーバーレスは「プロビジョニング、スケーリング、管理が不要」な特長をもつコンピューティングリソースのことである
- 従来はFaaSを指すことが多かったが、最近サーバーレスな特長をもつDBやコンテナ実行基盤のサービスも現れ始めた
- サーバーレスという言葉は、FaaSだけでなく「プロビジョニング、スケーリング、管理が不要」な特長をもつコンピューティングリソースのことを指すように改めて認知され始めるのではないか
まとめ
- 開発者目線で、アプリ開発に集中できるインフラの形態がサーバーレスアーキテクチャ
- 比較対象は、仮想マシン環境、コンテナ環境
- 近年DBやコンテナにも用途が広がってきており、今後も適用できる範囲は広がっていくだろう
- メリットも大きいが、デメリットも大きいので、導入先プロジェクトに向いているかは慎重な判断が必要
最近、GCPのCloud Runがなにかと話題なので、そのうち調べたいと思ってる。
iodide使ってみた
最近iodideというのを見つけたので少し使ってみた。
iodide
javascriptのjupyter notebookみたいなやつで、まだアルファ版。
似たようなサービスにObservableがあるが、Observableはjavascriptのみなのに対し、iodideは多言語対応を進めている点が異なる。
作者のブログにあるように、iodideはデータサイエンティストがレポーティングをする際、分析に使っているJupyter notebookやR-Studioを離れてpdf等の別媒体へアウトプットしなければならない点を解消する目的で始まったプロジェクトであるため、アルファ版である現時点でもpythonのデータ分析関連ライブラリ(numpyやpandas、scikit-learn、matplotlibなど)であればそこそこ動作する。 pythonの実装はpyodideといい、webassemblyを使ってブラウザでpythonが動くようにしたものとのこと。
iodideの特徴
JSMDというフォーマットのテキストを記載していくと、右上のウィンドウにHTMLが出来上がる。
javascript/pythonのコード、マークダウン、CSS、raw(HTMLに反映されないメモ書き)が書けるほか、web上のデータをURL指定で取得するfetch、js/python以外の言語用pluginを呼び出すpluginといった種類のセルを作れる。
トップページのサンプルノートを見るのが早い。
pyodideの特徴
- pythonの各種ライブラリを使う(サポートされているライブラリ)
- jsと同様の文法でDOM構築する
といったようなことができる。
from js import document
とすることでjsのdocument.getElementById
みたいなことが一通りできるし、イベント関数にはdef some_event(evt):
とかで定義したpythonの関数をそのまま入れられるので、ちょっとしたUI付きのドキュメントを作りたい場合は便利。
pyodideの簡単なサンプルノートも紹介されている。
UIが複雑ならjsで書いたほうがよさそう。その場合にはjsとpython間でデータやり取りが必要で、以下のようにやる。
js → py
from js import <param name>
py → js
var param = pyodide.pyimport("<param name>");
デバッグにあたってはjs同様、DeveloperToolsを開いてConsole出力を確認する。
pythonでprint関数を使うとconsoleに出力されることは確認した。
なお、右下のConsoleウィンドウに表示されるのはセル最終行のevalの結果のようで、標準出力ではないので注意。基本的にDeveloperToolsを使ったほうがよさそう。
セル実行時の標準エラー出力についてはConsoleウィンドウにもDevToolsの方にも出力されるが、HTMLのbuttonに付けたイベントの中で起きたエラーはDevToolsにしか出力されない点も注意。
このあたりは今後のアップデートで改善されていくと思う。
つくってみた:iris predictor
例によってiris分類をアプリにしてみた。
HTMLのテキストボックスに推論したい値を入力し、predictボタンを押すとscikit-learnのSVMで分類し、結果をHTMLに反映する。
試すときは、各ユーザがノートを開いたあとにブラウザ上で全セル実行する必要があるが、pythonのデータ分析部分の実装とjsによる可視化やUIの実装が1つのまとまったファイル(JSMD)でカジュアルに閲覧、実行できるというのは面白い体験だなと思った。
なお、どうやらpyodideにおけるscipyのimportにはかなり時間がかかっている。(自分の環境で、パッケージファイルのダウンロードに3.6minかかっていた。) scipyのパッケージサイズがバカでかい(60MB以上)のが原因のようだ。ローカル実行ならではの問題点かな。今後の改善に期待。
ちなみに:ReactやVueを動かす
意味があるかどうかはケースバイケースだけど、その気になればReactやVueも動く。
ともにfetchセルでjsファイルを呼び出して使う形になる。
%% fetch // Vueの場合 js: //cdn.jsdelivr.net/npm/vue/dist/vue.js // Reactの場合 js: //unpkg.com/react@16/umd/react.development.js js: //unpkg.com/react-dom@16/umd/react-dom.development.js
ノートは、Vueならこんな感じ。
ただしVueの場合、Vue側のコードを修正した後は、一度マークダウンの方にも何らかの更新をかけてから改めてVueのコードを実行しないと反映されない。
Reactの場合も同じイメージだけど、やはりJSXを使いたくなるところ。
JSXはそのままでは使えないので、ドキュメントにあるように、pluginでjsxを有効にする。
ノートはこんな感じ。
おわりに
現時点では「使える」というより「興味深い」という段階だが、今後のアップデートによっては新しい種類のツールになる可能性を感じた。
今後もウォッチしていきたい。
妻の産休明けから夫のみ育休を4ヶ月とった感想
経緯
昨年夏に子供が生まれ、12月から3月まで、育休をとりました。
妻は諸事情で育休がとれなかったため、平日日中は自分一人で育児する環境となりました。
育休は、職場が特別な制度を敷いていない限り、少なくとも
- 同一の事業主に引き続き1年以上継続して雇用されている
- 子供が1歳6ヶ月になる日の前日までに労働契約(更新される場合は更新後の契約)の期間が満了することが明らかでない
という条件を満たさなければ取得できません。
(参考:産休・育休の違いは?取得できる条件について解説していきます。 | 労務SEARCH)
これ、特に大企業に勤めていると、意外と知っている人少ないんですよね。自然と条件を満たすので。
妻は年単位の契約で働いていたため、二つ目の条件を満たせず、取れませんでした。
その場合、産休明けで復帰か、辞めるかになります。
妻は研究職なのですが、キャリアを考えると辞める選択肢はありませんでした。
そのため私が育休を取ることにしました。
私は幸い理解ある職場に勤めていたため、育休取得自体はすんなり受け入れられました。
ですがもちろん抱えている仕事に一区切りつけないといけなかったので、
子供が生まれて産休が明けてから11月末までは、妻と仕事の休みをずらしてお互い週2~3日働く形でどうにかこうにかつなぐ生活でした。
それはそれでハードでした。
ちなみに産休は雇用条件などに関係なく誰でも取れます(法律で定められています)。産前と産後がありますが、産後休業は8週間取ることができます。
(参考: 産休期間はいつからいつまで? 覚えておきたい産休の仕組みとお金の流れ | マイナビウーマン子育て)
逆に言うと育休を取らない場合は産後8週間で復帰する必要があります。文中でも述べますが、これ、体調面で超ハードとのことです。産後休業をのばすか育休を取りやすくするかしてほしい。
以降、12月から始まった私の育休中の様子について書いていきます。
※本記事は、単に自分大変〜っていうアピールがしたいわけではなく、今回「妻の産休明けから夫のみ育休」という(恐らく)レアケースを経験したと思っているので、世の中の育児に関わる/これから関わるであろう男性にとって参考になるといいなという思いで書いています。
直近の1日のスケジュール
だいたい子供が離乳食2食/日になるくらいの月齢におけるスケジュールです。
7:00くらいにおきる
朝食
(妻出勤)
あやす
11:00くらい 離乳食&ミルク準備、あげる
散歩、買い物
子供が寝たら昼ごはん (寝るとは限らない
離乳食食器洗う
洗濯
洗濯物畳む
子供と遊ぶ
15:00くらい ミルク準備、あげる
洗濯物干す
料理
(妻帰宅)
18:30くらい 離乳食&ミルク準備、あげる
沐浴
夕飯
風呂
食器洗い
ミルク準備、あげる
寝る
掃除がないけど、空いた時間にやるしかない感じでした。
あと、特に食器洗いが大変。料理すると量が多くなるし、哺乳瓶や離乳食食器は大人用とは別の洗剤で洗う必要があるので、毎日2時間弱かかります。
大変だったこと
はじめのうちはなれないことばかりで大変だったけど、新鮮味もあり体力もまだあるのでまあなんとかこなせていました。 それが、3ヶ月くらいできつくなってきました。なんだか、思考が鈍る感じ。
鈍り例
- 離乳食のスプーンに2種類(あげる用と潰す用)あることに気づかず、かつ潰す用の方であげているのに気づかず、なんかあげにくいなあ、なんでかなあとか思ってた。
- 保育園の準備のための買い物すらうまく選べない。
子供は大抵のとき、 自分が視界から消えるとこの世の終わりのように泣く ので、あまり離れてなにかすることができないです。
なので、家事はとてもしにくい。起きてる間は掃除なんかできないです。寝てても掃除機はかけられないんですけどね、起きるから。
傍で本読んだりスマホやPC使ったりはある程度できますが、それでもやっぱり相手しないといけないので、一度にできるのは10分ちょっとって感じです。
泣いてても無視して家事をしないと回らないときもあるし、そういった時間帯に受けるストレスはかなりのものです。
そういうストレスが、徐々に積み重なっていって 頭が鈍っていくんじゃないかと思います。
あと、休憩時間をとれないのも地味にしんどいです。仕事は昼休みが決まった時間にとれるけど、子供が寝てる間に家事を…と考えながら過ごすと気づいたら夕方。で家事終わってない、みたいな感じなので休憩とかなかったですね。
家事を一部諦めて意識的に休憩を取るようにするのもありなのかもしれないです。ルーチンになると躍起になってこなそうとしてしまうところがあるので。
他にも、
- ルーチンを繰り返しているのがシンプルにつらい
- 自由な時間が断片的かつ無計画に入るので落ち着いて思考する時間がない。 次何するかで頭がいっぱい。
- 上記のとおり、なんだかんだで休む暇があまりない。
- 自分が水分をほとんど摂っていないことに夕方気づく、とかよくある。
- 週に一回くらい、子供がやたら寝て楽な日とかあったりするけど。
- 前日の夜遅くても、朝起きるタイミングが強制される
- まあこれは仕事でも一緒ですが(笑)
- 昼間は、子供が起きている間は自分が仮眠をとれない。昼間子供が起きている時間が増えるに従って辛くなっていった気がする。
まあ、3月頭に引っ越しを挟んだ影響でめっちゃ疲れたのをひきずっている、というのもあるのですが。引っ越しは子供が生まれる前にすべし。。
あと、大変だったというかつらかったこと。
育休中、「時間がある」と思われることがなんかつらかった 。
「休業」してるけど、「育児」と「家事」してるんで、 仕事より拘束時間長い ですから。
一日のうち自分の自由時間は最大取れたとして2時間、平均1時間くらいだったと思う。
身についたこと
- 家事
- 料理、掃除、洗濯、食器洗い…
- 文字で書くとそんなもんですが、結構時間取られるし、毎日ルーチンでやり続けるのはかなりしんどいです
- 料理は、味噌汁くらいならパパっと作れるようになりました。レシピを見れば大体のものは作れることもわかりました。並行作業はうまくできないし野菜を切るのも時間かかるし、調味料のアレンジもできないけど、生きていくために最低限のことはできるようになったかなと。
- 育児
- ミルク、離乳食(作る・食べさせる)、オムツ替え、沐浴、散歩(抱っこひも)、病院(予防接種など)、あやす・あそぶ、爪切り…
- 子供の成長とともにやり方も変わっていくので、慣れつつも常に新鮮な感じでした
育児も程々に大変だけど、 どちらかというと家事がしんどい です。
世間に比べれば楽だったんだろうなあと思うこと
夜泣きがなかった
うちは、子供が一切夜泣きをせずに朝まで寝てくれる(いまのところ)。おかげで夜は世間に比べればぐっすり寝られるので、相当楽な方であると思う。
病気がなかった
皮膚がちょっと荒れた程度で、熱も出さなかったし、体調面で手はかからなかった。
※ちなみに育休あけて保育園に通いだしたら、すぐ熱出して、引いた後も1.5ヶ月くらいずっと鼻ズルズル咳コンコンでした。。これはこれで辛い。。。
自分がインドア派
アウトドア派の人間にとっては、電車に乗って外出するのが1ヶ月に1回っていうだけで相当ストレスなんじゃないかと思いますが、自分は何も問題ありませんでした。
むしろ毎日散歩のために家を出ないといけないのが面倒だったw
育休前に考えていたこととギャップ
育児中の生活について男性ならではの工夫ができるか?
こんなこと言うと怒られるかもしれないけど、男性目線で育児を見れば、女性とは異なる視点で、もっと割り切った工夫点が見つかるかな、と思っていましたが、現実はそう簡単ではなかったです。
保育園生活が始まって、家事育児とほんの少しだけ距離を置いた上でまとまった思考時間が取れるようになったら、もう少し冷静な考えが浮かぶかも、知れない。
とりあえず思うのは、子供のためと思うと手を抜けない作業がほとんどなので、工夫して楽しよう、と考えるとしたら、家事くらい。家事の効率化がカギ。
※保育園に通い始めてから、家にいる時間帯はより忙しくなりました。
朝の離乳食も始まってからなおさら。
とりあえず料理なんかする時間はないので、お弁当サービスを使っています。
おかげさまで食器洗いは超減りました!離乳食食器合わせても1時間弱で終わる。超楽。
子供はお父さんっ子になる?
これはどうだろう、まだわからないけど、なんとなく自分の抱っこには安心感を持ってくれているような気はする。
少なくとも嫌われてはいない(笑)
世間の、育休中の妻を持つ男性に知ってほしいこと
あくまで個人的な意見ですが、万が一参考になれば。
- まず、言わずもがなですが、 育休中の育児家事は超大変 ということ。
- 時給換算の論調はナンセンスだとは思うけど、想像以上に負担が、特に 精神的負担が大きい 作業だなと感じています。やってみないとわからない負担があります。
- 女性は出産後、体調が妊娠前の程度まで回復するのに半年〜一年かかる そうです。そのようなハンデのない男性でも、育児家事は辛い作業でした。女性にとってはより辛いはず。それを知っているだけでも日々過ごす気持ちが変わるかと思います。
- 前述のとおり、(自分の場合はだけど)育児より家事が大変なので、 家事を手伝うのが最善 かと思います。料理も洗濯も掃除も、誰だってやればできますので。
- そのかわり、女性側は男性がやった作業にやる気を削ぐような文句を言ったらダメ。
- で、男性は謙虚に自分から改善点について意見を求めるべき。間違っても「やってあげた」とか「手伝ってんのに」とか思ったらダメ。オススメの思考は「自分もこんなことができるようになった。もっと上手くなりたい」
- これは夫婦の関係性にもよるけど、どちらかが上から目線になったらうまく分担できないと思います。あくまで対等に、思いやりを持って。
- 育児関連作業でも手伝えるなら手伝うほうがいいけど、子供に関することになるので、上記のように冷静に対等な目線で話せない可能性があるし、「自分のやり方」が固まりやすく、やり方の違いや教えるのが面倒という点からうまく分担できない可能性も高くなると考えます。
従って、家事の分担よりハードルが高いと思われるため、手伝うならまず家事をやって信頼度を上げてからがいいと思います。
特に言いたいこと
家事育児の一日あたりの仕事のボリュームは、プロジェクトマネジメント的に言うと1.8人日くらいあると思います。
何が言いたいかというと、物理的に1人じゃ回らないということです。
育児はしたことがない人でもこう表現するとボリューム感が伝わるかなと思ってわざわざ言ってみました。
2人いるだけで、自分が何かしているときに別の作業が進む。それがどれだけ肉体的・精神的に助かることか、身をもって超知りました。
こと「今この瞬間」を求めてくる子供 の相手をしているときは、2人いるだけでものすごく助かるのです。
何が言いたいかというと、子供が小さいうちはなるべく家にいる時間を増やせるに越したことはない、ってことですね。当たり前ですね。
育休取得してよかったこと
ここまで大変さばかり書いてしまった感じですが、よかったこと。
- 家事・育児が主体的にできるようになったこと
- 妻との家事分担がやりやすくなり、家庭生活が円滑になりました。
- 育児関係の作業も当然難なくこなせます。月齢が低い時期から参加したことで、より身につきやすかったと思います。
- これはきっととても重要なことで、夫婦で育児をしていくにあたってお互いの理解がある状態になるので、今後も幸福度が高く維持されることを期待しています。
- 秒で成長していく子供の姿をずっとそばで見ていられること
- とくに月齢の低い子供は、日/週単位で様子や癖が変わっていきます。ずっとそばにいると、可愛さは倍増です。
反省していること
育児のノウハウは妻に頼りきりでした。肌のケア方法とか、どんなおもちゃをいつ頃あたえるといいかとか、どんな服を準備しないといけないとか、いつから離乳食始めるとか、調理方法とか、いろいろ。
日々のルーチンと同じくらいかそれ以上に、こういった育児ノウハウの情報収集とアクションが大変かつ大事なのは理解しているのですが、このあたりは妻に頼りきりでした。
金銭面の話
- 給与は育児休業給付金のおかげで、それほど損しません。育休期間6ヶ月までは約67%を非課税でもらえるので、休業前の手取りとそれほど変わりません。ありがとう保険。
- ボーナスはなくなります。これが痛い。
- あと会社の福利厚生関係も大抵はなくなりますので、家賃補助等の福利厚生が充実している会社の場合、つらい部分が増えると思います。
- 一方、家にずっといる生活になるので、変動費の出費は減り、電気代等の固定費は増えます。人によっては月の出費はトータル減るかもしれません。
- 子供の世話のための出費を入れたら絶対増えますが。
その他
よかったもの
- ブレンダー
- 離乳食初期の慣れない時期に離乳食作りがとても楽になった。数千円するけど、一考の価値あり。
- ヨシケイ
- あらかじめ決まったレシピについて、注文した人数分の食材を、毎日宅配してくれるサービスがある。
- うちは3食分/日頼んで、1食分は翌日の昼ごはんに回す生活をした。
- 料理する気力があれば、便利。なにより毎日何食べるか迷う必要がなくなるのは良い。
- 調理が自分たちなので味の調整ができる。レシピも気に入らなければ調整はできる。
- 調理や食器洗いがしんどくなってくると、弁当サービス系のほうがいいと思う。
- スマホで動画
- 家事中にできる唯一の娯楽。
- 子供が起きていると音が聞こえないといけないのでできないけど、寝ているときや妻が見てくれているときなどはスマホがあると動画コンテンツであれば楽しめる。
- 自分はudemyの教材を見たり、アニメ見たり、ゲームのストーリーまとめ動画見たりしてた。3ヶ月くらいで某ゲームの動画8本分見切った。計120時間くらい?家事にかけている時間、半端ない。
ほしいもの
- 食洗機
- 食器洗いは人間がすることじゃないと思う。洗濯機があるんだから食洗機もあるべき…
- でも大きいから賃貸だと結構難しいんですよね…
すべきこと
- 床のものをへらす
- 床に限らず、ホコリがたまる平面上にあるものは極力減らすべきだと思う。掃除のしやすさが段違いのハズ。
- 作り置き
- レシピへのこだわりを減らし、作り置きすると時短になるハズ。意外となかなかできないんだけど。。
おわりに
妻の産休明けから夫のみ育休を取って過ごした経験について書きました。
月齢の低い子供の育児に関われた今回の私の経験は世間的にはかなり珍しいことだったのではないかと思います。
伝えたかったのは以下二つです。
- 家事育児両方やるのは、特に精神面で大変なので、パートナーはそれを理解し、サポートできるとよい
- 男性も育休とる価値はとってもあるので、環境が許すなら是非
人生の価値観は人それぞれですが、少なくとも自分は、仕事を一定期間休んででもこのような期間を過ごせてよかったと思っています。 どのタイミングであれ、男性の育休取得はまだまだ少ないのが現状と思いますが、いい面もつらい面も含めて、皆が経験できるといいのではないかと思います。
金銭面やキャリアのことを考えると、取りたくても簡単には踏み切れない環境であるのは承知ですが、今後改善していくといいなと思います。
長文読んでいただきありがとうございました。
React入門 Redux
React入門本を読んで、Reduxについて勉強した。
React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで (NEXT ONE)
- 作者: 穴井宏幸,石井直矢,柴田和祈,三宮肇
- 出版社/メーカー: 翔泳社
- 発売日: 2018/02/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
基本
- Store
- stateの唯一の保管先。「ここさえ見ればアプリの状態がすべてわかる」。
- Reducer
- stateの変更方法を定義するもの。
- Action
- Reducerに対してstateの変更をリクエストするもの。
store
createStore関数にReducerを指定して、storeオブジェクトを得る。
import { createStore } from 'react-redux'; const store = createStore(myReducer);
storeオブジェクトは以下のメソッドを持つ。
- dispatch(action)
- 与えられたActionに応じ、Reducerに定義された方法でstateを変更する。
- subscribe(function)
- dispatchのタイミングで発火するイベント関数を設定する
- getState()
- storeに保管されているstateを得る
- replaceReducer(reducer)
- storeオブジェクトに関連付けられたReducerを他のReducerに置き換える
- なお、Reducerは複数定義しておいてcombineReducers関数でひとまとめにすることもできる。replaceReducerは動的にReducerを置き換えたい場合に使う。(らしい)
combineReducersは、大きなアプリなどでReducerを分割して開発するほうが効率が良い場合に使う。小さいアプリであれば1つのReducer内で分岐で処理しても問題ない。
Reducer
実体は関数。 storeのdispatchでactionが渡されたときに、その時のstateと渡されたactionを引数にとり、 actionに応じた処理を行う。
以下、一例。
function myReducer(state = initialState, action){ switch(action.type){ case 'MY_ACTION_1': return { ...state, hoge: action.payload.fuga, }; default: return state; } }
Action
Actionを作る関数をActionCreaterという。
後述のFSA(Flux Standard Action)に則ったオブジェクトを返すことが推奨される。
以下、一例。
const myAction1 = () => ({ type: "MY_ACTION_1", payload: { fuga: "hello", } })
myAction1をmyReducerにdispatchすると、stateに{ hoge: "hello" }
が書き込まれる結果となる。
store.dispatch(myAction1());
Reactアプリでの使い方 without react-redux
とりあえず、storeオブジェクト経由でstateの管理を自由にできるので、stateに対して読み書きしたいコンポーネントのpropsにstoreを渡せばよい。
その場合、setStateは使わず、アプリをrenderする関数を作っておき、store.subscribeに登録することで、store更新があったときに再描画が走るようにする。
でもそれだとアプリが大きくなってきたときに、
- 必要なコンポーネントだけを再描画する処理を書くのが大変
- 階層的なコンポーネントにstoreオブジェクトをたらい回しで渡していくのは美しくない
- コンポーネントがreduxに密結合してしまい、再利用性が損なわれる
といった問題があるので、react-reduxを使うとよい。
Reactアプリでの使い方 with react-redux
react-reduxでは、ReduxのstoreとReactのComponentを、connectという関数を介してつなげることで、疎結合なつくりにする。
主な要素は二つ。
Provider
storeを各コンポーネントのcontextを通じてアクセスできるようにするコンポーネント。
自分はまだcontextの仕組みはよくわかっていないが、現状おまじない的にアプリの大元のコンポーネントをProviderで囲むようにする。
index.jsはこんな感じになる。
import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import { createStore } from 'redux'; import rootReducer from './reducers'; import MyApp from './components/MyApp '; const store = createStore(rootReducer); render( ( <Provider store={store} > <MyApp /> </Provider> ), document.getElementById("root") );
Container component
connect関数を使って作られるコンポーネント。 connect関数では、引数に渡す関数を通してコンポーネントのpropsにstateやactionへのアクセス用オブジェクトを渡す。
import { connect } from 'react-redux'; import { myMethod } from '../actions'; import MyAppfrom "../components/MyApp"; // mapStateToPropsでは、MyAppに渡したいオブジェクトを作ってreturn function mapStateToProps(state) { return { ・・・ }; } // mapDispatchToPropsでは、MyAPpに渡したいactionをラップした関数をオブジェクトにしてreturn function mapDispatchToProps(dispatch) { return { myMethod(value) { dispatch(myMethod(value)); }, ・・・ }; } export default connect(mapStateToProps, mapDispatchToProps)(MyApp);
connectの第三引数にmergeProps関数も指定できる。
- mergeProps
- state, dispatchおよびコンポーネント自身のpropsをマージするロジックを書いた関数を渡す。
- デフォルトではmapStateToPropsとmapDispatchToPropsの返り値オブジェクトを単にマージしたオブジェクトを返すようになっている。
基本的には、mapStateToPropsでそのコンポーネントに必要なstateを入れたオブジェクトを返し、
mapDIspatchToPropsでそのコンポーネントに必要なActionを定義した関数が入ったオブジェクトを返し、
mergePropsはデフォルトで使えばよい。
受け取り側のコンポーネントでは、mapStateToPropsとmapDispatchToPropsで返したstate/actionはprops.***で利用できる。
connect関数を書くファイルはContainer Componentと呼ばれる。 このようなコンポーネントを間に挟むことで、Reactのコンポーネントは純粋にViewの処理(+コンポーネントに閉じたstatefulな処理)のみを記述できる。
※対してReactのコンポーネントはPresentational Componentという。
index.jsはこうなる。
import React from 'react'; import { render } from 'react-dom'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import rootReducer from './reducers/reducers'; import App from './containers/App'; const store = createStore(rootReducer); render( ( <Provider store={store}> <App /> </Provider> ), document.getElementById('root') );
ためしに実践
Qiita記事検索アプリ
例によってQiita記事をキーワード検索するだけのアプリを作ってみた。
某RPG風ショップアプリ
前から作ってみたかったお遊びアプリ。
設計について
設計順序とポイントとして、現状は以下がいいかなと思う。
何度か使っていけばもっといい方法が身についていくと思う。
- アプリに必要そうなstateを一通りreducerにinitialStateとして定義する。
- ルート画面のコンポーネントを作り、必要なコンポーネントを洗い出す。
- 各コンポーネントをできる限りStatelessに作る。
- initialStateと各コンポーネントのpropsとactionを確認し、stateの過不足を検討してきれいにする。
- 必要なreducerを定義する。
- reducerはstateごとに作る。
- なるべく単純な操作を行うよう定義する。
- 必要なActionを定義する。
- まずは、reducerが管理するstateに対して単純な操作をするactionとして定義する。
- その後、複数のactionを組み合わせたり非同期処理を入れたりして、UIから直接使えるActionCreaterを定義する。
(そのためには、本で紹介されているMiddlewareのredux-thunkをつかう)
- Container Componentを作る。
発展
以下の記事にて、reducerやactionをどう設計するかについて知見が紹介されている。
- Reducer
- Redux公式ドキュメントで、DomainState、 AppState、 UIState という3つのStateに分割することが提案されているとのこと。(Componentごとに分けるのではなく。)
- Action
- FSA(Flux Standard Action)を使うとよい、とのこと。
- Actionの定義が人によってまちまちになりがちなので標準化したもの。