山本ゆうごブログ

山本ゆうごの仕事メモ

調整さんの正しい使いかた

簡単みんなのスケジュール調整ツール「調整さん」を作った|blog|たたみラボ

調整さん リリースから10年以上も経つが、そもそもツールだけでは解決しないことが多々ある。 元々はメール文面で、日程調整をしていたのをビジュアル化したいというニーズから作ったものなので全ての課題を解決してくれるわけではない。

調整さん以前に時間調整ってどうするのかということを記したい。

例えば、会社の飲み会の調整。

二週間前後くらいあとの日程で

直近だと急すぎる。先すぎるともっとだいじな予定が入るかも知れない。なので、二週間前後くらいがちょうどいい。

自分の予定はまずはブロック

たまに見かけるのが、自分があとで日程候補に△とか書いちゃうケース。日程候補は自分が行ける日だけにしましょう。

会の重要性を伝える

行っても行かなくてもいいのか、必ず来て欲しいのかって重みは大事。既に予定が入っていてもそれを押しのけるべきかどうかも受けての判断ポイントになる。

調整さんで日程候補を出す前にキーマンの予定をブロック

ありがちなミスが、キーマンが調整さんに最後に予定をいれて、全滅というケース。まずは偉い人の予定を先に確保する。その確保された選択肢を、調整さんに候補として登録する。そして招待する際に「○○さんのブロック済みの候補です」とアナウンスしておけば、下々のものは「ならそっちに寄せるか」と判断しやすい。

日程候補を多くしすぎない

二週間くらいのレンジで飲み会日程候補がやってきたとしても、全てに◯とは書きづらい。「現時点での空き」を伝えるのではなく「日程調整が終わるまでのブロック」を差し出すことになる。二週間全部空いていたとしても、ユーザは「ブロックを差し出す数件」のみ◯にしちゃうので、結果的に日程が合わない。

選択肢は「できるだけブロックして欲しい数件(常識的には最大5件程度)」を提示するのがいい。

入力をお願いする

全員が入力されない場合もある。優先度が低い人は「ではこの日程に決まったのでできれば参加してください」と伝えるし、優先度が高い人(そして往々にして忙しい人)に対しては、直接会ってでも入力を促す。もしくは会ってその場で彼のスケジュールをブロックしながら候補を埋める。会えない人には電話をする。一対一のコミュニケーションでお願いする。

まとめ:時間調整は結構な意思決定を促している

調整さんというお手軽ツールを作っていながらもやっぱり幹事は気を使うべきだとは思ってる。偉い人も偉くない人も時間は平等に24時間。その時間を何らかの予定のブロックとして「差し出す」のは結構な投資/消費の意思決定をしている。その二時間で仕事をする以上のものが得られるのか、その二時間で一本の映画を見る以上の楽しみがあるのか。「どうか私に貴方の二時間を下さい。後悔はさせません」という気合でコミュニケーションをとるべき。

RDBにバイナリファイルを置くメリット

RDBにはBLOB型があって、そこにはバイナリファイルを置くこともできる。

あんまり有り難みがないかもしれないだけれど、個人的には結構よく使ってる。

以下、いいところだけをピックアップする

複数マシンから寄ってたかって使いたいとき

処理マシンのローカルにファイルを置くと共有できない。NFSみたいなものを使えばいいのだけれどそういうの作るのが面倒。開発環境と本番環境で揃えるのも面倒だ。

削除がしやすい

大量のファイルをローカルストレージに置いちゃうと、rm -rf だけですごい時間がかかっちゃう。黙ったままなので進捗も分からない。これが、RDBに置いたら、trancate 一発で削除できる。そもそもローカルストレージでファイルが多いと、lsだけでもビタット止まっちゃう。

ステータス管理しやすい

RDBなので、BLOB型の隣には、status(int) みたいな適当なフィールドを作っておいて、この画像サムネイル作ったっけ?みたいなステータス管理がしやすい。キューもかねたストレージとして扱える。

集計しやすい

select DATE_FORMAT(updated_at,'%Y/%m/%d %H') as ymdh, count(updated_at) as cnt  from テーブル名  group by ymdh;

こんな感じで、一時間おきのファイルの更新ペーストとかが分かる。

メモリに載せやすい

MySQLにはクエリキャッシュの機能がある。イマドキはいっぱい詰めるので、極端なはなしDBの中身が全部乗っけることもできる。クエリキャッシュは元データが変わるとキャッシュも破棄されるので、プログラマが意識する必要がない。どれくらいキャッシュにヒットしたかもSQL一発で分かる。ディスクのIOよりも、ネットワーク越しのメモリアクセスの方が管理しやすいってこともある。

SequelProならバイナリファイルもそのままみれる

SequelProというMySQLクライアントがめちゃくちゃよくできていて、バイナリファイルはプレビューができちゃう。jpgだけじゃなくてPDFまでプレビューしてくれる。めちゃくちゃ高速に検索できるファイルサーバとして使える。

そもそも、S3でいいのでは?

それはそもそう。容量あたりの単価も安い。ただ、ステータス管理とかしたくなると、S3のメタデータだけだとやや不便。そこは別途キューとかRDBでステータス管理したくなる。惜しい。「今日更新されたファイル一覧が欲しい」って検索条件がぱっと思いつかない。

僕はいつもこんな感じでざくっとデータをみている

CSVがドーンとあったとする。その際にどうやってデータを見るかってのは、なんとなくの手順がある。その手順を示しておく。

wc -l でみる

まずは行数をみる。10万行とか超えちゃうとExcelでは重すぎてみれない。

less コマンドでみる

そして中を確認する。lessコマンドでみれるのはutf8縛りなので、SJISの場合は別のエディタなどで開く。 中身が何かを確認する。 先頭にBOMがついているかどうかや、LF改行なのか、CRLF改行なのかくらいはここで分かる。 大きなファイルも早く開けるのがlessコマンド。先頭行と最終行はチェックする。

Excelでみる

文字コードを変換する

nkf -s utf8.csv > sjis.sv

で、SJISに変換する。UNICODEのままでExcelで開きたかったら、以下のコマンドでBOMをつける。

cat <(printf "\xEF\xBB\xBF") 元ファイル > BOMつきファイル

Excelで開く

数値の前ゼロが取れちゃうから、普通はCSVをダブルクリックしちゃだめなんだけど、参照専用と割り切って、ダブルクリックして開いちゃう。

フィルタをかける

フィルタをかけて、▼をクリックする、そうするとどういうデータがあるかが分かる。空白の存在などもここで分かる。ゴミデータが入ってないかが分かる。

ピボットテーブルを作る

ピボットテーブルを作ることで、データの分布が分かる。特に日付のフィールドがあれば、ピボットテーブルを日付でグループ化して、年単位や月単位の分布をみて、傾向をつかむ。

mysqlの場合

CSV単体が見づらい場合はmysqlなどのRDBでみる。

ひたすら並びかえる

データの異常値がないかどうかは、ひたすら並びかえて確認する。sequel proやphpmyadmin などのツールであれば、sqlを書くこと無く並び替えが用意なので、そこでみる。

ひたすらグループ化する

select DATE_FORMAT(updated_at,'%Y/%m/%d %H') as ymdh, count(updated_at) as cnt  from テーブル名 
group by ymdh;

こんな感じで、時間単位の更新時間を並べて見て、どういう処理ペースで動いているかを確認したりする。

そのままメールに出力結果を貼り付けたい時などは、FORMAT関数でカンマ区切りにしたり、LPAD関数で左空白詰めをして右揃えにしたりする。

BiqQueryの場合

MySQLだけだと、数百万件を超えるデータは扱いにくい。並び替えやグループ化をするデータはインデックスを貼ればいいのだが、インデックスをはるにもマシンパワーが余分にとられる。そこまでくれば、インデックスに気を使わなくてもいい、BigQueryをつかうのがいい。

ただ、CSVを参照可能にするにもそこそこの手間がかかる。

CSVはUTF8

UTF8のダブルクォート区切り。フィールド内ダブルクォートはダブルクォート二重でエスケープ。

CSVをgz形式にする

BiqQueryに入れるレベルのCSVファイルは、GBを超えるくらいなので、アップロードに時間をかけなくてもいいように、giz圧縮をする。

gzip -c data.csv > data.csv.gz

Google Cloud Strageにアップする

gsutil cp data.csv.gz gs://bucket/data.csv.gz

この段階で、Googleの認証が必要。gsutilもインストールしてる前提。認証は、gsutil auth で認証をする。

この際に、GoogleCloudStrageのプロジェクトIDが必要。GoogleCloudStrageのプロジェクトIDとBigQueryのプロジェクトIDは同じ方が権限的に楽。

bq コマンドでロードする

bq load --source_format=CSV  --skip_leading_rows=1 --project_id=XXX aaa.gz   gs://zzzz/aaa.gz \
id:integer,\
name:string

各カラム名とその型を、スキーマとして引数にしていしている。シェルとしては一行だけど、見づらいのでバックスラッシュで改行を入れている。

bq コマンドを最初につかうときにもGoogleの認証は聞かれる。 AWSみたいなアプリケーションキーを環境変数に入れておくというような手法でない。accountを切り替えるのは面倒。

BiqQueryで集計して、レポートにする

ひたすらグループ化のSQLをたたく。集計の結果は、SpreaSheetに出力できるので、ポンポン出力する。適当なファイル名で出力されるので、出力されるたびに、スプレッドシートのファイル名を変えたほうがいい。

スプレッドシートに出せば、グラフにポンポン変換できるので、グラフ化して、スライドの資料にポンポン貼っていけばいい。スプレッドシートには、SPARKLINEという関数があって、セルの中にちょっとしたグラフをかける。Excelでいうデータバーみたいなことができるので手軽。

f:id:yugo_yamamoto:20171015103510p:plain

ポンチ絵のナゾ

ポンチ絵は大事で嫌い

ポンチ絵は嫌われている。

Bubbles don't crash! という言葉がある。Bubbles というのは、ドキュメント上に書かれた図形のことで、ドキュメントをいくら頑張って描いても、その間違いって気づき用がないということ。だからエンジニアの間では、ソースコードの方が重視される。それがシステムを表しているし、間違っていたらエラーがでる。

しかしながら、ソースコードを見せてもそれが何なのかはわからないし。プログラムの外のこと(ユーザーとか銀行とかとの関係)は分からない。

そのシステムの社会的な位置付けを示したいときには、どうしてもポンチ絵が必要になる。大事なのは「システムの外」ということ。

規格としてのポンチ絵 UML

UMLという規格はあるのだが、ポンチ絵にはあまり役に立たない。基本は「自社のシステム」を作るためのものであって、他者との座組を示すものではないから。

ポンチ絵の定義

ラフイメージという位置付け。ハードウェア業界の人達は、製品の完成イメージ図や設計図のラフイメージをポンチ絵と言うし、企業ごとの提携を示すにもポンチ絵という呼び方をする。

ここでは、相関図をポンチ絵を呼ぶことにする。

ビジネスマンでなくてもポンチ絵は大事

例えばオリラジ中田のブログ。 http://lineblog.me/atshikonakata/ https://obs.line-scdn.net/0hWjYbkdvnCEVkGybdC6R3Ei5GDiodeBJNDmMffxFNAmsRdx9FDGEXZgNCDi8XdB9JCDgXPzVoADECLxRDXA9AUUJSLAlKQj1bDgpHKidHCCUKdAZHRH1CK0MbVHZIKkYTUC9PI0QZE3ROKRwaUChO

めちゃくちゃポンチ絵を使ってる。

ポンチ絵のわかりづらさ

学問がない

文学でもない。経済でもない。自然科学でもない。一番近いのは語学ではあるが、ジャンルとして存在していない。だから習うことができない。

ルールがない

ルール化されたのがUMLではあるが、一般的ではない。

ハンディキャップ仮説としてのポンチ絵の存在

本当にコミュニケーションを円滑に刷るために作られたのかさえ怪しい。「頑張って図がいっぱい入ったパワポ資料を作りました」ってスタイルは存在する。

というとで色々サンプルをみながらポンチ絵の存在をみてみよう

日経新聞はこれ http://www.nikkei.com/paper/article/?b=20170502&ng=DGKKZO15973950S7A500C1MM8000 http://www.nikkei.com/paper/image-article/?R_FLG=0&ad=DSKKZO1596443001052017MM8000&ng=DGKKZO15973950S7A500C1MM8000&z=20170502

日経新聞なので、登場人物やら組織やらの間を矢印で繋いで、お金の流れを表すということが多い。

http://www.nikkei.com/paper/article/?b=20170502&ng=DGKKZO15970070R00C17A5TI1000 http://www.nikkei.com/paper/image-article/?R_FLG=0&ad=DSKKZO1597009001052017TI1000&ng=DGKKZO15970070R00C17A5TI1000&z=20170502

この図の場合はもやは矢印が何かさえ言い表してはない。ただ、登場人物は明らかで、なんらかの取引のルールとが矢印で表されているということだけは分かる。

ポンチ絵で抑えるべき箇所

  • 登場人物を箱で書く
  • データ・モノ・お金の流れを矢印で書く

登場人物(組織)を発注などの情報を矢印で結ぶ。「誰が」→「誰に」という風にイベントのトリガーを元にする。 複数の登場人物がいる場合には、直接コミュニケーションをとっているのが誰かというだけでも分かりやすい。

アマゾンの例では、発注の流れではなく、在庫の流れを示してると思われる。普段は出版社はAmazonと直接取り引きをしていないが、日販に在庫がない場合には直接取引をしていることを示している。

形にはこだわりすぎない

日経のAmazonの例をみてみる。出版社はビルだし、日販は本の束だし、AmazonAmazonと書いているだけだ。じゃぁそれが分かりにくいかっていうとそうでもない。Amazonも何らかのイラストつけてあげなよとは思うけど、そこをモタモタするくらいなら、単なる長方形でいい。

社内用途ではロゴが分かりやすい

ロゴって勝手に使っちゃいけないから社外向けのドキュメントには書きづらい。日経もそうだと思う。一方でビジネス用途では本当にその会社を示すためにロゴを使いたいときもあるので、そういうときにはロゴを使った方が視認性が高い。

osxにphp7.1をインストール

brew でインストールできる。

$ brew search php7

これで、php7.0と7.1の両方があることが分かる(2017/02/17現在)。

んで、php7.1の方が速いらしいので、それを入れる。すると、php5.6とコンフリクトしているから、php5.6をunlinkしろと言われる。素直にunlink。unlink はアンインストールではないのであまりためらわずに。

==> Installing php71 from homebrew/php
Error: Cannot install homebrew/php/php71 because conflicting formulae are installed.

  php56: because different php versions install the same binaries.

Please `brew unlink php56` before continuing.

あれためて、インストール

$ brew install php71

すると、こんなインストールログ。

The php.ini file can be found in:
    /usr/local/etc/php/7.1/php.ini

✩✩✩✩ Extensions ✩✩✩✩

If you are having issues with custom extension compiling, ensure that
you are using the brew version, by placing /usr/local/bin before /usr/sbin in your PATH:

      PATH="/usr/local/bin:$PATH"

PHP71 Extensions will always be compiled against this PHP. Please install them
using --without-homebrew-php to enable compiling against system PHP.

✩✩✩✩ PHP CLI ✩✩✩✩

If you wish to swap the PHP you use on the command line, you should add the following to ~/.bashrc,
~/.zshrc, ~/.profile or your shell's equivalent configuration file:

      export PATH="$(brew --prefix homebrew/php/php71)/bin:$PATH"

✩✩✩✩ FPM ✩✩✩✩

To launch php-fpm on startup:
    mkdir -p ~/Library/LaunchAgents
    cp /usr/local/opt/php71/homebrew.mxcl.php71.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php71.plist

The control script is located at /usr/local/opt/php71/sbin/php71-fpm

OS X 10.8 and newer come with php-fpm pre-installed, to ensure you are using the brew version you need to make sure /usr/local/sbin is before /usr/sbin in your PATH:

  PATH="/usr/local/sbin:$PATH"

You may also need to edit the plist to use the correct "UserName".

Please note that the plist was called 'homebrew-php.josegonzalez.php71.plist' in old versions
of this formula.

With the release of macOS Sierra the Apache module is now not built by default. If you want to build it on your system
you have to install php with the --with-httpd24 option. See  brew options php71  for more details.

To have launchd start homebrew/php/php71 now and restart at login:
  brew services start homebrew/php/php71
==> Summary
🍺  /usr/local/Cellar/php71/7.1.1_12: 344 files, 39.7M

php.ini の場所とか、新しくなってるので要注意。PHP-FPMもデフォルトで面倒みてくれている。いよいよ、PHPApacheの付属のものではなく、自立し始めている感。とはいえ、直近ではまだまだApacheもつかいますと。Apache向けのモジュールはどこにあるかなぁと思って、探すとない。インストールログをあらためてみると、

With the release of macOS Sierra the Apache module is now not built by default

って思いっきり書いてある。

なので、オプションを付けて再インストール。install ではなく reinsall ね。

$ brew install php71 --with-httpd24 

するとこんなインストールログ。Apacheモジュールも入ってるっぽい。

To enable PHP in Apache add the following to httpd.conf and restart Apache:
    LoadModule php7_module    /usr/local/opt/php71/libexec/apache2/libphp7.so
    
    <FilesMatch .php$>
        SetHandler application/x-httpd-php
    </FilesMatch>

Finally, check DirectoryIndex includes index.php
    DirectoryIndex index.php index.html

The php.ini file can be found in:
    /usr/local/etc/php/7.1/php.ini

✩✩✩✩ Extensions ✩✩✩✩

If you are having issues with custom extension compiling, ensure that
you are using the brew version, by placing /usr/local/bin before /usr/sbin in your PATH:

      PATH="/usr/local/bin:$PATH"

PHP71 Extensions will always be compiled against this PHP. Please install them
using --without-homebrew-php to enable compiling against system PHP.

✩✩✩✩ PHP CLI ✩✩✩✩

If you wish to swap the PHP you use on the command line, you should add the following to ~/.bashrc,
~/.zshrc, ~/.profile or your shell's equivalent configuration file:

      export PATH="$(brew --prefix homebrew/php/php71)/bin:$PATH"

✩✩✩✩ FPM ✩✩✩✩

To launch php-fpm on startup:
    mkdir -p ~/Library/LaunchAgents
    cp /usr/local/opt/php71/homebrew.mxcl.php71.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php71.plist

The control script is located at /usr/local/opt/php71/sbin/php71-fpm

OS X 10.8 and newer come with php-fpm pre-installed, to ensure you are using the brew version you need to make sure /usr/local/sbin is before /usr/sbin in your PATH:

  PATH="/usr/local/sbin:$PATH"

You may also need to edit the plist to use the correct "UserName".

Please note that the plist was called 'homebrew-php.josegonzalez.php71.plist' in old versions
of this formula.

With the release of macOS Sierra the Apache module is now not built by default. If you want to build it on your system
you have to install php with the --with-httpd24 option. See  brew options php71  for more details.

To have launchd start homebrew/php/php71 now and restart at login:
  brew services start homebrew/php/php71
==> Summary
🍺  /usr/local/Cellar/php71/7.1.1_12: 345 files, 50.9M, built in 11 minutes 32 seconds

最初に書かれている、

To enable PHP in Apache add the following to httpd.conf and restart Apache:

の通りに、httpd.confを編集しようと、/etc/apache2/httpd.conf を編集しても反映されない。おっかしいなぁと思って、以下のコマンドをたたいてみた。

$ which httpd
/usr/local/bin/httpd

てことなので、/usr/local/etc/apache2/2.4/httpd.conf を編集して無事完了。

メール添付が生き残る道

ビジネス用途でのメールって、何かと添付ファイルをつけたがる。本文に書けばいいことまでメール添付にしたがる。zipにパスワードつけてまで暗号化したがる。

ということで、ダメなITの代名詞っぽい添付ファイルだが、以下の点で用途が残りそう。

セキュアなファイル送信

今どきのGoogleやMSのメールシステムは、送受信が暗号化されている。だからセキュア。

DropBoxやGoogleDriveは、「インターネットに公開しちゃう」リスクがあるけど、メールの受信箱はそうそう公開されない。ということでセキュアなファイル送信の仕組みとしてはまだまだ残りそう。

履歴付きのファイル送信

ちゃんとした会社ってメールのログをとってる。だから誰がいつ送ってきたかってのが辿りやすい。直筆の手紙ほどではないにせよ、履歴がとれている。複数サーバで辻褄もあわせれるから証拠能力が高い。

スマホでファイルの受け取る手段

スマホだと、PCと違って、ブラウザからファイルダウンロードしてフォルダ管理してってことがすごく面倒。だけどメールならどんなファイルでも添付で受け取れる。その後プレビューできるかどうかは、スマホ次第だけど、PDFの添付くらいは見れちゃう。さらにそのメールを転送すれば、スマホからどこかしらにファイルを送信もできる。

機械が受け取る手段としての添付

ガラケー時代のブログも添付ファイルで画像を送っていた。システムもメールの添付ファイルくらいは別にパースできちゃう。

下手すりゃローカルファイルより検索性が高い

お行儀よくないのだけれど、メールの方が時期とメールアドレスで添付ファイルが探しやすいということがある。gmailなら添付ファイルの中まで検索してくれる。まぁ便利。

リードオンリー

メール添付は編集できないのが面倒なのだが、リードオンリーという価値はある。ローカルファイルに置いたあとにリードオンリーにするのって結構面倒。

migration がそんなにありがたくない

RailsというかActiveRecordというか、今どきのモダンなORマッパーには、migrationという仕組みがある。

データベースのテーブル定義を、sql文で作るのではなく、プログラミング言語で定義できる。select や updateがRubyでできるなら、create tableやalter tableもRubyで書いちゃえばいいじゃないという発想。しかも履歴管理ができるから、戻すことも可能。これはユートピア

しかしながらどうも言うほど登場シーンがない。以下のようなケース。

既にテーブルがある

100%Rails完結するならいいんだけど、Javaのシステムが使ってるテーブルの管理画面をRailsで作るとかって、全然ありえる話。その場合って、もうmigration が要らないのです。「有るべき姿」ではないのだが、RDBが事実上のインターフェースファイルみたいになって、サブシステム同士を結びつけているケースもある。ActiveRecordeのモデルの裏方ではなく、もはやRDBがインターフェース。思想としては間違いなんだろうけど、RailsSQLのどっちが「世界共通言語?」って問いに対しては、SQLが勝ってしまう。

デプロイのタイミングと、alter table のタイミングが違う

Rubyのソースで一括管理すると、ソースのリリースとテーブル定義の変更が、「せーの」でできて、超美しいように見える。だけど本番ではなかなかそういうことしない。DBの定義ってソースのリリースよりも前に、テーブル定義をかえーの、ちょっとしたデータ変換をおこないーの、旧ソースでも新ソースでもどっちでも行ける状態にして、新ソースをドーンとリリースという形が多い。

結局ゴリゴリに直でDBをメンテすることになる。

テーブル定義は地味にエンジン依存が激しい

「utf8mb4 migration」 とかでググるといっぱい事例が出てくるんだけど、DBが定義する新しい目(といってもかなり前から実装されているmysqlの型)が、migratiion には長らく対応していなかった。ORマッパーそのものがDBエンジン依存を排除できるのがいいのところなのだが、実際には4バイトUTF8もネット上ではちらほら居ている。いわゆるUNICODE絵文字が保存したかったら、migration 使えない。