Software Design 202307
ペアプロ・モブプロ
- スキルの高い側は:
- 発言のハードルを下げる
- 例えば
- 理解度を確認する
- 判断を委ねてみる
- 感謝する(聞かれて逆に理解深まったよ的な)
- スキルの低い側が遠慮して喋らなくなってしまいがちだから
- 例えば
- 弱みを見せる
- わからない 、と率直に言うことでハードルを下げておく
- 発言のハードルを下げる
- スキルの低い側は:
- 積極的に質問する
- 能動的にアクションして得た知見は記憶に残るから
- 優先的にドライバーをやる
- 分かっている人がドライバーだと理解が不十分なままスラスラ進んじゃうから
- 積極的に質問する
- 共通認識を持つ
- どんな発言もチームにとって価値があること
- ペアプロ・モブプロをやったほうがいい兆候
- 「聞いてくれればすぐわかったのに」
- レビュー段階にて、そもそも設計が不適切だったことが発覚する
- レビュー指摘後に問題が修正されていない、手戻りが何度も発生する
- 一時的なモブプロ・ペアプロも有効
- 最初の 30 分だけペアプロする
- 難しい技術課題が見つかったときだけする
gRPC で始める Web API 開発
gRPC の特徴と登場背景
- gRPC とは
- 手元のプログラムから遠隔地に存在するプログラム処理の呼び出しを行う技術
- IDL
- インターフェースの定義に使用できる言語
- 特定のプログラミング技術に依存しない
- Protocol Buffer
- gRPC で採用されている IDL
- Protocol Buffer により記載した、サービス・メソッド・メッセージの定義を元に、API クライアント(Stubs ともいう)が自動生成される。
- Protocol Buffer の役割
- インターフェースの定義をする
- データのシリアライズ・デシリアライズをする
- 各プログラミング言語のデータ構造と対応する形でデータをシリアライズ・デシリアライズできる
- これにより、お互いの言語を気にする必要が完全になくなる
- シリアライズ等の処理は API クライアントに隠蔽されているので意識することはない
- protoc
- IDL からコードを生成するコンパイラ
サービスやメソッドの定義の例
- サービス
- RPC メソッドの集合
- メソッド
- メソッドごとにリクエストとレスポンスの型を指定する
- リクエストとレスポンスのことをメッセージという
service ProductManagement {
rpc GetProduct(GetProductRequest) returns (GetProductResponse) {}
rpc ListProducts(ListProductsRequest) returns (ListProductsResponse) {}
rpc CreateProduct(CreateProductRequest) returns (CreateProductResponse) {}
rpc UpdateProduct(UpdateProductRequest) returns (UpdateProductResponse) {}
rpc DeleteProduct(DeleteProductRequest) returns (DeleteProductResponse) {}
}
メッセージの定義の例
- 型、名前、フィールド番号(タグナンバーからなる)
message GetProductRequest {
uint64 product_id = 1;
}
message GetProductResponse {
Product product = 1;
}
message Product {
uint64 product_id = 1;
string name = 2;
string description = 3;
uint64 price = 4;
}
gRPC の特徴
- RPC フレームワークである
- 「フレームワーク」なので、API と Client の間でやるべきことをほとんど代わりにやってくれる
- 技術選定や実装の幅を減らすことで:
- 強い規約が不要になる
- メンバーのキャッチアップコストが減る
- ライブラリのメンテナンスコストが減る
- 現代的
- 現代的な開発体験
- 自動生成されるコード
- 型チェック
- IDE 補完
- インターセプター
- middleware ともいう
- ロガー・認証・分散トレーシングの実装が容易
- API の段階的な変更・リリース
- メッセージの自動バリデーション
- 現代的な技術
- HTTP/2
- 高効率
- ストリーミングの実装が容易
- HTTP/2
- 現代的アーキテクチャ(マイクロサービス)との相性の良さ
- 現代的な開発体験
- 高効率
- JSON よりも小さい
- どんな環境でも動作する
- 言語・プラットフォームに依存しない
- (ただしブラウザではいまいち使えないらしい)
- オープンソース
gRPC のデメリット
- HTTP/2 に対応していないレイヤーがあると使えなかったり面倒だったりする
- デバッグ難易度が高い
- バイナリなのでネットワークタブは使えない
- grpccurl など専用ツールが必要
- REST 等と比較して情報が少ない
登場の背景
- Stubby という、Google 社内で使われていた高パフォーマンスな RPC フレームワークがあった
- これを標準技術を活用する形で作り直し、オープンソースとして公開したもの
- 主眼は「パフォーマンス」
他の技術との比較
- REST API
- CRUD の枠に収まらない昨日の開発を行う際、メソッドの設計にある程度の幅がある。gRPC にはその迷いはない。
- 一方、キャッシュを聞かせる場合は REST API が楽(GET リクエストは全てキャッシュ、とか)
- GraphQL
- GraphQL はラウンドトリップ回数を削減してパフォーマンス向上を図る
- クライアントでの複雑かつ柔軟なデータ取得が重要な場合に向いている
- 双方向ストリーミングの機能は無い
ブラウザでの利用
一筋縄ではいかず、以下のいずれかが必要
- gRPC-Web
- ブラウザは HTTP/2 に対応していない場合もあるので、HTTP/1.1 に変換するために Envoy Proxy なるものを内部的に使っている
- gRPC-Gateway
- protoc のプラグインである
- gRPC との通信を REST API 風の Web API に変換するプロキシサーバを出力する
- メッセージは JSON になる
- Protocol Buffer のスキーマから OpenAPI のスキーマ生成も可能
- Connect
- Buf という gRPC ラブな会社が作っている、gRPC のスーパーセット的なものらしい
- とても有力な選択肢だが、2023/5 時点で connect-web はまだ正式リリース前な点に注意
その他
- protoc-gen-doc
- コメントを基に Markdown や HTML などで出力できるツール
(その他の項目は必要になったら読む)
瞑想
- 科学的に明らかな効果あり
- ストレスと不安の解消
- 集中力や意思決定力の向上
- 想像力の向上
- 睡眠の質の向上
- やり方
- 座る
- 背筋伸ばす
- 肩の力抜く
- 軽く目を閉じる
- ゆっくり呼吸する
- 今&呼吸に意識を向ける
- 鼻から吸って口から吐く
- 考えが浮かんでも OK、再び意識を呼吸に戻す
- 5 分からはじめる
GoF デザインパターン
一部は現代でも役立つ
- Proxy
- Remote Proxy
- 離れた場所にあるものを使えるようにする
- Virtual Proxy
- ハイコストなものを使いやすくする
- キャッシング
- 遅延初期化
- ハイコストなものを使いやすくする
- Protection Proxy
- アクセス制御
- Remote Proxy
- Iterator
- リスト等において中身を明かさずに要素にアクセスできるようにする
- Observer
- ある値の変更に付随して別の箇所の値を変更する
- Singleton
- 1 つだけインスタンスを作る
- Composite
- 階層的な構造を扱うためのデザインパターン
- 個々のオブジェクトとその集合のオブジェクトを同一視する
- 個々のオブジェクトとオブジェクトの集合を 同一の方法で操作可能にする
以下などは C++的オブジェクト指向の遺物っぽい。今は関数が一級市民だからでなんとでもなる。
- Bridge
- Strategy
- Factory Method
Deno + Rust
- Wasm / WebAssembly
- バイナリ形式のアセンブリ風の言語
- 仮想マシン上で動くため OS や CPU に依存しない
- C、Rust、Go など色々な言語からコンパイルできる
- Deno で Wasm を使う場合は、wasmbuild というツールを使う
- Deno から Wasm の関数を簡単に扱うためのコードを自動生成してくれる
- JS 側では単にインポートして関数を呼び出すだけで OK
Go 言語らしい書き方
- if 文を以下と組み合わせて使う場合は else を省略できる
- 早期リターン
- continue
- break
- goto
if ok := check(); ok {
doSomeThingA()
return
} else {
doSomeThingB()
}
// ↓
if ok := check(); ok {
doSomeThingA()
return
}
doSomeThingB()