# 考えたこと ## 前提 ### 銀の弾丸は存在しない - https://ja.wikipedia.org/wiki/%E9%8A%80%E3%81%AE%E5%BC%BE%E3%81%AA%E3%81%A9%E3%81%AA%E3%81%84 - 全てのチームで上手く行くプラクティスは存在しない - そのタイミングのそのチーム、プロダクトに合った解決策を模索する必要がある ### コードの品質は何もしないと下がり続ける - ≒技術的負債 - 基本的に品質の向上は機能追加の要望に劣後する - 意図して負債を返済する意識、プラクティスを実践する必要がある ## テストについて ### 自動テストが書きやすい設計≒良い設計 - テストがしやすい設計、実装は、良い設計であることが多い - それだけですぐに良い設計にはならない事に注意 - 逆にテストがしづらい設計を考えてみる - ランダム、動的な値への依存 - 例:Date.now(), UUID.randomUUID() - 多くの依存を持つクラス - 依存対象が多いとそれだけでテストを書くのが面倒になる - Service層のテストが書きづらい原因はこれ - システムの外部に依存するクラス - データベース、ファイルシステム、クラウドストレージ等 ### 自動テストを書くのも技術の1つ - すぐにはできないかもしれない - 覚えなきゃいけないテクニックがそこそこある - モック、スパイ、パラメタライズドテスト等 - 理想はテスト駆動開発(=テストを先に書いて実装を後から書く、テストと実装のループで設計を改善する) - 参考:https://www.amazon.co.jp/dp/B077D2L69C/ ## 実装について ### 重複するコードが生まれたら、共通化できないか考える - 既存の処理で代用できないか考える - 重複する部分に共通する意図は何か考える - 無理やり共通化するとかえって混乱する場合もある - コードよりも、意図に注目する - 共通化の方法はいくつかある - クラス内のprivate関数、新しいクラス、パッケージ等 ### 名前で意図を表す - コードをじっくり読まないと意図が分からないのは危険 - 読み手によって意図が誤解される可能性が高まる - インターフェース、抽象で意図を表現する - 「〇〇な条件を満たすkeyがuserでvalueがユーザー名のマップを配列に詰めて返す」のは実装 - 「〇〇なユーザーを取得する(=getHogehogeUsers)」のが意図 ## ServiceとRepositoryについて ### Serviceでは業務の流れ、仕様を表現する - 細かい実装をさらけ出しすぎない - 「どのように値を取得するか」の詳細はRepositoryの実装に任せる - 例:TypeORMのQueryBuilder等 - 例外をどのように投げるかも仕様の一部 - 例:例外が返ってきうる箇所では必ずtry-catchする等 - 単なるErrorよりもClientStatusCode等で具体的に例外を表現する - エラーメッセージでトレーサビリティを意識する - リクエスト時のIDを吐き出す - どのような処理が失敗したか、分かるようにする(単なるfailより、fail to get hogehogeとか) ### Repositoryのインターフェースで、どのようなデータの処理ができるのかを表現する - インターフェース上で実装に寄り過ぎない - 細かい実装が変わってもインターフェースが変わらないのが理想(必ずそうなるわけではない) - 例:DBの設計が変わった、配列の処理をfor文からmapに変えた等 ### Repositoryの実装で具体的にデータを取得する処理を書く - typeORMのQueryBuilderとかはここに書く ## その他 - PR上で「修正内容の概要」「修正した背景」「修正の意図(なぜそうしたか・しなかったか)」をレビュワーが伝わるように書く - 今回自分はチケットとかイシューがあったわけではないので、ここで情報が完結するようにしてた - レビュー時間短縮=デリバリまでのリードタイム短縮=競争力に繋がる ## 今回考えなかったけど考えた方が良さそうなこと(考えてたらごめんなさい) - Params, Entity, VOのそれぞれの役割 - パッと見てる感じ、以下のような理解だけどもう少し明確にコードで表せると更に良さそう - Params ... 外部(HTTP通信)から受け取ったパラメータ - Entity ... Databaseに格納されるオブジェクトの形 - VO ... クライアントに返却されるオブジェクトの形 - もう少しシステムが複雑化してきたらこれらとは別のDomain Objectを作成して業務ロジックを集約していきたい - 1Repository内で複数DBを扱うことについてのルール - サブクエリ、JOIN等やっちゃダメなわけじゃないけど、ルールがないと無秩序になりやすい - 取ってきたクエリの結果をどこでVOに変換するか - async/await, どこでawaitするか - 現状Repositoryでawaitしてたりしてなかったりする - 本来awaitが必要ないところでもawaitしてないか? - Factoryを作るか否か、Factoryを作るとしたら作るのはEntityかVOか