パフォーマンス改善おじさん

こんにちは。デザインシステム室の祖父江です。
普段はサーバーサイドでひっそりとロジックを組んだり、
マイグレーションを戻したり、進めたりして暮らしています。

デザイン・システム室では各々の得意分野や持ち味はあるものの、「あの人はフロント、あの人はサーバーサイド」という明確な区分けはありません。というわけで、フロントエンドのパフォーマンス改善案件に引っ張り出されてきました。

それにしても、フロントエンド開発は慣れないですね。
「Reactっていうのを使うらしいです。」(スニーカーのことかな)

というわけで、パフォーマンス改善おじさんが誕生しました。
(数週間前はデプロイおじさんでした。)

パフォーマンス0点


Lighthouseを用いて測ったパフォーマンスは0点ということが知らされました。
なにこれ!壊れてるんじゃないですか????

改善方法

何か一つを変えれば劇的に変わるわけではないパフォーマンス。一つ一つやれることを積み重ねて行くしかありません。(まぁ、0点なのですから。やれることを見つけることはフロントエンド 開発に疎い私にも容易であるに違いない。)

画像を圧縮する

不必要に高画質になっている画像を適切なサイズに圧縮します。単純ですが、手っ取り早く効果があります。

お気軽にRMagickを使って、画像のqualityを下げて置き換えるだけのImageCompressorなるクラスを作ったりして遊んでみました。画像にエフェクトもかけられますが、今回はただ画像のクオリティを下げて置き換えるメソッドしかありません。

require 'RMagick'

class ImageCompressor
  class << self
    def read(image_path)
      Magick::Image.read(image_path)
    end

    def optimize(image_path)
      original_image = read(image_path).first
      original_image.write(image_path) {
        self.quality = 70
      }
    end
  end
end

実際にアプリケーションに組み込まれる際には、画像が紐づけられているオブジェクトを渡したりする形になるのではないでしょうか。「おい、サーバーサイドでRuby書いているんじゃねえよ!」と怒られそうなの気がしたので、この辺りで他のメンバーにバトンタッチ。

クエリを見直す

今回手を入れていくサービスでは、React + Railsで構成されています。APIサーバから返されたjsonを元に描画が走ります。jsonのレスポンスは速いに越したことはありません。
手分けをして、本当にそのjsonはそのタイミングで取得しなければならないのかどうか、適切なアソシエーションのキャッシュがなされているかを見ていきます。

「おい、サーバーサイドで(以下略)」

あまりにも多くのテーブルを経由しなければ情報を取得できない場合、正規化を一部諦めてパフォーマンスをとるという選択もあります。(データ不整合のリスクがあるのであまり気が進まない…)

コード分割

React.lazyを使ったり、loadableコンポーネントを利用したりなどして、フロントエンド のコードを分割していきます。実際には分割することによって生じる不都合を調整しながらコンポーネントを置換していく作業になりましたが、ちょっとloadableを試すだけなら、これだけ!

import loadable from '@loadable/component'
const Component = loadable(() => import('~/path'));

色々試した結果

あれやこれや試してごにょごにょした結果がこちらです。

わーい、パフォーマンスが改善されました! 

実際には各ブラウザの差異を考慮する必要があります。モバイルにおいては依然として扱うデータやスクリプトが大きすぎるので、改善は続きます。

数値に現れない部分、丁寧なUIやサービス全体のUXの向上が大切なのはいうまでもありませんし、数値は上下や誤差があるのであくまで指標にすぎません。説明は省きますが、パフォーマンスを測定する指標そのものもいくつかあり、どれを重視していくかによっても有効な改善方法は異なってきます。

エンジニアのパフォーマンス

ところで、エンジニアのパフォーマンスについて考えるとき、どうすればいいのでしょうか。
明確な指標がない中で、どのようにパフォーマンスを測定すればいいのでしょう。
機能を実装する速度でしょうか。実装した機能に含まれているバグの数でしょうか。
それとも、コードの品質でしょうか。使い勝手でしょうか。
考えらえる全てを総合して判断を下すのでしょうか。

そして、どうすればパフォーマンスが向上するのか、誰かが示してくれるのでしょうか。

指標がどうあるべきかという問題はひとまずおいておくとして、パフォーマンスを発揮しやすい環境がどのようなものなのか、考えなければなりません。良い環境やチームがどのようなものかということを考えることとそれは等しいのではないでしょうか。

最近実施していること

カンバンを使った進捗管理をデザインシステム室の1部分で実験的に導入してみました。こういうと大袈裟なのですが、タスクを紙に書いてホワイトボードに張り出し、昨日やったことと、今日やったことと、困っていることを朝と夕方に共有する取り組みです。(ただ、今はまだタスクの可視化というフェーズで、もっと根本的なところから手を入れる必要があると感じています。)

困っていることを1日単位で発見できて軌道修正がしやすいことが利点です。タスクを紙にして張り出すことで、毎日変わる優先度や突然発生する障害への対応などが可視化されます。
「別にツールを使ってやればいいじゃないか」とも思うのですが、アナログならではの利点もあります。カンバンの前に集まることができるので自然な会話の機会が増えるのです。

この方式のデメリットとしては、長期間のプロジェクトをチケットの形に分割するのが困難であること。また、非エンジニア部門がエンジニアの動きを把握するツールとしてはやや細かすぎるというところです。悲しいことですが、現時点では非エンジニア部門はこのホワイトボードにはあまり関心がないと思っています。発信力を強めていって協力できる体制ができると好ましいと思っています。

個人からチームへ

ところで、開発の効率を高めたい場合はどうでしょう。並行して複数のタスクを進めた方が良さそうです。一人のエンジニアが一つの案件を持てば、たくさんの案件を進めることができそうです。これはとても良い方法に見えます。

ところが、当然エンジニアが他人のタスクに関心を持たなくなります。設計や実装方針は個々の力量に依存し、問題が起きても誰かが気づくことは難しくなるでしょう。
問題が明るみに出るのはリリースの直前か、その後になります。
そもそも、問題に気づいて助け合おうというモチベーションが生じることもありません。誰も自分の仕事を圧迫されたくないからです。

カンバンでタスクと進捗を共有していても、チームではなく個人にタスクが割り振られている状態ではあまり意味はありません。チームに対してタスクを振れるようになるには、組織として機能するチームができなければいけません。これは非常に時間がかかります。

アジャイル、スクラム、リーン、カンバン…様々な方法や考え方がありますが、どのようなものも形骸化する危険とは常に隣り合わせではないでしょうか。何かを導入したから突然良くなるというものではないので、地道に改善を続けていきたいなと思います。

メンバーぼしゅう

現在デザイン・システム室では新しいメンバーを大募集しています。
デザイン、フロントエンド 、サーバーサイド、組織づくりのあらゆる点で、試行錯誤をしながら今日よりも良いものを一緒に作っていきたいと考えています。

応募は下記エントリーフォームから。お待ちしております!

募集要項およびエントリーフォーム >