特に計算が必要ないbackendのGETはSQLゲーになる
と思う
書いた後に、「これめちゃくちゃ当たり前のことでは」という気もしてきたmrsekut.icon
どいういうものを想定しているか
RESTfulのAPI server的なもの
GET処理の話をしている
ORMを使っていない
計算が殆ど必要なく、DBにあるデータを整形して返す
server側で状態を管理する必要がない
対応するclient実装が2つ以上存在する
e.g. Webの実装と、アプリの実装があって両方とも同じserverを見ている
例えば、投稿(Post)を返すようなAPIを実装したいとする
Entityはこんな感じだとする
code:ts
type Post = {
id: PostId;
title: string;
contents: string;
author: User
}
type User = {
id: UserId;
name: string;
}
こんなAPIを作りたい
/posts :: () -> Post[]
例えば、2つのアーキテクチャを想定できる
再利用を重視した、「個別にDBから取得する関数」を用意するパターン
code:/posts/usecases.ts
export const getPosts = async () => {
const posts = await PostsRepository.getPosts();
const authors = await Promise.all(
// getUserByIdを呼んでpostsに対応するauthorを取得
);
return makePosts(..)
}
code:/posts/repositories.ts
export const getPosts = async () => {
... // DBから取得する
return {
id,
title,
contensts,
authorId // ← UserのEntityではなく、UserのIdを返す
}
}
code:/users/repositories.ts
export const getUserById = async (userId: UserId) => {
... // DBから取得する
return {
id: userI,
name
}
}
getUserByIdのような関数を用意しておくことで、「Userの取得」の処理を再利用しようという魂胆
1回のSQLでほぼ全てを構築するパターン
code:/posts/usecases.ts
export const getPosts = async () => {
return await PostsRepository.getPosts();
}
code:/posts/repositories.ts
export const getPosts = async () => {
... // DBから取得して、整形
return {
id,
title,
contensts,
author
}
}
SQL内でJOINして1回のSQLで必要なデータを全て取得する
両者の比較
再利用性
前者の方が関数を小さく切っているのもあり、再利用性が上がる
後に似たような構造を返すAPIを作る時に多少楽になるかもしれない
後者は、1つ1つのSQLが前者に比べて複雑になる
SQLは再利用しづらく、1つのAPIに対して、1つのSQLのような実装になる
APIを作るたびにそれに特化したSQLを書く必要がある
SQLの実行回数、パフォーマンス
前者は、最悪N+1問題のようなことが起きる
ORMを使っていれば解消しやすいのかもしれない
後者は、必要なデータを1回のSQLで取得する
内部で結合が何回か必要になるが、複数回SQLを呼ぶよりは速いはず
Usecase層の処理
前者は、Repositoryの結果を組み合わせる必要があるので、Usecase層の処理がやや複雑になる
後者は、殆ど必要ない
Repositryの返り値ですでにEntityが出来上がっているので、それを返すだけ
GETの場合は殆ど不要になると思う
強いて言えば、外部サービスと連携する時は必要になる
例えば、DynamoとかContentfulとか検索エンジンとか
その辺の返り値をUsecase層で合体させる
でもこれは、前者も同じ
修正容易生
後者は、1つ1つのAPIがほぼほぼ独立するので個別に修正することができる
修正しても他に影響がない
前者は、1つの関数の返り値が変わった時に、多くのものに影響を及ぼす
と、思ったが実際は意外とそうでもない気もしてきたmrsekut.icon
interfaceが合っていれば内部で何をやってもいいし、異なるなら新しく作ればいいだけ
interfaceに修正が必要なら新しく作ることになる
後者のほうが良いと思うmrsekut.icon
SQLで全てのデータ構成してしまって返すだけでいい
基本的に、1つのAPIに対して、1つのSQLを書けばいい
各APIの結合をできるだけ薄くする
前者の方が開発速度だけで言えば速いかもしれない
ただ、依存が増えるので修正は難しくなる
開発速度に関して言えば、SQLを書く能力をめちゃくちゃ上げればいい
その再利用と依存、修正コストと見合っているのか?を考える