Slide 1

Slide 1 text

@ageha734 脱・シェル芸!  Taskで始めるイマドキ? Go開発

Slide 2

Slide 2 text

名前:日比 恵多(ひび けいた) 所属:プラットフォーム開発本部 認可チーム 登壇者 2

Slide 3

Slide 3 text

⚠ はじめに:注意事項 この発表は、Makefile を批判するものではありません! Makefile は、非常に優れたツールです。 その歴史と実績に敬意を表します! この発表では、日々の開発タスク(ビルド、テスト、 Lint など)を管理する 汎用タスクランナーという文脈 で、Task という、もう一つの快適な選択肢を 知ることを目的としています! 「適材適所」でツールを使い分けるための一つの提案 としてお聞きください!

Slide 4

Slide 4 text

このパートの目的 4 ● Makefile での「あるある」を共有し、その解決策として Task を知ってもらう ● ほんの僅かでも、「プロジェクトで使ってみたい! 」と思ってもらう

Slide 5

Slide 5 text

このパートで説明するもの 5 ● Task の基本的な概念と、Makefile との違い ● Task を導入してみての知見の共有

Slide 6

Slide 6 text

目次 6 ● その Makefile では、もう限界かも?  ● Hello Task ● Task の"私的お推し"ポイント! ● 結局、何を使えばいいの? ● まとめ 07p 09p 16p 40p 43p

Slide 7

Slide 7 text

その Makefile では、も う限界かも? 7

Slide 8

Slide 8 text

こんな「つらみ」、ありませんか? 8 😭 どのコマンドが何をするのか、もう誰も分からない秘伝のタレ化した Makefile … 😭 新しいメンバーにコマンド体系を説明するのが大変 … 😭 「make 使い方」でググっても、コマンドばかりで公式ドキュメントにたどり着けない … 😭 タブとスペースを間違えて、謎のエラーと格闘 … 😭 Linux (GNU make) では動くのに、Mac (BSD make) だと微妙に動かない … 😭 そもそも Windows だと追加インストールが必要で環境構築が面倒 … そんな悩みを解決してくれる イケてるツール をご紹介します!

Slide 9

Slide 9 text

Hello Task 9

Slide 10

Slide 10 text

一言で言うと、Go言語で作られたビルドツール です。 ❤ YAML でシンプルに書ける! ❤ クロスプラットフォーム対応している! ❤ Gopher と相性がいい! Task って何? 10

Slide 11

Slide 11 text

Discord で直接聞いてみました。 【質問内容】 1. Task を開発したきっかけや動機は? 2. 具体的にどのような問題や課題を 解決しようとしていましたか? なぜ生まれたの? 11

Slide 12

Slide 12 text

Discord で直接聞いてみました。 【質問内容】 1. Task を開発したきっかけや動機は? 2. 具体的にどのような問題や課題を 解決しようとしていましたか? なぜ生まれたの? 12

Slide 13

Slide 13 text

Discord で直接聞いてみました。 【質問内容】 1. Task を開発したきっかけや動機は? 2. 具体的にどのような問題や課題を 解決しようとしていましたか? なぜ生まれたの? 13

Slide 14

Slide 14 text

【動機】 Windows での make は面倒... 💡 依存関係なしで単一バイナリで、簡単に導入できるツールが欲しいな〜 💡 YAML ファイルを読み込んでコマンドをいくつか実行できるものないかな〜 その当時探してみても、気に入ったものは見つからない 😭 そんなに難しいことなのだろうか? 開発者はこう思ってた! 14

Slide 15

Slide 15 text

【開発】 休暇中の2日間で作成した。 【リリース】 2017年に最初の PoC を動作に Reddit の /r/golang に投稿し v1.0.0 がリリースされました だからTaskを作った! 15

Slide 16

Slide 16 text

Task の"私的お推し" ポイント! 16

Slide 17

Slide 17 text

Task には様々なインストール方法があります! のほかに! 📦 brew install go-task/tap/go-task 📦 winget install Task.Task 📦 npm install @go-task/cli 📦 pip install go-task-bin 推しポイント①:マルチプラットフォーム 17 go install github.com/go-task/task/v3/cmd/task@latest

Slide 18

Slide 18 text

推しポイント②:設定ファイルのような明快さ 18 ● YAMLで書ける! ● GoDotEnv が内包されている! ● vars で変数を宣言できる! ● 記述後は task run で実行! ● task --list でタスク一覧 説明( desc )を表示できる! version: '3' dotenv: ['.env'] vars: BINARY: bin/$APP_NAME/app tasks: run: desc: "アプリを動かす" cmds: - go run {{.BINARY}}

Slide 19

Slide 19 text

Makefile と Task の比較してみると? 19 # Makefile -include .env export BINARY ?= bin/$APP_NAME/app .PHONY: run run: ## アプリを動かす go run {{.BINARY}} # Taskfile.yml dotenv: ['.env'] vars: BINARY: bin/$APP_NAME/app tasks: run: desc: "アプリを動かす" cmds: - go run {{.BINARY}}

Slide 20

Slide 20 text

推しポイント③: 防御力マシマシのタスクが作れる 20 ● aliases で短いタスクで 実行できる! ● preconditions コマンド実行前に 前提条件をチェック 満たさなければエラーで 止めてくれる! ● status で条件をチェック 満たしていればタスクを スキップしてくれる! tasks: generate: aliases: ['g'] preconditions: - sh: "[ -f go.mod ]" msg: "go.mod not found" - sh: "[ command -v mockgen ]" msg: "mockgen not command" status: - test -d test/mock cmds: - go generate ./...

Slide 21

Slide 21 text

Makefile と Task の比較してみると? 21 # Makefile .PHONY: generate g generate: @[ -f go.mod ] || exit 1 @command -v mockgen >/dev/null 2>&1 || exit 1 @[ -d test/mock ] && exit 0 @go generate ./... g: generate # Taskfile.yml tasks: generate: aliases: ['g'] preconditions: - sh: "[ -f go.mod ]" msg: "go.mod not found" - sh: "[ command -v mockgen ]" msg: "mockgen not command" status: - test -d test/mock cmds: - go generate ./...

Slide 22

Slide 22 text

推しポイント④:ホットリロードができる 22 ● watch:true この一行で ホットリロードが有効化! ● sources にソースファイルを generates に生成物ファイルを 書くだけでファイルの変更を 監視できる! ● exclude で監視対象から 除外できる! tasks: build: watch: true method: timestamp sources: - ./**/*.go - exclude: ./**/*_test.go cmds: - go build ./... generates: - app

Slide 23

Slide 23 text

# Taskfile.yml tasks: build: watch: true method: timestamp sources: - ./**/*.go - exclude: ./**/*_test.go cmds: - go build ./... generates: - app Makefile と Task の比較してみると? 23 # Makefile TARGET_APP := app GO_FILES := $(shell find . -name '*.go' | grep -v '_test.go$$') .PHONY: build watch build: $(TARGET_APP) $(TARGET_APP): $(GO_FILES) go build -o $(TARGET_APP) main.go watch: @find . -name '*.go' | grep -v '_test.go$$' | entr -c make build

Slide 24

Slide 24 text

includes で設定を分割・再利用! ルートの Taskfile.yml で 各サービスの Task を読み込める! 下記のコマンドで一括ビルド! (おまけ①)マイクロサービスでも活躍 24 includes: user-api: ./services/user-api tasks: mod: desc: "依存関係を整理" cmds: - go mod tidy build:all: desc: "全サービスをビルドする " deps: mod cmds: - task: user-api:build task build:all

Slide 25

Slide 25 text

(おまけ②)テンプレート ここがスゴい!テンプレート機能 🎁 動的な変数 {{.TIMESTAMP}} や {{.CLI_ARGS}} を利用して 実行時の情報を使って変数を動的に生成できる。 🎁 環境依存の自動化 {{.OS}} (linux, darwin...) や {{.ARCH}} (amd64, arm64...) を利用して クロスコンパイルのコマンドを OS ごとに書く必要がなくなる。 🎁 組み込み関数 upper (大文字化) や split (文字列分割) などが用意されており、 シェルスクリプトで書いていたような文字列操作を Task 内だけで完結できる。

Slide 26

Slide 26 text

(おまけ②)テンプレート dotenv: ['.env'] vars: PRODUCTION: $PRODUCTION VERSION: "1.2.3" FILENAME: {{.OS | trim}}-{{.ARCH}}-{{printf "v%s" .VERSION}}-$APP_NAME tasks: build: method: checksum sources: ['**/*.go'] status: - echo "{{.CHECKSUM}}" | cmp -s - bin/{{.FILENAME}}.checksum cmds: - go build -o bin/{{.FILENAME}} {{if .PRODUCTION}}-ldflags="-X main.revision={{.VERSION}}"{{end}} . - echo "{{.CHECKSUM}}" > bin/{{.FILENAME}}.checksum generates: - bin/{{.FILENAME}} - bin/{{.FILENAME}}.checksum

Slide 27

Slide 27 text

推しポイント⑤:実はコスパも良い! 27 もちろん導入コスト(学習・移行)はかかりますが … それ以上に、こんな人件費を削減できます! 💹 削減① (実行待機 ) Go製で高速に動作するので CI の待ち時間を短縮 💹 削減② (学習) ドキュメントもしっかりしているので理解しやすい 💹 削減③ (オンボーディング ) 新しいメンバーも task --list を見れば何があるのかがひと目で見れる

Slide 28

Slide 28 text

同じ一連のGoコマンド(lint, test, build, e2e)を、 💹 MacBook M4 16GB 💹 GitHub Actions(ubuntu-latest) Task と Makefile、シンプルシェルスクリプト各方法で実行し、 ジョブ全体の完了時間を比較しました。 https://github.com/ageha734/dmm-go-2025-09-17-go-task 実行時間を比較してみた 28

Slide 29

Slide 29 text

数値で見る(ローカル環境: E2E) 29 【2回目実行時】 7秒ほど 早くなっている 【1回目実行時】 実行時間に変わり あまり見受けられない

Slide 30

Slide 30 text

数値で見る(ローカル環境: E2E) 30 【2回目実行時】 7秒ほど 早くなっている 【1回目実行時】 実行時間に変わり あまり見受けられない

Slide 31

Slide 31 text

数値で見る(ローカル環境: E2E) 31 【2回目実行時】 7秒ほど 早くなっている 【1回目実行時】 実行時間に変わり あまり見受けられない

Slide 32

Slide 32 text

10回の実施検証結果では、 Task が最も速いという結果になりました 数値で見る(GitHub Actions: CI) 32

Slide 33

Slide 33 text

10回の実施検証結果では、 Task が最も速いという結果になりました 【実行内容】 💹 Dockerでのサービス起動 💹 DBセットアップ 💹 APIテスト 数値で見る(GitHub Actions: E2E Test) 33

Slide 34

Slide 34 text

で、結局どれくらいおトクなの? 34 💰 チリツモが効く! --parallel で並列実行するだけで、 毎日の小さな待ち時間がごっそりなくなる! 一回数秒の差が、一年経てば大きなリターンになる。 💰 待ちガチな重い処理が爆速に!( E2E Test) Deps による依存関係の解決で、 一番ボトルネックだった処理が半分以下の時間に! もうコーヒーを淹れにいく必要はありません。

Slide 35

Slide 35 text

つまり、1年でこれだけの「おトク」が! 35 (※ すべての実行時間が 1日30分と仮定) ● 時間: 年間 約90時間 GET! (だいたい11日分の労働時間に相当!) (※ 時給5000円と仮定) ● お金: 年間 約450,000円 浮く計算に! (MacBook M4 Pro 48GB、買えちゃいますね) これ、たった1人のエンジニアの話です。チームなら … 🤔

Slide 36

Slide 36 text

【状況:Go言語研修での出来事】 新卒研修で提供された神リポジトリは Makefile でタスクが管理されていました。 【課題:増殖するG】 ❓ カスタムコマンドの追加が必要になり、 Makefile やシェルを編集する。 しかし、どんどん複雑化していく、どこに何があるか分からなる。 ❓ コマンド生成を Gemini に頼ると、一見動くものの、自分では理解できない おまじない のようなコマンドが増殖 …。 「もう無理!ちゃんと自分で管理できる仕組みにしたい! 」 なぜ導入に至ったのか 36

Slide 37

Slide 37 text

移行プロセスの3ステップ 🤖 既存のコードを丸投げ 複雑化した Makefile と複数のシェルスクリプトの中身を全部コピーして Gemini に贈呈 🤖 魔法の言葉をお願いする。 「これを Task の作法に則って、読みやすく書き換えてください」と依頼 🤖 出力結果を微調整 Gemini が生成した Task をレビューし、細かい部分を修正して完成! どのように導入していったのか 37

Slide 38

Slide 38 text

① LLMの惜しい間違い Makefile の変数 $(VAR) と Task の変数 {{.VAR}} を混同するなど、 一見動くけど実は違う、 微妙なシンタックスミス が生成されることがありました。 デバッグする過程で、 Task の正しいお作法を学ぶ必要 ② 翻訳するだけではダメな場面 Makefile の書き方をそのまま Task に移植しても、 Task の良さ(deps や status)を活かせないことに気づきました。 単なる「翻訳」ではなく、 Taskならどう設計するか?という「再設計」の視点が必要 もちろん、つまずいた点も… 38

Slide 39

Slide 39 text

とにかく管理がめちゃくちゃ楽 になった 🙌 コマンドが一つの YAML ファイルに集約 され、見通しが最高! 🙌 実行時間の待ち時間が短縮できた! 🙌 task --listで一覧できるので、もう「あのコマンドどこだっけ?」と探さなくなる 🙌 自分が理解・管理できるコマンドが増え、自信を持ってタスクを実行できる それでも、移行して本当に良かったこと 39

Slide 40

Slide 40 text

結局、 何を使えばいいの? 40

Slide 41

Slide 41 text

用途で使い分けるのが賢い選択肢 41 比較要素 Task が得意なこと Makefile が得意なこと 主な目的 ビルド・テスト・開発全般 C/C++ コンパイラ 開発体験 watch によるホットリロード、 preconditions での事前チェックなど、開発を支援する 機能が豊富。 主要な Linux/macOS や CIランナーに標 準インストール済みが多い。 依存関係 キャッシュ機能があり、 depsでタスク間の 依存を定義。並列実行も簡単。 ファイルのタイムスタンプ を元にした厳 密な依存関係解決が得意。 ドキュメント 公式ドキュメント が非常に探しやすい。 機能がまとまっている。 記事や事例がネット上に膨大に存在す る。歴史が長い分、情報量は圧倒的。

Slide 42

Slide 42 text

💡 無理に置き換えない。共存の選択 Makefile から Task のコマンドを呼び出すことで、段階的な移行。 チーム内での併用が可能です。 💡 LLMに「壁打ち」してみる 既存の Makefile をどう Task に変換すれば良いか、 LLM に相談してみるのも良い方法 プロジェクトに合った Task の書き方を学ぶ良いキッカケになります。 【最終的な判断基準はこれ!】 「コスト削減」と「可読性」を最優先するなら ... ➡ Task を試す価値オオアリ 「環境の普遍性」と「既存資産」を最優先するなら ... ➡ Makefile を使い続けるのが合理的 明日から使えるTips & 判断基準 42

Slide 43

Slide 43 text

まとめ 43

Slide 44

Slide 44 text

今日から task --init しよう! 44 ✅ YAML で宣言的に書けるため、誰でも読みやすくメンテナンスが容易! 👉 秘伝のタレになりやすい独自構文から脱却しよう。 ✅ 差分ビルドや並列実行で、CI の実行時間を客観的に短縮! 👉 無駄な待ち時間を削減し、コストを節約。 task --init から始める快適な開発ライフ、あなたもいかがですか? 😉

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

Task ● Documentation ( https://taskfile.dev/ ) ● GitHub ( https://github.com/go-task/task ) 比較・関連ツール ● GNU Make ( https://www.gnu.org/software/make/manual/make.html ) ● golangci-lint ( https://github.com/golangci/golangci-lint ) ● gomock ( https://github.com/uber-go/mock ) 参考文献 46