よーぐるとのブログ

技術ネタを中心。私的なことを徒然と綴っていきます。

2019年の抱負

今更ですが明けましておめでとうございます! 2018年の簡単な振り返りと2019年の抱負です。

2018年

2018年は社会人になって2年目の年になりました。去年から都内でエンジニアとして働いていますが、大きいプロジェクトにアサインされ設計からリリースまでに携われたのは非常に学びが多かったです。また、DevOpsやコンテナ技術に興味を持って、勉強したり遊んだりとたくさんの新しいものに触れた年でもありました。

一方で仕事に比重がよってしまいそれ以外のことが徐々に疎かになってしまっていったのを感じたので、今年はこうやって文章に残しておきたいと思います!

2019年

去年もおおよそ同じだったのですが、2019年大事にすることは健康、技術、英語の3つです。

健康は生活習慣を改善すること、運動を継続することの2点。生活を豊かにしたいです。去年前半に自分の睡眠の質が悪いことに気がついて生活習慣の見直しを測り、一時期非常に良い朝型生活が送れていたんですが気がついたら戻っちゃっていました。生活習慣を変えることで非常にコンディションがよくなる感覚はあったのでなんとか維持していきたいです。

技術についてはインプットとアウトプットの量を増やすことを目指します。技術は日々進歩しているので、最前線との距離感や自分が経験したことの概念化、言語化をしっかりとしていきます。

英語はリーディングとリスニングを重点的に取り組みます。ここ二年間で英語でニュースを読んだり技術カンファレンスの講演を聞いたりするのは抵抗なくなってきたので、それがよりスムーズに速くできるよう慣れていきたいと思います。

AlexaスキルとAWS Lambda, Slackを使って我が家の買いもの管理を便利にした話

やったこと

ライフハックです。Alexaに買うものを伝えるとSlackの買い物チャンネルに伝えたものが追加されるシステムを作りました。 仕組みとしてはシンプルで、Alexaに「〇〇を追加して」と伝えると、Alexaのスキル、AWS Lambdaの関数が呼び出されSlackのチャンネルに〇〇がポストされるというものです。

f:id:yoghurt1131:20181223150520p:plain

買い物管理

同居人と生活をするにあたって、買いもの、特に洗剤やシャンプーなど日用品類の買い物管理をどうしようかという話題がありました。「XXを買っておいて」「〇〇はもう買ったんだっけ?」というコミュニケーションは仕事などで疲れているときにはコストが高いですし、買い忘れが発生して喧嘩する、みたいなのも避けたい。なんとかいい感じに解決したい、という思いを二人共モヤモヤ抱えていました。

ちなみに「Alexaで全部注文しちゃえばいいじゃん」というのはなしで。そういう案もあったのですが、お互い家にいない時間が多くマンションに宅配ボックスもないためボツとなりました。あくまでどちらかが買い物をしなきゃいけないという状況に対する取り組みが今回の記事です。

この課題を解決すべく、まずはSlackに買い物チャンネルを作り必要なものはそこにポストして管理する、というルールを決めました。やることは簡単で

  1. 買わなきゃいけないものがあったらその名前を書いてポストする
  2. ポストされたものを買ったら「済」スタンプをつける

というものです。 ルールを決めたことで「誰が何をいつ買ったか」が明確になり、お互い暮らしていく中で非常にストレスのない買いもの生活が送れるようになりました。

f:id:yoghurt1131:20181224165411p:plain

Alexaを用いた買うもの投稿機能

上記のルールで買いものの管理は便利になったものの、別の課題が出てきました。 それは「買わなきゃいけないものは日常生活をしている中でふと現れる」ということです。食器洗い、洗濯、掃除といった家事に取り組んでいる最中に「あれ買わなきゃ」と思っても、やっている最中にスマホを取り出してSlackに投稿するのは面倒だし(そもそも家事の途中は手が空いていないことの方が多い)、一段落ついた頃には忘れてしまうことだってあります。

そう、「Slackに買うものを投稿する」の自体がそもそもハードルが高いのです。

そこで、Alexaが代わりにSlackへの投稿をしてくれる簡単なアプリケーションを作成することにしました。声で伝えるのであれば手が埋まっていてもできるし、思いついたその場で登録しやすいですよね。 今回はAWS Lambdaと簡単なAlexaスキルを作成してVoice UIでの買い物登録を実現させました。

システム構成

最初に載せた図の再掲ですが。

f:id:yoghurt1131:20181223150520p:plain

ユーザがスキルを呼び出し、Alexaに向かって話しかけます。その発話から必要な情報(今回は「買うもの」)が取り出され、AWS Lambdaに登録した関数が呼び出されます。関数の実態はSlack APIを叩くだけのNode JSスクリプトです。Alexaから受け取った情報をもとにSlackの特定チャンネルにボットで投稿を行います。

Alexaスキルの作成

AlexaスキルはAmazon Alexaの開発者登録を行い、Alexa Developer Consoleから簡単に作成することができます。 アプリではインテントと呼ばれる発話意図を登録することで、特定のアクションを受け付けられるようになります。インテントには発話のパターンが登録でき、各発話パターンの中に「スロット」と呼ばれる枠を用意することで、「{りんご}を追加して」「{みかん}を追加して」といった発話によって変化する単語を入れることが可能になります。

f:id:yoghurt1131:20181224235329p:plain:w250

今回は「買うもの」に当たる部分を{things}という形でスロットにしました。また、買うものを追加する時に言うであろういくつかの発話パターンを登録します。

f:id:yoghurt1131:20181223151010p:plain
alexadevconsole

AWS Lambdaへの関数登録

AWS Lambdaには上述したように、Alexaスキルから連携される情報を受け取りSlackに投稿する関数を登録します。デフォルトのインテントや、定義したインテントを受け取るHandlerを定義することで、Alexaから連携される発話に対する処理を記述できます。

下記に買いものの処理をする部分のコードを載せます。let things = this.event.request.intent.slots[SLOT_NAME].value;の箇所が、実際にAlexaスキルから連携されているスロットを受け取っているところです。

SDKのバージョンが古いため、最新バージョンだとこの書き方では動かないかもしれません。

// Slack Webhook URL
const WEBHOOK_URI = process.env.WEBHOOK_URI;
// Alexaから受け取るスロット
const SLOT_NAME = 'things';
const handlers = {
    ...
    // 買いものリスト追加処理
    'ToBuyIntent': function () {
      let func = this;
      // thingsスロット(=買うもの)を取得
      let things = this.event.request.intent.slots[SLOT_NAME].value;
      // Alexaの発話
      const speechOutput = things + 'ですね。わかりました。';
      func.response.speak(speechOutput);
      func.emit(':responseReady');

      // Slackに投稿するためのパラメータ
      let options = {
        method: 'POST',
        uri: WEBHOOK_URI,
        body: {
          text: things
        },
        json: true,
        headers: {
          'content-type': 'application/json',
        }
      };
      // Slackに投稿
      requestPromise(options).then(function(body) {
      }).catch(function(err) {
        console.log(err);
        func.response.speak('エラーが発生しました');
        func.emit(':responseReady');
      });
    },
    ...
};

exports.handler = function (event, context, callback) {
    const alexa = Alexa.handler(event, context, callback);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

苦戦した部分

あとはAlexaスキルのエンドポイントにAWS Lambdaの関数を登録し、Alexaで呼び出す際のスキル名を設定すれば完成となります。

が、ここで一つ罠がありました。 買い物リストなんていうありふれた機能はすでにAlexaにデフォルトスキルとして実装されているのです。

f:id:yoghurt1131:20181224164032p:plain:w200f:id:yoghurt1131:20181224164036p:plain:w200

最初、スキル名を「買い物リスト」としいたんですが、そうすると自作したスキルではなくデフォルトのスキルが呼び出されてしまうのです。これでは使えない。。。

スキル名は「アレクサ、<今日の星占い(スキル名)>を開いて双子座の運勢を占って」のようにAlexaへの指示の中に織り交ぜて使われます。そのため、発話にいれて違和感のあるスキル名や極端に長いスキル名などは設定したくありません。 デフォルトのスキルが呼び出されず、かつAlexaへの呼びかけとして不自然じゃないスキル名を検討した結果、以下のようになりました。

f:id:yoghurt1131:20181224164658p:plain

これだ!!

「Alexa、スラックを開いてゴミ袋を追加して」

f:id:yoghurt1131:20181224165147p:plain:w200

きっちりとSlackに投稿されています。これならまあ及第点でしょう。やったね。

まとめ

AlexaスキルとAWS Lambdaを使って買いもの管理を便利にしてみました。 やはり音声による入力というのは手入力よりはるかにストレスがないらしく、もはやスマホでSlackを開いて買うものを投稿するという場面はほとんど見なくなりました。こういったライフハックを積み重ねて生活をどんどん便利にしていきたいですね。

資料とか

GitHub - IshinFUKUOKA/waht-i-buy: Alexa skill's application posting message to slack channel

スライド - 20180711-alexa-yoghurt1131.pdf - Google ドライブ

Knife-ZeroによるRaspberry Pi3の構成管理

お題

Raspberry Piの構成管理をChefで行いたい。 細かい環境構築やセットアップなどをコード化したい。

環境

・OS: Mac OSX Yosemite ・Chef: 14.5. ・ラズパイ: Raspberry Pi 3 ・ラズパイOS: Raspbian GNU/Linux 9 (stretch)

Knife Zeroのインストール

Knife-Zeroのサイトに記載されている方法に従ってknife zeroコマンドをインストール Installation · Knife-Zero

以下のようにknife zerと打ってUsageが出てくればOK。

$ knife zero
FATAL: Cannot find subcommand for: 'zero'
Available zero subcommands: (for details, knife SUB-COMMAND --help)

** ZERO COMMANDS **
knife zero apply QUERY (options)
knife zero bootstrap [SSH_USER@]FQDN (options)
knife zero chef_client QUERY (options) | It's same as converge
knife zero converge QUERY (options)
knife zero diagnose # show configuration from file

Rasbbian用の設定ファイル用意

bootstrap時には-tオプションで実行したいテンプレートを指摘できる。 以下のサイトにRaspbian用のテンプレートがおいてあったのでそれを利用する。

GitHub - dayne/raspbian_bootstrap: chef bootstrap for raspberry pi

bootstrapの実行

$ knife zero bootstrap -t raspbian-jessie-gems.erb --ssh-user pi --sudo 192.168.11.15
(中略)
ERROR:  Error installing chef:
  ohai requires Ruby version >= 2.4.
Starting the first Chef Client run...
sh: 112: chef-client: not found

よくみると先程ダウンロードしたテンプレート内に以下の記述が。

RUBY_VER=2.3.3

2.4.0に書き換えてあげる

RUBY_VER=2.4.0

別のエラー OpenSSL::OpenSSLError: password must be at least 4 bytes

knife.rbに以下を書き加えてあげる

ssl_verify_mode  :verify_none

bootstrapまではなんとか成功した。

mavenプロジェクトでフォーマッターを使う

技術Tipsです。

概要としてはmavenを利用しているspring bootプロジェクトにおいてコードフォーマットを行う方法、及びそれをIDE(Eclipse, IntelliJ)に適用する方法になります。

背景

コードフォーマッターが必要になった経緯です。

最近は仕事でSpring Bootを使ってWebアプリの開発をしています。Javaの開発であればEclipseIntelliJなど優秀なIDEがあるため、コマンド一発でフォーマットしてくれます。便利ですよね。

なので、個別にフォーマッターを入れる必要は開発時点ではなかったのですが、CI/CD時にフォーマットチェックを入れたいという話になり、Githubなどに上げたあとの環境でフォーマットをかける必要が出てきました。

今回はmavenでプロジェクトを作っていたためmavenでのフォーマッターの導入の話、IDEと共通のフォーマッターを使用する方法などを書きます。

使用するフォーマッター

formatter-maven-pluginというのを利用します。が、公式らしきサイトのUsageを試していてもうまくいかず、少し自分で調べる必要がありました。

利用方法

公式サイトの方ではpom.xmlに書くpluginと、実行方法は以下のようになっていました

pom.xml

<project ...>
    ...
    <plugins>
      <plugin>
        <groupId>net.revelc.code.formatter</groupId>
        <artifactId>formatter-maven-plugin</artifactId>
        <version>2.0.2-SNAPSHOT</version>
      </plugin>
    </plugins>
    ...
</project>

実行方法

mvn java-formatter:format

しかしこの方法ではフォーマットはおろか、プラグインの実行すらされません。 というかそもそもmvn java-formatter:formatで実行しているjava-formatterプラグインのprefixから検索しているのにプラグインのartifactIdがformatter-maven-pluginだし。。。

色々調べたり試したりしたところ、下記のプラグイン指定と実行方法で行けました。

pom.xml

<project ...>
    ...
    <plugins>
      <plugin>
        <groupId>net.revelc.code.formatter</groupId>
        <artifactId>formatter-maven-plugin</artifactId>
        <version>2.0.1</version>
      </plugin>
    </plugins>
    ...
</project>

実行方法

mvn formatter:format -Dconfigfile=formatter.xml

formatter.xmlは下で説明しますが、フォーマット用の設定ファイルです。

フォーマットチェックとフォーマット

対象ファイル

確認のため、あえてフォーマットが崩れているファイルを用意しました。main関数を1行で記述しています。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MavenFormatterDemoApplication{
    public static void main(String[] args){ SpringApplication.run(MavenFormatterDemoApplication.class, args);}
}

設定ファイルの取得

上で述べた設定用のxmlファイルですが、今回はSpring bootで標準的に使われているらしいxmlファイルを落としてきて入れました。formatter-maven-pluginではeclipseのフォーマット用のxmlが設定ファイルとして使え、検索するといくつかヒットします。

github.com

設定の例

下記は今回使用した設定ファイルの一例です。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="Spring Boot Java Conventions" version="12">
...
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
...
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="90"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
...
</profile>
</profiles>

設定項目はたくさんありますが、<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="90"/>(改行する文字数)のように比較的理解しやすいものが多いです。

とはいえ直接編集するのは骨が折れるので、カスタマイズするなら後述するEclipseの設定を用いてxmlを生成するのがよいでしょう。

フォーマットチェックとフォーマット

設定したxmlファイルのフォーマットに従っているかどうかをチェックするには以下のコマンドを実行します。

mvn formatter:validate -Dconfigfile=formatter.xml

先程のようにフォーマットが崩れているファイルがプロジェクトに存在すると、mavenがエラーを吐きます。

> ~/maven-formatter-demo> mvn formatter:validate -Dconfigfile=formatter.xml
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven-formatter-demo 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- formatter-maven-plugin:2.0.1:validate (default-cli) @ maven-formatter-demo ---
[INFO] Using 'UTF-8' encoding to format source files.
[INFO] Number of files to be formatted: 2
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.130 s
[INFO] Finished at: 2017-10-01T19:57:48+09:00
[INFO] Final Memory: 13M/81M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.revelc.code.formatter:formatter-maven-plugin:2.0.1:validate (default-cli) on project maven-formatter-demo: File '~/maven-formatter-demo/src/main/java/com/yoghurt1131/mavenformatterdemo/MavenFormatterDemoApplication.java' format doesn't match! -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

では、これをフォーマットしていきます。先程のmvnコマンドでvalidateとしていた箇所をformatに変えるだけです。

 mvn formatter:format -Dconfigfile=formatter.xml
> ~/mave-formatter-demo> mvn formatter:format -Dconfigfile=formatter.xml
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building mave-formatter-demo 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- formatter-maven-plugin:2.0.1:format (default-cli) @ mave-formatter-demo ---
[INFO] Using 'UTF-8' encoding to format source files.
[INFO] Number of files to be formatted: 2
[INFO] Successfully formatted:          1 file(s)
[INFO] Fail to format:                  0 file(s)
[INFO] Skipped:                         1 file(s)
[INFO] Read only skipped:               0 file(s)
[INFO] Approximate time taken:          0s
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.129 s
[INFO] Finished at: 2017-10-01T20:00:00+09:00
[INFO] Final Memory: 14M/79M
[INFO] ------------------------------------------------------------------------

フォーマット成功ファイルの数、失敗したファイルの数、スキップされた(すでにフォーマットされていた)ファイルの数などがでます。

実際に確認してみると、きちんとフォーマットがされています。

フォーマット前

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MavenFormatterDemoApplication{
    public static void main(String[] args){ SpringApplication.run(MavenFormatterDemoApplication.class, args);}
}

フォーマット後

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MavenFormatterDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MavenFormatterDemoApplication.class, args);
    }
}

IDEでの利用

作成したフォーマッターを使えば、PaaS環境などのIDEが無い場所でもフォーマットチェックやフォーマットが行えるようになりました。とはいえ、IDEのフォーマッターとmavenで使用するフォーマッターが違ってしまうと、開発環境でかけたフォーマットがpush先で通らないといった事故が起きる可能性があります。

ここでは、作成したフォーマッターを各IDE(eclipse, IntelliJ)に読み込む方法を書きます。

eclipseでの利用

Eclipse->Preferences(設定)->Java->Code Style->Formatterに設定項目があります。

f:id:yoghurt1131:20171001202002p:plain:w500

ここでxmlファイルをimportすることができます。

また、Newから独自のフォーマット規約を作成することができます。これはxmlファイルとしてExportすることができるので、既存のがイマイチで自分でフォーマッターを作りたいという場合はこれを利用してオリジナルのフォーマッターを作成するのがいいかと思います。

IntelliJでの利用

IntelliJでも利用方法はほとんど同じです。

IntelliJ->Preferences->Editor->Code Style->JavaからImport Schemeをすることで設定ファイルを導入することができます。

注意点としては、IntelliJにはIntelliJ独自のコードフォーマット(IntelliJ IDE code style XML)があることです。

Eclipseとの互換性はあるため、Eclipseで作ったxmlファイルをIntelliJで利用することはできますが、逆はできません。開発時にIntelliJの設定でフォーマッターを作成した場合はそのままmavenで使用することができないのでご注意ください。

リンク・参考

エンジニアのための時間管理術を読んだ

オライリー出版のエンジニアのための時間管理術を読みました。ここではその感想と、最近感じてる時間の使い方について書こうと思います。

store.shopping.yahoo.co.jp

エンジニアのための時間管理術

原題はTime Management for System Administratorsなので厳密には「システム管理者のための時間管理術」なのだけれど、多くのエンジニアにはもちろん、非エンジニアである人でも参考になるような良書です。

この本が魅力的なのは、著者の語り口によるところが大きいです。この本は著者の経験談や悪戦苦闘の歴史に基づいて書かれており、あくまで「自分はこれでうまく行った」という書き方で押し付けがましさがありません。

また、ユーモア豊かに書かれており翻訳もとてもチャーミング。例えば4章にはこのような文章が出てきます。

SAは、一般に頭の切れる人々です。あなたは賢いし、筆者も賢いのです。皆が賢いのです。

・・・最高じゃないですか?ところどころこんな感じで進んでいくので、読んでいてすごく楽しかったです。

内容をかいつまんで

この本は、タイムマネジメントの考え方や、その実践方法についてこと細かに書かれています。 とはいえそれを全て書くのは不可能なので、印象に残った部分をいくつか挙げていきます。

TODOは全て外部記憶に頼ろう

(他の仕事も多くはそうですが)エンジニアは頭脳労働です。仕事の際には仕事に集中できる環境を整えておく必要があります。 この本では集中して仕事に取り組むため、何か気になることや、やることがある場合は全て外部記憶(TODOリストやその他の記録ツール)に書き出すことを勧めています。人間は忘れる生き物です。「明日Aさんに電話する」でも「今日牛乳を買いに行く」でも、何かを覚えておくことは多かれ少なかれ頭脳に負荷がかかります。それらを外部に書き出すことで、より眼の前の仕事に集中できるとしています。

決断の回数を減らそう

この本では、上で書いた「やらなきゃいけないことは外部記憶に頼る」以外に「決断の回数を減らす」ことについてもその重要性が主張されています。 本当かどうかわかりませんが、かのアルバート・アインシュタインは同じスーツを7着持っていたと言われています。日常の些末な(人によっては違うかもしれませんが)決断に労力を割かないことで、自分の能力を全て学問に捧げることができたと。

我々の脳の容量は限られています。この本では、本当に大事なところで能力を発揮するために、日常における決断の回数を減らすべきであると述べられています。

何回もやる作業はルーチン(習慣)化する

では、実際に決断の回数を減らすにはどうすればいいか。著者はそれに対する回答はルーチン(習慣)を作成することであると述べています。習慣化しているということは、考えずにその行動が行えるということに近いです。 ルーチンとは「一度だけ考え、何度も実行するための手段である」と定義されています。これはプログラマならよく理解できることだと思います。プログラムは、一度書いたら何度でも実行できるものなのですから。

僕自信が最近作成したルーチンの例を紹介します。それは、「財布や家の鍵などの外出時に持ち歩くものは全て、自室の小箱にしまう」というものです。これを定める以前は、財布や家の鍵の場所が帰宅したときによって変わってしまい、家を出る時に鍵がない、財布がない、といった事態は多々ありました。そこで、「財布や定期券、家の鍵、イヤフォンなどの外出時に持ち歩くものは自室の小箱に全て置く。帰宅したらまずそこにそれらのアイテムをしまう」というのを習慣づけました。これによって、出かけるときに必要なものを探す必要はなくなり、結果として時間の節約になっています。

時間を上手く使うために

社会人になって、日常の自由時間がかなり少なくなったと感じます。しかし一方で、生活サイクルが定まることによってより日常の行動が最適化され、空きの有意義な時間が増えたような気持ちにもなっています。 学生の頃は、生活サイクルなんてかけらもありませんでした。目が覚めたときに起きる、眠くなったら寝る、研究が忙しければキリがつくまでやる。全てを自分の裁量でさばけるという意味では自由でしたが、「いつお昼を食べよう」「いつ帰ろう」といった些細な考え事が常に頭のなかに合ったと思います。そういったことを考えているだけで時間がすぎ、貴重な時間を無駄に消費していました。 働くようになってご飯を食べる時間、寝る時間、起きる時間はほぼ固定になりました。これによって自分の空き時間を自分がやりたいことに純粋に使えるようになったと感じています。別にアインシュタインになりたいわけではないですが、学ぶにしても遊ぶにしても「時間を無駄にしていない」という感覚は非常に気持のいいものです。 これからも良い習慣を作っていきたいなと思った次第です。

プレゼンテーションZENを読んだ

学生時代に研究室の教員から「これくらいは流石に読んでるよな?」と煽られたにも関わらず読んでなかった「プレゼンテーションZEN」を読みました。

store.shopping.yahoo.co.jp

ZENは「禅」を指しています。その名の通りこの本ではプレゼンが成功する方法ではなく、良いプレゼンをするための考え方やアプローチが書かれています。

ここでは、読んでいて心に刺さった点を幾つか挙げます。


プレゼンテーションの主役は自分

当たり前ですが、プレゼンの主役はPowerPointではありません。話をする自分自身です。そもそもPowerPointで全てを説明できるとしたらスピーカーは不要です。それに下で述べるようにPowerPointはテキストを詰め込むツールとしては適切ではありません。 人がプレゼンを行う際には、必ずその人にしか伝えられないアイディア、経験があります。PowerPointKeynoteなどのプレゼンテーションツールは、スピーチを引き立たせるための補助的な役割でしかないのです。

この考え方に立つことで、スライドを作るアプローチが劇的に変わると思います。「情報を載せなきゃ」というマインドで作るスライドと、「自分が話したいことをどうやって引き立たせるか」というマインドで作るスライドではきっと完全に違うものが出来上がるでしょう。

悪しき習慣のスライデュメント

本の中で著者は「スライドはシンプル」にと何回も説いています。スライドはスライドとして、資料は資料として用意するべきである、と。そして、スライドと資料が混ざったものを「スライデュメント」(Slide + Document)と呼び、それは非常に中途半端で良くないものであると主張しています。スライデュメントとは、スライド一面が大量の文字で埋め尽くされたり、箇条書きで埋まったりしているようなスライドのことを指しています。

しかし、現在ビジネスの場ではこの「スライディメント」が多く見られます。むしろPowerPointを使ってプレゼンする際の基本的な形とさえなっています。著者はこれを「一石二鳥だと思っている人がいるかもしれないが、二兎追う者は一兎も得ずである」とバッサリ切り捨てています。たしかに、PowerPointのスライドは、詳細を事細かに書けるようにはなっていませんし、文字を詰め込んだところで聴衆から読めなくなってしまっては意味がありません。詳細を伝えたいならWordなどで資料を作成して、それを後で読んでもらえばいいのです。

「究極的に何が言いたいのか」を考え抜く

自分が聴衆として聞く場合を想像するとわかると思いますが、100%の集中力でプレゼンを聞き続けるなんてことは不可能です。だいたいどこかで集中力が切れます。 だからこそ、準備の段階で「自分はプレゼンを通して聴衆に何を伝えたいのか」を考え抜き、それが伝わるような構成でプレゼンテーションを組まなければなりません。プレゼンを作る際には、「聴衆はたった自分のプレゼンの中でたった1つのことしか記憶に残らない」というつもりで作るべきなのです。

プレゼンを作っているとついつい色んなことをスライドに書きすぎてしまいますが、可能な限り削るべきです。ZENでは、プレゼンの準備に必要なのは「抑制」であると説いています。伝えたいことを詰め込みすぎて、聴衆の集中力が切れてしまったら最後、そのプレゼンは誰の記憶にも残らないものとなってしまいます。可能な限りシンプルに行くべきなのです。


上記に書いたのはまさにプレゼンテーションにおける禅のような考え方や姿勢でしたが、この本にはスライドを作る際のデザインの原則や、スピーチの場において必要なことなど、実践的なこともかなり載っています。スライドのサンプルもかなり多いです。今後も何かとプレゼンをする機会はあるので、この本を参考にして、禅のような精神で鍛錬を積みたいと思います。

GoogleCalendarAPIを使ってGoogleCalendarの予定を取得する

お題通りです。+ α程度の情報は載せていますが、基本的には公式のQuickStart通りに進めました。言語はPythonです。

Step1: Google Calendar APIを有効にする

自分のGoogleアカウントでGoogle Developers Consoleにログインします。初めての場合は「規約に同意して進む」みたいな画面が出るので、一通り確認して進みます。

認証が終わると自動的にAPIを使うためのProjectが作成されます。 「認証情報の追加」というメニューが出てきますが、APIを使うのに必要なのはClient IDなので「クライアントID」と書かれたリンクをクリックして次に進みます。

OAuth同意画面に飛ばされるので、必須項目のサービス名を記入して次へ。(他に記入できる項目があれば記入してください) アプリケーションの種類と名前(適当でもいいです)を入力して「作成」ボタンを押すとクライアントIDとシークレットキーが作成されます。

f:id:yoghurt1131:20170510212302p:plain

こんな感じです。右端のダウンロードのマークをクリックしてjsonファイルをダウンロードし、client_secret.jsonという名前にリネームしてプログラムを置く予定のフォルダに保存します。

Step2: Pythonライブラリのインストー

pipで入れるだけ。

pip install --upgrade google-api-python-client

Step3: サンプルスクリプトを動かす

サンプルのスクリプトquickstart.pyが公開されているので、これをコピーします。

Step4: 実行

あとはpythonで叩くだけ。

python quickstart.py

ブラウザが立ち上がって、Googleアカウントの認証をできればOK。 サンプルのスクリプトは、実行したタイミングから未来の予定10件を取得するようにできています。

補足

これだけだとちょっと寂しすぎるので、少しだけ補足を。

認証情報の保管

quickstart.py実行時にブラウザを使って認証を行いましたが、これは最初だけです。2回目以降は普通にAPIが使えます。 この時の認証情報が$HOME/.credentials/以下に保存されています。

APIの仕様

こちらのサイトに使えるメソッドが載っています。

予定の書き込み

quickstart.pyでは、予定の読み込みの例しか載っていません。 書き込みの例を簡単に紹介します。やることは主に3つ程度です。

1. SCOPEの変更

quickstart.pyの20行目

SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'

この最後のreadonlyを省きます。

2. 認証情報を削除

このままだと上記のreadonly権限での認証情報が残ってしまっているため、Permission Deniedで弾かれます。 $HOME/.credentials以下の認証情報ファイルを削除します。

3. イベントを挿入するソースコードを記述

quickstart.pyでイベントを取得している箇所を、以下のような感じに書き換えます。

    event = {
      'summary': 'Sample Event from Python',
      'start': {
        'dateTime': '2017-04-28T09:00:00',
        'timeZone': 'Asia/Tokyo',
      },
      'end': {
        'dateTime': '2017-04-29T19:00:00',
        'timeZone': 'Asia/Tokyo',
      },
      'recurrence': [
        'RRULE:FREQ=DAILY;COUNT=2'
      ],
    }

    calendarId = 'xxxxxxx@gmail.com' # 自分のカレンダーID(例えば、メールアドレス名)を入れる
    event = service.events().insert(calendarId=calendarId, body=event).execute()