コード最適化/仕事経験の重要性についての実体験

✍🏼 作成日 2015年10月30日   
❗️ 注意:この記事が作成されてから既に 日が経過しています。情報の鮮度にご注意ください

はじめに

プロジェクト経験がなかったため、フロントエンドとバックエンドの役割分担でよくミスをしていました。

本文

例えば、ボタンをクリックしてバックエンドから提供されたAPIでデータを取得し、handlebarを使ってフロントエンドに表示する機能を実装する必要がありました。しかし、毎回取得するデータ(配列で返され、各要素はmap型)は比較的長く、すべてを一度に読み込んでページに表示するのは適切ではありませんでした。そこで、私は「ボタンをクリックするたびにバックエンドからデータをクエリする」ように設計し、取得したデータに対して毎回slice処理を行い、同じ長さで切り取るようにしました。つまり、最初は0からxまで、次はxから2xまで、というようにしました。

しかし、ここに問題がありました。バックエンドのSQLクエリで取得したデータがorder byされているかどうかが不明だったのです。もしorder byされていなければ、ボタンをクリックするたびに取得するデータは無秩序になります。配列の順序が保証されない場合、順番に切り取ったデータが意図したものになるかどうかも保証できません。例えば、最初に切り取った0からxの配列要素にhが含まれていても、次にクエリしたときにはhがx+hの位置に移動してしまい、再度クエリされてhandlebarに渡されてしまう可能性があります。これは正しくありません。

もちろん、私は自分のできる範囲でこの問題を解決しようとしました。そこで、フロントエンドで配列の要素のうちuidなどのプロパティを使ってsortしようと考えました。すると、フロントエンドのリーダーが私に何をしているのか尋ねてきたので、バックエンドから取得したこの無秩序な配列をsortしようとしていると伝えました。彼はこう言いました:

『これはバックエンドがやるべきことで、フロントエンドでやるとパフォーマンスに影響する』

そして、次のように説明を始めました:

『一般的に、フロントエンドはバックエンドから提供されたAPIを使うだけで、APIで取得したデータを再処理する必要はありません。ただし、handlebarのようなテンプレート内では、取得したデータのプロパティを組み合わせて処理し、ページに出力する必要がある場合もあります。しかし、あなたの場合は明確にバックエンドがやるべきことです。彼らはAPIを提供する際に要件を満たすようにする必要があります』

『あなたの現在の状況は、ページネーション機能を実装する必要があるが、バックエンドのAPIは毎回すべての内容を取得するしかできず、必要な分だけをクエリすることができないということです。つまり、既存のAPIでは要件を満たせません。どうすればいいでしょうか?2つの案があります:時間が迫っているならフロントエンドでパフォーマンスを犠牲にして直接処理するか、時間に余裕があるならバックエンドにAPIを要求するかです。startやoffsetを追加するだけのAPIで、書くのは難しくありません。』

また、もう一つのベストプラクティスがあります:クエリ操作はできるだけ少なくし、データベースから情報を取得するよりもページから情報を取得するようにすること
例えば、バックエンドにAPIを追加した後でも、私は4回のクエリ操作を行う必要があります:初期化、さらに読み込むボタンのクリック、タブの切り替えです。毎回パフォーマンスのロスがあります。なぜでしょうか?私のロジックは次の通りです:

1回目:ページ初期化時にデータをクエリし、固定長の配列を切り取ってページにデータを配置します(クエリ1回)。「もっと見る」ボタンを何回クリックする必要があるかを判断するために、取得した全データの長さを必要なデータ長で割り、整数部分に1を加えた回数がクリック回数になります。この回数だけクリックするとすべてのデータが読み込まれ、「これ以上ありません」ボタンが表示されます(クエリ1回)。これは間違いないでしょう?

2回目:「さらに読み込む」をクリックするとデータをクエリし、必要な長さをページに配置し、クリック回数countを+1します(クエリ1回)

3回目:「マイコミュニティ」と「マイアクティビティ」という2つのタブがあるため、これらのボタンをクリックするたびにクエリが必要です(クエリ1回)

最も困ったのは、私は「マイコミュニティ」と「マイアクティビティ」という2つのタブの内容を重ねてしまったことです!つまり、ボタンをクリックするたびに元の内容がjQueryの$(container).html()メソッドで強制的に置き換えられてしまいます。コンテナが1つしかないため(私の設計)、タブの切り替えではhtmlを使うしかなく、「さらに読み込む」をクリックしたときだけappendを使えるのです!
本当に恥ずかしいことです。

あとがき

その後、私は前述のベストプラクティスに従いました。さらに、機能をできるだけ分離し集中させるようにしました。どういうことでしょうか?つまり、タブの切り替えはタブ自体が担当し、データのクエリは関与しない(機能の分離)、そして「さらに読み込む」ボタンはデータのクエリだけを担当し、他のことはしない、ということです。さらに、ページ初期化時にもtriggerを使ってこのボタンを発火させてデータをクエリするようにし、ページ読み込み時に最初にクエリして、ボタンクリック時に再度クエリするようなことはしませんでした(機能の集中)。

- EOF -
この記事の初出: コード最適化/仕事経験の重要性についての実体験 - Xheldon Blog