SPAをS3でホスティングすると404が出てしまうのの対策

何回か遭遇しているので備忘録として書いておく。

問題

S3でホストしているSPAでURLのルーティングをしたい場合、とくに何も設定しないとS3側のルーティングが優先されるのでSPAでのルーティングがされる前にエラーになってしまう。

例えば、http://example.com/user/account_settings というアカウント設定画面のURLがあった場合、これをWebブラウザでHTTPリクエストしたらSPA上のアカウント設定画面が表示開くことを期待する。 しかし、S3としてはこのURLがSPAのものかどうかなんて分かるはずもなく、ただの /user/account_settings へのリクエストとして捌くので、そんなS3オブジェクトは無いということで404エラーを返してしまう。

普通にindex.htmlを開いた後に画面遷移したりする分には、SPA内での遷移として扱われるのだが、直リンで指定した場合等にはエラーとなってしまうので少しわかりづらい。

対策

Cloud Frontを挟んで、S3の404レスポンスを全てを200に書き換えて、index.htmlを返すようにする。

f:id:ron4321:20191216231822p:plain
Cloudfrontでの設定画面(403は要らない)

少しトリッキーだが、こうすることでユーザーにはindex.htmlが返り、ルーティングの処理は全てSPA側に任せることができる。

S3のerror pageとしてindex.htmlを指定することでも実現できそうだが、多分レスポンスコードがエラーのままになるのでダメ(だと思う。たぶん。試してはいない。)

感想

SPAだとなるほど確かにという感じ。S3に限らず他のWebサーバーでホスティングする時にも同じような設定は必要そうだ。

これだけのためにCloud Frontを挟むことに若干の抵抗感があって、S3だけでできないもんかねーという気持ちにもなったが、S3はStorageサービスであって、Webサーバーとして扱えるのはあくまでオプションだということを考えると、贅沢言ってんな自分とか思ってました。

今一度、チャットコミュニケーションに対する期待値を合わせる

こんにちは。@ron_4321です。この記事はEM Advent Calenderの14日目のものです。

はじめに

最近、色んな職種の人がチャットを使って仕事をするのが当たり前になったことで、どうしても使い方の価値観の違いによる不満が発生しがちだなーと感じます。DMで業務の相談をしないでほしいーとか、その会話はスレッドでやらないでーとか、みなさんも一度は経験があるのではないでしょうか?

年々チャットコミュニケーションの割合が増えていったり、リモートワークを実施する企業が増えていく中、こういったチャットコミュニケーションでの消耗が生む生産性の低下はバカにならないんじゃないかと思っています。

色んな人が当たり前に使うようになってきた今だからこそ、チャットコミュニケーションに対する期待値を合わせることを見直してもいいんじゃないか。

とそんなことを思ったので、書いていきたいと思います。

チャットコミュニケーションにおける不満の正体

先にチャットコミュニケーションの不満の例を挙げましたが、こうした不満はなぜ発生してまうのでしょうか?

色んな要因があると思いますが、私は組織やチームで何を是とするかの合意が取れていなく、各々の価値観で他人のチャットの使い方を評価してしまうことが大きな要因じゃないかと思っています。 特に、合意を得れているかが重要で、何を是とするかが決まっていてもそれがどのような理由や背景で決定したかがからないと反対意見の人は合意したくてもできません。その状況だと自分の価値観を優先して判断してしまい結果的に不満につながってしまうでしょう。

また、もう一つ大きな要因として、チャット文化への関わり方に差があることにより、使い方の期待値が合わないということがあると思っています。

例えば、エンジニア職の方は長年チャットを使っているので、チャット文化について理解が深い人が多いでしょう。 慣れがあるので、階層化されているわけでもない大量のテキストデータをストリーミングして適切に必要なものだけフィルタリングすることにも抵抗がなかったり、 パブリックなチャンネルでオープンなコミュニケーションを取ることも嫌じゃないという人は多いのではないかと思います。

一方、ビジネス職や管理部門の方はチャットを使い始めたのが最近でチャット文化へまだ慣れていないという方が多いのではないでしょうか。

仕事上のコミュニケーションは長年Gmailを使っていて、スレッド形式の階層化されている情報に触れていることが多く、Slackでも同じようにスレッドを使うことにまとまりがあって好ましいと考えたり、 1:1の対面のコミュニケーションで仕事を進めることが多かったことから、DMを使うことの方がしっくりくると考えたりすることもすごく自然なことだと思います。

これらの使い方や考え方というのはどちらか良くてどちらが悪いというものではないと思っています。 あくまで今までのチャットとの関わり方の差から生まれる文化の違いでしかありません。 海外では家の中で靴を履くのが当たり前だけど、日本では履かないのが当たり前といった文化の違いと同じことでしょう。

一方で、文化が違うと争いが発生するのもとても自然なことだと思います。

文化が違う人が混在する中で、個人の価値観で是非を決めるのは危険なので、組織やチームの価値観で是非を決めていき、理由を説明して合意を得るということが必要になってくるのではないでしょうか。

チャット文化への慣れが少ない人を置き去りにしていないか?

上記したように、組織やチームの価値観で是非を決めて合意を得ていくことは非常に大事なことだと思っています。 大なり小なり、多くの企業ではこうした取り組みは行なっているのではないでしょうか。

一方で、こうした決め事や運用をしていくときに、チャット文化に慣れていない人が置き去りになっていないでしょうか?

  • 慣れている人だけでルールを決めていないでしょうか?
  • 慣れていない人はそのルールや背景を理解できているでしょうか?
  • 慣れていない人はそのうち勝手に慣れてくれると思っていないでしょうか?
  • 新しく入社した人も同じように理解できているでしょうか?

こういった決め事をしていく時にはどうしても権威勾配が急になりがちだと思います。慣れてない人は意見を言いづらいし質問もしづらいはずです。

慣れている人ほど権威勾配が急になることを意識して、慣れていない人をフォローしていってあげることで質の良い合意形成になっていくのではないかと思います。

組織としてもっとコストをかけて取り組んでもいいのではないか?

これは組織によって全然違うと思うので一概には言えないのですが、個人的にはこうした取り組みに組織としてコストをかけて取り組んでもいいのではないかと思います。 なぜ「コストをかけて」なのかというと、

一つは、コストをかけずふんわり運用するとそれなりに回ってしまうがゆえに問題が顕在化しないと思っているからです。

コミュニケーションで何か問題が起きたとき、多くの人は多少の不満であれば我慢するでしょう。そんなに頻度も高くないと思うのでなおさらです。 そういった多少の我慢が積み重なっていくことで徐々に徐々に綻びが生まれていきます。その綻びは何か大きめのきっかけがあると爆発して修復不可能になってしまうものだと思っています。 そういう綻びを生まないためにコストを支払うことは費用対効果があることなんじゃないか。と思っています。

もう一つは、年々対面コミュニケーションが減り、チャットコミュニケーションの割合が増えてきていると感じるからです。 対面コミュニケーションの時は顔や表情や話し方など、色んな情報からその人のへの印象を決定しますが、 チャットコミュニケーションでは基本的にはチャットでのやりとりがその人への印象になりやすいと感じています。 対面よりテキストでのコミュニケーションの方が圧倒的に難しいので、ただでさえ難しい組織内での心理的安全性を担保していくのがさらに難しくなっていくと思っています。

このような考えから、個人的にはコストをかけて取り組んでもいいのではないか。と考えています。

まとめ

色んな人が使うようになった今だからこそ、チャットコミュニケーションの期待値を合わせる取り組みについて見直したり、改めて力をいれてやっていくってことをしてもいいんじゃないか? というのがこの記事で伝えたいことでした。

こうした取り組みが増えていって、チャットコミュニケーションで疲弊する人が少しでも減って、チームとしての成果が最大化されていって楽しく働ける組織が増えていけばいいなーと思っています!

『THE TEAM』を読んだ

前々から気になってた『THE TEAM』を読んだので読書感想文を書いておく。

どういう本か?

https://www.amazon.co.jp/dp/B07PZB9DTKwww.amazon.co.jp

『THE TEAM』はチーム作りについてかかれている本で、特に

  • チームとは何なのか?
  • 世の中のチームはなぜうまくいかないのか?どうすればうまくいくのか?

を紐解いている本だ。

中でも 目標設定/メンバー選定/コミュニケーション方法/意思決定の方法/モチベーションと共感 を5つを大事な要素として解説している。

下記の記事で目次が全て転記されているので、詳細な内容が気になる方はこちらを確認するといいだろう。 dev.classmethod.jp

感想

期待値を合わせていくことの大事さを改めて感じた

それぞれの法則を私は下記のように解釈した。

  • 目標設定の法則
    • チームとしてどういうゴールを目指すかの期待値を意義目標、成果目標、行動目標のように分類し細かく合わせないと、チームメンバーが自律的に行動することができない。正しく議論ができない
  • 人員選定の法則
    • チームの形をビジネスや目標に対して正しく選択したり変化させていかないと歪みや矛盾が生じて機能しない
    • 「xxxという理由があるからこういうチームの形でやっていく」という意思決定に対する期待値をチームと合わせておくことが大事である
  • コミュニケーションの法則
    • 価値観が多様化している昨今、別の価値観を持った人達で心理的安全に仕事をするためには、適度なルール設定をしたり相手のバックグラウンドを理解して意図しない期待値外なコミュニケーションを減らす努力が必要である
  • 意思決定の法則
    • ビジネスや目標に対して最適な意思決定の方法を選択する必要があり、この意思決定の方法の期待値をあらかじめ合わせていないと、納得感が生まれずチームメンバーが主体的に動けない。
  • エンゲージメントの法則
    • どんな人でも仕事の質はモチベーションに左右されるもの。チームに貢献しようと思うためのモチベーションは4P(Philosophy/Profession/People/Privilege)で構成されている。このうち自分たちのチームでは何が提供できるのか、チームメンバーは何を求めているのかを明らかにして期待値を合わせることが大事である。

あくまで個人的な見解ではあるが、どの法則で書かれていることも最終的には「期待値を合わせる」という行動に繋がっている気がしていて、チームを作ってくうえで「期待値を合わせる」というのは大きな割合を占めているんだろうなーという感じがしている。

「期待値が合っている状態」を作るためには、組織の方針を深く考え、言語化し、理解してもらい、変更があれば更新し、また理解してもらう...というサイクルを回していく必要がある。それはとっても精神的にも時間的にもコストがかかることだったりするけど、今組織がうまく回ってそうな会社はそれをやり切れてる会社だと感じるので、改めて大事だなと感じた。

エンジニア職以外の人にもオススメできるチーム本ができた

過去、『Team Geek』『エンジニアリング組織論への招待』『チームが機能するとはどういうことか 』を見た時に、これらの本に書かれているチーム作りのエッセンスを非エンジニア職の人にも共有したいと思うことがあった。 しかし、内容の多くがエンジニア向けだったりそこそこ重厚だったりして、気軽にオススメはできないなーと感じていた。

この本はページ数も少なくて内容もすごく平易に書かれているので、誰が見ても理解がしやすい内容になっている。一方で、チームとは何で大事なことは何なのかはしっかり書かれていて非常にバランスの良い本だと思っている。

なのでチームのことで課題を抱えてる非エンジニア職がいたら今だったらこの本を紹介したいと思う。

チームづくりの組織施策を始める前の1冊として

昨今、チームづくりやっていくぞ!となった時に、OKRやスクラムなど先人たちが作ってきた有用な施策に乗ることがおおい。それ自体は良いことだと思うが「そもそもなんでチームづくりが必要なんだっけ?」の理解度がチームメンバーによってバラつきがあるまま進んでしまうっていることはよくあることな気がしている。 そういったチーム内での情報の非対称性を無くしていく意味でも、最初にこの本を読み合わせたり、この本からエッセンスを拾ってきて「xxxという理由でチームを強くしていくことが重要だ」のような認識合わせをしていく。というような活用の仕方ができそうだと感じた。

おわりに

めちゃ良い本だったので広めてまわりたい

aws-sdk-go-v2を使う時にアクセスキーをコード上で直指定する

はじめに

aws-sdkを使う場合、認証方法として環境変数、ローカルのcredentialsファイル、IAMRoleなどを使うことが一般的だが、 カジュアルな用途で使用する場合にはこれらの準備をすることが煩雑な場合もある。 こういった場合にaws-sdk-goのv1では credentials.NewStaticCredentials() を使うことができたのだが、v2になってCredentialの指定方法が刷新されたことによりこの方法が使えなくなったのでv2の方法をメモしておく。

※この記事はあくまでカジュアルに使う場合を想定しており、セキュアな環境下には適さないので注意してください。 アクセスキー管理のベストプラクティスは下記を参照してください。

https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-access-keys-best-practices.html

コード

aws-sdk-go-v2からは external.LoadDefaultAWSConfig() を使って aws.Config を生成し、各サービスのクライアントに渡して実行するようになっている。 external.LoadDefaultAWSConfig() の引数に external.WithCredentialsValue() を指定すると直接アクセスキー情報を指定した形のConfigが作れる。

package main

import (
    "context"
    "log"

    "github.com/aws/aws-sdk-go-v2/aws"

    "github.com/aws/aws-sdk-go-v2/aws/external"
    "github.com/aws/aws-sdk-go-v2/service/ec2"
)

func main() {
    config, err := external.LoadDefaultAWSConfig(external.WithCredentialsValue(aws.Credentials{
        AccessKeyID:     "xxxx",
        SecretAccessKey: "xxxx",
    }))
    if err != nil {
        log.Fatal(err)
    }

        config.Region = endpoints.ApNortheast1RegionID

    ec2Client := ec2.New(config)
    req := ec2Client.DescribeInstancesRequest(&ec2.DescribeInstancesInput{})

    resp, err := req.Send(context.Background())
    if err != nil {
        log.Fatal(err)
    }
 
    log.Println(resp)
}

external.LoadDefaultAWSConfig() は引数無しでも実行できて、その場合は環境変数やローカルのファイルからよしなにCredentialsを探してきて、なければエラーを返す。というようになっている。 引数はデフォルトの挙動に対してオプションを指定するためのものとなっている。

所感

external.LoadDefaultAWSConfig() の引数に何が指定できるのかが分かりづらいのが注意点。 aws-sdk-go-v2自体はシンプルにはなったしリクエスト毎にcontextが指定できるようになったりしてめちゃ良さそうな印象でした!

CloudWatch Logs Agentをセットアップする時に便利なあんちょこ

CloudWatch Logs AgentをEC2環境で手動でセットアップしたいということが稀によくあって、 毎回エディタで開いて実行するのも面倒なのであんちょこを書いておく。

# agentのインストール
sudo yum install -y awslogs

# awscli.confのregionを 'us-east-1' to 'ap-northeast-1' に変更する
sudo sed -e s/us-east-1/ap-northeast-1/ /etc/awslogs/awscli.conf -i

# 変更されてるかを確認する
sudo cat /etc/awslogs/awscli.conf

# awslogs.confにcloudwatch logsに送りたいログの収集設定を追記する
# 基本的には「/var/log/xxxxxxxxxx_log」に相当する所を置換すれば良い
# 詳しい設定方法のリファレンスはこちら: https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/AgentReference.html
    
sudo tee -a /etc/awslogs/awslogs.conf echo << EOS

[/var/log/xxxxxxxxxx_log]
datetime_format = [%a %b %d %H:%M:%S %Y]
file = /var/log/xxxxxxxxxx_log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/xxxxxxxxxx_log
EOS

# serviceの再起動
sudo service awslogsd restart

# 自動起動を設定しておく
sudo chkconfig awslogs on

# 自動起動設定の確認
chkconfig --list | grep awslogs

さいごに

IaCが整ってる環境であればこんなことしなくても良いという話ではあるが、お試しで立てるインスタンスなどわざわざコードを書くのは大げさだよねーという場合に便利です

MACアドレスを収集するためのツールをGoで書いた

collect-mac-address というものを書いたのでそれに対する感想というか振り返りみたいなものを書いておく。 github.com

どんなツールなのか?

collect-mac-addressコマンドラインツールで、実行するとPC名とMACアドレス一覧が出力されるただそれだけのプログラムだ。 Goで書いているのでGoが使える環境なら go get すればコマンドとしてすぐ使える。 また、クロスコンパイルするビルドスクリプトを用意しているので、GoかDockerがローカルに入っていればビルドスクリプトをキックしてもらうだけでどのOS環境でも実行できるファイルが作れる。

なんで書いたのか?

フリーランスとしてお手伝いしている会社がオフィス移転を機に無線LAN環境も一新して、WPA-PSK + MACアドレスで認証するようにしたいという話があったのがきっかけだった。

MACアドレスを収集するだけなら、各々にifconfig 相当のことをしてもらって結果を送ってもらえばいいだけという話ではあるのだが、

  • 社員にはビジネス職の人が多いので、コマンドラインで実行させるのは心苦しい
  • 仮に実行できたとしても、その後アクセスポイントに設定する用のフォーマットに整形する必要がある
  • WindowsMacで手順が違う

という前提があり、 これを手順としてドキュメント化して実行してもらうのは結構効率が悪そう(問い合わせも多く結局正しく整形されてないものがきたりしそう)だと思った。

そんなに数が多いわけでもないので全部自分が実施して回ることも一瞬考えたが、フリーランスという関わり方で属人的なことをするのは微妙だよなーと思ったので、各々が実行ファイルをダブルクリックしてコピペするくらいのツールを作ろうと思った。 この要件に対してGoのクロスコンパイルがちょうど良くハマりそうで、あまり使ったことがなかったので丁度良いお勉強になりそうだったのも大きな要因だった。

学びがあった点

まずGoのクロスコンパイルはめちゃくちゃ簡単だった。

たったこれだけで、MAC用のバイナリが出来上がる。

GOOS=darwin GOARCH=386 go build -o ./bin/darwin386/hoge

今回は、Win/Mac/Linux用でビルドされるようにスクリプトを書いたが、この手のツールなら大体このスクリプトをコピペして使っていけそうな気がしている。 github.com

また、Docker全盛期な昨今、ビルドするためだけにGoが必要なのも微妙だなというのがあったので、Dockerでビルドできるようにもしてみた。

最初はビルドする用のDockerイメージを作ってDockerHubにpushしておこうかとも思ったが、 そんなに使われる前提でも無いツールなので、そこまでする必要無いかと思い至り特にイメージ等は用意せずシェルスクリプトを書くにとどめた github.com

改善点とか

  • 実行したらSlackに自動でポストされるのも良いかなーと思った
    • が、あまり便利にすると何をやっているのか分からなくなってしまうので、少しコストがかかるくらいの方がセキュリティを意識してもらいやすいのではないか。
    • 社員数が多ければ意識ではなくツールで解決した方がいいと思うが、社員数が少ないのであれば既存社員の意識をあげて後に入る社員の意識がつられて上がることの方が大事ではないか。
    • とか、そんなことを考えたり。
  • ビルドされた成果物が危険な実行ファイルとして判定されてしまう
    • コードサイニングされていないから?
    • あまり詳しく調べていないが、ダブルクリックするだけで済むようにしたい

まとめ

まぁそんな大層なツールではないのだが、書いて公開までするとそれなりに学びがあるなーというのは思ったので、 今後もアウトプットの一環としてカジュアルにやっていければなと思っている

CircleCIのbuild imageでgit-lfsを使う

Circle CIでビルドする用のdockerイメージにgit lfsはインストールされていないため、別でインストールする必要がある。 下記のような感じで、checkout後に手動でインストールすることで git lfs pull が使えるようになる。

docker:
  - image: circleci/node:11.13.0
steps:
  - checkout
  - run:
      name: Install Git LFS
      command: |
        curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
        sudo apt-get update
        sudo apt-get install -y git-lfs openssh-client
        git lfs pull

他のイメージを使う時でも、そのimageで使えるパッケージ管理ツールを使うか、最悪githubからバイナリを落としてmakeするみたいなことをすればできるはず。 git lfsを入れたビルド用のdockerイメージを作っておく。みたいなのも手かもしれない。

あと、上記の設定だと毎回のビルドの度に git lfs pull してしまい、Datapackを食いつぶしてしまうので、 必要に応じてキャッシュする戦略をとった方がよさそう。