行動すれば次の現実

テック中心の個人ブログ

私が行っている「1週間の振り返りと計画」の具体的な方法

振り返りの時間とはなにか?

私は毎週土曜日の午前中に1時間程度の振り返りの時間を設けています。 今週1週間の学びと反省、来週1週間の計画を行い、自分としっかり向き合うのが目的です。

忙しい日々を送っていると、つい目の前のことで手一杯になり視野が狭くなってしまいます。 そのため、強制的に振り返りの時間を設けることで人生を俯瞰することができ、目まぐるしく発生する日々の物事を根拠を持ってコントロールできると考えていいます。

本記事では私が行っている「1週間の振り返り」の具体的な方法を紹介したいと思います。

振り返りはどこでやるのか?

基本的には「自宅以外」で行うと良いと考えています。私の場合は最寄りのカフェです。 なぜ自宅以外なのかというと、「集中力が向上されるという点」と「非日常感での思考の転換できる点」というのが大きな理由です。

それぞれメリットとデメリットをあげたいと思います。

カフェで振り返りをするメリット・デメリット

〇メリット
  • 非日常の環境に身を置ける
  • 余分なものを持ち込まないため集中できる
〇デメリット
  • カフェ代が掛かる
  • カフェに行くまでの往復時間が掛かる
  • 気楽に離席できない

自宅で振り返りをするメリット・デメリット

〇メリット
  • その気になったら、いつでも振り返りができる
  • 備品を持ち歩かなくても、家にあるものは全て使用できる
  • 費用が掛からない
〇デメリット
  • いつもと同じ環境なので非日常感がない
  • いろいろなものが目に入るため気が散る
  • 家族のスケジュールに影響され、好きな日程が選べない

人によっては人混みや雑音が苦手という方もいると思うので、自分にあった場所で行うと良いでしょう。

振り返りに持っていくもの

振り返りを行う際は、以下のアイテムを持参します。

  • ペン、ノート
  • タブレット
  • スマホ

ペン、ノート

頭の整理をしながら振り返りをします。 ゼロ秒思考でメモを取ったり、図解しながら頭の整理をする際にペンとノートを使用します。

タブレット

振り返りのメインはタブレットを使用します。 後述するtodoistやmindmeisterアプリを使って振り返りを行います。

スマホ

スマホは基本的にはオフラインモードにします。l だったら持っていかなくても良いのでは?と思いますが、災害時などの緊急用として仕方なく持参しています。

振り返りの手順

ここからが本題です。振り返りは大きく3ステップで行います。

  1. 今週やったことを振り返る
  2. 今気になってることを書き出す
  3. 来週やることを計画する

1.今週やったことを振り返る

まずは今週やったことを思い出す作業です。 各媒体に振り返るための材料が残っているため、それらをもとに振り返りを実行します。

todoistを振り返る

後述しますが、タスクはtodoistというアプリで管理しています。

todoistの「完了したタスク」で過去1週間に自分が何を行ったのかを確認し、その時の状況などを頭の中に思い出します。

カレンダーを振り返る

今週のカレンダーに記載されているイベントを元に振り返ります。私はGoogleカレンダーを使用しています。

メールを振り返る

今週受信したメールをざっと振り返ります。 未読メールもここでチェックして、必要なければアーカイブまたはゴミ箱行きにします。そうすることで頭の中がスッキリします。

X(旧Twitter)のいいねを振り返る

X(旧Twitter)では自分のツイートと、いいねしたツイートを見返すことで、どんなツイートをしたのか、その時の感情などを振り返ります。

Youtubeのいいねを振り返る

自分がどんな動画にいいねしたのかを見返すことで、その時の感情などを振り返ります。

2.今気になってることを書き出す

上記の振り返り材料を元に、今気になっていることを改めてノートに書き出します。

気になっているを書き出す

今気になっていることをノートに箇条書きで列挙します。

気になっていることをさらに深堀りたい場合は、ゼロ秒思考で深堀りをしていきます。

気になっていることがある程度明確になった時点でtodoistのinboxに追加していきます。

ゼロ秒思考については下記参照

3.来週やることを計画する

いつかやるリストを確認する
  • いつかやるリストの内、来週やりたいものがあれば期限を設定してtodoistの適当なプロジェクトに移動させます。
  • いつかやるリストの内、やる必要がないと思ったものは削除します。
mindmeisterで価値観マップを確認する
  • mindmeister上の価値観マップを確認します。
  • 価値観マップを確認して来週やりたいことがあればtodoistの適当なプロジェクトに移動させます。
  • 価値観マップとは人生で大切にしたいモノ・コトを以下の観点ごとにまとめたマインドマップです
    • 精神生活
    • 健康
    • プライベート
    • 人間関係
    • 仕事
    • 会社
    • 資産
  • 価値観マップの作成方法はワン・シングという書籍に詳しく書いてあるので参考にしてみると良いかもしれません
    • 「11 成功の習慣」を参照
来週のカレンダーを確認する
  • 来週のカレンダーを確認してtodoistの適当なプロジェクトに移動させます。
inboxを確認する

todoistのinboxに追加されたタスクを確認します。

  • 2分以内でできるなら今すぐやります。
  • 来週やりたいなら期限を設定してtodoistの適切なプロジェクト(※)に移動させます。
  • 誰かがボールを持っていてpendingしているなら「連絡待ち」のプロジェクトに移動させます。
  • やる必要がないならタスクを削除します。
  • いつかやりたいならtodoistの「いつかやる」のプロジェクトに移動させます。

※ 適切なプロジェクトとは以下のいずれかである

  • 精神生活
  • 健康
  • プライベート
  • 人間関係
  • 仕事
  • 会社
  • 資産

まとめ

以上が振り返りの全容です。

1.今週やったことを振り返る 2.今気になってることを書き出す 3.来週やることを計画する

の3ステップを1週間おきに回していくという内容になっています。

この振り返りのフレームワークは、主に以下の書籍や手法を元に独自で編み出したものです。 参考としてリンクをまとめておくので、気になる方は読んでおくとフレームワークの本質が理解できるかと思います。

参考書籍
  • はじめてのGTD ストレスフリーの整理術
  • 新版 ザ・マインドマップ(R)
  • ゼロ秒思考 頭がよくなる世界一シンプルなトレーニング
  • ワン・シング 一点集中がもたらす驚きの効果
使用ツール
  • evernote
  • todoist
  • mindmeister
  • ノート
  • ペン

blueimp-load-imageを使った画像リサイズ処理の実装例 | Javascript | npm

昨今では画像アップロード処理をする際、サーバーサイドだけでなくフロントサイドでもリサイズ(圧縮)するのが主流になっています。

画像圧縮は、Javascriptのcanvas APIを使って実装するのが一般的ですが、canvasで画像圧縮処理を一から実装となると、それなりのコーディング量が必要となります。 そのため、よっぽどな理由がない限りはJavascriptライブラリを使用するのをオススメします。

今回は、代表的な画像圧縮ライブラリ「blueimp-load-image」を使用した実装例を紹介したいと思います。

blueimp-load-imageを使用した画像圧縮の実装例

blueimp-load-imageは画像加工処理を行うためのnpmライブラリです。 画像加工、リサイズ、回転情報の削除、プレビュー画像の作成などを簡単に実装することができます。

github.com

さっそく実装を見ていきましょう。

import * as loadImage from 'blueimp-load-image';

const resizeImageWorker = (imageFile, options = {
  maxHeight: 828,
  maxWidth: 1104,
  canvas: true,
  orientation: true,
}) => {
  return new Promise((resolve) => {
    loadImage(imageFile, (canvas) => {
      const type = 'image/jpeg';
      const dataUri = canvas.toDataURL(type);
      const bin = atob(dataUri.split(',')[1]);
      const buffer = new Uint8Array(bin.length);
      for (let i = 0; i < bin.length; i++) {
        buffer[i] = bin.charCodeAt(i);
      }
      resolve(new Blob([buffer.buffer], { type: type }))
    }, options);
  });
}

function createProductImages(payload) {
  const { productRecipeId, productImage } = payload;
  return resizeImageWorker(productImage).then((blob) => {
    const params = new FormData();
    params.append('product_image', blob);

    // リサイズ後の画像を画像アップロードAPIサーバーに連携
    return axios.post(`/api/product_recipes/${productRecipeId}/product_images`,
      params, {
        headers: {
          'content-type': 'multipart/form-data',
        },
      });
  })
}

商品レシピの画像をリサイズして画像アップロードAPIに連携するというサンプルプログラムになります。

resizeImageWorkerという関数で画像リサイズ処理を行っています。

blueimp-load-imageからimportしたloadImageという関数を使用します。 loadImageは非同期処理なのでPromise化して、resolveしてBlobを返却するという作りにしています。

resizeImageWorkerで返却されたBlobを画像アップロードAPIに送信することで処理が完了します。

たった10行ほどのコードでリサイズ処理が実装できてしまいます。

他に候補に上がったライブラリ

画像リサイズ処理を実装するにあたり他にもいくつかライブラリを試してみました。

今回は要件が合わなくて使用を見送りましたが、使い勝手が良いライブラリばかりなのでチェックしてみると良いでしょう。

imtool

github.com

IE11はサポート対象外であるためNGとしました。

実際に導入したところAPIが分かりやすく使いやすかったです。 IEがサポート対象外であればこちらを使用していたと思います。

jimp

github.com

commonJS方式のみサポートなのでNGとしました。

commonJSをサポートしている環境であれば有りだと思います。

pica

github.com

commonJS方式のみサポートなのでNGとしました。

commonJSをサポートしている環境であれば有りだと思います。

画像アップロード時はクライアントサイドでも圧縮処理をすべき理由

画像アップロードする際に、最近ではクライアントサイドであらかじめサイズを圧縮しておくのが主流である。

スマホカメラの高性能化に伴い、写真がどんどん高画質になっているためである。 10MB近いサイズのこともあったりする。

画像アップロードのフローからみる改善点

スマホ ①=> サーバーサイド ②=> ファイルストレージ

上記の①のアップロード部分はクライアント側のネットワーク速度に依存するため、通信が不安定な状態だといつまでたってもアップロード処理が終わらない。 (10MBの画像を上り1Mbsの速度でアップロードすると10秒以上かかる)

②はサーバーサイドなので通信による影響はある程度制御できる。 安定した状態であれば10MB程度のアップロードは1秒未満で完了するためそれほど問題にはならない。

画像サイズを1/10の1MBまで圧縮できれば、①の処理は1秒程度で完了する。

それゆえにクライアントサイドで画像を圧縮した上でアップロードすることがとても重要なのである。

(保険としてサーバーサイドでも圧縮処理を掛けておくべきであるのは言うまでもない)

Reactのライフサイクル一覧まとめ

マウントフェーズ

componentWillMount

  • 基本的には非推奨
    • まずはconstructorかcomponentDidMountで制御できないか検討すること
    • v16からUNSAFE_componentWillMountという名前に変更
  • renderよりも前に呼ばれる
  • constructorよりも後に呼ばれる
  • setStateしてもrenderはされない

componentDidMount

  • コンポーネントがマウントされた直後に呼ばれる
  • DOMにアクセスできるため、イベントリスナー登録などはこのフェーズで行う
  • setStateは原則禁止
    • render → componentDidMount → setState → render
    • 無駄に2回描画されるので特別な理由がない限りは禁止

componentWillUnmount

  • コンポーネントがアンマウントされる直前に呼ばれる
  • setIntervalをクリアしたり、イベントリスナーを解除したりするフェーズ

アップデートフェーズ

componentWillReceiveProps(nextProps)

  • 基本的には非推奨
    • v16からUNSAFE_componentWillReceivePropsという名前に変更
  • setState可
  • propsの変更直前に呼ばれる
  • stateの変更では呼ばれない

shouldComponentUpdate(nextProps, nextState)

  • renderさせるかどうかを制御する
    • PureComponentを使用するほうが一般的
  • true/falseが返却値
    • trueの場合はrenderさせる
    • falseの場合はrenderさせない
  • 主にパフォーマンスチューニングのために使用する

componentWillUpdate(nextProps, nextState)

  • 基本的には非推奨
    • v16からUNSAFE_componentWillUpdateという名前に変更
  • renderされる直前の最後のフェーズ
  • setStateは禁止
    • componentWillUpdateが再度実行されて無限ループの可能性があるため
  • shouldComponentUpdateでfalseを返した場合は呼ばれない

componentDidUpdate(prevProps, prevState, snapshot)

  • 仮引数は前のprops、state
  • renderの直後に呼ばれる
  • setState可
  • shouldComponentUpdateでfalseを返した場合は呼ばれない

Herokuのworker dynoが突然遅くなったときに確認すべきこと

Herokuのworker dynoのパフォーマンスが数日前から突然悪くなった。

今まで30秒程度掛かっていたバックグラウンド処理が10分程度掛かるようになった。

直近で心当たりのあるリリースはなかったため、調査することにした。

丸一日調査して解決はしたのだが、思っていたよりも根が深く、自身の学びにもなったのでまとめておく。

前提情報

  • Rails5.2
  • Jobフレームワーク: Sidekiq

  • Heroku

    • web dyno * 2
    • worker dyno * 2 (内1つはcron用)
  • DB

    • posgresql
  • 監視ツール

    • Papertrail
    • NewRelic

Papertrailでworker dynoのログを確認する

まずはログを確認する。Pepartrailを入れているので、問題が発生したJobIDをもとにログを特定する。 (各処理の実行時間などから問題の原因をある程度推測できるケースが多い)

ActiveRecordが発行しているログからDBへのアクセス時間が極端に遅くなっていることがわかった。 通常時はテーブルのUpdateに1ms程度掛かっていた処理が、100ms程度掛かっていることがわかった。

「DBアクセス周りになにか原因があるのではないか?」と推測する。

NewRelicでパフォーマンスを確認する

念の為NewRelic APMも確認する。 CPUやMemoryの状況に異常は見られなかった。 Transaction traceを確認するとDB Queryのパフォーマンスに異常はなく、アプリケーションコードの実行速度が極端に遅いことがわかった。

ActiveRecordの処理時間は生のDB Query以外の処理時間も含まれている。

「DBが原因ではない」と推測する。

DBが原因ではないことの確認

念の為web dynoからのアクセス時間を図ってみたところ、異常は見られなかった。

  • webからのアクセスは遅くない
  • workerからのアクセスのみ遅い

上記よりDBが原因ではないことがわかった。

「workerで動くアプリケーションに原因があるのではないか?」と推測する。

デバッグログを仕込む

workerで実行しているJobアプリケーションに対してデバックログを仕込んだ。

デバッグを仕込む際は、

  1. 大きめなメソッド単位でログを仕込んで、どこでメソッド時間がかかっているか特定する
  2. 時間が掛かっているメソッドが特定できたら、ドリルダウンで情報が把握できるようにあらに詳細なログを仕込む

というステップを踏む。

1の段階で全体的に遅いということがわかった。

「特定のコードが遅いというわけではなくプロセス自体が遅いのではないか?」と推測する。

Herokuのmetricsを確認

原因がわからず小一時間息詰まっていたが、初心に戻ってHerokuのMetricsタブを確認することにした。

するとDyno Loadが常に1以上稼働していることがわかった。

dyno load
dyno load

試しにworker dynoをもう一つ起動してjobを実行してみると もう一つのworkerに割り振られたJobは通常通りのパフォーマンスで処理を終えたことが確認できた。

「デーモンプロセスが動いていて、dynoを専有しているのではないか?」と推測する。

Sidekiqの管理画面を確認

Sidekiqの管理画面を確認すると実行中のジョブプロセスが常に1あることが判明。 worker dynoで再起動してみる。するとSidekiqの性質上、自動でリランが走った。 リランされたジョブがなぜか終了されることなく、デーモン化していることがわかった。

「アプリケーションコードで無限ループしているのではないか?」と推測する。

コードを確認

対象クラス内で無限ループが発生しそうなコードがないか調査したところ、whileを使用している処理が一箇所見つかる。 ある特定の条件の場合、whileを抜けられずに無限ループしてしまうことが判明。

原因は、

「アプリケーション内の無限ループによりworker dynoを専有していたこと」

パッケージシステムにカスタマイズ対応を入れる場合、どのようにソースコードを管理すべきか

弊社ではクラウド型のWebアプリケーションパッケージシステムを開発しています。 基本的にはパッケージに搭載した機能のみを顧客に使用してもらいたいのですが、当然のようにカスタマイズ要望が生まれます。

カスタマイズ要望は、企業に特化した要件が多く、抽象的というよりは具体的な内容です。

具体的な要望でも、要件を整理して抽象度の高い汎用性のある機能に落とし込めればよいのですが、あまりにも特化した要望の場合はそれが出来ないことがあります。

とはいえ、これらを全て切り捨ててしまうと業務が回らないという自体になりますので、パッケージに影響の少ない方法で機能を提供できないかという課題が生まれます。

そのような場合にどのような開発手法的アプローチがあるのか考えてみたいと思います。

顧客ごとにブランチを分ける

パッケージとしての本ブランチ(master)と顧客ごとにブランチを作成する方法です。

  • メリット:他顧客に影響ないのでカスタマイズを好き放題できる
  • デメリット: ブランチの管理が大変。masterへのマージ、各ブランチへのマージなどの業務が発生して煩雑になる

マイクロサービス化する

カスタマイズ機能をマイクロサービス化する方法です。パッケージとはコードベースが別になります。アプリサーバーなども別に用意します。

  • メリット:パッケージのコードベースの煩雑化を防げる。影響範囲が絞られるのでメンテナンス性が高い
  • デメリット:マイクロサービスとして切り出す上で、アーキテクチャの見直しをしなければならない。複数コードベースを横断して開発する必要がある。

フラグで分岐させる

機能を使用するかどうかのフラグで処理を強引に分岐させる方法です。

  • メリット:一番手っ取り早い、コードベースが小規模段階ではスピードをもって開発することが可能
  • デメリット:コードベースが肥大化し、分岐処理によって複雑化する。しっかりテストを書かないと品質担保が難しい

我々の結論

我々の結論としては「フラグで分岐させる」を採用することにしました。

弊社のパッケージシステムの場合、まだ完全にはPMF(プロダクトマーケットフィット)していないプロダクトなので、スピードを重視したいためです。

メンテナンス性やデグレードの懸念については自動テストである程度担保できると判断しました。 理想は「マイクロサービス化する」ですが、現状ではそれを構築するほどのリソース確保ができていないので今回は見送りしました。