aminev.blog

20210821

いろいろ溜まっていたので、一気に吐き出してみました。それぞれの質はかなり低いので悪しからず。

[AWS][Go] LocalStack はこまめに最新化すべき

aws-sdk-go + LocalStack で、 s3manager.Download() を使って、ローカルの S3 バケットからファイルをダウンロードしようとしたら、 以下のようなエラーになる。

InternalServerError: Internal Server Error
status code: 500, request id: , host id:

向き先を AWS 上の S3 バケットに変更したらダウンロードできたから LocalStack の問題だろう。そう思って調べたら、すでに Issue があって修正済みだった。

ということで、手元の LocalStack を最新化してみたら正常に動いたという、しょうもないお話。

ちなみに、LocalStack は docker-compose で動かしているが、イメージを更新したいときは docker-compose pull とすればいいらしい。

[AWS][Go] aws.WriteAtBuffer

s3manager.Download() の第 1 引数は io.WriterAt 型でなければならない。

ただし、 ドキュメント に書かれているように aws.WriteAtBuffer を使えばメモリー上にも出力できる。

The w io.WriterAt can be satisfied by an os.File to do multipart concurrent downloads, or in memory []byte wrapper using aws.WriteAtBuffer.

バッファの中身を取得するには、 aws.WriteAtBufferBytes() メソッドを呼び出す。戻り値は []byte 型なので、文字列へ変換する必要があることに注意。

client := s3.New(sess)

// バッファサイズを取得
headOutput, err := client.HeadObject(&s3.HeadObjectInput{
  Bucket: aws.String(bucket),
  Key:    aws.String(key),
})
if err != nil {
  log.Fatal(err)
}

contentLen := *(headOutput.ContentLength)
bufWriteAt := aws.NewWriteAtBuffer(make([]byte, contentLen))

// メモリ上にダウンロード
downloader := s3manager.NewDownloader(sess)
_, err = downloader.Download(bufWriteAt, &s3.GetObjectInput{
  Bucket: aws.String(bucket),
  Key:    aws.String(key),
})
if err != nil {
  log.Fatal(err)
}

// 内容を標準出力
fmt.Println(string(bufWriteAt.Bytes()))

[Android] ワイヤレスデバッグ

USB ケーブルが無くてどうしようと思ったら、Android 11 から USB ケーブルを繋がなくても Wi-Fi 経由で接続できるようになったらしい。最近スマホを買い替えて 4 から 11 になったので、ちょうどよかった。

adb コマンドは Android Studio をインストールしたら入ってくるけど、パスがなかなか分からなかった。Mac だと、 ~/Library/Android/sdk/platform-tools/adb にあるので、 .bashrcPATH に追加すれば使える。

[その他] jq コマンド

これ、なかなか便利。

JSON ファイルを指定できる場合( curl や AWS CLI の DynamoDB とか)では素直に指定すれば良い気もするけど、たまにエスケープして渡さないといけないことがあって、そういうときは重宝しそう。

[AWS] Amazon MemoryDB for Redis

どうなんでしょう。ElastiCache の後継かな?と思ったらそうではないみたい。東京リージョンにもまだ来ていないし、使い所がよくわからないので様子見かな。

[Slack] Slack Webhook でメンションを飛ばすには

仕事で定期的に Slack に通知する Webhook を作った。

Webhook でも、普通にテキストに @aminevsky と書けばメンションが飛んでいたので、とくに意識していなかったが、本格運用しようとしたら、人によってはメンションが飛ばないことがあった。

最初は 氏名表示名 を指定すればメンションが飛ぶのかなと思ったけど、そうではないみたいで頭を抱えていたら メンバー ID なるものを知った。

メンバー IDプロフィール -> その他 -> メンバーIDをコピー で取得できるらしい。また、メンバー ID を使ってメンションする場合は <@メンバーID> というように <> で囲む必要がある。

で、このとおり修正したら動くようになった。にしても、Slack API は仕様が頻繁に変わって、しかも古いバージョンも中途半端に動き続けることができたりして、なかなか辛い。1

[その他] カーニハン先生

ブライアン: 無限にあるドキュメントのどこに必要な機能があるのか​​を調べるよりも、自分でロジックを考えた方がプログラミングしやすいと思いました。ですから、私にとってプログラミングとは、調べることよりも何かを作るようなものであり、今のプログラミングは、調べることを重視しているものが多過ぎます。

耳が痛い…

そういえば、カーニハン先生の UNIX: A History and a Memoir って、いつ日本語訳が出版されるんでしょう。一応、先生の ホームページ には、日本語訳が進行中であると記載されているのですが。

Translations into Japanese, Polish, Russian and other languages are underway.

[JavaScript] 論理和演算子

論理和演算子( || )を使うと、例えば、値が空文字であるときに初期値を設定することができる。

const x = '';
const y = x || 'initial'
console.log(y) // 'initial'

でも、ときどき初期値を「異常系が発生したときの保険」として使っている人がいて、うーんとなる。

例えば、Node.js で環境変数から値を取得する場合。 envName は動作環境がステージングなのか本番なのかを区別するためのものと思われたい。

const envName = process.env.ENV_NAME || 'stg' // stg: ステージング環境、prod: 本番環境

たぶんこれを最初に書いた人は、 ENV_NAME の中身が空文字ということはありえないけど、保険として stg を初期値に設定したんだと思う。

だけど、これだと、万一、本番環境で ENV_NAME が空文字だったときに stg が代入され、しかもそのまま処理が継続してしまう。

そもそも、 ENV_NAME が空文字ということがありえないならば、ちゃんと if 文を書いてチェックして異常終了させるべきだっただろう。

[その他] Safari の不思議な挙動

数ヶ月前に、これにハマったので、記念として残しておく。

結局どうしたかというと、そもそもログイン認証を付けているのだから、その手前で Basic 認証をするのは過剰だよねということで、Basic 認証のほうを一時的に外したんだっけ。

仕様的にどうなのかとかは全然わからないけど、開発者視点としては「余計なことしやがって…」という感想だった(笑)


  1. 2020年頃に Webhook の仕様が変わったらしいけど、今の会社では古い仕様で Webhook を今も作り続けている。いつ使えなくなるか分からないけど、中途半端に使えているものだから、みんな移行するモチベーションが上がらないみたい。 ↩︎