Go クイズ: v == v が false 編

この記事は Goクイズ Advent Calendar 2020 の 18 日目の記事です。 問題 以下の一部欠けたプログラムの出力は false になります。①には任意の式が入り、②にはビルトイン関数名が入ります。 func main() { a := 【 ① 】 b := 【 ② 】(a, a) c := [2]interface{}{b, b} fmt.Println(c == c) } [レベル1] 選択肢の中から変数 a の型を選んでください。 選択肢: string byte float32 uintptr [レベル2] ①、②に当てはまるものを答えてください。 ※Playground の利用を認めます: https://play.golang.org/p/uKoGpyiHdee 回答 [レベル1] float32 [レベル2] func main() { a := float32(math.NaN()) b := complex(a, a) c := [2]interface{}{b, b} fmt.

Web アプリケーションコンテナをクラスタ無しでデプロイするのに最適な AWS サービスを探したときのメモ

この記事は AWS その2 Advent Calendar 2020 の 16 日目の記事です。 あるコンテナ化された Web アプリケーションを AWS 上にデプロイする必要がありましたので、どのサービスを使うべきか検討したときの話です。 社内ではなくお客様に露出するアプリケーション(ダウンタイムや大きなレイテンシは極力減らしたい) オートスケールは今のところは考えなくて良い、想定されるトラフィックも少なめ 料金はそこそこ安く済ませたい アプリケーションの性質上、クラスタは組めない(常にひとつのコンテナがすべてのトラフィックを請け負う) DB は SQLite, MongoDB, PostgreSQL, MySQL などから選べる(どれでも動く) できる限りコンソールに触ることなくデプロイまでできるようにしたい 以上の条件下で、コンテナをデプロイするサービスと DB をどうすべきか検討しました。 候補① ECS/Fargate 実際にデプロイしてみましたが、Copilot CLI の出来の良さに驚きました。簡単にデプロイできるし、Application/Service/Environment の抽象化がとても使いやすそうでぜひ今後も使っていきたい… という感じだったのですが、主にFargate の値段の高さに断念しました。 Fargate ではひとつのタスクに割り当てる vCPU を決められるのですが、これが最低 0.25 vCPU です。だいたい月 1000 円ちょっとですが、万が一 0.25 vCPU では足りなくなった場合、ECS/Fargate では AutoScale でタスクをで増やすのが基本的な考え方になります。しかし今回は 1 コンテナのみという条件があるため、もともと余裕を持ってコンテナに CPU を割り振っておかなければなりません。 対して EC2 の場合、2 vCPU を積んだ t3.micro インスタンスでほぼ同じ値段ですから(1 vCPU あたりの性能が単純に比較できない気がしますが、だいたい同じでしょう)、今回の条件で Fargate を採用するのはあまり理に叶った選択ではないと判断しました。 候補② ECS/EC2 こちらも Copilot CLI を使えるあたり本命感が出ていますが、ECS/Fargate を触ってみて分かったのは ECS はクラスタを管理することに特化しているということでした。コンテナはいつ置き換えられても良いという前提の上で動くので、今回のようなアプリケーションだとちょっと余計な心配事を増やすことになるなと考えました。どうせ EC2 の OS 等の管理コストを払うならシングルインスタンスモードもサポートした Beanstalk のほうが良いだろうということで、今回は見送りました。

AWS CDK: Construct とは何か

この記事は AWS その2 Advent Calendar 2020 の 9 日目の記事です。 AWS CDK を使っていれば、Construct というキーワードは目にしたことがあると思います。基本的なところですが、今回はこの Construct とは何者か? というところを整理したいと思います。 Constructs Programming Model とは constructs という TypeScript のライブラリがあります。 これは何かというと、「設定ファイルを TypeScript で記述するための基本となるライブラリ」です。いろいろと便利な関数が実装されていますが、主に木構造を構成する Construct クラスを定義しています。 例えば以下のような感じで使うことができます。 import { Node, Construct } from 'constructs'; class MyConstruct extends Construct { onSynthesize() { console.log(Node.of(this).id); } } const c1 = new MyConstruct(undefined as any, 'C1'); const c2 = new MyConstruct(c1, 'C2'); new MyConstruct(c1, 'C3'); new MyConstruct(c2, 'C4'); Node.of(c1).synthesize({ outdir: '' }); Output:

AWS CDK + SAM CLI で Lambda 関数をローカルで動かす

この記事は AWS その2 Advent Calendar 2020 の 5 日目の記事です。前回は @gsy0911 さんによるreInvent2020で発表されたLambdaContainerをCDKで実装してみるです。 CDK で定義した API Gateway + Lambda をローカルで実行する話です。 基本的にはこのあたりの焼き直しなのですが、自分や同僚の環境だとこの手順ではうまくいかなかったので改めてうまくいった手順を記しておこうと思います。 尚以下の方法でも HTTP API(ApiGatewayV2)は認識してくれません。Lambda 単体(sam local invoke コマンド)なら HTTP API を利用していても問題なく動きます。 サンプル 一応例として以下のような定義を想定することとします。 index.ts import * as apigateway from '@aws-cdk/aws-apigateway'; import * as cdk from '@aws-cdk/core'; import * as lambda from '@aws-cdk/aws-lambda'; class MyStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string) { super(scope, id); const handler = new lambda.Function(this, 'Func', { runtime: lambda.

AWS CDK で特定の Secret ID を持つ Secret へのアクセス許可を与える

この記事は AWS その2 Advent Calendar 2020 の 2 日目の記事です。前回は @kazuhito1982 さんによる AWS CDK & Step FunctionsでInputPathを加工するです。 こんにちは。acomaguと申します。AWS その2 Advent Calendar では気が向いたら CDK の Tips をいくつか投稿しようかなと思っています。今回は Secrets Manager についてです。 CDK で Secrets Manager の値を扱うには secretsmanager.Secret コンストラクトを用います。 const secret = new secretsmanager.Secret(this, 'Secret'); secret.grantRead(lambdaFunc); 上記のように新しい Secret コンストラクトを定義すると、その値はランダムな文字列になります。値を指定することはできません。 この挙動は新しいパスワードを生成しなければならない場合には便利だと思うのですが、そのようなケースは実際には少なく、既に決まっているパスワードやトークンを Secret として扱うことのほうが多いかと思います。そのような場合、Secret は手動で(コンソール等から)作成し、Secret ID を CloudFormation(CDK) 上に記載するのが正攻法になるかと思います。 CDK では以下のようなコードになります。 const secret = secretsmanager.Secret.fromSecretNameV2(this, 'Secret1', 'MySecret'); // MySecret という ID の既存の Secret をインポート secret.grantRead(lambdaFunc); Secret.

[Go言語] お前の文字列引数のドキュメントは多分間違っている

これば Go2 Advent Calendar 2019 - Qiita の16日目の記事です。 この記事は会津大学 Zli BigLT2019 #biglt2019_aizu で発表した"UTF-8 依存の Go コードとは?“の内容をまとめ直したものです。 Go では文字列操作を比較的簡単に行うことができますが、実はその挙動をドキュメントするという作業は意外といろいろな落とし穴があり、気を遣う作業です。今回は「文字列を受け取る関数」を外部に公開するということを前提として、正しくドキュメントを書くための確認事項をまとめたいと思います。 string 型の文字コードって? 例えば func ToLower(s string) string という関数があったとき、s の文字コードは何でしょうか? 答えは「未定義」です。要するに 「string 型に入る文字コードは決まってないよ」 ということですね。 ドキュメントに明示的に書いてあります。 「必ずしも UTF-8 の文字列である必要はない」 builtin package · go.dev よって関数が string 型の文字列を受け取り、その挙動が文字コード依存の場合、ドキュメントには対応する文字コードを明示しなければならないと言えます。 もちろんこれは []byte や []rune にも同じことが言えます([]rune も UTF-8 限定の型ではありません)。 「UTF-8 依存のコード」とは何か 前項では「string 型の文字コードを明示する必要性」について話しましたが、最もありがちなミスは「引数が UTF-8 前提の関数なのに、ドキュメントにはそう書いていない」場合だと思います(そもそも他の文字コードに対応することを意識していれば、ドキュメントに書くのを忘れることもないでしょう)。 そこでここでは「どういうコードが UTF-8 依存なのか(非依存なのか)」を確認していこうと思います。 以下、例に出てくる変数 str → string 型 bts → []byte 型 rns → []rune 型 とします。

TS と Jest で Table Driven Test をする

この記事はTypeScript Advent Calendar 2019の11日目の記事です。 Go を齧ったことのある方は馴染み深いと思うのですが、Table Driven Testing という手法があります。いきなり見せます: const table = [ [1, 1, 2], [1, 2, 3], [2, 1, 3], ]; test.each(table)('.add(%i, %i)', (a, b, expected) => { expect(a + b).toBe(expected); }); こんな感じで「テストケースひとつひとつを test(...) 等と記述するのではなく、引数と予期する結果を配列として持っておいてテストコードの共通化を図る」手法です。同じ関数に関して書かなければならないテストケースが多い場合に、ごちゃごちゃしがちなテストコードをすっきりさせることができると思っています。 はてさてこれも Go 病なのか、自分はどうしてもこう書きたくなってしまいます。 const table = [ { name: '1+1', a: 1, b: 1, expected: 2, }, { name: '1+2', a: 1, b: 2, expected: 3 }, { name: '2+1', a: 2, b: 1, expected: 3, }, ]; // 動きません test.

makepkg-template で PKGBUILD の管理をちょっとだけ楽にする

これはAizu Advent Calendar 2019の 7 日目の記事です。 情報系の大学生にとって最も満足度が高い OS は Arch Linux だという結果が 2019 年全日本まちカドまぞく選手権大会で出ましたね(当まぞく比)。ちなみに私は Arch ではなく Manjaro Linux を使っていますごめんなさい。 そんな Arch 系 OS 使いにとって PKGBUILD の管理は大きな悩みの種なのではないでしょうか。いやまじでみんなどうしてるんだ。自分は基本的にジェネレートしたものやイチから書いたものをまとめて雑多に GitHub の(プライベート)リポジトリに放り込んでいたのですが、その方法だとそこまで大きな問題にもならないものの微妙に気持ち悪い点がいくつかありました。 ジェネレート/コピペしたコードを Git で管理することになる 稀にジェネレートしたコードを更に自分で編集する必要がある ジェネレートされたコードが汚くて読めない(それを Git に入れたくない) どのジェネレーター/バージョンで生成されたものなのか生成物(PKGBULID)を読んでも書いていない ジェネレーター/コピー元がバージョンアップしたら今までの生成物も一括でアップデートしたいがその方法がない などなどです。今回はそんな悩みを全ては解決できないのですが、多分ちょっとは解決できる方法をひとつご紹介します。 makepkg-template とは Arch なら標準で入っている1 PKGBUILD の生成ツールです。非常にシンプルな仕組みでテンプレートファイルから PKGBUILD の生成を行います。 例えば /usr/share/makepkg-template/gobin-1.template に pkgname=$_pkgname-git arch=('i686' 'x86_64') pkgver() { cd "$srcdir/$_pkgname" ( set -o pipefail git describe --long --tags 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' || printf "r%s.

「NOCOMMIT」アノテーションを活用してコミットミスを減らす

TODO や FIXME などのアノテーションコメント(もしくはコメントタグ)はみんなよく使ってると思いますが、自分は NOCOMMIT というものも使用します。 意味は単純で、コミットするべきでないデバッグ用のコードなどの行に書いておきます。 var SecretToken = "HARD_CODED" // NOCOMMIT TODO でも良いのですが、 TODO を単にデバッグ用の行などに付けると意図が伝わりづらい感覚があります。 TODO とだけ書いてあっても一瞬「なにをすべきなんだっけ?」となりますし、ちょっと頑張って TODO: delete って書いてあったとしても「何かを削除する処理を足さなければならないんだっけ?」と誤解する可能性があります(TODO: delete this line なら完璧ですが)。なので自分は NOCOMMIT のほうが性にあっていました。 これをコミット時に感知するGit HooksをGit Templateに追加しておけば、以降 clone/init するリポジトリに関してはいい感じになってくれます。 ~/.config/git/templates/hooks/pre-commit: #!/usr/bin/env bash if git diff --staged | grep NOCOMMIT >&2; then echo "The diff has NOCOMMIT line." >&2 exit 1 fi ~/.config/git/config: +[init] + templatedir = ~/.config/git/templates 余談ですが最近よく go.mod の replace ディレクティブに使っています。 require ( ... github.

[会津大学ハック] 学外からweb-intのホストネームでアクセスできるようにする

去年か一昨年あたりから学生はweb-int.u-aizu.ac.jpに学外からアクセス可能になったと思うのですが、そこから別のページにリンクを辿ると以下のような状態になることがあります。 web-int というホストネームを解決できません、というものですね。学内では web-int ホストにIPアドレスが割り当てられているのでアクセスできますが、学外からはもちろん無理です(web-int.u-aizu.ac.jp に書き換えなければなりません)。 毎回書き換えるのもだるいのでルートを追加しましょう。 echo -e '163.143.181.52\tweb-int' | sudo tee -a /etc/hosts いい感じです。 web-int.u-aizu.ac.jp のIPアドレスは自分は dig で調べました。 ところで疑問なんですがIPアドレスではなく web-int -> web-int.u-aizu.ac.jp というアクセス先の書き換え(つまり web-int.u-aizu.ac.jp のIPアドレスが将来的に変わっても大丈夫な方法)をするにはローカルでDNSを立てる以外にないんでしょうか。