maku693です。この記事は はてなエンジニア Advent Calendar 2025の11日目の記事です。
以前 WebGPUの紹介 - The Third Law という記事を書いてから6年が経ち、WebGPUが最新のブラウザで広くサポートされるようになりました*1。この記事では、改めて最新のWebGPUについてまとめてみます。
続きを読むmaku693です。この記事は はてなエンジニア Advent Calendar 2025の11日目の記事です。
以前 WebGPUの紹介 - The Third Law という記事を書いてから6年が経ち、WebGPUが最新のブラウザで広くサポートされるようになりました*1。この記事では、改めて最新のWebGPUについてまとめてみます。
続きを読むこの記事ははてなエンジニアアドベントカレンダー 2023の5日目の記事です。
maku693です。
私が現在所属しているチームではJiraを使ってチームのタスクを管理しています。
はてなではスクラムやそれをベースにした手法を使ってプロジェクトを管理していることが多いですが、以前所属していたチームでは別のウェブサービスを使っており、ベロシティ計測や中長期の計画に手間がかかると感じていました。
私は今のチームに異動して初めてJiraに触れたのですが、うまくJiraの機能に乗ることでそういった仕事を省力化できることがわかりました。
この記事では私のチームでJiraをどのように活用しているか紹介します。
Jiraの良いところはスクラムのコンセプトをもとにした機能が豊富な点です。私のチームもスクラムをベースにプロジェクトを管理しているので、他のツールに比べてよりチームに適していると感じました。
Jiraを使っていて特に良いと感じるのは次の3点です。
それぞれ詳しく説明します。
Jiraの「ボード」とはJiraの課題の表示方法の一種です。私のチームでは「バックログ」ボードを使って直近数スプリントの計画を実施しています。

Jiraのバックログボードには「スプリント」と「バックログ」の概念があります。これらはそれぞれスクラムのスプリントバックログとプロダクトバックログに相当するもので、バックログには将来とりかかる予定のタスクを、スプリントにはそのスプリントに手がける予定のタスクを並べられます。
スプリントは好きなだけ用意しておくことができるので、先のスプリントの計画をするだけでなく、まだリファインメントされていない課題を表現するなど、とりあえずタスクを分類する場所として使うこともできます。
ボード上のスプリントには見積もりの合計が表示されます。後ほど説明するスプリントレポートを見ればチームのキャパシティがわかるので、スプリントプランニング時にスプリントバックログの過不足を防げるのが便利です。
Jiraでは課題タイプを任意に追加できますが、私のチームではデフォルトで存在する「エピック」と「ストーリー」をよく利用しています。
「エピック」は「〇〇機能」のような、開発に1ヶ月程度かかるような粒度でバックログを管理するのに利用しています。

「ストーリー」ではエピックを構成するユーザーストーリーを管理しています。ストーリーについては必ずしも「△△できる」のようなユーザーストーリーっぽい書き方のタイトルにしているわけではなく、作業量が多いときは「××のUI」「××バックエンドAPI」などのようにコンポーネントレベルで分割することもあります。タスクの見積もり(ストーリーポイント)はストーリーに記録しています。

また、ストーリー中の細かいタスクは「サブタスク」で管理しています。サブタスクに関してはストーリーを実現するコードを書く際に、Pull Request単位くらいの粒度で分割して利用しています。これに関しては見積もりはしていません。
私のチームでは1チームでいくつかのプロダクトの面倒を見ている都合で、複数のエピックを並行して何スプリントにもまたがって進行させることがあるのですが、単に課題の種別があるだけでなく、エピック - ストーリー - サブタスク という親子関係がスプリントとは別に存在することで、素直にそういった状況を表現できるのが便利なポイントです。
「バージョン」は課題タイプやスプリントとはまた別の軸で、これを使うと複数の課題をあるバージョンにまとめられます。
私のチームでは何ヶ月かかけていくつかの機能を開発し、全てが完成してからそれらをまとめてリリースしています。
このようなマイルストーンを管理する際に、一つの大きなエピックを作るのではなく、エピックは機能単位で表現し、バージョンを使ってそれらをまとめられるというのがわかりやすくて気に入っているポイントです。

なおバージョンはストーリーに設定しています。こうすることで同じバージョンに紐づくストーリーの見積りの合計がレポートで把握できます。
Jiraが特に秀でていると感じるのはこのレポート機能です。
私のチームではつぎのレポートをよく利用しています。
私のチームではスプリントプランニングの際に 「ベロシティグラフ」で過去のスプリントのベロシティの実績を確認し、次のスプリントのキャパシティの参考にしたり、「バージョンレポート」「エピックレポート」でバージョン・エピックの開発が締切に間に合うか確認したりといった形で利用しています。


なお、バージョンレポートとエピックレポートは集計対象が異なるだけで見た目はほぼ同じです。
この2つのレポートはいわゆるバーンアップ形式の表現ですが、どちらもバーンダウン形式のものも存在するので、必要に応じてどちらも見れるのが便利です。
内部的にどのような計算式が使われているのか把握していないのですが、バージョンやエピックの完了予定日も表示されるので、これも計画の参考にしています。
また、このレポートは半期や1年などの中長期計画を立てるときにも利用できます。たとえば企画の立ち上げ段階で、開発を実施するかどうかが確定していないタイミングでは、バックログがまだ詳細化できないことが多いと思います。そのような状況でも、レポートを使えば過去のエピックの見積もりや開発期間が簡単にわかるので、同等の規模の機能の見積もりと、直近のチームのベロシティをもとに開発期間の予測を立てられます。
ただし、レポートを正常に運用するには、バックログアイテムの見積もりがある程度正確に行われていたり、スプリントの期間を一定にしていたりと、スクラムのお約束が守られていることが前提になります。そういったスクラムのコンセプトをチームに浸透させておくことも重要かと思います。
Jira以外のツールだとタスクを分類する軸が足りなかったり逆に自由度が高すぎて使いづらかったりと不満を感じることが多いのですが、Jiraにはスクラムの概念をもとにモデリングされた機能がビルトインされているので、そういった面での辛さがないのが嬉しいポイントです。
スクラムチームのプロジェクト管理に悩んでいるけど、今までJiraを使ったことがないという方は一度試してみてはいかがでしょうか。
この記事ははてなエンジニアアドベントカレンダー 2023の5日目の記事でした。
明日の担当は
id:tomato3713 さんです!
この記事を書くにあたって初めて知ったのですが、クラウド版Jiraのプロジェクトには、「チーム管理対象プロジェクト」と「企業管理対象プロジェクト」の2種類があります。今回説明した機能のうち特にレポート周りは「企業管理対象プロジェクト」でしか利用できないものが多いです。
「チーム管理対象プロジェクト」だとエピックやバージョンのレポートが見れない上に、あとからプロジェクトタイプの変換はできないようなので、そのようなレポートが必要な場合は最初から「企業管理対象プロジェクト」として作成するのがおすすめです。
詳しくは次のJiraのヘルプを参考にすると良いでしょう。
チーム管理対象プロジェクトと企業管理対象プロジェクト間の移行 | Jira Software Cloud | Atlassian サポート
少し調べてみたところ、どうやらPremiumやEnterpriseプランではAdvanced Roadmapsという機能が利用でき、これが代替になるようにも見えるのですが、無料プランのアカウントしか持っていないので試せていません。この辺りも機会があれば触ってみたいと思います。
Go言語の標準ライブラリには他言語のset型のようなものは存在しませんが、単純なものでよければ組み込みのmapをsetのように使えます。
x := map[string]struct{}{} // string型のset相当のmapを作成 x["foobar"] = struct{}{} // "foobar" を登録 _, ok := x["foobar"] // ok == true。集合に値が含まれる _, ok = x["barbaz"] // ok == false。集合に値は含まれない
Mapのキーには比較演算子 (== と !=) が定義されている型が利用できます *1(comparable*2 に近いが、mapやsliceはキーにできないのでcomparableとは異なる)。
Mapのvalueの型に空struct (struct{}) を使っているので、valueのために余計なメモリを確保せずに済みます。またこうすることでvalueに意味がないことの表明にもなります。
ただし、mapはあくまでmapなので、他言語のsetのような集合どうしの和や積などをとるためのインタフェースは存在しません。そのようなアルゴリズムが必要な場合はおとなしくdeckarep/golang-setのようなライブラリを入れるのがよいでしょう。
このテクニックは
id:cockscomb さんのコードをレビューしていて知りました。
maku693です。
Github ActionsでPuppeteerを簡単に使えるCustom Actionを作りました。
最近Github Actions上でブラウザを動かしたくなったのですが、いちいち実行環境を整えるのも面倒なので、サクッとできないものかと調べたところ、意外とPuppeteerをそのまま使えるactionというのは存在しないようだったので、自分で作りました。
使い方はREADMEに書いてありますが、ここでも軽く紹介します。
以下のjobでは、ページのタイトルを取ってきて、それを後続のstepで利用しています。
- id: get-title
uses: maku693/action-puppeteer-script@v0
with:
script: |
const page = await browser.newPage();
await page.goto("https://maku693.hatenablog.jp");
const title = await page.$eval('title', el => el.textContent);
return title;
- run: echo '${{ steps.get-title.outputs.result }}' # `"The Third Law"` が出力されるちゃんと試していないのですが、基本的にほぼ全てのPuppeteerのAPIが使えると思うので、スクリーンショットを撮るとか、ファイルをダウンロード・アップロードするとか、ブラウザが必要な色々な場面の自動化に活用できると思います。
続きを読むタイトルでほとんど説明しましたが、Go Modulesが有効な環境で、module-awareなコマンドに特定のディレクトリを無視させるには、無視させたいディレクトリにダミーのgo.modファイルを設置しておくとよいです。ファイルの内容は空で構いません。
Githubにサンプルコードを置いておいたので、参考にしてください。
パッケージパターンを引数として受け取るgoコマンドのサブコマンドを使うとき、...というワイルドカードを使うと、特定のディレクトリツリー内のパッケージをまとめて指定できて便利です。
例えば
$ go generate ./...
というコマンドは、カレントディレクトリ(.)以下のすべてのパッケージを対象にしてgo generateコマンドを実行します。
これはパッケージがたくさんある場合にひとつずつ指定せずに済むので便利なのですが、この方法だとgoコマンドがすべてのディレクトリツリーを走査してしまうので、実行に時間がかかる場合があります。
例えば、GoとNode.jsのソースコードが同居しているコードベースがあったとき、node_modulesディレクトリにはGoのソースコードは含まれていないので、goコマンドがこのようなディレクトリを見ないようにできると、パフォーマンス上のメリットがあります。
goコマンドは_または.から始まるディレクトリや、testdataというディレクトリは無視する*1ので、ディレクトリをリネームできる場合はそうすればいいのですが、node_modulesのようにディレクトリ名を制御できないこともあります。
これに対処するには、ダミーのgo.modファイルを当該ディレクトリに設置し、goコマンドにそのディレクトリ以下を別のモジュールとして認識させるという方法が使えます。
個人的には筋の良い解決策とは思えないのですが、Goチームとしてはgoコマンドに特定のディレクトリを無視する機能を追加する予定はないようです*2。
node_modulesを無視したい場合はpostinstallスクリプトを使う一般にnode_modulesディレクトリはバージョン管理システムで管理されないため、go.modファイルが必ずnode_modulesに配置されるようにするには一工夫必要です。
ワークアラウンドとしては、package.jsonのpostinstallスクリプトに空のgo.modファイルを作成するようなスクリプトを指定するとよいでしょう(とりあえずnode_modules生成後に自動でgo.modを配置するという用途にはこれで十分ではあるものの、GoのツールチェインのためのファイルをNode.jsの仕組みで生成させるのはいかがなものか……とも思いますが)。
1ヶ月くらい前の話なのですが、friendly-words-cliというコマンドラインツールを作りました。
趣味でコードを書くにあたってプロジェクト名を決めたいとき、ランダムな英単語を組み合わせた文字列が欲しいときのワンライナー - The Third Lawのように決めていたのですが、この方法には公の場で使うのは憚られそうな単語が入っていることがある
という欠点があったので、代替を探していました。
あるときp5.js Web Editorを使う機会があり、これに実装されているプロジェクト名を決める仕組みを流用できないかと調べてみたところ、glitchdotcom/friendly-wordsというNPMパッケージを見つけたので、これを使ったコマンドラインツールを作りました。
プロジェクト名を決めたいというのが個人的な使い道なのですが、ランダムな単語が欲しいシチュエーションは他にもあると思うので、コマンドとしては単語の出力に専念するようなインタフェースにしてあります。
$ friendly-words comfort
p5.js Web EditorやGlitchのプロジェクト名のような単語が欲しい場合は、以下のように使うとよいでしょう。
$ echo "$(friendly-words -l predicates)-$(friendly-words -l objects)" flax-tangerine
直接ディレクトリを作りたい場合はこんな感じで使えます。
$ mkdir "$(friendly-words -l predicates)-$(friendly-words -l objects)" $ ls plucky-bacon
ぜひお使いください。
GraphQL APIを作るとき、素朴に実装するとN+1問題が発生しがちなので、これを解消するためにDataloaderという仕組みも実装するのが一般的です。
少し前にHaskell Dayというイベントの発表資料をレビューする機会があり*1、Dataloader的な設計はGraphQL以前から知られていて、Facebookで開発されたHaxlというHaskellのライブラリに由来するということを知りました*2。
ちなみにレビューした発表はこちらです(この発表をネタにして記事を書いていいですか?と発表者の@nakaji_dayoさんに聞いたところ、快諾いただけた上にこのブログ記事の内容もレビューしていただけました!ありがとうございます)。
www.youtube.com
speakerdeck.com
このHaxlですが、他言語で実装された一般的なDataloaderにはない特徴があります。
よくあるDataloaderには、RDBMSへのクエリやWeb APIの呼び出しなどのリモートへのリクエストのバッチ化や、その結果をキャッシュしておく機能があります。Haxlではこれに加えて、ApplicativeDoというGHC拡張*3を用いることで、データの取得を暗黙に並行化できます。
たとえば、データAとデータBが必要なとき、AとBに依存がなければ、ユーザーが何も指定しなくても、Aの取得とBの取得を順番に実行するのではなく、同時に実行してくれるのです。
これは特定の構文(といっても特殊なものではなく、Haskellでは一般的なdo構文という書き方)を使ってHaxlを呼び出すコードを書くと、コンパイラがコンパイル時に処理を並行に実行できるようにしてくれるという方法で実現されています。より詳しく知りたい方は、ぜひ冒頭で紹介した発表を見てください。
この嬉しさを実感するには、実際にコードをみた方が早いでしょう。
AとBの取得を並行化したい場合、JavaScriptではPromise.all、Goではgoroutineとsync.WaitGroupを使うなど、人間が手で依存を解決して、並行に実行されるコードを書く必要があります。
// 並行に取得しない場合 async function numCommonFrends(a, b) { const fa = await friendsOf(a); const fb = await friendsOf(B); return intersect(fa, fb).length; } // 並行に取得する場合 async function numCommonFrends(a, b) { const [fa, fb] = await Promise.all([friendsOf(a), friendsOf(b)]); return intersect(fa, fb).length; }
// 並行に取得しない場合 func NumCommonFrends(a, b *User) int { fa := friendsOf(a) fb := friendsOf(a) return len(intersect(fa, fb)) } // 並行に取得する場合 func NumCommonFrends(a, b *User) int { var fa, fb []*User var wg sync.WaitGroup wg.Add(2) go func() { fa = friendsOf(a) wg.Done() }() go func() { fb = friendsOf(b) wg.Done() }() wg.Wait() return len(intersect(fa, fb)) }
ApplicativeDoとHaxlを使うと、この地味で面倒な作業をコンパイラがやってくれるわけです。
-- 何もしなくても並行に処理が実行される numCommonFriends a b = do fa <- friendsOf a fb <- friendsOf b return (length(intersect fa fb))
私は普段ウェブアプリケーションの開発ではJavaScript (TypeScript) やGoを書いていて、Haskellを使うことは全くありませんが、こういうところを見るとHaskellは進んでるな〜と感じます。
こうして見比べてみると、Goのコードの冗長さが目立ちますね……。
*1:Haskellにはあまり詳しくないので、主にGraphQL面のレビューをしました。
*2:調べたらオリジナルのdataloaderのREADMEにも書いてありました。
*3:GHCはGlasgow Haskell CompilerというHaskellコンパイラのデファクトスタンダードで、GHC拡張とはコンパイラのFeature Flagを切り替えてHaskellの言語機能を拡張できる仕組みです。
タイトルでほぼ全部説明しましたが、Stylelintを使う時、既存のconfigで指定されているルールを完全にオフにするには null を使います。
例えば、stylelint-config-sass-guidelinesとstylelint-config-property-sort-order-smacssを組み合わせて使いたい時、プロパティの並び順のルールがそれぞれ異なるので、単に組み合わせるだけだとルールがコンフリクトしてしまうのですが、不要なルールをオフにすると解決できます。
{ "extends": [ "stylelint-config-sass-guidelines", "stylelint-config-property-sort-order-smacss" ], "rules": { "order/properties-alphabetical-order": null } }
このように設定すると、基本的にはstylelint-config-sass-guidelinesを使いつつ、プロパティの並び順についてはstylelint-config-property-sort-order-smacssのものを使う、という設定が可能です。
オフにするとき何を指定したらいいのか分からず、false や空配列などを指定していましたが、うまく動かなかったのでStylelintのソースコードをみたところ、 nullを指定するという仕組みだというのを発見しました。
よくみると null だけでなく [null] でもいいみたいですね。
タイトルで全て説明していますが、BuildKitがオンの環境で、docker build 中の標準出力の内容をビルドする側で全部確認したい場合は --progress=plain オプションが使えます。
$ docker build --progress=plain .
docker build するとき、BuildKitが有効化されていると、デフォルトではすでに完了したステップのstdoutが隠れてしまいます。
いつからか自分の手元でも BuildKit が有効になっていたのですが、イメージのビルド時に何が起きていたか調べたくなり困ったので、ログを出す方法を調べてみたところオプションがありました。
BUILDKIT_PROGRESS 環境変数を使ってデフォルトでplainにすることもできるようです。