Classi開発者ブログ

教育プラットフォーム「Classi」を開発・運営するチームの開発者ブログです。

レガシーな管理画面のリアーキテクトPJをリブートし、ゴールに導くまでの意思決定

こんにちは、エンジニアの id:kiryuanzu です。

今回の記事は、私のチームが数年の間頓挫していた社内の管理画面の立て直しPJをリブートし、ゴールに導くまでの動き方についてご紹介します。

直近の記事で to_lz1さんによる Claude Code を活用したレガシーコードのリプレース事例について紹介されていました。

tech.classi.jp

本記事もリプレース事例を扱う内容となります。このPJでも Claude Code を駆使して開発を進める場面が多くありました。
ただし、機能群も多く歴史的なシステムだったこともあり、Claude Code を使う以前の場面で一筋縄ではいかない問題があり、システムリプレースは数年間ずっと頓挫し続けていました。
本文では、頓挫し続けてきた理由、そしてそこからゴールへと導くために決めた意思決定と進め方について焦点を置いてお伝えしていきます。

今レガシーシステムのリプレースに取り組んでいる方にとって、リプレースの進め方や判断軸について参考にできる部分がありましたら幸いです。

状況と課題

社内には、Classiの顧客対応を担当するメンバーを中心に利用されているFuelPHP製の社内の顧客管理システムがあります。

このシステムは、2015年からFuelPHPによる開発・運用を続けてきましたが、以下の理由により2021年頃から Rails に全て作り替える方針をチームで決めました。

  • FuelPHPの公式のサポートが事実上止まっている
  • チーム内では Rails でのアプリケーション開発が中心となっており、FuelPHPで新機能の追加・機能改善の敷居が高い状況が続いている*1

この社内システムは学校ごとの受注情報・ユーザー情報の登録やClassiから学校へのお知らせ配信といった、Classiの顧客管理を扱う上で欠かせない機能が集約されたシステムです。
管理システムの要望改善を社内からいただきつつも、FuelPHPでの運用では気軽に改善に手を出すことが難しく、チームで慣れているRailsでの開発に移行するという方針に至りました。

並行して、自チームではエンドユーザー(先生・生徒・保護者)向けのサービスの開発・運用も行っています。
エンドユーザーを中心とする顧客価値への貢献もチーム内でとても優先度の高い取り組みとなります。
そのため、そちらのサービスの改善の案件が持ち上がりそちらにメンバーを集中させることになると、社内システムのタスクは優先度を落とさざるをえません。
上記の背景によりタスクを担当するメンバーの入れ替わりが続き、一人以上のメンバーでまとまった期間で着手できず開発がストップする時期を繰り返しました。

ただ、今年度からは組織統合もあり Classi の管理システムを触る社内メンバーはさらに増えていくことになります。
その流れで、利用ユーザーからの改善要望がさらに求められることは大いに予想され、機能改善をよりスムーズに進められることが組織のメンバーへの価値貢献に繋がるのではないかとチームで再認識しました。

そういった経緯を踏まえ、エンドユーザ向けのサービス改善も継続しつつ、社内システムのリプレースを完遂せねばならないとチームで判断しました。
リプレースPJの完遂に向け現状と今後の方針の見直しを行い、定めた方針に即して開発に着手し無事期日までに最終的にはゴールに到達することができました。

ゴールに到達するまで我々はどういった意思決定を経てきたのか、ここからお話していきます。

リプレースを完遂させるための意思決定

課題を再認識し、ゴールを切り分ける

当初の計画 今回のPJの開始にあたって、当初は「Railsの全面リプレースによって対象のシステムが抱える課題を一括で解消する」という狙いがありました。

具体的には、以下の課題を完遂することをゴールとし、そのためには FuelPHP をなくして全機能を置き換えることが必須であると違和感なく受け入れていました。

  • コンテナイメージ・フレームワークなどのEOL対応
    • サポート終了する amazon linux2 や PHP 7.2、FuelPHP など、現状の技術スタック全体を全て置き換える
  • 利用者が望むシステム改善
    • 現場の顧客対応メンバーから上がっていた社内システムの機能改善や、業務効率化の要望への対応

しかし、EOLの期限を意識してスケジュールを計画する場合、社内システムの全ての機能を期日までに一つずつ置き換えるのはかなりタイトかつ現実的に難しいものに見えました。

元々計画されていたリプレースPJの趣旨には、EOL対応以外にも「社内システムの改善を容易に行えるようにすること」も含まれています。むしろ、顧客価値の貢献を意識するならば、こちらの趣旨が確実に達成されることが今後の動きとして大事であると言えます。

たとえEOL対応の期限に急いで開発を遂行させたとしても、今後の運用を意識したコードの品質を担保する余裕が維持できるのか懐疑的でした。

意思決定後のアプローチ

上記の背景を踏まえた結果、以下のようにEOL対応とリプレースのゴールを切り分けて進めることにしました。

  • EOL対応は現状の技術スタックでアップデートを実施し、まずはこちらを最優先で終わらせる
    • 具体的には以下のアップデート作業を実施(作業の具体的な内容は本記事では割愛します)
      • サポート終了する amazon linux2 イメージ → PHP公式イメージへの置き換え
      • PHP7.2 → PHP 8.x系のアップデート
    • まずはEOL対応を終わらせることで、EOLの期日を意識せずにリプレースPJの開発スケジュールを敷くことが可能となる
  • 今回のリプレースPJの趣旨は「社内システムの継続的な改善を可能とする」のみとする
    • まずはユーザーの利用頻度の高い画面を抽出したリプレース完遂を本PJのゴールとする
    • 本PJ完遂後、別PJ扱いとして今回対象外とした画面を含む移行を実施しフレームワーク単位での移行を完遂させる

小さな機能であれば最初からフレームワーク単位のリプレースを計画し、EOL対応もまとめて解決する方針も現実的ではあったと思います。
しかし、複数の機能が連なった規模の大きいシステムのリプレースをタイトなスケジュールで実施するのはコードの品質を意識する以上、困難であると判断しました。

そこで、まずはClassiとしてクリアしたいと考えるEOL対応を先に終わらせることによって、リプレースPJの遂行に際してEOL対応で迫られる期日のことは考慮しなくて良いようにしました。
そのおかげで、余裕をもってリプレースを進める段取りとスケジュールを準備することができました。

その後、本PJではリプレースのゴールの見直しを行い、まずはリプレースを通して「社内システムの継続的な改善を可能とする」のみに絞り込むようにしました。
これらの判断をもって、具体的にどのように着手を進めたかどうかについて次にお話しします。

リプレース対象の画面を絞り込む

前章では抱えている課題を切り分け、まずは目先で優先すべきタスクだったEOL対応のためのアップデート作業を完遂させました。

そこから、リプレースPJの完遂に向けて今までの状況を見直し、今見据えるべきゴールは「社内システムの継続的な改善を可能とする」ことであると認識し、着手対象を絞り込むことを決めました。

当初は前述のように本PJの完了条件は「FuelPHPをやめるために全ての画面を置き換える」と定めていました。

しかし、「社内システムの継続的な改善を可能とする」ことを目的と掲げるならば、一律で全ての画面の置き換えるのではなく「ユーザーが今頻繁に使っている画面を優先して置き換える」ことにフォーカスした開発が現実的なアプローチではないかとチームで認識を改めました。

よって、以下の二つの軸を元にユーザーに影響がある画面を絞り込んで着手する対象を確定させるようにしました。

  • ユーザーにとって必須機能であるかどうか
    • 管理機能でしか操作・閲覧できないデータがあるかどうか調査
  • ユーザーが頻繁に使う・今後使われる可能性が高い機能であること
    • 顧客対応などを中心に行うメンバーにヒアリングを実施し、利用頻度の高い機能・それらの改善要望の情報収集

中には、機能クローズによって今後使われないことが確定した管理機能や、サービスの運用の都合上もう使われていない機能もありました。
開発着手前に優先度の低い機能を洗い出すことで、必要なものだけに絞り込むのは開発コストを下げるために重要な作業だったと認識しています。

対象画面の絞り込みを行った後、実際に開発に着手する上での段取りを計画しました。

フェーズ単位で対象画面と担当者を振り分ける

画面の優先度・そこに画面の着手難易度も加味し、フェーズを3つに分けて対象画面を振り分けました。
以下の表にあるフェーズ2の完遂をもって、今回の目的となる「社内システムの継続的な改善を可能とする」ラインまで到達できるように計画しました。

フェーズ1

  • 難易度が低~中の不確実性がない参照系画面 → 更新系画面
    • 最低限ユーザーに使われる機能であること
    • ユーザーリスクの低い参照系・更新系機能が中心
  • 利用頻度が高く、難易度の高い更新系画面
    • フェーズ2も継続して固定のメンバーに開発を担当してもらう

フェーズ2

  • 中難易度の更新系画面
    • フェーズ1の高難易度画面よりは難しくないが、社外サービスへの影響があり、より複雑なドメイン知識が求められる
  • 低難易度の参照系画面
    • 新しくジョインした新卒メンバーのオンボーディングタスクとして扱う

フェーズ3

  • 難易度関係なく、優先度がかなり低い画面
    • サービスの運用上ほぼ使われない機能や・改善要望が発生しにくい画面
    • これらはPJ内に終わらせる必要はなし
      • 今後予定するフレームワーク単位での移行PJ発足に合わせて対応する

上記のフェーズごとに着手対象の画面を振り分け、チーム内の2〜3名のエンジニアで担当画面をそれぞれ持ってリプレース移行対応を進めました。

優先度を整理し対象画面の振り分けをしたことで、チーム内で並走してPJの進捗を共有し開発に向き合う環境を整えることができました。

例えば、途中からPJに参画したメンバーがこれらの振り分けを元にすることで、「どこから着手すればよいかわからない」といった認知負荷を抱えることなく、担当がまだ置かれていない画面を振り分けて進めてもらいました。
他にも、新しくチームにジョインした新卒メンバーに管理画面のリプレースを通して Classiのサービスの仕様理解を深めてもらう目的で難易度の低い画面を担当してもらう取り組みも実施しました。

計画の旗振り役をした筆者がチームのタスクの都合上一時的にこのPJから離れる時期もありました。その間も、他メンバーがPJ内のタスクの優先度を把握し予定通りリプレース作業を継続することができました。

今までは、主要の開発メンバーが一度PJから離れるとキャッチアップが難しくなり頓挫してしまうのを繰り返していましたが、今回はチーム全体でリプレース対象画面の優先度を把握できるようにし、ゴールを見据える状況を作り出すことに成功しました。
これらの取り組みによって、PJを頓挫させずに無事期日までにフェーズ2のリプレースまで完遂させることができました。

まとめ

今回のPJを進めた上で意識したこととして、主に以下の2点があります。

より効率的かつ現実的なアプローチを探り続けること

当初は、全ての画面の移行をゴールとして定めていましたが、今のチームのキャパシティを鑑みると「それらを最初のゴールとして扱うことは難しいのでは?」という状況が見えてきました。
そこから課題を整理し、今求められているものだけを抽出してゴールを再定義し完遂させることができました。

ただし、いま最小限の画面で使っているFuelPHPを残し続けるのは今後のEOL対応を意識するといずれは取り除きたい現状があります。
そのためには、ここからまたチームのスケジュールに合わせて新しいリプレースPJを策定し完全な移行を目指す必要があります。
ただ、今回のリプレースの趣旨だった「社内システムの継続的な改善を可能とする」目的は達成されたので、対象画面は今までよりかなり絞られ、現実的なスケジュールを敷くことが可能になりました。
このようにして、今求められている状況を把握して現実的なアプローチを定め、効率的な進め方を模索することが中長期的なPJで必要な動きだと捉えるようになりました。

腕力だけで解決しないやり方を見つけ出すこと

今回のリプレース移行ですが、たとえ膨大な作業量であっても人によっては Claude Codeによる開発支援を駆使して一人でとにかく勢いをかけて進めるといった選択肢も可能だったかもしれません。
ただ、開発を進めていく上では、社内システムのドメイン知識をはじめとしたプロダクトの知見・サービス開発の知識がやはり必要となります。
一人で進められたとしても、今までの頓挫した背景のように外部的な要因で集中して開発することが困難になることも大いに予想できます。

それらを踏まえると、一人の腕力に依存せずにチームで継続して連携するといったアプローチも今回のゴールに到達する上で確実に必要な動きであったと考えています。

おわりに

はじめて中長期的なPJの旗振り役を担ってみて、PJを頓挫させずに進める動き方について改めて考えさせられる機会となりました。
これらの経験を通して今後の課題でも活用できる意思決定のやり方を学べたように思います。

もし今、中長期的な課題やレガシーシステムのリプレースに向き合う方にとって、参考になる振る舞い・考え方の一助となりましたら幸いです。

次回予告: 開発面での取り組みについて

今回のPJでは、サービス開発を最小限のコストで進めるために、チーム内のRailsアプリケーション開発のコーディング方針を策定する取り組みや、将来的にHotwire導入を検討しチーム内でHotwireのインプット会を企画するなど、開発面でのアプローチも複数実施しました。

今回はリプレースを終わらせるための意思決定についての話が中心となるため割愛としましたが、これらの具体的な対応例についてもまた別の機会で紹介できたらと考えています。

*1:https://github.com/fuel/core/tree/1.8/master 最終の stable バージョンである 1.8.2 は2019年以降リリースされておらず、正式なリリース情報が出ていない

生徒の継続的な学習を支援する新機能「学トレAIコーチ」におけるプロダクト開発の紹介

はじめに

こんにちは、学習トレーニング開発エンジニアの工藤 id:irisuinwl です。最近は加水フォカッチャ作りがマイブームです。

さて、先日学習トレーニングの新機能である「学トレAIコーチ」をリリースしました。
本機能は、生徒自身が学習目標を設定し、AIと伴走しながら継続的な学習を支援する機能となっております。
詳しくは機能紹介動画と紹介ページをぜひご覧になってください!

機能紹介動画:

www.youtube.com

機能紹介ページ: 手軽に個別最適な学習継続を促す-学トレAIコーチ – チエノワ

さて、本記事では「学トレAIコーチ」の企画から開発、リリースまでに参画してきた筆者が開発の上でどのような工夫を行い、上手くいった点、障壁となったかを紹介いたします。

リリースまでの大まかな流れ

本機能の企画スタートからリリースするまでに辿ったプロセスは以下になります

  • 企画立案・価値探索(2024年~2025年9月)
    • 市場調査、ユーザーヒアリングなどを通して、企画のコア・バリューを定めて、ユーザーにとって価値あるプロダクトとは何かを検討
    • 期間が長いように思えますが、2024年はほぼPoCで、本格的なヒアリングと仮説検証は2025年から開始
    • 企画から仕様検討、開発に着手するために必要な情報(企画のWhy、What)を決定してFIXする
    • 今回の場合、2つの機能を段階的リリースする方針で進めることとした
  • 機能開発① 生徒が自分の取り組みを把握する機能の仕様検討、開発、リリース (2025年10月~2025年12月)
  • 機能開発② 生徒が自分で設定した目標を学習する機能の仕様検討、開発、リリース (2025/12月 ~ 2026年4月)
    • 企画でどんなことを提供したいかを元に、どのようなものを作れば良いのかを明らかにする
    • この機能は実現するシナリオが多かったので動くプロトタイプを元に仕様やデザインを詰めつつ実装できる部分から進める「プロトタイプ駆動」開発を行った

以下では各フェーズでどのようなことを行い、作りたいアイデアから実現に至るまでのプロセスを解説します。

企画立案・価値探索

課題仮説、ソリューション仮説の設定

このフェーズではどんなものを開発することがユーザーの価値に繋がるかを考え、プロトタイプの作成、インタビューによって仮説検証を行いました。

具体的には、既存のプロダクトの課題を考え、ユーザー(生徒)は「学習を始めたい意思はあるものの、継続できず困っている」という課題に焦点を当てて、どのような体験を提供するかのループ図を作成しました。

提供したい体験のループ

そこから、企画のWhyとWhatにあたる「どんなユーザーが何に困っていて、どのような状態になっていると嬉しいのか」を明らかにするために、ユーザーのペルソナを考えて、提供したい体験を実現するためのバリュープロポジションを作成して、課題仮説の解像度を高めました。

ペルソナ

バリュープロポジションキャンパス

インタビューによる課題仮説の検証

続いて、設定した課題仮説が妥当なものなのかをチェックするために、プロトタイプを用いたユーザーインタビューを行いました。

インタビューで用いたプロトタイプ

インタビューする前に1~2週間ほどプロトタイプアプリケーションをユーザーに使用していただきました。

インタビューの目的は、自分たちが考えた仮説が正しいのか、正しくなければどこにギャップがあるのかを検証することです。それを達成するためにインタビュー項目を設計しました。

インタビュー項目として例えば以下のようになります:

  • 「勉強をする際、自分のための勉強だとわかっているが、やる気がでなかったり興味のあることが優先になってしまい、継続的に勉強することができないことに困っていますか?」
    • 意図: 課題仮説である「自分のための勉強だとわかっているが、勉強を始められず、継続的に勉強することができないことに困っている」という点を聞く
  • 上記質問を解決する「意思の力にたよらず、コンスタントに勉強ができるような仕組み」があるとすれば、使いたいですか?
    • 意図: 解決を求めているか、ソリューションへのイメージを聞く。また、プロトタイプを使っていただいたことで具体的なソリューションのイメージが生徒の課題にフィットしているかをヒアリングする。

インタビュー実施 → フィードバックから仮説の修正 → インタビュー実施という仮説検証サイクルを回してブラッシュアップしていきました。

結果として、プロトタイプを通してユーザーに我々のイメージを伝えやすくなり円滑にインタビューをすることができました。そして、5回以上のインタビューを通して以下のような仮説と体験設計を作ることができました。

このタイムラインから作るべき機能のコア・バリューとして

  • 自分で目の前の学習目標を作る
    • 目標設定することで、自分自身の力で学習しようと思ってもらう
  • 自分で設定した目標を学習する
    • この​勉強を​すると​成績が​上がると​思って​もらう​
    • 自身が​勉強に​費やせる​時間を​知って​もらい、​その​時間に​合わせた​勉強内容を​Classiが​提示する
    • 「今日やるべきこと​(生徒が​設定した​方​針に​基づいた​勉強内容)」を​Classiが​提示する​
  • 自分の取り組みを把握する
    • 行動の​積み重ねから、​学力の​向上を​自覚できるように​成果を​提示する​

という2つの機能を段階的に作っていくことを決定しました。

開発フェーズ

自分で設定した目標を学習する」機能の開発フェーズでは従来のデザインカンプ先行型のフローを見直し、以下の手順で開発しました。

  • プロトタイプアプリケーションでデザインの骨格を決定
  • プロトタイプから作るべき機能と要件を決定し、見積もる
  • 開発と詳細なデザイン作成を並行する
  • 作成した機能のQA
  • 機能リリース

今回行ったプロトタイプ駆動な開発方法で上手くいった点、工夫した点を紹介します。

要件定義の時間短縮

今回は作成する機能が多かったため、要件定義にプロトタイプを用いて開発に必要な部分のみ決めて、すぐに開発と詳細なデザインを行う形で進めました。
今までデザイン決定と要件定義を同時に行っていた部分をプロトタイプによって骨格を作ることで短縮できました。
従来では1か月程度掛かっていたものが2週間程度で済み、すぐに開発に入ることができました。
結果として、要件定義・見積もりフェーズを半分程度短縮することに成功しました。

プロトタイプ画面と実際に開発した画面を比較しておおまかなデザインの骨格は変わらないことを見てみます。

トップ画面(プロトタイプ)
トップ画面(Classi)

ミッション詳細画面(プロトタイプ)
ミッション詳細画面(Classi)

デイリーミッション完了画面(プロトタイプ)
デイリーミッション完了画面(Classi)

デザインやしっかりとした仕様が決まってないプロトタイプを見ながら議論をすすめることで、我々がアプリケーションで達成すべきことは何かという最低限の目線合わせを行いました。その結果、デザインの詳細や実装における詳細はデザイナー、エンジニアが開発していく中で決定していく動きをとることができました。
そして、問題なくリリースを完了することができました。

コンポーネント単位のUIデザインと開発の橋渡しとなったstorybook

プロトタイプを用いて大まかなデザインを決めて開発と詳細なデザインを作っていくうえで、今回のAIコーチでは画面設計とUIパーツ作成を並行して着手しました。

そこで、デザインと開発の連携を円滑にするために、storybookを導入することでデザインコンポーネントレベルで開発・レビュー・テストを可能としました。

storybookとは、UIコンポーネント(ボタンやフォームなど)をカタログのように表示し、画面単体で開発・テストできる無料のOSSです。

storybook.js.org

プロトタイプによるデザインとstorybookを導入した結果として、開発とデザインが独立に動くことに成功して、差し替えも問題なく実装できました。

何が決まっていて何が決まっていないかを明らかにする

プロトタイプによって大まかなデザインは決まっている一方で、開発に必要な情報全てが詳細には決まっていないため、「何を後々詳細に決める必要があるか」、「どこまで実装を進めるか」というところはチームで共通の意識を持ちながら開発を進めていきました。
プランニングなどのスクラムイベントを通して今回作る上で必要なチームの共通意識を持つようにしました。

要件や作りたいもの、デザインの大枠は決まっているものの、開発を進めていく上で、不明瞭な仕様が明らかになる局面もありました。
その際は定例やデイリースクラムなどのイベントや、日頃のslackでのメッセージで都度明らかにしていくことをしていきました。

以前のプロジェクトと比較して、密なコミュニケーションとチーム全体での計画意識が求められたと感じますが、それらはチームイベントやコミュニケーションが十分できていれば問題なく機能するものだと捉えています。

チームが機能し、作りたいプロダクトに意識が向いているというシンプルなことですが、成功させるために最も大切な部分だと私は考えています。

まとめ

  • 新機能「学トレAIコーチ」機能において、価値探索から開発まで一気通貫で携わり、それまでのプロセスを紹介しました。
  • プロトタイプアプリケーションをインタビューと開発の中で用いました。
    • 実際に動いているものを見ることでインタビューでの意思疎通しやすさ、開発を進める上でのチームの共通理解を得やすいという利点がありました。
  • 開発の中でプロトタイプを用いて開発とデザインを並行して行いました。
    • その際に何が決定的で何が検討中かを意識、コミュニケーションしながらチームで動くことが開発を成功するうえで大切な要素だと感じました。

AIへ丸投げした結果、失敗した話

 こんにちは。学習・コミュニケーションプラットフォーム課でデータエンジニアをしている nekobits です。私が所属している課では主にClassiのデータ基盤の運用・開発を行っており、営業や企画の方からの質問に答える社内AIも開発しています。「Classi活用レポート生成AI」の機能改善においてコーディング用のAIを利用していた際に起きた出来事を時系列で振り返ります。これから自律型コーディングAIを活用しようとしている方や、すでに沼にハマった経験があるエンジニアの方にとって、少しでも参考になれば幸いです。

概要

 「Classi活用レポート生成AI」(参考: 「あえてSQLは書かせない」営業現場で“そのままでも使える“レポート生成AI Agentの紹介 以下、レポート生成AI)はご契約いただいている学校の活用状況を、グラフやAIによる分析を交えてドキュメント化するツールです。当初は2025年度のみへの対応を行っていました。そのため、新年度に対応するべく「レポートの集計期間を可変(動的)にする」という改修を行うことになりました。

 一見すると、日付選択UIの追加と内部処理の軽微な変更だけで済む単純なタスクに思えました。そのため、私はClaude Codeに指示を丸投げし、並行して他の業務を進めていました。その結果、数週間を浪費した末にPull Request(以下、PR)をクローズすることになりました。本稿はこの苦い経験から得た教訓の記録になります。

どう失敗したか

1. 「Issueのタイトル」だけで簡単だと思い込み、AIに雑な指示を出した

 Issueのタイトルと概要をパッと見ただけで「少しの変更で実現可能」と判断し、内部実装やコードベースを深く読み解かないまま、Claude Codeに対して、「集計期間を可変にしておいてください」と1行の雑な指示を出して丸投げしました。

2. 出力された結果を見ると間違えていた

 Claude Codeが出力した結果を確認すると、以下のような一見動いているが実は間違えているという厄介な状態になっていました。

  • データ/グラフ:指定した期間で正しく集計されて出力されている(Pythonコードや簡単なクエリの修正は成功)箇所もあるが、特定の条件下ではデータが0件や間違った値で表示されている箇所も存在した
  • AIの日本語要約:レポート生成AIがデータを解釈して出力する考察テキストが、指定期間外のデータまで参照・指摘していた

3. 部分的には合っていたので続きを直すようにと指示

 一部は正しく動いていたため、「AI側のちょっとした勘違いだろう」「レポート生成AIのプロンプトを少し調整することで直るはず」と考えた私は、根本的なコード上の原因を調べないまま、再びClaude Codeに「ここを直して」と雑な追加指示を出してしまいました。

4. 力任せで解決しようとするも一向に改善せず

 あと一歩で直るように見えていたのですが、修正依頼をすれば他の箇所がおかしくなり始め、修正依頼を重ねれば重ねるほど、コードは複雑化し、解決しないまま時間だけが過ぎていきました。「モデル性能が悪いのか?」とも思い、Opus4.7などのハイエンドモデルに切り替えて試してみるものの、状況は一向に改善しませんでした。

5. 自分でコードを読み、チームで相談

 AIに依頼しても一向に直る気配がないどころか出力結果がどんどん怪しい結果になってきたため、自分でコードベースをじっくり読むことにしました。そこで初めてAIがハマっていた理由がわかりました。
 それはバグ修正で詰まっていたのではなく、どういうビジネスロジックにするべきかという取捨選択の必要な箇所がいくつか存在するコードだったのです。具体的には、学校プロダクト固有の年度を跨いだ学年やクラスの同一性の取り扱い(年度を跨ぐと名称は同じだが中身は別になってしまう問題)や、データ上の「年」が学校現場の「年度」として扱えているのかなど、ドメイン知識を要するハイコンテキストな問題が存在しました。これはコードを見るだけでは判断できないのと、私一人だけで決められることではなかったためチームで相談することにしました。

6. PRクローズ

 チームで議論した結果、この改修は利用者である営業や企画の方に意見を求めたほうが良いとわかり、直近で利用者に対してインタビューする機会が控えていたため、最終的にこのPRは一旦クローズすることにしました。
 もし、最初から内部の仕様を理解していたのなら、取捨選択が必要な場面で相談を早めに持ち込むことができていたはずでした。

反省点

  • 内部仕様を自分で把握することを怠ったため、AIに対して具体的な指示を出すことができず、AIに迷いを生じさせてしまいました
  • 並行して作業していたため、このPRの実働時間自体は短かったかもしれません。しかし、専念することがなかったため、ずるずると日数だけが伸びてしまいました
  • 進捗確認の際に、「ここまではできています」とは伝えられるものの、「どこまでできていないのか」「どこで迷っているのか」を言語化できず、チームへの相談が遅れてしまいました
  • 私自身がドメイン知識不足だったとも思っています。AIがこのあたりのドメイン知識やビジネスロジックも補完してくれるだろうと淡い期待をしてしまっており、AIの設計判断をそのまま受け入れたことも泥沼化した原因だと感じています
  • 簡単だろうと推察したは良いものの、その思い込みと、あと一歩で直るだろうという執着によって異変を感じたときに引き返すことができませんでした

得られた教訓

  1. 正しい判断のために、まず人間が既存コードを把握する
     AIが出力したコードが正しいのかを評価するには、人間側がシステムの内部構造や事業が扱うドメイン、または提供するソフトウェアの扱うデータ特性やライフサイクルを理解しておく必要があると感じました。AIにコードを書かせる前に既存のコード、データ構造、アーキテクチャを最低限把握しておくべきだと痛感しました。
  2. 設計判断は人間が握り、コード化をAIに任せる
     仕様上での取捨選択など、ドメイン知識が必要な意思決定は人間が行う必要があります。全てのコンテキストを渡すことができれば設計判断も任せることが出来るかも知れませんが、現状は難しいため、分業が大切だと感じました。『Backbone.js画面をAngularへ。Claude Codeと挑んだレガシー移行』 にもあるように「型定義やデータマッピングはまず丸投げして損はない」とのことなのでAIの得意領域も把握することも大切です。

おわりに

 今回は「AIへの丸投げ」で数週間を浪費し、結果的にPRをクローズするという苦い経験をしましたが、ツールが悪いのではなく、利用する人間の利用方法が重要だと学ぶことができました。今後はまず、必要に応じて仕様把握をAIといっしょに行い、設計判断は人間が、コーディングはAIに任せながら実装していくといった適切な分業スタイルで開発を進めていきたいと思います。
 今回の失敗談が、これから自律的コーディングAIを活用しようとしているどなたかの参考になれば幸いです。

Backbone.js画面をAngularへ。Claude Codeと挑んだレガシー移行

こんにちは、エンジニアの鳥山(to_lz1)です。

皆さま、AIを用いた開発は快適に行えていますでしょうか?Claude Code, Cursorなどなど多様なツールが現れ、「開発にAIを取り入れる」ということはもはや当たり前になってきていますが、その具体的な使い方となるとまだ模索しているチームも多いのではないでしょうか。

最近、我々の開発するClassiに残っていたレガシーコードを駆逐したのですが、その過程でClaude Codeが大いに役立ってくれました。今回はその事例を紹介するとともに、その過程で工夫したことや考えたことをお伝えしていきたいと思います。「AIやLLMは古いライブラリからの移行やリアーキテクチャに向いている」といった言説はしばしば聞きますが、その具体的な事例はまだそれほど充実していないように思います。今回の話が少しでもご参考になれば幸いです。

  • 発端
  • Claude Codeと働く上で、良かったと思う考え方・Tips
    • 型定義やデータマッピングはまず丸投げして損はない
    • 「良いお手本は何か」を真っ先に学び取る
    • なんだかんだ言っても品質保証(QA)は要る
    • 「移行」なら現仕様が維持できてれば良いのでは?
  • 結果と総括
続きを読む

twadaさんによるTDDワークショップ2026を開催しました!

はじめに

Classiでは5年ぶり2度目となるTDDワークショップを『テスト駆動開発』の翻訳者として知られる t_wada さんこと和田卓人さんにオンラインで開催していただいたので、その様子をお伝えします。
前回の記事はこちらになります! ​​

tech.classi.jp

概要

ワークショップは午前と午後の2部制で午前中は講義、午後にはTDD実践という流れで1日をまるまる使って実施していただきました。

午前の講義では、「AIとの協業を支える自動テスト」をテーマにAIとの向き合い方やAIと開発をするうえでのテストの立ち位置についての講義を行っていただきました。

午後からはAIを使わず、TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング - YouTubeや講義で出てきたTDD例を参考に「整数の閉区間」というお題で4つのレベルの中から選んでTDDを実践し、t_wadaさんにレビューをしていただきました。TDDを行う中で参考にしたのが以下になります。(参考: 【翻訳】テスト駆動開発の定義 - t-wadaのブログ])

  1. 網羅したいテストシナリオのリスト(テストリスト)を書く

  2. テストリストの中から「ひとつだけ」選び出し、実際に、具体的で、実行可能なテストコードに翻訳し、テストが失敗することを確認する

  3. プロダクトコードを変更し、いま書いたテスト(と、それまでに書いたすべてのテスト)を成功させる(その過程で気づいたことはテストリストに追加する)
  4. 必要に応じてリファクタリングを行い、実装の設計を改善する
  5. テストリストが空になるまでステップ2に戻って繰り返す

参加した人の感想

いもり
エンジニアに求められるのは「やりたいことを正確に言語化・設計する力」だと再認識できた1日でした。
午前の講義で特に印象深かったのは「AIとの伴走パターン」のテンプレートです。事前に設計書を作成・レビューしてから実装させる手法は、その後のコーディング精度を劇的に向上させると感じ、普段の開発にもすぐに取り入れられた内容でした。
午後のワークショップではTDDに初挑戦しましたが、最初のリスト作成以上に、開発サイクルの中での「TODOリストの軌道修正」に苦戦しました。原因としてはリスト単位の機能実装に集中するあまり、全体像を見失ってしまった点にあります。部分と全体を行き来し、時には柔軟に設計方針を見直す視点こそが、開発を行う上での重要なスキルなのだと痛感しました。

kanapiii22 ( id:kanapiiii )
今回のTDDワークショップで特に印象に残ったのは、「テストはコードで書く仕様書である」という言葉でした。これまでの私は、RSpecを「実装したコードが意図通りに動いているかを確認するためのもの」として書いており、テストは実装の後追いになっていました。しかし、事前動画やワークショップを通して、使用や振る舞いを先に言語化し、それをテストとして表現するという体験をし、テストそのものが仕様書の役割を果たす感覚をつかむことができました。
将来このコードを読むチームメイトが、テストを読むことで使用を理解できるようにするためにも、今回ワークショップでつかんだ「テストをドキュメントとして書く」という感覚を忘れず、チームに戻ってからも振る舞いを表現にするテストを書くことを意識していきたいと思います。

akinko
本講義を通じ、AI時代におけるエンジニアの真価は「知識に基づいたディレクション能力」にあると再認識しました。直感的な「Vibe Coding」に留まるのではなく、専門知識を駆使してAIを自律的に制御する「Agentic Coding」へと昇華させることが、プロのエンジニアには不可欠であると身が引き締まる思いになりました。
午後のワークショップでは、テストリストの作成を通じて自身の設計スキルの現在地を痛感しました。実装前に設計を言語化し、思考の解像度を高めることが、成果物の品質を左右するのだと改めて学びました。今回の気づきを糧に、より一層スキルアップに励みたいと思います。

すずまさ
受講前は、TDDの概要こそ知っていたものの「一気に実装してからテストを書く方が効率的に書けるのではないか」と考え、実践したことはありませんでした。
しかし、今回TDDを体験したことで、むしろ実装が複雑なものほど全体的なスピードが上がりそうだと感じました。

ワークショップでは小さめのお題を対象に取り組みましたが、当初作成していたTODOリストは次々と更新され、最終的には2倍近い数の項目になっていました。
実際の業務でも、TODOに漏れが見つかり想定より時間がかかることはよく経験しているので、Red→Green→Refactorのサイクルを小さく回すことで素早く漏れに気づけるのはTDDの強みだと感じました。
また、小さくステップを刻むことで、複雑な仕様でどこから着手していけばよいかわからない場合も、設計を練りながら「とりあえず書いてみる」ことができるのも魅力的でした。

AIとどう協働していくかの話も含めて、明日から実践できる学びを多く得られたので早速取り入れていきたいと思います!

しらたき
講義の中で言及されていた「AIと作業するときは細かく指示するより、広く使われているテクニックを一言伝える方が正確」という教えは、目から鱗でした。 デザインパターンなどの標準的な語彙を学ぶことは、単なる実装技術の向上以上に、AIとのコミュニケーションコストを下げるために不可欠だと痛感しました。
また、私がやっていたのは「Vibe Coding」であり、「Agentic Coding」ができていなかったなと気づきにもなりました。
データエンジニアリングの領域でも、標準的なアーキテクチャやパターンを意識的に取り入れ、AIと共通言語で対話できるスキルを磨いていきたいです。

マイン
午前中はAIと開発についての話でした。いろいろな新しいキーワードが出てきて、とても面白かったです。AIが進化しても、人間がテストを書いて「何が正しいか」を決めることが大切だとわかり、勉強になりました。

午後は実際にTDDを体験しました。テストを先に書くやり方は初めてでしたが、少しずつコードを作る感覚がよくわかりました。今まではテストを「最後にするもの」と思っていましたが、これからは「作りながら考えるための道具」として使っていきたいです。

とても役に立つワークショップでした。明日からの仕事でも頑張って使ってみます。

いしかわ
テスト駆動開発を理論だけで終わらせず、手を動かして学べたのは大きな収穫でした。 特に印象的だったのは、オープンな場でのコードレビューです。自分ひとりの視点だと気づけない「詰まりどころ」や、それに対する回答を周りと共有できたことで、学びの解像度がぐっと上がりました。

また、AIコーディングの難しさについても改めて実感しています。ハルシネーション以上に「AIが自分に合わせすぎてしまう(イエスマン化)」(シコファンシー)の方が意外と厄介だなと感じています。AIは自分の考えを肯定して増幅させるツールだからこそ、流されないように主導権を持って使っていきたいです。

アイン
今回のTDDワークショップを通して、開発における「考える順番」の重要性を改めて実感しました。特に印象的だったのは、テストを書くことで「何を作るべきか」「何が正しい振る舞いか」を先に決められる点です。

午後のワークでは、TODOリストを何度も見直しながら進める難しさと同時に、その過程自体が設計を洗練させていくことを体験できました。
また、AIを使った開発においても、人が設計と判断を担う重要性を強く感じました。今後からの開発でも、小さなサイクルで考え、確認し、改善する姿勢を大切にしていきたいです。

daichi ( id:da1chi24 )
普段サービス開発をしていると「ユーザー視点で考えろ」と言われます。これはUIに限った話ではなく、インターフェース設計やアーキテクチャにも通じる考え方です。今回の研修を通じて、テスト駆動開発とは「実装するメソッドを利用者としてどう使いたいか」から設計を考えるプロセスであり、Red / Green / Refactor の手順を行う中で自然と利用者視点の設計になる手法だと腹落ちしました。これは大きな学びでした。

研修全体を通して、テスト駆動開発だけでなく、エンジニアリングの歴史やAIとの向き合い方、t_wadaさんご自身の学習の姿勢に至るまで、幅広い内容に触れられました。知識として理解するだけではなく、リアルタイムに質疑しながら学べたことは研修ならではの価値だったと思います。一流のエンジニアの思考に触れて、刺激になりました。ありがとうございました。

ねこびっと
TDDワークショップの中で一番手が止まってしまったのは、最初のリストを作るフェーズでした。その原因は全体から詳細までを決めてからテストを書き始める必要があるからだと思い込んでしまっていたためです。ですが、ワークショップやレビューを通して、TDDにおいてリストは途中で変更をしても良いものであり、さらにはテストコードまでも状況によっては変更をしても良いという柔軟性のあるものであることを学ぶことができました。
開発、設計におけるプロセスは成果物では体験しづらいので、ワークショップを通してTDDにおける試行錯誤のプロセスを体験できたのは非常に良かったです。今回得られた感覚を大切にして日々の開発に活かしていきたいと思います。

開催の背景

lacolaco ( id:lacolaco )
プラットフォーム部のlacolacoです。Classiでは2020年に一度t_wadaさんのTDDワークショップを開催し、参加者からは非常に好評でしたので、またお呼びしたいとずっと思っていました。2025年は、社内でも生成AIを使ったAgentic Codingの導入も本格的になり、コードを読み書きする仕事の形や意味が変わっていく時期でした。特に、新卒エンジニアにとっては生成AIと共に行う業務が最初の経験になります。開発のスピードがどんどん加速する状況の中で、ソフトウェアの開発をいかに安心できる、地に足ついたものにするかということは、これまで以上に深刻な課題になっていると感じていました。そこで、いまこそテスト駆動開発の考え方が必要だと思い、t_wadaさんにお声がけをしました。とてもいいタイミングで実施できたと思います。

おわりに

今回、研修を行っていただいた t_wada さんに改めてこの場で感謝申し上げます。講義中、コードレビューの際にSlack上や口頭での質問に一つ一つ丁寧に答えていただいたため、TDDにとどまらず、AIとの協業についてや設計、開発における考え方を得ることができたと思います。TDDワークショップを通して得られた知見を今後の開発に活かしていきたいと考えています。ありがとうございました!

Classiエンジニアの「OSSやっていきの集い」 〜活動1年を経て得られたプロセスによる学び〜

こんにちは、id:da1chi24 です。

Classi では、チーム横断でOSS活動に取り組む「OSSやっていきの集い」を行っています。早いもので活動開始から1年が経過しました。 発足の経緯や過去の活動は、前回の記事をご覧ください。

tech.classi.jp

ここでは、OSSやっていきの集いを通して、私自身が実際にOSSへコントリビュートした経験と、活動を通じて実感したメリットについてお話しします。

HTML Parser の修正(Herb へのコントリビューション)

社内では Rails サービスの開発をする際に、ERBの静的解析ツールとして Herb を利用しているリポジトリがあります。

github.com

ある日、HerbでHTMLをパースしているコードにおいて <div></DIV> のように大文字・小文字が混ざっていると、Parser エラーになることが分かりました。この挙動は普段ブラウザでは見かけないため、違和感がありました。

実際に発生していたエラー

Errors (2 total)

  1. MissingClosingTagError at sample.erb.html:1:0
     Opening tag `<div>` at (1:1) doesn't have a matching closing tag `</div>` in the same scope.

  2. MissingOpeningTagError at sample.erb.html:1:5
     Found closing tag `</DIV>` at (1:7) without a matching opening tag in the same scope.

そこで、改めて HTML Living Standard を確認すると「タグ名は case-insensitive である(大文字小文字を区別しない)」と明記されていました。

In the HTML syntax, tag names, even those for foreign elements, may be written with any mix of lower- and uppercase letters that, when converted to all-lowercase, matches the element’s tag name; tag names are case-insensitive. refs. https://html.spec.whatwg.org/multipage/syntax.html#elements-2

つまり、Herb Parser と HTMLの標準仕様は振る舞いに乖離がありました。特に深い意図がない限りは、基本的に Herb は HTMLの標準仕様に準拠するべきだと考え、Issue で報告しました。

さらに一歩踏み込んで原因を探るため、Herb Parser の内部実装も読んでみることにしました。Herb Parser は HTML + ERB を Abstract Syntax Tree (AST) という木構造に変換して解析しています。この AST を解析する処理を追っていくと、開きタグと閉じタグの比較が大文字・小文字を区別して行われている実装箇所がわかりました。その調査内容も Issue に追記しました。

github.com

報告後、オーナーの方から「確かにその通り、原因分かってるならぜひ直して欲しい!」というコメントをいただいたので、修正のPull Requestを作成、無事にマージされました。

github.com

1年間活動して感じた変化、当初の目的を達成できたのか

前回の記事では、活動を通じたアウトカムとして「OSSに関わる心理的ハードルを下げる」「実践を通じた学び」「チームを越えた交流」などが挙げられていました。実際に私が1年間参加してみて、これらは得られたのかを振り返ります。 https://tech.classi.jp/entry/2025/06/23/120000

OSSへの「心理的ハードル」が下がり、日々の仕事の質が上がった

以前の私は、問題の再現性をとってIssueを立てたり、普段開発をしないリポジトリに対して Pull Requestを作成したりすることに、ハードルを感じていました。しかしOSSやっていきの集いの中で、気軽に相談し、事象の再現方法を一緒に考えてくれる場があったことで、OSS活動へどのように関われば良いかという視点が得られました。その結果、私自身のOSSに対する心理的ハードルはかなり下がりました。

また、この「OSSに関わる観点やプロセス」は、普段の仕事にも直結していると感じています。Classi には社内ライブラリやデザインシステムがあります。こういった普段の自分が関わらないプロダクトに対しても、バグを見つけた際に「ここが原因だと思うので直していいですか?」と直接 Pull Request を出しています。こういった課題を拾い、原因調査をして、改善の提案をするまでの動きが早くなったという実感が得られました。

単なる指摘にとどまらず、解決策を提案するコミュニケーションを取るかどうかで、問題解決までの速度が上がるという話は、以下のブログで挙げられている「提案のレベル」の話に繋がっています。OSS活動での経験が、結果的に日々の仕事の「提案のレベル」を引き上げてくれたのだと思います。

konifar-zatsu.hatenadiary.jp

チーム横断で問題を解決する地力を育てる場になってきた

OSSやっていきの集いでは、新卒1年目のジュニアエンジニアからアーキテクトまで、チーム横断で様々なエンジニアが参加しています。同じチームでなくても、フラットにコミュニケーションを取る場になっています。 実際にOSSにコミットするために、仕様書を読み込んだり、内部実装をデバッグし状況が再現するようなエビデンスを集める必要があります。今ある課題を特定し、問題が再現する最小のコードを探していくプロセスは、普段の業務でのバグ修正や障害対応に直結しています。こういった実践的な学びを得られる場として、OSSやっていきの集いは機能していると思います。

社内のレベルを底上げするOSSやっていきの集い

この1年間で、OSS活動はコントリビュートするという結果だけでなく、「課題を発見し、他人に伝わる形で再現し、実際に手を動かして解決するというプロセスそのものに重要な学びがある」と感じました。こういったプロセスを複数のメンバーと取り組むことで、個人の学びを組織の学びに昇華できる重要な機会になっています。今後も続けていきたい活動です。

今回の記事を読んで、1つでも得られるものを持ち帰っていただければ幸いです。

学習記録をもっと使いやすく。「一日の振り返り」改善ができるまで

こんにちは。Classi のコーチング/校務支援チームの とみやま(id:tommy1038)です。

この記事では、過去に担当した学習記録の「生徒の一日の振り返り」に関する改善施策を題材に、 Classi では日々どのように機能改善を進めているのかを、具体的な事例を通じてご紹介します。

今回題材にする機能

今回取り上げるのは、先生用の画面で

  • 生徒の「一日の振り返り」の記入履歴
  • それに対する先生のコメント数

を、生徒ごとの詳細画面を開かなくても 「生徒一覧」画面でまとめて確認できるようにした改善 になります。

もともとは、振り返りやコメントの状況を確認する際、

生徒の詳細画面を開く→ 内容を確認する → 一覧へ戻る → 次の生徒を開く……

という操作が必要でした。 この導線を見直し、一覧画面上で状況を把握できるようにしたのが、今回の改善です。

改善後の生徒一覧画面

なお、本機能については、ヘルプページでも紹介されています。

support.classi.jp

この改善に取り組むきっかけ

先生方からは、次のような声が寄せられていました。

  • 生徒が数日前や1週間前にさかのぼって振り返りを記録した場合、見逃してしまうことがある
  • 週初めや休暇明けなど、複数日の記録をまとめて確認したい場面で、ひとつずつ画面を開くのが大変

特に、“記入された振り返りへ、きちんとコメントを返したい” という思いが強い学校ほど、見逃しが発生しやすい構造になっていました。

そこで今回は、

  • 生徒ごとに「一日の振り返り」の記入がある、最新3件の日付
  • それぞれの日付に対する先生からのコメント数

を、生徒一覧画面に表示するようにしました。 これにより、生徒ごとの状況を詳細画面を開かなくても把握しやすくなることを目指しました。

タスクの選定

Classi では、機能ごとに担当チームがあり、そのチームの中で新機能の実装・改善・保守運用を行っています。

改善要望を確認したあとは、次のような観点で「どういった時期に対応するか」を検討します。

  • 緊急度・優先度
  • ユーザーへのインパクト
  • 実装および運用コスト

今回の改善は、学校現場での困りごとが明確であり、比較的小さな実装で先生の負担感が改善される見込みがあったため、対応することに決めました。

対応決定後は、

  • どの画面で、どう見えると先生は使いやすいか
  • 既存 UI との整合性はどうか
  • どのように実装するとシンプルで保守しやすいか

といった観点で、もう少し深く検討を進めていきました。

UI案の検討

仕様の方向性がある程度見えたところで、UI モックを作成し、複数案を検討しました。

例えば、

  • 先生が最後にコメントした日時を表示する案
  • 生徒の振り返りコメント日をすべて表示する案

なども候補に挙がりました。

検討した表示案

しかし、これらの案には

  • 情報量が多くなりすぎる
  • 一覧画面としての見通しが悪くなる

という課題がありました。

最終的に

  • 生徒ごとに「一日の振り返り」の記入がある、最新3件の日付
  • それぞれの日付に対する先生からのコメント

という形にすることで、必要な情報を保ちつつ、一覧としての見やすさも損なわないバランスを実現できると判断し、現在の仕様に落ち着きました。

多職種での協働

今回の改善では、開発チームだけでなく、

  • CS チーム
  • QA チーム
  • 学校現場を支援している社内メンバー

とも相談しながら進めました。

さらに、実際に学習記録を活用いただいている先生にもヒアリングの機会をいただき、

  • どのような表示だと確認しやすいか
  • 現場の運用イメージと合っているか

といった観点でご意見を伺いながら検討しました。

こうした 多職種での連携を自然に行える体制 は、Classi の開発の大きな強みだと感じています。

実装から QA 検証へ

UI 案と仕様の方向性が固まった段階で実装に進み、一覧画面への表示追加や、必要なデータ取得の調整を行いました。

検証環境で動作を確認した後、QA チームと連携してリグレッションテストを実施します。

今回の改善に限らず、実際の利用シーンや権限の違いなど、さまざまなパターンを想定して確認してもらっています。

開発側だけでは気づきにくい観点も多く、QA チームにはいつも支えてもらっています。

リリースと先生の反応

QA を通過したのち、本番環境へリリースしました。 リリース後、営業メンバーを通じて

夏休み直前のタイミングでリリースしてもらえて、本当に助かりました

といった声もいただきました。 実際の現場で役立っている様子を伺えるのは、開発者として本当に嬉しい瞬間です。

おわりに

今回ご紹介した改善は、学習記録をより使いやすくするための取り組みの一つです。

その中で、

  • 学校現場での困りごとを拾いあげ
  • チームで検討し
  • 関係者と連携しながら形にしていく

というプロセスを続けていくことが、 Classi の使いやすさ向上につながると考えています。

今後も、いただいた声を参考にしながら、学校のみなさまにとって使いやすいサービスを目指して改善を続けていきます。 ここまで読んでいただき、ありがとうございました。

© 2020 Benesse Corporation. All rights reserved.