---
# System prepended metadata

title: 2021/8/29 メンター相談
tags: [メンター相談, 8月]

---

# 2021/8/29 メンター相談

###### tags: `メンター相談`,`8月`

## webアプリケーションのログにはどのようなことを出力しますか？ログ出力に関する指針などチームで設けていますか？

[質問リンク](https://airtable.com/tblA4yYGHwaqDYKwx/viwAUwNVsR9rOkW6u/recshCEJbHHw92OOY?blocks=hide)

- 2つの観点がある
    - デバッグ
        - エラーが起きた時の状況を知るときにクラス内の変数などを全部詰めて送るようにしている
        - スタックトレースは入れている
            - 自分で設定しないといけない場合hもあるので、入れている
        - ユーザーの環境
            - フロントの場合はsentryを使うと、直前のボタン操作なども記録してくれるので、追いやすくなる
                - https://sentry.io/vs/logging/
            - ログロケットなどもある
                - https://logrocket.com/
        - 変化が早いので、新しいツールを早く知って使ってみるのがいい
    - メトリクス
        - ログレベルを使う
            - info、warning,error
                - エラーの数を集計して、閾値を決めて、超えたらアラート出す
            - SLA（サービスレベルアグリーメント）を作るときに、warningも含めるのか、などを決める
        - みやすさ
            - jsonにしないで、文字列にするとパースが面倒
                - エラーメッセージと引数とコンテキスト情報は、文字列だと解析しづらいので、json化することが多い
                - node.jsだとbunyanを使ってパースしやすくしている
                    - https://www.npmjs.com/package/bunyan
        - アクセスログはログレベルは決めていない
        - warningは、アプリとしては正常動作するけど、何かおかしい場合
            - 松原さんはあまりwarningとして出したことがない
        - 開発（=検証環境を指す）と本番のログは保存先を分ける
            - 開発環境はデバッグしやすいようにログをたくさん飛ばす
            - infoレベルであれば個人の判断で入れる
            - メトリクスに入れるレベルだとレビューは入るかも
            - SLAを満たせないとペナルティがあったりすると、決済者レベルの承認がないといけない気がする
        - GCPだとログメトリクスの条件を作ることができる
            - その条件を超えたらslackにアラートを飛ばすようにしていた

- サービスの測定
    - ログを吐き出すのはアプリケーション責務だが、集計は内部でやる
    - ログをcsvで吐き出して、あとはそれをエクセルでいじってもらう
    - 集計作業はアプリケーションと分けるのが大事だと思う
    - 集計する側が開発わかる人の場合、集計は自由にいじっていいとしたいときに分ける方が後々楽になる
        - 昔怖い目にあったことがある    


## DDDにおける例外処理について

[質問リンク](https://airtable.com/tblA4yYGHwaqDYKwx/viwAUwNVsR9rOkW6u/recLkxF41rIsymoIw?blocks=hide)

### ①以下のイメージであっていますか？

ドメイン層の共通エラークラス・ユースケース層の共通エラークラスをそれぞれ定義し、それをプレゼンテーション層にてキャッチし、
・ドメイン層/ユースケース層で定義されたエラー → ステータス400を返す
・それ以外のエラー → ステータス500を返す

- DDDはエラー処理についてあまり決まりがない
- チームの認識があっていればそれでよい
- HTTPステータスは種類が少なすぎてフロントエンドで役に立たない
    - エラーコードを返している
    - ステータスはざっくり500にしている
- ユースケースに渡すまでもないときは400にしている
    - これがきているということはフロントが壊れている証だから
    - これがくるのはメトリクスとしても異常事態だと思っている
        - バリデーションが適切に働いていない
        - 不正アクセスの疑い
- たまに404を使う
    - 検索をして、ヒットが0だった時に404は変ではないのか？空で返すべきではないか？は人によって意見分かれる
    - 松原さんなら正常で0件なら、200にする
    - 見つかるはずなのにない場合は、200以外にする

### ②エラーの共通化クラスはどのディレクトリに置いていますか？それぞれのレイヤーに `shared` ディレクトリを配置し、そこに置くのでしょうか。

- はい
- application/shared/error など

- プレゼンテーション層のsharedのエラーにしている
    - httpステータスごとのエラーがある

### ③例外発生時にエラーをthrowせずに直和型を返す方法もあるようですが、この方法を採用したことはありますか？

- 使おうとした記憶あるけど、普段使ったことはない
    - 例外が発生するのがどれだけ致命的な状況なのかによる
    - 書き込みできない状況 -> 確実に止めたい
        - result型を使うと、そのまま処理が進んでしまう可能性がある
- throwとcatchだとハンドルしない場合、伝搬するので必ずどこかで止まってくれる。致命的な状況ならばthrowを選択する
- if (e type of NullPointException) みたいなTypeごとにわける手法はあまり採用したくない
    - catch中身は最低限のものにしたい
    - なぜなら、その中でエラーが発生したときにアプリケーションが止まってしまうので
    - catchの中では何もしないようにしたい
    - 複数の条件があるのならば、複数のtry/catchでわける
- Question: 複数のtry/catchとは？
    - １つの処理毎にtry/catch実行する。


## DDD 課題の「チーム名が３文字以下でなければならない」はドメインルールなのか、フォームバリデーションなのか？

- アプリケーション次第になる気がする
    - 企業コードは3桁ではないといけない は ドメイン知識
    - 初回登録には200文字しかプロフィールを入れられないが、登録後に1000文字入れられる (画面都合のルール) は コントローラーに書く
    - 他の画面でも守らなければ行けないルールかどうか？
    - validationRequest(req)のところは必須項目チェックや型チェックが多い
    - ドメインモデルで定義したものをこのバリデーションから呼び出すのはよくないか？
        - あまりしないかも
        - 同じことをやっているので、どちらにせよドメインでかけるのであれば、validationでやる必要はないかと思う
        - validationRequestの中身は`name.length > 3`とか以外のバリデーションになると思う 
        - validateのロジックは、リクエストのパラメータが存在するか存在しないかのチェックに留める
- コントローラーのvalidateはnest.jsに任せる事が多い
    - プロパティがあるかどうか
    - 型があっているか
- どのフィールドでエラーになったかどうかをどう知らせるか？
    - nestjsは知らせてくれるが、文字列なのでパースが必要
    - まずフロントエンドでバリデーションしたい
    - それでもエラーになる場合は、フロントエンドが壊れているということになるので、400エラーを返す

## TypeScriptで公称型を表現する方法で、良い方法はありますか？以下のコードをどう思いますか？
> https://bit.ly/3mtGbTu (TS Playground に飛びます)
> https://qiita.com/suin/items/57cfc0ec9bb1a6995aa5#three-ジェネリクスを使う を参考にしました

- Qiitaに書かれている処理と同じようにジェネリクスを利用する

## 技術選定

- 会社での決め事はなく、チームごとに判断している
- (フレームワーク)余裕があれば、テストアプリを作る
    - 実装して初めて疑問が出てくる
    - 大量にデータが入ってきて初めて問題になることがある
- 松原さん書ける人がいるかどうかを重視している
    - 重量フレームワークはあまり使わない
    - 自分たちで書いておけば直せる
- フレームワークが解消してくれるのは作業時間
    - なれてなければ早くない
    - コードを書く時間は短い (読むほうが多い)
    - 読みやすさを重視して、軽量フレームワーク + 自分たちで書く
- `hoge gotchas` で検索する
    - gotchas ハマりどころ
    - 自分たちに当てはまりそうなところがあるか確認できる
- ライブラリを入れるかどうかチームで確認する？
    - 場合によるが、確認する場合が多いかも？
    - ライブラリ選定に問題があった場合、手戻りが発生してしまう
- ライセンス気にしている？
    - してない (イケてない、、)

## その他

- goのエラー処理
    - エラーが有る場合はエラーと通常の戻り値を両方返す
    - 本当にやばいときにpanicを使う (throw)
        - panicとエラーの使い分けをしている
    - バグとエラーの違い (t-wadaさんのスライドがあったはず、、)
- prismaから取得したものをエンティティにマッピングするのは、1回はかかないといけないが、1回で済むはず
    - railsのように自動ではやってくれない
        - railsはそこらへん密結合
- ドメインとコントローラのバリデーション
    - 同じことをチェックすることはしない
    - ドメインルールの場合は、ドメイン層にバリデーションを書き、コントローラに書く
- バックエンド(ドメイン層)とフロントのバリデーション
    - バックエンドでチェックしているからフロントでは必要ない派
    - UXのためにフロントでも重複してチェックする派
        - 両方同じ言語で使っていれば、共通化できるかも、、？
        - 同じ言語で書くことはまれなのでおそらく重複して書いているはず

- typeormを使うときは、@transactionをつけると全部トランザクション化されるので、ユースケースの中にインフラの知識が漏れるが、漏れたとしても扱いやすいからそれだけ例外を認めるケースが多い
    - prismaの場合は $transaction で囲ってトランザクションを処理する
    - これは複数の集約をまたいだ整合性をどのように担保すればいいのかに関係する