ネットの海の片隅で

技術ネタの放流、あるいは不法投棄。

middleman, CodeBuild, S3, CloudFront でいい感じにシュッとやる

モチベーション

自分が何者であるかを表明しておく場所が Web に欲しいなという気持ちがあった。

そのために osa.in.net というドメインを取得していたが、肝心のコンテンツが一切なかったのでとりあえず仕組みをつくることにした。

要件

安くて簡単

自分が何者であるかを表明するのは大事だが、使用頻度はそれほど高くないので手間も金もかけたくない。

HTTPS

時は既に2017年なので、原始人でもないかぎり HTTPS を喋ってほしい。

自動デプロイ

いちいちデプロイするのは面倒なので勝手にデプロイされてほしい。

構成

  • 静的ページをつくって S3 に置く
  • 独自ドメインHTTPS を喋らせるために CloudFront を経由させる
  • 静的ページは middleman をつかって生成する
  • CodeBuild を使って自動デプロイする

設定

middleman の使い方とか S3, CloudFront, Route 53 の基本的な設定なんかは Web に腐るほどあるのでここでは書かない。

ここでは少し手間取った以下の2点について書いておく。

  • 自動デプロイ
  • いい感じの URL

自動デプロイ

はじめは CodePipeline を使って CI/CD パイプラインを作ろうと思っていた。 しかし、CodeDeploy は S3 へのデプロイに対応していないことが発覚。 「Build とは? Deploy とは?」という気持ちを抱えつつ、CodeBuild でデプロイすることに。

やることは主に3つ。

  • ビルド環境の構築
  • ビルド
  • デプロイ

環境構築を毎回やるのは効率が悪いんだけど、いちいち docker image を管理するのが面倒なので毎回構築している。

ビルドについては middleman の機能をそのまま使っているが、デプロイについては middleman-s3_sync を使っている。 CodeBuild の IAM Role に S3 Bucket へのパーミッションをつけてあげれば、環境変数経由でいい感じに credential を受け渡してアップロードしてくれる。

なお、CodeBuild 用の build spec ファイルはこんな感じ。

# test/buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - sudo apt-get update
      - sudo apt-get install -y nodejs
      - bundle install
  build:
    commands:
      - bundle exec middleman build
  post_build:
    commands:
      - bundle exec middleman s3_sync

これで、master に変更が入るたびに middleman によってビルドされた静的ファイルが S3 へ自動デプロイされるようになった。

CodeBuild の料金が $0.005/min で、実行に1分半くらいかかるので1円/デプロイくらいのコストがかかる。

いい感じの URL

ここで「いい感じの URL」というのは https://example.com/path/to/page のようなものを指す。 URL の末尾を削って https://example.com/path/to としてもページがあってアクセスできるようにしたい。 そのために拡張子を含まない URL にする必要がある。

S3 において、拡張子を含まない URL を提供することは難しくない。 S3 の Static Website Hosting では directory index が有効になっているので、/path/to/page/index.html が存在していれば /path/to/page でアクセスできる。

また、この形式でファイルを吐き出すオプションが middleman にあるので、それを使えばビルドも簡単にできる。

この際の注意点として、S3 の Static Website Hosting の結果を CloudFront 経由で配信する場合、CloudFront の Origin として S3 Origin を選ぶと directory index がうまく動かず Access Denied を返してしまう。 そこで、Custom Origin を選択した上で、Static Website Hosting のエンドポイントを設定してあげると動くようになる。

ただ、この状態で /path/to/page にアクセスすると /path/to/page/ にリダイレクトされてしまう。 これは directory index がその名前の通りディレクトリを指しているために起こってしまうことで、S3 の設定などでどうにかすることはできない。

もちろん、EC2 を立てるなどすれば /path/to/page のままアクセスすることは可能だが、EC2 は S3 の Static Website Hosting より遥かに高いし、サーバーのお世話をしたくない。

そこでダーティではあるが、以下のような JS を書くことでごまかすことにした。

document.addEventListener('DOMContentLoaded', function() {
  var path = window.location.pathname;

  if (path.match(/\/$/)) {
    path = path.replace(/\/$/, '');
    history.replaceState(null, null, path);
  }
});

これで、事実上 /path/to/page でアクセスできるようになった。

おわりに

こうして作ったサイトが https://osa.in.net で動いている。

コンテンツがほとんどない、デザインが非常にアレなどの問題はあるが、今後少しずつ足していくことにする。

Ruboty で TRPG をする

Ruboty pluginを書いたので簡単に紹介しておく。

使い方

1d100, 3d6 などの文字列を ruboty roll に渡すと、ダイスの出目と出目の合計値が出力される。

> ruboty roll 3d6
[2, 4, 5] => 11
> ruboty roll 1d100
[41] => 41

擬似乱数の生成は SecureRandom

きっかけ

休日に何もやる気が起きなくて、クトゥルフ神話 TPRG のリプレイ動画を見ていたところ、無性に自分でもプレイしたくなり、「オンセをするときに Slack を使ったら便利なのでは?」という発想から、「とりあえずダイスを振るための plugin を書こう!」となった。

問題

ダイスロールする Ruboty plugin はできたけど、一緒に TRPG をやる友達がいない。

ruboty-tomodachi が必要。

価値のないものを高速につくらないために

スピードとスピード感は違うし、素早くつくることと雑につくることも違う。

我々の仕事がコードを書くことではなく問題を解決することである以上、どんなに素早くつくるとしても誰のどんな問題を解決するのかは常に意識していなければならない。 その点について深く考えずに思いつきで「A すれば B できるようになる」というものをつくるのは素早いのではなく雑なものづくりだと思っている。

そもそも「〜できる」ということにはあまり価値がないと思っていて、「〜するようになる」「〜してしまうようになる」というように行動が変わるところまで意識的に持っていかなければならないと考えている。 *1

面と向かって他者の行動を変えるのだってめちゃくちゃ大変なのに、インターネット越しに画面だけでユーザーの行動を変えるということがそんなに簡単にできるはずがない。 だから、画面の向こうにいる人に対して何かしらのアクションを引き起こさせようと思うのであれば、その人が抱えている問題や欲求を可能な限り理解しようとした上でその欲求に従うものをつくらないといけない。

でなければ、「機能」はつくれたとしても行動を変えられない。

また、開発者はユーザーそのものではないので、どんなに時間をかけて考えたとしても、最終的には実際にリリースしてみないと本当に価値があるのかどうかはわからない。 しかし、それは問題や欲求について考えなくても良いという理由にはならない。

速度という点では、リリースと測定のサイクルよりもチーム内での対話の方が数段速い。自分の頭の中で考えるのはもっと速い。

仮説検証という点では、ちゃんと考えてもいないものに対して一体何を検証するというのか。南波六太の言葉を借りると「本気でやった場合に限るよ。本気の失敗には価値がある」。

リーンは雑な開発の言い訳じゃない。

以上、価値のないものを高速に作っても仕方がないというお気持ちでした。

*1:もちろん例外はある。強い欲求によってすぐに行動に繋がるケースはあるし、できるようになることそのものに一定の価値があるものもある。