Diary of a Perpetual Student

Perpetual Student: A person who remains at university far beyond the normal period

Jest で落ちたアサーションを GitHub のアノテーションに出す

最近 GitHub Actions を弄くり倒すことにハマっていて、 GitHub の Checks API を利用して annotation を出すおもてなしをすることだけが生きがいだと思って生活していました。

そんな中、JavaScript (TypeScript) のコードのテストでよく使われている Jest で、どの assertion が落ちているかを annotation で分かりやすく表示したいと思っていました。自作で頑張ろうかな~と思って調べていると、 Jest 28.0.0 (2022年4月末ごろリリース)から Github Actions で annotation を出す reporter 機能が組み込まれていたという事実を知りました。

jestjs.io

この便利機能が思ったより世の中で使われていない感じがしたので紹介します。

サンプル

こちらをどうぞ:

github.com

CI で動かしているテストが落ちたとき、アサーションを満たしていないところを以下のように表示してくれます。

fail test sample by Arthur1 · Pull Request #1 · Arthur1/jest-github-actions-report-sample · GitHub

やり方

本当に簡単です。

  1. jest を v28.0.0 以上にアップデートする
  2. jest.config.js に 以下のような編集を加える
  3. GitHub Actions 上で jest を実行する(オプションなどは不要)
/** @type {import('jest').Config} */
const config = {
  testEnvironment: "node",
  roots: ["<rootDir>/src"],
  testMatch: [
    "**/__tests__/**/*.+(ts|tsx|js)",
    "**/?(*.)+(spec|test).+(ts|tsx|js)",
  ],
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  reporters: ["default", "github-actions"], // <- この行を足す
};

module.exports = config;

ドキュメントのリンクも残しておきます。

jestjs.io

感想

最近の GitHub は PR の差分外についた annotation も表示する(ベータ版機能)ので、落ちているテストを放置する運用をしていると annotation だらけになって厳しいかもしれません。まあそんな形骸化したテストを CI で動かす必要はないでしょうし、これが問題になることはないでしょう。

(というより、これができないと、テストコードを編集していない時にが落ちるとアノテーションが出なくなってしまう。ベータ版じゃなくなると良いですね。)

(そしてガッツリ TDD している場合はどうなるんだろう。)

あと assertion と annotation の区別は寝起きの IQ1 の頭脳にはつらいですね。

(2022/9/9 追記) テストコードに差分がないのにテストが落ちた時にどう表示されるか

PR の差分外のコードに annotation を出す機能もせっかくなので紹介しておきたく、例を用意しました。

fail test sample (without test code diff) by Arthur1 · Pull Request #2 · Arthur1/jest-github-actions-report-sample · GitHub

個人開発をクラウドシフトすることにした〜Github Actions 用の IAM ロールを作る〜

個人開発用に VPS を借り始めてもう7年近くになる。これまでにボードゲーム関連で作ったサービスは基本的に VPS 1台に全部載せて運用している。コンテナすら利用していないので、PHPMySQL のバージョンを上げるだけで一苦労だ。

日々の運用が toil になってしまって放置気味なこと、得た知見を業務にそのまま生かすのが難しいことから、今後作るものは Amazon Web ServicesGoogle Cloud などのクラウドサービス上に構築することに決めた。社会人になって資金面の余裕が生まれたという理由もある。

同人活動に近いということもあり収益化はほぼできておらず、普段から赤字を垂れ流しているわけだが、やはり自ら手を動かして得た知見に勝るものはないだろう。これは勉強代ということにしておく。

そして、VPSAmazon EC2 に変えても、勉強としては何の意味もないだろう、ということで、マネージドなサービスにちゃんと寄せていくことにする。とはいえ、個人開発レベルで Amazon RDS や Amazon ElastiCache を使うのはコストに見合うメリットが得られないのは明らかだ。この辺り、どう折り合いをつけていくかは今後の課題とする。

クラウドシフトプロジェクトの手始めに、Github Actions 上で動かす Visual Regression Test の結果を Amazon S3 にアップロードする仕組みを作る作業に取り掛かった。完成品は以下のような感じで、Github の Checks API を利用して良い感じに表示できるようにしてみた。

まずは、Github Actions のコンテナから画像を S3 にアップロードするのに必要な IAM ロールを作ることにした。慣れない Terraform を黙々と書いていった。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region  = "ap-northeast-1"
  profile = "AgricolaDevJP-admin"
}

// ref: https://zenn.dev/yukin01/articles/github-actions-oidc-provider-terraform
data "http" "github_oidc_configuration" {
  url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration"
}

data "tls_certificate" "github_oidc" {
  url = jsondecode(data.http.github_oidc_configuration.response_body).jwks_uri
}

resource "aws_iam_openid_connect_provider" "github_oidc" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = data.tls_certificate.github_oidc.certificates[*].sha1_fingerprint
}

resource "aws_s3_bucket" "agricola_card_image_generator_snapshot_bucket" {
  bucket        = "agricola-card-image-generator-snapshot"
  force_destroy = true
}

resource "aws_s3_bucket_public_access_block" "agricola_card_image_generator_snapshot_bucket" {
  bucket                  = aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.id
  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

resource "aws_s3_bucket_versioning" "agricola_card_image_generator_snapshot_bucket" {
  bucket = aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.id
  versioning_configuration {
    status = "Disabled"
  }
}

resource "aws_s3_bucket_policy" "agricola_card_image_generator_snapshot_bucket" {
  bucket = aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.id
  policy = data.aws_iam_policy_document.agricola_card_image_generator_snapshot_bucket_public_access_policy.json
}

data "aws_iam_policy_document" "agricola_card_image_generator_snapshot_bucket_public_access_policy" {
  statement {
    principals {
      type        = "*"
      identifiers = ["*"]
    }
    actions = [
      "s3:GetObject"
    ]
    resources = [
      "${aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.arn}/*"
    ]
  }
}

resource "aws_iam_role" "agricola_card_image_generator_snapshot_github_actions_role" {
  name               = "agricola-card-image-generator-github-actions-role"
  assume_role_policy = data.aws_iam_policy_document.agricola_card_image_generator_snapshot_github_actions_role_policy.json
}

data "aws_iam_policy_document" "agricola_card_image_generator_snapshot_github_actions_role_policy" {
  statement {
    effect = "Allow"
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github_oidc.arn]
    }
    actions = [
      "sts:AssumeRoleWithWebIdentity"
    ]
    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values = [
        "repo:AgricolaDevJP/agricola-card-image-generator:*"
      ]
    }
  }
}

resource "aws_iam_role_policy" "agricola_card_image_generator_snapshot_bucket_put_policy" {
  name   = "agricola-card-image-generator-snapshot-bucket-put-policy"
  role   = aws_iam_role.agricola_card_image_generator_snapshot_github_actions_role.id
  policy = data.aws_iam_policy_document.agricola_card_image_generator_snapshot_bucket_put_policy.json
}

data "aws_iam_policy_document" "agricola_card_image_generator_snapshot_bucket_put_policy" {
  statement {
    effect = "Allow"
    actions = [
      "s3:PutObject"
    ]
    resources = [
      "${aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.arn}/*"
    ]
  }
}

ググっても credential を環境変数に埋め込む方法ばかり出てくるが、セキュリティ上の問題から定期的なローテートが必要で面倒だ。そこで、GitHubAWS アカウントから、こちら側が用意したロールに Assume Role するようにしてみた。

zenn.dev

上記の記事を参考に、thumbprint を直書きしないようにしたのもポイントである。

AWS を扱う上では避けたくても避けられない IAM と仲良くなるための第一歩としてちょうど良いスタートになったと思う。

周囲の iPhone ユーザに迷惑をかけまくっていた話

僕は Apple 信者ではないのに、どういうわけか Apple 製品に囲まれて暮らしている。 M1max の Macbook Pro に Magic Trackpad と Magic Keyboard を繋いで仕事をし、 iPad Air で動画を見ている。 そして、財布には AirTag をつけている。

この AirTag は発売日に即ポチしたのだが、 iPhone を常に持ち歩いている人にしかあまり恩恵がないということを知らずに購入してしまった。 AirTag はインターネットに直接繋がっていなくても、日本に数多と存在する iPhone 総出の力で探し物の場所を特定することができるという優れ物である。 しかし、その仕組み上、自分が iPhone を持っていないと持ち物を所有者自身が持っているという判定ができないのだ。

そして、僕は iPhone を持っていない。 おサイフケータイを昔から使ってきた関係でスマートフォンAndroid 製品を選んでおり、今更変える気もないからだ。

そのため、一応手元の iPad と紐付けはしておいたものの、大きな iPad を普段持ち運ぶことはないため、たまに音が鳴る*1高級ストラップとして運用していた。

使用し始めて15か月が経つ頃には、 iPad に「AirTag の電池がバッテリー残量が少なくなっています」という通知が来ていた。しかし、忘れ物タグとしては使っていないので通知を放置していた。これが事件の引き金となる。

一緒にドライブをしていた友人が、「変な通知が何度も来るんだが」と言ってきた。iPhone の画面を覗き込むと、画面下部に見覚えのあるこんな通知が出ている。

そうだ、これは AirTag を初期設定するときの画面である。電池が切れかかっていたからか、AirTag が初期化されてしまったようだ。 そして、残っていたわずかな電力を使って、周りの iPhone ユーザに母をたずねて三千里していたということらしい。

時代遅れの Lightning 端子を備えた iPhone アンチの僕としてはいい気味だったかもしれない。 しかし、これで第三者に AirTag を登録されたら、自分の居場所が追跡されてしまう可能性もあって笑い事ではなくなってしまう。

「AirTag くんごめん……すぐ楽にしてやるからな」

そう言って僕は AirTag の電池を抜いた。

今日の教訓

AirTag を高級ストラップとして運用している人はボタン電池を外しましょう。

*1:AirTag は、持ち主の元をしばらく離れていると、防犯のために音が鳴る

フロクロさんを語る:マルチタレントとオープンネス

今日はとあるアーティストについての話をします。先日のエントリで1楽曲だけ取り上げた、フロクロ(Frog96)さんです。

音楽制作者としての自分、ソフトウェアエンジニアとしての自分、両方の目線で強く惹かれるところがあったので、ぜひ紹介させてください。

楽曲紹介

映像も素晴らしくて、楽曲というより作品と言った方が良いのかもしれない……

ロスト・デリュージョン

www.youtube.com

ディスプレイスメントマップを利用した MV が見ていて気持ちが良いというか中毒性があります。メディアアート

空を満たして

www.youtube.com

サビの、かすかに聞こえるハット以外はほぼフィルインだけで構成されたドラムフレーズ(たぶん名称があるんだろうけど分からない)をはじめとして、全体的に緊張感を覚えるサウンドです。 ラスサビ直後の映像演出が最高にゾクゾクして好きです。

黒塗り世界宛て書簡

www.youtube.com

リズミカルにビープ音が鳴っているのが印象的ですが、調の主音とビープ音が同じ高さなので、調和していて鬱陶しくない感じがあります。そして何より歌詞とビープ音に隠されたギミックがすごい。

input と output がすごい

フロクロさんはScrapbox に制作物のメイキングや有益情報などをまとめています。これが本当に興味深いのです。

scrapbox.io

フロクロさんの作品の特徴として、作詞、作曲、MVの制作すべて一人で担当されているという点があります。それぞれどういった手法で作ったのかが事細かに公開されていて、勉強になります。

例えば、先ほど紹介した「ロスト・デリュージョン」の音楽メイキング記事では、インスピレーションを受けた楽曲やコード進行、使用しているVSTプラグインまで動画つきで丁寧に説明されています。自分が感覚的に好きだと思った作品が、どのよう過程で、どんな要素を用いて構成されたのかを知ることができるのは面白いというほかありません。

scrapbox.io

これら様々な記事を読んで、 output と input の質は互いに関係があるということを改めて実感しました。音楽にしても映像にしてもその他にしても、思考が圧倒的な知識に裏付けられているように感じられます。

僕は仕事として、コードやその設計思想を Pull Request という形で表現したり、エンジニアリングに関する学びを他者に共有したりしています。そして、それらアウトプットの質・量が自分の働きぶりを評価する指標の一つとなっています。

分野は違えど、ソフトウェアエンジニアとして生きていく上でフロクロさんの姿勢が手本になると思いました。僕も、自分の思考をもっと言語化していきたいし、良い思考をするために自分の知識の幅を広げていきたいです。そして、同じような人が同僚にもいるなあ。

まとめ

色々小難しいことを語りましたが、言いたいことはこれだけ。良いアーティストだから聞いてくれ!!!!!

www.youtube.com

アグリコラ:泥沼からの出発 リバイズドエディション の誤訳指摘

遅くなってしまいましたが、 アグリコラ:泥沼からの出発 リバイズドエディション(日本語版)を開封しましたので、誤訳の指摘や補足情報の提示をします。ゆっくりやればよいと思っていたのですが、お盆休みで多くのプレイヤーが泥沼で遊んでいそうなのを観測したので取り組みました。

hobbyjapan.games

id:arthur-1 は2018年夏に海外で先行販売されたドイツ語プレプリント版を所有しており、そちらを訳したものとの比較になります。現時点ではエラッタが入っており、日本語版に反映されたカードもあるかもしれませんが把握はしていません。

なお、それとは関係なくこちらの情報も間違っているかも知れないので、間違いあれば指摘してください。

本記事はメンテナンス終了しました

公式の訂正情報が出たようなので、基本的には本記事のメンテナンスを終了します。以下を参照してください。

hobbyjapan.co.jp

[M125] 資材倉庫 など、私が気づいていなかったものも掲載されていましたので、ぜひご確認ください。

(逆に言うと、こちらでは指摘していますが掲載されていないものもありました。)

更新情報

  • 2022-10-14 15:20 公式の正誤表が公開された情報を追加
  • 2022-08-22 13:00 [M068] 教会のアイコン誤記に関する情報を追加
  • 2022-08-12 10:45 [M006] 高熱窯、 [M007] タイル窯は窯である旨に訂正

ルールブック

軽く目を通しましたがドイツ語版との致命的な差異はなかったと思います。強いて言えば、「つい最近まで、泥炭を掘るというということは…」という文章がありますが、つい最近なんてことはなくて、前世紀ぐらいかな〜と思いました。

カード

[M006] 高熱窯

  • 日本語版のカード名に窯と書いてあるが、ドイツ語版・英語版を見る限りは窯ではない
    • 例えば、[C075] 薪 のような、窯を参照するカードの対象にはならない
  • 2022-08-12 追記) こちらのミスで、窯としての扱いで問題ないです
    • 旧版のカード名と同じだと思っていたら変わっていた
    • そもそもルールブックに Brenn- und Heizofen gelten entsprechend ihrem Namen als Öfen. って書いてあった

[M007] タイル窯

  • [M006] 高熱窯と同様に窯ではない
  • 2022-08-12 追記) こちらのミスで、窯としての扱いで問題ないです

[M022] ビオトープ

  • 「自分だけ小麦 そして/または 野菜を植えていれば食料1を得る」のそして/またはの使い方がよく分からない。小麦を植えていれば食料1、野菜を植えていれば食料1の意味が正解
    • 両方達成していれば食料2もらえる
  • 「森タイル そして/または 泥地タイル」のところも同様に、森タイル最多なら食料1、泥地タイル最多なら食料1
  • さらに、森タイル/泥地タイルのカウントについては、単独で最多である必要がある。誰かとタイならもらえない

[M023] 森のはずれ

  • (補足) 柵のスペースとは、タイルとタイルの間にある柵を置ける空間のことを指す。
    • 隣接している、という表現が若干わかりにくいが、タイルとタイルの間にある柵置き場の数を数えてね、と言う意味

[M031] 有用動物市場

  • 前提の「動物5」は「家畜5」

[M032] 泥炭塀の小屋

  • 食糧供給フェイズ -> 食料供給フェイズ

[M039] 特別牧場

  • 「柵で囲んだスペースは、タイルがなくなると牧場になる。」の一文が丸々不要。[M038] 自然保護区域の文章からコピーしてきたのだろう

[M044] 沼地化

  • 沼地タイル -> 泥地タイル

[M049] 不動産地図

  • 前提の「2ラウンド以前に出す」は「ラウンド2以前に出す」の意味

[M055] 道具小屋

  • 『 特別アクション「焼畑」または「泥炭を掘る」を行う前か後、すぐにもう1つの特別アクションも実行できる』とあるが、もう1つのとは同じカードに描かれているはずの2つのアクションのもう一方という意味である
    • 焼畑」と「労働市場」を同時に、と言う芸当ができるわけではない
    • 「もう一方の」という言葉を使うとこのニュアンスが表現できているかもしれない

[M065] 消防署

  • 森タイル5枚以上であればボーナス4点得られる
    • 日本語版のテキストでもそう解釈できはするのだが、すぐ後ろの[M066] 耕作区画のテキストのように「2/3/4/5枚以上 ある場合」、とした方が分かりやすいのではないだろうか

[M066] 耕作区画

  • 注釈として(未使用スペースによるマイナス点に追加される。)とあるが、未使用スペースのマイナス点は変わらずあるよ、という意味
    • このカードで得られる点はボーナス点扱いのまま

[M068] 教会

  • ※誤訳ではないし、日本語版の問題でもない
  • 左下に「泥炭を掘る」マークが描かれているが、カード効果的に不要と思われる
    • 独語版でも同様に印刷されていたので、言語に依存しないミスだろう

[M069] 革の鞍

  • 「馬が3以上になるたび」というよりは「馬が3以上ならば」の方がわかりやすいだろう

[M070] 泥炭考古学

  • 「空いた農場スペース」というのは、ただの未使用スペースということではない。「泥炭を掘る」を行ったことによってちょうど今空いたスペースを指している

[M073] 繁殖手当

  • 旧版の日本語版で勝利点という表記が確かにあったような気もするが、ボーナス点に統一したい
  • 独語版では(以降同様)とは書かれていない。最大でも3倍までしかボーナス点はもらえないと思う

[M074] 管理部門

  • 前提の「手札の進歩* 4枚以上」は「4枚以下」の間違い
    • 旧版の泥沼拡張も同じ誤訳があった

[M078] 小舟

  • 燃料1と木材1を交互に置くのではなく、燃料1と食料1を交互に置く
    • そして、(先に木材1を置く)とあるが、燃料から置くのが正解

[M081] 泥炭船

  • (ここから、建設資材1種類だけを得ることはできない。)という注釈は間違い。建設資材1つだけを得ることができない、が正しい。
    • 燃料2で葦1を買うのはダメだよ、という意図の注釈

[M084] 炭坑場

  • ルール上問題はないが、カード名は炭坑場ではなく炭坑馬の方が適切だと思う

[M092] 乾燥地

  • 「空の農場スペース」とあるが、[M070] 泥炭考古学 での指摘同様に、「泥炭を掘る」を行ったことによってちょうど今空いたスペースを指している

[M096] 休閑地

  • [M070] 泥炭考古学・[M092] 乾燥地 での指摘同様に、「空いている農場スペースに食料1ずつ置く」のではなく、特別アクションによってちょうど今空いたスペース1か所に食料1を置く
    • 先に挙げた2つは正しく解釈できなくもないが、こちらは「食料1ずつ」と書かれており明らかに誤訳

[M099] 泥薬

  • 『人物がベッドに横たわっている「病院」のアクションスペースを使うたび』という表現は不適切。ベッドに寝ている主体は病院ではなく人物であり、「ベッドに横たわっている人物が」とするのがよさそう

[M101] 肉処理台

  • 4、7、9、11、13、14ラウンド -> ラウンド4、7、9、11、13、14

以上です。良い泥沼ライフを!

ダークモードをおまけ感覚で提供するのは厳しい

スマートフォンを先日発売された Google Pixel 6a に乗り換えました。 もともとは Pixel 3a を利用していたのですが、セキュリティアップデートの提供保証が切れたことが買い替えの主な理由です。

store.google.com

機種変更に伴って、ワンタイムパスワードを用いた2要素認証の設定をし直しました。

GitHub の Web 上で表示された2次元コードをスキャンしたのですが、なぜか読み込むことができませんでした。

2次元コードはダミーです

原因はダークモードなのに2次元コードの周囲に白い余白が十分用意されていなかったことでした。 試しに、開発者ツールからスタイルを変更して、以下のように余白を白くすると読み込むことができました。

.qr-code-img {
  background: white !important;
}

近年は、CSS でカスタムプロパティが使えるようになり、変数の値をまとめて変えるだけでフロントエンドのデザインテーマを切り替えられるようになりました。 しかし、ライトなテーマの延長として色を変えるだけで実装すると、このように操作性の悪い UI が生まれてしまうことがあります。

今回の件以外にも、プロパティの設定値によってコントラストの差が小さくなり、視認性が悪くなるという問題が起こることも考えられます。

実装コストとの兼ね合いを考えると気づきベースでなんとかしていくしかないような気もします。しかし、ダークモードが市民権を得た今、アクセシビリティテストを CI で動かすなどの手法(思いつきです、できるかどうかは分からない)により、ダークモードを安心して世に出せる仕組みが整備されたいと思いました。

株式会社はてなに入社しました(本物)

株式会社はてなに入社しました

株式会社はてなに入社しました - hitode909の日記


といういつものやつではなくて、これは本当の入社エントリ(にしては遅すぎないか?)です。

株式会社はてなにWebアプリケーションエンジニアとして入社して4か月が経とうとしています。 はじめての査定結果が通知され会計年度が終わろうとしているこのタイミングで振り返っていきます。

自己紹介

id:arthur-1 です。お理工だけじゃダメなんだ大学の学部に7年間通った後に、はてなに新卒入社しました。 3留なのでどこにも雇ってもらえないと思っていたけどなんとかなりました。

学生時代は学園祭実行委員会で参加団体向けの Web 申請システムやお客さん向けの優良企画投票システムを作ったり、ボードゲームに関する Web サービスを個人開発・運用したりしていました。

db.buratsuki.page

neo.buratsuki.page

また、専攻はコンピュータサイエンスだったのですが、研究では比較的得意だったプログラミング系から距離を置き、数理最適化×信号処理という分野をターゲットとしていました。

会社のこと

新卒研修

新卒エンジニア研修として、他の新卒エンジニアと一緒にとある社内向けサービスを開発しました。 この時の話だけで 1 エントリ書けてしまうので、今回は触れないでおきます。

技術グループのPodcast である Backyard Hatena でも少しだけ紹介されています。

developer.hatenastaff.com

所属チームのこと

5日間のエンジニア研修が終わったのちに、Mackerel という監視 SaaS の開発チームに配属されました。

ja.mackerel.io

Mackerel 開発チームへの onboarding

「Mackerel アプリケーションエンジニア入門」として、各領域に設定された実績を解除していきました。 チームとしてのタスク(スプリントバックログアイテムの消化)をメインとしてこなしつつ、余った時間で以下のような内容について学習しました。

幸いなことに、Mackerel で使っている技術スタックと自分が持っていたスキルがある程度合致していた(Scala・TypeScript+React)ので、業務に必要なプログラミングの習得には時間がかかりませんでした。 join して 3日目には最初の Pull Request をマージすることができました。 しかし、インフラ周り(特にクラウドサービス)の知識はほとんどなかったため、最初は話についていくのが大変でした。

メンターを始めとするチームメンバーの方々から絶妙なタイミングで新しいことにチャレンジする声掛けをしていただきました。 そのおかげで、毎日少しずつ背伸びをしながら、できる業務の幅を少しずつ広げていくことができました。

また、SRE と同じチームで一緒に仕事をしていることもあり、入社時と比べて格段にインフラ周りの知識が身についています。 これは、留学するとめちゃくちゃ英語できるようになる、みたいな話と近いかもしれません。

業務の上で心がけたこと

dogfooding

Mackerel を自分で使っているうちに見つけた要改善ポイントを、積極的にプロダクトバックログアイテムとして起票しています。 誰のどんな課題をどうやって解決するのかをきちんと言語化するのは大変ですが、時間をかけても良い大事な作業だと考えています。 これによってプロダクトオーナーを始めとするチームメンバーに、課題そのものや、課題の価値によってプロダクトの価値を上げられるということを共有することができます。 結果、優先度が高いと判断されたアイテムは、素早くスプリントに載せられ、チームとして取り組むことになります。

大規模なシステム開発だと、上から降ってきたタスクをただこなしているだけの人間になってしまいそうと思っていましたが、現実はそうではありませんでした。 Mackerel チームのスクラム開発では、 dogfooding を通じて明らかになった課題を、プロダクトの価値を高めるために解決していく仕組みが整っています。 自分がプロダクトに貢献できているという実感を持って取り組む仕事はとても楽しいです。

また、dogfooding から始めたこの取り組みによって、他のプロダクトバックログアイテムについても、利用者のことを考えた進め方を提案して進めることができています。

先ずテストより始めよ

チームに join してしばらくの間は、アプリケーションの仕様の理解に時間が掛かります。 先にテストを書いたり修正したりして、不安な場合にはこの状態で他のエンジニアに見てもらうことで、仕様への理解を深めました。 その上で、テストが通るようにアプリケーションコードを改修しました。

闇雲にタスクに取り組むのではなくテストコードから始めることにより、手戻りを減らしつつ、自信を持って Pull Request を作ることができました。

最後に

特に入社エントリとしてのまとめとしての話は用意していないのですが、このエントリで楽しく仕事をしていますという雰囲気が伝われば、エントリの目的は果たしていそうです。

これだけだと締まらないので、将来の話を少しだけします。

8月から始まる来半期は、自分の成長だけを考えていた状態からチーム・プロダクトの成長も合わせて考えられるようにシフトしていきたいと考えています。 チームとしてカバレッジが足りていない領域や、プロダクトが抱えている問題に合わせて、自分の成長の指針となる目標を設定しようと、メンターやディレクターと相談しています。

こんな形で今後も public な振り返りを定期的に書いていきたいですね。