0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ページネーションのtotal件数を実装する前に確認すべき3つの観点

0
Posted at

この記事でできること

一覧APIで「全件数(total)」を返す実装では、パフォーマンスのために内部処理を絞り込むための上限(取得件数の上限、スコアリング対象の母集団サイズなど)と、ユーザーに見せる正確な件数を、同じ配列やクエリ結果から作ってしまいがちです。この記事は特定の実装コードではなく、ページネーションのtotalを設計する/見直すときにチェックすべき3つの観点を整理したものです。個人化ランキング・検索結果・レコメンドなど、「内部処理のために母集団を絞り込む」構造を持つ一覧APIであれば当てはまります。

背景: なぜ気づきにくいか

一覧APIでは、パフォーマンスや計算量の都合で「まず候補をN件に絞ってから、その中で並び替え・スコアリングする」という実装がよく使われます。このとき、total(合計件数)を「絞り込んだ後の配列の長さ」からそのまま作ってしまうと、絞り込みの上限(N件)がそのままtotalの上限になってしまいます。

厄介なのは、ページ送り自体は別の仕組み(次のページを取りに行くクエリ)で動いていることが多く、実際にはNを超えた先のデータにも複数リクエストでたどり着けてしまう点です。つまり「ページは先に進めるのに、totalだけ足りない」という、辻褄の合わない状態が発生します。しかも1ページ目だけを見ている限りは正しく動いているように見えるため、テストやレビューでも見落としやすいところです。

観点1: totalの計算と、内部処理を絞る上限を分離する

「内部処理を絞り込むための上限(N件)」と、「ユーザーに見せるtotal」は、目的が異なる別々の値です。前者はパフォーマンスのための制約、後者は正確な情報提供のための値なので、同じ配列やクエリ結果を使い回さず、それぞれ専用に計算します。

  • 絞り込み用: .limit(N)を付けたクエリで候補を取得する
  • total用: フィルタ条件だけを適用した(.limit()を付けない)クエリに対して、別途.count()を投げる

同じフィルタ条件を2回クエリすることになりますが、正確性を優先するなら妥当なコストです。

観点2: ページ送りが実際に到達できる範囲と、totalが一致しているか確認する

ページ送りの実装(オフセット指定・カーソル指定・除外ID積み増しなど)が、内部処理の上限(N件)を超えた先のデータにも到達できる設計なのかを確認します。

  • 到達できる設計なら、totalも上限に縛られず正確な件数を返すべき
  • 到達できない設計(その上限が事実上の「全件」を意味する)なら、totalが上限で頭打ちになっていても矛盾はない

自分の実装がどちらに該当するかを言語化せずに実装すると、「ページは進めるのにtotalだけ足りない」「totalは正しいのにこれ以上ページを送れない」のような食い違いが起きます。

観点3: 条件分岐しているコードパスごとに、同じ考慮が漏れていないか確認する

ログイン/未ログイン、検索あり/なし、個人化あり/なしのように、一覧取得のロジックが条件分岐している場合、片方のパスだけ実装上の都合(スコアリング用の上限など)を引きずっていないかを確認します。

一方のパスが最初からtotal用に正確なCOUNTを取る設計で書かれていても、もう一方のパスが後から追加された個人化処理の都合で「絞り込み後の配列の長さ」を流用していた、というケースが起こり得ます。分岐しているパスごとに、同じ観点でのチェックを当てはめます。

まとめ

  • totalの計算と、内部処理を絞り込むための上限(母集団サイズなど)を、同じ値から作らない
  • ページ送りが実際にどこまで到達できる設計かを確認し、その範囲とtotalが示す範囲を一致させる
  • 条件分岐しているコードパスがある場合、片方だけ実装の都合(絞り込み用の上限など)を引きずっていないかをパスごとに確認する

実際にこのバグが起きた経緯はZenn版にまとめています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?