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/-/.

「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 ( .

[会津大学ハック] 学外から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を立てる以外にないんでしょうか。

アカツキインターンに行ってきて考えたこと

株式会社アカツキさんにてありがたいことにインターンをさせていただきました。 きっかけ したこと Go1.11.4対応/調査 多段カナリアリリース カナリアリリース中に特定のAPIが叩かれたかどうかレポートするシステム(Ensurerun) 技術的に学んだこと 痛感した自分の弱み 遅い 進捗報告 質問が下手 そのほかいろいろ思ったこと/得たこと インターン生という感覚が薄かった 固くない 「どれだけちゃんとやるのか」の感覚を学んでいきたい 結局何を学んだの? まとめ きっかけ 直接的なきっかけとしては Supporterz の 1on1 で人事の方とお話させていただいたことです。 ただそれまでにも、大学のZliサークルで開催した企業さんとの合同LT会や、前の年の1on1イベントなどで何度かお話させていただいたこともあり採用に力を入れている企業さんだなという認識はありました。ただゲーム系の企業は今のところどこもRails/Unityの人材を探している印象が強く、あまり興味を持って話を聞いたことがありませんでした。 しかし去年の夏にnatumnくんがアカツキのATLASチームというところでインターンをした話を聞き、「なんだかGoでゲーム基盤を開発しているらしい」「とても働きやすい環境らしい」という印象を持ちました。 そこで1on1で人事の花田さんとお話した際にインターンをお願いし、2月の12日から3月1日まで受け入れていただくことになりました。 したこと 配属していただいたのはnatumnくんと同じATLASチームです。 主に課金基盤アプリケーションのカナリアリリース周りを触っていました。 Go1.11.4対応/調査 やっていた期間: 2 / 12 - 2 / 13 これはもともとIssueとしてあったタスクではなく、環境構築中に手元でアプリケーションのビルドができなかったことからIssueを作ったものです。 エラー内容からどうやらいくつかのダウンロードしたGoのモジュールがgo.sumに記述されたチェックサムに適合していない、というもののようでした。 go: verifying github.com/aktsk/nolmandy@v0.1.2: checksum mismatch go.sumを削除すれば正常にビルドできることから、該当のモジュールにForce Pushやタグの付け替えがありチェックサムが変更された可能性をまず考えましたが、そのような心当たりはないという話を聞き、頭をひねっていたところ cmd/go: symbolic links not dropped from repo [1.11 backport] · Issue #29191 · golang/go

雑にワンライナーのシェルスクリプトをHTTPサーバーとしてデプロイする

[追記] 執筆後にGAE-FEがGCEと同様の値段がかかる&&最小インスタンス数が1以上であることから無茶苦茶お金がかかることに気づいたため、この記事はなかったことになりました。 以下本文 自分はシェルスクリプトが好きなので、いろいろなことをシェルスクリプトでやるのですが、たまにシェルスクリプトがHTTPサーバーであってほしいときがあります。 話は変わって最近AtCoderをやろうかなと思っているのですが、AtCoderにはABC、AGC、ARCの3種類の定期開催のコンテストがあります(参考: AtCoder Grand Contest (AGC) について:suda_k0のブロマガ - ブロマガ)。しばらくABCに参加しようかなと考え、公式のGoogle Calendarを見ると、 ABC以外も混ざっている!! ABC(AtCoder Beginner Contest)の予定は表示しておきたいけど、他のAGC(AtCoder Grand Contest)などの参加する予定のないものは表示しておきたくないのでどうにかフィルタしたいところです。 ところでGoogleカレンダーのカレンダーはiCal形式でインポート/エクスポートできます。自分はiCal形式を前に少し触ったことがあったので、シェルスクリプトでフィルタをしてみようと思いやってみたのが以下です。 curl https://calendar.google.com/calendar/ical/atcoder.jp_gqd1dqpjbld3mhfm4q07e4rops%40group.calendar.google.com/public/basic.ics \ | sed -e '/BEGIN:VEVENT/{:l N; /END:VEVENT/!bl; /\(Beginner\|ABC\)/!d;}' 1行目のcurlで取ってきているURLが先の画像でお見せしたAtCoder公式のカレンダーのiCalです。これをsedでいい感じに”Beginner”や”ABC”を含むものだけにフィルタします。雑いですが個人用なのでこれで十分です。 これで現時点でのABCのみのカレンダーを作ることができましたが、今後も自動的にアップデートしてほしいものです。このシェルスクリプトにURLを与えて、URLが叩かれるたびに新しいカレンダーが出力されるようになれば完璧なのに… ここまでが前置きです。 やりたいこと HTTPサーバーを立っている リクエストが来るとシェルスクリプトが実行され、標準出力がレスポンスで返される これをできるだけ楽に作りたい。 検討したサービス 一番に思いつく方法はEC2やGCEなどのインスタンスをまるごと借りるタイプのものですが、お金のない学生なので選択肢に挙がりません。 次にAWS Lambdaでシェルスクリプトが動く、みたいな話があったのを思い出しましたが、個人のプロジェクトはGCPで統一しているので管理コストなども考え今回は除外させていただきました… すみません(AWSに慣れている方は一番の選択肢になるかもしれないです)。 同様にGoogle Cloud FunctionsやFirebase Functionsでシェルスクリプトが動いてほしいという希望を持ちましたが、残念ながら対応していないようでした。 そして今回採用したのがGoogle App Engine(GAE) Flexible Environment(FE)です。FEは使ったことがなかったのでどれだけ楽にできるのか不安なところがありましたが、慣れればまあそこそこ頭を使わずにできそうな感じだったので紹介します。 GAE-FEでシェルスクリプトを実行するHTTPサーバーを立てる シェルスクリプトの公式のランタイムはありませんので、カスタムランタイムとしてDockerイメージをデプロイすることにします。というわけでまずHTTPサーバーとシェルスクリプトを含むDockerfileを書きます。 FROMalpineRUN apk add sed bash curl coreutils busybox-extrasCOPY index.cgi /www/cgi-bin/index.cgiRUN chmod 700 /www/cgi-bin/index.cgiCMD httpd -h/www -p$PORT -f サーバーにはBusybox httpdを使用しました。BusyboxがもともとAlpineに入っていた(といいつつ busybox-extras を別途入れる必要があります)のと、そこそこ楽そうだったからです。あとsedやcoreutilsを入れているのはGNUのコマンドが使いたかったからです。シェルスクリプトに必要なコマンド類はこれらに加えてfindとか入れておけばだいたいのスクリプトで足りるイメージがあります。

VSCodeの見た目をシンプルにする

自分はほとんど使わなかったり要らないUIが目障りなのが嫌いなので、少しだけカラースキーマを書いてこんな感じにしてみました。 "workbench.colorCustomizations": { "widget.shadow": "#0c0c0c", "statusBar.background": "#111", "statusBar.foreground": "#555", "statusBar.debuggingBackground": "#111", "statusBar.noFolderBackground": "#111", "panel.background": "#111", "sideBar.background": "#111", "activityBar.background": "#111", "activityBar.foreground": "#555", "activityBarBadge.background": "#555", "activityBarBadge.foreground": "#111", "editor.background": "#111", "editorOverviewRuler.border": "#555", "editorGroupHeader.noTabsBackground": "#111", "editorGroupHeader.tabsBackground": "#111", "editorGroup.border": "#111", "editorLineNumber.foreground": "#555", "editorLineNumber.activeForeground": "#555", "tab.border": "#111", "tab.activeBackground": "#111", "tab.activeForeground": "#aaa", "tab.activeModifiedBorder": "#444", "tab.activeBorderTop": "#333", "tab.inactiveBackground": "#111", "tab.inactiveForeground": "#444", "tab.inactiveModifiedBorder": "#333", "scrollbar.shadow": "#0c0c0c", "scrollbarSlider.background": "#333" }, "editor.overviewRulerBorder": false ただそもそも要らないものは表示しなければ目障りにならないので、Activity Bar(左のやつ)とMinimapは結局非表示にしてしまいました。 一瞬Theme拡張として公開しようかと思いましたが、Themeにはシンタックスハイライトの設定も含めなければならないということでやめました。自分のsettings.jsonに書いておけば好きなほかのTheme拡張と組み合わせられるので。

[Linux] VSCodeでGlobal Menuを有効にする

KDEやGnomeにはGlobal Menuという概念があり、アプリケーションのAltキーでフォーカスされるようなよくあるメニューバーをアプリケーションウィンドウの中ではなくその他の好きなところに(設定次第で)置くことができます。Macのメニューバーに似てますね。 ↑アプリケーションの中にある通常のメニューバー。自分は普段はこうではなく、Global Menuを使用して画面の左上にマウスHoverしたときのみ表示されるようにしています。 しかしVSCodeのメニューバーをこのように表示することができていませんでした。クロスプラットフォームのアプリケーションでは対応していないことが多い1ので、諦めてAltキーでトグルする設定にしていたのですが、 たまたまこちらのStack Overflowを見てVSCodeをGlobal Menuに対応させることができてしまいました。 [Linux] KDE’s menubar button does not work · Issue #34510 · Microsoft/vscode 自分はArch系のディストリなので、以下でうまく行きました。 $ yay libdbusmenu-glib libdbusmenu-glib というものが何なのか気になりますが、とりあえず今日はここまで。 おそらくQtやGTKを適切に使用してメニューバーを実装しないとGlobal Menuとして扱えないのでは無いかと思っています。 [return]

TRPGキャラクターシートの管理のこれから

この記事はTRPG なんでも Advent Calendar 2018の24日目の記事です。 こんにちは。まだまだTRPG初心者(クトゥルフPL2回、アマデウスPL1回)の@acomaguと申します。プログラミングをたまにします。 今回はキャラクターシート置き場についての話をします。自分はクトゥルフTRPGのキャラクターシートをキャラクター保管所さんで管理しているのですが、キャラクターシートを保存できるサイトは他にもいくつかあります。 TRPGキャラクターシートアーカイブスさん とらぷぐ.comさん オンセンSNSさん …などなど。(クトゥルフ以外だとまたいろいろあるみたいですね) まあ言うほど無いんですが、それでも選択肢があります。ただ、ほとんどの方は自分と同じくキャラクター保管所さんを使っているような気がしています(あくまで自分の観測範囲ですが)。理由を考えると、いろんなサイトで推奨されているとか、数多くのTRPGに対応している、技能値の割り振りがしやすいなどがあると思います。 自分もそこそこ満足していたのですが、何度かアクセスするうちに不満点も見えてきました。「連携できるツールが少ない」ことです。 チャパレさんなど一部のツールはキャラクター保管所さんからの読み込みに対応していますし、キャラクター保管所さんのほうではどどんとふ連携に対応しているのですが、他のほとんどのオンセツールなどでは自分で能力値と技能値を手入力する必要があります。また、クトゥルフWebダイスさんのようなキャラクター作成ツールからの読み込みにも対応していません。このあたりの連携ができるサービスが見つからないのは、キャラクター保管所さんがキャラシートに書き込むためのAPIを提供していないことが原因と考えられます。 「ダイスを振る → キャラクターシートに保存する → オンセツールに表示する」までを一度も手入力することなくやりたかったのです。 このあたりのしんどさを解決しようと以下のようなツールを作ってみたりもしました。 acomagu/cstoml: TRPGキャラクター保管所 -> TOML キャラシートをパースしやすく人間も読み取りやすいTOMLに変換し、GitHubで管理しようという発想でした。しかし例えば能力値が変更された際にオンセツールが自動でGitHubにコミットを投げるというのも考えづらく、連携のしやすさという点ではこちらも貧弱なものでした。 また、単にキャラクターシートのデータを取得/更新できるだけではなく、リアルタイム性も担保したいと考えていました。というのも今後GMをやる上で、PL全員の能力値の現在値をまとめて閲覧できるビュワーがほしいと考えていたからです。単なる保存場所としてのWebサイトとは一線を画したものが必要でした。 そこまで考えて、私は Solid が解決策になるのではと気づきました。 Solidとは ちょっと一言で表すのが難しいのですが、もし無理やりその一言を選ぶのならばやはり「データをユーザの手に取り戻す」でしょうか。 仕組みを大まかに説明すると、ユーザーはサービス提供企業それぞれに個人情報を提供するのではなく「Solid POD」と呼ばれる保管場所(クラウドあるいは自分のサーバ)上に情報を保存し、Solid上のサービスを使う際、どの情報をサービス側に提供するかを選択する。これにより、ユーザーが自分の情報を管理しやすくなるだけでなく、サービスを利用した際に生じる個人データもアプリと分離されてPODに保存されるので、サービス側も大量のデータを収集する必要がないという(Solid Explainedページより)。 気になったエンジニアの方はぜひ公式サイトのMake a Solid app on your lunch breakをやってみてほしいのですが、結構面白いです。 以上のような特徴により、Solidは今までWebアプリケーションの背後にあったユーザのデータを、別の場所(=POD)に切り離して管理できるようにします。 そしてこのSolidを単なる理想論から現実に近づける特徴が「標準化された技術でできている」ことです。 Solidは大雑把に言って2つの標準を使用しています。まず1つがWebIDです。ユーザは自由にPODを乗り換えることができますが、ユーザがPODを変えてもユーザのデータのURLは変えない仕組みと言えます。1 そしてもう1つがRDFです。これはアプリケーション間のデータの形式の差異の最小限にするためのものです。GoogleカレンダーがPODに正しく予定を保存してくれていれば、その情報がYahoo! カレンダーでもそのまま開けるということですね。 なるほど… ではこのSolidをTRPGのキャラクターシート置き場に利用すると、何が起こるのでしょうか。 キャラクターシートをSolid PODに保存すると何が起こるか 「キャラクターシート置き場にSolidを利用する」ということは「キャラクターシートをSolid PODに保存する」ことを意味します。 こうすることで何がどうなるのか、もしすべてのサービスがSolidに対応していたと仮定して、使い方をシュミレートしてみたいと思います。 まず、ユーザはキャラクターシートを作成するために「クトゥルフWebダイス」さんのようなサイトでダイスを振り、能力値を決めます。ついでに技能値やキャラクター名も決めたところで保存ボタンを押すと、Solid PODに保存されます。 ユーザはそのまま好きなオンセサイトに移動すると「PODに保存されたキャラクターシート一覧」が更新され、先程作ったものが選べるようになっています。 こんな感じです。書き込みも読み取りも、初回はWebIDの入力と権限の確認があるでしょう。 データとアプリケーションが粗結合になったことでそれぞれのサービスの相互の対応の可否を気にする必要がなくなりましたし、開発者としてもSolidのみに対応することでよくなりました。 また今までは、例えばオンセなどでは「外部サービスからのインポート」と「自サービスのDBからの読み出し」を別の機能として実装していたのが、「Solidからの読み出し/保存」に統一されることで開発の負担も減ることが予想されます2。 更にSolidはリアルタイム更新対応です3。

git push origin masterを絶対に手打ちしないために

この記事はAizu Advent Calendar 2018の10日目の記事です。 雰囲気でシェルをやっているクソザコです。 $ git push fatal: The current branch master has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin master 初回にgit pushを打つとこのようなエラーが出ますよね。このメッセージどおり git push --set-upstream origin master と打てば二回以降は origin/master をデフォルトとして扱ってくれます。 が、Gitの言うがままにタイプしていては、リーナス・トーバルズに負けたということになってしまいます。 そこで自分はこんな感じにプロンプトを出すようにして今の所満足しています。 —追記— git push origin HEADでローカルブランチと同じ名前のリモートブランチにpushできるよ! -uのときも使える — そな太@Swift始めました (@sonatard) December 21, 2018 まじで!? と思ってドキュメントを確認したら本当に書いてあった。 なんというか、HEADはローカルのリビジョンを指すときのみに使用できるイメージがあったので、これには驚きだった。 ちゃんとこんなふうに書いても動く。 git push origin HEAD:HEAD ちなみにちなみにHEADの内容をそのまま展開しても動く。