新卒の一年間で確立させた紙のノートを使った仕事術!

この記事は Tech KAYAC Advent Calendar 2017 の22日目の記事です。

こんにちは、最近入社2年目になったバックエンドエンジニアの @commojun と申します。

皆さんは紙のノート使っていますか?僕は毎日使っていて、仕事を進める上ではPCの次くらいに必要不可欠な存在となっています。 本日は、新卒で入社してから約1年、毎日紙のノートを使ってきて自分なりのノート活用法が確立したので紹介いたします。

もくじ

どんな感じに使っている?

まずはこちらをご覧ください。僕は毎日紙面にこのような欄を設けてノートを利用しています。それぞれの箇所に役割があるので、順番に紹介していきます。 f:id:commojun:20171221002659j:plain

ノートの役割

①その日のタスクを一覧する

ノートの一つめの役割はタスク管理です。一日が始まる前に、その日あることとやることをリストに書き出します。

[予定]の欄には、その日のスケジュールの一覧を、[やるコト]の欄には、その日やるもしくはやりたいタスクを書き出し、デスクに置いておきます。

基本的に人間は一つの作業に集中している時は他のことを考えません。ちょっとした作業に身が入りすぎて、もっと重要なタスクのことを忘れてしまっていた!なんて経験は無いでしょうか?作業が一息ついた時にこのページが目に入る場所に置いてあれば、「あぁ、次はこれをやるんだったな」と次のタスクへスムーズに移行できます。

ポイントは、「気にかける」とか、「確認をする」とか、「何か起きたら対応する」だけのようなとても小さなタスクもここにしっかり記しておくことです。このリストはTODOリストでもありながら、後述する一日の振り返りをするための材料となります。小さなタスクを書き漏らすと、たまたままとまった成果が得られなかった日に「あれ、オレ今日仕事してなくね?」という感覚に陥ることがあります。これは正しく振り返りが出来ておらず、メンタルヘルス的にもとてもマイナスなことです。小さなタスクもタスクとしてしっかり認めましょう。

②一日ごとに小さな目標と振り返りを持つ

弊社社長日記より、

www.kayac.com

「その人にとっての天職とは、その仕事を通して、その人に多くの気づきを与えてくれるものである」

という記事が話題になったことがあります。これについて僕自身も同様の意見を持っており、仕事で能力を継続的に向上できるかどうかは、一日の中でどれだけ多くの気付きを得続けることができるかにかかっていると考えています。

そのための習慣付けが[目標]と[評価]の欄です。[目標]の欄には、「今日一日でこれが出来たらマジで最高だぜ!」という達成目標を記入します。[評価]の欄は、一日を振り返って今日が何点だったかを主観で点数*1を付け、よかったことや、もっとよく出来たことなどの気づきを記入します。この一連の振り返りをすることで、「明日はこうしてみよう!」という小さな改善を継続できるようになります。

③まとまりきらない考えをいったん書き下す

ここから先はなんでもありの殴り書きメモのページです。一番初めに着手するタスク名を書いたら、あとは頭に浮かんでいるものをどんどん自由に書き下していきます。

ところで皆さんは、頭に浮かんだままのアイデアから、いきなりコードや文書、グラフィック・デザインなどの成果物を生み出すことが出来ますでしょうか?たいていの場合、一度作っては壊し、の試行錯誤を繰り返すケースが多いと思います。すんなりとできる人は相当その作業に慣れた熟練の方だと思います。

人間の脳には常時様々な雑念が流れており、その混沌とした中に浮かんだアイデアからいきなり完成形の成果物を生み出すというのはとても精神的なコストが大きく、ストレスがかかります。

f:id:commojun:20171221153654p:plain

そこで、アイデアから成果物への変換経路にまとまりきらない考えをいったん書き下す場を設けます。

f:id:commojun:20171221153712p:plain

もやもやとした形になりきらないアイデアをいったん全て紙に吐き出すことで、頭がスッキリします。(この作業をブレインダンプと呼ぶらしいです。)そのスッキリとした状態で書き下したメモを眺め、重要そうな部分を抽出したり、新たに浮かんだことを書き加えたりというブラッシュアップを経ると、アイデアに方向性が付き始めます。このタイミングが実際に成果物に取り掛かる合図です。ノートで一度アイデアの方向性に確信が持てた状態になっているので、最後まで作り上げたのにやっぱりゼロからやり直し、といった事が起こる確率を下げることができます。

なぜ、紙のノートなのか?

なんだ、それくらいのことならデジタルのメモでも同じようなことができるじゃないか、という意見を持つ方も多いと思います。僕があえて紙のノートを利用しているのにはいくつか理由がありますので、紹介いたします。

①汚く使える

皆さんは学生時代、問題集を解いた後に丸つけをしていましたか?僕は結構丸つけが好きで、シュバババー!っと大胆に赤ペンで丸つけをしていました。

[やるコト]リストにも同じようなことをしています。着手したタスクには容赦なく赤線を引いて、DONEという文字を書いたり、チェックマークをつけたりしています。デジタルのTODOチェックリストでポチポチとチェックマークを付けるのと何ら変わりない作業なのですが、汚く使えば使うほど「やったったぜ!」という気分にひたれるので僕は紙のノートが好きです。

f:id:commojun:20171221143150j:plain

②型にはまらない使い方ができる

①と関連しますが、デジタルでメモを書く場合、メモはアプリケーションで扱える型で記入しなければなりません。

例えばメモ帳アプリでメモ書きをしていてこんなことがしたくなった時、どうしますか?

  • 図を入れたい
  • 絵を描きたい
  • 下線を引きたい
  • 赤文字を書き込みたい
  • 急に大きな文字が書きたくなった
  • 文字を斜めに書きたい
  • テキストに横断して矢印が書きたい
  • 文字の隙間に小さい文字で一言追加したい
  • 今まで書いたメモにでっかいバツ印をつけたい
  • ページを破って人に渡したい
  • 破ったページを折り紙にして立体物を作りたい(!?)

これらを我慢してプレーンテキストでメモを書いたとき、メモ帳アプリによってアイデアの広がりが制限されてしまったことになります。

近年はこれら全ての要望を叶えるアプリケーションがいくつも登場しているかと思います!使いこなすことができれば最強かもしれませんが、結局はそのアプリケーションの作法に従わなくてはならず、どこかしら一長一短なケースが多いな、と個人的に感じています。

こちらは、今回の記事を作成するために書いたメモ書きです。アプリの設計思想にとらわれず、ストレスなく使えるというのが紙のノートの利点だと思います。

f:id:commojun:20171221143330j:plain

③目に入る場所に置いておける

TODOリストをデジタルで管理している方、一日に何回TODOリストを見返しますか?PCの画面は(マルチディスプレイでない限り)一つしかないので、デジタルのTODOリストをずっと見える形で置いておくことはあまり現実的ではありません。

紙であれば、デスクの空いている場所に置いておけばよいので、自然と今日のタスクを定期的に思い返すことができます。

欠点

もちろん紙のノートにも欠点がいろいろとありますよね。それらを理解することも紙のノートを上手く活用するコツです。

アンドゥができない

消しゴムを使って消してもいいですが…間違いを修正するのはデジタルのほうが楽ですね。むしろどんどんノートを汚く使うべきだと思います。

あのメモっていつどこに書いたっけ?ってなる

検索できませんからね。お決まりの手順書のような、あとで見返すようなメモを書くのには向いていないと思います。そういった情報を記す場合は積極的にデジタル媒体を利用したほうが良いでしょう。

エコでない

仕方ないですね…圧倒的に仕事効率を上げて元をとりましょう。

最後に

入社初日から約1年間毎日ノートを書き続け、10冊目に差し掛かりました。過去のページを見ると「そういえばあのときはこんな仕事していたなぁ」と振り返ることができてなかなかおもしろいですね。

f:id:commojun:20171221154430j:plain

といった感じで紙のノートの活用術を紹介させていただきました。参考にしてみてください。

面白法人カヤックでは、紙のノートをもっと賢く使っているぞ!という人を募集しています。

www.kayac.com

www.kayac.com

次回は @ogrew による「エレベータにイライラする話」です。

*1:点数を主観で付けることにあまり意義を感じていませんが、後から見返すと、少なくともそのときの自分が楽しく働けているかどうかがこの点数に反映されていることがわかってきました。

Google Homeで変身する

この記事は、Tech KAYAC Advent Calendar 2017 の21日目の記事です。

こんにちは!17新卒HTMLファイ部の入江です。

技術の無駄遣いをモットーに日々最新技術を追っています。今回は今流行りのAIスピーカーGoogle Homeを使って変身できるようにしてみました。

できたもの

まずはこちらご覧ください。


Google Home と Firebase Realtime databaseを連携して顔を変える

使った技術

  • Dialogflow
  • firebase
  • Fusion 360

仕様

Google Homeに「変身〇〇」というと〇〇の部分をfirebaseのrealtime databaseに保存するAgentをつくる。realtime databaseをブラウザから監視し、変わった値に紐づいた画像を画面(iPad)に表示する。

f:id:kiyoshidainagon:20171220121825p:plain
システム図

DialogflowでAgentをつくる

Entitiesの設定

まずEntityを作ります。 「変身〇〇」の〇〇の部分に当たるやつですね。

f:id:kiyoshidainagon:20171220142709p:plain
Entity

右側が特定の単語。左側が特定の単語に対しての類義語になります。

Intentsの設定

続いてintentの設定していきます。 「変身〇〇」という単語を理解できるようにしてあげます。

f:id:kiyoshidainagon:20171220142724p:plain
Intent

User saysで認識してもらいたい文言を追加します。今回は変身したいので、変換が間違っても問題ないように「変身ブルー」と「返信レッド」を追加しました。レッド、ブルーの単語を選択して、先ほど作ったEntityを設定してあげると、黄色くなります。

FulfillmentのUse webhookにチェックを入れます。

Integrationの設定

f:id:kiyoshidainagon:20171220125932p:plain

一番上のGoogle AssistantのINTEGRATION SETTNIGSをクリックすると上図のようなポップアップが出ます。最近UI変わったみたいですね。 Additional triggering intentsの欄に先ほど作ったintentを設定して、TESTを押して問題ないようだったら、MANAGE ASSISTANT APPを押します。

Fulfillmentの設定

firebase cloud funcitonの作成

firebaseのcloud functionをローカル環境で作成します。手順としては以下です。

  1. yarn global add firebase-tools
  2. firebase login
  3. firebase int functions
  4. Select a default Firebase project for this directory: (Use arrow keys)と聞かれるので、Dialog flowで作成中のAgentを選択する
  5. JavaScript と TypeScriptどっちにするかとか聞かれますが、そこはお好みで
  6. できたらfirebase deploy --only functionsでデプロイする

今回書いたfunctionは↓になります。内容はFullfillmentのInline Editor内に書いてあるサンプルスクリプトに、FirebaseのRealtime Databaseにデータを追加するプログラムを書き足しただけです。

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const DialogflowApp = require('actions-on-google').DialogflowApp;

admin.initializeApp(functions.config().firebase);

exports.dialogflowWithRealtimeDetabase = functions.https.onRequest((request, response) => {
  if (!request.body.result) {
    console.log('Invalid Request');
    return response.status(400).end('Invalid Webhook Request (expecting v1 or v2 webhook request)');
  }

  let action = request.body.result.action;
  const parameters = request.body.result.parameters; 
  const requestSource = (request.body.originalRequest) ? request.body.originalRequest.source : undefined;
  const path = "/faceName";

  // realtime databaseにデータを突っ込む 
  admin.database().ref(path).set(parameters.change_name);

  const googleAssistantRequest = 'google'; 
  const app = new DialogflowApp({request: request, response: response});

  const actionHandlers = {
    'input.welcome': () => {
      if (requestSource === googleAssistantRequest) {
        sendGoogleResponse('Hello, Welcome to my Dialogflow agent!'); 
      } else {
        sendResponse('Hello, Welcome to my Dialogflow agent!'); 
      }
    },
    'input.unknown': () => {
      if (requestSource === googleAssistantRequest) {
        sendGoogleResponse('I\'m having trouble, can you try that again?'); 
      } else {
        sendResponse('I\'m having trouble, can you try that again?'); 
      }
    },
    'default': () => {
      if (requestSource === googleAssistantRequest) {
        let responseToUser = {
          speech: 'シャキーン', 
          text: 'シャキーン'
        };
        sendGoogleResponse(responseToUser);
      } else {
        let responseToUser = {
          speech: 'シャキーン', 
          text: `シャキーン`
        };
        sendResponse(responseToUser);
      }
    }
  }

  if (!actionHandlers[action]) {
    action = 'default';
  }

  actionHandlers[action]();

  function sendGoogleResponse (responseToUser) {
    if (typeof responseToUser === 'string') {
      app.ask(responseToUser); 
    } else {
      let googleResponse = app.buildRichResponse().addSimpleResponse({
        speech: responseToUser.speech || responseToUser.displayText,
        displayText: responseToUser.displayText || responseToUser.speech
      });
      if (responseToUser.googleRichResponse) {
        googleResponse = responseToUser.googleRichResponse;
      }
      if (responseToUser.googleOutputContexts) {
        app.setContext(...responseToUser.googleOutputContexts);
      }
      app.ask(googleResponse); 
    }
  }
  function sendResponse (responseToUser) {
    if (typeof responseToUser === 'string') {
      let responseJson = {};
      responseJson.speech = responseToUser; 
      responseJson.displayText = responseToUser; 
      response.json(responseJson); 
    } else {
      let responseJson = {};
      responseJson.speech = responseToUser.speech || responseToUser.displayText;
      responseJson.displayText = responseToUser.displayText || responseToUser.speech;
      responseJson.data = responseToUser.data;
      responseJson.contextOut = responseToUser.outputContexts;
      response.json(responseJson); 
    }
  }
});

DialogflowのFulfillmentの設定

  1. WebhookをENABLEDにします。
  2. URLに先ほどdeployしたcloud funcitonのURLを指定します。

フロント側でfirebase realtime databaseを監視する

単純にデータを監視するだけなんで、ちょっとの記述で実装できます。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <style>
            body {
              width: 100vw;
              height: 100vh;
              background-color: #000;
              background-repeat: no-repeat;
              background-position: center bottom;
              color: #fff;
            }
      </style>
    </head>
    <body>
        <p id="face-name">ホゲホゲ</p>

        <script src="https://www.gstatic.com/firebasejs/4.2.0/firebase.js"></script>
        <script>
            // Initialize Firebase
            var config = {
                apiKey: "<API_KEY>",
                authDomain: "<PROJECT_ID>.firebaseapp.com",
                databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
                storageBucket: "<BUCKET>.appspot.com",
                messagingSenderId: "<SENDER_ID>",
            };
            firebase.initializeApp(config);

            var db = firebase.database();
            var faceType = db.ref('faceName'); //取得したいデータのパスを指定
            faceType.on('value', function(snapshot) { 
                const value = snapshot.val(); //faceNameに入ってる値を取得
                document.getElementById("face-name").innerText = value;
                document.body.style.backgroundImage = 'url(img/' + value + '.png)';
            });
        </script>
    </body>
</html>

ウェアラブル化する

micro USBで給電してるし、戦隊モノのベルトのバックルに見えなくもないので、ウェアラブル化してみます。

ThingiverseというサイトからGoogle Home Miniのマウントをダウンロードしてきます。

今回ダウンロードしたものは↓ Google Home Mini Wall Mount by tilmansp - Thingiverse

続いて、先ほどダウンロードしたマウントに合うように、ベルトにかけれるフックをモデリングしていきます。 モデリングにはFusion 360を使いました。

f:id:kiyoshidainagon:20171219213531p:plain

Fusino 360でモデリング

このモデルを1個にまとめて3Dプリントで出力するのはうまく行かなそうなので、フックの部分とマウントの部分の2パーツに分けて出力し、出力後に合体させます。 接着剤はアクリサンデーがオススメです。http://www.acrysunday.co.jp/products/article/

合体させたマウントはこんな感じになります。 f:id:kiyoshidainagon:20171219214420j:plain

念のため、フックの部分もあげておきます。ベルトにつけたい方はご気軽にダウンロードしてください。 www.thingiverse.com

モバイルバッテリーも同様にフック付きのケースを用意して、完成したのがこちらになります。

f:id:kiyoshidainagon:20171220173834p:plain
Google Home 搭載ベルト

まとめ

いかがだったでしょうか。firebaseを使うことで、Google Homeでできることが格段に広がる気がしますね。

面白法人カヤックではAIスピーカーを使って家を便利にするだけじゃ飽き足らない人を募集しています。

www.kayac.com www.kayac.com

明日は先日の合宿で新人王を獲ったcommojun.comです。