💃
【Golang】アーキテクチャにおける適切な構造体
モデルに関して某pomeさんから教わったことpart1です。
「ソフトウェアは用途によってクラスや構造体を分ける必要がある」
弊社のプロジェクトはgo-swaggerでスキーマ駆動にしており、コードが自動生成されるので、型も自動生成されます。しかし、その自動生成された型を無理にいろんなところで使いまわしていると、下記のようなありがたいお話をしてくださいました。
例えば
入力 ---> 処理 ----> 保存 ----> 出力
のステップがあり、入力の時点の構造体は
入力
id ない
createdAt, updatedAt なし
(具体例: HTTP Requestのデータを持つ構造体,APIのリクエストの定義から生成する。
openAPIの定義から生成された構造体など)
だとしても、
処理の段階でidを生成する場合は、入力の構造体に対してidというフィールドが多い構造体になる。
処理(M)
id がある(生成)
news.IsXxxx()
(具体例: モデルの構造体)
また、保存するときに、createdAtやupdatedAtを生成する処理であれば、保存時の構造体にはcreatedAtやupdatedAtというフィールドを持った構造体になる。
保存(M) <--- repository
createdAt, updatedAt ある(生成)
(具体例: DBのテーブルデータを持つ構造体で、RDBのテーブル定義から生成する)
さらに、出力時idも作成日も更新日も取得したい場合にはid,createdAt,updatedAtも持った構造体になる。
出力
id, createdAt, updatedAt ある
(具体例: HTTP Responseのデータを持つ構造体でAPIのレスポンスの定義から生成する。)
このように、それぞれのステップによって、適した構造体があるので、一つの構造体を無理に使い回すのではなく、それぞれのタイミングで適切な構造体を作った方が良いらしいです。
それをいい感じに定義できるのがクリーンアーキテクチャだったりオニオンアーキテクチャだったりします。
なので、自動生成された構造体は、出力や入力の部分で使えても、保存や処理の部分でフィールドの過不足が出る場合は個別に構造体を定義するのが好ましいです。
上記で説明した入力/出力の構造体、DBテーブルのデータを持つ構造体は、モデルのようでモデルでないのです。
Discussion