読者です 読者をやめる 読者になる 読者になる

詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

なぜプレゼンで失敗するのか

自分も大方の人間と同じように人前で喋るのは苦手で、可能であれば避けたいと思っているけれど、一方でこの業界で生きのこる方法のひとつとして避けられないものでもあると思っている(ので苦しい)。若かりしころ手痛い失敗をしたこともあって、かなり苦手意識を持ちつづけていたが、最近はわりかし上手く付き合えるようになってきたかなとふり返って思う。

今もうまいプレゼンテーションをする方法は知らないし、それを僕から知りたいという人はいないとおもうが、プレゼンでしくじる方法なら経験から知っている。準備をしないこと。自分の経験からはそうだし、まずいプレゼンを見ていてもそうなんだろうな、と思うことはやっぱり多い。

このエントリはプレゼンがいやでいやで仕方がなかった自分のための分析であり、プレゼンのマイナスレベルをゼロまで引き上げようとする努力です。ソフトウェアエンジニアの技術者間交流のためのプレゼンというのが前提。

準備にかける時間が足りていない

そもそもの話。『パブリックスピーカーの告白』という本を昔に読んで、今となっては内容はほとんど覚えていないが、プレゼン時間×聴衆の人数くらいの時間はかけよ、というようなことが書いてあったはず。愚直に従うものではないだろうけど、他人の時間を使うのだという意識を持とういうことだと思う。

やる気が出なくて準備に体が動かない、というパターンがもっともあると思う。人前で話すことは怖いし、準備に時間をかければかけるほどその失敗が具体的になって目の前に現れてくるように感じてしまう。それだったら何も準備しないで臨んで失敗したほうがマシだ……という風にすら考えてしまう。自分の場合はアルコールが使えるので、自分をシラフの自分と酒を飲んだ自分に分けて、ここから先は酒を飲んだときにやる、あとはシラフのときに考える……という風に分業しています。酒を飲むと気が大きくなって別のことをしはじめたりするので、諸刃の剣ではある。

他人が「資料できてない」みたいなことをツイートしていても、絶対に安心したり、真似しようとしたりしてはいけない。そういう人たちは強者であって、すでに自分たち自身のなかに蓄えがあるからそういう所業ができるのであり、それにプレゼンテーションは一人きりの舞台なので他人がどうこうというのは全く関係がないことだからだ。

時間を割く対象が間違っている

これまで、だいたい最初に資料を作りはじめて失敗するパターンが多かった。プレゼンテーションの準備というのは聴衆に受けいれられるストーリーを作ることが一番であって、資料を作ることではない。最近はとりかかる際に、アウトラインも書かず、完全に頭のなかにあるものだけから口に出して喋ってみるようにしている。喋ってみると話の内容を直列化しなければいけないので、話の内容の依存関係から意外と整理しやすくなったりする。

このストーリー作りにもっとも時間を割かないといけない。どんな聴衆がいて、何を持ち帰ってもらうのかもはじめに考えておくと手戻りが少ない。勝手だけど、自分の場合は id:hakobe932 さんを想定聴衆に置くことがおおいです(自分が喋れる分野ならまず押さえているし、にこやかに聞いてくれるから)。

巷のスライドを見ると凝ったものが多く、こんな風にできればわかりやすいだろうな、と思うものの、そんな能力はないので愚直に箇条書きする。凝りだすとキリがないので最初から諦めていく。

プレゼンは喋りがメインであるという前提のもと、話したい内容の全部ではなく、それをさらに蒸留したものをスライドには書く。フォントサイズをあまりに小さくしない。ページからあふれる場合は削るか分けるかする。

リハーサルをしていない

前の項目に被るが、独立した一項目にしていいやつ。とても重要。

リハーサルはやった方がいいことは分かっているものの、失敗をより具体的にイメージさせるものなので、やらないですむならそれがいいと思ってしまう。しかし本当のところは、やった方がいいものではなくてやらなければならないこと。ストーリーなしの資料作りが設計なしの実装なら、リハーサルなしのプレゼンはテストなしの本番投入。たまにはスリルがあっていいかもしれない。短くない時間、自分のために他人を拘束するのにぶっつけ本番で舞台に登るなんてのは大変おこがましいことである。

……などと建前上はわかっていても、できないから苦しいのである。わかります。経験上、とりあえず自分の作ったスライドを見ずに喋りだすと、言葉が続くことが多い。先の、ストーリーをまず喋ってみることをしながら作っていると、身体も慣れているのだと思う。腕を振ったり歩き回ったりしながら喋るとやりやすい気がする。

巷のエントリを読むとリハーサルをもとに時間の調整をする……とされていることが多いが、正直本番で冷静に時計が見られたためしがないので、せいぜい時間がオーバーしないようにしておくくらい。

他人に聴いてもらうのが一番だと思うけど、自主的にこれをできたことはないので口をつぐみます。

自信がない

一番つらいやつ。準備不足の最初にして最大の原因。ストーリーを作らずリハーサルもせず無目的にスライド作りに手を動かしてしまうのは自信がないから。対処方法は各自見つけるしかないと思うけど、ストーリーを口の中でくり返しているうちに、プレゼンがだんだんと精神を使う作業というよりは身体的なものになって気が楽になってくることはあった。あまり頭を使わなくなる。

自信がないからといって本論から逸れる話をしない。より自信がなさそうに見える。楽屋ネタやアニメネタを入れない。笑いを取りにいくのも難しいのでやめよう。

自分以外の人物が自分のプレゼンをハキハキと行っていることを想像するのもいい。全方位的に恥ずかしい話だけど、自分の場合はアニメ『アイドルマスター』のプロデューサーを代わりに演台に立ててます。スーツにネクタイなのが好印象なのだと思う。なんそれって感じですけど。

まとめ

プレゼンは身体的なものなので身体に叩き込む。身体を動かすと、やる気もあとからついてくる。

おたがい頑張りましょう。

パブリックスピーカーの告白 ―効果的な講演、プレゼンテーション、講義への心構えと話し方

パブリックスピーカーの告白 ―効果的な講演、プレゼンテーション、講義への心構えと話し方

英国王のスピーチ スタンダード・エディション [DVD]

英国王のスピーチ スタンダード・エディション [DVD]

吃音者のスピーチ。一緒にするなと言われるかもしれないけど何か通じるものはあるんじゃないかと思う。

Google App EngineでGoを動かすときに知っておくべきこと(ソースコード・ビルド編)

Go GAE

Google App Engine(GAE)で Go 製のウェブアプリを動かしたかった話。いっぺん動かしてみると GAE/Go はウェブアプリを動かす環境としてはとてもいい。ただ、中途半端な知識だけで始めると開発者としてはつまずくことが多かったので、分かりにくい点をまとめておく。


コンテキストとして、スタンドアロンで動くよう書いていた Go ウェブアプリを GAE で動かしたいと思った、しかし GAE の知識はほとんどない、という背景を想像してください。その際に壁となる以下のような点だと思うので、それぞれ自分がどうしたかを見ていく。

  • GAE/Go のデプロイの仕組み
  • GAE/Go 環境の制限

この記事の内容は、SDK のインストールと、goapp による Hello, world のデプロイくらいまでは済ませてある人むけ。そうでない人は、まずはチュートリアルをおさえると良いです。

Quickstart for Go App Engine Standard Environment  |  App Engine standard environment for Go  |  Google Cloud Platform

Google App Engine Go Standard Environment について

GAE は自分が知っていたころの知識では単体のサービスで、Python で書かれたアプリケーションを動かすことのできる代物だったが、今は Google Cloud Platform に吸収されて、そのいちコンポーネントとなっているらしい。2016年の今では、GAE 上で Go が動くようになっている。

App Engine - Platform as a Service  |  Google Cloud Platform

Getting Started with App Engine - YouTube より

ベータ版として Flexible Environment というものもあるらしいけど、ここでは触れません。

この記事で扱う goapp のバージョンは "go version go1.6.2 (appengine-1.9.40) darwin/amd64" 。

goapp は $GOPATH 以下もアプリケーションのソースとしてアップロード/コンパイルする

何を当たり前のことを、と思われるかもしれないし自分も今書いていてそりゃそうだとしか思えないのだけど、最初は「GAE って Heroku みたいなもんでしょ」というくらいの大雑把な認識しか持っていなかったので、ワークツリーの外に存在するソースコードが暗黙に利用されるというのに驚きがあった。

つまり、GAE/Go では

  • 手元でコンパイルしたアプリケーションのバイナリをアップロードするのではないし、
  • 主要なソースコードだけをアップロードしてリモートで go get するわけでもなく、

アプリケーションのビルドに必要なソースコードを $GOPATH 含めて探索し、すべてアップロードした上でリモートでコンパイルする。

この挙動は、一度デプロイしたアプリケーションのソースコードを appcfg.py download_app してダウンロードしてみるとわかる。たとえば github.com/pkg/errors をインポートしている場合、以下のようにソースコードが配置される(もちろん、この github.com というディレクトリはデプロイ時にはアプリケーションのソースコードに存在しなかったもの)。

.
|-- _go_manifest.txt
|-- app.yaml
|-- github.com
|   `-- pkg
|       `-- errors
|           |-- errors.go
|           `-- stack.go
`-- init.go

goapp はプロジェクトルート以下のソースコードをすべてコンパイルしようとする

これも驚きのあるところ。どういう経緯かは分からないけど、まあそういうものらしい。ここでプロジェクトルートというのは app.yaml が置いてあるディレクトリのことを指す。GAE/Go におけるアプリケーションのコンパイルはけっこうややこしいことになっていて、それを調べて書くだけで長い文章になりそうなのでやらないけれど、さしあたりこのルート以下のコードがすべてコンパイルされることを覚えておけば充分そう。以下に、このことによって発生するエラーメッセージを挙げる。

go-app-builder: Failed parsing input: parser: bad import "syscall" in ...

GAE/Go では syscallunsafe パッケージのインポートが許されていない。たとえばプロジェクトルート以下に vendor ディレクトリを作っていて、その下に置いたサードパーティ製のライブラリがこれら利用不可のパッケージを利用していた場合、アプリケーションから利用していなくても開発サーバの起動やデプロイができなくなることになる。

go-app-builder: Failed parsing input: app file xxx.go conflicts with same file imported from GOPATH

また、プロジェクトルート以下のファイルが $GOPATH や vendor ディレクトリに含まれていて、通常の方法でインポートされている場合も、アプリケーションの一部として自動的にコンパイルされるソースコードと、$GOPATH からインポートされるパッケージの一部としてのソースコードが重複するとみなされてエラーになる。

対処方法

アプリケーションからインポートされるソースコードは、プロジェクトルート以下に配置しない。プロジェクトルートの外にある $GOPATH からインポートするようにする。

その他の方法として、app.yamlnobuild_files なる項目を設定する、というやり方があるらしい。この項目、公式のドキュメントが見当たらない(のに巷のブログでは紹介されていたりする)のでやや不安がある。のだけど x/tools/cmd/present で紹介されてるのでまあ大丈夫じゃないかな……。

nobuild_files: vendor/

これは正規表現を指定するのだけど自動的に ^ が付与され、先頭一致となる模様。

API のドキュメント らしきものには Files that match this regular expression will not be built into the app. This directive is valid for Go only. と書いてありました。

ちなみにビルドされたくないソースコードに // +build !appengine なるビルドタグを付与することでコンパイルを避けることもできるが、現実的ではないだろう。

goapp は Python 製ツールのラッパー、コア部分は go-app-builder

これはまあ知らなくてもハマらないけど、細かい挙動を追いたくなったら必要になってくる。

goapp は挙動を見る限りでは Go 公式の go コマンドのフォークで、goapp deploy および goapp serve という GAE 専用のサブコマンドが追加されている。

% goapp help
Go is a tool for managing Go source code.

Usage:

        goapp command [arguments]

The commands are:

        serve       starts a local development App Engine server
        deploy      deploys your application to App Engine
...

で、

  • goapp servedev_appserver.py
  • goapp deployappcfg.py update の、

単なるラッパーになっている(それぞれのサブコマンドのヘルプに書いてある)。goapp にはログレベルを変更するオプションがないので、必要ならこれらを直接呼び出すとよい。

さらに、これら Python 製のツールは、アプリケーションのランタイムが Go である場合には go-app-builder というツールを呼び出す。これが前に述べた挙動の源になっている。これはソースコードが $(goapp env GOROOT)/src/cmd/go-app-builder にあるので興味あれば見てもらうとして、コメントだけ引用しておく。

go-app-builder is a program that builds Go App Engine apps.

It takes a list of source file names, loads and parses them, deduces their package structure, creates a synthetic main package, and finally compiles and links all these pieces.

いろいろやってます。

アプリケーションを構成するパッケージの置き場所とインポート

以上のような事情もあってか、GAE/Go ではプロジェクト内のパッケージは、デプロイ時のみ ルートからの相対パスによってインポートできることになっている。例えば import foo/bar と書かれたコードが goapp によってビルドされると、パッケージ foo/bar のコードは $GOPATH だけでなくプロジェクトルート以下の foo/bar ディレクトリからも探索される。

.
|-- app.yaml
|-- foo
|   `-- bar
|       `-- bar.go
`-- init.go # import "foo/bar"

しかしサブパッケージのインポートをこの挙動に頼るのは、あまりに GAE にバインドされてしまう点でよい方法とは言えないだろう。GAE と強く結びついているコードからこの形のインポートをするのはアリとしても、それ以外の、いわゆるドメイン層などアプリケーションのコアとなる部分までインフラの影響を受けてしまうのは一般的に避けたいはず。

そういうわけで、アプリケーションが複数パッケージ構成になる場合は、それらを $GOPATH から普通にインポートするように寄せるのがよい(いま説明したこの挙動は忘れたほうがいい)。プロジェクトに固有の $GOPATH を設定し、その中にサブパッケージを配置するようにする。go-app-builder は(普通の go と違い) 、$GOPATH 内のシンボリックリンクを辿るようになっているので、この構成も作りやすいはず。

このへんの話は公式ドキュメントにも触れられているんだけど、ちょっと分かりにくいかな……。

どういうソースコード構成にすればいいのか

で、結局どうしたらいいの、という話。ここは事実じゃなく意見の話なので、話半分で読んでください。

これまでの話を踏まえると、

  • デプロイされるアプリケーションが $GOPATH の状態に依存するので、
    • プロジェクト用の $GOPATH を設定し、それが開発者の環境に依存しないようにする(何らかの形でプロジェクトに含める)
    • 普通の vendoring を行う
  • プロジェクトルート以下のファイルがすべてコンパイル対象となってしまうので、
    • app.yaml のあるディレクトリ以下に依存ライブラリのソースコードを置かない
    • 置くなら nobuild_files を指定する

というオプションから好きなものを選べばよいということになる。

もともとスタンドアロンで動くものを書いていたこともあって、新たに appengine というディレクトリを作って、

$GOPATH/src/github.com/motemen/gae-app
|-- appengine/
|   |-- app/
|   |   |-- app.yaml
|   |   |-- init.go
|   |   ...
|   `-- gopath/
|       |-- src/github.com/motemen/gae-app/lib # lib への symlink
|       `-- vendor/src # vendor への symlink
|-- main.go # GAE に依存しないバイナリのエントリポイント
|-- lib/ # アプリケーションのコアロジック
|-- vendor/
...

のようにし、Makefile 中で $GOPATH を appengine/gopath に設定していた。この中にアプリケーションのサブパッケージや、vendor へ向いたシンボリックリンクを作っている。そうすることでアプリケーションにとっての $GOPATH をコントロール可能にしている。vendor の管理だけ、グローバルな $GOPATH の下で行っている。

まだ試行錯誤の数が少ないのでベストとは到底言えないけれど、自分は今は上記のようにしている。みなさんはどうしてますか? と丸投げして終わります。

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】

その他、読んでおいたほうがいいもの

エンジニア立ち居振舞い: 属人性を減らす

お題「エンジニア立ち居振舞い」

おもしろそうなお題なので乗ってみる。自分は今は技術組織のとりまとめをしているけど、会社の古めのプロダクトの面倒を見る仕事もしてきた。時を経てサービスに携わる人が変遷し、コードの歴史も重層的で一筋縄ではいかないことが多い。仕事で触れるプロジェクトが多いので、ひとつのプロジェクトに関する知識を深めづらい面もある。

属人性を減らす

さまざまなタスクを通じてプロダクトに触れるうちにだんだんと自分の中に知識がついてきて、用件を聞いたときに「あ、それならあのプロジェクトのあのへんのコードだな」、というアタリがつけられるようになってくる。この地図や勘といったものは正直なところ外部化しづらく、ある程度を超えると個々人の中で養っていくしかないものだけれど、日々の仕事において、属人性を減らすように努力することはできる。

普段からやっていることは以下のようなところ。

  • 作業ログを残す。他の人が「とりあえず検索」したときに、周辺的な情報を掴めるようにする。Slackに書いて満足しない。
  • 単調作業はコード化する。簡単な手順でもスクリプト化してインターフェイスを狭めておくことで迷いを少なくする。
  • ドキュメントを書く。初見の人のためには、ふるまいや解決したいことを軸に記していくと入りやすい。

当たり前のことではあるけれど、先人がこれをやってくれているおかげで助けられることも多いです。