kikitori Tech Blog

株式会社kikitoriは、農業流通現場のDXを実現するSaaS『nimaru』と青果店『KAJITSU』を運営する会社です。

プロダクトマネージャーとしてMagicPodを活用し、品質向上に取り組んでいる話

はじめに

kikitoriでプロダクトマネージャーをしている兒玉です。
本記事では、プロダクトマネージャーである私が、MagicPodを活用してプロダクトの品質向上に取り組んだ(取り組んでいる)事例について紹介します。
QAエンジニアが不在で、少人数でプロダクトを開発・運営しているスタートアップやチームにとって為になれば幸いです。

開発チームとして直面していた品質課題

nimaruはPMF目前の状況で、ほぼ毎日リリースを行う体制を取っています。ありがたいことにお客様も日増しに増えており、BizとDevが日々高速に連携しながら開発・リリースを進めています。

最終的な品質担保については、基本的に実装者が責任を持つ形で進めていましたが、ある日PRの内容からは想像しきれない箇所で、お客様にとってクリティカルな機能が操作不能になる事象が発生することがありました。

ポストモーテムを実施する中で見えてきたのが、お客様の主要な操作を担保する仕組みが存在していないという課題でした。
そこでこのタイミングで、主要なE2Eテストを継続的に実施できる仕組みを構築する方針を取りました。

一方で、進行中のプロジェクト状況を踏まえると、新たに体制を構築したり、エンジニアのリソースを大きく割いたりするのは現実的ではありませんでした。
そこで、私自身が過去にエンジニアとしてE2Eテストツールの導入・運用を少し経験していたこともあり、今回はプロダクトマネージャーである私が主導して進める判断をしました。

なぜMagicPodを選んだのか

nimaruの主要機能として、集出荷機能があります。

この機能では、生産者はスマートフォンから「いつ・何を・どれだけ出荷するか」を事前に連絡し、職員はPC・タブレットスマートフォンを使って、実際に集まった農産物を受け取り、出荷先ごとに仕分け(分荷)を行います。その後、最終的に出荷内容を確定し、市場や取引先へ出荷するための出荷連絡を行うことができます。

この操作フローは、プロダクトにおける最重要ユースケースの一つであり、この一連の操作をテストできることを必須条件としました。

加えて重視したのが、運用に手間がかからないことです。
ここで言う「手間がかからない」とは、非エンジニアでもテストケースの作成・メンテナンスを低工数で行えることを含みます。

この条件を満たす候補として、MagicPodBrowserStackに絞り、両方の無料枠を利用して使用感を試しました。

BrowserStackは、画面操作を録画するだけでテストケースを作成できる点が非常に魅力的でした。一方で、生成されたテストケースの修正時に、裏側で生成されているコードを修正する必要が出てくる点に、長期的な運用面での懸念が生まれました。

その点、MagicPodでは同様の懸念がなく、テストケースの保守をコード修正に依存せず行えることが、選定の決め手となりました。

プレ導入期間の計測指標について

MagicPodは価格面で見るとBrowserStackよりも高額なため、いきなり本導入するのではなく、成果を計測しながら慎重に導入する方針を取りました。

具体的には、月契約で3か月間のプレ導入期間を設け、その後に年契約に切り替えるかの判断を行う形にしました。

そこで、プレ導入期間中は以下3点の基準で、毎月1回振り返りをしました。

保守工数(1か月あたりのメンテ時間)

  • 非エンジニア主体でも無理なく回せるか
  • 目標:5〜7時間以内
  • 「負荷が高くて回せない」状態にならないか

安定稼働性

  • UI変更がない限り安定して動き続けるか
  • テスト落ちが頻発しないか
  • テスト落ち時の対応工数が過度でないか

品質担保への実感

  • コア機能の自動実行によって、致命的なデグレを検知できているか

プロダクトマネージャー主導で進めた導入・運用の進め方

まず、MagicPod導入の目的をチーム全体で共有しました。
このテストがテストピラミッドのどこに位置づけられるのか、主要ユースケースに絞って自動化する理由、そして「メンテナンスを増やさない」ことを特に重視しました。

過去にエンジニアとしてE2Eテスト導入を進めた際、QA知見が乏しい状態でユニットテスト寄りの内容をE2Eで自動化してしまい、失敗した経験があります。その反省から、今回はここを強く意識しました。

テストピラミッド

次に、先輩プロダクトマネージャーを巻き込みながら、nimaruにおける主要ユースケースをユーザーシナリオとして定義しました。
プレ導入期間では、特に優先度が高い3つのユーザーシナリオを自動化対象としました。

幸い、過去の大きな改修時に使用していた手動テスト用のユーザーシナリオが存在していたため、それをベースに進めることができ、選定と定義に大きな時間を割かずに済みました。

テストケースの作成は、まずは私一人で行うことにしました。 また、テスト結果はSlackへ通知し、毎時の自動実行形にしました。

開発との連携としては、1時間に1回dev環境でMagicPodを実行し、テストが通っていることを確認したうえでリリースを行ってもらう運用にしました。

実際に導入・運用してみてどうだったか

2025年12月に初回の振り返りを行いました。

主要な成果としては、運用体制の構築や初期セットアップ、Slack連携の整備に加え、優先度が最も高いテストケースを作成し、安定的に稼働させられた点が挙げられます。

また、保守工数は月6時間程度に収まり、自動補正機能も有効に働いたことでテスト落ちはほとんど発生しませんでした。 これらの結果から、MagicPodは本導入に向けて十分に手応えのある指標を示していると感じています。

プロダクトマネージャー視点での課題とその打開策

1. テストケース作成にかかるリソース確保
現状は私一人が立ち上げを担っており、意識的に時間を確保しなければ進まないのが正直なところです。一方で、共有ステップ機能を活用してテストケースの部品化を進めたことで、以降のテストケース作成は徐々に効率化できています。実際に、1ケースあたりの作成時間は確実に短くなってきており、運用として現実的な手応えを感じています。

2. MagicPodの運用が属人化
テストケースの作成や運用を一人で担っているため、このままでは継続性やスケールに限界があります。その打開策として、本導入を見据え、テストが落ちた際には、その変更によって影響を与えたエンジニア自身が修正対応できるよう、簡易的なマニュアル整備を進めています。将来的には、私がすべてを抱え込むのではなく、チーム全体で品質を支える体制に移行していきたいと考えています。

3. E2Eテストだけでは担保しきれない領域が存在すること
nimaruには各種帳票のPDFを出力する機能がありますが、PDFの中身などは自動テストの対象にしづらく、引き続き人の目による確認が必要です。こうした領域については、自動化にこだわりすぎず、自動化と人力を組み合わせたハイブリッドな体制を前提とすることが、現実的かつ健全な選択肢だと感じています。

今回の取り組みを通しての学びとみなさんへ伝えたいこと

今回の経験を踏まえ、これから同じような取り組みを行う方に伝えたいポイントは、主に次の3点です。

一つ目は、すべてを自動化しようとしないことです。
E2Eテストで担保すべきなのは、プロダクトにとって「絶対に落とせない操作」に限る、という割り切りが重要だと感じています。

二つ目は、「絶対に落とせない操作」から着手することです。
最初から広く網羅しようとすると、テストケースの作成・保守が重荷になりがちです。まずは影響範囲が大きく、失敗した際のインパクトが大きいユースケースに絞ることで、小さくても確実な価値を出すことができます。

三つ目は、ツール導入そのものをゴールにしないことです。
MagicPodは非常に便利なツールですが、導入すること自体が目的になってしまうと、運用が形骸化しやすくなります。小さく始め、価値を確認しながら徐々に広げていく、そのプロセスを、役職にとらわれず誰かがしっかり主導することが、品質向上をプロダクト改善につなげるうえで重要だと考えています。

まだ取り組みは途中ですが、同じような課題を抱えるチームの参考になれば幸いです。

最後に

kikitoriでは事業拡大に伴い、一緒に働く仲間を募集しています!
ご興味ありましたらぜひお気軽にエントリー・面談をお申し込みください。
お待ちしております!

careers.kikitori.jp

現場とともに進めるDX nimaruアワード2025先進DX事例研究会レポート

こんにちは。株式会社kikitoriでプロダクトマネージャーをしている松本です。

今回は11月に開催された「nimaruアワード2025先進DX事例研究会」について紹介します!

※株式会社kikitoriは「nimaru」という、JA等の集出荷団体や運送会社、市場の方が業務で使うSaaSの開発をおこなっています

nimaruアワード2025先進DX事例研究会は普段からnimaruを積極的に使ってくださっている事業者様を表彰し、その活用事例を共有するイベントです。

イベントは事業者様を表彰するnimaruアワード2025と事業者様とkikitori社員が座談会形式で事例を紹介する先進DX事例研究会の2部で構成されています。

全国のnimaruユーザー様に集まっていただきました

nimaruアワード2025

全国のnimaruを使っていただいている事業者様の中から「導入定着部門」「導入推進部門」「波及創出部門」「組織変革部門」「連携協創部門」「nimaruDX大賞」の合計6部門で表彰させていただきました。

表彰の様子

個人的には使っていただいている事業者様すべてにありがとうございます、なのですが導入当初に既存機能だけでは現場オペレーションがうまくまわらなかった事業者様が表彰されているのを見ると感慨深いものがありました。

もう実際に使っていただいている中、タイムプレッシャーを感じながらも開発部一丸となって頑張ってよかったなと。

今年もたくさんの機能拡充をしたので、その機能をフル活用していただいた事業者様が来年の賞につながれば嬉しいですね。

先進DX事例研究会

先進DX事例研究会では下記の3つのトークセッションと代表上村による今後のnimaruの未来について話すセッションが行われました。

  • セッション①:「壁」を越えて成果へ導く ~nimaru導入推進のリアルと成功要因~
  • セッション②:現場と共に歩むDXの第一歩 ~JA高知県・JA佐波伊勢崎と考える生産者とのコミュニケーションと生産管理の可能性~
  • セッション③:つながる販売、広がる協働 ~nimaruJAが導く市場・物流との新時代の連携モデル~
  • 基調講演:「nimaruが見据える将来構想」

トークセッションの様子

実際に導入していくにあたってのハードルやそれをどう乗り越えたか、新機能を一緒に作っていく上で掘り出していった課題、今後の事業者間の連携などそれぞれ熱く語っていただきました。

導入前の稟議といったフェーズは普段あまり関わることがなく、DXを組織として決断していくのはプロダクトをつくるのとは別の大変さがあるのだなと実際にお話を聞いて再認識です。

nimaruを信じて導入を推進していただいた担当者様には感謝しかありません。

代表上村による講演

基調講演:「nimaruが見据える将来構想」では代表の上村からnimaruの構想、今後の開発ロードマップが共有されました。

参加者皆さんが壇上に映るスライドの写真を撮られていて、将来構想への関心が高いのをひしひしと感じました。

そこまで伝えてしまうのかと内心ヒヤヒヤし引き返せないぞと気を引き締めたのは内緒です。

まとめ

お忙しい中集まっていただいた事業者様への感謝はもちろん、そんな事業者様をこのようなイベントに招待できる関係値を築いてきたBizメンバーに感謝を感じた1日でした。

また、私は普段の業務だと課題感のある現場や新機能のための現場ヒアリングが多くなりなかなか活用が進んでいる現場に行くことができず、今回のイベントで実際にプロダクトを使ってもらえていると実感をもつことができました。

来年もnimaruを導入いただいた方々の期待に応えられるよう機能開発を進めていきたいと思います。

kikitoriではBizメンバーが日々顧客との関係構築を進め、開発のための現場訪問やヒアリングがしやすい環境が整っています。 ユーザーと向き合いながらプロダクト開発を進めていきたいという方はぜひ一度お話ししましょう!

herp.careers

ChatGPT AtlasでE2Eテストを書こうとして、うまくいかなかった話

ChatGPT Atlas がリリースされた時

自然言語でブラウザ操作できるなら、E2Eテストがかなり楽になるのでは?」

そう思っていました。

Playwright のような E2E テストフレームワークはまだプロダクトに入れておらず、

Atlas でE2Eテストは実現できるのか?

というところから検証を始めました。

最初に試した方法は単純に、「ログインしてダッシュボードが表示されることを確認して」のようなざっくりとした指示を Atlas に出す方法です。
「うまくはいかないだろう」とは思っていましたが、やはり期待した通りには動きませんでした。
※ 動いたことには感動しました。

そこで次に試したのが、playwright codegen のログを ChatGPT に渡して自然言語の手順に書き起こしてもらい、 そのまま Atlas に流す、という方法です。

「ChatGPT が整形してくれたので、手順としては十分だろう」 正直そんな期待をしていました。

が、結論としてこれはあまりうまくいきませんでした。

この記事では、

  • なぜ ChatGPT に整形してもらった自然言語手順でも Atlas は安定しなかったのか
  • 逆にどのレベルまで書けば、Atlas がそれなりに動くようになったのか

といった点をまとめます。


背景:E2Eテストの“面倒な部分”を機械化したかった

Playwright でテストコードをゼロから書こうとしたのですが、以下のポイントでつまづきました。

  • セレクタやロールの管理が大変
  • ページ遷移や非同期周りの待ちを考慮しなければならない
  • UIが変わるとテストも壊れやすい
  • 「何を検証したいのか」と「どう実装するか」を両方考える必要がある

そこで、Atlas のように自然言語で操作できる仕組みが使えれば、

実装の負担をかなり減らせるのでは?

という期待をしていました。

ただ、テスト仕様書をいきなり書くのも大変なので、

codegen のログ → 生成したプロンプト”

を最短ルートとして使えないか? というところから始めました。


アプローチ:codegen → ChatGPTでプロンプト化 → Atlasに渡す

手順は次の通りです。

  1. npx playwright codegen https://example.com/ を実行
  2. ログイン~画面遷移のシナリオを手動で操作
  3. 生成された Playwright コードを ChatGPT に渡す
  4. 「playwright codegenで生成されたコードをAtlas Agent用プロンプトに変換してください。」と依頼
  5. ChatGPT が生成したプロンプトを Atlas にそのまま渡す

ざっくりですが ChatGPT が生成した手順は以下のような感じでした。

Step 01: ログイン画面表示
baseUrl にアクセスする。
ログインフォームの2項目
ID 入力欄 に id を入力
パスワード入力欄に password を入力

ボタン(role=button, name=ログイン)をクリック。

画面に 「認証しています」 などの進捗表示が出た場合は、それが消える/遷移が完了するまで待機。

Screenshot: Step_01_Login.png

検証: ログイン後のトップ/ダッシュボードが表示されること。

動作や検証ポイントなどがそれなりに明示されていて、一見すると問題なく見え、正直期待をしてました。

実際には、この手順を Atlas に渡しても安定して動作しませんでした。


前提条件が曖昧で、テストの開始地点がずれる

ChatGPT が作成した手順はあくまで「操作の順番」を文章化しただけのため、

  • 既にログインしている状態
  • セッション情報を反映した画面の状態
  • すでに1度動かしてデータが登録されている状態

といったケースを考慮していません。

加えて、どの要素を具体的に操作対象とすべきか、何をもってテストの成功とみなすのかといった情報も、この手順の中には含まれていませんでした。

前提が書かれていないと、Atlas が正しい判断ができず、指示を意訳して操作しようとします。 いつまでも試行を続けてしまうこともあります。


codegen → ChatGPT での整形では“仕様書レベルの情報”が足りなかった

ここまで試して分かったのは、

ChatGPT が codegen のコードを綺麗に文章化しても
Atlas が必要とするレベルには情報が足りていない

ということです。


では、どう書けば安定したのか

結局、以下のような構造までプロンプトを整えると Atlas の動きが大きく改善しました。

(抽象例)

あなたは **E2Eテスト自動化エージェント** です。  
以下の要件に従って、指定URLにアクセスし、ブラウザ操作によるE2Eテストを実施してください。  

## 注意点
- 指示していない情報で操作しないでください
- 失敗したら操作を停止してください
- 全ての画面においてスクリーンショットを取得し、最後に提示してください。  

## 接続情報
- **URL:** https://example.com/ 
- ログイン情報
    - ID: xxxxx
    - パスワード: xxxxx

## テストシナリオ
- [ ] https://example.com/  にアクセス
  - [ ] もしログイン状態であれば、ログアウトしてください。
- [ ] ログインテスト
  - [ ] 無効な認証情報でエラーメッセージが表示されることを確認
  - [ ] IDとパスワードを入力してログインできることを確認
  - [ ] ログイン後、ユーザー名が表示されることを確認

ポイントは、

  • 操作対象の特定方法を明確にする
  • もし~の場合の動作を書く
  • 曖昧な表現を排除する
  • 「操作」と「確認」を分離する

といった、仕様書とほぼ同じ粒度で書くことでした。


ChatGPT Atlas での E2E テストを検証してわかったこと

一言でいうと、

AI は「よしなに」はやってくれない。

ということでした。

プロダクトを初めて触る人でも迷わず操作できるくらいの粒度で
テスト仕様書を書いてあげると、その通りに忠実に動いてくれる。

逆にいうと、そのレベルまで仕様を書き下ろさないと安定しない、ということでもあります。


まとめ

今回の検証で分かったことをまとめると、

  • playwright codegen のコードを ChatGPT に整形してもらうだけでは テスト仕様としては情報不足だった
  • 情報が不足していると Atlas は迷子になりやすい
  • 自然言語で書けるから楽になる」というよりは、 仕様書を書く力がそのまま求められる

総じて、 ChatGPT Atlas で楽にはならないものの、E2Eテストの新しい形を模索する価値は十分にある というのが現時点での手応えです。

We're hiring!

私たちは、すべての人の生活に不可欠な「食」の基盤となる「農業」を、テクノロジーの力で支える、縁の下の力持ちとも言えるプロダクトを作っています。 私自身、難しいこと、これまで誰も取り組んだことがなかったこと、他の業界では見られない現場のリアルなど、こういった文面や資料では伝えきれない多くのチャレンジのあるドメインだと感じています。 ぜひ一度、ゆっくりお話ししましょう!

ご興味をお持ちいただけた方はこちらまで↓↓↓

herp.careers

JavaScript エコシステムでバイナリデータを扱う API の歴史+チートシート

こんにちは。kikitori の永谷です。

テックブログの執筆が一巡したので、改めて私からスタートです。 前回の一巡はテックブログと言いつつテックではない話も多かったので、今回はもう少し技術的な内容も書いていければなと考えています。

というわけで今回は JavaScript エコシステムにおけるバイナリデータの扱いについての記事です。

どうしてこの記事を書こうと思ったのか

弊社のプロダクト「nimaru」はフルスタック TypeScript 構成で開発しています。 農産物という不確実な商品を扱う都合上、画像や PDF ファイルなどバイナリデータを取り扱う処理が多く登場します。

最近もそのあたりのコードレビューを何度か行いましたが、よくコメントするのが、Web API に準拠するのか、Node.js API に寄せるのかという点についてです。

日本語で体系的にまとまっている資料が少なく、しかも歴史的な経緯を知らないと混乱しやすいテーマです。

この記事では、それぞれの API がどのように生まれ、どう関係しているのかを整理してみます。

JavaScript がバイナリを扱えるようになるまで

JavaScript が最初にバイナリデータを扱えるようになったのは、2009 年の Node.js の登場がきっかけでした。

Node.js はネットワーク通信やファイルI/Oを効率的に行うために、文字列ではなくバイト列を直接扱う必要があり、そのために Buffer オブジェクト が導入されました。

Buffer は低レベルなメモリ領域を直接操作できる仕組みで、サーバーサイドでのバイナリ処理を支える重要な要素になりました。

一方で、2010 年ごろにはブラウザ側でも似たようなニーズが生まれます。 WebGL が登場し、GPU に数値配列を渡すために高速なメモリ操作が必要になったのです。

この問題を解決するために考案されたのが ArrayBufferTypedArray で、これは WebGL のための技術として誕生しました。

後にその有用性が広く認められ、2015 年の ECMAScript 2015(ES6) で正式に言語仕様に統合されます。 この時点で、ブラウザ側では ArrayBuffer / TypedArray、サーバー側では Buffer という二系統のバイナリAPI が併存する形になりました。

さらに 2012 年以降、Browserify や Babel、Webpack などのツールが登場し、Node.js のモジュールをブラウザでも動かせるようになります。

その結果、Node.js の Buffer をブラウザで再現する polyfill(npm パッケージ buffer)が普及。 Node.js とブラウザのエコシステムが急速に融合し、現在のように両方の API が混在する環境が生まれました。

バイナリ APIの関係図(チートシート

こうした背景のもとで、JavaScript エコシステムには現在

  • ECMAScript 標準の ArrayBuffer 系列 (ArrayBuffer, TypedArray, DataView)
  • Node.js 由来の Buffer

の二系統が存在します。

その全体像を以下の図にまとめました。

JavaScript エコシステムでバイナリデータを扱うオブジェクトのチートシート

なお、この図には関連する Web API である File や Blob も併記しています。

API の詳細については次の通りになります。

ArrayBuffer (ECMAScript 標準)

「生のメモリ領域」を表す、バイナリデータを扱うための最も基本的なオブジェクトです。 バイト単位で固定長の領域を確保し、その中身を直接読み書きすることはできません。 実際の操作は TypedArrayDataView などのビューを通じて行います。

TypedArray (ECMAScript 標準)

ArrayBuffer の内容を型付きで効率的に操作するためのビューです。 TypedArray オブジェクト自体は公開されておらず、Int8ArrayFloat64Array のように、値の型ごとに異なるサブクラスを使用します。

通常の配列に近い構文で操作できますが、通常の配列と異なり、インデックスアクセスはプロトタイプチェーンを辿りません。具体的に言えば、Object.prototype["0"] = 123 としても new Uint8Array()[0] === undefined です。これにより、通常の配列へのアクセスよりもロジックを簡略化でき、高速化に寄与しています。

なお、Uint8Array は C でいう char[] に近く、「バイト列」の表現として最も自然な API なので、ReadableStream や Fetch API のレスポンスなど、さまざまな Web API で標準的なバイト列表現として利用されており、単なる「ビュー」以上の存在です。

ArrayBuffer の一部分のみから TypedArray を作ることもできるので、 new Uint8Array(oldArray.buffer) はもとの TypedArray とは必ずしも同じサイズにならないことに注意が必要です (byteOffset, byteLength プロパティで位置が分かる)。

  • Uint8Array: 最も汎用的。0〜255 の整数を扱う。
  • Int8Array: 符号付き 8 ビット整数。
  • Float64Array: 64ビット浮動小数点数
  • Float32Array, Uint16Array, Int32Array など他にも多数。

DataView (ECMAScript 標準)

ArrayBuffer をより柔軟に操作するためのビューです。

TypedArray が単一の数値型を扱うのに対し、DataView は任意のバイト位置から任意の型を読み書きできるほか、プラットフォームのアーキテクチャに依存せず好きなエンディアンを使用できます。

便利そうなのですが、一般的な Web アプリケーションで使うのはたいてい Uint8Array なのであまり出番はありません。独自フォーマットのファイルを解析するときとかには便利かもしれませんね。

Blob (Web API)

Blob は イミュータブルなバイト列を抽象的に参照するオブジェクト です。

この「バイト列」がどこに存在するか(メモリ、ファイル、ネットワークキャッシュなど)は実装に依存し、必ずしもメモリ上に読み込まれているとは限りません。 そのため、内容を一度にすべて扱う textarrayBuffer メソッドの呼び出しは、内部でストレージやネットワークからデータを読み出す可能性があるため非同期処理となり、結果としてコピーも発生します。

File (Web API)

Blob を継承したオブジェクトです。Blob が純粋に「データのかたまり」であるのに対し、File はそれに ファイル名 (name)・更新日時 (lastModified) などの「ファイル」に必要なメタ情報が追加されています。

ブラウザで <input type="file">ドラッグ&ドロップ操作を通じて取得できるのは、この File オブジェクトです。

Buffer (Node.js API)

BufferNode.js が独自に持つ伝統的なバイナリ API です。もともとは C++ のネイティブメモリを扱うために設計されましたが、現在は Uint8Array のサブクラスとして実装されています。 現在でも多くの Node.js 標準 APIBuffer を返しますが、内部的には Uint8Array と互換性があるため、ブラウザとの境界は徐々に薄れつつあります。

まとめ

JavaScript でバイナリデータを扱うために、ECMAScript 由来の API と Node.js 由来の API があることを見てきました。

なお、Node.js の BufferUint8Array として実装されるようになったことからも分かる通り、近年の Node.js は ECMAScript 標準、Web API との互換性を重視するようになっています。

新しく書くコードでは、可能な限り標準に準拠した API を使っていきたいですね!

We're hiring!

私たちは、すべての人の生活に不可欠な「食」の基盤となる「農業」を、テクノロジーの力で支える、縁の下の力持ちとも言えるプロダクトを作っています。 私自身、難しいこと、これまで誰も取り組んだことがなかったこと、他の業界では見られない現場のリアルなど、こういった文面や資料では伝えきれない多くのチャレンジのあるドメインだと感じています。 ぜひ一度、ゆっくりお話ししましょう!

ご興味をお持ちいただけた方はこちらまで↓↓↓

herp.careers

0→1フェーズを高速に立ち上げるための要点

kikitoriでエンジニアマネージャーをしている坂村です。 青果流通の新しい事業を立ち上げるなかで、これまでの0→1フェーズでの経験を活かしつつ、日々チームで挑戦しています。

本記事では、その経験をもとに 高速に0→1フェーズを立ち上げるための要点 を整理します。 技術的な工夫はもちろん、チームづくりや文化面の工夫についても触れますので、kikitoriの開発文化を知っていただくきっかけになれば嬉しいです。

要件定義

新規事業の立ち上げでは、ビジネスの仮説は発案者が持っていることが多いため、仮説の立て方そのものには触れません。 ただし、その仮説や信念、あるいはひらめきを 発案者と同じレベルで自分ごと化すること がとても重要だと考えています。

そのうえで、我々エンジニアは事業を技術的な視点から解像度を高めていきます。

  • 今後どんな付加価値を提供できるか
  • 採用する技術が運用コストを高めてしまわないか
  • 技術自体を参入障壁にした場合、その陳腐化リスクをどう見るか

たとえばAIがコモディティ化しつつある近未来においては、「AIそのもの」だけで優位性を担保するのは難しくなっていくでしょう。

次に、サービスが提供する価値をどうやってエンドユーザーに届けるのかを、ユースケースとして分解します。この過程で大枠の機能要件が見え、データの流れや外部連携も整理されます。ユースケース図や全体のワイヤーフレームを作りながら、事業とサービスの解像度を高めていきます。

開発

個人的な感覚ですが、要件が6割程度固まった段階からは同時並行で開発を進め 実際に動くものを見せながら共通認識を形成する 方が早いです。

もちろん作り直しは発生しますが、そこは「プロトタイプだから仕方ない」と割り切ります。設計と開発を明確に分け、レビューを通して承認を得る…といったフローは0→1フェーズにはスピード感が合いません。

ただし、手戻りを最小限に抑える工夫は必要です。

  • 変更が入りそうなテーブルは正規化しておくことで、柔軟性を担保しつつ後の仕様変更に耐えやすくする
  • バックエンドはインターフェースを先に定義し、実装はDIで差し替えられるようにする

こうした仕込みをしながら、仕様変更や方向転換があっても極力追加工数を増やさない工夫を施します。

チーム

0→1フェーズは 少数精鋭 が圧倒的に進めやすいです。

採用観点でいえば、技術を突き詰めるタイプよりも 事業に共感できるタイプ の方が適しています。要件定義と開発を並行して進めるため、常にチームで共通理解を得ながら走り続ける必要があり、大規模なチームだとマネジメントコストが高すぎるのです。また、エンジニア自身も自分はサービス全体のどこの何を作っているのかという意識づけを常にしておくこと、マネージメント側からするとそういうインプットをメンバーにし続けることもポイントになります。でないと、せっかく担当機能を作ったのに結合してみるとちょっと思ったのと違った、みたいな状況になりかねません。ただただ仕様や設計をまとめてエンジニアに渡すのでは0→1フェーズではうまくいきません。

さらに、0→1フェーズでは要件や仕様が変わることは避けられません。確度の低いものは後回しにする工夫をしても、最後はどうしても変更が発生します。 だからこそ 変化に強いチーム構成 を意識することが重要です。

また、特に我々の青果流通ドメインは学習コストがとても高いため、単に技術に強いだけでは立ち上げられません。 生産者さん、JA関係者や市場事業者や運送事業者との会話から要件を拾うことも多く、事業に強く共感できるメンバー でないとキャッチアップが難しいのです。

まとめ

要件定義では、仮説を自分ごと化し、ユースケースから解像度を高める。 開発では、動くものを早く見せつつ、壊れても耐えられる設計を仕込む。 チームは、事業共感と変化耐性を持つ少数精鋭で臨む。

kikitoriでは青果流通という巨大な産業を舞台に、こうした0→1フェーズの挑戦を続けています。不確実性の中でスピード感を持って事業を立ち上げるフェーズにワクワクできる方と、一緒に新しい価値を作っていければ嬉しいです。

現在、kikitoriではエンジニアメンバーを募集しています。

0→1フェーズの事業立ち上げに興味のある方、事業づくりと技術の両輪で挑戦したい方はぜひ採用ページをご覧ください。

自社SaaSに最適なAIコードレビューはどれ?4つのツールを比較して分かったこと

こんにちは。株式会社kikitoriでエンジニアをしている岩本です。

弊社では、AIを活用した業務改善に全社で取り組んでいます。 その一環として、開発時のコードレビューにAIを活用する試みで得られた知見をご紹介します。

AI自動コードレビューツールの選定

ツールの選定にあたり、以下の3つの観点を重視しました。

* ドメイン知識やビジネスロジックを考慮したレビューが可能か

私たちが開発するJA・市場向けの業務SaaS「nimaru」は、専門的な業務知識や複雑なドメインを扱います。そのため、単なる構文チェックに留まらず、プロダクト固有のドメイン知識やビジネスロジックを反映したレビューができることが、ツールを導入する上での重要な要件です。

具体的には、Jiraチケットに記載された仕様をAIが理解し、実装の妥当性や考慮漏れを指摘できるかを重視しました。

* チームの開発フローに馴染むか

チームの一員として自然に受け入れられ、開発フローを妨げない使いやすさも重要な観点です。

* コストは妥当か

機能に見合った価格で、費用を抑えられることが望ましいです。

選定候補ツール

上記の観点とJira連携などを考慮し、以下4ツールを候補としました。

Qodo Merge

オープンソースのPRレビューツール「pr-agent」を企業向けに拡張したサービス。

TOML形式の設定ファイルで細かくカスタマイズでき、RAG技術によるコードベース全体の分析も可能です。

価格: 開発者1人あたり月額38ドル

qodo-merge-docs.qodo.ai

Code Rabbit

対話形式でコードレビューを進められるツールです。専用UIまたは設定ファイルでレビュー内容を柔軟に調整できます。

価格: 開発者1人あたり月額30ドル

docs.coderabbit.ai

Greptile

コードベース全体を読み込み、レビューを行います。

特徴的なのは、レビュアー(人間)のコメントも学習し、使えば使うほどプロジェクトに最適化されていく点です。

Jiraだけでなく、NotionやGoogle Driveのドキュメントを知識ソースとして読み込める点も魅力です。

価格: 開発者1人あたり月額30ドル

www.greptile.com

www.greptile.com

Claude (Anthropic)

AI レビュー専用ツールではありませんが、社内でコーディング支援AIとして利用実績のあるLLM「Claude」でGitHub Actionを使いコードレビューにも活用でき既に導入済みいうことで、比較対象としました。

価格: API利用量に応じた従量課金制

導入と比較評価

比較方法

実際の開発案件を題材に、各ツールを試しました。

題材: 特定の項目をCSVダウンロードする機能の開発

準備1: Jiraに受け入れ条件を詳細に記載

Code Rabbitに明確なチケットの記載例が載っていたのでそれを参考に設定

docs.coderabbit.ai

準備2: 受け入れ条件を意図的に満たさないコミットを一部作成し、AIがそれを指摘できるか検証

評価結果

Qodo Merge

良い点

  • TOMLファイルによる設定の自由度が高く、他のツールより詳細なカスタマイズが可能です。
  • Jira連携の精度が高く、チケットの内容を深く理解した上でのレビューが見られました。

気になる点

  • 他のツールに比べてレビューの指摘事項数が少ない印象です。

tomlファイル設定例

PR上AIツールからの指摘で受け入れた事項は次回以降考慮されます

Qodo Merge PR Jiraチケット分析

Qodo Merge PR 指摘サマリ

Qodo Merge PR 指摘例

Code Rabbit

良い点

  • 他のツールに比べて導入が簡単で、yamlの設定項目もドキュメント見て設定しやすいです。
  • 処理の流れをシーケンス図で自動生成してくれるため、視覚的な理解がしやすいです。

気になる点

  • Jiraチケットの仕様を反映した指摘が少なく、コードの細かな文法チェックが中心でした。

Code Rabbit ウォークスルー

Code Rabbit yamlファイル設定例

Code Rabbit PR指摘例

Greptile

良い点

  • 条件に合致するスタートアップは割引があります。

気になる点

  • レビューのカスタマイズには試行錯誤が必要で、設定項目の参考例が少なかったです。

  • 初期設定からサービスが利用可能になるまでに少し時間がかかりました。

Greptile設定画面

Greptile Context 設定

Greptile PR サマリ

Greptile PR Score

Greptile PR 指摘例

Claude

良い点

  • 指摘の的確さと分かりやすさは、今回試した中で最も優れていました。

  • 正式なJira連携機能はないものの、PRのdescriptionに仕様を書き出すという簡単な工夫で、仕様の考慮漏れなどを的確に指摘できました。

(画像:指摘の例、レビュー総評)

Claude サマリー

Claude PR 指摘例

Claude PR 総評

チーム内での評価

各ツールのレビュー結果をチーム内で比較したところ、「端的かつ仕様の要点を網羅している」として、Claudeのレビューが最も高く評価されました。

まとめ

今回の比較検証を経て、現在の私たちのチームに最もフィットするのはClaudeであるという結論に至りました。

その理由は、指摘の質の高さと、簡単な工夫でドメイン知識を反映させられた柔軟性にあります。重視したドメイン知識を考慮したレビュー」という観点では、ツールごとにアプローチが異なり、今回の検証ではClaudeとQodo Mergeが特に有効でした。

コスト面でも、Claudeの従量課金制は、私たちのチーム状況によって月額固定料金のツールより費用を抑えられる可能性があります。

現状、複雑なロジックの妥当性評価はまだ人間に分がありますが、仕様の考慮漏れを指摘するアシスタントとしては、AIはすでに非常に有用です。

そしてツールを比較する中で、今後AIレビューの質をさらに高めるには、プロジェクトに合わせて「AIを育てていく」という視点が重要だと改めて感じました。

株式会社kikitoriでは、今回の取り組みを足がかりに、今後もAIを活用した業務改善と開発効率の向上に積極的に取り組んでいきます。

(※本記事は2025年7月時点の情報に基づいています。各ツールの最新の価格や機能については、公式サイトをご確認ください。)

React 18 へのアップグレード: 新バージョン非対応の依存ライブラリへの対応

こんにちは。 株式会社 kikitori でエンジニアをしている小川です。

kikitori では JA や卸売市場向けの SaaS「nimaru」を開発しています。

nimaru のフロントエンドは TypeScript + React で構築しており、ローンチから約5年間 React 17 を使用してきました。

このたびようやく React 17 を React 18 にアップグレードしたのでその手順と対応内容をまとめました。

主な対応内容

今回のアップグレード対応は、大きく以下の2点に分かれました。

  • アプリケーションコードの React 18 対応
  • 依存ライブラリの React 18 対応

アプリケーションコードの React 18 対応

React 17 から React 18 への変更内容は内部的な変更が主で、アプリケーションコードが直接影響を受ける変更はそれほど多くありません。

How to Upgrade to React 18

nimaru で対応が必要だったのは以下の3点です。

これらの変更は将来の仕様変更に備えての非推奨化だったので tsceslint による静的解析で検出でき、公式ガイドに沿って対応できました。

※ JSX 名前空間の変更 は React 19 で行われた変更でしたが、React 18.3 でも導入されたため同時に対応しました。

依存ライブラリの React 18 対応

React をアップグレードすると、当然ながら React に依存する各種ライブラリにも影響が出ます。 nimaru で利用しているライブラリのいくつかも React に依存しており、React 18 では不具合が発生したものがありました。

ほとんどの不具合は利用する API を変更するか同等の機能を持つ別のライブラリへの置き換えで解消できましたが、1つだけ代替手段がなく独自に対応する必要がありました。

react-qr-reader

nimaru ではアプリ内の各所でQRコードの読み取りを行っており、そのために react-qr-reader を使用していました。

しかし、React 18 では react-qr-reader で一度カメラを起動するとブラウザをリロードしない限りカメラを停止できないという不具合が発生しました。

react-qr-reader/cant use this library in react@18.2.0

このライブラリは3年以上更新されておらず、公式での修正も期待できない状況でした。幸いMITライセンスで公開されていたため、自分たちで修正を試みることにしました。

まずは GitHub の Issues に解決方法が投稿されていないかを確認しましたが、同様の不具合に関する報告は多数あったものの明確な対処法は見つかりませんでした。

react-qr-reader は、バーコード処理用のライブラリ zxing-js をラップして React コンポーネントとして提供する構成になっており、カメラの制御は主に zxing-js 側で行われています。

そのため zxing-js の Issue を確認したところ以下の投稿を見つけました。

How to stop the reader and turn off the camera

そして このコメント にメディアストリームの停止と video 要素のクリーンアップすることでカメラを停止する方法が投稿されていました。

この処理を react-qr-reader のカメラ停止処理に組み込みます。react-qr-reader では useEffect のクリーンアップ関数でカメラを停止しています。

// from: https://github.com/JodusNodus/react-qr-reader/blob/master/src/QrReader/hooks.ts

export const useQrReader: UseQrReaderHook = ({
  scanDelay: delayBetweenScanAttempts,
  constraints: video,
  onResult,
  videoId,
}) => {
  const controlsRef: MutableRefObject<IScannerControls> = useRef(null);

  ...

  useEffect(() => {
    ...

    return () => {
      controlsRef.current?.stop();
    }
  }, []);

この useEffect のクリーンアップ関数に先ほどの Issue で紹介されていたカメラ停止処理を追加します。 また依存配列も空配列のままだったため依存変数を追加しました。

  useEffect(() => {
    ...

    return () => {
      controlsRef.current?.stop();
+     controlsRef.current = null;
+     BrowserQRCodeReader.releaseAllStreams();
+     const videoElement = document.getElementById(videoId) as HTMLVideoElement;
+     if (videoElement) {
+       BrowserQRCodeReader.cleanVideoSource(videoElement);
+     }
    };
-  }, []);
+  }, [videoId, scanDelay, onResult, constraints]);

この修正により React 18 でも react-qr-reader が正常に動作するようになりました。

React 18 では useEffect の挙動が変更されており、Strict Mode 有効時は開発環境でセットアップとクリーンアップが2回実行されるようになりました。

コンポーネントのマウント時にエフェクトが 2 回実行される

この仕様変更によりクリーンアップ処理が不完全な場合は従来とは異なる挙動になる可能性があるとアナウンスされていました。 react-qr-reader のカメラの停止処理は useEffect のクリーンアップ関数で行われており、今回の不具合もこの仕様変更よるものと考えられます。

振り返って

nimaru で使用しているライブラリは定期的にアップデートしていますが、破壊的変更を含むメジャーバージョンアップはどうしても慎重にならざるを得ず後回しになりがちです。 今回ようやく重い腰を上げて React のアップグレードに取り組みましたがやはり一筋縄ではいきませんでした。

また React 18 への移行は一度にリリースするのではなく、React 17 でも適用可能な変更から少しずつ反映していく方針を取りました。 こうした段階的なリリースにより一度のリリースで発生しうる影響を最小限に抑え、他の機能開発を妨げることなくアップグレードを進められました。 もちろんリリースの分割には手間もかかりましたが、最終的には延べ8,000行以上のコードを変更することになったため結果としては正解だったと思います。