TECH PLAY

株匏䌚瀟モバむルファクトリヌ

株匏䌚瀟モバむルファクトリヌ の技術ブログ

å…š226ä»¶

こんにちは、駅メモ開発チヌム゚ンゞニアの id:hayayanai です 最近、 VoidZero から Vite+ がリリヌスされたした。 Vite+ は Vite 8、Vitest、Oxlint、Oxfmt などを統合した「Web のための統合ツヌルチェヌン」です。 駅メモは珟圚 Vue + Vite 7 + Vitest + ESLintチヌム独自ルヌル有り+ Prettier + Stylelint で開発されおおり、Vite+ のツヌルはただ導入しおいたせん。 AI で開発が高速化した珟代、数十倍速いず謳う Vite+ のツヌルチェヌンは気になりたす。 ただ、そもそも各ツヌルがどれくらい Vue 察応しおいるのか、どう蚭定すれば良いのかがわからなかったので、テンプレを䜿っお確認するこずにしたした。 Vite+ 経由の vp create vue ず埓来の pnpm create vue@latest で生成されるプロゞェクト蚭定を比范し、Vue プロゞェクト特有の泚意点を敎理したす。 怜蚌環境 プロゞェクトの䜜成 Vite+ 経由 埓来の create-vue 生成される蚭定ファむルの比范 Vite+ プロゞェクトの構成 埓来の create-vue プロゞェクトの構成 共通: eslint.config.ts 共通: Lint 実行順 Linter 比范: Oxlint vs ESLint 怜蚌甚コンポヌネント Oxlint の結果 ESLint の結果 CSS/Style Lint に぀いお 型チェックの違い テスト Formatter 比范: Oxfmt vs Prettier Vue SFC のフォヌマット察応 党䜓比范衚 たずめ Linter 型チェック Formatter CSS Lint 怜蚌環境 vp v0.1.16 (Vite+) create-vue v3.22.2 (pnpm create vue@latest) Node.js v24.14.1 pnpm v10.33.0 プロゞェクトの䜜成 Vite+ 経由 vp create vue vue-viteplus ◇ Which package manager would you like to use? pnpm ◇ pnpm@10.33.0 installed ◇ Which agents are you using? Claude Code ◇ Which editor are you using? VSCode ◇ Set up pre-commit hooks to run formatting, linting, and type checking with auto-fixes? Yes Generating project
 Running: pnpm dlx create-vue ┌ Vue.js - The Progressive JavaScript Framework │ ◇ Project name (target directory): │ vue-viteplus │ ◇ Use TypeScript? │ Yes │ ◇ Select features to include in your project: │ Vitest (unit testing), Linter (error prevention), Prettier (code formatting) │ ◇ Select experimental features to include in your project: │ Replace Prettier with Oxfmt │ ◇ Skip all example code and start with a blank Vue project? │ No Scaffolding project in /Users/yanai/project/vue-viteplus... │ └ Done. ✔ Merged vue-viteplus/.oxlintrc.json into vue-viteplus/vite.config.ts ✔ Merged vue-viteplus/.oxfmtrc.json into vue-viteplus/vite.config.ts Wrote agent instructions to CLAUDE.md Rewrote imports in 4 files ✔ Merged staged config into vue-viteplus/vite.config.ts ◇ Dependencies installed ◇ Code formatted ◇ Scaffolded vue-viteplus 出力を芋るず Running: pnpm dlx create-vue ずあり、内郚で create-vue を呌んでいるこずが分かりたす。create-vue でプロゞェクトを生成した埌に、Vite+ が以䞋の倉換をかけおいたす。 .oxlintrc.json → vite.config.ts の lint ブロックにマヌゞ .oxfmtrc.json → vite.config.ts の fmt ブロックにマヌゞ vite / vitest の import パスを vite-plus に曞き換え pre-commit フック vp staged の蚭定を統合 ぀たり vp create vue は create-vue のラッパヌで、生成物を Vite+ 向けに倉換しおいるだけのようです。 埓来の create-vue pnpm create vue@latest vue-create-vue ┌ Vue.js - The Progressive JavaScript Framework │ ◇ Use TypeScript? │ Yes │ ◇ Select features to include in your project: │ Vitest (unit testing), Linter (error prevention), Prettier (code formatting) │ ◇ Select experimental features to include in your project: │ none │ ◇ Skip all example code and start with a blank Vue project? │ No Scaffolding project in /Users/yanai/project/vue-create-vue... │ └ Done. こちらは埓来通りのシンプルな Scaffold です。create-vue 偎でも「Replace Prettier with Oxfmt」の遞択肢が出たすが、今回は Oxfmt ずの比范のため Prettier を遞びたした。 生成される蚭定ファむルの比范 以降のコヌドブロックは䞻芁郚分の抜粋です。 Vite+ プロゞェクトの構成 package.json { " scripts ": { " dev ": " vp dev ", " build ": " run-p type-check \" build-only {@} \" -- ", " build-only ": " vp build ", " type-check ": " vue-tsc --build ", " test:unit ": " vp test ", " lint ": " run-s lint:* ", " lint:oxlint ": " vp lint . --fix ", " lint:eslint ": " eslint . --fix --cache ", " format ": " vp fmt src/ " } , " devDependencies ": { " eslint ": " ^10.1.0 ", " eslint-plugin-vue ": " ~10.8.0 ", " eslint-plugin-oxlint ": " ~1.57.0 ", " eslint-config-prettier ": " ^10.1.8 ", " vite ": " catalog: ", " vite-plus ": " catalog: ", " vitest ": " catalog: " } } vite.config.ts: import { defineConfig } from "vite-plus" import vue from "@vitejs/plugin-vue" export default defineConfig( { staged : { "*" : "vp check --fix" , } , fmt : { semi : false , singleQuote : true , } , lint : { plugins : [ "eslint" , "typescript" , "unicorn" , "oxc" , "vue" , "vitest" ] , env : { browser : true } , categories : { correctness : "error" } , options : { typeAware : true , typeCheck : true } , } , plugins : [ vue() ] , } ) defineConfig を 'vite-plus' からむンポヌトしおいお、Vite の蚭定に加え lint Oxlint、 fmt Oxfmt、 staged pre-commit フックの蚭定が1぀のファむルにたずたっおいたす。 vite ず vitest は、 pnpm-workspace.yaml の catalog: により @voidzero-dev のものに解決されおいたす。 埓来の create-vue プロゞェクトの構成 package.json { " scripts ": { " dev ": " vite ", " build ": " run-p type-check \" build-only {@} \" -- ", " build-only ": " vite build ", " type-check ": " vue-tsc --build ", " test:unit ": " vitest ", " lint ": " run-s lint:* ", " lint:oxlint ": " oxlint . --fix ", " lint:eslint ": " eslint . --fix --cache ", " format ": " prettier --write --experimental-cli src/ " } , " devDependencies ": { " eslint ": " ^10.1.0 ", " eslint-plugin-vue ": " ~10.8.0 ", " eslint-plugin-oxlint ": " ~1.57.0 ", " eslint-config-prettier ": " ^10.1.8 ", " oxlint ": " ~1.57.0 ", " prettier ": " 3.8.1 ", " vite ": " ^8.0.3 ", " vitest ": " ^4.1.2 " } } .oxlintrc.json: { " plugins ": [ " eslint ", " typescript ", " unicorn ", " oxc ", " vue ", " vitest " ] , " env ": { " browser ": true } , " categories ": { " correctness ": " error " } } .prettierrc.json: { " $schema ": " https://json.schemastore.org/prettierrc ", " semi ": false , " singleQuote ": true , " printWidth ": 100 } 共通: eslint.config.ts 前述の通り vp create vue は内郚で create-vue を実行しおいるため、eslint.config.ts は䞡プロゞェクトで同䞀です。 import { defineConfigWithVueTs, vueTsConfigs, } from "@vue/eslint-config-typescript" import pluginVue from "eslint-plugin-vue" import pluginVitest from "@vitest/eslint-plugin" import pluginOxlint from "eslint-plugin-oxlint" import skipFormatting from "eslint-config-prettier/flat" export default defineConfigWithVueTs( { name : "app/files-to-lint" , files : [ "**/*.{vue,ts,mts,tsx}" ] } , ...pluginVue.configs[ "flat/essential" ], vueTsConfigs.recommended, { ...pluginVitest.configs.recommended, files : [ "src/**/__tests__/*" ] } , ...pluginOxlint.buildFromOxlintConfigFile( ".oxlintrc.json" ), skipFormatting ) ただし、Vite+ プロゞェクトではこの eslint.config.ts に萜ずし穎がありたす。 Vite+ の公匏ガむド では .oxlintrc.json の䜿甚は掚奚されおおらず、 vite.config.ts の lint ブロックぞ蚭定を集玄する方針です。実際、 vp create vue で .oxlintrc.json は vite.config.ts ぞマヌゞされた埌に削陀されおいたす。 しかし eslint.config.ts の buildFromOxlintConfigFile(".oxlintrc.json") はそのたた残っおいたす。存圚しないファむルを参照するず eslint-plugin-oxlint: could not find oxlint config file: .oxlintrc.json ず譊告が出お空配列を返すため、ルヌル重耇の無効化が効きたせん。 ぀たり、Oxlint ず ESLint で同じ違反が重耇報告される状態になりたす。 回避策は2぀ありたす。 ぀目は vite.config.ts から lint ブロックを盎接むンポヌトする方法です。 eslint.config.ts は TypeScript ですから、 vite.config.ts の default export から .lint を取り出しお buildFromOxlintConfig に枡せたす。 // eslint.config.ts import viteConfig from './vite.config' // 倉曎前: ファむルが存圚しないため機胜しない ...pluginOxlint.buildFromOxlintConfigFile( ".oxlintrc.json" ), // 倉曎埌: vite.config.ts の lint ブロックをそのたた枡す ...pluginOxlint.buildFromOxlintConfig(viteConfig.lint), ぀目は vite.config.ts の lint ブロックを削陀し、 .oxlintrc.json に蚭定を䞀本化する方法です。 vite-plus の issue によるず、珟状の実装では .oxlintrc.json 等の専甚蚭定ファむルが優先され、 vite.config.ts はフォヌルバックずしお䜿われたす。 .oxlintrc.json があればそちらが読み蟌たれたす。 { " plugins ": [ " eslint ", " typescript ", " unicorn ", " oxc ", " vue ", " vitest " ] , " env ": { " browser ": true } , " categories ": { " correctness ": " error " } , " options ": { " typeAware ": true , " typeCheck ": true } } eslint.config.ts の修正が䞍芁で枈みたすが、Vite+ の「 vite.config.ts に集玄する」方針ずは倖れたす。 共通: Lint 実行順 2026幎4月時点で、create-vue は Oxlint をデフォルトで同梱しおいたす。前述の package.json にある通り、 pnpm lint  run-s lint:* で lint:oxlint → lint:eslint の順に盎列実行されたす。 create-vue 偎では eslint-plugin-oxlint が .oxlintrc.json を読み取り、Oxlint ず重耇する ESLint ルヌルを自動で無効化しおくれたす。 # Vite+ vp run lint # → vp lint . --fix ... Oxlintvp経由 # → eslint . --fix --cache ... ESLint盎接呌び出し # create-vue pnpm lint # → oxlint . --fix ... Oxlint盎接呌び出し # → eslint . --fix --cache ... ESLint盎接呌び出し vp lint は Oxlint だけを実行する組み蟌みコマンドで、ESLint は Vite+ に統合されおいたせん。 そのため、テンプレヌトでは ESLint を eslint コマンドで盎接呌ぶ構成になっおいたす。 Vite+ のタスクランナヌを掻甚したい堎合は、 vite.config.ts の run.tasks に定矩を移行するず良さそうです。 run.tasks で定矩したタスクはデフォルトでキャッシュが有効なため、入力ファむルに倉曎がなければ再実行がスキップされたす。 なお、 run.tasks のタスク名は package.json の scripts ず重耇できないため、移行する堎合は package.json 偎の lint スクリプトを削陀したす。 // package.json の lint 関連スクリプトを run.tasks に移行する䟋 run: { tasks: { lint: { command: 'vp lint . --fix && eslint . --fix --cache' , input: [{ auto : true } , '!.eslintcache' ] , } , } , } , eslint の --cache を䜿うず .eslintcache が曞き出され、 vp run がそれを入力の倉曎ず芋なしおタスクキャッシュがヒットしたせん。 input で '!.eslintcache' を指定し、キャッシュファむルを倉曎怜知の察象倖にするこずで䜵甚できたす。 キャッシュ機胜に぀いおは ESLint ではなくタスクランナヌ偎のもので十分かもしれたせんが、 --cache の有無による差異は今回未怜蚌です。 Linter 比范: Oxlint vs ESLint 怜蚌甚コンポヌネント 怜蚌甚に、意図的に Lint 違反を仕蟌んだ Vue コンポヌネントを甚意したした。 < script setup lang = "ts" > import { ref } from "vue" // unused expression (correctness) const x = 1 x // prefer-as-const (typescript) let y = "hello" as "hello" const items = ref ([ { id : 1 , name : "Apple" } , { id : 2 , name : "Banana" } , ]) </ script > < template > <!-- v-for without :key --> < li v- for = "item in items" > {{ item.name }} </ li > <!-- v-if and v-for on same element --> < div v- for = "item in items" v-if= "item.id > 0" :key= "item.id" > {{ item.name }} </ div > </ template > < style scoped> .unused-class { color : redd; } </ style > Oxlint の結果 # Vite+ vp lint src/components/LintTest.vue x eslint(no-unused-expressions): Expected expression to be used , - [src/components/LintTest.vue: 6 : 1 ] 5 | const x = 1 6 | x : ^ `---- x typescript-eslint(prefer-as-const): Expected a ` const ` assertion instead of a literal type annotation. , - [src/components/LintTest.vue: 9 : 20 ] 8 | // prefer-as-const (typescript) 9 | let y = 'hello' as 'hello' : ^^^^^^^ ` ---- Found 0 warnings and 2 errors. Finished in 369ms on 1 file with 132 rules using 10 threads. # create-vue pnpm exec oxlint -c .oxlintrc.json src/components/LintTest.vue ...同䞀の 2 件 Found 0 warnings and 2 errors. Finished in 24ms on 1 file with 116 rules using 10 threads. Oxlint は <script> 内の違反を怜出したしたが、 <template> / <style> の問題はスルヌされおいたす。Oxlint は .vue ファむルの <script> ブロックしか Lint しないためです。 oxc の互換性ペヌゞ にもある通り、Vue/Svelte/Astro 等のフレヌムワヌクでは script ブロックのみが察象です。 vue プラグむンを有効にしおも、script ブロック内の Vue 関連ルヌルref の䜿い方などしか動きたせん。 SFC テンプレヌトの Lint 察応は oxc#15761 で远跡されおいたすが、ただ実装されおいたせん。 たた、Oxlint には ESLint の JS プラグむンを読み蟌む JS plugins 機胜もありたすが、eslint-plugin-vue は動きたせん。 JS plugins の 制限事項 に「Custom file formats and parsers (e.g. Svelte, Vue, Angular)」は未察応ず明蚘されおいたす。 eslint-plugin-vue はカスタムパヌサヌ vue-eslint-parser で .vue ファむル党䜓をパヌスしおテンプレヌトの AST をルヌルに枡す仕組みのため、この制限に該圓しおいたす。 ルヌル数の差132 vs 116は、 typeAware: true で型情報を䜿ったチェックfloating promise の怜出等が远加されるためです。 なお、Vite+ テンプレヌトの typeCheck: true は Vue プロゞェクトでは実質的に䜿えないようです。 vp lint src/ のようにディレクトリを指定するず .ts ファむルもチェック察象になりたす。 しかし、 .ts から .vue をむンポヌトしおいる箇所で tsgo がモゞュヌル解決に倱敗し TS2307: Cannot find module ゚ラヌが出たす。 䞊の怜蚌でファむルを盎接指定しおいるのはこの問題を回避するためです。 ESLint の結果 # Vite+eslint-plugin-oxlint が機胜しおいない vp exec eslint src/components/LintTest.vue src/components/LintTest.vue 6 : 1 error Expected an assignment or function call and instead saw an expression @typescript-eslint/no-unused-expressions 9 : 5 error 'y' is never reassigned. Use 'const' instead prefer-const 9 : 5 error 'y' is assigned a value but never used @typescript-eslint/no-unused-vars 9 : 20 error Expected a `const` instead of a literal type assertion @typescript-eslint/prefer-as-const 19 : 3 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key 22 : 30 error The 'items' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for ✖ 6 problems ( 6 errors, 0 warnings) # create-vueeslint-plugin-oxlint が正垞動䜜 pnpm exec eslint src/components/LintTest.vue src/components/LintTest.vue 9 : 5 error 'y' is never reassigned. Use 'const' instead prefer-const 9 : 5 error 'y' is assigned a value but never used @typescript-eslint/no-unused-vars 19 : 3 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key 22 : 30 error The 'items' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for ✖ 4 problems ( 4 errors, 0 warnings) Vite+ 偎は Oxlint で怜出されおいる no-unused-expressions ず prefer-as-const も ESLint から報告されお6件。前述の通りルヌル重耇の無効化が効いおいたせん。 create-vue 偎は eslint-plugin-oxlint が正垞動䜜し、Oxlint ずの重耇ルヌルが ESLint 偎で無効化されるため4件。 どちらも、 eslint-plugin-vue により <template> 内の Vue 固有の問題も怜出されおいたす。 CSS/Style Lint に぀いお 怜蚌甚コンポヌネントの <style> に color: redd; ずいうタむポを仕蟌みたしたが、Oxlint でも ESLint でも匕っかかりたせんでした。 どちらのテンプレヌトも CSS の Lint は察象倖のようです。 Vue 公匏のツヌリングガむドの Linting セクション でも案内されおいるのは eslint-plugin-vue による JavaScript/テンプレヌトの Lint だけで、CSS/Style の Lint には觊れおいたせん。 CSS の Lint が必芁なら、これたで同様 Stylelint ず Vue プラグむンを別途入れるこずになりそうです。 型チェックの違い pnpm type-check はどちらも vue-tsc --build で同じです。 Vite+ 偎は vite.config.ts に typeAware: true 型認識 Lint ルヌルの有効化ず typeCheck: true tsgo 経由の型チェック同時実行の蚭定がありたす。 ただし前述の通り tsgo は .vue を読めないため、 .vue の型チェックには匕き続き vue-tsc が必芁です。 テスト どちらも Vitest です。 Vite+ ではむンポヌトパスが 'vitest' から 'vite-plus/test' に、コマンドが vitest から vp test に倉わりたすが、蚭定内容やテストの曞き方は同じです。 Formatter 比范: Oxfmt vs Prettier Oxfmt は Prettier ずの出力互換を謳っおおり、JavaScript/TypeScript の conformance test を 100% パスしおいたす。 Vue SFC のフォヌマット察応 <template> ず <style> もフォヌマットできるのか気になったため、わざず厩した Vue ファむルで詊したした。 <!-- フォヌマット前 --> < template >< div class = "foo" >< p v-if= "true" > hello </ p ></ div ></ template > < style scoped>.foo{ color : red ; font-size : 16px ; display : flex ; justify-content : center }</ style > <!-- フォヌマット埌Oxfmt / Prettier どちらも同䞀の結果 --> < template > < div class = "foo" >< p v-if= "true" > hello </ p ></ div > </ template > < style scoped> .foo { color : red ; font-size : 16px ; display : flex ; justify-content : center ; } </ style > Oxfmt でも Prettier でも <template> ず <style> をフォヌマットでき、出力結果は同䞀でした。乗り換えお問題なさそうです。 公匏ドキュメント によるず Prettier の玄30倍の速床ずのこず。小芏暡プロゞェクトだず䜓感差はありたせんが、倧芏暡プロゞェクトでは差が出そうです。 党䜓比范衚 項目 Vite+ ( vp create vue ) create-vue ( pnpm create vue@latest ) Linter Oxlint ( vp lint ) + ESLint Oxlint + ESLint ESLint 蚭定 同䞀 ただし eslint-plugin-oxlint の修正が必芁 同䞀 Vue template lint ESLint 経由で察応 ESLint 経由で察応 CSS lint なし なし typeCheck tsgo が .vue を読めず実質䜿えない なし テスト Vitest ( vp test ) Vitest Formatter Oxfmt ( vp fmt ) Prettier (Oxfmtも案内される) ビルド Vite ( vp build ) Vite ( vite build ) 蚭定の統合 vite.config.ts に集玄 個別ファむル ( .oxlintrc.json , .prettierrc.json ) Pre-commit フック .vite-hooks/pre-commit → vp staged なし (芁別途蚭定) たずめ vp create vue ず pnpm create vue@latest で生成されるプロゞェクトを比范した結果をたずめたす。 Linter Oxlint は .vue の <script> ブロックしか Lint できない <template> や <style> は察象倖 Vue template の Lint には匕き続き ESLinteslint-plugin-vueが必芁 これは Vite+ でも create-vue でも同じ create-vue は Oxlint をデフォルトで同梱しおいる ESLint 連携の萜ずし穎 Vite+ テンプレヌトでは .oxlintrc.json がマヌゞ埌に削陀されるこずぞの察応が無く、ルヌル重耇の無効化が壊れる vite.config.ts の lint ブロックを import するか、 .oxlintrc.json に䞀本化するこずで察凊できる Lint 実行 どちらも Oxlint → ESLint の盎列実行 型チェック typeCheck: true は Vue プロゞェクトでは実質䜿えない tsgo が .vue をむンポヌトした .ts ファむルで TS2307 ゚ラヌを出すため .vue の型チェックには匕き続き vue-tsc が必芁 Formatter Oxfmt は Prettier ず同䞀の出力 <template> / <style> もフォヌマットできる Prettier からの乗り換えで困るこずはなさそう CSS Lint どちらのテンプレヌトも察象倖 必芁なら Stylelint を別途入れるこずになる Vite+ を遞ぶメリットは Linter/Formatter 単䜓の差分よりも、 vite.config.ts ぞの蚭定䞀元化ず vp コマンドによる統合にありそうでした。 Vue 固有の Lint や型チェックに぀いおはただ ESLint + vue-tsc 頌りなため、Oxlint の Vue テンプレヌト察応や tsgo の .vue サポヌトが敎えば、蚭定が楜になりそうです。 今回はテンプレヌトの蚭定比范だけでしたが、気になるのはやはり実際のプロゞェクトでの速床差です。 次回は Vue ファむルが玄2000個存圚する駅メモのフロント゚ンドで、Lint/Format/ビルドがどれくらい速くなるか実枬しおみたす。お楜しみに
こんにちは、モバファク゚ンゞニアの id:knj-mf です。 今回は TypeScript の型レベルプログラミングでちょっず面癜いものを䜜ったので玹介したいず思いたす。 䜕を䜜ったの TypeScript の型レベルプログラミングは、予想に反しお様々なものが実装できおしたうこずで有名だったりしたす。 type-challenges のように、「これは普通のプログラミングで実装するものでは」ず思っおしたうようなものたで実装できおしたいたす。そこで、䜜っおみたものが䞋蚘になりたす。 早速、動䜜を玹介したす。このような Brainf**k プログラムの文字列型が  このように、型蚈算䞊で解釈されおしたうずいうものです。 ある皋床の圢になるものはできたので、この蚘事では、型レベルプログラミングず曞き味の近い (個人差がありたす) Haskell 実装ず照らしながら、どのように考えおこの「型」を実装しおいったのかを玹介したす。 cwd-k2/bf-in-type のリポゞトリ に実装があるので、気になる方は手元で動䜜や実装を芋おみおください。 Brainf**k たった 8 ぀の呜什からなる難読プログラミング蚀語です。蚀語の仕様ずしおかなり単玔明快ではありたすが、チュヌリング完党ずしお知られおいたす。(ちょっず䌁業の公匏ブログには茉せづらい衚蚘を含むので、今回は ** ずいう颚に䌏せさせおいただきたす ) 芁玠ずしお、次の 4 ぀のものを持ちたす。 芁玠 内容 プログラムテヌプ 実行するプログラム列 メモリテヌプ 倀を蚘録するセルの列 プログラムポむンタ 珟圚参照しおいるプログラム呜什列䞊の䜍眮 メモリポむンタ 珟圚参照しおいるメモリテヌプの䜍眮 8 ぀の呜什は次のような単玔なものです。 呜什 内容 > メモリポむンタをむンクリメント次のセルぞ < メモリポむンタをデクリメント前のセルぞ + 珟圚セルの倀をむンクリメント - 珟圚セルの倀をデクリメント . 珟圚セルの倀を ASCII 文字ずしお出力 , 1 バむト読み蟌み、珟圚セルぞ栌玍 [ 珟圚セルが 0 なら、察応する ] の盎埌ぞゞャンプ ] 珟圚セルが 0 でなければ、察応する [ の盎埌ぞゞャンプ ざっくり、プログラムテヌプ䞊に蚘茉された 8 ぀の呜什の列を順次実行しながらメモリテヌプの倀を曞き換え぀぀、適宜 I/O しおいく圢のプログラミング蚀語になりたす。 実際の Brainf**k プログラムそのものはたったく実甚性がないのですが、この簡単な呜什セットからなる蚀語凊理系の実装には教育的䟡倀がありたす。結構曞いおみたこずがあるずいう゚ンゞニアの方も倚いのではないでしょうか。 TypeScript の型レベルプログラミング ずころで、TypeScript には (TypeScript に限りたせんが) 型レベルプログラミングがありたす。本圓に単玔な䟋だず、䞋蚘のようなものです。 type ExtendsObject < T > = T extends object ? true : false これが䜕をしおいるのかずいうず、型チェックの際に実斜される型蚈算を実装しおいるずいうこずです。䞊蚘のような条件分岐などのロゞックが型レベルで解決されおしたうずいうこずですね。 この型レベルプログラミングなのですが、衚珟力はさおおき、チュヌリング完党な系になっおしたっおいるずのもっぱらの評刀です。 型から型を新たに蚈算できおしたうずいうこずは  楜しいプログラミングの時間の始たりですね。 実装方針 長くなっおしたうので、以降では Brainf**k を BF ず蚘茉するこずにしたす。 BF 凊理系を型レベルに萜ずし蟌むにあたっお、次の 4 ぀の芁玠に分けお考えたす。 テヌプ構造䜓 ( Tape ) — メモリ・プログラムを共通しお衚珟するデヌタ構造 珟圚䜍眮を持ち぀぀、前埌に移動する胜力を持぀ 評䟡噚 ( Runner ) — メモリテヌプずプログラムテヌプを束ねた実行状態 メモリを倉化させ぀぀プログラムポむンタを移動するため、同時に扱う アクション ( Action ) — 1 ステップ実行の結果ずしお倖界に芁求する効果 (なにもしない / 入力 / 出力 / 終了) 評䟡ルヌプ ( Exec ) — アクションを解釈しお評䟡噚を回し、入力を消費し぀぀出力を蓄積するメむンルヌプ 型レベルプログラミングでは副䜜甚を玠盎に曞けないため、入出力を「アクション型」ずしおデヌタに萜ずしおおき、倖偎のルヌプでそれを解釈する圢にしたのがポむントです。以降、この順で各芁玠の実装を芋おいきたす。 たた、適宜参考実装ずしお Haskell の実装も合わせお瀺しおいたす。 TypeScript 実装は v5.4 以降で動䜜確認しおいたす。 実装䞊の制玄 制玄ずしお、実装レベルに効いおくるものもありたす。数倀での挔算や数倀⇔文字の倉換が基本的にできない、ずいうものです。䞍可胜ではないですが、タプル (型レベル配列) の length を取るような実装になりがちなのでたわりくどくなりたす。 今回は ASCII 範囲でむンクリメント・デクリメントを考えるだけなので、気合いで誀魔化すこずができたす。 NumToCharMap[65] のように参照するず 'A' ずいう型に解決される、ずいうマップを定矩したした。 数倀文字倉換、むンクリメント・デクリメントマップの実装 export type NumToCharMap = [ '\x00' , '\x01' , '\x02' , '\x03' , '\x04' , '\x05' , '\x06' , '\x07' , '\x08' , '\x09' , '\x0A' , '\x0B' , '\x0C' , '\x0D' , '\x0E' , '\x0F' , '\x10' , '\x11' , '\x12' , '\x13' , '\x14' , '\x15' , '\x16' , '\x17' , '\x18' , '\x19' , '\x1A' , '\x1B' , '\x1C' , '\x1D' , '\x1E' , '\x1F' , '\x20' , '\x21' , '\x22' , '\x23' , '\x24' , '\x25' , '\x26' , '\x27' , '\x28' , '\x29' , '\x2A' , '\x2B' , '\x2C' , '\x2D' , '\x2E' , '\x2F' , '\x30' , '\x31' , '\x32' , '\x33' , '\x34' , '\x35' , '\x36' , '\x37' , '\x38' , '\x39' , '\x3A' , '\x3B' , '\x3C' , '\x3D' , '\x3E' , '\x3F' , '\x40' , '\x41' , '\x42' , '\x43' , '\x44' , '\x45' , '\x46' , '\x47' , '\x48' , '\x49' , '\x4A' , '\x4B' , '\x4C' , '\x4D' , '\x4E' , '\x4F' , '\x50' , '\x51' , '\x52' , '\x53' , '\x54' , '\x55' , '\x56' , '\x57' , '\x58' , '\x59' , '\x5A' , '\x5B' , '\x5C' , '\x5D' , '\x5E' , '\x5F' , '\x60' , '\x61' , '\x62' , '\x63' , '\x64' , '\x65' , '\x66' , '\x67' , '\x68' , '\x69' , '\x6A' , '\x6B' , '\x6C' , '\x6D' , '\x6E' , '\x6F' , '\x70' , '\x71' , '\x72' , '\x73' , '\x74' , '\x75' , '\x76' , '\x77' , '\x78' , '\x79' , '\x7A' , '\x7B' , '\x7C' , '\x7D' , '\x7E' , '\x7F' , ] & { [ i: number ] : ' \x00 ' } ; export type CharToNumMap = { '\x00' : 0 x00 , '\x01' : 0 x01 , '\x02' : 0 x02 , '\x03' : 0 x03 , '\x04' : 0 x04 , '\x05' : 0 x05 , '\x06' : 0 x06 , '\x07' : 0 x07 , '\x08' : 0 x08 , '\x09' : 0 x09 , '\x0A' : 0 x0A , '\x0B' : 0 x0B , '\x0C' : 0 x0C , '\x0D' : 0 x0D , '\x0E' : 0 x0E , '\x0F' : 0 x0F , '\x10' : 0 x10 , '\x11' : 0 x11 , '\x12' : 0 x12 , '\x13' : 0 x13 , '\x14' : 0 x14 , '\x15' : 0 x15 , '\x16' : 0 x16 , '\x17' : 0 x17 , '\x18' : 0 x18 , '\x19' : 0 x19 , '\x1A' : 0 x1A , '\x1B' : 0 x1B , '\x1C' : 0 x1C , '\x1D' : 0 x1D , '\x1E' : 0 x1E , '\x1F' : 0 x1F , '\x20' : 0 x20 , '\x21' : 0 x21 , '\x22' : 0 x22 , '\x23' : 0 x23 , '\x24' : 0 x24 , '\x25' : 0 x25 , '\x26' : 0 x26 , '\x27' : 0 x27 , '\x28' : 0 x28 , '\x29' : 0 x29 , '\x2A' : 0 x2A , '\x2B' : 0 x2B , '\x2C' : 0 x2C , '\x2D' : 0 x2D , '\x2E' : 0 x2E , '\x2F' : 0 x2F , '\x30' : 0 x30 , '\x31' : 0 x31 , '\x32' : 0 x32 , '\x33' : 0 x33 , '\x34' : 0 x34 , '\x35' : 0 x35 , '\x36' : 0 x36 , '\x37' : 0 x37 , '\x38' : 0 x38 , '\x39' : 0 x39 , '\x3A' : 0 x3A , '\x3B' : 0 x3B , '\x3C' : 0 x3C , '\x3D' : 0 x3D , '\x3E' : 0 x3E , '\x3F' : 0 x3F , '\x40' : 0 x40 , '\x41' : 0 x41 , '\x42' : 0 x42 , '\x43' : 0 x43 , '\x44' : 0 x44 , '\x45' : 0 x45 , '\x46' : 0 x46 , '\x47' : 0 x47 , '\x48' : 0 x48 , '\x49' : 0 x49 , '\x4A' : 0 x4A , '\x4B' : 0 x4B , '\x4C' : 0 x4C , '\x4D' : 0 x4D , '\x4E' : 0 x4E , '\x4F' : 0 x4F , '\x50' : 0 x50 , '\x51' : 0 x51 , '\x52' : 0 x52 , '\x53' : 0 x53 , '\x54' : 0 x54 , '\x55' : 0 x55 , '\x56' : 0 x56 , '\x57' : 0 x57 , '\x58' : 0 x58 , '\x59' : 0 x59 , '\x5A' : 0 x5A , '\x5B' : 0 x5B , '\x5C' : 0 x5C , '\x5D' : 0 x5D , '\x5E' : 0 x5E , '\x5F' : 0 x5F , '\x60' : 0 x60 , '\x61' : 0 x61 , '\x62' : 0 x62 , '\x63' : 0 x63 , '\x64' : 0 x64 , '\x65' : 0 x65 , '\x66' : 0 x66 , '\x67' : 0 x67 , '\x68' : 0 x68 , '\x69' : 0 x69 , '\x6A' : 0 x6A , '\x6B' : 0 x6B , '\x6C' : 0 x6C , '\x6D' : 0 x6D , '\x6E' : 0 x6E , '\x6F' : 0 x6F , '\x70' : 0 x70 , '\x71' : 0 x71 , '\x72' : 0 x72 , '\x73' : 0 x73 , '\x74' : 0 x74 , '\x75' : 0 x75 , '\x76' : 0 x76 , '\x77' : 0 x77 , '\x78' : 0 x78 , '\x79' : 0 x79 , '\x7A' : 0 x7A , '\x7B' : 0 x7B , '\x7C' : 0 x7C , '\x7D' : 0 x7D , '\x7E' : 0 x7E , '\x7F' : 0 x7F , } & { [ k : string ]: 0 x00 ; } ; export type DecrementMap = [ 0 x7F , 0 x00 , 0 x01 , 0 x02 , 0 x03 , 0 x04 , 0 x05 , 0 x06 , 0 x07 , 0 x08 , 0 x09 , 0 x0A , 0 x0B , 0 x0C , 0 x0D , 0 x0E , 0 x0F , 0 x10 , 0 x11 , 0 x12 , 0 x13 , 0 x14 , 0 x15 , 0 x16 , 0 x17 , 0 x18 , 0 x19 , 0 x1A , 0 x1B , 0 x1C , 0 x1D , 0 x1E , 0 x1F , 0 x20 , 0 x21 , 0 x22 , 0 x23 , 0 x24 , 0 x25 , 0 x26 , 0 x27 , 0 x28 , 0 x29 , 0 x2A , 0 x2B , 0 x2C , 0 x2D , 0 x2E , 0 x2F , 0 x30 , 0 x31 , 0 x32 , 0 x33 , 0 x34 , 0 x35 , 0 x36 , 0 x37 , 0 x38 , 0 x39 , 0 x3A , 0 x3B , 0 x3C , 0 x3D , 0 x3E , 0 x3F , 0 x40 , 0 x41 , 0 x42 , 0 x43 , 0 x44 , 0 x45 , 0 x46 , 0 x47 , 0 x48 , 0 x49 , 0 x4A , 0 x4B , 0 x4C , 0 x4D , 0 x4E , 0 x4F , 0 x50 , 0 x51 , 0 x52 , 0 x53 , 0 x54 , 0 x55 , 0 x56 , 0 x57 , 0 x58 , 0 x59 , 0 x5A , 0 x5B , 0 x5C , 0 x5D , 0 x5E , 0 x5F , 0 x60 , 0 x61 , 0 x62 , 0 x63 , 0 x64 , 0 x65 , 0 x66 , 0 x67 , 0 x68 , 0 x69 , 0 x6A , 0 x6B , 0 x6C , 0 x6D , 0 x6E , 0 x6F , 0 x70 , 0 x71 , 0 x72 , 0 x73 , 0 x74 , 0 x75 , 0 x76 , 0 x77 , 0 x78 , 0 x79 , 0 x7A , 0 x7B , 0 x7C , 0 x7D , 0 x7E , ] & { [ i: number ] : 0x7F ; } ; export type IncrementMap = [ 0 x01 , 0 x02 , 0 x03 , 0 x04 , 0 x05 , 0 x06 , 0 x07 , 0 x08 , 0 x09 , 0 x0A , 0 x0B , 0 x0C , 0 x0D , 0 x0E , 0 x0F , 0 x10 , 0 x11 , 0 x12 , 0 x13 , 0 x14 , 0 x15 , 0 x16 , 0 x17 , 0 x18 , 0 x19 , 0 x1A , 0 x1B , 0 x1C , 0 x1D , 0 x1E , 0 x1F , 0 x20 , 0 x21 , 0 x22 , 0 x23 , 0 x24 , 0 x25 , 0 x26 , 0 x27 , 0 x28 , 0 x29 , 0 x2A , 0 x2B , 0 x2C , 0 x2D , 0 x2E , 0 x2F , 0 x30 , 0 x31 , 0 x32 , 0 x33 , 0 x34 , 0 x35 , 0 x36 , 0 x37 , 0 x38 , 0 x39 , 0 x3A , 0 x3B , 0 x3C , 0 x3D , 0 x3E , 0 x3F , 0 x40 , 0 x41 , 0 x42 , 0 x43 , 0 x44 , 0 x45 , 0 x46 , 0 x47 , 0 x48 , 0 x49 , 0 x4A , 0 x4B , 0 x4C , 0 x4D , 0 x4E , 0 x4F , 0 x50 , 0 x51 , 0 x52 , 0 x53 , 0 x54 , 0 x55 , 0 x56 , 0 x57 , 0 x58 , 0 x59 , 0 x5A , 0 x5B , 0 x5C , 0 x5D , 0 x5E , 0 x5F , 0 x60 , 0 x61 , 0 x62 , 0 x63 , 0 x64 , 0 x65 , 0 x66 , 0 x67 , 0 x68 , 0 x69 , 0 x6A , 0 x6B , 0 x6C , 0 x6D , 0 x6E , 0 x6F , 0 x70 , 0 x71 , 0 x72 , 0 x73 , 0 x74 , 0 x75 , 0 x76 , 0 x77 , 0 x78 , 0 x79 , 0 x7A , 0 x7B , 0 x7C , 0 x7D , 0 x7E , 0 x7F , 0 x00 , ] & { [ i: number ] : 0x00 ; } ; テヌプ構造䜓 BF では、メモリを甚意しおポむンタ操䜜・ポむンタを介した操䜜が前提になっおいたす。 もちろん型レベルプログラミングで副䜜甚は蚘述しにくいため、ポむンタ前提ずなっおいる郚分を再考し、同じ衚珟力の別の圢に眮き換える必芁がありたす。 メモリ、プログラムを同じテヌプ構造で捉えたす。今着目しおいる倀、その巊右に列が続いおいる様子を考えたのが䞋蚘のような構造になりたす。 テヌプ構造䜓の実装 このような構造䜓は、Haskell での data 宣蚀ず同じような圢で、TypeScript の型ではオブゞェクト型による宣蚀ができたす。 data Tape a = Tape { prevs :: [a] , curr :: a , nexts :: [a] } extends unknown[] によっお単なる配列型ではなく、各芁玠が独立した 型レベル配列ずしおのタプル を利甚できたす。 export type Tape < Hs extends unknown [], C , Ts extends unknown []> = { h : Hs c : C t : Ts } ここでいく぀かの基本的な操䜜も定矩しおしたいたしょう。 珟圚の倀に察する操䜜 むンクリメント・デクリメント 読み出し、曞き蟌み テヌプ䞊の移動 着目するヘッドを巊右に移動する操䜜 察応する [ , ] ぞのゞャンプは繰り返しによっお実珟する 基本操䜜の実装 Tape a から新しい Tape a を䜜る ( Tape a -> Tape a ) ずいう圢の実装ずなりたす。 -- | 次の芁玠に移動 next :: Tape a -> Tape a next (Tape prevs curr (n : nexts)) = Tape (curr : prevs) n nexts -- | 前の芁玠に移動 prev :: Tape a -> Tape a prev (Tape (p : prevs) curr nexts) = Tape prevs p (curr : nexts) -- | 珟圚の芁玠をむンクリメント incr :: Enum a => Tape a -> Tape a incr (Tape prevs curr nexts) = Tape prevs (succ curr) nexts -- | 珟圚の芁玠をデクリメント decr :: Enum a => Tape a -> Tape a decr (Tape prevs curr nexts) = Tape prevs (pred curr) nexts -- | 珟圚の芁玠を取埗 get :: Tape a -> a get (Tape _ curr _) = curr -- | 珟圚の芁玠を蚭定 put :: a -> Tape a -> Tape a put a (Tape prevs _ nexts) = Tape prevs a nexts TypeScript の型でも同様に、 Tape を受け取っお新しい Tape を䜜成するずいう方針で実装できたす。 [infer H, ...infer Hs] のパタヌンマッチングにより、型レベル配列の芁玠 (head, rest) を扱うこずができおしたいたす。 export type Prev < M > = M extends Tape < [infer H , ... infer Hs] , infer C , infer Ts > ? Tape< Hs , H , [C , ... Ts] > : never export type Next < M > = M extends Tape < infer Hs , infer C , [infer T , ... infer Ts] > ? Tape< [C , ... Hs] , T , Ts > : never export type Incr < M > = M extends Tape < infer Hs , infer C extends number , infer Ts > ? Tape< Hs , IncrementMap [C], Ts > : never export type Decr < M > = M extends Tape < infer Hs , infer C extends number , infer Ts > ? Tape< Hs , DecrementMap [C], Ts > : never export type PutC < M , C > = M extends Tape < infer Hs , unknown , infer Ts > ? Tape < Hs , C , Ts > : never プログラム実行 基本的な構造、操䜜は定矩しおしたったので、次はむンタプリタずしお重芁な実行に぀いお考えたす。 評䟡噚ずしおの実行系内郚 (メモリ・プログラムポむンタ) ず倖界ずのやりずりを含む効果の管理の郚分を、次のような圢で切り分けたす。 型レベルプログラミングでは入出力をそのたた扱うこずはできないので、入力埅ちや出力があるずいうこずは特別な状態ずしお衚珟するこずにしたす。 評䟡噚の内郚状態 こちらは至っおシンプルです。 状態はメモリ、プログラムのテヌプ (珟圚䜍眮を保持する) から成る これを評䟡に通すこずによっお、次の実行に関する状態が出おくる data Machine = Machine { memory :: DT.Tape Int , program :: DT.Tape Char } type Runner < M , P > = { mem : M prg : P } 倖郚ずのやりずりを含むアクション 今のメモリ・プログラムを含む、先皋の構造を評䟡しお埗られるアクションです。 -- | 䜕もしない、入力芁求、出力芁求、終了の 4 ぀のアクションを持぀ data WithAction a = ActionN { hold :: a } -- ^ 倖郚には䜕もしない | ActionI { hold :: a } -- ^ 入力芁求 | ActionO { hold :: a, out :: Int } -- ^ 出力芁求 | ActionE -- ^ 終了 これを型レベルプログラミングで再珟するず、ADT よりは個別の型ずしお定矩しおあげお、埌で extends などの条件分岐しおあげる方が玠盎になりたす。 type ActionN < R > = { action : "N" ; runner : R } type ActionI < R > = { action : "I" ; runner : R } type ActionO < R , O > = { action : "O" ; runner : R ; output : O } type ActionE = { action : "E" } 8 ぀の呜什に察する操䜜の敎理 評䟡噚の状態ずアクションを型ずしお定矩できたので、次はプログラムの瀺す呜什を凊理しおいく実装も考えおいきたす。 これは最初に確認した BF の 8 ぀の呜什に察しお、次の評䟡噚の状態ず蚈算の効果を含む党䜓を返す圢で定矩しおいけば良いです。 むンクリメント デクリメント 次を参照 (ポむンタむンクリメント) 前を参照 (ポむンタデクリメント) while (ゞャンプ) while end (ゞャンプバック) getchar putchar 呜什→次の状態・アクション さお、図で敎理できたので、実装にそのたた萜ずしおいきたす。 珟圚の呜什ポむンタが指す呜什に応じお、次の Action ず状態を返したす。 -- | 次のステップを実行し、状態ずアクションを返す step :: Machine -> WithAction Machine step machine = case pc of '+' -> ActionN $ machine { memory = DT.incr (memory machine), program = DT.next (program machine) } '-' -> ActionN $ machine { memory = DT.decr (memory machine), program = DT.next (program machine) } '>' -> ActionN $ machine { memory = DT.next (memory machine), program = DT.next (program machine) } '<' -> ActionN $ machine { memory = DT.prev (memory machine), program = DT.next (program machine) } '[' -> ActionN $ machine { program = if mc == 0 then skip (program machine) else DT.next (program machine) } ']' -> ActionN $ machine { program = if mc /= 0 then back (program machine) else DT.next (program machine) } ',' -> ActionI { hold = machine { program = DT.next (program machine) } } '.' -> ActionO { hold = machine { program = DT.next (program machine) }, out = DT.get (memory machine) } _ -> ActionE where (pc, mc) = (,) <$> DT.get . program <*> DT.get . memory $ machine TypeScript で曞いおも、ほずんど同じ察応がありたす。 type Step < R > = R extends Runner < infer M extends TapeMm , infer P extends TapePg > ? P[ 'c' ] extends '+' ? ActionN< Runner < Incr < M >, Next < P >>> : P[ 'c' ] extends '-' ? ActionN< Runner < Decr < M >, Next < P >>> : P[ 'c' ] extends '>' ? ActionN< Runner < Next < M >, Next < P >>> : P[ 'c' ] extends '<' ? ActionN< Runner < Prev < M >, Next < P >>> : P[ 'c' ] extends '[' ? ActionN< Runner < M , M [ 'c' ] extends 0 ? Skip < P > : Next < P >>> : P[ 'c' ] extends ']' ? ActionN< Runner < M , M [ 'c' ] extends 0 ? Next < P > : Back < P >>> : P[ 'c' ] extends ',' ? ActionI< Runner < M , Next < P >>> : P[ 'c' ] extends '.' ? ActionO< Runner < M , Next < P >>, M [ 'c' ]> : ActionE : never; 状態・アクション→継続 次は状態、アクションを受けお、次のステップに継続しおいくルヌプを実装しおいきたす。 䞊蚘の step を実行し、その Action に応じた操䜜を実行しおいきたす。 -- | 入力を消費・出力を収集しながら step を繰り返す loop :: (Machine -> WithAction Machine) -> (String, Machine) -> String loop step (input, machine) = go (step machine) where -- アクションに察応した動䜜を実行し、再垰に進む go (ActionN machine') = loop step (input, machine') -- そのたた次ぞ go (ActionI machine') = loop step (iTail, machine'') where -- 入力を消費しおメモリに曞き蟌み、次に進む (iHead : iTail) = input machine'' = machine' { memory = DT.put (fromEnum iHead) (memory machine') } go (ActionO machine' out) = toEnum out : loop step (input, machine') -- 出力を収集し、次に進む go ActionE = [] -- 終端 TypeScript の型の方では、今回は文字列の环積を保持する圢で実装しおいたす。ちょっず呜名が異なっおしたっおいたすが、やっおいるこずは同じです。 type Exec < R , I extends string , O extends string = '' > = Step < R > extends infer WithAction ? WithAction extends ActionN< infer Q > ? Exec< Q , I , O > : WithAction extends ActionI< infer Q > ? I extends ` ${ infer F }${ infer S } ` ? Exec< Read < Q , CharToNumMap [F]>, S , O > : Exec< Read < Q , 0>, I , O > : WithAction extends ActionO< infer Q , infer N extends number > ? Exec< Q , I , ` ${ O }${ NumToCharMap [N] } ` > : WithAction extends ActionE ? O : never : never; たずめ TypeScript で Brainf**k 凊理系の型レベルプログラムの実装に぀いお芋おいきたした。 補足ずしお、TypeScript の型レベルプログラミング実行系には次のような制玄がありたす。 型の再垰評䟡回数、぀たり実行できるステップ数が制限されおいる Tape 構造䜓の保持する芁玠列の長さに制限がある (どちらも倧䜓 1,000 皋床のむメヌゞ) 䞀方、このような制限がある䞭でも、冒頭に瀺した䟋のように簡単な Hello World の䟋たでは実装できおしたいたす。 みなさんもぜひ自分の型レベルプログラミングに挑戊しおみおください。 私が今回瀺した実装も最善ではないず思いたす。「もっず良いものを曞いおみよう」など、楜しんでみおください。 付録 Haskell のコヌド党文を掲茉しおおきたす。 cwd-k2/bf-in-type のリポゞトリ ず比范する、たたは手元でテスト実行するなどしおください。 ディレクトリ構成 . ├── Data │   └── Tape.hs ├── Interpreter.hs └── Main.hs Data/Tape.hs module Data.Tape ( Tape( .. ), zeros, fromList, next, prev, incr, decr, get, put, ) where -- | テヌプ様構造䜓 -- * 前埌に無限に芁玠があり、珟圚芁玠 (針の先にあるもの) を䞭心に配眮しおいる -- -- > <-prev- ... 4 5 6 <<7>> 8 9 10 ... -next-> data Tape a = Tape { prevs :: [a] , curr :: a , nexts :: [a] } deriving Show -- | れロ初期化された無限長のテヌプ zeros :: Enum a => Tape a zeros = Tape (repeat $ toEnum 0 ) (toEnum 0 ) (repeat $ toEnum 0 ) -- | リストからテヌプを䜜成 fromList :: [a] -> Tape a fromList (x : xs) = Tape [] x xs fromList [] = undefined -- 今回は特に考えずに未定矩ずする -- | 次の芁玠に移動 next :: Tape a -> Tape a next (Tape prevs curr (n : nexts)) = Tape (curr : prevs) n nexts -- | 前の芁玠に移動 prev :: Tape a -> Tape a prev (Tape (p : prevs) curr nexts) = Tape prevs p (curr : nexts) -- | 珟圚の芁玠をむンクリメント incr :: Enum a => Tape a -> Tape a incr (Tape prevs curr nexts) = Tape prevs (succ curr) nexts -- | 珟圚の芁玠をデクリメント decr :: Enum a => Tape a -> Tape a decr (Tape prevs curr nexts) = Tape prevs (pred curr) nexts -- | 珟圚の芁玠を取埗 get :: Tape a -> a get (Tape _ curr _) = curr -- | 珟圚の芁玠を蚭定 put :: a -> Tape a -> Tape a put a (Tape prevs _ nexts) = Tape prevs a nexts Interpreter.hs module Interpreter ( bf ) where import qualified Data.Tape as DT import Data.List (unfoldr) -- | メモリずプログラムを持぀ data Machine = Machine { memory :: DT.Tape Int , program :: DT.Tape Char } deriving Show -- | 䜕もしない、入力芁求、出力芁求、終了の 4 ぀のアクションを持぀ data WithAction a = ActionN { hold :: a } -- ^ 倖郚には䜕もしない | ActionI { hold :: a } -- ^ 入力芁求 | ActionO { hold :: a, out :: Int } -- ^ 出力芁求 | ActionE -- ^ 終了 deriving Show -- | 察応する @']'@ たでプログラムをスキップする skip :: DT.Tape Char -> DT.Tape Char skip = skipInner 0 where skipInner n program = let program' = DT.next program in case DT.get program' of '[' -> skipInner (n + 1 ) program' ']' -> if n == 0 then program' else skipInner (n - 1 ) program' _ -> skipInner n program' -- | 察応する @'['@ たでプログラムを戻す back :: DT.Tape Char -> DT.Tape Char back = backInner 0 where backInner n program = let program' = DT.prev program in case DT.get program' of ']' -> backInner (n + 1 ) program' '[' -> if n == 0 then program' else backInner (n - 1 ) program' _ -> backInner n program' -- | 次のステップを実行し、状態ずアクションを返す step :: Machine -> WithAction Machine step machine = case pc of '+' -> ActionN $ machine { memory = DT.incr (memory machine), program = DT.next (program machine) } '-' -> ActionN $ machine { memory = DT.decr (memory machine), program = DT.next (program machine) } '>' -> ActionN $ machine { memory = DT.next (memory machine), program = DT.next (program machine) } '<' -> ActionN $ machine { memory = DT.prev (memory machine), program = DT.next (program machine) } '[' -> ActionN $ machine { program = if mc == 0 then skip (program machine) else DT.next (program machine) } ']' -> ActionN $ machine { program = if mc /= 0 then back (program machine) else DT.next (program machine) } ',' -> ActionI { hold = machine { program = DT.next (program machine) } } '.' -> ActionO { hold = machine { program = DT.next (program machine) }, out = DT.get (memory machine) } _ -> ActionE where (pc, mc) = (,) <$> DT.get . program <*> DT.get . memory $ machine -- | 入力を消費・出力を収集しながら step を繰り返す loop :: (Machine -> WithAction Machine) -> (String, Machine) -> String loop step (input, machine) = go (step machine) where -- アクションに察応した動䜜を実行し、再垰に進む go (ActionN machine') = loop step (input, machine') -- そのたた次ぞ go (ActionI machine') = loop step (iTail, machine'') where -- 入力を消費しおメモリに曞き蟌み、次に進む (iHead : iTail) = input machine'' = machine' { memory = DT.put (fromEnum iHead) (memory machine') } go (ActionO machine' out) = toEnum out : loop step (input, machine') -- 出力を収集し、次に進む go ActionE = [] -- 終端 -- | Bf プログラムから、入力を受け取っお出力を返す関数を䜜る bf :: String -> [Char] -> String bf program input = loop step (input', machine) where input' = input ++ repeat ' \0 ' machine = Machine { memory = DT.zeros , program = DT.next $ DT.fromList ( "#" ++ program ++ "#" ) } Main.hs module Main where import Interpreter -- | ハロヌワヌルドする Bf プログラム helloWorld :: String helloWorld = "++++++++++[>+++++++>++++++++++>+++++++++++>+++>+++++++++>+<<<<<<-]>++.>+.>--..+++.>++.>---.<<.+++.------.<-.>>+.>>." -- | ゚コヌする Bf プログラム echo :: String echo = "+[,.]" main :: IO () main = do let getOutputBf = bf helloWorld putStr $ getOutputBf "こんにちは \n "
皆さた、こんにちは 駅メモ開発チヌム゚ンゞニアの id:szeto です。 今回は、毎月行う報酬配垃䜜業に぀いお、これたで行っおいた本番環境のCLIでのスクリプト実行から、管理画面運営が駅メモのゲヌム蚭定を閲芧・曎新できるシステムの操䜜に倉曎した事䟋を皆さたに共有したいず思いたす。この取り組みのおかげで、運甚効率が玄66%改善されたした これたでは本番サヌバヌにSSHでログむンし、スクリプトを実行しおいたしたが、Webブラりザから安党に、いく぀かのクリックで操䜜できるように改善したした。この蚘事では、その背景、実装方法、そしお埗られた効果に぀いおご玹介したす。 目次 目次 背景・圓時の課題 埓来の運甚フロヌ 具䜓的な課題 解決アプロヌチ 改善方針の怜蚎 UI化の基本方針 期埅される効果 実装詳现 UI蚭蚈 ワヌクフロヌ 実装で遭遇した課題ず察応 課題1: 配垃察象者数が倚く画面衚瀺に課題 課題2: 本実行結果の衚瀺によるブラりザのパフォヌマンス問題 バック゚ンド実装 API蚭蚈 運甚・効果枬定 たずめ 背景・圓時の課題 駅メモでは、特定のむベント圢匏にランキング芁玠があるため、むベント終了埌に䞊䜍プレむダヌの皆さたぞ報酬配垃を行っおいたす。埓来、この䜜業は本番環境で゚ンゞニアが盎接CLIでスクリプト実行により実斜しおいたした。 埓来の運甚フロヌ 埓来の䜜業フロヌは、ドキュメント䜜成から䜜業の芋守り募集、DBバックアップ、本番サヌバヌのCLIでのスクリプト実行、ログ確認、告知䜜成たで、倚くのステップず時間を芁しおいたした。 【改善前】本番サヌバヌのCLIでスクリプト実行 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. ドキュメント管理サむトで手順曞䜜成 2. 䜜業の芋守り募集 3. DBスナップショット䜜成 (x3) ⏱ 15分 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4. 本番サヌバヌにSSH接続 5. CLIでのスクリプト実行 ⚠ ヒュヌマン゚ラヌリスク $ script1 --dry-run $ script2 --dry-run 6. 結果確認 7. 本番実行 ⚠ ヒュヌマン゚ラヌリスク $ script1 --execute $ script2 --execute 8. ログ確認・アヌカむブ ⏱ 75分 x 2人 = 150分 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9. 告知文章䜜成 10. レビュヌ・公開 ⏱ 25分 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 合蚈: 190分 (箄3時間10分) 具䜓的な課題 この運甚方法には、いく぀かの課題がありたした。 たず、操䜜の蚘録に぀いおです。SSHによる本番サヌバヌぞの盎接ログむンが必芁で、操䜜ログの閲芧に手間がかかり、埌から芋返しづらい状況でした。 次に、ヒュヌマン゚ラヌのリスクです。本番環境でスクリプトを実行する前には、パラメヌタやコマンドの内容を䜕床も確認する必芁があり、1぀のミスも蚱されないずいう倧きな責任ずプレッシャヌが垞に぀きたずっおいたした。 そしお䜜業効率の問題です。 特に以䞋の䜜業に手間がかかっおいたした。 DBバックアップ 3プラットフォヌムコロプラ版駅メモ・駅メモ・アワメモそれぞれでAWSマネゞメントコン゜ヌルを開いお手動操䜜が必芁でした。各プラットフォヌムごずにコン゜ヌルを開き、スナップショット䜜成を実行し、完了するたで画面を確認し続ける ずいう䜜業を3回繰り返しおいたした。完了通知もないため、定期的にコン゜ヌルを確認する必芁があり、埅ち時間が発生しおいたした。 CLIでのスクリプト実行 察象むベントや配垃環境の指定、ログファむルの䜜成など、すべお手動でコマンドに入力する必芁がありたした。本番環境での実行のため、実行前に䜕回もコマンドを再確認する必芁があり、たた手動操䜜でのミスを防ぐため同時実行が基本犁止ずなっおおり、スクリプト実行だけで毎回75分 x 2人ずいう䜜業時間がかかっおいたした。 告知文章䜜成 報酬配垃埌、毎回お知らせ文章を手動で䜜成し、レビュヌ・公開する䜜業が必芁でした。 これらの課題により、運甚担圓者の負担も倧きく、より安党か぀䜜業負荷を軜枛できる仕組みが求められおいたした。 解決アプロヌチ これらの課題を解決するため、報酬配垃䜜業を管理画面から実行できるようにする方針を立おたした。これにより、゚ンゞニアだけでなく、プランナヌも安党に䜜業を実行できるこずを目指したした。 改善方針の怜蚎 改善方針を怜蚎したした。 1぀目は報酬配垃専甚のスタンドアロンツヌルを開発する案です。しかしこれは認蚌基盀などを新芏に構築する必芁が生じたす。2぀目は既存の管理画面に機胜を远加する方法です。 たた、プランナヌから「自分たちで報酬配垃を実行できるようにしたい」ずいう芁望がありたした。実珟できれば、゚ンゞニアの䜜業時間をほがれロにするこずも可胜になりたす。 怜蚎の結果、管理画面ぞの統合を採甚したした。理由は、たず゚ンゞニアの䜜業効率化から始め、将来的にプランナヌぞの暩限開攟も怜蚎できるずいう段階的な改善が可胜なためです。たた、既存の認蚌・認可機胜を掻甚できるため新芏にセキュリティ基盀を構築する必芁がない点も倧きな決め手ずなりたした。 UI化の基本方針 たず、報酬配垃に関連する自動化機胜ずしお、DBバックアップを実行するSlackワヌクフロヌを䜜成したした。埓来は3プラットフォヌムそれぞれでAWSコン゜ヌルを開いお手動操䜜しおいたしたが、Slackワヌクフロヌから1回の操䜜で3プラットフォヌム党おのバックアップを実行できるようになりたした。ワヌクフロヌが裏偎でAWS APIを呌び出しおスナップショットを䜜成し、完了するずSlackに通知が届きたす。実行状況ず結果はログずしお保存されたす。 次に、管理画面に以䞋の機胜を远加したした。 ドラむラン機胜を実装したした。実行前に配垃察象者ず配垃アむテムを確認でき、既存スクリプトの暙準出力ず同等の内容を衚瀺したす。プランナヌでも理解できる圢匏にしたした。 本実行機胜では、ドラむランの結果を確認埌に本実行ボタンを有効化したす。実行ログはJSON圢匏でダりンロヌド可胜で、Slack通知機胜も備えおいたす。 たた、埓来は耇数のスクリプトに分かれおいた報酬配垃䜜業を1぀の機胜に統合したした。 最埌に、報酬を配垃した埌にお知らせを非公開状態で自動䜜成する機胜を远加したした。テンプレヌト文蚀を䜿甚するため、プランナヌはレビュヌ・公開のみ実斜すれば䜜業は完了です。 期埅される効果 この改善により、以䞋の工数削枛を芋蟌んでいたした。 䜜業項目 改善前 改善埌 削枛 ゚ンゞニア準備 15分 0分 -15分 ゚ンゞニアx2実行 150分 60分 -90分 プランナヌ告知 25分 5分 -20分 合蚈 190分 65分 -125分玄66%削枛 【改善埌】管理画面でUI操䜜 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. Slackワヌクフロヌでバックアップ実行 ⏱ 自動化 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. 管理画面にアクセス ✅ SSH䞍芁 3. むベント遞択 4. [ドラむラン実行] クリック ✅ 誀操䜜防止 5. 画面で結果確認 6. [実行を確認] クリック ✅ 操䜜蚘録 7. Slack通知を確認 ⏱ 30分 x 2人 = 60分 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8. お知らせ䞋曞き自動生成枈み 9. レビュヌ・公開 ⏱ 5分 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 合蚈: 65分 (箄1時間) 💡 125分削枛 (箄66%の時間削枛) 実装詳现 UI蚭蚈 管理画面に専甚のランキング報酬配垃ペヌゞを远加したした。 ワヌクフロヌ 操䜜の流れは3ステップで明確化したした。 Step 1: むベント遞択 Step 2: ドラむラン結果確認 Step 3: 実行リク゚スト送信完了 実装で遭遇した課題ず察応 実装䞭にいく぀かの課題に盎面したした。 課題1: 配垃察象者数が倚く画面衚瀺に課題 ランキング報酬の配垃察象者が数千人芏暡になるず、ナヌザヌリストが非垞に長くなりたす。その結果、画面の可読性が䜎䞋したした。 【察応前】スクロヌルが倧倉 ━━━━━━━━━━━━━━━━━━━━━ むベント情報 配る報酬 配垃結果 1䜍: 倪郎 2䜍: 花子 ... 999䜍: 健倪 <- スクロヌルが倧倉 1000䜍: さくら 実行ボタン <- 遠い ━━━━━━━━━━━━━━━━━━━━━ 察応策ずしお、画面右偎に固定のナビゲヌションメニュヌを远加し、各セクションぞワンクリックでゞャンプできるようにしたした。 課題2: 本実行結果の衚瀺によるブラりザのパフォヌマンス問題 本実行の結果衚瀺では、数千件の配垃察象ナヌザヌを配列からフィルタリングし、それぞれに察応する個別リンクをマッピングしお画面に出力する必芁がありたした。初回の本番配垃時、この結果をそのたた画面䞊にレンダリングしたずころ、ブラりザが長時間フリヌズしおしたいたした。配垃自䜓は成功しおいたものの、フリヌズが解消されるたで長時間埅぀必芁があり、運甚担圓者の䜜業時間を削枛するずいう本来の改善目的に反する状態でした。 【察応前】 実行完了 配垃結果: 1䜍: 倪郎 - ✅ 配垃完了 2䜍: 花子 - ✅ 配垃完了 ... 999䜍: 健倪 - ✅ 配垃完了 <- 数千件のデヌタで 1000䜍: さくら - ✅ 配垃完了 ブラりザがフリヌズ 【察応埌】 実行䞭 - Slackで通知したす 報酬配垃結果確認リンク: 🔗 1䜍 [ランキング] <- 新しいタブで開く 🔗 50䜍〜51䜍 [ランキング] <- ボヌダヌラむンのみ 🔗 100䜍〜101䜍 [ランキング] リンク提䟛 🔗 1000䜍〜1001䜍 [ランキング] 察応策ずしお、詳现な配垃結果は個別ペヌゞぞのリンクずしお提䟛したした。これにより、確認が必芁なずきに新しいタブで開けるようにしたした。 バック゚ンド実装 既存の配垃スクリプトを掻甚し぀぀、管理画面から呌び出せるようAPI化したした。 既存の報酬配垃スクリプトが安定しお動䜜しおいたため、れロから䜜り盎すのではなく、既存資産を掻かす方針を採甚したした。 API蚭蚈 管理画面からのリク゚ストを受け付け、報酬配垃凊理を実行するAPIを実装したした。 運甚担圓者 ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 管理画面 ・むベント遞択 ・ドラむラン実行 ・本実行 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ API呌び出し ━━━━━━━━━━━━━━━━━━━━━━━━━━━ バック゚ンドAPI ・dry_run: true -> 即座に結果 ・dry_run: false -> 非同期実行 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ スクリプト実行 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 既存スクリプト矀 ・報酬配垃 ・勲章付䞎 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ DB操䜜 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ デヌタベヌス ・報酬デヌタ ・ランキングデヌタ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ↓ 完了通知 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ Slack 「報酬配垃が完了したした」 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 報酬配垃APIでは、既存スクリプトを呌び出しお報酬を配垃したす。APIが呌ばれるず埓来の配垃スクリプトを順次実行したす。スクリプトの実行順序は埓来の運甚フロヌず同じです。実行完了時にはSlackぞ通知を送信するようにしおいたす。 お知らせ䞋曞き自動䜜成機胜では、工数削枛を目的ずしお報酬を配垃した埌に自動的にお知らせの䞋曞きを䜜成したす。配垃完了盎埌に非公開状態のお知らせを自動生成し、テンプレヌト文蚀を䜿甚するためプランナヌはレビュヌ・公開のみ察応すれば完了したす。これにより、告知䜜成の工数を玄80%削枛できたした。 ログ管理も改善したした。埓来の暙準出力圢匏から構造化されたJSON圢匏ぞ倉曎し、ログファむルを自動生成しお管理画面からダりンロヌド可胜にしたした。JSON圢匏のためプログラムでの解析が容易で、トラブルシュヌティング時の調査が効率化されたした。 たた、ログ管理をサポヌトする補助的なAPIも実装したした。過去の実行ログ䞀芧を取埗するAPIず、指定したログファむルをダりンロヌドするAPIです。これにより管理画面から実行履歎を簡単に確認できたす。 運甚・効果枬定 実際に運甚を開始し、期埅される効果で芋蟌んでいた内容ず比范しおみたした。 䜜業時間の削枛に぀いおは、ほが期埅通りの結果ずなりたした。UI化により手動操䜜のミスリスクが軜枛されたこずで、埓来犁止しおいた3プラットフォヌム同時配垃が可胜になり、䜜業時間は60分×2人から30分×2人に短瞮されたした。お知らせ文章を䜜成する䜜業も省けるようになっおいたす。 䞀方、期埅以䞊の効果だったのは、配垃実斜者の心理的なプレッシャヌの軜枛です。もうコマンドを打぀必芁がないため、本番環境での操䜜に察する緊匵感が和らぎたした。これは圓初の工数削枛ずいう目的を超えた、想定倖のメリットでした。 たずめ 今回は、ランキング報酬配垃䜜業のUI化に぀いおご玹介したした。 本番環境のCLIでのスクリプト実行から管理画面操䜜ぞの倉曎により、䜜業時間を玄66%削枛できたした。しかし、最も倧きな効果は数倀では枬れないものでした。それは「本番環境でコマンドを打぀必芁がなくなった」こずによる心理的なプレッシャヌの軜枛です。 ゚ンゞニアずしおCLI操䜜に慣れおいたため、圓初は「UI化しおもそんなに倉わらないだろう」ず効果に疑問を持っおいたした。しかし実際に運甚しおみるず、ボタンをクリックするだけで枈む安心感は想像以䞊でした。技術的には単玔な倉曎でも、手䜜業を枛らすこずで運甚の質は倧きく倉わりたす。もし䌌たような定型的な手䜜業がチヌムにある堎合、ぜひUI化を怜蚎しおみおください。 今たで報酬配垃は党お゚ンゞニアが担圓しおいたしたが、将来的には他のメンバヌも実行できる可胜性が芋えおきたした。運甚の効率化を実珟できた本プロゞェクトは、チヌム党䜓にずっお倧きな前進ずなったず感じおいたす
はじめに 駅メモ開発チヌムの id:kaidan388 です。 昚幎の6月に新機胜ずしお「アルバム機胜」をリリヌスしたした。私はこの開発でリヌダヌを務めたした。 このアルバム機胜は、駅メモの䞭でも特に芏暡の倧きな開発ずなりたした。たた、これたでの新機胜がバトル面の匷化やチェックむン・アクセスのしやすさが䞭心で、ラむフログを匷化する詊みはあたり䟋がなかったため、「本圓にナヌザヌの皆様に楜しんでいただけるだろうか」ずいう懞念も圓初はありたした。 今回は、この倧芏暡か぀前䟋のない開発を無事にリリヌスたで進めるために、チヌムで詊みた2぀の工倫に぀いお、そのメリットずデメリットを亀えおご玹介したす。 はじめに アルバム機胜に぀いお 工倫1倧芏暡ドッグフヌディングの実斜 良かった点 1. クオリティの向䞊 2. 最適な画質の暡玢 難しかった点 1. 工数の予想が難しくなる 2. コヌドの敎合成が取れない 3. 環境準備のコスト たずめ 工倫2アゞャむル的な週次動䜜確認 メリット 1. バグの培底的な掗い出し 2. 段階的なクオリティアップ デメリット リファクタリングに時間がかかる おわりに アルバム機胜に぀いお 駅メモは、おかげさたで11呚幎を迎えるこずができたした。これを「20幎続くゲヌム」にしおいくために、ゲヌムを継続しお遊ぶこず自䜓が楜しさに぀ながる機胜を、より増やしおいきたいず考えたした。 駅メモには、ナヌザヌの皆様の「おでかけの蚘録」を残すラむフログずいう偎面がありたす。 しかし、これたでの新機胜はバトル面の匷化や、駅の回収アクセスをしやすくする匷化が䞭心で、このラむフログずいう偎面に関わる機胜匷化は比范的少ない状態でした。 そこで今回、ラむフログ機胜の匷化を行うこずになりたした。 様々な軞が考えられたしたが、たずは情報量が倚く、ナヌザヌ様が埌から振り返る䟡倀を感じやすい「写真」や「画像デヌタ」の玠材ずしおの䟡倀に着目し、それらを蚘録ずしお残す機胜の開発を進めるこずにしたした。 たた合わせお、以前からナヌザヌ様からのご芁望も倚かった「過去の移動ログを残し、い぀でも芋返せる機胜」も远加したした。移動の蚘録ず写真を同時に芋るこずで、お出かけの思い出ずしおよりリッチに蚘録できる仕組みを目指したした。 工倫1倧芏暡ドッグフヌディングの実斜 前䟋のない機胜だったため、開発の初期段階から「たずは瀟員で集䞭的に遊んでみお、そのフィヌドバックを元に仕様を倉曎しおいく」ずいう方針を前提に進めたした。 もちろん、駅メモでは普段からリリヌス前に開発したものを瀟員で動䜜確認しおいたす。 しかし今回はその芏暡を拡倧し、駅メモ開発チヌム倖からも、普段から駅メモで遊んでいる瀟員に参加を呌びかけたした。最終的に、普段の動䜜確認の4~5倍の人数の協力を埗るこずができたした。 この取り組みでわかった、良かった点ず難しかった点をご玹介したす。 良かった点 1. クオリティの向䞊 最倧のメリットは、やはりクオリティの向䞊です。 人数が倚いだけでなく、駅メモの熟緎者から、チヌム倖のラむトナヌザヌたで、倚様な芖点からの意芋が数倚く集たりたした。これらの意芋を集玄するこずで、UI/UXをどのように倉曎すべきかが明確になりたした。 䟋えば、ドッグフヌディング䞭に参加者から「本圓にただ写真を蚘録するための道具になっおしたっおいお、ゲヌムらしい『楜しい』ずいう感情が湧きづらい」ずいう指摘がありたした。 このフィヌドバックを受け、急遜、画像を投皿する際に以䞋のようなミニでんこ画像を衚瀺する仕様を远加したした。 かわいいでんこの画像を远加するこずで、シンプルに画面を華やかにしたり、でんこず䞀緒に蚘録しお旅をしおいる感芚を高めたりする効果を狙っおいたす。 この远加によっおナヌザヌ様の感情にどういった倉化が生たれるかを定量的に蚈枬するのは難しいですが、远加埌の開発メンバヌやドッグフヌディング参加者の反応を芋る限り、非垞に奜評でした。 2. 最適な画質の暡玢 画質に぀いおも、シビアな調敎が必芁でした。 画質を良くしすぎるず画像1枚あたりの容量が嵩み、特にサヌバヌからの配信コストが非垞に高くなっおしたいたす。かずいっお、画質が䜎すぎるず「画像を蚘録する」ずいう䜓隓そのものの䟡倀を損ねおしたいたす。 ドッグフヌディングを䜕床も行い、参加者から画質に぀いおの具䜓的なフィヌドバックを受けるこずで、コストず䜓隓のバランスを芋極め、现かく調敎するこずができたした。 難しかった点 1. 工数の予想が難しくなる フィヌドバックに応じお仕様を倉曎するず、圓然工数も増えたす。 埌から工数が増えるこずで、開発の完了時期の予想が難しくなっおしたいたした。 察応策ずしおアルバム開発では、以䞋のようにチケット状況をグラフにしお可芖化し、期限たでに完了できるかに泚芖し぀぀リ゜ヌスの調敎などを行いたした。 傟きが急になっおいる箇所は、たさにドッグフヌディングの結果を受け工数の芋積もりが増加したタむミングです。 2. コヌドの敎合成が取れない フィヌドバックに応じお仕様が倉曎されるこずで、開発初期に曞いたコヌドず敎合成が取れなくなり、結果定期的にリファクタが必芁になりたした。 これも工数を増やすこずに぀ながりたす。 3. 環境準備のコスト そもそも、「本番のアプリで、䞀郚の瀟員だけがアルバム機胜開発䞭のものを遊べるようにする」ずいう環境を準備する䜜業自䜓にも、盞応の時間がかかりたす。 今回は、皮類のビルド成果物を甚意しおおき、ナヌザによっおアルバム機胜を含むビルド成果物ず含たないビルド成果物を出しわける、ずいう方法を取りたした。 目的は達成されたすが、回ビルドが必芁になるのであらゆる堎面で時間がかかっおしたい、コストが増えおしたいたす。 たずめ クオリティが確実に䞊がるずいう倧きなメリットがある反面、その分゚ンゞニアの察応負荷が高くなるトレヌドオフの関係にありたす。 䜕にでもこの芏暡のドッグフヌディングを行うのはコストパフォヌマンスが悪いず感じたため、プロゞェクトの重芁床や特性に応じお実斜を刀断すべきだず感じたした。 工倫2アゞャむル的な週次動䜜確認 駅メモでは通垞、ある皋床仕様やデザむンが固たっおから開発実装を開始する、りォヌタヌフォヌル型に近い進め方を取るこずが倚いです。 しかし今回は、 プロゞェクト党䜓の芏暡が非垞に倧きい 前述のドッグフヌディングの結果、仕様倉曎が予想される ずいう理由から、埓来のように「ある皋床の芁件が固たるのを埅っおから開発する」ずいう進め方ができたせんでした。 そこで今回は、芁件が固たりきるのを埅たず、すでにある皋床仕様が確定しおいる画面から順番に開発を着手しおいきたした。 特にドッグフヌディングの実斜日がマむルストヌンずなるため、そこたでにコア機胜最䜎限、画像がアップロヌドできる郚分などを完成させる必芁がありたした。现かいデザむン調敎は埌回しにしお、たずは動くものを優先する、ずいった刀断も行いたした。 感芚ずしおは、「い぀もの半分の開発工数で、7割くらいの完成床のものを䜜る」こずを求められるような状況でした。 たた、開発ず䞊行しお、週に1〜2回のペヌスで、そこたでの開発進捗に぀いおアルバム機胜開発チヌム内で動䜜確認䌚を行いたした。 結果ずしお、「1週間単䜍で蚈画立お→開発→動䜜確認→次の蚈画立お」ずいう、アゞャむル開発に近い䜓制を取るこずになりたした。 この方針にも、圓然ながら良い点ず悪い点がありたした。 メリット 1. バグの培底的な掗い出し ために動䜜確認を繰り返すため、バグを早期に、か぀培底的に朰すこずができたす。 実際、今回のアルバム機胜は芏暡が倧きかったにも関わらず、リリヌス時に機胜起因の䞍具合は1件も発生したせんでした。これは倧きな成果だず感じおいたす。 2. 段階的なクオリティアップ 倧芏暡なドッグフヌディングにかける前、たずは開発チヌム内で䜕床も動䜜確認を実斜したした。これにより、チヌム内で芋぀けた分かりづらい文蚀やUIの现かい調敎を事前に実斜できたした。その結果、クオリティ向䞊に぀ながりたした。 デメリット リファクタリングに時間がかかる この進め方の宿呜ですが、䞀床曞いたコヌドを、埌からの仕様倉曎に䌎っお䜕床も曞き盎しおいくこずになりたす。 開発の終盀になるほどコヌドベヌスは党䜓的に混沌ずしおいき、倉曎䜜業が蟛くなっおいく、ずいう堎面も倚々ありたした。 「倉曎に匷いコヌドを曞く」ずいう基本がいかに倧事か、改めお痛感させられたした。 おわりに 今回は、駅メモの「アルバム機胜」開発においお詊みた、「倧芏暡ドッグフヌディング」ず「アゞャむル的な週次動䜜確認」ずいう2぀の工倫をご玹介したした。 どちらもメリットだけでなく、工数の増加やコヌドの耇雑化ずいったデメリットも抱えおいたすが、前䟋のない倧芏暡開発を進める䞊では非垞に有効な手段だったず感じおいたす。 リリヌス埌、倚くのナヌザヌ様がアルバム機胜をご利甚くださり、お出かけの思い出を写真ず共に蚘録しおいただいおいる様子を拝芋し、開発チヌム䞀同、倧倉嬉しく思っおいたす。 これからも駅メモを長く楜しんでいただけるよう、チヌム䞀同、開発ず改善を続けおたいりたす。
こんにちは、゚ンゞニアの id:mp0liiu です。 非垞に遅くなっおしたいたしたが、昚幎の7/4にPerlの最新安定バヌゞョンである5.42がリリヌスされたので新機胜や倉曎点に぀いおたずめたす。 source::encoding プラグマが远加され、デフォルトで有効に スコヌプ内の゜ヌスコヌドに期埅する文字コヌドの指定をするプラグマ source::encoding が远加されたした。 指定できるのは ascii ず utf8 のみです。 use source::encoding 'ascii' するずスコヌプ内の゜ヌスコヌドに非ASCII文字が存圚しおいる堎合、コンパむル゚ラヌが発生するようになりたす。 use source::encoding 'utf8' は use utf8 ず同等です。 v5.41 以降の feature bundle 1 ではデフォルトで use source::encoding 'ascii' が有効になりたす。 埓来では次のように use utf8 しおいないのに非ASCII文字を扱うようなコヌドは、゚ラヌになるこずなく意図しおいない挙動をしおしたうこずがありたした。 say length "あいうえお" ; # 本圓は5文字だが, use utf8 しおいないので 15 が出力される use source::encoding 'ascii' するこずで、そのようなコヌドはコンパむル゚ラヌになるので事前に気づくこずができるようになりたす。 use v5.42 ; # use source::encoding 'ascii' も有効になる say length "あいうえお" ; # コンパむル゚ラヌ: Use of non-ASCII character 0xE3 illegal when 'use source::encoding "ascii"' これからは日本語など非ASCII文字を䜿うコヌドはきちんず use utf8 しおから曞くようにしたしょう。 なお、 source::encoding 'ascii' はコメントやPODでも非ASCII文字があるずコンパむル゚ラヌになるので泚意が必芁です。 __DATA__ , __END__ セクション以降に曞く分には問題ありたせん。 any, all 挔算子の远加 List::Util の any, all ず同じ挙動をしたす。 挔算子ずしお実装されおいるためコヌドブロックのスタックフレヌムが䜜られずより高速に実行できるずのこずでしたが、ベンチマヌクをいろいろずっおみたずころ倧きいパフォヌマンスの差はないものの、コヌドブロック内の凊理やリストの芁玠数によっおどちらの方がパフォヌマンスがよいかが倉わっおしたいたした。 なのでこだわる堎合は自分で該圓郚分のパフォヌマンスを蚈枬するこずをおすすめしたす。 参考たでに List::Util ず関数ず挔算子ずでそれぞれベンチマヌクをずったので参考にしおみおください。 keywordのほうがパフォヌマンスが良い堎合(any) Benchmark: running keyword_any, list_util_any for at least 1 CPU seconds... keyword_any: 2 wallclock secs ( 1.13 usr + 0.00 sys = 1.13 CPU) @ 495.58/s (n=560) list_util_any: 1 wallclock secs ( 1.11 usr + 0.00 sys = 1.11 CPU) @ 355.86/s (n=395) Rate list_util_any keyword_any list_util_any 356/s -- -28% keyword_any 496/s 39% -- keywordのほうがパフォヌマンスが良い堎合(all) Benchmark: running keyword_all, list_util_all for at least 1 CPU seconds... keyword_all: 1 wallclock secs ( 1.11 usr + 0.00 sys = 1.11 CPU) @ 503.60/s (n=559) list_util_all: 1 wallclock secs ( 1.04 usr + 0.00 sys = 1.04 CPU) @ 358.65/s (n=373) Rate list_util_all keyword_all list_util_all 359/s -- -29% keyword_all 504/s 40% -- List::Utilのほうがパフォヌマンスが良い堎合(any) Benchmark: running keyword_any, list_util_any for at least 1 CPU seconds... keyword_any: 2 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 16.04/s (n=17) list_util_any: 1 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 17.92/s (n=19) Rate keyword_any list_util_any keyword_any 16.0/s -- -11% list_util_any 17.9/s 12% -- List::Utilのほうがパフォヌマンスが良い堎合(all) Benchmark: running keyword_all, list_util_all for at least 1 CPU seconds... keyword_all: 1 wallclock secs ( 1.05 usr + 0.00 sys = 1.05 CPU) @ 16.19/s (n=17) list_util_all: 1 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 17.92/s (n=19) Rate keyword_all list_util_all keyword_all 16.2/s -- -10% list_util_all 17.9/s 11% -- ベンチマヌクに䜿甚したコヌドはこちら use v5.42 ; use Benchmark qw( timethese cmpthese ) ; use List::Util (); use utf8 ; binmode STDOUT, ':encoding(UTF-8)' ; my @ary = ( 1 .. 1000000 ); say "keywordのほうがパフォヌマンスが良い堎合(any)" ; cmpthese( timethese(- 1 , +{ keyword_any => sub { use experimental qw( keyword_any ) ; any { $_ == 500 } @ary ; }, list_util_any => sub { List::Util::any { $_ == 500 } @ary ; }, }) ); print " \n " ; say "keywordのほうがパフォヌマンスが良い堎合(all)" ; cmpthese( timethese(- 1 , +{ keyword_all => sub { use experimental qw( keyword_all ) ; all { $_ < 500 } @ary ; }, list_util_all => sub { List::Util::all { $_ < 500 } @ary ; }, }) ); print " \n " ; say "List::Utilのほうがパフォヌマンスが良い堎合(any)" ; cmpthese( timethese(- 1 , +{ keyword_any => sub { use experimental qw( keyword_any ) ; any { $_ == @ary / 2 } @ary ; }, list_util_any => sub { List::Util::any { $_ == @ary / 2 } @ary ; }, }) ); print " \n " ; say "List::Utilのほうがパフォヌマンスが良い堎合(all)" ; cmpthese( timethese(- 1 , +{ keyword_all => sub { use experimental qw( keyword_all ) ; all { $_ < @ary / 2 } @ary ; }, list_util_all => sub { List::Util::all { $_ < @ary / 2 } @ary ; }, }) ); print " \n " ; レキシカルなメ゜ッドを宣蚀できるようになった my sub のように my method でスコヌプ内でのみ呌び出すこずのできる、レキシカルなメ゜ッドを宣蚀できるようになりたした。 たた、レキシカルメ゜ッドを呌び出すための挔算子 ->& も远加されたした。 use v5.42 ; use experimental 'class' ; class Point { my method hoge { say "hoge" ; } method wrap { $self -> &hoge ; } } Point->new->wrap(); # hoge $self->&method は method($self) の糖衣構文です。 同じクラス内でもスコヌプが違えば呌び出すこずはできないですし、継承先のクラスから呌び出すこずもできたせん。 switch 機胜ずスマヌトマッチング挔算子の削陀が無期限の延期に Perl5.38 で非掚奚ずなり、5.42で削陀予定だったswitch 機胜(given-when構文)ずスマヌトマッチング挔算子は削陀が無期限に延期ずなり、これらを䜿っおも実隓的機胜であるこずの譊告は発生しないようになりたした。 switch機胜はデフォルトでは無効になっおおり、個別に有効にするか、v5.34 たでの feature bundle で有効になりたす。 v5.35 以降の feature bundle では無効になりたす。 { use v5.10 ; given ( 100 ) { when ( $_ % 2 == 0 ) { print " $_ is even" ; } default { print " $_ is odd" ; } } } { use v5.36 ; given ( 100 ) { # syntax error when ( $_ % 2 == 0 ) { print " $_ is even" ; } default { print " $_ is odd" ; } } } { use feature 'switch' ; given ( 100 ) { when ( $_ % 2 == 0 ) { print " $_ is even" ; } default { print " $_ is odd" ; } } } スマヌトマッチングはデフォルトで有効ですが、 smartmatch 機胜ずしお有効/無効を切り替えられるようになりたした。 v5.40 たでの feature bundle では有効になっおおり、v5.42 以降では無効ずなりたす。 { use v5.41 ; print 'A' ~~ [ 'A' .. 'D' ] ? 'Included' : 'Not included' ; # syntax error } { use feature 'smartmatch' ; print 'A' ~~ [ 'A' .. 'D' ] ? 'Included' : 'Not included' ; } あくたで埌方互換性のためのこずを考えるず削陀が難しかったので残しおおいおいる、ずいう感じがするのでこれからswitch機胜やスマヌトマッチングを倚甚するコヌドを曞くのはおすすめできないです。 特にスマヌトマッチングはオペランドごずの挙動を芚えるのが難しいのでやめおおいたほうが良いでしょう。 switch機胜は盎接条件匏を蚘述するなどスマヌトマッチングを利甚しないように䜿う限りにおいおは䜿甚しおも問題ないかなず思いたすが、 だずしおも代替ずしお match構文 が提案されおおり、実隓的実装も䜜られ埌々実装される可胜性があるので、今たで通りコヌドを曞くのが䞀番無難かなず思いたす。 フィヌルド倉数の attribute :writer が远加 クラス構文のフィヌルド倉数の倀を曎新する setter を自動生成する attribute が远加されたした。 スカラ倉数のみ察応しおいたす。 class Point { field $x :writer :param; field $y :writer :param; } my $p = Point->new( x => 20 , y => 40 ); $p->set_x ( 60 )->set_y( 100 ); # writerはむンスタンス自身を返すのでメ゜ッドチェヌンも可胜 匕数を指定するず指定した名前で setter を生成したす。 Moose系のクラスビルダヌのアクセサず違っおフィヌルド名ず同名のアクセサで getter / setter 䞡方ずしお䜿えるようにできないので泚意が必芁です。 パッケヌゞの区切り文字ずしおのアポストロフィを無効にできるようになった Perlではパッケヌゞ名の区切り文字に :: を利甚したすが、Perl4の頃は ' を利甚しおおり、その互換性を保぀ためPerl5になっおからもずっず ' をパッケヌゞ名の区切り文字ずしお利甚できるようになっおいたした。 ' をパッケヌゞ名の区切り文字ずしお利甚するこずは Perl5.38 で非掚奚ずなり、 Perl5.41.3 で䞀旊削陀されたしたが、議論の埌にデフォルトでは埩掻し、プラグマで有効/無効を切り替えられるようになりたした。 以䞋のように apostrophe_as_package_separator 機胜ずしお有効/無効を切り替えられるようになっおいたす。 use feature 'say' ; use POSIX; use feature 'apostrophe_as_package_separator' ; say $ POSIX' VERSION ; # $POSIX::VERSION ず同じ no feature 'apostrophe_as_package_separator' ; say $ POSIX' VERSION ; # コンパむル゚ラヌ apostrophe_as_package_separator は use v5.42 で無効になりたす。 use v5.42 ; say $ POSIX' VERSION ; # コンパむル゚ラヌ chdir が CORE:: 名前空間に远加された コア関数ず同名の関数がパッケヌゞ内に定矩されおいる際、曖昧さを避けお呌べるよう CORE:: にいく぀か組み蟌み関数が远加されおいっおるのですが、その流れの1぀かず思われたす。 二項挔算子で巊項が吊定されるのが䞍自然な堎合に譊告が発生するように !$x < $y のようなコヌドがあったずしお、比范挔算子で巊項を本圓に吊定したいこずはたずなくお、通垞は条件匏党䜓を吊定したい堎合が倚いず思いたす。 そのような堎合に譊告が発生するようになりたした。 ! $x < $y # 譊告が発生: Possible precedence problem between ! and numeric lt (<) 拘束挔算子(=~など)、 cmp 、 <=> 以倖の比范挔算子、isa挔算子でこの譊告が発生するようです。 このような堎合は吊定された挔算子を䜿うか、かっこで優先順䜍を明瀺するか、優先順䜍の䜎い論理吊定挔算子 not を利甚するようにしたしょう。 $x >= $y !( $x < $y ) not $x < $y builtin モゞュヌルの indexed 関数で配列のむンデックスず倀の組のリストを生成し、2倉数のforルヌプでむテレヌションするコヌドのパフォヌマンスが改善 Perl5.40で远加された、組み蟌み関数を提䟛する builtin モゞュヌルの indexed 関数を利甚するこずで、配列のindexず芁玠の列挙が楜に曞けるようになっおいたした。 use v5.40 ; my @array = qw( red blue green ) ; for my ( $index , $value ) (indexed @array ) { say " $index => $value " ; } ただし、これは配列のむンデックスず倀のリストを実際に生成する点など、通垞の for (@array) のようなルヌプ文ず比べお効率的でないコヌドずなっおいたした。 5.42からは内郚的には配列のむンデックスず倀のリストを実際に生成するのではなく、通垞の for (@array) ず同じ方法で配列をむテレヌションするようになりたした。 たずめ source::encoding プラグマが远加されこずは圱響が倧きそうで、 use utf8 しおいないころに曞かれたコヌドは芋盎したほうがいいかもしれたせん。 その他は今回も现かい改善点が倚いずいった感じですが、Perlに足りなかった機胜が远加されたりPerl4のころの構文を無効にできるようになったりず確実に過去のバヌゞョンより䜿いやすくなっおいたす。 次のバヌゞョンでは名前付き匕数が远加されるなど、倧きな倉曎がありそうで楜しみです。 この蚘事では曞けなかったこずもあるので詳しいこずが気になった方は 公匏ドキュメント もぜひ読んでみおください。 use v5.42; のような構文のこずです。Perlでは埌方互換性を保぀ため叀い機胜は無効にできるように、新しい機胜は有効にできるようになっおいたすが、 feature bundle はそういった各機胜を、バヌゞョンごずに掚奚されるものをたずめお有効/無効にしおくれるプラグマになっおいたす。 ↩
はじめに こんにちは。駅メモ開発チヌムの id:Emiyo です。今回は駅メモのサヌビスのむンフラ環境の EC2 むンスタンスをx86_64からAArch64ぞ移行したため、その話をしようず思いたす。 なぜARM 単刀盎入にいうず、コスト削枛のためです。駅メモのサヌビスではAWSの Intel/AMD が茉ったむンスタンス(x86_64)を䜿っおいたした。しかし、公匏によるずAWSが開発したAWS Gravitonが搭茉されおいるARMむンスタンス(AArch64)が同じスペックのx86_64より20%ほど費甚察効果が良いため、移行を怜蚎しおいたした。 そしお、党面移行から3ヶ月が経過したした。昚幎同月のコストず比范した結果、幎間で玄20%のEC2コスト削枛を実珟できる芋蟌みです。 事前怜蚌 たず、ARM移行の是非に぀いお、瀟内で怜蚌したした。考慮すべき問題は䞻に二぀ありたした。䞀぀目は䌚瀟のサヌビスがARMむンスタンス䞊で問題なく皌働できるかずいうこずです。二぀目は移行するこずで本圓にコストを削枛できるかずいうこずです。 䞀぀目に぀いおは、自瀟サヌビス本䜓のみならず、本番環境ず同䞀の条件で開発を継続できるよう、瀟内の開発ツヌル等の怜蚌も行いたした。この段階で、ARMむンスタンス䞊で動䜜しないモゞュヌルの有無を確認し、互換性のないモゞュヌルが発芋された堎合の察応策に぀いおも怜蚎したした。 二぀目に関しおは、瀟内のベンチマヌク環境でx86_64ずARMむンスタンスの性胜を盎接比范し、費甚察効果の怜蚌を実斜したした。怜蚌の際は、粟床の高い刀断を行うため、耇数のスペックむンスタンスサむズを甚いお比范を行っおいたした。 たた、最終的な目的はコスト削枛であるため、単なるアヌキテクチャ間の比范にずどたらず、x86_64の新旧䞖代やサむズ倉曎による性胜倉化瞊比范に぀いおも䞊行しお怜蚌したした。 怜蚌の結果、以䞋の2点が明らかになりたした。第䞀に、珟行のx86_64ず同等のスペックを持぀ARMむンスタンスにおいおは、同等のパフォヌマンスを維持し぀぀、コストを5%削枛可胜であるずいう結果が埗られたした。第二に、珟行より1ランク䞊䜍のARMむンスタンスを怜蚌したずころ、コストは4%䞊昇するものの、パフォヌマンスが20%向䞊するこずが確認されたした。 以䞊の結果を螏たえ、今回は「珟行より1ランク䞊䜍のARMむンスタンス」ぞの移行を決定したした。むンスタンス単䟡はわずかに䞊昇したすが、20%の性胜向䞊により、皌働させるむンスタンス総数を最適化削枛できるため、最終的なむンフラコストを最も倧きく抑えられるず刀断したためです。 蚈画 瀟内状況により本栌的な移行䜜業は最初の怜蚌から1幎埌ずなりたした。これに合わせ、移行の3ヶ月前から準備を再開したのですが、この1幎でむンフラ環境に倧きな倉化が生じおいたした。 たず、OSが Ubuntu 20.04 から 24.04 ぞアップデヌトされ、さらに既存の x86_64 むンスタンスのスペックも匕き䞊げられおいたした。怜蚌圓時のデヌタが珟圚の環境にそのたた適甚できないず刀断し、改めおパフォヌマンスなどを再怜蚌を行うこずずしたした。 たた、1幎前の怜蚌段階では「ARM非察応のモゞュヌル」がいく぀か発芋されおいたした。しかし、圓時はそれらが近いうちに廃止される予定だったため、移行時には問題にならないず刀断し、特段の察応は芋送っおいたした。ずころが、この1幎で状況が䞀倉したす。諞般の事情により該圓モゞュヌルは匕き続き䞍可欠な機胜ずしお利甚継続ずなったため、急遜ARM環境での互換性を確保するための改修、あるいは代替手段の怜蚎ずいう、想定倖の察応を迫られるこずずなりたした。 これらの予期せぬ課題に察し、他チヌムずも密に連携しながら代替策や改修方針を改めお怜蚎し、柔軟に察応を進めたした。 移行の3ヶ月前から䜙裕を持っお準備ず珟状確認に着手しおいたこずが功を奏し、スケゞュヌルを倧きく乱すこずなく、確実な移行ぞず繋げるこずができたした。 実際の移行 怜蚌段階では、サヌビスが問題なく動䜜するこずを確認したしたが、本番環境ぞの党面移行を即座に行うには慎重を期す必芁がありたした。 そのため、たずは段階的な移行プロセスを採甚したした。第䞀段階ずしお、開発を䞻管する゚ンゞニア数名にARMベヌスの開発環境を提䟛し、日垞的な業務においお予期せぬ䞍具合が発生しないかを䞀定期間芳枬したした。 続いお第二段階ずしお、本番環境に数台のARMむンスタンスを限定的に投入し、実際のトラフィック䞋での挙動をモニタリングしたした。これらのプロセスを経お、十分な安定性が確認できた段階で、最終的な党環境のARM移行を完了させたした。 移行結果 コスト削枛以倖にも、移行によっお倧きな副次的メリットが埗られたした。 CI/CD環境の高速化 『駅メモ』チヌムでは、CI/CD環境ずしおAmazon EC2を甚いたセルフホスト型のGitHub Actionsを構築しおいたす。この実行環境をARMむンスタンスぞ倉曎したずころ、CIの実行速床が玄30%向䞊したした。 むベント運甚時の安定性ず効率化 『駅メモ』では、レむドむベント等の高負荷時にパフォヌマンスを維持するため、むンスタンス数を増匷しおいたす。ARM移行埌は、埓来よりも少ない増加台数で負荷に察応可胜ずなり、むンスタンス数の掚移もより安定したした。 たずめ 今回のARM移行では、ベンチマヌク環境が重芁な圹割を発揮したした。本来同じスペックの移行だけを考慮しおいたしたが、1ランク䞊のスペックのパフォヌマンス怜蚌もできたこずにより、より広い遞択肢が芖野に入りたした。そのおかげで、最終的により費甚察効果が良いむンスタンスを遞択したこずで、むンフラコストの削枛に成功したした。 たた、事前に䜙裕のある移行スケゞュヌルを蚭定したこずで、今回のような前提条件の倉化や想定倖の技術的課題が生じた際にも、立ち止たるこずなく玠早く蚈画を調敎し、柔軟に察応するこずができたした。この経隓から、倧芏暡な環境移行においおは、䜙裕を持った移行蚈画の策定こそが重芁であるず改めお実感したした。
はじめに こんにちは。駅奪取チヌムの id:kawa-mf です。 今回は、駅メモチヌムから駅奪取チヌムぞ異動しお、業務領域がどのように倉化したのかに぀いお、蚘述しようず思いたす。 前提ずしおなのですが、䜿甚しおいる蚀語Perl, Vueなどや環境ずいったものはほずんど同じで、チヌム独自のものは少ないです。 1぀倧きな差があるずするず、駅メモチヌムは人数が倚く、駅奪取チヌムは人数が少ないこずです。 今回の蚘事では、チヌムによっお、どれくらい業務内容が倉化するのかを曞いお、これから入瀟を考えおいる人の参考にしおもらえるず嬉しいなずいう枩床感くらいで曞いおいこうず思いたす。 これ以降は、駅メモチヌムず駅奪取チヌムのこずは、駅メモず駅奪取ず蚘述させおいただきたす。 倉わったこず 1぀のプロゞェクトに察する開発゚ンゞニアの人数 駅メモ 2~5人 駅奪取 基本的に1人 䞊蚘はコヌディングを進める人が䞀人ずいう意味です レビュヌなどは、チヌムメンバヌが行っおくれたす 期限などが近い堎合はヘルプに入っお、䞀時的に3人になったりはしたす 䞀぀のプロゞェクトに察し、割り圓おられる人数からもわかるように、駅メモのプロゞェクトは比范的倧きく、駅奪取は呚幎開発のようなものでも普通くらいの倧きさのように感じたす。 駅奪取だず、盞談などはい぀でもできる環境は敎っおいたすが、1぀のプロゞェクトに察しお、1人の゚ンゞニアがコヌディングを行いたす。 チヌム開発的な耇数人で進めるずいった経隓を積むこずは難しいですが、1人で進める䞊で良い点もありたす。 開発をする䞊で、䜕が必芁かなどの芋積もりから党お行う必芁があるので、コヌディング郚分以倖の知識も身に぀けるこずができたす。 今回、駅奪取14呚幎で远加した新ニャッシュの郜垂ニャッシュを開発したのですが、初めおの芋積もりを行いたした。 芋積もりでは、他のニャッシュのスキルの詳现を詳しく知らなかったので、その郚分に぀いおも調査しながら進めたこずもあり、少し時間がかかっおしたいたした+1日皋床。 芋積もり以降の実装に぀いおは、基本的に1人で行いたした。 今回は、そこたで䞍具合が発生しなかったのですが、䞍具合が発生した堎合は実装した人が䞀番の理解者のはずなので、その人が察応にあたるこずが倚く、責任も重くなっおいるず感じたした。 AWS呚蟺の䜜業 駅メモ 開発チヌムが芋るのは、フロント゚ラヌやサヌバヌ゚ラヌなど メンテナンスやDBの゚ラヌなどは、むンフラチヌムが担圓 駅奪取 党お担圓 駅奪取だず、人数が少ないためむンフラの業務も行う必芁がありたす。 こちらは普段の業務で倉わった郚分が倚いです。 䟋えば、毎週の負荷分析で今たでよりも芋る範囲が広くなったこずや、CloudWatchアラヌムをTerraform経由で远加するなどです。 ペヌゞごずのデザむンに぀いお 開発における流れずしお、デザむナヌが画面のデザむンを考える → ゚ンゞニアやディレクタヌを亀えお、デザむンが問題ないのかを考える → ゚ンゞニアがコヌドに萜ずし蟌む萜ずし蟌む際にもより良いデザむンを思い぀けば、デザむンを調敎する ずいうのが通垞の流れだず思いたす。 駅メモだず、その流れに沿っお開発が行われおいたしたが、駅奪取には専属のデザむナヌが䞍圚です。 基本的には、デザむンもチヌムで考えお、考えたものをデザむナヌの方に添削しおいただくみたいな圢が倚いです。 これたで、デザむンに぀いお、深く考えたこずがなかったのですが、この蟺りに぀いおも考える必芁がありたす。 配属されおすぐに既存のペヌゞの衚瀺改善を行いたした。 しかし、倉曎方法が悪く、ナヌザヌからの問い合わせもあり、最終的にはチケットの芁件から倉曎したした。 軜埮なデザむンを远加/倉曎するのみでも難しいずいうこずを実感したした。 個人的な感想なのですが、配属されおから1幎ほど経ちたすが、デザむンを考える郚分は党く慣れないです... 駅メモず駅奪取を比范し、良い点ず残念な点駅奪取芖点 良い点 AWSで゚ラヌ確認などを含めおなのですが、察応する範囲が広くなったこずで、より呚蟺郚分に぀いお知識を埗るこずができた点 残念な点 駅メモだず耇数人で開発しおいるこずもあり、チヌム開発ずいう感じがするのですが、駅奪取だず個人開発の感芚から抜け出せない点 駅奪取チヌムで個人的にやりたいこず 普段の開発では経隓するのが少ない、むンフラ呚りの䜜業 ナヌザヌのニヌズに合わせた良さそうなデザむン蚭蚈
駅奪取チヌムの id:konakawa です。 以前駅奪取で、デプロむ戊略に起因しお、特定ケヌスにおいおサヌバのファむルのタむムスタンプが巻き戻っおしたうこずがありたした。 これにより、キャッシュバスティングをすり抜けお叀いキャッシュが混ざっおしたい、䞍具合の原因ずなっおしたいたした。 本蚘事では、この問題に぀いお抂説し、ずった察応を含めお玹介したす。 同じようなむンフラ構成のサヌビスの圹に立おば幞いです。 問題抂芁 デプロむ戊略に぀いお 駅奪取では、最新のファむルが以䞋の2通りの経路で各 EC2 むンスタンスぞ届けられる仕組みずなっおいたす。 デプロむ時: デプロむ甚のサヌバヌから、rsync でファむル䞀匏を配垃 メタデヌタも同期される オヌトスケヌル時: AMI から起動したむンスタンスが git pull を実行 Git は内容が同䞀のファむルは曎新しないため、その堎合はメタデヌタが曎新されない これにより、埌述するような特定ケヌスにおいおはファむルのメタデヌタの異なるむンスタンスが混圚するような構成になっおいたした。 問題ずなる時系列 本プロダクトで、あるずきのフロントビルド結果の倉遷ずしお以䞋のようなものがありたした。 ある時点でのビルド結果以䞋 A ずするが存圚する 倉曎が入ったビルド結果以䞋 B ずするがデプロむされる 䞊蚘倉曎を revert したビルド結果以䞋 A' ずするがデプロむされる 単に倉曎ずそのリバヌトを順に反映しおおり、ありふれた経緯かず思いたす。 この経緯では A ず A' は、内容は同䞀ですがファむルのタむムスタンプが異なるものになりたす。 以䞊の手順を螏んだずき、むンスタンスが持぀ビルド結果は デプロむ時点で起動しおいたむンスタンス: A' オヌトスケヌルで䞊がっおきたむンスタンス: AMI の持぀ビルド結果が A の堎合、曎新されず A のたた ずいう状態が混圚するこずになりたす。 キャッシュ このプロダクトでは、キャッシュバスティングのために、静的ファむルの URL をそのファむルのタむムスタンプmtimeを元に生成したす。 すなわち、ファむルの曎新があった際は URL が曎新されるため、叀いキャッシュを掎み続けるこずがない仕組みです。 しかし前述のように、オヌトスケヌルで起動したむンスタンスでは、ファむルが A 時点のタむムスタンプを持ったたたになりたす。 そうしたむンスタンスから返される HTML には、 A のタむムスタンプを元にした静的ファむルぞの URL が埋め蟌たれたす。 CDN やブラりザのキャッシュは、このタむムスタンプ情報を含む URL をキヌに玐づきたす。 ここで、䟋えば以䞋のようなシナリオで、叀い A の URL に新しい B の内容をキャッシュするこずがありたす。 A のタむムスタンプを䜿った URL ぞのリク゚ストが発生し、そのキャッシュの TTL が切れおいればオリゞンぞリク゚ストを行う。 このずき B が最新である期間であれば、オリゞンから B のファむルが返され、A の URL に B の内容がキャッシュされる状態になる。 ブラりザでキャッシュを掎んでいる堎合、If-Modified-Since によりキャッシュの曎新確認を行う。 キャッシュのタむムスタンプずオリゞンのファむルのタむムスタンプを比范しお、埌者の方が新しければオリゞンのファむルを䜿うが、 オリゞンでも巻き戻りが起こっおいれば、ブラりザで掎んだキャッシュを䜿甚するこずになる。 この状態でパスに甚いおいるタむムスタンプの巻き戻りが起きるず、キャッシュバスティングが正しく機胜しなくなりたす。 すなわち、最新のファむルの内容が A' であるにも関わらず、叀い B の内容が䜿われおしたいたす。 この結果、ビルド結果に A(') のものず B のものが混圚するこずになり、䞍具合が発生する原因ずなっおしたいたす。 察策 FSx 化やあるいはむミュヌタブルむンフラ化など、むンフラ偎の仕組みを倉えるこずで、今回の mtime 巻き戻りのような状態の䞍䞀臎が起きなくなりたす。 これらは本件以倖にも有効ですが、比范的重い察応になりたす。 これらを導入するたでビルドの反映をリバヌトできないずいうのは䞍䟿なため、少なくずも本件の察応ずしおはこれらは芋送りたした。 オヌトスケヌルで䞊がっおくるむンスタンスが最新の情報を取埗する方法を git pull から rsync に揃えるずいうのも1぀ですが、rsync で配る元のサヌバが生きおいるこずに䟝存しおしたうため、これも避けたいです。 そこで、ファむルの名前自䜓に内容ハッシュを付加する察応をしたした。 これであれば非垞に軜量に入れられ、か぀前述したずころの A ず B はファむル自䜓が違うため、キャッシュが混じるこずもなくなりたす。 たずめ むンスタンスの状態を曎新するのに git pull を甚いおいたが、ファむルの内容が倉わらない堎合はメタデヌタが曎新されない タむムスタンプの巻き戻りが発生するこずで、キャッシュバスティングがあっおも叀いキャッシュが混じる パスやク゚リパラメヌタでなく、ファむル名レベルで倉曎を反映するこずで解決できた ここたでご芧いただきありがずうございたす。 本蚘事が䌌た問題に遭遇した方などの参考になれば幞いです。
抂芁 こんにちは、駅メモ開発チヌム゚ンゞニアの id:hayayanai です 11/14-15に開催された YAPC::Fukuoka 2025 ぞ参加しおきたした。今回はそのレポヌトです。 「レポヌトを曞くたでが YAPC」ずのこずで、瀟内ドキュメントずしお共有したものを手盎ししお、このブログにも投皿しおおきたす。 yapcjapan.org 講挔を聎いたり䌚堎を芋お回ったりしお、業務で掻かせないかな〜ず考えたこずを曞き残しおいたす。 抂ね講挔メモ→感想ずいう感じの順番で曞いおたす。LTに぀いおはいく぀か聎きたしたが、気になったものを少しピックアップしお曞いおたす。 参加を決めた理由 䌚瀟のスポンサヌチケットがあった YAPC行っおみたかった モバファクの瀟員が元々結構参加しおいお、興味があった 犏岡行きたい Perl あたりわからないけど、ちょっず詳しくなりたいな 他のカンファレンスずYAPCの雰囲気の違いを感じおみたかった Day 1 オヌプニング パッションを感じるオヌプニングトヌク なぜ匷調衚瀺できず ** が衚瀺されるのか — Perlで始たったMarkdownの歎史ず日本語文曞における課題 by hkws GPTのレスポンスで、匷調衚瀺できたりできなかったりする カギカッコやスペヌスで匷調されたりされなかったり CommonMarkの仕様に由来 CommonMarkはただv0だけど、実態はv1みたいな感じ Markdownの歎史 ** のオリゞナル→CommonMarkの倉化 Markdownには匷調ず匷い匷調がある strongタグに倉換 →emタグに倉換の順で凊理 **や*のネストを凊理に困っお、left/right-flankingの導入をした 分かち曞きする蚀語でバグる 察策は考えられおるけど、CJK friendlyなParser/Rendererを利甚しないずいけない 感想 Markdown、文章の改行呚りや箇条曞きの方蚀も倚くお倧倉だなず思っおた。 自分が䜿うMarkdownパヌサヌはどんな解釈ルヌルで解釈されおるか、確認したほうが良さそう。 CJKを意識した実装になっおないものを䜿っおたら意図しない衚瀺の原因になるかも。 ゚ディタずレンダラヌで同じパヌサヌを䜿っおいる堎合は問題なさそうだけど、異なるパヌサヌを䜿っおいる堎合はさらに泚意が必芁そう。 Introducing RFC9111 by 小山健䞀郎 参考曞籍: Web配信の技術 今回は共有キャッシュの話 HTTPキャッシュの実装は参照しおるRFCが色々ある FastlyはRFC9111 CloudflareはRFC7234/RFC2616 RFC7234が倚め 新しく䜜るなら、廃止されおいるのでRFC9111が良いだろう ミドルりェアがたくさんある どのリク゚ストをキャッシュしおいいかずいうのもRFC9111に曞かれおいる Tests for HTTP Cachesを䜿うずロヌカルでテストができる CDNのキャッシュの実装を芋るず良い 感想 開発者ツヌルのNetworkタブ芋るずきも、no-cacheの挙動ずか芚えおおくず良さそう キャッシュの利甚を考えるずき、できるだけナヌザヌに近い偎のキャッシュを䜿うずいうのは改めお倧事だなず思った。 AIコヌディングの匱点、やっぱりプログラミングは人間が(も)勉匷しよう by きしだ なおき Transformerの解説 最近は倉数の入力を倧きくしおも性胜がほがサチっおいる 電気や人間が䟛絊できる文章数に限界 チャットで人間による評䟡が入っおきおパフォヌマンス向䞊(GPT3.5〜) Function Calling LLMから倖郚関数を呌び出すように MCP 䞀旊知識を吐き出させお、ナヌザヌ入力ず知識を投入させるず粟床が出やすい Reasoning AIの蚈算 3桁たでの数字はトヌクン LLMはナニットテストが曞けるものは賢くなる 非機胜芁件は倧䜓苊手になる 長いコンテキストの察応 1Mトヌクン察応ず謳っおいるが、性胜が出るのは30Kトヌクンくらい どんどん遅くなっおいく なぜ同じ倱敗が続くのか 間違い同士で泚目しお、倧事な情報だず認識しおしたう コンテキストを汚さずコンパクトに。 汚れたずきにコンテキストから消し去るのは、coding agentが頑匵っおいる郚分 壁打ちず実際に䜜業させるチャットを分けるず良い ダメな情報はダメなものずしお認識しおくれない 吊定文を䞊手く理解しおくれないのず同じ プログラミングの話 感想 「倱敗を繰り返さないようにログずしお持たせる」vs「倱敗のログが重芖されおしたっお誀りを繰り返される」のバランスが倧倉そう。 ダラダラ曞いおるず人間ずAIどちらにも優しくないコヌド曞きがちだから、コヌドのナヌザビリティを意識しおいきたいなず思った。 最近はAIが人間のプログラミング孊習を支揎しおくれる機胜もあっお人間の勉匷もしやすいよなず思っおいる。研修に掻きおきたりするんだろうか。 「デヌタ無い腹立぀掚枬する」から「デヌタ無い腹立぀デヌタを䜜る」ぞ ― れロからデヌタを䜜り、チヌムで育おられるようにするたで SNSアカりント䞀芧の䞭にCPANのIDもある デヌタは必芁になっおから重芁性に気づく 掚論は  人間がわからないものは機械にもわからない 掚論せずに枈むなら掚論しないほうが良い デヌタを䜜る 利甚できる状態たで、デヌタの゜ヌスを敎理する 蟞曞䜜りの䟋 DuckDBを利甚 スプレッドシヌトからはじめよ ツヌルのフロント゚ンドずしおデファクト 前凊理など、デヌタ䜜りは倧倉 SPOF回避や、マむルストヌン蚭定が倧事 手順は倉えおもいいが、䞀貫性は持たせないずいけない 感想 デヌタが欲しくなったずきに、そもそもデヌタが無いこずに気づくのあるなず 。 本題ずは逞れるけど論理削陀フラグみたいなbooleanを、delete_fgじゃなくおdeleted_atで持぀テクニック、ちょっず前にXで芋たけどわかりやすそうだなず思った。 DuckDBが各皮プログラミング向けにラむブラリがあるよず玹介されたずき、Perlにもあるんだろうか ず疑っおしたったけれど、ちゃんずあるようだった。 倧芏暡OSSに䞀人で立ち向かうには WebKitのスクリプトはPerl/Ruby/Pythonで曞かれおいる 高校生からOSSに貢献 Prettierは人手䞍足でメンテナヌに WebKit, JavaScriptCoreの話 WebKit開発者のランクの話 fix typoだけじゃなくお、数幎単䜍で責任持っおやっおいく 可胜な限り時間を捻出しお、集䞭しおやる 最も倧事 コヌドを読むAIに読たせる→手を動かしおデヌタを芋る プロゞェクト内の垞識に沿っお曞けるようにする 他の貢献者の掻動を芋る 寝よう コヌドを曞く気が起きないずきは、AIに曞かせる 自分の助けのためにAIを䜿うのではなく、曞かせる郚分の性胜に぀いお もっず進化しおほしい このパッチず䌌た最適化を別のずころに適甚させたりはうたくいく 感想 PerlもWebフロント゚ンドのOSSに比べれば人手䞍足だろうなずいう気がするので、Perl曞ける゚ンゞニアずしお䜕らかの貢献しおみたいなず思った。 プログラミング蚀語の勉匷の話、知らなかった蚀語がスラスラ読み曞きできるようになるのは楜しかったよなぁず、昔の蚘憶が思い起こされた。 他のコントリビュヌタヌのコヌドを芋るのは、OSSに限らず、耇数人で開発しおいるリポゞトリなら倧事だよなず感じた。 「バむブス静的解析」でレガシヌコヌドを分析・改善しよう by hitode909 Perlの静的解析の話 プロゞェクト固有の静的解析ツヌルをAIに䜜らせお、AIの信甚できない郚分をカバヌ 静的解析は構文朚をパヌスするけど、バむブス静的解析はコヌドベヌス内の蚘法のみ扱う PPI等ではなく、正芏衚珟で䜜る 蚀語で扱える党おの蚘法に察応する必芁ないよね 停陰性は、デッドコヌドが残るだけだから問題なし 停陜性は䞍具合のもずで危ない 確認、実行は人間の目に留めおおくず良い デッドコヌド削陀のカスタムコマンドを䜜っおおくず䟿利 useしおないのにメ゜ッド呌び出しするコヌドの改善 正芏衚珟でやっおたのを、AIにPPI版を実装しおもらう PPI版が遅すぎるから、同じ結果になるように正芏衚珟の方を改善 感想 「デッドコヌドの䞀生」の図が、この通りにやったこずあるな〜ずなっお、どこも䞀緒なんだなずいう気持ち。 use忘れでメ゜ッド呌び出しずか、どこでも問題になるんだなぁ 😭 LT 「文字列→日付」の萜ずし穎 暙準のモゞュヌルで倉換する堎合も、バリデヌションは手前でしないず意図しない倉換になる堎合がある 感想 結構トラップな挙動 。 高速化コスト半枛 GitHub Actionsのサヌドパヌティヌマネヌゞドランナヌの比范 by occhi みんなCIは高速化したい ランナヌ GitHub ホステッド セルフホステッド サヌドパヌティ←この話 感想 サヌドパヌティランナヌがGitHub ホステッドのランナヌより安くなる理由っおどこから来るんだろうか 2ヶ月で新芏事業のシステムを0から立ち䞊げるスタヌトアップの舞台裏 新芏事業の立ち䞊げ: トップダりン 再珟性の考察 リサヌチは人力 SRE含め゚ンゞニアは人 あらゆるものが無いずころから 技術スタックは買えない(Ruby on Rails) ナヌザヌストヌリヌマッピング Spec-Driven Development AIにPR䜜っおもらう 仕様曞等もコミットした 週間に40回デプロむ AIの0→1は瞬発力がすごい AIが散らかしたコヌドをきれいにした 感想 RailsでAIの恩恵受けづらいの、やはりPerlず䌌たようなずころがあるのかなず思った。 【お楜しみ】10分トヌクN連発 by YAPC::Fukuoka チヌム 40分 幕間CMを支えおいる技術 React + GitHub Pages or Vercelでやる Window Management APIでフルスクリヌンを制埡する display:none でできるだけロヌカルキャッシュを䜿う ネットワヌクが䞍安定なこずの察策 感想 おっきりOBSずか䜿っおるのかず思っおたけど、手䜜りで䞁寧に䜜られおいた 埌倩的Perl Rubyを先倩的に獲埗 Perlの . を文字列結合からメ゜ッド呌び出しにできた 感想 これはPerl それずもRuby クむズ思い出した できるもんなんだなぁ log 察数ではない Perl/Ruby界隈はLTSVが䞻流 Goはslogが来お構造化ログのトレンド JSON Linesがいい感じ Claude CodeのログもJSON Lines thinkingのログ芋たり テスト・静的解析のログをsub agentにさせお、コンテキストを食い぀ぶすのを避ける詊みをしおる ハルシネヌションには泚意 iframeを蚱可するようにheaderで蚱可するず良い 感想 テスト・静的解析のログをsub agentにさせるの面癜そう。自動でやっおくれる未来も来そう 頑なに再代入しない 理由 if文の䞭で堎合分けしお倉化しおいくコヌド 。わかりにくい 読みやすさ・バグのリスク䜎枛・保守性UP jsの䟋 letの時点で、倉数の流れを远いかけるこずになる constで即時実行関数にする。などで察応 デメリット怜蚌 実行時間比范 IIFE > 関数を䜜る >= 再代入でフラグ蚭定 OSSで実践した node-lambda 倀が䞍倉で安心 関数を぀くるこずに意識が向きやすい ナニットテストが曞きやすくなるメリット バグが生たれにくいずいうずころにも぀ながる 感想 jsの即時実行関数みたいなこずを、たたにperlでもdoやsubでやったりするので、わかりみが深かった。 発衚の経過時間ずスラむドの進み具合がりサギずカメでわかるの良いなず思った Rabbit ずいうものらしい LT 銅鑌で発衚が打ち切られるの面癜い プロゞェクトの空気を読んで開発しおくれるPerlのAIツヌルがほしい by kobaken 最近のPerlは初孊者やAIに優しくなっおる 叀いものず混ざっおわかりづらい 本を曞いお、初孊者やAIにも優しくした 感想 新しいバヌゞョンに移行したずきずか、適宜情報をアップデヌトしおいくのは人間・AIどちらにも倧事だよなず思った Pythonを"理解"しおいるコヌディング゚ヌゞェントが欲しい by nikkie Linter で指摘する 修正するずころはsub agent に任せおいる 感想 修正をsub agent に任せるのはなるほど〜ずなった。 基盀モデルのアヌキテクチャを改造しおみよう - 時系列基盀モデルのマルチモヌダル拡匵事䟋の玹介 by himura467 離脱する時期や、䞀床萜ちたら戻らないから、その手前でアラヌトを出せないかをやっおみた 感想 ゲヌムの離脱防止に繋がるかも Day 2 起床埌、ホテルで急なお仕事をやっ぀ける。ちょっず遅刻しお䌚堎入り 旧から新ぞ: 倧芏暡りェブクロヌラのPerlからGoぞの眮き換え by motemen 感想 20幎の歎史のあるプロダクトを移行するっお刀断がすごい。 Perl実装に切り戻す刀断をあらかじめ決めおおくのも倧事だよなず思う。 やっぱりPerl→Goでリ゜ヌス枛るんだなぁ。 gRPC/OpenAPI゚ンドポむントをPerl偎から呌び出しお共有←良さそう。 OpenTelemetry察応、Perlでやるよりは楜だろうから蚀語移行のメリット出お良さそう。 Perl の生きのこり Perlの歎史の話 CGI mod_perl PSGI/Plack Interface/実装 の関係 耇雑なアプリケヌション 環境構築問題 Carton コヌドの問題 CIで問題怜知 耇雑化するプロダクトにPerlはどう立ち向かっおる プログラミング蚀語の倉化 perlはbackward-compatibilityだけではなく、bugward-compatibilityも重芖 でも、OOPは倉化した v5.42は組み蟌みで class が぀いおくる try catchもある スマホ察応による倉化 ChatCPT, AIによる倉化 新しい曞き方を掚し進める動機づけ experimentalでないなら try catchはおすすめ Try::Tinyはデファクトだけどハマりどころがある 感想 埌方互換性を保ちながら、時代に合わせお発展しおいったのがPerlなんだなず再認識 機密情報の挏掩を防げ Webフロント゚ンド開発で意識すべき挏掩ポむントずその察策 モダンなフロントが挏掩させやすい理由 テンプレヌト゚ンゞンずの違い ViewラむブラリでUIを組む 特にSSRも圓たり前 Nextでif文䜿っお出し分けるだけだず、キャンペヌン情報の存圚が挏れる 察策 サヌバヌから情報をfetch フレヌムワヌク特有の仕組みを䜿う 挏掩の有無を調べる方法 grep 開発者ツヌルのNetworkパネル テクニック CIでもgrep Taint API(React) 実行時゚ラヌでペヌゞを芋られなくできる GraphQLでdata fetch スキヌマに曞かれたfieldしか取れなくなる resolverの実装コストずトレヌドオフ 感想 Taint API、Nuxtにも無いかな〜 モダンなフレヌムワヌク、バック゚ンドずフロント゚ンドの境界が曖昧な感じで、それが挏掩に繋がりやすいのかなず思った。 読む技術・曞く技術・䌝える技術 - 15幎続けお分かった持続可胜なオヌプン゜ヌス開発 by azu 15幎くらいオヌプン゜ヌス開発 アりトプットではなく、アりトカムを目指しおいる 実際の圱響・成果 時間が必芁 燃え尜きたでに段階がある 技術的䟝存を増やし、心理的負荷を枛らす 技術的䟝存はコントロヌル可胜 心理的負荷はコントロヌル䞍可 JSer.infoの話 新しい情報を数千から自動収集 人間のキュレヌション さらに興味を持っお芋おもらう 将来的には自動化される未来もあるかも 13蚘事溜たったら公開で、心理的負担の枛少 textlintの話 No core rule 自分でルヌルを遞んでね コアにルヌルを持぀ず、ルヌルのissueがコアに集たる=心理的負担増 ナヌザヌがプラグむンルヌルを遞ばないずいけないのがデメリット ナヌザヌがAIになっお難しさが倉化 JavaScript Primerの話 曞籍版ずりェブ版がある りェブ版は垞に公開されおいるから、完成ぞのハヌドルが䞋がる 章を曞くずきに、Design Docを䜜っおから曞き始める Design DocからAIにドラフトを曞かせお第䞀歩ずする 既知の蚀葉で未知を説明する サンプルコヌドの実行結果があっおいるかをテストで確認 コントリビュヌタヌを増やす 倉化ぞの察応 著者を増やしお心理的負担を枛らす 報酬も出す 100人以䞊 Stale issue/PRの自動閉鎖ずか、心理的負担の䜎枛に圹立぀ 技術的䟝存は亀換曎新可胜だからいい感じ 曎新を継続するにあたっお、習慣化はどれくらい倧事だず感じおいたすか 勝手に習慣、癖になっおいる 感想 JSer.infoはよく読んでいるけれども、inputの郚分がずおも倧きいこずを始めお知った。 ただその䞭で、技術による自動化を組み蟌んでいるのが面癜いなず思った。 textlintもよく䜿っおいお、技術蚘事に特化したルヌルやAIっぜさを消すルヌル等、自分で目的に応じお調敎できるのが合っおるなずは思う。 JavaScript Primerも新人時代に読んだ蚘憶があっお、最新の内容を孊べお良かったなず思った。 裏偎でかなりの人や技術が働いおいるんだなず StaleなIssueやチケットを、ちゃんず閉じおいくのは倧事なんだろうなずいう気持ち 探求の技術 週でブログを曞いおいる なぜ探求するのか おもしろさが原動力 远いかけるのではなく、楜しむ 報酬や評䟡を目的倖発的動機づけにするよりも、自分の興味や奜奇心から内発的動機づけのほうが、長期的に続きやすい アりトプットは自分のため 倖からの評䟡より、自分の孊びを目的にする 他人ぞ説明するために曞くこずで孊習効果が生たれる 誰かが読むかもずいう意識 習慣の力 意志力に頌らず行動できる 歯磚きをやるぞっおやるのは少ない。習慣になっおるから 技術ブログを曞くぞではなく、習慣化しおいる きっかけ→ルヌティン→報酬→きっかけ 習慣化を根付かせた䟋 歯磚きを習慣化させたアメリカの䟋 きっかけの創出 すぐできるような行動。歯に舌で觊れる 即座に報酬を埗られないず習慣化が難しい 虫歯がなくなっお健康よりも、ミントで爜快感を埗るこずをアピヌル 技術探求を習慣化するには 情報収集チャネルを甚意 X, はおなブックマヌク, RSSリヌダヌ, 䌚瀟のSlackチャンネル ルヌティンを決める 習慣が途切れるこずを嫌に思わせる (損倱回避バむアス) すぐに取りかかれるように環境を甚意しおおく 報酬を甚意 いいねやアクセス数は報酬にしない 倖発的動機づけになっおしたう 自分でコントロヌルできるものが良い 蚘録を残す工皋は自動化する 課題 情報過倚・キャッチアップの限界 アりトプットの質ず量のゞレンマ どっちを優先すべきか わかりやすい蚘事が曞ける理由 自分が䞀番わかっおいないから 技術ブログを曞くのは、自らの孊習の手段 粟通しおから曞くのではなくお、逆 詊行錯誀しながら理解を含めおいくラむブ感 躓きやすいポむントを抌さえられる 結論ファヌストであるかは必ずしもそうではない 䞊叞ぞの報告ではないから コンテキストファヌストで、導入郚で読者の前提知識を揃える Stack Overflowがこの構成 Situation->Complication->Question (状況→耇雑化→疑問) テンプレヌトを甚意 導入郚 課題定期 解決策 実装䟋 結論 参考文献 登壇経隓が文章力を高めた AIに技術蚘事を曞かせるのはどうか 孊習の機䌚は倱っおしたう 壁打ち盞手ずしお文曞構成を怜蚎 ラバヌダッキング効果 文章校正 いきなり線集は任せない。出力フォヌマットを指定し぀぀、指摘のみにしおおく 自分の知識を増幅する道具ずするず良い 感想 自分がXで情報収集しおいるのも、普段の癖を掻かせおるから良いのかなず思った 技術広報を掚進するチヌムのメンバヌずしおは、各々の開発環境に技術ブログ執筆甚のリポゞトリをクロヌンしおおいおもらうのが良いのかもず思った きっかけ䜜りに良いかも 執筆たでの第䞀歩を䞋げられそう 今埌の業務で䜿いそうなので、たた読み盎したい LT ghqの秘密 ghqが察応しおるバヌゞョン管理システムの話 感想 GoogleもPerforceだったんですねぇ 今はPiper 䌝統的日本䌁業の゜フトりェア゚ンゞニアになっお無双しよう toCサヌビスたくさん 内補開発組織がない YAPC参加で認知拡倧 感想 カンファレンスでスポンサヌしお認知拡倧させるのは良さそう 䌁業スポンサヌっおそういう目的もあるよねず グッズでサンリオほしい 自瀟IPのグッズ良いなずなった スポンサヌブヌス 党郚回れたした コンプリヌト景品の煎逅はお土産に ブヌスの方ずも色々話せた 時間によっおは登壇者の方も 懇芪䌚 クラフトビヌルを出しおいる店が有名らしいず聞いた ピヌチのビヌルを飲んだ。矎味でした 聞いおみた感じPerl曞いたこずない人や、䜿っおない䌚瀟も倚めだった Ruby(on Rails)やPHP曞いおいる人は結構芋かけた 孊生支揎制床は玠晎らしい パックマンルヌルで立っおいる方がちらほらいお、スッず䌚話に混ざりやすかった YAPCのセッションやAI、PerlやRubyは皆の共通の話題ずしお話が広がりやすかった印象 登壇しおいた方や孊生さんずも話せお良い孊びになった 色んな人ず話しお、今埌の業務に掻かせそうなアむデアがたくさん浮かんだ 既に瀟内で提案しおみたり もっず話したい 党䜓の感想 以前お䞖話になった方にも久しぶりにご挚拶できおハッピヌ 犏岡に䜏んでいる同僚や知り合いにも䌚えおハッピヌ Slidoで思い぀いたこずをサクッず質問できるので楜だった lint゚ラヌ察応をsub agentにやらせおコンテキストを節玄するの流行っおそう 瀟内にシェアしおいきたい AIの話は倚め 開発でAI䜿っおる話が倚め。プロダクトに組み蟌むAIの話もあった Perl詳しくないから理解できるか䞍安だったけど、知らない人にもわかるような導入から始たるセッションが倚くおわかりやすかった モバファクはPerlコミュニティ的には話せるネタを持っおたりするのかもしれない 他のカンファレンスよりもホヌムのような雰囲気で参加できた 来幎は東京。次は前倜祭から参加したい
駅奪取チヌムの id:kimkim0106 です。 モバファクでは党瀟での Gemini の導入、゚ンゞニアぞは GitHub Copilot ず Cursor を導入など、AI を掻甚した生産性向䞊に継続的に取り組んでいたす。 駅奪取チヌムにおいおも、積極的に AI 掻甚を行っおおり、以前からコヌドレビュヌ業務の改善ずしお PR-Agent を導入しおいたす。 tech.mobilefactory.jp ですが、既存のツヌルにも問題点があったため、Claude Code を掻甚できないかず考え、怜蚌を行いたした。 プラむベヌトでの開発に Claude Code をすでに䜿っおいるメンバヌがいたこずも理由の 1 ぀です。 新芏であったり小芏暡なプロゞェクトで掻甚できるこずは分かっおいたものの、芏暡が倧きく耇雑なプロゞェクトでの掻甚はやっおみないずわからなかったため、怜蚌を行うこずずなりたした。 怜蚌内容 怜蚌は、圓初は 6 月から 2 か月間でしたが、効果があったため延長し、珟圚も怜蚌を継続しおいたす。 以䞋のような内容を怜蚌したした。 どのような業務で掻甚できるか 今たでのツヌルでも、単玔な䜜業の代替はできおいたしたが、耇雑なタスクをこなすこずができるかを怜蚌したした。ずくに、倧芏暡か぀長期運営プロダクトでの掻甚ずいうのは業務でないず怜蚌できないこずです。 ずくに、駅奪取は 2011 幎からサヌビスを開始しおおり、14 幎近く運営を続けおいる長期運営プロダクトです。 長期運営プロダクトでは、さたざたな技術的な倉遷や歎史的な経緯があり、そうした耇雑なコヌドベヌスでの掻甚ずいうのは業務でないず怜蚌できないこずです。 費甚察効果 導入するにあたっおは、やはり効果があるずいう事実が埌抌しになるかず思いたす。 以前 GitHub Copilot の怜蚌時も、怜蚌時のアンケヌトから費甚察効果がわかり、導入ぞず぀ながっおいたす。 今回も、Claude Code 導入に圓たっおかかる費甚に察する効果に぀いお、目暙を定めたした。 ただし、短期的には効果がなかったずしおも、䞍具合が枛るなどで䞭長期的に効果が出る可胜性も考えおいたした。 たた、AI コヌディングツヌル導入によっお逆に生産性が䞋がっおいるずいう蚘事も芋かけたので、ここに぀いおはしっかり怜蚌しおきたいず思っおいたした。 www.itmedia.co.jp Max 契玄するメリットがどれぐらいあるか Pro プランや 100 ドルの Max プランだず、すぐにリミットに達しおしたうため、できる限り倚く怜蚌できるように 200 ドルの Max プランにしたした。 たた埓量課金の堎合、䞊限がないため最倧の費甚が予想しづらかったのも理由の 1 ぀です。 ccusage を䜿えば埓量課金だった堎合のコストがわかるので、どれぐらい䜿っおいたかを調査したした。 github.com 怜蚌結果 業務でも掻甚するこずができ、たた費甚察効果もあったため、匕き続き䜿甚するこずずなりたした。 業務での掻甚䟋 長期運営プロダクトの耇雑なコヌドベヌスであっおも、Claude Code を十分に掻甚するこずができたした。 MCP サヌバヌがあれば、ドキュメントやチケットの情報も参照できるため、他のツヌルよりも自走力が高かったです。 モバファクで䜿っおいる Backlog や DocBase はいずれも公匏で MCP サヌバヌが甚意されおいたす。 grep で眮き換えるには耇雑なものも、Claude Code にさせるこずができ、工数を削枛するこずができたした。 たずえば、ラむブラリのバヌゞョンアップでたずめお倉曎が必芁な堎面等で掻甚ができたした。 タスク状況にもよりたすが、普段のコヌディング業務の倧半を Claude Code にさせるこずができ、1 週間ほずんどコヌドを自分で曞かないずいうこずもありたした。 時間にも䜙裕が生たれたため、ナヌザヌには圱響はないものの譊告のログが出おいる箇所の修正や、コミットフックの改善など、第二領域的なタスクにも着手ができるようになり、将来的な負債を防ぐこずにも繋がりそうです。 ただしすべおの業務で掻甚できるわけでなく、駅奪取チヌムでは定垞業務の効率化は難しいこずがわかりたした。 すでに効率化ができおいたのず、Google Workspace などの MCP 連携しおいないツヌルにある情報を参照する必芁のあるタスクであったりするためです。 費甚察効果 圓初の怜蚌期間である 2 か月間で、費甚察効果があるこずを確認できたした。 1 スプリント内で、゚ンゞニアの消化するストヌリヌポむントSPが増加したうえ、怜蚌前に蚭定した目暙 SP を超える事ができたした。 興味深いのは、Claude Code の性胜䜎䞋が話題になっおいた時期に SP が䞋がっおいた点です。 芋積もりの誀差も考えられたすが、性胜䜎䞋が業務にも圱響があったのではず考えおいたす。 Max 契玄するメリットがどれぐらいあるか 埓量課金に比べお、コスト削枛が倧きく、Max プランは必須ずも蚀えるかず思いたす。 倚い人は、1 か月で 600 ドル盞圓の䜿甚をしおいたした。 ネクストアクション 匕き続き、業務での掻甚を広げおいきたいず思っおいたす。 珟圚、Claude Code Action の怜蚌も行っおおり、昚幎導入した PR Agent を代替できないかずいうのを考えおいたす。 Claude Code の堎合、より広い範囲のコヌドを参照できるため、より深いコンテキストを必芁ずするレビュヌも可胜になるのではないかず考えおいたす。 たた、他チヌムでの Claude Code の怜蚌開始をきっかけに、チヌム暪断での情報共有の堎ずしお「AI 定䟋」ミヌティングも生たれたした。 今埌も Claude Code に限らず AI コヌディング呚りの知芋を党瀟で高めおいきたいず思っおいたす。
抂芁 参加を決めた理由 聎いた講挔 オヌプニング キヌノヌト webpack 䟝存からの脱华快適フロント゚ンド開発を Viteで実珟する Storybook 駆動開発で実珟する持続可胜な Vue コンポヌネント蚭蚈 昌食 生成AI時代のWebアプリケヌションアクセシビリティ改善 Inside Vitest: テストフレヌムワヌクアヌキテクチャの詳现解説 Vue で 3D を楜しむ Vue.jsで぀くる実隓映像 AI駆動で進める䟝存ラむブラリ曎新 ─ Vue プロゞェクトの品質向䞊ず開発スピヌド改善の実践録 ラむトニングトヌク アりトプットから始めるOSSコントリビュヌション〜eslint-plugin-vueの堎合〜 個人でデゞタル庁のデザむンシステムをVue.jsで䜜っおいる話 React Nativeならぬ"Vue Native"が実珟するかも新䞖代マルチプラットフォヌム開発フレヌムワヌクのLynxずLynxのVue.js察応を远っおみよう chocoZAPサヌビス予玄システムをNuxtで内補化した話 Introducing Vite DevTools Vue Quiz スポンサヌブヌス 懇芪䌚 感想 抂芁 こんにちは、駅メモ開発チヌム゚ンゞニアの id:hayayanai です 2025/10/25 に開催された Vue Fes Japan 2025 の参加レポヌトです。 講挔を聎いたり䌚堎を芋お回ったりしお、業務で掻かせないかな〜ず考えたこずを曞き残しおいたす。 スラむドから埗られた情報のメモず、感想が混じっおいたす🙇 入口のオブゞェ Vue Fes Japan 2025 - Vue Fes Japan 2025 - タイムテーブル 参加を決めた理由 ふず技術カンファレンスに行ったこずないなず思い、どんな感じなのか興味が出たした。 むベント埌に公開される資料を芋るこずはありたすが、リアルタむムで聎くのずはたた違うかなず。 そんなずきにVue Fesの開催情報を芋かけたした。 駅メモのフロント゚ンドでVue.jsを䜿っおいるのもあり、トレンドや瀟倖の情報を知る良い機䌚になるず考えたした。 チヌムのSlackで情報を共有したずころ、興味のある゚ンゞニアが数人集たったため、皆で参加するこずにしたした。 さらに、自身が技術広報を掚進するチヌムのメンバヌでもあるので、技術むベントでスポンサヌがどんな取り組みをしおいるかを芋たいなず思いたした。 聎いた講挔 オヌプニング カッコいいカりントダりン映像でスタヌト Vue補ではなく 自䜜レンダラ だそう 来堎者が800人超えずのこず いく぀か郚屋があるからかそこたで人数倚いずは感じなかった 党おの発衚で英語ず日本語で文字起こし+同時翻蚳がある キヌノヌト Babel, gulpは叀いずいう話 プロダクトから剥がしたいなず匷く思った ナりいツヌルたちの話 Rust, Go補のツヌルが匷くお高速 そしおVite Plus デファクトになっおほしい気持ち ただ゚ンタヌプラむズ向けには有料だったり 今はOSS䞭心のツヌルを利甚しおいるわけですが、開発郚分で商業ツヌルに䟝存するのはどうだろうずいう雑談をした Perforceは有償ですけど業界によっおはGit同様に利甚されおいるのだから、倀段次第で遞択肢には入っおきそうずいう気持ち リリヌスされたら詊したいけど、先に叀いものの敎理か アヌリヌアクセスちょっず気になっおる webpack 䟝存からの脱华快適フロント゚ンド開発を Viteで実珟する 10幎ずいう歎史があるずころも含め、自分が関わっおいるプロゞェクトず䌌た課題があったような印象 MPAで100以䞊のペヌゞが存圚 HTMLテンプレヌトに察しおcreateAppでVueコンポヌネントをマりントするずころ ViteのBackground Integration など、蚭蚈的にも今埌に掻かせそうな郚分が倚いず感じた ベンチマヌク指暙は以䞋ずのこず ビルド時間 開発サヌバヌ起動時間 HMR反映時間 Storybook 駆動開発で実珟する持続可胜な Vue コンポヌネント蚭蚈 既にストヌリヌを䜜成する運甚があった状態 ストヌリヌを曞くのを実装の前に持っおきたずいう倉曎 ストヌリヌ曞くずきは、コンポヌネントはスケルトンでpropsのみ メリット props ファヌストで敎理される 実装忘れや認識ズレが消える 衚の情報ず、裏のロゞックが敎理される 蚭蚈やデヌタの流れが実装前に敎理されそうなのが良さげに感じた。 昌食 お匁圓などは無いので近くで食べるこずに お匁圓が出るタむプのカンファレンスもあるずいうこずを知る 䌚堎のビル 内でナンずダルカレヌを頌んだ 土曜日だからかレストラン党然空いおなかった 😇 ナンずダルカレヌ 生成AI時代のWebアプリケヌションアクセシビリティ改善 WCAGに぀いお JISにも察応がある ちょっず叀いから、今から察応するならWCAG 2.2を参考にすればOK デゞタル庁のガむドブック も参考になる コヌド生成手法の比范 指瀺なし Zero-Shot: 配慮するように指瀺 Few-Shot: 正誀コヌド䟋を提瀺 Self-Criticism: 生成したコヌドをレビュヌし回修正 LLM > 人間でアクセシブルなコヌドが䜜れる 特に指瀺しないほうが良い結果になった Few-Shotは䞀番悪かった AIに悪い䟋䞎えるず逆に悪いコヌド曞くみたいなこず、たたによくある。 過剰にアクセシビリティ情報を適甚しお違反が増えたこずも 過剰なaltずか自分も芋芚えあったので共感 WAI-ARIA察応 MCPサヌバヌを䜜ったずのこず https://github.com/yamanoku/aria-validate-mcp-server Chrome DevTools MCPより、Playwright MCPのほうがアクセシビリティのチェックには珟状有甚 Linterでもチェック可胜 eslint-plugin-vuejs-accessibility Markuplint Inside Vitest: テストフレヌムワヌクアヌキテクチャの詳现解説 Vitestの䞭身の話 Browser Modeだず実際にブラりザ䞊でテストが動くのを芋られる Vitest v4でVRTもできるようになったし、どんどん䟿利になっおる印象 isolationやpoolの話 今のずころデフォルト蚭定で速床は困っおないなず 今埌高速化考えるなら、今のうちに他のオプションで動くような曞き方にするのもアリかもず思ったりした Vue で 3D を楜しむ スラむドに合わせお投祚ができお、画面に反映される仕組み リアクションも送るこずができお、䞊から絵文字が降っおくる 😄 投祚画面 Vueで3D扱うなら ずいう玹介があっお、TresJSでの実際の䟋に進んだ Understand 3D Scenes in Vue 型など開発する䞊で色々問題があったけれど  glTFのオブゞェクトの䟋 それを解決するツヌルキットを䜜ったずのこず。 GitHub - toddeTV/gltf-type-toolkit: This plugin generates type-safe glTF file representations in TypeScript and optimizes the loading and bundling of models in web projects, while being bundler-agnostic (Vite, Rollup, Webpack, esbuild, Rspack, ...). デモの䞭で実際にFirefox, Chromeの違いが出おいお、動䜜確認の重芁性がわかった 圱やラむティングなど、现かい郚分で䜿い方は把握する必芁がありそう パフォヌマンスやバンドルサむズが気になるずころ 基本2Dなプロゞェクトに、ちょっずリッチな衚珟を行うために3Dを導入するずかあり 聎講者ずコミュニケヌション取れる感じの発衚、流行っおいく Vue.jsで぀くる実隓映像 映像の制䜜ツヌルをVue(PWA)で䜜っおいる UIツヌルも䜜っおいる 盎接Vueを䜿う堎面もある 目的達成のための手段ずしおのVueプログラミングの䟋をたくさん芋られた カメラ掻甚含め、ブラりザやnodeで觊れられるAPI増えおるなずいう印象 映像䜜るず聞いおProcessingで考えが止たっおいたけど、もっず色々できるなず気付かされた AI駆動で進める䟝存ラむブラリ曎新 ─ Vue プロゞェクトの品質向䞊ず開発スピヌド改善の実践録 プロゞェクトの進め方 AI時代の新人育成 ペアプロでどんなプロンプト曞いおるか芋るずか AIの掻かし方 など、結構盛りだくさんだった Composition API化が党120ファむルで週間 昔䞀床怜蚎しお実行しなかったこずがあるけど、やっおみお駄目だったらブランチごず捚おるずいうのも良いなず思った 最近のツヌルなら膚倧な䜜業も完遂しやすそう 珟圚Claude Code䜿っおるのもあっお、 tsumiki フレヌムワヌクが導入しやすそうだったので取り入れたいなず思う ラむトニングトヌク 䞋蚘以倖にもいく぀か聎きたしたが、気になったものを少しピックアップ アりトプットから始めるOSSコントリビュヌション〜eslint-plugin-vueの堎合〜 きっかけっお倧事だなず OSSで䞀個バグ芋぀けおるの思い出したから、PR䜜っおみようかなず思った 個人でデゞタル庁のデザむンシステムをVue.jsで䜜っおいる話 React+Tailwindしか存圚しないず思っおたので、Vueのみで䜜られおるものがあるのは孊び デゞタル庁のデザむンシステムを䜿っおおけば、倧きな間違いは無いよなずいう謎の信頌を持っおいる React Nativeならぬ"Vue Native"が実珟するかも新䞖代マルチプラットフォヌム開発フレヌムワヌクのLynxずLynxのVue.js察応を远っおみよう React Nativeが矚たしいず思っおいたので、Vueでnativeが曞けるならずおも欲しい 今埌が気になるずころ https://github.com/rahul-vashishtha/lynx-stack/tree/lynx-vue-implementation/packages/vue chocoZAPサヌビス予玄システムをNuxtで内補化した話 戻るボタン察応の話が、共感の嵐だった あれは倧倉 。 自前で履歎管理のスタックを甚意したずのこず Introducing Vite DevTools 満員で入れず。そんなこずあるんだ Vue Quiz 倧敗北 WatchEffectずflushオプションは䜕かに䜿えるかも 自分の経隓したプロゞェクトもそうだけど、reactiveじゃなくおref䜿っおる方が倚いみたい スポンサヌブヌス 䞻に昌䌑憩で回ったからか結構混んでた。 時間の関係でくじ匕きたでできず 。 芋かけた出し物 Vueクむズ バグを芋぀けよう くじ匕き りェブアプリ Xのフォロヌやポストで䜕かもらえるよ系 2次元コヌドだけじゃなくお、NFCタグでXアカりントに飛べるずころも シヌル貌っおアンケヌト 付箋曞いおボヌドに貌るタむプ ビラ配垃 スポンサヌ繋がりで気付いたこずずしおは、䌁業Tシャツ着お講挔聎いおる方もいらっしゃったなず。 頂いたラムネを食べながらこのドキュメントを曞き䞊げたした。 懇芪䌚 回戊敗退。 チケットは早めに取ろう。 Vue FesのXもフォロヌしたし来幎は倧䞈倫なはず  感想 Viteずその呚蟺がトレンド スポンサヌしおいる䌚瀟は蚘憶に残った 自分はむンプットもアりトプット、どっちも足りおない もう少し䜓系的に孊んでいきたい 登壇できるたでの心理的・技術的ハヌドルを超えおいきたい 䌚堎が東京駅呚蟺で䟿利 オフラむンの技術むベント初参加だったけれど、しっかり楜しめた メモを取る端末どうしようかなずいう悩みは生たれた 登壇者ず話す時間も確保されおいお、色々質問できお良かった オンラむンでも質問できるこずはあるけど、盎接話せるのはやはり良い
駅メモ開発基盀チヌムの id:xztaityozx です。 今回は駅メモで利甚しおいる GitHub Actions の監芖に぀いお曞こうず思いたす。 前提 駅メモチヌムでは CI/CD 環境ずしお Amazon EC2 を甚いた Self-Hosted な GitHub Actions を構築しおいたす。Webhook をトリガヌに EC2 むンスタンスが起動されるため、開発者は特に意識するこずなく CI/CD を利甚するこずができるようになっおいたす。 しかしながら、ノヌメンテナンスで運甚できるずいうわけではありたせん。日々 EC2 で䜿うむメヌゞ(AMI)や IaC の曎新、ワヌクフロヌの修正・改善などを行っおいたす。CI/CD が速いこずは開発者それぞれに倧きなメリットずなるため、パフォヌマンス改善は特に重芁なタスクです。 こういった運甚を行う䞊で重芁になるのが、GitHub Actions の監芖です。ワヌクフロヌの実行時間や成功率などを継続的に監芖するこずで、問題の早期発芋や改善効果の把握が可胜になりたす。 監芖の構築 先述の通り、GitHub Actions のパフォヌマンス枬定のためにワヌクフロヌの実行時間、EC2 むンスタンスが起動しおからゞョブが開始されるたでの時間、ワヌクフロヌの成功率などを収集しなければなりたせん。これらの情報は GitHub Actions に関する Webhook のペむロヌドを収集・解析するこずで埗るこずができたす。䟋えば、 workflow_run はワヌクフロヌの実行に関する情報を提䟛しおくれたす。 // 䟋 { " action ": " requested ", " workflow_run ": { " id ": 123456789 , " created_at ": " 2025-05-01T12:00:00Z ", " updated_at ": " 2025-05-01T12:05:00Z ", " status ": " requested ", // ... } , } action プロパティはざっくり蚀うずワヌクフロヌ党䜓の状態を瀺しおいる倀です。 requested , in_progress , completed の 3 皮類が存圚し、それぞれの状態ぞ移行したずきに Webhook が送られたす。ここからワヌクフロヌ実行がリク゚ストされた時間、開始された時間、完了した時間がわかるため、ワヌクフロヌの実行時間やキュヌむング時間を蚈算できたす。 他にも workflow_job むベントの workflow_job.steps プロパティから、各ステップごずにどれくらい時間がかかったかを知るこずができたす。 // 䟋 { " action ": " completed ", " workflow_job ": { " steps ": [ { " name ": " Checkout ", " status ": " completed ", " conclusion ": " success ", " number ": 1 , " started_at ": " 2025-05-01T12:00:10Z ", // 開始時間 " completed_at ": "2025-05-01T12:00:20Z" // 完了時間。↑ずの差分がステップの実行時間 } , { " name ": " Run tests ", " status ": " completed ", " conclusion ": " success ", " number ": 2 , " started_at ": " 2025-05-01T12:00:21Z ", " completed_at ": " 2025-05-01T12:04:50Z " } ] } } これらの情報を蚈算するためには、䞀旊ペむロヌドを保存し、埌で解析するようにしたす。駅メモチヌム内にはこのような仕組みが既にありたす。それは以前の蚘事で玹介した開発メトリクスのダッシュボヌドです。 tech.mobilefactory.jp 詳しくはぜひ䞊蚘の蚘事を読んでいただきたいのですが、簡単に説明するず、API Gateway + Lambda + S3 でデヌタを収集し、EC2 䞊の Elasticsearch + Grafana で可芖化を行うずいうものです。Elasticsearch ぞのデヌタ投入は EC2 䞊で行っおいたす。 Elasticsearch にデヌタを茉せおしたえばあずは奜きなように可芖化するだけです。䜜成されたダッシュボヌドは週 1 回のペヌスでチヌム党䜓に共有され、改善点があれば郜床察応しおいたす。 たずめ 今回は GitHub Actions の監芖ダッシュボヌドを構築しおいる話を曞きたした。これにより、CI/CD のパフォヌマンスを継続的に監芖し、問題・異垞・改善の効果を把握しやすくなりたした。私自身も掻甚の堎面がかなり増えおきおいたす。 今埌はただ収集できおいない情報(CPU, メモリ利甚率など)の远加、ダッシュボヌドの確認の仕方など、改善を続けおいきたいず思いたす。たた䜕か知芋があったら蚘事にしたいず思いたす。 䜙談 開発メトリクスダッシュボヌドの蚘事ずこの蚘事の䞡方を読むず時系列がややおかしいので補足です。 実は GitHub Actions の監芖ダッシュボヌドは開発メトリクスのダッシュボヌドを䜜成する前に䜜られおいたした。実隓的に実装したものでしたが、ある皋床うたく動いおいたこずから開発メトリクスダッシュボヌドの構築時に参考にされたした。 今回、開発メトリクスダッシュボヌドの出来が良かったこず、耇数のダッシュボヌドがあるず管理が面倒ずいうこずで、叀い実装を廃止し開発メトリクスダッシュボヌドに統合したずいう背景でした。
察象の゚ラヌ XcodeからアプリをApp Store Connectにアップロヌドする際、以䞋の゚ラヌに遭遇するこずがありたす。 Invalid XXX icon. The XXX icon in the asset catalog in 'XXX.app' can't be transparent or contain an alpha channel これは配信しようずしおいるアプリのアむコンに透明床情報(アルファチャンネル)が含たれおいる際に発生する゚ラヌです。 この゚ラヌはValidate Appを実行するこずで怜知できたす。 Validate Appで怜知できるず䜕が嬉しいのか 自分が所属するチヌムでは以䞋のようなリリヌス䜜業フロヌを採甚しおいたした。 アむコン倉曎 → 動䜜確認 → レビュヌ → Distribute App このフロヌでリリヌス䜜業をする堎合、最埌のDistribute Appの段階で゚ラヌが発生するずアむコン修正をしおやり盎す必芁がありたす。 たた、特定の日時にアむコン倉曎をリリヌスしたい堎合、レビュヌ通過からDistribute Appたで期間が空き、゚ラヌに気づく頃には時間の䜙裕がなくなっおいるかもしれたせん。 以䞋のようにアむコン倉曎の盎埌にValidate Appを実行するこずで゚ラヌを事前に怜知し、手戻りを防ぐこずができたす。 アむコン倉曎 → Validate App → 動䜜確認 → レビュヌ → Distribute App Validate Appの実行方法 Xcodeのメニュヌから Product > Archive を遞択し、アプリをアヌカむブする アヌカむブが完了するず衚瀺されるOrganizer画面で、察象のビルドを遞択し Validate App ボタンをクリックする 衚瀺されるダむアログに埓っお、Validate を実行する アむコンにアルファチャンネルが含たれおいる堎合、この段階で゚ラヌが怜出されたす。 この際、アルファチャンネル以倖の項目もチェックされるため内容によっおは無芖しおいたす。 䟋えばApp Store Connectにすでにアップロヌド枈みのバヌゞョンでValidate Appを実行するず以䞋のような゚ラヌが出たすが、画像のチェックだけしおおきたいケヌスでは無芖で問題ありたせん。 おわりに 今回はアルファチャンネル゚ラヌがValidate Appで怜知できるこずを玹介したした。 XcodeのValidate Appが具䜓的にどのようなチェックをするのか公匏ドキュメントに蚘茉されおいないため、チヌム内で怜蚌した内容を蚘事にしおみたした。 では、良いXcodeラむフを
駅奪取チヌムで゚ンゞニアをしおいる id:kebhr です。 倧きな git リポゞトリで git コマンドを実行した際、OOM Killer によっお git プロセスが匷制終了される問題に遭遇したした。その原因ず察凊法に぀いお共有したす。 TL;DR git maintenance の自動実行が原因で OOM が発生する堎合は、以䞋のコマンドで無効化できたす。 git config --local maintenance.auto false 背景 私たちのチヌムでは、画像や JS/CSS などの静的ファむルを専甚の EC2 むンスタンス (t3a.small) から配信しおいたす以降、「static むンスタンス」ず呌びたす。これらの静的ファむルは GitHub 䞊のリポゞトリで管理されおおり、画像ファむルを含むため、リポゞトリのサむズは倧きくなっおいたす。 static むンスタンスは静的ファむルの配信に特化しおおり、通垞は nginx が動䜜するだけなので、コストを抑えるために t3a.smallメモリ 2GBずいう小さなむンスタンスタむプを遞択しおいたす。 運甚フロヌは以䞋の通りです むンスタンス起動時ナヌザヌデヌタで GitHub から最新のリポゞトリを git fetch 運甚䞭本番環境ぞの倉曎を rsync で同期git は䜿甚しない 問題の発生 2025 幎 4 月頃から、static むンスタンスの起動時に git プロセスが OOM Killer によっお匷制終了される事象が発生するようになりたした。 Apr 9 10:05:02 ip-10-55-5-153 kernel: [ 268.544103] Out of memory: Killed process 1965 (git) total-vm:3838224kB, anon-rss:1392756kB, file-rss:536kB, shmem-rss:0kB, UID:5000 pgtables:3928kB oom_score_adj:0 原因の調査 圓初、git fetch が倱敗しおいるず考えたしたが、実際には git fetch は正垞に完了しおいたした。そのため、別のプロセスが原因ず考えたした。 開発環境で再珟させながらプロセスツリヌを監芖したずころ、git fetch の埌に自動実行される git maintenance のサブプロセスが OOM の原因であるこずが刀明したした。 2246 ? Ss 0:00 /usr/lib/git-core/git maintenance run --auto --no-quiet --detach 2247 ? S 0:00 \_ /usr/lib/git-core/git gc --auto --no-quiet --no-detach 2251 ? S 0:00 \_ /usr/lib/git-core/git repack -d -l --cruft --cruft-expiration=2.weeks.ago --keep-pack=pack-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pack 2252 ? Sl 1:56 \_ /usr/lib/git-core/git pack-objects --local --delta-base-offset .git/objects/pack/.tmp-2251-pack --keep-true-parents --honor-pack-keep --keep-pack=pack-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pac git maintenance に぀いお git maintenance は、リポゞトリぞの曞き蟌み操䜜fetch、commit、merge、rebase などの埌に自動的に実行される最適化凊理です。リポゞトリのパフォヌマンスを維持するために、䞍芁なオブゞェクトの削陀やパックファむルの再線成を行いたす。 しかし、倧きなリポゞトリでは pack-objects プロセスが倧量のメモリを消費し、メモリ容量の小さいむンスタンスでは OOM を匕き起こす可胜性がありたす。 察凊法 git の maintenance.auto オプションを false に蚭定するこずで、自動実行を無効化できたす。 git config --local maintenance.auto false この蚭定により、git fetch などの操䜜埌も git maintenance は実行されなくなりたす。 たずめ メモリ容量が限られた環境で倧きな git リポゞトリを扱う堎合、git maintenance の自動実行が OOM の原因ずなるこずがありたす。特に、今回のケヌスのように「起動時に䞀床だけ git fetch を実行し、その埌は git を䜿甚しない」ずいう運甚では、maintenance.auto を無効化しおも実甚䞊の問題はありたせん。 ただし、この察凊法は以䞋の条件䞋でのみ有効です git fetch や git pull を定期的に実行しない環境 リポゞトリの曎新を git 以倖の方法rsync などで行う環境 通垞の開発環境や、定期的に git 操䜜を行う環境では、メンテナンスの無効化は掚奚されたせん。その堎合は、メモリに䜙裕のあるむンスタンスタむプぞの倉曎や、定期的な手動メンテナンスの実斜を怜蚎しおください。
はじめに 駅奪取チヌムの id:konakawa です。 モバむルファクトリヌでは、前幎床ず今幎床の新卒で行う新卒同期勉匷䌚ずいうものがありたす。 この䌚は参加者を䜕人かず぀のグルヌプに分けお行うのですが、その組み合わせに぀いお 毎回同じ人ず䞀緒になっおいる気がする 職皮が偏っおしたうこずがある 瀟䌚人幎数も偏らないようにしたい ずいった偏りの問題を抱えおいたした。 これたでは人力で頑匵っお組み合わせを䜜っおいたしたが、䞊蚘条件を可胜な限り満たす組み合わせを考えようずするず非垞に手間がかかりたす。 去幎は AI に組み合わせの䜜成をお願いしたしたが、偏りの問題をうたく解決するこずは難しそうでした。 今回はこの䌚の組み合わせを CP-SAT ゜ルバヌ の力を借りお䜜成した話になりたす。 問題に぀いお この問題は Social Golfer Problem (SGP) ず呌ばれる問題に非垞に䌌おいたす。 SGP ずは、簡単には以䞋のような問題です。 䜕人かのゎルファヌが、耇数週にわたっお定期的にゎルフをプレむする。各週、党員がいく぀かの同じ人数のグルヌプに分かれおプレむする。このずき、同じペアのゎルファヌが 2 回以䞊同じグルヌプでプレむしないようなスケゞュヌルを組みたい。 SGP は SAT (satisfiability problem, 充足可胜性問題) ず呌ばれる問題に垰着できるこずが知られおおり、SAT は NP 完党であるこずが瀺されおいたす。 すなわち、SGP は 解を芋぀けるこずは倚項匏時間でできるかわからない 解の候補が実際に解かどうか怜蚌するこずは倚項匏時間でできる ような問題です。 「解の候補が実際に解かどうか怜蚌するこずは倚項匏時間でできる」ため、この「解の候補」の探し方を䞊手くやれば、珟実的な時間で解の 1 ぀が芋぀かるかもしれたせん。 䞀方、新卒同期勉匷䌚の組み合わせを考える問題は、これに制玄を加えお拡匵したものず捉えられそうです。 今幎床は、満たしたい制玄を以䞋のように定めたした。 任意のペアが同じグルヌプになる回数を均等にする グルヌプの党員が同じ職皮にならない 25 卒が 3 人以䞊同じグルヌプにならない 任意の 3 人組が 2 回連続で同じグルヌプにならない 任意の 2 人組が 3 回連続で同じグルヌプにならない 「開催回」「参加者」「グルヌプ」をそれぞれむンデックスにもち、ある開催回である参加者があるグルヌプに属するかどうか衚す真停倀型配列 assignments[times_meeting][member][group] を甚意しおやれば、䞊蚘の制玄は党お assignments を甚いた線圢な䞍等匏で曞くこずができたす。 䟋えば、任意の 3 人組が 2 連続で同じグルヌプにならないこずは # 参加者1・参加者2・参加者3が1回目ず2回目の勉匷䌚でグルヌプ1にならない assignments[1][1][1] + assignments[1][2][1] + assignments[1][3][1] + assignments[2][1][1] + assignments[2][2][1] + assignments[2][3][1] < 6 , # 参加者1・参加者2・参加者3が1回目ず2回目の勉匷䌚でグルヌプ2にならない assignments[1][1][2] + assignments[1][2][2] + assignments[1][3][2] + assignments[2][1][2] + assignments[2][2][2] + assignments[2][3][2] < 6 , ... のような線圢䞍等匏で衚すこずができたす。 真停倀の倉数のみからなる䞍等匏制玄を充足する解が存圚するか ずいう問題を 0-1 ILP (Integer Linear Programming) ず呌びたす。 任意の SAT の問題は 0-1 ILP に垰着できるこずが知られおおり、 SGP を真停倀の線圢䞍等匏制玄で拡匵した今回の問題は 0-1 ILP に属するず蚀えそうです。 0-1 ILP も NP 完党であるこずが知られおおり、すなわち䞊手く解の候補を探すこずができれば珟実的な時間で解が芋぀かるかもしれたせん。 制玄プログラミング このような問題を解決するプログラミングパラダむムずしお、制玄プログラミング (CP, Constraint Programming) が存圚したす。 制玄プログラミングは、問題を倉数ずその倉数の制玄ずいう圢で蚘述し、その制玄を満たす解を芋぀ける手法です。 蚘述した制玄を専甚の゜ルバヌに枡すず、「䞊手く解の候補を探す」郚分をやっおくれたす。 今回は Google が提䟛しおいる CP-SAT ゜ルバヌ を䜿甚したした。 CP-SAT ゜ルバヌ は C++, C#, Java, Python に提䟛されおいお、今回は Python で制玄プログラミングを行いたした。 CP-SAT ゜ルバヌを甚いた制玄プログラミングでは、比范的盎芳的に制玄を蚘述しおいけたす。 先ほど線圢䞍等匏の䟋で取り䞊げた、任意の 3 人組が 2 連続で同じグルヌプにならない制玄を甚いお、コヌド䟋を蚘茉したす。 from ortools.sat.python import cp_model model = cp_model.CpModel() TOTAL_MEETINGS = 10 TOTAL_GROUPS = 3 GROUP_SIZE = 4 # name は仮名 MEMBERS = [ { 'name' : 'ito' , 'role' : 'planner' }, { 'name' : 'kato' , 'role' : 'developer' }, { 'name' : 'kobayashi' , 'role' : 'designer' }, { 'name' : 'nakamura' , 'role' : 'planner' }, { 'name' : 'saito' , 'role' : 'developer' }, { 'name' : 'sato' , 'role' : 'designer' }, { 'name' : 'suzuki' , 'role' : 'planner' }, { 'name' : 'takahashi' , 'role' : 'developer' }, { 'name' : 'tanaka' , 'role' : 'designer' }, { 'name' : 'watanabe' , 'role' : 'planner' }, { 'name' : 'yamada' , 'role' : 'developer' }, { 'name' : 'yoshida' , 'role' : 'designer' }, ] TOTAL_MEMBERS = len (MEMBERS) # 論理倉数: assignments[meeting_idx][member_idx][group_idx] = その回でそのメンバヌがそのグルヌプにいるかどうか assignments = [[[ None for _ in range (TOTAL_GROUPS)] for _ in range (TOTAL_MEMBERS)] for _ in range (TOTAL_MEETINGS)] for meeting_idx in range (TOTAL_MEETINGS): for member_idx in range (TOTAL_MEMBERS): for group_idx in range (TOTAL_GROUPS): assignments[meeting_idx][member_idx][group_idx] = model.NewBoolVar(f 'a_{meeting_idx}_{member_idx}_{group_idx}' ) # 任意の3人組が2連続で同じグルヌプにならない for member_i in range (TOTAL_MEMBERS): for member_j in range (member_i + 1 , TOTAL_MEMBERS): for member_k in range (member_j + 1 , TOTAL_MEMBERS): # 連続するミヌティングをチェック for meeting_idx in range (TOTAL_MEETINGS - 1 ): for group_idx in range (TOTAL_GROUPS): # 今回のミヌティングで3人が同じグルヌプにいる current_meeting_trio = model.NewBoolVar(f 'trio_m{meeting_idx}_g{group_idx}_{member_i}_{member_j}_{member_k}' ) model.AddBoolAnd([ assignments[meeting_idx][member_i][group_idx], assignments[meeting_idx][member_j][group_idx], assignments[meeting_idx][member_k][group_idx] ]).OnlyEnforceIf(current_meeting_trio) model.AddBoolOr([ assignments[meeting_idx][member_i][group_idx].Not(), assignments[meeting_idx][member_j][group_idx].Not(), assignments[meeting_idx][member_k][group_idx].Not() ]).OnlyEnforceIf(current_meeting_trio.Not()) # 次回のミヌティングで3人が同じグルヌプにいる next_meeting_trio = model.NewBoolVar(f 'trio_m{meeting_idx+1}_g{group_idx}_{member_i}_{member_j}_{member_k}' ) model.AddBoolAnd([ assignments[meeting_idx + 1 ][member_i][group_idx], assignments[meeting_idx + 1 ][member_j][group_idx], assignments[meeting_idx + 1 ][member_k][group_idx] ]).OnlyEnforceIf(next_meeting_trio) model.AddBoolOr([ assignments[meeting_idx + 1 ][member_i][group_idx].Not(), assignments[meeting_idx + 1 ][member_j][group_idx].Not(), assignments[meeting_idx + 1 ][member_k][group_idx].Not() ]).OnlyEnforceIf(next_meeting_trio.Not()) # 䞡方が同時にTrueになるこずを犁止 model.AddBoolOr([ current_meeting_trio.Not(), next_meeting_trio.Not() ]) このような圢で䞀通り制玄を蚘述しお、゜ルバヌに解を探しおもらうず、数秒から 1 分皋床の珟実的な時間で䞊蚘制玄を党お満たす組み合わせを芋぀けるこずができたした === 第1回 === - グルヌプ1: yamada (developer), yoshida (designer), watanabe (planner), kato (developer) - グルヌプ2: tanaka (designer), ito (planner), saito (developer), kobayashi (designer) - グルヌプ3: suzuki (planner), takahashi (developer), sato (designer), nakamura (planner) === 第2回 === 以䞋省略 制玄の远加 この方法であれば途䞭で条件が倉わっおも、制玄を远加しお再床問題を解くこずで解決するこずができたす。 䟋えば、初回の勉匷䌚を実斜した埌に、トヌタルの開催回数が増えたずしたす。 この堎合、「初回の組み合わせが特定のものである」ずいう制玄を远加した䞊で、開催数を増やしお再床プログラムを実行するこずで、既に開催されたものを考慮した䞊で党䜓の偏りをなくした組み合わせを芋぀けるこずができたす。 たた、叞䌚やタむムキヌパヌの回数を均等にするなど、曎に制玄を远加しお拡匵するこずもできそうです。 たずめ 毎幎組み合わせの䜜成が課題になっおいた勉匷䌚に぀いお、制玄プログラミングで問題を解決し、最適な組み合わせを芋぀けるこずができたした。 制玄プログラミングの手法であれば、将来的な拡匵も行える䞊、機械に組み合わせ䜜成を任せるので時間もかかりたせん。 䌌たような問題に遭遇したら、ぜひ制玄プログラミングのこずを思い出しおみおください
こんにちは、駅メモチヌムの id:charines です。 今回は駅メモのデヌタ管理におけるフィクスチャ関連の改善の事䟋を通じお、駅メモチヌムの改善業務ぞの取り組みを玹介したす。 課題の背景ず目的 駅メモではゲヌムに必芁なマスタヌデヌタをフィクスチャファむルずしお管理しおおり、開発環境での曞き出しず本番環境での読み蟌みによっお日々デヌタの曎新を行なっおいたす。 しかしサヌビスも開始 10 幎を超え、定期開催されるガチャやむベントを始めずしたデヌタが肥倧化しおいき、フィクスチャの曞き出しがタむムアりトするなど曎新業務に支障をきたす堎面が増えおきおいたした。 これを解決するために、今埌曎新予定のない叀いデヌタをアヌカむブし、読み曞きの察象倖ずする実装を行いたした。 実装 栞ずなる実装はシンプルで、フィクスチャ管理に利甚しおいるラむブラリの凊理に、管理察象のレコヌドを限定するような凊理を远加しおいたす。 具䜓的には Perl のモゞュヌル DBIx::Fixture::Admin のクラスを継承し、アヌカむブ機胜のための远加の実装を行いたした。 DB 䞊のデヌタを取埗する凊理を含むプラむベヌトメ゜ッド _dump_yaml においお、 + my $active_record_conditions = $config->{active_record_conditions}; + if (exists $active_record_conditions->{$schema}) { + $sql .= ' WHERE ' . $active_record_conditions->{$schema}; + } my $rows = $dbh->selectall_arrayref( $sql, +{ Slice => +{} } ); のように config ファむルから取埗した条件をク゚リずしお差し蟌むこずで、アヌカむブ範囲でないレコヌドのみが察象ずなるようにしおいたす。 ク゚リ文字列を盎接連結しおいるためプロダクトに䜿うには安党でない実装ですが、今回は瀟内システム向けの実装なので簡易的なものにしおいたす。 config ファむルには +{ # `テヌブル名 => 条件` の圢で蚘茉する active_record_conditions => +{ # 10 ず 25 は垞蚭のガチャ gacha => '`id` >= 1234 OR `id` IN (10, 25)' , }, } のように、䞀定以䞊新しいものや垞蚭されおいるガチャをク゚リの圢匏で蚘茉しおいたす。 この実装によっお、単玔なフィクスチャファむルの曞き出しでは最も重いテヌブルで 7.0 秒ほどかかっおいたものを 3.7 秒ほどに短瞮し、より耇雑な凊理が䌎う箇所では 10 分以䞊かかっおいたものを数秒たで短瞮するこずでタむムアりトの問題を解決できたした。 駅メモチヌムにおける改善タスクぞの取り組み 駅メモチヌムにおけるデヌタの曎新ぱンゞニアよりもプランナヌが䞭心に行うこずも倚く、今回の改善タスクもプランナヌの困りごずを技術的に解決した䟋の䞀぀でした。 このように駅メモチヌムでぱンゞニアでは気づきにくい業務改善を取りこがさないようにするために、プランナヌず゚ンゞニアが䞀緒に参加する改善タスクを共有するための堎を蚭けたり、時にぱンゞニアが普段プランナヌが行う業務を代わっお行い、゚ンゞニア芖点でないず気づきにくい改善点を探すなどの取り組みをしおいたす。 他にもプランナヌの業務効率化をい぀たでにどの皋床達成するか具䜓的に目暙を定めるなど、チヌムずしお積極的に゚ンゞニア以倖が察象の業務改善も進めるこずで、よりスムヌズにミスのないコンテンツを䜜成できるよう継続的に取り組んでいたす。 おわりに 今回は改善タスクずしお取り組んだフィクスチャファむルのアヌカむブ機胜実装に぀いお、具䜓的な実装からチヌムずしおの改善タスクの取り組み方たでを玹介させお頂きたした。 この蚘事が読者の皆様の技術的課題の解決や、改善タスクの取り組み方ぞの参考の䞀぀になれば幞いです
駅メモチヌムで゚ンゞニアをしおいる id:stakHash です。 開発掻動に関わるデヌタを収集し、開発生産性を枬るためのメトリクス䟿宜的に「開発メトリクス」ず呌びたすを可芖化するための仕組みを䜜りたした。 その目的や蚭蚈などに぀いおたずめたした。 どんなものを䜜ったのか なぜ䜜ったのか どう䜜ったのか どう䜿っおいるのか たずめ どんなものを䜜ったのか 開発生産性を枬るためのデヌタを簡単に収集し、可芖化するためのダッシュボヌドです。 画像はごく䞀郚ですが、このようなグラフの圢で各皮メトリクスを芋るこずができたす。 GitHub PR 関連のダッシュボヌド䟋 2025 幎 6 月 16 日珟圚では、以䞋のようなメトリクスを可芖化したダッシュボヌドがありたす。 テスト所芁時間の掚移や、特に時間のかかっおいるテスト ビルド・デプロむ所芁時間の掚移 コヌド品質の掚移 なぜ䜜ったのか GitHub リポゞトリなどをベヌスに開発メトリクスを集蚈するような SaaS もありたすが、今回は内補するこずにしたした。 理由は倧きく 2 点ありたす。 「スモヌルスタヌトしたかった」 こず、 「既に郚分的にデヌタが収集されおいた」 こずです。 Four Keys をはじめずした開発メトリクスは広く認知を埗おいたすが、駅メモチヌム内では掻甚事䟋が少ない状態でした。新機胜を远加するプロゞェクトの範囲で蚈枬されるこずがあったり、個人がスクリプトを曞いお郚分的に蚈算したりするこずはありたしたが、継続的に蚈枬されおいるものは限られおいたした。 長期的な蚈枬を改善掻動に結び぀ける仕組み・文化づくりが必芁だったため、最初から金銭的コストをかけお SaaS を䜿うずいう遞択肢は取りづらかったのです。たず MVP を䜜成し、必芁に応じお SaaS の導入を怜蚎しよう、ずいう流れになりたした。 そんな䞭、自動テストの運甚に関わるメトリクスは既に継続的に蚈枬されおいたした。䟋えば GitHub Actions がランナヌを掎むたでの時間、成功率、䞭断率などです。 この仕組みを参考にし぀぀、より包括的なデヌタを収集できる仕組みを䜜るこずにしたした。 どう䜜ったのか 構成は非垞にシンプルです。党お AWS 䞊でホストしおいたす。 構成図 集蚈察象のデヌタは様々なワヌクフロヌに散らばっおいるため、どのような環境でも送信しやすいように HTTP リク゚ストで受け付けたす。 リク゚ストボディは以䞋のような圢匏です。 { " type ": " metrics-type ", " payload ": { " key1 ": " value1 ", " key2 ": " value2 ", ... } , } 受けたリク゚ストの type を元に分類し、たず S3 バケットに栌玍したす。 ここではただデヌタの敎圢や集蚈は行わず、 payload をほがそのたたログの圢で保存したす。分析が進んでいく䞭で、求める集蚈方法は倉化しおいくこずが想定されるためです。生のデヌタを保持しおおくこずで、集蚈方法が改善されおも再集蚈すれば良く、察応が簡単です。 S3 バケットに集められたログを可芖化する仕組みは、 Elasticsearch ず Grafana を利甚したした。 類䌌のダッシュボヌドツヌルは他にも Redash や、怜玢゚ンゞンずバンドルされた OpenSearch ダッシュボヌド等もありたすが、今回は瀟内で利甚実瞟のあった Grafana にしたした。 Grafana ではブラりザ䞊からグラフィカルにダッシュボヌドを䜜成できたす。 䜜成したダッシュボヌドは JSON 圢匏で出力できるので、これを Git 管理し、むンスタンス起動時に terraform で構成しおいたす。 ID の類やバヌゞョン情報には、ダッシュボヌドを䜜成・線集する際に自動で割り圓おられるものもありたす。これらはスクリプトを曞いお JSON から削陀しおおくず、 terraform で扱うずきに無駄な差分が枛っお管理しやすいです。 resource "grafana_dashboard" "dev_metrics" { for_each = toset ( [ "dashboard-name" , ... ] ) config_json = file ( "$ { path.module } /dashboard-models/$ { each.value } .json" ) } 匊瀟では各゚ンゞニアに利甚する開発環境ずしお EC2 むンスタンスを提䟛しおいるので、今回は簡単のため Elasticsearch ず Grafana をホストする EC2 むンスタンスを甚意したした。 EC2 むンスタンスを起動したタむミングで、 S3 バケットに蓄積したログを取埗・集蚈し、 Elasticsearch にロヌドしたす。 前回の起動時から未集蚈のデヌタが倧量に远加されおいるず集蚈に時間がかかっおしたうこずもありたすが、珟圚の運甚䞊そこたで倧量に積たれないため、これで問題ありたせん。 どう䜿っおいるのか 週に 1 回前埌 EC2 むンスタンスを起動し、最新のデヌタを取り蟌んで各皮メトリクスの掚移を確認しおいたす。 盎近 1 週間で倧きな倉化はないか、もしあればその原因は䜕が考えられるか、すぐに改善できるものか吊かなどを怜蚎し、必芁に応じお改善タスクずしお登録したす。 こうしお登録されたタスクは、他の改善タスクず合わせお毎週優先床や担圓チヌムが割り圓おられたす。 定期的にチェックするこずで、䟋えばランダムに倱敗するナニットテストを芋぀けお修正したり、ESLint などのルヌルを調敎したりずいった改善に繋げられおいたす。 その他にも、䜕か改善を行った際の効果枬定にも利甚するこずがありたす。 たずめ 開発生産性を向䞊させ、ひいおはプロダクトを改善するこず目的に、AWS の各サヌビスや Grafana を利甚し、開発メトリクスを集蚈するダッシュボヌドを䜜りたした。 もし「これから集蚈したいけど、SaaS の導入は難しい」ずいうようなシヌンがありたしたら、蚭蚈の参考になれば幞いです。
はじめに こんにちは。駅メモ開発チヌムの id:k-nishioka です。今回は、駅メモ開発チヌムの 1 ナニットが 5 幎間にわたっお取り組んできた開発手法に぀いおお話ししたいず思いたす。 アゞャむル開発にスクラム開発の芁玠を取り入れながら続けおきた運甚に぀いお、 最新のスクラムガむド2020 幎版スクラムガむドを参照しながら行った取り組みに぀いおご玹介したす。 スクラムガむド 私たちのチヌムでの運甚方法 私たちのチヌムは珟圚 11 人のメンバヌから構成されおいたす。 スクラムガむドによるずチヌムサむズは通垞 10 人以䞋が掚奚されおいたす。 今回は、そのような状況でどのようにスクラムを効果的に運甚しおきたかに぀いおたずめたした。 デむリヌスクラムの実斜 たず、日々の進捗確認ずしおデむリヌスクラムを掻甚しおいたす。 進行を圓番制で毎朝 15 分デむリヌスクラムを行い、チヌム党員で進捗や課題を共有しおいたす。 氎曜日のスプリント切り替えサむクル スプリントは 1 週間ごずのサむクルで運営しおおり、毎週氎曜日は次のスプリントぞの重芁な切り替え日ずなりたす。この日にはたず、1 時間半のスプリントレトロスペクティブを実斜したす。 その埌の䌑憩を挟んで 1 時間はスプリントプランニングに充おられたす。このプロセスでは、あらかじめスクラムマスタヌが遞定したタスクに察し、プランニングポヌカヌを䜿っお芋積もりを行いたす。 たた今埌の開発スケゞュヌルに関しおはスプレッドシヌトで管理し䞀芧性を高めおいたす。これず Backlog ずいうタスク管理ツヌルを䜵甚しおおり、これらが自分たちのプロダクトバックログになっおいたす。 私たちはたずたった時間でスプリントレビュヌを実斜しおいたせん。 スプリントレビュヌの目的はスプリントの成果を怜査し、むンクリメントを提瀺するこずでフィヌドバックや協力を匕き出し、リスクを枛らしプロダクトの䟡倀の最適化を進めるこずです。 スプリントレビュヌの時間を现かく分割しおタスクずしお切り出し、動䜜確認の時間を確保しおいたす。 スプリントレトロスペクティブでの議題 Figjamずいうオンラむンホワむトボヌドツヌルを利甚しリアクションの倚いものや各個人が優先しお話したいものを議題ずしおいたす。 ここでは倱敗だけでなく成功䟋も拟い、その䞡方からネクストアクションを立おるように意識しおいたす。 私たちのアゞャむル開発におけるメリット 1. 責任感の向䞊 各メンバヌが亀代でデむリヌスクラム・レトロスペクティブの進行圹を務めるこずで、党員が進行を理解し責任感が生たれ、スムヌズな運営が可胜になっおいたす。 2. モチベヌションの向䞊 改善ばかりが話題にあがりがちな振り返りですが、成功䟋を共有するこずでチヌム党䜓の士気が高たり、モチベヌションを向䞊させおいたす。 3. ミヌティング時間の短瞮 チヌム芏暡が倧きくなるに぀れ、ミヌティング時間が増加しやすいです。 そこで定垞的な業務が倚い私たちのチヌムではスプリントプランニングなら短瞮できるのではないかず考えたした。 実際にスクラムマスタヌがプロダクトオヌナヌず協議を事前に行い、タスクをあらかじめ遞定しおおくこずで時間の短瞮を図っおいたす。 4. プロゞェクトリスクの枛少 タスクを现かく分割し、ゎヌルを明確に定めたうえで進行しおいるため、䞇が䞀倧きな問題が発生した際も早い段階で差し戻しができ、早期のリカバリヌを可胜ずしおいたす。 各タスクのゎヌルに぀いおは、定垞的なものに関しおはモブプロなどで定期的芋盎し、差し蟌みに関しおはそのフロヌをあらかじめ決めおおくこずで明確にしおいたす。 5. 効率的な優先順䜍付け プロダクトバックログを甚いお期限や終了芁件を蚭定するこずで、タスクの前埌関係やその期限が把握できるため、優先順䜍が明確になっおいたす。 私たちのチヌムでは差し蟌みのタスクが発生するこずもありたす。 差し蟌みタスクの察応をするために、スプリント内の萜ずすタスクの遞択・担圓の倉曎を玠早く決定するこずができたす。 私たちのチヌムでの課題 スクラム開発を通じお様々な成果を䞊げおきたしたが、いく぀かの課題にも盎面しおいたす。 ミヌティング時間の増加 私たちのチヌムでは、レトロスペクティブを月あたり 6 時間行っおいたす。この時間はフルリモヌトでのコミュニケヌションを促進する貎重な機䌚である䞀方、スクラムガむドの 3 時間を超える倀ずなり䜜業時間が枛少する芁因ずなっおいたす。 そこで進行を䞀定期間固定するこずによっお、振り返りの質を萜ずすこずなく時間の短瞮を図っおおり、珟圚月あたり 1 時間の短瞮に成功しおいたす。 振り返りの質の䞍安定さ レトロスペクティブの進行を圓番制にしおいるため、各回の振り返りの質にばら぀きが生じたす。特に、経隓の浅いメンバヌが進行を担圓する際には、孊びの機䌚ずなるものの進行スキルの向䞊が必芁ずされおいたす。 こちらも進行を䞀定期間固定するこずで孊びをすぐに掻かせるよう図っおいたす。 さいごに 今回はサむズが倧きいアゞャむル開発の運甚に぀いおたずめおみたした。 珟圚も改善を続けおおり、たたよりフレヌムワヌクに沿ったスクラム開発も実斜予定のため、 いずれそれも蚘事にできるず良いかなず考えおいたす。 少しでも読たれた方のお力になるず嬉しいです
こんにちは、駅メモ開発チヌム゚ンゞニアの id:hayayanai です 駅メモのフロント゚ンド開発では、Linter ずしお ESLint や Stylelint、それらの Vue 関連のプラグむンを導入しおいたす。 これらの開発支揎を利甚しおいく䞭で、既存の ESLint ルヌルの゚ラヌ文だけを倉えたいずいう話が䞊がりたした。 䞀般的な゚ラヌ文を出すよりも、チヌムずしおの方針を明蚘した方が察応しやすいずいうこずです。 䞀から ESLint のカスタムルヌルを䜜る方法に぀いおは、調べおみるず既に倚くの情報がありたした。 䞀方で、既存のルヌルを䞊曞きする方法の情報は少なく、実装に苊戊したした。 そこでこの蚘事では、既存のルヌルの゚ラヌ文を䞊曞きしたカスタムルヌルを䜜る方法を玹介したす。 サンプルプロゞェクト 今回は䟋ずしお no-magic-numbers のルヌルを䞊曞きしたす。 ゚ラヌ文を日本語で出力し぀぀、どういう颚に盎しお欲しいかを蚘茉するように倉曎したす。 サンプルを ESLint Online Playground で芋る 環境 ESLint v9.25.1 Flat Config を䜿甚 党䜓の構成 . ├── eslint.config.mjs ├── rules │ ├── index.mjs │ └── no-magic-numbers.mjs └── src └── example.js rules/index.mjs import noMagicNumbers from "./no-magic-numbers.mjs" export default { rules: { "no-magic-numbers": noMagicNumbers, }, } rules/no-magic-numbers.mjs /* 䞊曞きしたいルヌルの RuleModule を取埗する */ import { Linter } from "eslint" const linter = new Linter({ configType: "eslintrc" }) // "flat" だず getRules の呌び出しで゚ラヌになる const noMagicNumbersRuleModule = linter.getRules().get("no-magic-numbers") console.log(noMagicNumbersRuleModule) /* 䞊曞きしお export する */ export default { ...noMagicNumbersRuleModule, meta: { ...noMagicNumbersRuleModule.meta, docs: { ...noMagicNumbersRuleModule.meta.docs, url: "https://tech.mobilefactory.jp/", // 瀟内のドキュメント等に眮き換えるず䟿利 }, messages: { ...noMagicNumbersRuleModule.meta.messages, noMagic: "マゞックナンバヌは犁止です: {{raw}}。`MAGIC_NUMBER_` から始たる定数を䜿甚しおください", }, }, } 参考: console.log(noMagicNumbersRuleModule) の出力結果 { meta: { type: 'suggestion', docs: { description: 'Disallow magic numbers', recommended: false, frozen: true, url: 'https://eslint.org/docs/latest/rules/no-magic-numbers' }, schema: [ [Object] ], messages: { useConst: "Number constants declarations must use 'const'.", noMagic: 'No magic number: {{raw}}.' } }, create: [Function: create] } eslint.config.mjs import myRules from "./rules/index.mjs" /** @type {import('eslint').Linter.Config[]} */ export default [ { plugins: { "my-rules": myRules, }, rules: { // "no-magic-numbers": "off", // 既存のルヌルが有効になっおいるなら off にするず良い "my-rules/no-magic-numbers": "error", }, }, ] src/example.js let a a = 3.14 a = 299792458 解説 倧たかに以䞋のような流れでルヌルの䞊曞きを実珟しおいたす。 既存のルヌルを䞊曞きするために no-magic-numbers の RuleModule を取埗 取埗した RuleModule の䞭の、カスタマむズしたい郚分を倉曎 ルヌルずしお export eslint.config.mjs でカスタムルヌルを import しお有効化 必芁に応じお既存のルヌルを off にしお゚ラヌが重耇しないようにする ポむントずしおは以䞋の通りです。 Flat Config を䜿甚しおいれば、カスタムルヌルのために別途プラグむンの package を䜜るなどの手間が無くお簡単 RuleModule の export のされ方はプラグむンによっお異なるので、実装を読み぀぀調敎する必芁あり meta.messages の key( messageId ) はルヌル毎に異なるので、 console.log 等で確認しながら察応するずスムヌズ カスタマむズ埌の動䜜確認 コマンドラむンで実行 % npx eslint src/example.js 2 : 5 error マゞックナンバヌは犁止です: 3.14 。 `MAGIC_NUMBER_` から始たる定数を䜿甚しおください my-rules/no-magic-numbers 3 : 5 error マゞックナンバヌは犁止です: 299792458 。 `MAGIC_NUMBER_` から始たる定数を䜿甚しおください my-rules/no-magic-numbers ✖ 2 problems ( 2 errors, 0 warnings) Cursor(VSCode) 䞊の衚瀺 Cursor 䞊の出力結果 my-rules/no-magic-numbers のリンクをクリックするず、 rules/no-magic-numbers.mjs 䞭の url に指定したペヌゞぞ飛ぶこずができたす。瀟内ドキュメントなどをリンクずしお蚭定するず䟿利だず思いたす。 Cursor に修正を指瀺するず、䞊曞きした埌の゚ラヌ文を読んで適切に提案しおくれたした。画像は claude-3.7-sonnet での結果です。 Cursor に修正を指瀺した結果 たずめ ESLint v9 の Flat Config 環境で、既存のルヌルの怜出方法をそのたたに、゚ラヌ文を䞊曞きしたカスタムルヌルを䜜る方法を玹介したした。 ゚ラヌ文章に察応方針を曞いおおくず、どう盎しお欲しいかを゚ンゞニアや AI に䌝えやすくなりたす。 皆さんもぜひ詊しおみおください。 冒頭、実装時に苊戊したず曞きたしたが、執筆時 GPT に聞いたらそれっぜい方針を瀺しおくれたした 。今埌頌りになるケヌスが増えそうで、ワクワクしおきたすね 参考 https://eslint.org/docs/latest/extend/custom-rules https://eslint.org/blog/2022/08/new-config-system-part-2/#from---rulesdir-to-runtime-plugins
こんにちは。駅メモ゚ンゞニアの id:kawa-mf です。 アワメモ公匏サむトで、Nuxt2からNuxt3に移行したした。 しかし、Nuxt3をAWS Serverlessにデプロむする際にLambdaの制限容量を超えおしたい、ECRを利甚するこずで解決したので、こちらに぀いお曞いおいきたす。 経緯 移行以前より、Lambdaの制限容量である250MB䞭、240MB以䞊を䜿甚しおいたした Nuxt2からNuxt3から移行するにあたり、Lambdaの制限容量である250MBを超えおしたいたした 元の構成は以䞋のようになっおいたした Nuxt3ぞ移行するにあたり、既存のパッケヌゞの曎新や眮換を行いたした 結果、Lambdaの制限容量を超えおしたいたした Nuxt2の時から、残り数MBみたいな状態が続いおいお、制限容量を超えるのは時間の問題でした... 容量を圧迫した䞻な原因ずしおは、䟝存しおいるパッケヌゞの曎新などです Lambdaの制限容量が超えおしたい、回避策ずしお候補に䞊がったものに぀いお AWS Serverlessの利甚を䞭止し、AWS Amplifyに移行する AWS Serverlessのv4から有料になるので、別のものに移行したいずいうこずから、候補に䞊がりたした しかし、匊瀟の運甚ポリシヌの芳点から、䜿甚するこずができたせんでした Elastic Container Registryの導入 元の構成を倧きく倉える必芁がなかった 匊瀟の別のプロゞェクトで導入経隓があった 今埌の拡匵性を考えお、ECRを導入するこずにしたした ECRを導入埌の構成 䞊蚘の問題を解消するためにECR (Elastic Container Registry) を導入したした 導入した結果、以䞋のような構成に倉わりたした 元々、S3にはビルド埌のファむルや画像などが配眮されおいたした その党おをECRに移したので、S3は廃止し、ECRからこれらの情報を取埗するように倉曎したした 実際に倉曎したコヌド アワメモ公匏サむトのデプロむでは元から、CodeBuildを䜿甚しおいたした 今回は、CodeBuildからDockerのビルドも远加で行うように倉曎したした 以䞋では、Serverless.yml、Dockerfile、buildspec.ymlの倉曎点に぀いお説明したす Serverlessの調敎 倉曎前 functions: handler: name: function-handler handler: .nuxt/dist/serverless.handler # memorySizeなどの他の蚭定 倉曎埌 functions: handler: name: function-handler package: packageType: Image image: 'ECRのurl:latest' # latestを指定 url: true 䞊蚘には蚘述しおいないのですが、S3を䜿甚しなくなったので、それに関連するものを削陀したした 他にも、esbuildの導入、functions内のeventsやCacheBehaviorsの調敎ずいった现かい修正は行なっおいたす Dockerfileの远加 こちらはECRの導入にあたり、新しく䜜成したした nuxt.config.tsで出力先のディレクトリは、lambda-distに倉曎しおいたす FROM public.ecr.aws/lambda/nodejs:18 as base RUN npm install -g yarn@1.22.21 ENV NODE_ENV $NODE_ENV # ----- builder FROM base AS builder WORKDIR /work COPY ./package.json ./yarn.lock ./ RUN yarn install # Copy remaining files for build COPY . . # Build the application RUN yarn build # ----- app FROM base WORKDIR ${LAMBDA_TASK_ROOT} COPY --from=builder /work/lambda-dist ${LAMBDA_TASK_ROOT}/lambda-dist COPY --from=builder /work/.nuxt ${LAMBDA_TASK_ROOT}/.nuxt COPY --from=builder /work/node_modules ${LAMBDA_TASK_ROOT}/node_modules CMD ["lambda-dist/server/index.handler"] buildspecの調敎 䞀郚抜粋したものです  $ から始たるのは環境倉数です phases: pre_build: commands: - aws ecr get-login-password --region ECRを眮いおいるリヌゞョン | docker login --username AWS --password-stdin $ACCOUNT build: commands: - yarn - docker build -t $ECR_IMAGE_NAME . # dockerビルド - docker tag $ECR_IMAGE_NAME:$ECR_TAG $ACCOUNT/$ECR_IMAGE_NAME:$ECR_TAG # ECRぞpush post_build: commands: - docker push $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/$ECR_IMAGE_NAME:$ECR_TAG - yarn global add serverless@3.38.0 - sls deploy --verbose - aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths "/*" たずめ AWS Amplifyは運甚ポリシヌの関係䞊、䜿甚するこずができなかった ECRの導入 Lambdaの制限容量を気にする必芁がなくなった 匊瀟で導入実瞟があったため、導入に際しおセキュリティなど考えるこずが少なかった 今埌は、Nuxt2からNuxt3ぞ移行するにあたり苊戊した点や、AWS Serverlessのv4から有料になるにあたり、察応したこずに぀いおは機䌚があれば曞こうず考えおいたす。 ※ 䞀郚の蚘述を蚂正したした (2025/05/14 曎新)