有名テック企業の技術ブログを、ひとつのフィードで。
フィード
912件
プロダクトエンジニアの谷(@uta8a)です。2025年にkintoneのダッシュボード開発チームにジョインして、1年半近くプロダクトエンジニアとして働き、kintoneの性能ダッシュボード、利用状況ダッシュボードのリリースに関わってきました。今日はチーム紹介をします! kintoneを、もっと安心して大規模に活用していくために必要なこと kintoneは、様々な業務システムが作れる業務改善プラットフォームです。 現在42,000社(執筆時点)に使われているkintoneは、多様な業務を支えています。しかし、大規模利用に伴い足りない部分も出てきました。 アプリの操作が重いという問い合わせを、現場からIT部門が受け取る IT部門がkintoneの活用を促進していきたいが、どう使われてきたのか分からない こうした大規模利用に伴う不安への対応や、もっとkintoneの利用を拡大していくための後押しが必要です。 これらの課題はお客様が現状を把握できることがまず必要だと考え、kintoneの状態を時系列で把握できるような、管理者向けダッシュボード機能を開発しています。 (性能など、改善もセットで必要な部分は別チームで取り組んでいます! *1 ) ダッシュボードの開発によって、例えば次のような効果を目指しています。 このペースの利用増だと性能問題が起こりそう。性能カスタマイズオプションを検討しよう 社内のkintone活用の実態が分かった。全社導入に向けて動いていきたい このようにして、もっと安心して大規模にkintoneを活用していける世界を目指しています。 もっと安心して大規模にkintoneを活用していける世界を目指しています kintoneのダッシュボード開発チームの取り組み 今までに、3つの種類のダッシュボードをリリースしています。 性能ダッシュボード 大規模利用顧客向けに、アプリの性能情報を見て改善の効果測定に役立てる 利用状況ダッシュボード 社内のkintone活用状況を見て、活用促進に繋げられる 社内向けダッシュボード サイボウズ社内でのお問い合わせ対応や、次に作るダッシュボードを考えるヒントとして利用する これらのダッシュボードで価値を素早く提供するために、以下のような取り組みをしています。 既存プロダクトとビジョンを共有しつつ、作るものを自分たちで決める ダッシュボード開発はkintone本体とは独立したチームとして開発している プロダクトエンジニアとして、kintone本体の理解を深めつつダッシュボードの役割を考えて開発 チームで意思決定の精度を上げていく 開発速度だけでなく、何を作るか、どういう順番でタスクを進めるかといった意思決定に関する会話がチームで行われる ツール・環境・プロセスを柔軟に試して取り入れる AIツール(Claude Codeなど)はもちろん、小さなチームだからこそ柔軟にやりやすいように開発プロセスを変えていける強み Findy Team+を利用して開発にまつわるメトリクスを活用した振り返り 個人的には、特に意思決定の精度は高いなと感じます。AIによってやることが高速になっても、無駄なことをたくさんやっていたらあまり嬉しくないです。結局何をやるか、どういう順番で進めていくかという意思決定の精度が重要だと思います。例えば、チームの朝会で会話を通してその視点あるなぁ...という気持ちになったりすることがあり、チームで意思決定の精度を上げていると思っています! チャレンジ & わいわい チームの雰囲気としては、kintone開発の中でも比較的パイオニア寄りというか、小さく実験的なチームなのでチャレンジしていこうという感覚が強いです!とりあえずやってみたいことは試してみて、ダメだったら撤退できる環境であり続けたいと思っています。チャレンジ! あと、あまり枠組みにとらわれずわいわい越境していこうというのも特徴的です。例えば、私はもともとAWS周りのインフラをメインで取り組んでいたのですが、チームで働く中でフロントエンドのタスクを取ったり、デザイナーやEMと作るものについて議論したりと活動範囲を広げることができました。 リリース後のオンラインお祝いや、対面でのチームビルディングも盛り上がります!わいわい! 対面でのチームビルディングでみんなで作ったご飯。盛り上がりました。 一緒に働きましょう もっと安心して大規模で使えるkintoneを目指して、ダッシュボード開発に一緒に取り組んでくれる仲間を募集しています! cybozu.co.jp 小さなチームで大きなインパクトを起こすことに興味があれば、ぜひカジュアル面談からでもお話しましょう。 *1:性能カスタマイズオプション など
Web未経験MLエンジニアが社内プロダクト開発でAIコーディングにどハマりするまで はじめに こんに ...
こんにちは、アクセシビリティエンジニアでSmartHR UIコアメンバーの tajiman です。 SmartHR UI は SmartHR のプロダクトで使われているコンポーネントライブラリです。この記事では、SmartHR UI の2025年の活動を振り返ります。 ※2025年度ではなく、2025年の活動です。いいえ、間違いではありません。 SmartHRでは、SmartHR UI がどのように成長してきたか毎年振り返りをしています。 昨年の振り返り記事はこちらです。 SmartHR UI の現在地 SmartHR UI の2024年12月時点と2025年12月時点の数値を比較します。 項目 2024/12/13 2025/12/18 バージョン v62.2.0 v82.0.0 コンポーネント数 *1 100 99 ソースコード規模 *2 32,108行 43,664行 コミット数 *3 5,754 6,430 コントリビューター数 *4 83人 119人 バージョンは v62.2.0 から v82.0.0 へと20のメジャーバージョンが上がりました。コントリビューター数は83人から119人に増えました。 コンポーネント数が100→99と微減しているのは、リネーム(CheckBox→Checkbox 等)に伴う統廃合や ActionDialogContent、MessageScreen 等の削除が、新規追加(SmartHRAILogo、StepFormDialog等14個)を一部相殺しているためです。 コントリビューター 2025年のコミット数上位10名を紹介します(同率10位を含む)。 順位 名前 コミット数 1 Mizoue Atsushi 187 2 たふみ 82 3 KANAMORI Yu 26 4 Tajima Sachiko 13 5 Ryō Igarashi 9 6 shingo.sasaki 5 6 Kei Kono 5 6 oti 5 6 Misako Tateiwa 5 10 nabeliwo 4 10 Takatsugu Kageyama 4 10 Daichi Hashimura 4 コントリビューターの皆さん、ありがとうございます。 開発・運用体制 SmartHR UI のコアメンバーは7名(エンジニア4名、デザイナー3名)で構成されています。昨年と同様に専任のメンバーはおらず、有志による運営を続けています。 週次の定例ミーティングを開催し、課題の共有や方針の議論を行っています。 リリース リリース作業は昨年に引き続き自動化されており、週1回のペースで実施しています。2025年は v63.0.0 から v82.0.0 まで、20のメジャーバージョンをリリースしました。 アクセシビリティへの取り組み SmartHR UI ではアクセシビリティの品質向上に継続的に取り組んでいます。 2025年には12件のアクセシビリティに関するPRがマージされました。 代表的なものとして チャートを色のみで表現しないようにした というPRがあります。 色だけに頼らず、模様(パターン)で系列を区別できる棒グラフ 棒グラフを色のみではなくパターンを付けることで、色覚特性をもつユーザーでも判別ができるようにしました。 ESLint カスタムルール 2025年には、テーブルセル内でのCheckboxやRadioButtonの使用を禁止するルールなど、12件の新しいルールが追加されました。 アクセシビリティ関連:18 ルール その他:34 ルール 合計 52 ルール おわりに SmartHR UI は2025年も多くのコントリビューターに支えられながら成長を続けました。 まだまだやりたいことが山ほどあるため、引き続き沢山のコントリビューターとレビュワーを募集しています! We Are Hiring! SmartHR では一緒に SmartHR を作りあげていく仲間を募集中です! 少しでも興味を持っていただけたら、カジュアル面談でざっくばらんにお話ししましょう! hello-world.smarthr.co.jp *1:packages/smarthr-ui/src/index.ts から export されているコンポーネントの数をカウント。Icon は export * でまとめてエクスポートされているが1つとしてカウント。hooks・テーマ・定数・i18n 関連の export はカウント対象外。なお、2024年以前の計測とは数え方が若干異なる(以前は Storybook を作成している外部向けコンポーネントの数をカウントしていた)。 *2:cloc で packages/smarthr-ui/src を計測(空行・コメント除く)。2024年以前と同条件で測ると35,137→43,664と大幅に増えていますが、2024年のブログ値(32,108)とは計測日・条件の差異がある可能性があります。 *3:bot によるライブラリのアップデートを含む。 *4:bot を含む。
こんにちは。メルペイのフロントエンドエンジニアの @mattsuu です。この記事は「Merpay & Mercoin Tech Openness Month 2026」の7日目の記事です。 EGP Code は、ランディングページ(LP)を AI と作る社内向けのエディタです。作成背景については AI と作る HTML ベースの LP エディタ EGP Code を内製した理由 という記事で紹介しました。本記事では、その内部で動いている 4 つの仕組みを紹介します。 EGP Code が扱うのは、HTML と状態や動きを担う少数の <egp-*>(独自の Web Components)を混ぜた 1 枚のページです。 <section class="p-6 text-center"> <h1>春のキャンペーン</h1> <p>応募受付中</p> <egp-button>応募する</egp-button> </section> この HTML を AI エージェントとの対話やエディタで編集し、プレビューで確認して公開します。紹介する 4 つの仕組みは、(1) エージェントの再帰ループ、(2) Firestore を介したリアルタイム反映、(3) ブラウザだけで完結するテストランナー、(4) プレビューと HTML を結ぶ対応表です。 1 つの指示がユーザーから届いてプレビューに反映されるまでの流れと、それぞれの仕組みが効く場所は次のとおりです。 仕組み 1: 文脈とツールを束ねるエージェントの再帰ループ 「フォントサイズを 24px にして」「文字を太くして」のように特定の要素への簡単な指示なら、その要素を特定して CSS を更新したり文言を調整したりするだけなので、ほぼ 1 回の操作で終わります。一方で複数の要素にまとめて指示したり、API を使った画面やテストを作ったり、Lint・テストのエラーを直したりする場合は、推論とツール実行を何度か往復することになります。 エージェントは「推論 → ツール実行 → 結果を会話履歴に追加 → 再び推論」という再帰ループで動きます。ここでいうツールとは、AI が必要と判断したときに呼べる関数の定義と説明のことです。HTML を書き換える、ファイルを読む、Lint で検証する、テストを走らせる、といった操作をツールとして用意しておき、モデルがその中から必要なものを選んで呼び、戻り値を見て次の手を考えます。 1 回の入力に対して 4 つの情報をまとめて渡します。システムプロンプトで AI エージェントに役割やコード生成のルールといった前提を与え、それにユーザーの指示と選択要素と現在の HTML、これまでの会話履歴、そして使えるツールの一覧を教えます。このうち現在の HTML・仕様・テストといったページの状態は、種類ごとに XML タグで区切ってまとめます。 会話履歴の持ち方は、開発当初 OpenAI API 側に任せていました。しかし全社的に ZDR(Zero Data Retention) を適用することになり、プロバイダ側に会話を残せなくなったため、いまは履歴をすべて自前で記録し、毎回のリクエストに載せて送るステートレス方式にしています。履歴の肥大化を防ぐため、一定量を超えたら要約させてコンテキストを圧縮しています。 // 1 ラウンドの推論 const stream = await client.responses.stream({ ...args, input: sessionBuffer.getItems(), // 自前で管理している履歴全体を送る previous_response_id: undefined, store: false, // プロバイダ側に会話を保存させない }); ループの工夫をいくつか紹介します。 1 つ目は、ツールの失敗の扱いです。ここでいう失敗とは、apply_patch の差分が当たらない、Lint がエラーを返す、テストが落ちるなど、ツールが期待どおりに完了しなかった状態を指します。こうした失敗ではループを止めず、エラーの内容をそのまま結果としてエージェントに返すことで自己修正させています。 2 つ目は、find_skill ツールによる情報の出し分けです。社内 API の使い方などのドキュメントは、最初は ID と一行説明の一覧だけを見せておき、本文は必要になったタイミングで読み込みます。たとえば「商品一覧を表示したい」という指示が来ると、エージェントはまず一覧から関連しそうなものを探し、find_skill でそのドキュメント本文を取得します。エージェントは取得したドキュメントを読み、正しい引数で API を呼びます。 この推論とツール実行の往復を繰り返し、最後にエージェントが apply_patch で HTML を差分更新すると 1 つの指示が編集として完成します。 ループの途中で方向を変える Real-time steering ここまでは、1 つの指示を最後まで処理してから次を受け取る前提でした。ですが実際には、処理の途中で「やっぱり色は青にして」と方針を変えたり、「ついでにフッターも直して」と指示を足したくなることがあります。完了を待たずに割り込みで指示を足し、走っているループに後から反映する仕組みを用意しています。こうした仕組みは Real-time steering とも呼ばれます。 ユーザーが処理中に指示を足したときの流れは、次のようになります。 エージェントが処理中(画面がローディング中)にユーザーがメッセージを送ると、クライアントはそれを通常の指示ではなく、割り込みメッセージとして送信します。サーバは受け取った割り込みメッセージを、 Firestore の通常の会話履歴とは別のサブコレクションに、いま走っているリクエストの ID を添えて書き込みます。エージェントは、自分が処理しているリクエストの ID に一致する割り込みだけを読み取ります。 // 自分のリクエスト宛の割り込みメッセージだけを読み、読んだら消す const consumeSteeringMessages = async (conversationId, requestId) => { const snapshot = await steeringRef .where('requestId', '==', requestId) // このリクエスト宛だけを対象にする .orderBy('timestamp', 'asc') .get(); const messages = snapshot.docs.map((doc) => doc.data()); await deleteDocs(snapshot.docs); // 読んだら消す return messages; }; ID で絞るので別のリクエスト宛の割り込みを拾うことはなく、読んだら消すので同じ指示が二重に効いたり取りこぼしたりすることもありません。処理のループに差し込むため、割り込みが来たときにエージェントが何をしようとしていたかで、対応が 2 つに分かれます。 1 つ目は、ツールを呼ぼうとしていた場合です。そのツールを実行せず、戻り値の代わりに「ツールは実行していません。処理中に新しい指示が届きました」という内容を返します。 // ツール実行の直前に割り込みを確認する const steering = await consumeSteeringMessages(conversationId, requestId); if (steering.length > 0 && toolCalls.length > 0) { for (const toolCall of toolCalls) { // ツールは実行せず、戻り値の代わりに割り込みを差し込む buffer.pushMessage({ role: 'tool', tool_call_id: toolCall.id, content: '[CONVERSATION_STEERING] 処理中に新しい指示が届きました ...', }); } continue; // 計画を立て直すため、もう一度推論へ } 2 つ目は、ツールを呼ばずに、ユーザーへの返信メッセージを作り終えていた場合です。本来ならこれを見せてループが終わるところですが、割り込みが届いたので止めるべきツールがありません。この返信はまだ画面に出していないので破棄し、直前のユーザーの指示に割り込みメッセージを足して送り直すことで、続きの作業を依頼します。 // ツールがない場合は、画面に出していない返信を捨てて指示を足す if (steering.length > 0 && toolCalls.length === 0) { buffer.pop(); // まだ画面に出していない返信を捨てる const priorUserTurn = buffer.pop(); // 直前のユーザーの指示を取り出す buffer.pushMessage({ role: 'user', content: `${priorUserTurn.content}\\n[CONVERSATION_STEERING] 処理中に新しい指示が届きました ...`, }); continue; } いずれの場合も、すでに実行した副作用を巻き戻すわけではなく、これから実行するはずだったツールを止めたり、まだ画面に出していない返信を捨てたりして、計画を組み直しています。 仕組み 2: Firestore を指示の受け渡し場所にしたリアルタイム反映 仕組み 1 で見たように、エージェントは複数のツールを往復させて指示に応えるため、編集には時間がかかることがあります。処理が終わるまで画面が何も更新されないと、利用者は反映されたかどうか分からないまま待つことになります。 そこで Firestore SDK を利用して、変更をリアルタイムに受け取れるようにしています。サーバ側は 1 つの操作が終わるたびにその内容を Firestore へ書き込み、ブラウザ側はそれをサブスクライブして即座に検知・反映します。これで自前で WebSocket を張らずに、編集の途中経過をそのままプレビューへ反映できます。 エージェントが何かを書き換えると、サーバは会話ごとのコレクションに、次のようなドキュメントを 1 件追加します。 { "status": "PENDING", "requests": [ { "action": "setHtmlSchema", "payload": "<body> ...更新後の HTML... </body>", "reason": "ユーザーの依頼を反映" } ] } ブラウザ側の JS は、Firestore の SDK(onSnapshot)でこのコレクションをサブスクライブしており、PENDING のドキュメントが届くと requests の各操作をエディタの状態へ反映します。たとえば setHtmlSchema なら、エディタが表示している HTML を新しいものに置き換えて、プレビューを再描画します。 ブラウザが requests の操作を反映し終えると、その JS が status を COMPLETED に書き戻します。HTML 差し替えなどの「反映だけ」のアクションは、投げたら終わりで結果を待ちません。一方でテスト実行のように結果が必要なアクションでは、ドキュメントが COMPLETED になるまで一定間隔で読み直して、書き込まれた結果を取り出します。取り出した結果はツールの戻り値としてエージェントに返り、それを見て次のツール呼び出しを決めます。 仕組み 3: ブラウザだけで完結するテストランナー 応募ボタンを押したときの API 呼び出しやその結果に応じた表示の切り替え、リンクによる画面遷移といった LP の動作を手動で確認するのは手間がかかります。そこで EGP Code では、こうした動作をテストで確かめられるようにしています。 テストはブラウザ上のエディタで直接書いたり、AI に書かせたりできます。これらのテストは、サーバや CI ではなく、プレビューと同じブラウザの中で実行します。ただし Jest や Vitest は Node.js 上で動くツールなので、そのままブラウザには読み込めません。そこで test / it / describe / expect を提供する小さなランナーを自作しました。アサーションは単体で使える @vitest/expect、DOM 操作は Testing Library をそのまま利用しています。 // 自作の test 関数でテストを定義する test('エントリーボタンで API が呼ばれる', async () => { // Testing Library でユーザーのクリックを再現する await userEvent.click(screen.getByText('エントリー')); // @vitest/expect で結果を検証する expect(mockEntry).toHaveBeenCalledWith({ campaign: 'X' }); }); テストが社内 API を呼ぶこともありますが、本番に飛ばすわけにはいきません。そこで iframe 内で window.fetch を差し替え、リクエストはすべてモック関数に通します。モックしていない呼び出しはエラーになるので、本番へ漏れることはありません。 テストの実行は、この iframe を作るエディタのページ(ホスト)と iframe の postMessage のやり取りで進みます。 ホストは iframe を作ってテスト用 HTML を流し込み、iframe 側の初期化(window.fetch の差し替えなど)が済むのを待ってから実行を指示します。先に指示が届くと取りこぼすため、必ず「準備完了」を待つようにします。結果は仕組み 2 のアクションでエージェントへ戻ります。失敗していれば、仕組み 1 で触れた自己修正がここで働き、内容を読んで実装を直してもう一度走らせます。 仕組み 4: プレビューの要素と HTML の位置を結ぶ対応表 ここまではエージェント主導の編集を見てきましたが、人が直接手を入れる場面もあります。Code タブを開くと Monaco エディタで HTML を直接編集でき、プレビューでリアルタイムに確認できます。プレビューの要素をクリックしてエージェントへ指示を出したり、Monaco の対応行へジャンプするには、「プレビューの要素と HTML 上の位置」を対応づける仕組みが必要です。 <img src="https://storage.googleapis.com/prd-engineering-asset/2026/06/1aa073c8-preview-jump-ja.png" alt="EGP Code のエディタ。左
こんにちは。カミナシで「カミナシ 設備保全」の開発を行っている澤木です。今回はフロントエンドのコンポーネントディレクトリの構成、特に「ネストを深くしないために何をやっているか」という話をご紹介したいと思います。 feature-basedなディレクトリ構成 まず前提として私たちのチームでは機能(feature)単位でディレクトリを切り、各featureの中をさらにcomponents / hooks / contexts / model / repositoryといった責務ごとのディレクトリに分けるスタイルを採用しています。現在のフロントエンドの実装では一般的な構成かと思います。 features/hoge/ ├── components/ ├── contexts/ ├── hooks/ ├── model/ ├── repository/ └── index.ts 今回はこの中で主にcomponents/ディレクトリに着目してどういった規約で実装を行なっているかについてお話しします。 なぜネストが深くなるのか 例としてfeatures/hoge/というfeatureを考えます。この中のcomponents/には一覧画面のHogeList、詳細画面のHogeDetail、フォーム画面のHogeFormなどhoge featureに関わるコンポーネントが置かれる形になります。今回は詳細画面のHogeDetailを例に見ていきます。 それぞれのコンポーネントには、そのコンポーネント内でしか使われないコンポーネントや hook、model などが存在します。例えばHogeDetailであればHeader・Footer・Contentといった子コンポーネントや、HogeDetail内でだけ使う hook(useHogeDetail)やロジック(logic.ts)など。これらはHogeDetailでしか使われないものなので、外部ではなくHogeDetailディレクトリの内部に置きたくなります(いわゆるcollocation)。 components/HogeDetail/ ├── HogeDetail.tsx ├── components/ │ ├── Header/ │ │ └── Header.tsx │ ├── Footer/ │ │ └── Footer.tsx │ └── Content/ │ └── Content.tsx ├── hooks/ │ └── useHogeDetail.ts └── model/ └── logic.ts このようにコンポーネントの階層が浅ければこれで問題ないのですが、子コンポーネントがさらに専用の子コンポーネントを持ち始めたりすると、どんどんネストが深くなっていきます。 components/HogeDetail/ ├── HogeDetail.tsx ├── components/ │ ├── Header/ │ │ └── Header.tsx │ ├── Footer/ │ │ └── Footer.tsx │ └── Content/ │ ├── Content.tsx │ ├── components/ │ │ └── Section/ │ │ ├── Section.tsx │ │ └── components/ │ │ └── SectionTitle/ │ │ └── SectionTitle.tsx │ └── hooks/ │ └── useContent.ts ├── hooks/ │ └── useHogeDetail.ts └── model/ └── logic.ts この構成はコンポーネント内の構造を統一的に保てるというメリットはあるのですが、同じ components/ や hooks/ といった責務ごとのディレクトリが各階層に繰り返し現れるうえ、階層を辿っていきながら目的のファイルを探すのが大変になります。特にSectionTitleのような小さな部品を作るたびに階層が深くなっていくと、どこに何があるのか見通しが悪くなっていきます。 同一構造をあきらめる そこで、各階層で components/ hooks/ model/ といったディレクトリを統一的に置く方針はあきらめて、コンポーネントの中身はフラットに並べてしまう方針にしました。 今回以下の二つの理由からあえて責務ごとにディレクトリを切る必要はないと考えました。 1つ目は、コンポーネント1つあたりの内部部品の数がそもそも多くならないこと。1つのコンポーネントの中の hook や model はせいぜい数個で、ディレクトリを切っても中身のファイル数は多くならないため、わざわざディレクトリを切らなくてもファイル数は見通せる範囲におさまります。 2つ目は、ファイル名の規約さえ揃っていれば、種類はディレクトリで分けなくても名前から判別できること。useXxx.ts であれば hook、Xxx.tsx であればコンポーネント、というように、hooks/ や model/ といったディレクトリに入っていなくても何のファイルなのかは伝わります。ディレクトリでの種類分けと命名規約は同じ情報を二重に持っているので、名前のほうを揃えればディレクトリは省略してよいと判断しました。 コンポーネントもフラットにしてみる 責務ごとのディレクトリを切らない方針に合わせてコンポーネント同士の入れ子もやめて、HogeDetail/ の中身も完全にフラットに並べてみました。そうすると以下のようになります。 components/HogeDetail/ ├── HogeDetail.tsx ├── Header.tsx ├── Footer.tsx ├── Content.tsx ├── useHogeDetail.ts └── logic.ts これで HogeDetail/ の中身は完全にフラットになりました。 ただこうした場合、コンポーネント同士の入れ子が消えてしまったことで、どれが内部部品でどれが外から呼び出される公開コンポーネントなのかがわからなくなってしまいます。HogeDetail.tsx は外から呼び出される公開コンポーネントですが、Header.tsx、Footer.tsx、useHogeDetail.ts、logic.ts は HogeDetail 内でしか使わない内部実装です。同じ階層にフラットに並べてしまうと、どれを外から呼んでよくて、どれが内部実装なのかが見た目で区別できなくなってしまいます。 ネストの代わりに命名規則で集約する そこで、ディレクトリで分けるのではなくファイル名で public/private を表現する方法を試してみました。コンポーネント内は以下のようなルールを決めています。 _ から始まるファイル・ディレクトリはprivate(外から参照されないもの)とする _ が付かないもののみpublic(外から参照されるもの)とする コンポーネントディレクトリの中は1階層しか掘らない 例えばHogeDetail/ の中はこのようになります。 components/HogeDetail/ ├── HogeDetail.tsx ├── _Header.tsx ├── _Footer.tsx ├── _Content.tsx ├── _useHogeDetail.ts └── _logic.ts componentsディレクトリ内はhooksやmodelといった種類で分けることもせずにpublicかprivateかのみをファイル名で区別して全てをフラットにおくようにしています。この結果、_Header という名前を見れば「コンポーネント内の内部部品」だと判別がつき、HogeDetail/ の中にあるので HogeDetail の部品だと判別できるようになりました。この方法であればディレクトリを作成しなくとも、ファイル名と置き場所で親子関係が表現できます。 このルールは HogeDetail/ の中だけでなくその外側でも同じように適用できます。features/hoge/components/ 直下にも _ 付きの private コンポーネントを置けますし、features/hoge/hooks/_useHoge.ts のように feature 全体で使う private hooks を置くこともできます。どの階層でも「_ 付きは private」の1つのルールで通せるので、レイヤーごとに違う規約を覚えなくて済みます。 privateなファイルを表現する方法はディレクトリを分ける・barrel export(index.ts)で公開範囲を絞るなど他にもありますが、それらはいずれもディレクトリを増やすアプローチで、今回避けたかったネストや階層構造が生まれてしまいます。 _ プレフィックスはファイル名だけで public/private を表現できるので、ディレクトリを増やさずに公開範囲を示せるのが利点です。一方で、ファイル一覧が _ で埋まって見た目が少しノイジーになる、規約を知らないと意図が伝わりにくいといったデメリットは存在します。後者に関しては後述の dependency-cruiser で機械的に守る形にして補っています。 コンポーネントが大きくなったら上の階層に切り出す 先ほどの命名規則での集約ではコンポーネント内の部品が増えていくと、コンポーネント内での依存関係も増えていき見通しが悪くなっていく可能性があります。そこで、コンポーネントが大きくなってきたら、「ネストさせるのではなく上の階層に切り出す」というルールも同時に運用しています。 最小は、HogeDetail/ の中に全部 _ 付きでフラットに並べた状態。 components/HogeDetail/ ├── HogeDetail.tsx ├── _Header.tsx ├── _Footer.tsx ├── _Content.tsx ├── _useHogeDetail.ts └── _logic.ts 例えばこの中で _Content が自身の子コンポーネント(Section)や専用 hook(useContent)を持つようになったとします。そうした時にHogeDetail/ の中でさらにディレクトリを作成するのではなく、components/ 直下に独立したディレクトリとして外に出します。 components/ ├── HogeDetail/ │ ├── HogeDetail.tsx │ ├── _Header.tsx │ ├── _Footer.tsx │ ├── _useHogeDetail.ts │ └── _logic.ts └── _Content/ ├── Content.tsx ├── _Section.tsx └── _useContent.ts _Content は private のままなので、HogeDetail.tsx 側の import は変更不要です。ここでも同じ「_ 付きは private」ルールが効くので、_Content/ の中でもまた _Section.tsx を private として扱えます。さらに Section が育ってきたら同じように _Section/ を切り出せばよく、同じパターンが入れ子で適用される形になります。 こうして切り出された _ 付きのコンポーネントが features/hoge/components/ 直下に増えてくると、HogeDetail まわりだけでなく HogeForm の private 部品も同じ階層に並ぶようになり、_Content や _Section がどちらのコンポーネントに属するものなのかが見分けづらくなってきます。 features/hoge/components/ ├── HogeDetail/ ├── HogeForm/ ├── _Content/ ← HogeDetail / HogeForm どちらの部品? ├── _Header/ ├── _Section/ └── ... そこで HogeDetail まわりや HogeForm まわりが大きくなってきたら、それぞれを sub-feature として別 feature に切り出します。features/ 全体ではこのように切り出していきます。 features/ ├── hoge/ ├── hoge-detail/ ├── hoge-form/ └── ... 最初は hoge/ だけ切っていたものを、詳細画面やフォーム画面が大きくなってきたタイミングで hoge-detail/ hoge-form/ を切り出す、というイメージです。<feature>-detail <feature>-form で命名を揃えることで、どの feature の詳細やフォームなのかもわかるようにしています。 切り出しの基準は数値などで厳密には決めていませんが、深くネストさせる代わりに上に出す、という選択肢が常にあることで実装時の迷いが減り、コンポーネントディレクトリが一定以上には深くならないように保たれるようになっています。 命名規則をツールで守る 命名規則は、規約としてはシンプルですがコード上で強制されているわけではないので、どこからでも_がついているファイルをimportできてしまいます。そこで静的解析で弾けるように dependency-cruiser を導入して、_ 付きのファイルは外から参照できないようにルールを設定しています。 まず、feature の外からは index.ts(barrel)経由でしかアクセスできないようにします。 { name: "features-barrel-only", from: { pathNot: "^app/features/" }, to: { path: "^app/features/[^/]+/.+", pathNot: "^app/features/[^/]+/index\\.ts$", }, }, from(参照元)が feature の外、to(参照先)が feature 内部の index.ts 以外のファイル、という組み合わせを禁止するルールです。これによって外部から feature の内部実装に直接 import することを防ぎます。 次に、その index.ts から _ 付きのファイルを再 export するのを禁止します。 { name: "no-underscore-in-barrel", from: { <sp
こんにちは、 id:sezemi です。 季節外れの台風に振り回されましたが、元気にやっております。 天候急変によるイベントのハンドリングは難しいですねぇ。 さて、アンドパッドでは、技術やプロダクト開発、組織に関するさまざまなカンファレンス・イベントでの登壇、開催や会場提供などを行っています。 今月もイベント情報をまとめてお知らせします。 ぜひご参加ください !! なお、開催状況により、満員となってしまっている場合、すでに受付を終了している場合がございます。 1. スポンサー情報 | 松江Ruby会議12 開催日時 : 2026年6月6日(土) 会場 : 興雲閣 主催 : Matsue.rb イベント概要 : Matsue.rb が主催する地域Ruby会議です。アンドパッドは本カンファレンスに スポンサー として協賛します。 申込方法 : カンファレンスの公式ページ からお願いいたします。 「興雲閣」は、松江城山公園内に建つ美しい歴史的な洋風建築です。 地域 Ruby 会議らしく、趣のある空間で開催されていて、建築好きの私には見逃せない楽しみです。 また、アンドパッドはブースを出展していますので、ぜひ遊びに来てください。 そして nagachika が「ruby.wasm で作る MIDI コントローラー」というタイトルで発表しますので、ご期待ください! ちなみに、今回の "Kaigi" も音ネタが多いですね。 2. 登壇情報 | 食べログ x ANDPAD x Sansan モバイル勉強会 #4 開催日時 : 2026年6月17日(水) 会場 : Sansan株式会社 主催 : 食べログ、アンドパッド、Sansan イベント概要 : 食べログ、アンドパッド、Sansanの3社が共催するモバイルアプリ開発者向けの勉強会です。本イベントには、アンドパッドから 長堀 が登壇予定です。 申込方法 : イベントページ からお願いいたします。 今回はモバイルアプリ開発では対応が欠かせない "OS アップデート" がテーマです。 当たり前すぎて、実はなかなか知見がないテーマなので、発表された Tips は貴重なものになる予感です。 ぜひご参加ください! 長堀 翔太 @nashcft 2023 年 6 月に Android アプリエンジニアとして入社。チャットアプリの開発に携わりつつ、チームビルディングや開発プロセス改善にも取り組んでいる。 長堀 翔太 のテックブログ執筆記事 - DroidKaigi 2024 参加レポート / 感想編 - ANDPAD Tech Blog - アンドパッドは DroidKaigi 2024 に協賛しています & 事前勉強会のお知らせ - ANDPAD Tech Blog 発表タイトル: OS アップデートの進め方がもっと共有されてほしい 3. 登壇・会場スポンサー | v-tokyo Meetup #25 開催日時 : 2026年6月16日(火) 会場 : 株式会社アンドパッド 主催 : v-tokyo イベント概要 : v-tokyoが主催するミートアップイベントです。本イベントに、アンドパッドは 会場スポンサー として協賛し、会場を提供するほか、アンドパッドから 羽馬(NaokiHaba)と 小泉 (@ykoizumi0903) が登壇予定です。 申込方法 : イベントページ からお願いいたします。 いま大注目の VoidZero 社が開発している Void / Vite+ がテーマのイベントです。 カンファレンス並みのゲストとトークが揃い、とても楽しみですね。 そしてアンドパッドのフロントエンドエンジニア陣を代表する二人、羽馬と小泉が登壇します。 ぜひ期待ください。 NaokiHaba @naokihaba 株式会社アンドパッド フロントエンドエンジニア。 Vite+ Team Member 発表タイトル: Vite+ 「The Unified Toolchain for the Web」 を掲げる Vite+ は、runtime や package management、build、さらには monorepo のタスクキャッシュに至るまで、あらゆる機能を一つの依存関係に統合しています。今回はこの Vite+ について、開発に携わるチームメンバーとしての視点から詳しくお話しします。 小泉 佑太郎 @ykoizumi0903 ANDPAD引合粗利管理や ANDPAD資料承認などのプロダクトや機能をテックリードとして開発しているフロントエンドエンジニア。 業務では Vue/Nuxt を中心に、Next や React Router を使った開発にも携わる。 Zenn で Vue や Nuxt に関する記事を ykoizumi0903 というユーザーネームで書いている。 小泉 佑太郎 のテックブログ執筆記事 (直近 2 記事を抜粋) - Nuxt の自動インポート機能、無効化しました - ANDPAD Tech Blog - 乗り換えるなら今! Prettier から Oxfmt への移行を試してみた - ANDPAD Tech Blog 興味のあるイベントがございましたら、ぜひご参加ください !! アンドパッドでは技術コミュニティが大好きな採用広報を大歓迎しています。 広報の経験がない方でも Welcome です! カジュアル面談やご応募、お待ちしております。 hrmos.co
こんにちは!SmartHRでプロダクトエンジニアをしているTaiです。 2025年12月にSmartHRに入社し、勤怠管理の開発チームに所属しています。 前職ではフロントエンドエンジニアとしてOCR(光学文字認識)やSCM(サプライチェーン管理)のプロダクト開発に携わっていました。HR・労務ドメインのプロダクト開発は今回が初めてです。 入社から約半年が経ち、チームの中にいることが自然になってきた今だからこそ、ジョイン当初に感じた驚きや発見を残しておきたいと思いこの記事を書いています。 私たちが開発している勤怠プロダクトは、法令・制度・企業ごとの就業規則が複雑に交差するドメインで、入社直後は「これは一筋縄ではいかないな」と率直に感じました。しかし、チームにはその複雑さを乗り越えるためのサポート体制が想像以上に整っていました。会社のバリューがチーム文化に深く浸透していることにも驚かされます。 外から来た目線がまだ残っているうちに、チームの特徴を「文化」と「技術・開発体制」の2つの軸でお伝えしていきます。 チーム文化の特徴 「実装するだけ」の人間がいない 私たちのチームでは、エンジニア全員がユーザー目線を強く意識しています。何かを実装する前に、まず「ユーザーにとってなぜそれが必要なのか」というWhy(目的)を徹底的に掘り下げます。 How(手段)を詰める前にWhy(目的)を大事にする姿勢がチーム全体に根付いています。 そのために、仕様検討などを職種関係なくチームメンバー全員で決めていく形をとっており、エンジニアも要件や仕様の段階から主体的に参加し、「何を作るべきか」をチーム全員で考えます。 この体制は良い循環を生んでいます。仕様検討に関わることでドメイン理解が深まり、その理解が進むことでより良い設計判断ができるようになり、結果としてプロダクトの質が上がっていきます。 私が見てきた限りでは、「言われたものを作る」のではなく、メンバー一人ひとりがプロダクトに対してオーナーシップを持って開発に向き合っているチームです。 リモートでも距離を感じないコミュニケーション チームはフルリモートで開発を行っており、だからこそテキストコミュニケーションを大切にしています。Slackでのやり取りが盛んで、ミーティング中もスレッドで議論や補足が活発に飛び交います。 リモートワークでありがちな「聞きづらい」「様子がわからない」といった距離感は全く感じません。 新しく入ったメンバーへのサポートも手厚く整っています。勤怠プロダクトの開発組織内には複数のチームがありますが、チームを横断して話せる場が設けられています。 自分のチームに閉じず、チーム内外を問わず気軽に相談できるので、ジョイン直後の不安感はかなり和らぎました。 挑戦とフィードバックが日常にある雰囲気 チームには、質問や提案を安心して出せる雰囲気があります。その土台にあるのは、「光の速さでまず動く」というSmartHRが掲げている三つのバリューのうちの一つでしょう。「まずやってみる」を大切にし、挑戦を後押しする姿勢がチーム全体に根付いています。 挑戦が前提なので、間違いを恐れる空気がありません。仮にうまくいかなかったとしても、建設的なフィードバックが返ってきます。 挑戦とフィードバックがセットになっているからこそ、安心して新しいことに踏み出して成長できる環境になっていると思います。 何か気づいたことがあればすぐにチーム全体にフィードバックを求める姿勢があり、それは1on1やふりかえりに限らず、日常のSlackのやり取りの中でも自然に行われています。 フィードバックが特別なイベントではなく、日常の一部になっているチームです。 また、SmartHRにはバリューを表すSlackのスタンプが用意されていて、誰かのアクションに対して都度リアクションとして押されているのをよく目にします。 お互いの行動をバリューの観点から認め合う文化が、こうした小さな習慣を通じて自然と根付いているのだと思います。 認識の「ズレ埋め」文化 SmartHRには「ズレ埋め」という文化があります。認識のズレをそのままにせず、気づいた時点でお互いに指摘し合う文化です。ズレが小さいうちに修正できるので、一人で抱え込んで問題が大きくなるということが起きにくい環境になっています。 何かで連携をとる際にも、互いの認識を揃えてからスムーズに進行できるよう心がける姿勢がチーム全体に浸透しています。Slackには「ズレ埋め」の状況を伝えるためのSlackのスタンプも用意されていて、日常的に活用されています。 課題を一人で抱え込ませないサポート体制 入社直後は慣れない技術スタックやドメインに戸惑う場面もありました。そんなときありがたかったのは、チームが放置しなかったことです。自分が課題を整理する前に、チームが先回りして状況を確認し声をかけてくれて、すぐに「どうすれば改善・解決していけるか」を一緒に考えるフェーズに入りました。こまめに1on1を設けてもらい、自分の状態を定期的に言語化する場があったのですが、これがかなり効きました。掘り出し始めると課題がボロボロ出てきましたが、今まで顕在化していなかった問題を認知でき、良い取り組みになったと感じています。 また、そこからは毎週の振り返りで内省のサイクルを回すようにもしました。その週に何があって、自分はどう感じて、何がうまくいかなかったのかを細かく言語化する。地味ですが、これを続けることで自分の問題のパターンが見えてきます。やったことはシンプルで、問題を洗い出して、それぞれに対するアプローチをブレイクダウンしていっただけです。魔法みたいな解決策があったわけではなく、泥臭く一個ずつ潰していきました。 技術・開発体制の特徴 フロントエンド・バックエンドの垣根がない開発体制 私たちのチームでは、一つの機能をフロントエンドからバックエンドまで通して実装します。「フロントエンドエンジニア」「バックエンドエンジニア」という分業ではなく、プロダクトエンジニアとして機能全体に向き合うスタイルです。 私は前職ではフロントエンドを専門にしていたため、バックエンドは2〜3年まともに触っておらず、RubyもRailsもほぼ浦島太郎状態でした。「いけるでしょ」と思っていた矢先、いざ取り組んでみると思ったより読めないことに気が付きました。 これはまずいということで、チームメンバーにサポートを受けながらキャッチアップの日々が始まりました。SmartHRにはRubyやRails入門のためのカリキュラムも用意されており、体系的に学び直すことができて効率よくキャッチアップすることができました。おかげさまで、今ではかなり読み書きできる状態になっています。 特定の領域に閉じないことで、機能全体を見通した設計判断ができるようになります。フロントエンドだけを見ていた頃には気づけなかった観点が得られる実感があり、大変ではあるものの、エンジニアとしての幅が確実に広がっていると感じます。 大規模なコードベースと丁寧なコードレビュー SmartHRのコードベースは、前職のスタートアップと比べて規模が桁違いでした。前職では0→1の開発が中心で、コードベースは比較的コンパクトでした。改修時の影響範囲もだいたい把握できていて、「ここを変えたら何に影響するか」は感覚でわかることも多かったです。 一方、SmartHRでは影響範囲の調査だけでも結構な労力が必要です。ドメインの複雑さも相まって、一つの変更がどこに波及するのか丁寧に追っていかないと痛い目を見ます。実際に見ました。痛かった。 コードレビューもかなりしっかり行われており、コードに対する自分の理解が少しでも足りていないとすぐに顕在化します。裏を返せば、レビューを通じて理解の甘さに気づける機会でもあり、コードベースへの解像度を上げていく良い糧になっています。この大規模なコードベースに対して、AIをどう活用すれば効率良くキャッチアップできるかを考えることも、良いキッカケになっています。 ドメイン知識にアクセスしやすい環境 先述のとおり、勤怠ドメインは非常に複雑です。しかし、チームにはその複雑さに対応するための環境が揃っています。 まず、ドメインエキスパートへの質問はSlackで気軽にできます。「こういう場合はどうなるんですか?」といった疑問をその場で投げかけられるので、理解が曖昧なまま実装を進めてしまうリスクが減ります。 新機能の実装など、複雑なドメインが絡む場面ではドメインエキスパートによる共有会が開かれることもあり、チーム全体で認識を揃えてから開発に入れる体制になっています。 また、ドキュメントも充実しています。用語集、業務フロー、法令の解説など、ドメイン理解に必要な資料が体系的に整備されています。 入社直後、多数ある労働時間制の仕組み・違いが分からず戸惑いましたが、用語集などで基本概念を理解し、実装に必要な理解を得ることができました。こうした資料のおかげで、後からジョインしたメンバーでも自力でキャッチアップを進められます。 ドメインの複雑さそのものは変わりませんが、「わからないことをわからないままにしない」ための手段がチームとして整っていることが、大きな強みです。 AIを活用した開発文化 勤怠プロダクトの開発組織では、個人個人がAIを活用して開発業務に取り組んでいるのはもちろんのこと、組織としてもAI活用を推進する体制が整っています。その中の1つのチームは、AIネイティブな開発プロセスの実現を専門的に担っています。開発プロセスを可視化し、どの工程をAIネイティブ化できるかを検証したうえで、成果を他のチームへ横展開しています。すでに開発ライフサイクルにAIが組み込まれた業務フローもでき始めており、試行錯誤の段階から実運用のフェーズに移りつつあります。 AIと人間の役割をどこで分けるかについて、明確なルールがあるわけではありません。ただ、チームの基本的な考え方として「どうすればAIに一任できるか」を起点にしています。人間がやるべきことを先に決めてAIに残りを渡すのではなく、まずAIに任せることを前提に考え、人間の判断が本当に必要な部分を見極めていく。この発想の順序が、AI活用を自然に進められている要因の一つでしょう。 半年を振り返って 入社前、勤怠ドメインの理解にはかなり時間がかかるだろうと覚悟していました。法令・制度・就業規則が複雑に絡み合うドメインなので、一人前に議論できるようになるまで相当かかるだろうと思っていたのが正直なところです。 しかし、先述したドメインエキスパートへの相談のしやすさやドキュメントの充実など、チームのサポート体制のおかげで、想像していたよりもずっと早くキャッチアップが進みました。今では仕様検討の場でも自分の意見を出して議論に参加できており、入社前に抱いていた不安はすっかり解消されました。 ドメイン理解も技術面も、まだまだこれからではありますが、半年前には見えていなかった景色が見えるようになってきた実感があります。 まとめ 約半年このチームで過ごしてきて感じる魅力は、「複雑なドメインに対して、メンバーが主体的に向き合っているチーム」だということです。Whyを大事にする開発姿勢、フロントエンド・バックエンドの垣根を越えて機能全体に向き合うスタイル、ドメイン知識への投資、AI活用の推進。そのすべてに、一人ひとりが自分ごととして取り組む姿勢が貫かれています。 このチームで活躍しているメンバーに共通しているのは、主体性を持って動いていることです。 複雑なドメインを自ら理解しにいき、担当範囲を越えて機能全体に向き合う。そうした姿勢がチーム全体の推進力になっています。 勤怠ドメインという複雑で大きなプロダクトの開発を最前線で経験できる機会はなかなかありません。ドメインの奥深さ、チームの文化、技術的な挑戦、どれをとっても貴重な経験が得られる環境です。 私自身、この環境でもっと力をつけて、チームとプロダクトの成長に貢献していきたいと思います。 We Are Hiring! SmartHR では一緒に SmartHR を作りあげていく仲間を募集中です! 少しでも興味を持っていただけたら、カジュアル面談でざっくばらんにお話ししましょう! hello-world.smarthr.co.jp
こんにちは、SmartHR でプロダクトエンジニアをしている@nabeliwoです。 SmartHRは、2026年5月22日〜23日に開催された「TSKaigi 2026」にSilverスポンサーとして協賛し、9名が参加し、1名が登壇しました。 この記事では、イベントの模様と合わせて、スポンサー活動から登壇までの経験をお届けします! TSKaigi 2026とは TSKaigi 2026は、TypeScriptに関する技術カンファレンスです。今年のミッションも昨年から引き続き「学び、繋がり、型を破ろう」でした。 2026.tskaigi.org Silverスポンサーとして協賛しました SmartHRはTSKaigi 2026にSilverスポンサーとして協賛しました。 TypeScriptはSmartHRのフロントエンド開発において重要な技術であり、このコミュニティの発展に貢献したいという思いから協賛させていただきました。 Silverスポンサーは参加者に配布されるトートバッグにノベルティを封入できるため、フロントエンドエンジニア向けの採用チラシとクリアファイルを制作しました。 その際に、クリアファイルにチラシを挟んだ状態で送付する必要があったため、900部のクリアファイル全てにチラシを一枚一枚手作業で挟み込む作業をしたのですが、たまに雑談をしつつ黙々と作業する時間が思いの外楽しかったなと、今回のイベントの一つの思い出になりました。 封入作業の様子 また、今回は学生支援スポンサーもさせていただきました。 学生支援を担当してくれたメンバーからは、「地方からTSKaigiに参加されていた学生4名と一緒にランチをして、TSKaigiに興味を持っている背景、個人プロジェクトや研究の内容などについて話をしました。美味しいご飯を食べながら雑談をし、実際のSmartHRの社員としての責任などを話すことができ、貴重な時間でした!」とコメントをもらっており、とても良い機会をいただけたと感じています。 本編への参加 当日は9名がイベントに参加しました。 タイミングが合わず全員は揃いませんでしたがSmartHRポーズで 当日企画としてNFCカードを配付して各自好きなURLを登録することでコミュニケーションを促進したり、ネイルやフェイスペイントのブースが設置されていてお祭り感を楽しめたり、はたまたマッサージコーナーを設けて疲れを癒したり、とてもホスピタリティ溢れる素敵なイベントだと感じました。 また公式サイトでは事前に自分の見るセッションのスケジュールを組むことができ、会場であるベルサール羽田空港に因んで飛行機の運行ダイヤのような見た目でシェアできる機能もあったり、よく作り込まれたサイトになっていました。 当日のセッションに関しては、今年はBranded Typesの話が多かったように感じました。 Branded Types自体は去年から採用事例を各所で見るようになった印象でしたが、今年はそれが運用に乗ってメリット・デメリットも含めて話せるくらいにはこなれていったのかもしれないなと思いました。 個人的に特に印象に残ったのはlacolacoさんの「いつテストを書くか?―ソフトウェア開発における安心と不安について考える」とminako-phさんの「柔軟なPDFレイアウトエディタを支える型システム設計 — Discriminated UnionとConditional Typeの実践」というセッションでした。 どちらも豊富な経験と深い考察からしか出てこないような、とても勉強になる内容でした。 docs.google.com speakerdeck.com またブーススペースに関して、多くの企業が趣向を凝らした企画をされていて、どのブースも人で溢れていてとても熱気がありました。 個人的には普段の開発においてAIレビューでとてもお世話になっているCodeRabbitさんのブースでキーキャップをもらえたことが嬉しかったです。 登壇レポート 僕は2日目に「React の props は値の集合ではない — UI の状態を宣言するコンポーネント設計」というタイトルで10分のセッションを行いました。 Reactを使った開発を行う中でコンポーネントのインターフェースについて日々考えていたことをまとめています。 nabeliwo.github.io TypeScriptという言語として深い話をするわけではなかったので、発表前は自分の話す内容が参加者の期待に沿うのかわからず不安だったのですが、終わってみると良い反応をいただけたので安心しました。 どんな話であれ、自分の経験に基づいて生み出された話であれば誰かしら刺さる人はいるものだなと思えました。 緊張しました! まとめ 個人としては初回のTSKaigiから数えて3回目の参加だったのですが、年々カンファレンスの質が上がっており、TSKaigi運営の皆様には尊敬の念を禁じ得ません。 セッション内容も言語自体を深堀る好奇心をくすぐる話から、明日の業務からすぐに使える実践的な知識までとても幅広く、多くの学びと刺激を得られました。 改めて、TSKaigi運営の皆さま、参加者の皆さま、ありがとうございました! 次回こそは弊社もブースを出すぞ……!(2年連続落選しました) 事後勉強会を開催します 最後に告知ですが、2026年6月25日(木)にSmartHR主催で「TSKaigi 2026事後勉強会」を開催します。 TSKaigi 2026に参加して「もっと語り合いたい」と感じた皆様、まだまだ参加者を募集しておりますのでぜひお申込みください! smarthr.connpass.com
.images-row {width: 100% !important;} Developer Engagementブロックの@ikkouです。2026年5月22・23日の2日間にわたりベルサール羽田空港で「TSKaigi 2026」が開催されました。 ZOZOはGold Sponsorとして協賛し、スポンサーブースを出展しました。ZOZOがTSKaigiに協賛するのは今回が初めてです。 technote.zozo.com 本記事では、前半はZOZOのWebフロントエンドエンジニアが気になったセッションを紹介します。後半では、ZOZOのスポンサーブースの様子と各社のブースにおけるコーディネートを写真中心に報告します。 ZOZOのWebフロントエンドエンジニアが気になったセッション 開発体験を左右するライブラリの API 設計 ― GraphQL スキーマ構築ライブラリから考える 「関数型プログラミング」を分解する.ts 純粋性について 型でエフェクトを表す いつテストを書くか?―ソフトウェア開発における安心と不安について考える LLM時代のリファクタリング戦略:AIエージェントによる段階的・安全なTS移行方法 TypeScript の型で副作用の実行順序を制御する ZOZOのスポンサーブースの紹介 協賛企業ブースのコーディネートまとめ おわりに ZOZOのWebフロントエンドエンジニアが気になったセッション 開発体験を左右するライブラリの API 設計 ― GraphQL スキーマ構築ライブラリから考える ssssotaです。izumin5210さんの「開発体験を左右するライブラリの API 設計 ― GraphQL スキーマ構築ライブラリから考える」を紹介します。 speakerdeck.com このセッションでは、スキーマや型情報をいかにTypeScriptの実装に接続するかという観点で、既存ライブラリのアプローチやその長短を深ぼる内容でした。弊社ではOpenAPIを使っているケースが非常に多く、いかにOpenAPIスキーマを実装に接続するかは往々にして発生する問題の1つです。 セッションではGraphQLに焦点が当てられていましたが、スキーマから実装を生成するスキーマファースト、コードからスキーマを生成するコードファースト、コードファーストのうちDecoratorsを使うパターン、DSL的な独自のbuilderパターン、計3パターンについて評価していました。比較・評価軸として、1.スキーマと実装の分離、2.型整合性、3.DBモデルとの接続、の3軸を用いています。 スキーマと実装の分離については、スキーマファーストが優れているのは言うまでもありませんが分離する強いモチベーションがなければ優先度は低くなります。型整合性は採用するライブラリのtype ergonomicに依りますが、コードファーストなDSL builderパターンが強い傾向にあります。DBモデルとの接続においてはGraphQL特有と見ることができますが、コードファーストなDSL builderパターンで型整合問題と合わせて解決できることを示唆しています。 セッションの最後には、自作のライブラリでこのギャップを埋める取り組みとAIを用いた評価結果を紹介していました。気になる方はスライドも合わせて確認してみてはいかがでしょうか。 私自身、OpenAPIスキーマと実装の接続に関して関心があり、ライブラリ(openapi-ts-hono)を作った経験から非常に共感できるところがありました。もちろんGraphQLとはギャップがありますが、スキーマと実装の分離、型整合性などは感覚としてもっていながらも、改めて言語化されることで気付きのあるセッションでした。 「関数型プログラミング」を分解する.ts www_REM_zzzです。おーみーさんの『「関数型プログラミング」を分解する.ts』を紹介します。 tsk-2026-aumy.vercel.app 自分の話ですが、TypeScriptに入門する前はScalaを書いていた経験があります。当時はコップ本と呼ばれる本とHaskellの公式ドキュメントが日本語で関数型プログラミングに入門する入口でした。Object指向プログラミングとは全く別の世界からやってきたような考え方で、面白くもあり、苦労もした過去があります。 このセッションでは、そもそも関数型プログラミングとは何なのかの考え方に触れながら、TypeScriptで真の関数型はできないのかに触れられています。僕もTypeScriptで真の関数型が書けたらいいのにと思った一人です(OCaml書けよというのは一旦置いといて)。スライドの中で語られた関数型プログラミングは「いい感じのソフトウェアを作るため」というのは本質的だなと思いました。ついつい手段に引っ張られてしまうところがあるのですが、心に留めておきたいです。 純粋性について 特に純粋性についてのところはReactでも他のライブラリでも語られる部分であり、意味の純粋性の部分は悩ましいと感じたことがあるので共感しました。 // 「副作用を表す値」を返すだけ(純粋関数) function pureAlert(msg: string) { return ["alert", msg] as const; } // 副作用の実行は別の関数に委ねる function executeAction(action: readonly ["alert" | "confirm", string]) { switch (action[0]) { case "alert": alert(action[1]); break; case "confirm": confirm(action[1]); break; } } const actions = [pureAlert("hey"), pureAlert("bye")]; actions.forEach((a) => executeAction(a)); 引用:https://tsk-2026-aumy.vercel.app/29 このような「何をするかの宣言」と「実行」が分離されている書き方は普段からできるし、メンテナンスを考えると普段から実践していきたいと思いました。 returnは「この関数の呼び出し元(= 継続)に値を渡して戻る」という考え方はTSを書いていてなんとなく感じていたものがはっきりと言語化されてスッキリした気持ちになりました。 型でエフェクトを表す () => T // 特に何も起きない純粋な処理 () => Option<T> // 失敗しうる処理 () => Promise<T> // 非同期処理 これを徹底すると 関数の型を見るだけで「何が起きるか・何が起きないか」がわかる 純粋な部分と副作用のある部分が型レベルで分離される 「支払い処理を起こしうる部分」だけを特定して二重実行を防げる これはTypeScriptを堅牢に書くうえで実践したいと思います。ちょうど業務でも似たシチュエーションがあることを思い出して、まず「この関数は副作用を持つか?」を命名(execute, get, !記法)で示すのが現実的な入口かなと思いました。 いつテストを書くか?―ソフトウェア開発における安心と不安について考える ジン(@Jin_pro_01)です。自分の気になったセッションとして、lacolacoさんの「いつテストを書くか?―ソフトウェア開発における安心と不安について考える」を紹介します。 docs.google.com このセッションでは、テストをどのような時に書くべきなのかを「開発者の安心と不安」を起点に問い直したlacolacoさんの気づきの共有、問いの提示、視点の提案をするというセッションでした。 セッションの中ではソフトウェアの保守性の本質は「変更容易性」であり、それは予期的変更容易性(変更する前に感じる不安)と経験的変更容易性(変更をする中で実際に感じる手応え)の二層モデルとして見ることができるとしていました。その上でテストはその両方にフィードバックを返すセンサーであるとし、変更前に感じる不安があるならそれを取り除く安心のために書き、変更のしやすさを試したり構造に問題が見つかったりするなら設計を見直すために書くという体系的な整理がされており、とても興味深いセッションでした。 自分が従事しているZOZOTOWNでは、新規機能の実装や既存機能の改修と並行で、フロントエンドリプレイスも各チームで進行しています。ZOZOTOWNの発展を止めずに開発を進める体制である一方、考慮すべきことが多く、自分にとっては比較的「予期的変更容易性」が低い状態だと表現できることに気づきました。そして、まさにこの「予期的変更容易性」を高めるためのテストへの投資価値が高いと感じました。 さらにAIを使ってコーディングをしていく時代に入り、開発の生産量が増える一方で、自分が直接書いていないコードや構造との距離は広がっていきます。その距離は新たな不安、つまり予期的変更容易性の低下にもつながると感じています。だからこそ変更の前後で「振る舞いが変わっていないこと」を担保し、その不安を取り除くセンサーとしてのテストの価値は、AI時代にこそますます高まっていくのだと考えました。 <p
Googleがリリースした「Modern Web Guidance」スキルを使うと、AIエージェントが最新のWeb機能でコードを書けるようになります。 https://zenn.dev/ubie_dev/articles/modern-web-guidance スキルが参照するガイドラインはMarkdownで書かれており、Googleが推奨するWeb開発のDos / Don'ts、つまり「やるべきこと・やってはいけないこと」がまとまっています。Googleお墨付きの、モダンなフロントエンド開発の知見が詰まっています。AIエージェントを使う・使わないにかかわらず、ウェブ技術の勉強に使った...
こんにちは。2025年に新卒 0 期生として SmartHR に入社したプロダクトエンジニアのかずえもんです。SmartHR の様々なプロダクトの中で、私は届出書類機能の開発チームに所属しています。 届出書類機能は SmartHR の中でも歴の長いプロダクトで、状態管理ライブラリには当時主流であった Redux が採用されています。入社するまで Redux を触ったことがなかった私が、Redux を通じて JavaScript の比較にまつわる落とし穴に遭遇した話をします。 Redux とセレクター: state の基礎 Redux はアプリケーション全体の状態(state)を管理するためのライブラリです。state は唯一のグローバルなオブジェクトとして管理され、コンポーネント側から必要な値を取り出して利用します。 state から値を取り出す関数をセレクターと呼びます。React Redux が提供する useSelector フックにセレクターを渡すことで、コンポーネントは state の変化に応じて自動的に再レンダリングされます。 // state 全体を受け取り、必要な値だけを返すセレクター const selectUsername = (state: RootState) => state.user.name // コンポーネント内でセレクターを渡して値を取り出す const username = useSelector(selectUsername) useSelector は、セレクターの返り値が前回と変化したときだけ再レンダリングを実行します。返り値の変化はデフォルトでは === で比較されます。ここで注意が必要なのは、セレクター関数の中で配列やオブジェクトを新規に作成して返す場合です。 例えば以下のようなセレクターの場合、state が変わっていなくても呼び出すたびに新しいオブジェクトが生成されるため、=== で比較すると常に「変化あり」と判断されてしまい、name と age が変わっていなくても再レンダリングが発生してしまいます。 const selectUser = (state: RootState) => ({ name: state.user.name, age: state.user.age }) // 不要な再レンダリングが発生してしまう const { name, age } = useSelector(selectUser) そこで利用できるのが、React Redux が提供する比較関数 shallowEqual です。useSelector の第2引数に shallowEqual を渡すことで、オブジェクト全体の参照ではなく各プロパティの値を個別に === で比較するようになります。すなわち name か age の値が変わっていなければ再レンダリングは実行されません。 const selectUser = (state: RootState) => ({ name: state.user.name, age: state.user.age }) // shallowEqual を設定すると再レンダリングを抑制できる const { name, age } = useSelector(selectUser, shallowEqual) 常に shallowEqual を使いたい場合は、React Redux の公式ドキュメントでも紹介されている useShallowEqualSelector というカスタムフックを作成しておくと便利です。 import { useSelector, shallowEqual } from 'react-redux' export function useShallowEqualSelector(selector) { return useSelector(selector, shallowEqual) } プロダクト内でもこのカスタムフックを利用しており、次のような書き方で複数の値をまとめて取り出していました。 const { docIds, status } = useShallowEqualSelector((state: RootState) => ({ docIds: getActiveDocIds(state.docGroup, state.doc.currentDoc?.docMasterRevisionId), status: getDocGroupStatus(state.docGroup), })) Redux の warning が教えてくれた 書類の詳細画面に関するレビューをしていたある日、ブラウザの開発者コンソールを眺めていたら warning が出ていることに気がつきました。 Selector unknown returned a different result when called with the same parameters. This can lead to unnecessary re-renders. 「同じインプットに対して、セレクターが異なる結果を返している」という内容です。「shallowEqual を使っているのになぜ?」と疑問に思い、調査を開始しました。 鍵は shallowEqual 関数の比較ロジックにありました。 shallowEqual が渡された配列やオブジェクトを比較するとき、それぞれのプロパティの値は === で比較されます。次の表は、 shallowEqual に対して空の配列、同じ値の入った配列、配列が入ったオブジェクトを渡したときの比較結果をまとめたものです。 式 shallowEqual の結果 shallowEqual([], []) true shallowEqual([1], [1]) true shallowEqual({ ary: [] }, { ary: [] }) false [] や [1] 同士を shallowEqual で比較すると true になります。前述の通り shallowEqual は渡された配列・オブジェクトをプロパティごとに見て === で比較するためです。つまり shallowEqual([1], [1]) では 1 === 1 が比較されていることになります。 しかし { ary: [] } のようにオブジェクトのプロパティが配列の場合は false になります。プロパティ ary の値を === で比較するとき、それぞれの [] は別のインスタンスであるため参照が異なると判断されるためです。 useShallowEqualSelector でオブジェクトにまとめて複数の値を取り出す手法ではまさにこれが落とし穴になります。問題になっていた getActiveDocIds の実装を見てみましょう。 export const getActiveDocIds = (state: DocGroupState, docMasterRevisionId: string | undefined) => { const docsPerdoc = state.current.docGroup?.docsPerDoc.find((doc) => doc.docMasterRevisionId === docMasterRevisionId) return docsPerdoc?.docIds || [] } find の結果が存在しない場合に [] を返しています。このリテラル [] は呼び出すたびに新しい配列インスタンスを生成します。つまり、各値を取り出すセレクター関数の中にこのような呼び出すたびに新しい配列を生成するものが含まれていると、そのプロパティは常に === で false と判断されてしまい、shallowEqual を使っていても docIds プロパティは常に「変化あり」と判断されて再レンダリングが走り続けていたのです。 createSelector でセレクターをメモ化する 呼び出すたびに新しい配列を生成してしまう場合、Reselect が提供する createSelector の出番です。createSelector は計算をメモ化するための関数で、インプットが変わっていなければ再計算をスキップし、前回と同じ参照を返し続けます。createSelector は Redux Toolkit 経由でも利用できます。 基本は useSelector に渡す関数そのものに使われることが多いですが、今回のようにオブジェクトにまとめて複数の値を取り出す手法における個別の関数に対しても適用できます。getActiveDocIds をメモ化することで、インプットが変わらない限り同じ配列の参照を返し続けるようになり、再レンダリングを防げます。 import { createSelector } from '@reduxjs/toolkit' export const getActiveDocIds = createSelector( [ (state: DocGroupState) => state.current.docGroup?.docsPerDoc, (_: DocGroupState, docMasterRevisionId: string | undefined) => docMasterRevisionId, ], (docsPerDoc,<span cla
ZOZO開発組織の2026年3月分の活動を振り返り、ZOZO TECH BLOGで公開した記事や登壇・掲載情報などをまとめたMonthly Tech Reportをお届けします。 ZOZO TECH BLOG 2026年3月は、前月のMonthly Tech Reportを含む計19本の記事を公開しました。特に次の3記事は反響も大きく、とても多くの方に読まれています。ぜひご一読ください。 techblog.zozo.com techblog.zozo.com techblog.zozo.com 登壇 【Flutter推し活】Flutter好きが集うLT会 Studyplus x Linc'well 3月13日に開催された「【Flutter推し活】Flutter好きが集うLT会 Studyplus x Linc'well」に、新規事業部の大野(@junjun_1345)が登壇しました。 ZOZO フロントエンドMeetup 3月18日にZOZOで主催した「ZOZO フロントエンドMeetup」に、ZOZOTOWN開発3部の揚原、WEAR開発部の岩崎、ZOZOTOWN開発1部の佐藤、そしてZOZOTOWN企画開発部の片岡が登壇しました。 掲載 Apps in ChatGPT対応 OpenAIの対話型AI「ChatGPT」の新機能「Apps in ChatGPT」にファッション領域でいち早く対応し、アプリ連携を開始しました。このことが複数のメディアで取り上げられました。まだ試したことがない方はぜひ一度お試しください。 corp.zozo.com www.fashionsnap.com netkeizai.com ZOZOEDUCATION つくっちゃお! ZOZO初となる、子どもが“つくって売る”に挑戦できる教育プロジェクト「ZOZOEDUCATION つくっちゃお!」を始動しました。本プロジェクトの一環として、Tシャツのデザインから販売までを、親子が自宅で気軽に体験できるTシャツづくりキットを3月25日より販売開始しています。このことが複数のメディアで取り上げられました。親子で体験できる楽しいキットですので、ぜひお試しください。 corp.zozo.com www.nikkei.com kosodate.mynavi.jp 以上、2026年3月のZOZOの活動報告でした! ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。 corp.zozo.com
Sansan株式会社では、技術イベントや勉強会の主催・登壇・協賛を行っています。 各イベントの詳細については、以下のリンクからご確認ください。 ※開催状況により、すでに受付を終了している場合がございます。 ※掲載している内容は公開当時の情報です。最新情報は各イベントページをご確認ください。 イベント開催情報 2026/05/12(火) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } Mobile Mob #1 〜スマホのハードウェア制御の悩み・工夫を語り合う〜 株式会社ビットキー、株式会社アンドパッド 、GO株式会社、Sansan株式会社が共催するMobile勉強会です。 第1回となる今回のテーマは「スマホのハードウェア制御」。 モバイルアプリ開発者が現場で直面する悩みや工夫を共有します。 開催日時:2026/05/12(火)19:15 〜 21:15 開催場所:Sansan株式会社 本社 参加方法:https://bitkey.connpass.com/event/389364/ 2026/05/21(木) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } Sansan Tech Talk @関西 vol.4~データ正規化の深淵~ 今回のテーマは、「データ正規化の深淵」です。 Sansanの膨大なデータを支えるエンジニアが登壇し、独自のアルゴリズム、名寄せのロジック、そしてそれらを支えるアーキテクチャについて、現場の知見を語ります。 開催日時:2026/05/21(木)19:00 〜 21:00 開催場所:Sansan株式会社 関西支店 参加方法:https://sansan.connpass.com/event/390947/ 2026/05/27(水) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } Nagoya Tech Talk #3 〜CloudNative × Platform〜 今回のテーマは、「CloudNative × Platform」です。 クラウドという基盤の上に展開している様々なプラットフォーム開発者のリアルな事例を語ります。 開催日時:2026/05/27(水)19:00 〜 21:00 開催場所:Sansan株式会社 中部支店 参加方法:https://sansan.connpass.com/event/390822/ 2026/05/28(木) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } 【ハンズオンあり】MLOps勉強会 @京都 Google Developer Groups on Campus Kyoto University (GDGoC Kyoto Univ)、Sansan株式会社が共催するMLOpsをテーマにした勉強会です。 登壇セッションに加え、実際に手を動かして学べるMLOpsに関するハンズオンを実施し、MLOpsの考え方や実践のイメージを多面的に学べる内容です。 開催日時:2026/05/28(木)19:00 〜 21:00 開催場所:Sansan Inovation Lab 参加方法:https://sansan.connpass.com/event/391090/ 登壇情報 2026/05/03(日) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } BigData-JAWS 勉強会 #32 Apache Icebergハンズオン会 JAWS-UGビッグデータ主催のイベントに、Sansan Engineering Unitの織田が登壇します。 Apache Icebergのメタデータレイヤーを活用し、AWS Lambda・AWS Glue・Amazon CloudWatch を組み合わせてデータレイクのテーブルを監視する方法を、ハンズオン形式で紹介します。 開催日時:2026/05/03(日)13:00 〜 15:00 開催場所:オンライン 参加方法:https://jawsug-bigdata.connpass.com/event/391438/ 2026/05/09(土) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } フロントエンドカンファレンス名古屋 2026 プロポーザルが採択時されましたので、セッション登壇を予定しています。 17:40~Room B(1203):「リセットCSSを1行消したらアクセシビリティが向上した話」(Eight Engineering Unit鳥山) 開催日時:2026/05/09(土) 開催場所:ウィンク愛知 2026/05/13(水) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } 事業成長を牽引する全社横断データ組織とは? ファインディ株式会社主催のイベントに、CTO室の中村が登壇します。 「データ基盤をプロダクトとして育てる」仕事の全体像とリアルな働き方について語ります。 開催日時:2026/05/13(水)19:00 〜 20:00 開催場所:オンライン 参加方法:https://findy.connpass.com/event/391865/ 2026/05/15(金) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } potatotips #95 iOS/Android開発Tips共有会 potatotips主催のイベントに、Sansan Engineering Unitの上野が登壇します。 直近リリースした音声入力機能の開発秘話について語ります。 開催日時:2026/05/15(金)19:00 〜 21:30 開催場所:LINEヤフー株式会社 赤坂オフィス 参加方法:https://potatotips.connpass.com/event/389026/ 2026/05/20(水) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } B2B SaaSの認証認可の変遷ー 事業成長が迫る基盤移行のリアル ー 株式会社アンチパターン主催のイベントに、Platform Engineering Unitの樋口が登壇します。 Sansanの認証基盤について、内製化の全貌と全社展開の現在地を紹介します。 開催日時:2026/05/20(水)19:00 〜 20:45 開催場所:オンライン 参加方法:https://saas-harbor.connpass.com/event/389591/ 2026/05/29(金) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } 3社に聞く!IaC運用におけるTerraformの課題と解決アプローチ ファインディ株式会社主催のイベントに、Sansan Engineering Unitの藤田が登壇します。 実際に直面したIaC運用におけるTerraformの課題と解決のアプローチを紹介します。 開催日時:2026/05/29(金)12:00 〜 13:00 開催場所:オンライン 参加方法:https://findy.connpass.com/event/391776/ 協賛情報 2026/05/22(金)~05/23(土) h4 a { color: #1487BD !important; text-decoration: none !important; font-weight: 700; } h4 a:hover { color: #0E5F8F !important; } TSKaigi 2026 日本最大級のTypeScriptをテーマとした技術カンファレンス「TSKaigi 2026」にSilver Sponsorsとして協賛します! また、3名のプロポーザルが採択されましたので、セッション登壇を予定しています。 5/22(金)11:50~12:20:「関係性から理解する"同一性"の型用語たち」(Eight Engineering Unit鳥山) 5/23(土)16:40~17:10:「childrenの順序まで型で縛る ── Branded Typesで実践するJSXの構造安全」(Eight Engineering Unit藤野) 5/23(土)16:40~17:10:「string地獄を脱出する — ValueObject + Zod 実践パターン」(Digitization部高田) フォローお願いします! Sansanの公式アカウントでは、最新のイベント情報をいち早くお届けします。 ぜひフォローしてください! X: @SansanTech connpass:Sansan株式会社
はじめに こんにちは、Checkout Reliabilityチームでバックエンドエンジニアをしているかがの(@ykagano)です! 2026/4/11(土)に開催されたPHPカンファレンス小田原2026にブース出店し、今年は「UMECO周辺のBASEショップを巡ろう! 小田原ショップスタンプラリー」と題した企画を実施しました。 こちらの特設サイトからスタンプラリーをすることができます(5/11までの限定公開)。 odawara2026.thebase.in 当日のスタート地点となっていたUMECOのスタンプ獲得画像です。 UMECOでのスタンプ獲得 BASEをご利用のショップオーナーにご協力いただき、UMECO周辺の実店舗をスタンプラリーのチェックポイントとさせていただきました。 ご協力いただいたショップオーナーの皆さまありがとうございました! スタンプラリーサイトの実績 早速ですが、スタンプラリーサイトの実績についてです。 4/11のアクセスユーザー数とスタンプ獲得数がこちらになります。 対象 件数 アクセスユーザー数 75 スタンプ獲得数 63 スタンプ種類数 6 今回のイベント参加者は150名ほどと伺っていたので、約半数の方にアクセスいただけて嬉しいです。 スタンプを全種類獲得された方はまだいませんが、ご自身のスマホでほとんどの方が最初のスタンプは取っていただけたようです。 当日は暑かったため、散歩するにはあまり向いていなかったと思います。それにも関わらずスタンプを獲得していただいた皆さまありがとうございました。 以降はスタンプラリーサイトの企画から実装についてお話ししていこうと思います。 スタンプラリーサイトの企画 私はこれまで何度かブーススタッフを担当してきましたが、企画段階から参加したのは今回の小田原イベントが初めてでした。 今回のスタンプラリーサイトの企画が、これまでと大きく方向性が変わったのは同僚の02さん(@cocoeyes02)からの一言がきっかけだったと思います。 Slackでの02さんの投稿 こちらの発言の後、ブレインストーミングをして、アイデアを持ち寄った後、最多投票だったのがシンプルスタンプラリーでした。 Figmaの付箋 この段階ではまだどうやってやるかは決まっておらず、ボード型のマップにするのか、パンフレット型のマップにするのか色々と話し合った結果、今はバイブコーディング(AIへ会話的にコードを高速生成させる開発スタイル)もあるので、スタンプラリーサイトを作ってみようということになりました。 スタンプラリーサイトの実装 スタンプラリーサイトはClaude Codeを使って実装しました。 実装期間は合計で3日程度でした。 技術スタック 技術スタックは以下を使用しています。 レイヤー 技術 フロントエンド HTML / CSS / Vanilla JavaScript フロントエンドデプロイ S3 + CloudFront マップ Leaflet.js + OpenStreetMap バックエンド AWS Lambda (Node.js) フロントエンドはビルドのないシンプルな作りとなっており、バックエンドもサーバーレスです。 データの永続化 当初、LocalStorageにスタンプ獲得を記録するプロトタイプを作ったのですが、会社で同僚のパンダさん(@Panda_Program)に見せたところ、LocalStorageに値を入れて小田原にいないのにスタンプを獲得されてしまいました。 そのため、簡単に偽装ができないように、スタンプの獲得判定はバックエンドで行うようにしました。 デザイン WebサイトをAIで生成すると人間があまり選ばないようなデザインになる部分がありました(影を付けたり角丸にしたり濃い色を使ったり)。 この辺りは一つずつ確認した上で、なるべくシンプルなデザインになるように修正していきました。 工夫した点 チェックポイントを目立つように工夫しました。 チェックポイントの100m以内に近づくと光るようにしています。 100m以内にあるチェックポイント 50m以内に近づくとスタンプ獲得ボタンが表示されます(これも光ってます)。 50m以内にあるチェックポイント 本当はスタンプが獲得できるようになったらスマホを振動させることもしたかったのですが、Vibration API にSafariが対応していないことから実装は見送りました。 今回こうした普段作っているものと方向性の違うアプリケーションを作成するのは、色々と考えるところがあって面白かったです。 おわりに スタンプラリーサイトはまだ2週間近く公開予定ですので、小田原に行かれた際にはぜひご利用ください。 BASEではこのように技術イベント・カンファレンスへのスポンサー協賛活動に取り組んでいます。 ブース企画などにご興味がある方はぜひ採用情報をご覧ください! binc.jp
はじめに こんにちは、ZOZOTOWN企画開発部 企画フロントエンド2ブロックのパクサンイです。普段はZOZOTOWNにあるCMSベースのLPページのメンテナンスや機能追加、企画LPページ環境のメンテナンスを担当しています。 ZOZOTOWNの複数のWebアプリケーション間で、プロモーション用ランディングページコンポーネントを共有するために、LitベースのWeb Componentsを導入しました。本記事ではその事例を紹介します。 ZOZOTOWNでは多数のLPページが開設・更新されており、従来はiframeを使った埋め込み方式でUIを共有していました。しかし、この方式にはさまざまな課題が存在し、レガシー環境からNext.jsベースの新環境へのリプレイスを進める中で、フレームワークに依存しないUI共有アーキテクチャが必要となりました。 本記事では、iframeベースの共有方式が抱える具体的な課題と、LitベースのWeb Componentsを採用した理由と選定プロセスを解説します。さらに、フレームワーク非依存なコンポーネント共有基盤を設計・実装する中で得た経験を共有します。 対象読者 マルチWebアプリケーション環境でUI共有に課題を感じているフロントエンドエンジニア iframeを使ったUI共有方式の代替手段を探している方 Web Componentsの導入を検討している方 目次 はじめに 対象読者 目次 背景・課題 ZOZOTOWNフロントエンドのマルチWebアプリケーション構成 LPコンポーネントの共有仕様 従来のiframeベース共有方式とその課題 1. レイアウト制御の煩雑さ 2. UI制御の複雑化 3. SEOの制約 アプローチ:Web Componentsの導入 要件整理 技術選定:Lit基盤Web Components Litを選択した理由 npmパッケージ方式を除外した理由 設計・実装 全体アーキテクチャ 1. 利用側アプリケーションによるデータ取得・加工 2. Lit ContextによるProps Drilling防止 3. Scriptローディングによる独立したUI更新 4. Shadow DOMからLight DOMへの切り替え ビルド・配信 全体フロー LPコンポーネント開発側(コンテンツ共有専用リポジトリ) 利用側Webアプリケーション 効果 学んだこと 今後の課題 今後の展望 まとめ 最後に 参考資料 背景・課題 ZOZOTOWNフロントエンドのマルチWebアプリケーション構成 現在、ZOZOTOWNのフロントエンドは3つのマルチWebアプリケーションで運用されています。 リポジトリ 説明 主な役割 リポジトリA(レガシー環境) 統合リポジトリ 既存の全ページを管理 リポジトリB(リプレイス環境) コアメインページ ホーム、カート、検索結果、商品詳細ページなど リポジトリC(リプレイス環境) 企画ページ フルスクラッチLP、CMS活用LP レガシー環境では複数のサービスが単一リポジトリで管理されていたため、共通UI共有に関する課題はありませんでした。しかし、リプレイス後にマルチWebアプリケーションが増えたことで、従来の方式ではUIを再利用できなくなりました。 LPコンポーネントの共有仕様 ZOZOTOWNでは特定のLPコンポーネントを複数のページで表示しています。一部のページでは以下の2つの形態で表示されます。 単独ランディングページ — header/footerを含むフルページ モーダル表示 — 特定ページのバナークリック時に、header/footerなしでコンテンツセクションのみをモーダルで表示 つまり、ほぼ同一のUIでありながら、header/footerの有無、SEOメタタグ、計測用トラッキングスクリプトの有無などで差異がある仕様でした。 従来のiframeベース共有方式とその課題 リプレイス後は以下の方式でUIを共有していました。 環境 運用方式 リポジトリA(レガシー) LPページ配信 + iframe用LPページ(header/footerなし)配信 リポジトリB・C(リプレイス) 特定ページにバナー表示 → クリック時にモーダル内でiframeとしてリポジトリAのLPを埋め込み このiframe方式には以下の課題が存在していました。 1. レイアウト制御の煩雑さ iframeは独立したドキュメントを読み込むため、フレームサイズの調整や使用箇所ごとの非表示領域の処理は対応していたものの、煩雑な部分がありました。 2. UI制御の複雑化 各バリエーションに応じて非表示にすべき子コンポーネントもあり、クエリパラメータやpostMessageで解決できるものの、ケースが増えるほど複雑化しました。 3. SEOの制約 検索エンジンはiframe内のコンテンツをsrc側の所有として認識するため、SEO上の制約がありました。 アプローチ:Web Componentsの導入 要件整理 上記の課題を解決するために、以下の4つの要件を整理しました。 要件 説明 各アプリのデプロイなしにUI更新 iframe方式の利点であった各マルチWebアプリケーションのデプロイなしにUI変更が反映されることを維持 iframe脱却 各アプリケーションでネイティブにUIをレンダリング フレームワーク非依存 React、Vueなど、どのフレームワークでも使用可能であること 軽量バンドルサイズ 利用側に負担のない最小限のサイズを維持 技術選定:Lit基盤Web Components Web Componentsはブラウザのネイティブコンポーネントモデルであり、特定のフレームワーク(React、Vueなど)に依存せず、ブラウザが直接理解する標準技術です。主に以下の3つの中核技術で構成されています。 Custom Elements:開発者が独自のHTMLタグを定義できる。タグ名にはハイフン(-)を含む規約がある。 Shadow DOM:コンポーネントのスタイルとマークアップを外部ページから隔離(Encapsulation)する。 HTML Templates:<template>と<slot>要素により、再利用可能なマークアップ構造を定義する。 このWeb Componentsをより効率的に開発するため、Litライブラリを採用しました。 Litを選択した理由 選定基準 Litの特徴 バンドルサイズ 約5KB(minified + compressed)で非常に軽量 リアクティブプロパティ Reactive Propertiesにより状態変更時に自動再レンダリング テンプレート Tagged Template Literalsベースで別途コンパイル不要 パフォーマンス Virtual DOM diffingなしに動的部分のみを直接更新 相互運用性 すべてのLitコンポーネントはネイティブWeb Componentであり、HTMLを使うあらゆる場所で動作 npmパッケージ方式を除外した理由 LPページはテキスト更新の頻度が高く、UIも不定期に変更されます。npmパッケージで運用すると、変更のたびに各環境でパッケージ更新+デプロイが必要となり、運用負荷が大きいため除外しました。 設計・実装 全体アーキテクチャ コンテンツ共有専用リポジトリを新たに構築し、以下の設計原則を適用しました。 1. 利用側アプリケーションによるデータ取得・加工 ZOZOTOWNにはページアクセス時に初期設定すべき値やAPIフェッチのためのロジックが各アプリケーションに存在します。これらのロジックをコンテンツ共有専用リポジトリにも含めると管理が二重になりメンテナンス負荷も大きくなるため、このリポジトリではUIレンダリングのみを責任範囲としました。 利用側の親アプリケーションでデータを取得・加工してpropsで渡す形式を採用しています。 2. Lit ContextによるProps Drilling防止 UI内部で必須的に共有すべき情報(デバイス種別、性別など)は、Lit Contextを活用したカスタム要素を設けて処理しました。 Lit ContextはReactのContext APIと同様の概念で、Props Drillingなしに上位から下位コンポーネントへデータを渡すことができます。 3. Scriptローディングによる独立したUI更新 各Webアプリケーションで別途デプロイなしにUI変更が可能なよう、Scriptローディングを採用しました。各アプリケーションでは<script>タグで必要なコンポーネントのJSファイルを読み込み、クライアントでWeb Componentがレンダリングされます。 4. Shadow DOMからLight DOMへの切り替え Web Componentsの代表的な特徴であるShadow DOMは、スタイルを完全に隔離し、コンポーネント内部のCSSが外部に影響せず、外部CSSも内部に影響しません。 しかし、今回のケースでは、Shadow DOMで隔離して管理するUIではなく、利用側から自由にスタイルだけでなく要素にもアクセスできることが重要でした。そのため、Shadow DOMの代わりにLight DOMを採用しました。 ビルド・配信 Viteを使用してLit基盤Web Componentをビルドし、S3にデプロイしてCDN経由で配信します。 全体フロー LPコンポーネント開発側(コンテンツ共有専用リポジトリ) Lit + Vite dev serverでローカル開発 各テスト環境にてHTML + JSで動作確認 問題なければ各環境(S3)にデプロイして確認 利用側Webアプリケーション SSR時にCMS APIでデータ取得(スケジュールに応じて変更されるテキストなどはCMSで管理) クライアントで<script>タグによるJSファイルローディング、Web Componentのレンダリング カスタムタグへCMS API仕様に合わせたデータをpropsで渡す 効果 この仕組みの導入により、以下の効果が得られました。 マルチWebアプリケーション間でiframeを使わずにUIコンポーネントを共有できるようになった 各アプリケーション側のリリース(デプロイ)なしでコンテンツ更新が可能になった 利用側からスタイルだけでなく要素へのアクセスも自由に可能になった(Light DOM採用) CMS連携により、エンジニア以外でも直接スケジュールベースのデータ管理が可能に 学んだこと Litを通じて開発する中で、Web Componentsのベースとなるウェブ標準技術をより深く理解し、関心を持つようになりました。また、CSS変数などを活用してJavaScriptなしにCSSだけでスタイルを制御する方法も知ることができました。 今後の課題 Web Components公式のSSR対応はまだ限定的ですが、Lit SSRなど複数の解決策がライブラリやコミュニティで共有されています。現在、このプロジェクトで管理しているLPページの仕様ではWeb ComponentのSSRは不要ですが、将来に備えた準備は必要だと考えています。 また、現在の運用方式では、Scriptローディング+CMSデータ連携という構造上、テストが非常に重要であり補強が必要です。<
こんにちは、フロントエンドエンジニアのmehm8128です。 僕は25卒としてサイボウズに新卒入社し、内定者アルバイト時代も合わせると1年半なのですが、正社員としてはちょうど1年が経ちました。弊社1年目ではどんなことができるのかという参考に、書いてみました。 フロントエンド基盤の刷新 サイボウズのほとんどのフロントエンドエンジニアの多くは、主力製品であるkintoneのフロントエンド基盤の刷新プロジェクトに参加しています。 普段は個人としてアクセシビリティに関する発信を多くしていることから、業務でもアクセシビリティ関連のことをメインでやっていると思われていることがあります。しかし実際には、フロントエンド全般に幅広く関わっています。 今のkintoneの大部分は、Google Closure Toolsというフレームワークで作られています。しかしこれは2024年にEOLになったこともあり、今では「Google Closure Toolsといえばサイボウズ」と言えるくらい他で見ないものになってしまいました。そこでフロントエンド基盤の刷新プロジェクトでは、kintoneを全てReactに置き換えています。 その中でも僕のいるチームはkintoneのアプリ機能という、kintoneの中でも最も基本的な機能の刷新を行っています。アプリ機能の画面では、ユーザーがシュシュっと作成したアプリに対してレコードを追加したり、そのレコードの一覧や詳細情報を閲覧したりすることができます。 レコード一覧画面(開発中の画面) もう少し詳しい説明は過去の記事をご覧ください。 blog.cybozu.io blog.cybozu.io 現在のチームのメンバー構成としては、EM1人、SWE5人(自分はここ)、QA2人となっています。多いときは内定者アルバイトメンバー含めてもう4人ほど所属していました。 内定者アルバイトのメンバーを除くと自分は最年少ですが、フロントエンド基盤の刷新はやることが多く、かつなるべく最短で完了することが求められていることから、新卒1年目の自分でもタスク管理や内定者アルバイトメンバーのサポートを行うことが多くあります。それ以外は、与えられたタスクやコードレビューをひたすらこなしたり、必要に応じて他チームとの連携を図ったりしています。 ここからは具体的な業務内容をいくつか紹介していきます。 インライン編集機能の実装 前述の内定者アルバイト時の記事にも記載したのですが、インライン編集は僕がメインで実装した大きい機能のうちの1つです。 レコード一覧のテーブル行で編集ボタンをクリックすると、テーブル上でそのレコードの情報を編集できます。記事にも書いたのですが、モード切り替え、各フィールドのUI配置、編集した値の保存処理、データの変換処理という複数の作業が必要で、規模が大きいタスクでした。 インライン編集(開発中の画面) kintoneはアプリのフォームに様々な種類のフィールドを配置することができ、それぞれ特徴が違います。例えば以下のような特徴を持つフィールドがあります。 値を編集できるフィールド 例:文字列(1行)フィールドやユーザー選択フィールド 値を編集できないフィールド 例:ラベルフィールドや作成者フィールド フィールドの中にフィールドを入れられるフィールド 例:テーブルフィールドやグループフィールド 編集画面では編集できるけどインライン編集では編集できないフィールド 例:添付ファイルフィールドやルックアップフィールド jp.kintone.help これらを踏まえて、編集できないときの表示や、そもそもテーブル上に表示しない場合、通常は編集できるけど特定のユーザーには編集権限を与えられていない場合、などを意識しながら実装する必要がありました。もちろん全部1人で実装したわけではないですが、基盤部分は僕が実装したのでkintoneのアプリ領域の複雑さを体験できる良いタスクでした。 グラフ設定ダイアログの実装 グラフ設定ダイアログは、半年ほど前に実装したものです。こちらも多くの部分を僕が実装しました。 kintoneでは、アプリに登録されたレコードの情報をグラフ形式で閲覧することができます。レコード一覧画面・レポート画面の「グラフを設定」ボタンをクリックして開くダイアログ上で、グラフの種類や集計に使うフィールド、絞り込みなどの設定をすることができます。 jp.kintone.help グラフ詳細画面(開発中の画面) グラフ設定ダイアログ(開発中の画面) アプリ設定画面でも同様のグラフ設定画面があり、そちらは既に他チームが実装済みだったので、中心となるロジックはそちらから取ってくることができました。しかし、アプリ領域の仕様・既存コードとの整合性を取ったり、URLのパラメータから取得した初期値をグラフ設定ダイアログ用に変換して適用したりする作業にかなりの時間を費やしてしまいました。 反省点としては、もう少しコンポーネントテストやロジックの単体テストを多く書きながら進められると良かったのかもしれません。ちなみに最近『単体テストの考え方/使い方』を読んだので、個人的にフロントエンドテストについてもう少し探求してみたいと考えています。 デザイナー・デザインシステムチームとの連携 チームの中でも、僕はデザイナーチームやデザインシステムチーム(厳密にはデザインテクノロジストという、デザインシステムに限らず開発チームとデザイナーチームとの橋渡しをする役割を持っているチーム)との連携を取ることが多いです。僕がロジック寄りの領域よりも、HTMLやCSS、アクセシビリティなどUI方面の領域に興味を持っていることから、いつの間にか自分がこの役割を担うことが多くなっていました。 具体的な例として、定例ミーティングを紹介します。 週1で30分、僕が所属する本体開発チームに加えてデザイナーチーム、デザインシステムチームの3チームから一部のメンバーが集まって合同でミーティングを行い、アプリ領域の開発を進める上での相談事を持ち込んで議論しています。 例えば本体開発チームからは、以下のような議題を持ち込むことが多いです。 デザイナーさんに作ってもらったデザインを実装する上で技術的に難しく、妥協案を相談したい部分 少し複雑なインタラクション実装において、アクセシビリティを確保するための実装方針 既存のデザインシステムのI/Fのままでは実現するのが難しそうな箇所 <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cybozuinsideout/20260401/20260401113023.png" alt="Garoon予定にmehm8128が投稿したコメント。「カレンダーの年月の入力欄+ポップアップがkDSのInputDateと違う(日の入力欄がない)ことに気づいたので、そこ&
こんにちは!サイボウズでプロダクトエンジニアをしている @daikimkw です。 この記事では、kintone のフロントエンド開発で AI をどのように活用しているか、そして kintone 開発全体として生産性を向上させるために今後どのような取り組みをしていくかについて紹介します。 kintone 開発での AI 活用については、以下の記事でも紹介しています。 サイボウズで利用可能な AI コーディングツールの紹介 kintone AI 開発の効率化!Claude Code に Renovate PR レビューをお任せした話 チーム専用の Claude Code Plugin マーケットプレイスを作った話 また、本記事の取り組みの一部は JS ConfJP 2025 で発表しているので、そちらの動画や資料も参考にしてください。 www.youtube.com 資料:大規模プロダクトで実践するAI活用の仕組みづくり AI 活用の取り組み kintone は顧客領域ごとに複数チームで開発されており、コードベースの規模も大きく、AI をうまく機能させるにはいくつかの工夫が必要でした。 ドメイン知識をマークダウンで管理する kintone は歴史的経緯や最適化のための工夫により、コードを読んだだけでは意図が伝わりにくい設計が多くあります。これらを AI に都度伝える必要がないよう、ドメイン知識をマークダウンファイルとしてリポジトリに配置し、AI が参照できるようにしています。具体的には、JS API・プラグイン機構・グラフなどの複雑な実装の設計背景や、kintone 固有の用語集などです。 kintone のフロントエンドはチーム単位でディレクトリが分かれており、その中で pnpm の monorepo として構成されています。この構成を活かし、ドメイン知識のマークダウンもチームごとに配置しています。こうすることで、AI が参照するコードとコンテキストの範囲がチームの担当領域に絞られます。グラフなどの複雑な実装や設計背景も、グラフを管理しているチームに閉じられるため、他チームのコンテキスト消費を抑えられます。 frontend/ ├── teamA │ ├── ai-guide # ドメイン知識をチームごとに管理 │ │ ├── js-api.md # JS API の設計 │ │ └── glossary.md # 用語集 │ ├── app1 │ ├── app2 │ ├── pnpm-workspace.yaml ├── teamB │ ├── ai-guide │ ├── app1 │ ├── app2 │ └── pnpm-workspace.yaml └── ... Agent Skills をチーム横断でリポジトリ管理する kintone 開発では、もともと各チームで Agent Skills を整備していました。 kintone リポジトリのルートに共通の Agent Skills もいくつかありましたが、チームによっては不要な Agent Skills が混ざっていると不要なコンテキスト消費につながってしまいます。一方で、チームの中だけに閉じていると知見がサイロ化してしまいます。 そこで、お互いの Agent Skills を参考にしつつ、チームごとに必要なものだけを選んで導入できるように、kintone 開発全体で共有する共通リポジトリを用意しています。 kintone-skills/ ├── kintone-development/ │ └── skills/ # 汎用 Agent Skills ├── teamA/ │ └── skills/ # チーム固有の Agent Skills └── teamB/ └── skills/ Claude のプラグインマーケットプレイスの構造に準拠させているため、 /plugin から追加でき、Cursor など他のツールでも vercel-labs/skills 経由で利用できるようになっています。ルールは設けず自由に追加できる運用にすることで、他チームがどんな Agent Skills を作っているか見える化し、知見がサイロ化しないようにしています。 具体的な Agent Skills の紹介 実際に使っている Agent Skills をいくつか紹介します。 文言の検討 kintone は多言語対応しており、新しい機能を実装するときには複数言語の文言を用意する必要があります。ただし、デザインシステムのライティングガイドラインや既存の文言パターンとの一貫性を保つのは手間のかかる作業です。この文言作成・レビューのワークフローも Agent Skills 化し、効率よく文言の検討を進められるようにしています。 以下は、「input:type=file にホバーしたときに相当する文言を検討して。」と入力した時の結果です Claude Code とのやり取りのスクショ セッション情報をファイル出力する AI とのやりとりはセッションが途切れたり、サマリー化(Compact)されるとコンテキストが失われます。そこで、AI とのやりとりや、実装計画を全てファイルに出力して残すようにしています。 実装開始時に、次のようなディレクトリを作成します。 0123_feature-name/ ├── plan.md # 実装計画 └── prompt.md # やりとり履歴 plan.md には、実装計画、タスクの分解、進捗を記録します。prompt.md には、生のプロンプト内容と、それに対してどう実装したかを記録します。どういう指示を出して、AI がどう判断したかが残るため、コンテキストの復元に役立ちます。 この 2 つのファイルにより、セッションが途切れても作業を再開でき、計画と実装を別のエージェントに任せるなど、柔軟にエージェントを切り替えることもできます。 エージェントによっては、実装計画専用のプランモードがありますが、プランモードを抜けるタイミングでファイル出力等のコンテキストを忘れてしまうため、今はプランモード相当のサブエージェントを使用しています。プランモードを抜けるタイミングで Hook させ、思い出させることができればもっと良いのですが、今のところはこのようになっています。 ドメイン知識を継続的に育てる ドメイン知識を管理するマークダウンファイルは実装が進むにつれて内容が実態と乖離していきます。そのため、定期的に実装とドキュメント内容に乖離がないかチェックするための Agent Skills も用意しています。 MCP の活用 Agent Skills だけでなく、MCP も AI の作業範囲を広げるのに役立っています。 kintone には kintone Design System チームが管理するデザインシステムがあり、デザイントークンやコンポーネントの仕様が Figma や npm パッケージとして管理されています。 note.com Figma で構築されたデザインの反映には Figma MCP や Chrome Devtools MCP 等を活用し、デザイントークンの取得から動作確認まで AI に任せています。 また、kintone Design System チームでは、コンポーネントの情報や仕様を取得できる MCP サーバーも開発しています。これにより、AI がデザインシステムの仕様を直接参照しながらコードを生成できるようになっています。 これからの課題 AI 活用が進む一方で、まだ解決できていない課題もあります。開発工程での AI 活用が進んでも、全体のリードタイムを短縮するには、デザインや品質保証のプロセスも一緒に変えていく必要があります。現状は、各チームが試行錯誤しながら、うまくいった取り組みを横展開していくという形になっています。この動きを加速させるために、組織横断での AI 活用推進の取り組みもやっています。こちらについては、また 1 〜 2 ヶ月後に誰かが書く記事を参考にしてください。 おわりに kintone 開発における AI 活用は、個人の生産性向上から始まり、開発チーム横断でのナレッジの共有、そして他職能を跨いだ活用推進へと広がりつつあります。開発速度以外も AI を使って加速させていきたいですね!