仕様駆動開発してみた

はじめに

はじめまして。情報系を専攻する学部3年の西田です。2026年10月の1ヶ月間、【Excitech Camp!!!】28卒就業型サマーインターン 2026に参加しました。

今回は、ボタン1つを追加した改修の話です。小さな改修ですが、要件定義書・基本設計書・システム設計書と、画面モックまで作りました。

コードより先に仕様を決める「仕様駆動開発」を試したからです。仕様を先に決めると何が変わるのか、やってみてわかったことを書きます。

担当した改修

配属先は、相談系サービスの開発チームです。チャット占いの終了画面に、「コイン購入はこちら」ボタンを追加する改修を担当しました。鑑定(占い師に占ってもらうこと)が特定の条件で終わってしまった人を、コイン購入ページへ案内します。

チームには、仕様駆動開発のための Claude Code のスキルがあります。打ち合わせのメモと対象のリポジトリを渡すと、今のコードを調べたうえで、次の資料を作ってくれます。

  • 要件定義書(何を作るか)
  • 基本設計書・システム設計書(どう作るか)
  • 画面モック(ブラウザで見た目や動きを確かめられるHTML)

作られた資料をしっかりとレビューしたあと、設計書もPRにして、コードと同じようにレビューを受けます。

設計書をレビューするために、今の仕様を知る

AIが作った設計書をレビューするには、今の仕様を知っている必要があります。

キャッチアップは、基本的にコードを読んで進めました。そのうえで、改修に関連する部分をAIに抜き出してもらい、説明してもらいました。

設計書を作ったら、決まっていないことが見えた

依頼には、「ある条件に当てはまる人には、ボタンを出さない」という指定もありました。

設計書には、決まったことと一緒に、まだ決まっていないことも書き出されます。今回いちばん大きかったのが、この条件の判定です。

調べてみると、判定に使うデータはリアルタイムでは更新されていませんでした。鑑定が終わった時点で厳密に判定するには、APIに手を入れる必要があります。

そこで、この点を未決事項として設計書に書き、メンターと企画担当の方に確認しました。最初の設計書は、終了時に判定する方式で書いていました。確認の結果、鑑定の終了時には判定しない方式に変えました。その条件に当てはまる人は、そもそも鑑定を申し込めないためです。これで、画面の変更だけで済むことになりました。

企画担当の方に伝えるときに心がけたこと

インターンの目標のひとつに、「分かりやすく自分の考えを伝える」を立てていました。企画担当の方とのやりとりで心がけたのは、次の2つです。

  • 案は、スクショで何パターンか用意して見てもらう
  • もらった返事をもとに作り直して、また見てもらう

スクショにしたのは、人が思い浮かべるイメージは十人十色だからです。画像なら、イメージをそのまま写せるので、ずれが起きにくくなります。

ボタンの見た目は、画面モックで決めました。色や大きさを変えた候補のスクショを並べて、企画担当の方に意見をもらいました。「1枚目の案がよさそう」「派手にならない範囲で、似た色も見てみたい」といった返事をもとに、候補を作り直しては、また見てもらいました。候補は十数個になり、最後は、すぐ下にある「口コミを書く」ボタンと同じ見た目に落ち着きました。

設計書の段階で、矛盾が見つかった

設計書のPRには、GitHub Copilot(AI)のレビューもつきます。指摘のひとつは、設計書の中の食い違いでした。

終了時に判定しない方式にしたので、鑑定中に「ボタンを出さない条件」に当てはまるようになった人にも、ボタンが出ます。その人は、コインを買ってもすぐには申し込めません。件数が少ないので、設計書にはこれを受け入れると書き足しました。

ところが、最初に書いた前提の欄には「コインを買えば、どのケースでもまた申し込める」が残ったままでした。同じ書き方は、ほかに2か所にもありました。

方式を変えたときに、前に書いたことが古いまま残っていたのです。コードではなく、設計書の段階でそれが見つかりました。

仕様を先に決めて、変わったこと

方式が決まってから、設計書をもとにAIに実装させました。変えたのは、チャット画面の3ファイルだけです。

仕様をしっかり決めていたぶん、AIが自分自身で考えて勝手に実装し、意図とずれることが少なくなったと感じました。おかげで、コードレビューの手間も少し減りました。ただ、要件定義書や設計書などをしっかりとレビューしないといけないぶん、レビュー自体の手間は増えました。

ボタン1つの改修でも、仕様を先に決めた効果はありました。

最後に、メンターの方をはじめ、相談系サービスの開発チームのみなさん、人事の方々、ありがとうございました。

【Excitech Camp!!!】28卒就業型サマーインターン 2026 参加レポート

はじめに

こんにちは。情報系を専攻する修士1年の平田と申します。

2026年9月下旬から10月下旬にかけての1ヶ月間、エキサイト株式会社にて【Excitech Camp!!!】28卒就業型サマーインターン 2026に参加しました! この記事では、インターン中に経験した内容と、そこから得た学びについてお伝えします。

このインターンで一番大きな学びは 「エンジニアの仕事は、思っていた以上に人と話して、文字で伝える仕事だった」 です。 コードを書く時間と同じくらい、仕様を確認したり、判断の理由を書き残したりする時間が大切であると感じました。

自己紹介

まずは簡単に自己紹介を。 僕のプログラミング初体験は高校生の時でした。家にあった父のPython入門書をふと開いたのがきっかけです。 そこから現在まで、個人開発や研究室の仲間とのチーム開発を経験し、やがてエンジニアとして就職することを考えるようになりました。

ただ、エンジニアとして働くとなると、身内でやっているターゲットの狭い開発とは違い、実際のユーザーを相手に業務としてコードを書くことになります。 そこで、エキサイトのインターンは1ヶ月という長期間で実務を体験できるうえ、オンライン開催なので地方に住んでいる僕でも参加しやすいと感じ、応募を決めました。

配属先とタスクの概要

インターンでは L&W 事業部に配属されました。L&W とは「Life & Wellness」の略で、お悩み相談や占いなど、お客様のココロの健康や日々の悩みの解消にフォーカスしたサービスを展開している事業部です。

その中で僕は、占いサービスのTOPページ改修を担当しました。 具体的には、ログインしているユーザーに知っておいてほしい変化があったときに、画面上にマークを表示して気づいてもらうための機能を2つ実装しました。

  1. ユーザーのランクが変動したことを知らせるマーク表示
  2. 失効が近いコインがあるときに「!」マークを表示する機能

どちらも、現状と改善案を確認 → 必要に応じて新しいAPIを実装 → 見た目を変更 → レビュー → テスト環境・ステージング環境での確認 → 本番リリース、という流れで進めました。

使用した技術は、主にPHP(フレームワークはBEAR.Sunday)と、画面描画のためのテンプレートエンジンSmartyです。

取り組んだこと

ランク変動を知らせるマーク表示

占いサービスには会員ランクがあり、ランクに応じて特典を受けられます。ランクは月単位で決まるため、月が変わるとランクが上がったり下がったりします。 ところが、これまではランクが変わってもユーザーが自分で確認しにいかない限り気づけませんでした。 そこで、ランクの変動に応じてメニューにマークを表示し、ユーザーに気づいてもらうのがこのタスクです。

実装としては、先月と今月のランクをもとにランクの変動状況を返すAPIを新しく作り、その結果に応じてフロントでマークを出し分けています。 月をまたいだときに正しく判定できるかなど、動作確認でも気を配りました。

仕様の確認やレビュー対応、テスト環境・ステージング環境での動作確認を経て、APIを本番環境にリリースすることができました!

失効間近コインの「!」表示

ユーザーがもうすぐ失効するコインを持っている時にヘッダーのコインアイコンに「!」マークを表示するタスクです。 せっかくのコインを使わないまま失効させてしまわないよう、ユーザーに知らせることが目的です。

ページですでに取得している情報だけではこの判定ができなかったため、ユーザーが持っているプレゼントコインの中に有効期限が7日以内のものがあるかを判定するAPIを新しく作り、フロントでその結果に応じて「!」を表示しています。 既存の似た機能(クーポンの期限間近表示など)を参考にしながら、SQLの実行計画を確認してパフォーマンスにも気を配っています。

良かったこと

  • 実際のプロダクトの中で開発できた
    • 実際のユーザーが使うサービスのTOPページという、影響の大きい部分を任せていただけました。テスト環境 → ステージング環境 → 本番環境という段階を踏んだ確認や、PRレビューを通じて、実ユーザーに届けるための品質管理を体感できました。
  • 実務の作業フローを経験できた
    • プロデューサーさんに仕様を確認したり、デザイナーさんに見た目の調整をお願いしたりと、個人開発では得られない「チームで作る」経験ができました。
  • チームの開発環境・文化に触れられた
    • AIエージェントの設定(ハーネス)をチーム全体で共有していて、誰が使っても一貫した品質で作業できるようになっているのが印象的でした。自分が今後チーム・個人開発をするときにも取り入れたいと思います。
  • 社員の方と話す機会が多かった
    • オンライン参加ということもあり、実際の業務中はそこまで他の社員さんと話す機会はなかったのですが、その分面談の時間をとっていただき、今後のキャリア選択の考え方や、サービスならではの裏話も聞くことができました。

大変だったこと

オンラインでの距離感

オンライン開催は参加しやすい反面、自分から質問のタイミングをつくらないと、話す機会が減ってしまいます。 また、重要な議論でSlackの返信を待っている時間の使い方や、在宅での仕事のメリハリのつけ方には試行錯誤しました。 とはいえ、Google MeetやTandem、Slackなどで気軽に話しかけられる環境が整っていたので、困ったときに相談しづらいと感じることはありませんでした。 大事なのは環境よりも自分から声をかけにいくことなのだと思います。

得た学び

1. エンジニアは思った以上に人と話す仕事

インターンに参加する前は、エンジニアの仕事はもっと黙々とコードを書くものだと思っていました。 ところが実際には、仕様の確認、デザインのすり合わせ、レビューのお願いなど、人と話す場面がとても多かったです。

それを一番実感したのが、ランク変動マークのタスクで仕様を確認したときです。 「ランクが上がったときだけマークを出すのか」「キープやダウンのときはどうするのか」といった、実装中に出てきた疑問をプロデューサーさんとデザイナーさんに確認したところ、2つ質問して2つとも仕様が変わりました。

仕様を決めるのはエンジニア1人ではなく、プロデューサーやデザイナーを含めたチームです。 実装していて初めて見えてくる曖昧な点もたくさんあるので、それを見つけてチームに投げかけることも、エンジニアの大事な仕事なのだと感じました。 また、仮に仕様が変わらなかったとしても、「これで合っている」と確認できるだけで、迷わず実装に集中できます。

実装中に疑問が出たら、自分だけで判断せず、すぐにプロデューサーやデザイナーに確認する。それが手戻りを防ぎ、自信を持って実装を進めることにつながります。

2. 自分の意思決定を文字に起こす

エキサイトのチームでは、後から見返す人・他の人が読むことを前提に、意図を文字で残す意識がとても強いと感じました。

コードを書いた本人の頭の中には「なぜこう書いたのか」という理由がありますが、それは書き残さない限り他の人には伝わりません。 レビュアーも、数ヶ月後にそのコードを修正する人も、書いた本人にいつでも聞けるわけではありません。 そこで、コードを書いた本人が「なぜそうしたか」を文字で残しておくことで、レビュアーや将来コードを触る人が意図を正しく理解できるようになり、レビューや保守がスムーズになります。

インターン中、実際に次のようなことを意識して取り組んでいました。

  • コードには「何をしているか」ではなく「なぜそうしたか」をコメントで残す
    • 処理の内容はコードを読めばわかりますが、「なぜその書き方を選んだのか」はコードからは読み取れません。
  • 動作確認でどんなケースを確認したかを、PRコメントに残す
    • ランク変動マークのタスクではステージング環境で何度か動作確認をやり直すことになりましたが、確認したケースを残しておいたおかげで、2回目以降の確認や、他の方に確認をお願いするときにスムーズに進められました。
  • 実装中に悩んだ判断をメモしておき、PRの説明に書く
    • たとえばコイン表示のタスクでは、フロントからAPIを同期的に読むか、JavaScriptで非同期に読むかで悩みました。こうした判断をメモしておくと、PRの説明で「ここの判断を見てほしい」とレビュアーに伝えやすくなり、レビューで見てもらうべきポイントがはっきりします。

これらは書いてみると基本的な内容ですが、実際にチームで開発してみて、その効果を強く実感しました。

3. 関数名・変数名と処理の整合性を大事にする

ランク変動マークのタスクで作ったAPIでは、ランク同士の上下関係を「そのランクになるために必要な支払額」で比較していました。 そこで、その支払額を求める関数として getCurrentRankPaymentAmount という名前の関数を実装していました。

ところが、この名前だけを見ると「ユーザーの支払額を取得する関数」のように読めてしまいます。 実際には、支払額をランクの序列を表す値として使っているだけです。

この名前のままだと、たとえば次のような問題が起こりえます。

  • ランクを比較している箇所を読んだ人が、「なぜここで支払額を比べているんだろう?」と戸惑う
  • 別の機能を作る人が、ユーザーの支払額を取得する関数だと勘違いして使ってしまう

そこで、「PaymentAmount」を「RankOrder」と言い換え、getRankOrderByRankId とリネームしました。 これにより、比較している箇所も「ランクの序列を比べている」とそのまま読めるようになりました。 また、名前が「どうやって求めているか(支払額)」ではなく「何を表しているか(ランクの序列)」を表すようになったので、関数の役割が名前だけで伝わるようになりました。

関数名・変数名と処理の整合性をとっておくことで、コードを読む人が処理の意図を誤解せずに読めるようになり、結果として保守性の高いコードにつながります。

さいごに

1ヶ月という短い期間でしたが、実際のプロダクトの中で、設計から本番リリースまでを一通り経験できたことは、僕にとって大きな自信になりました。 そして何より、「エンジニアとして働く」ことの解像度が大きく上がりました。

これからインターンを検討している方には、ぜひ長期インターンをおすすめしたいです。 短期間の体験だけではわからない、実際の仕事の進め方やチームの空気に触れることで、自分がエンジニアとして働く姿をはっきりと思い描けるようになります。

インターン期間中、タスクのオンボーディングや実装のレビューを丁寧にしてくださったメンターさん、仕様の相談に何度も乗ってくださったプロデューサーの方とデザイナーの方、そしてPCのパスワードを忘れた初日に復旧を助けてくださったインフラ部の皆さま、本当にありがとうございました!

最後まで読んでいただき、ありがとうございました!

【Excitech Camp!!!】生成AIで1日22ページ実装したら、レビューが1日で終わらなかった話

はじめに

はじめまして。情報系を専攻する学部3年の小出です。 2026年9月の1ヶ月、【Excitech Camp!!!】28卒就業型サマーインターン 2026に参加しました。

生成AIにコードを書かせて、次々に形になっていくのが気持ちいい。 そういう感覚、わかる人は多いと思います。私もそのひとりです。

この記事では、その「気持ちよさ」に乗って走った結果、実務でどうなったかを1つだけ書きます。


何をしていたか

配属先は、恋愛相談サービス「恋ラボ」の開発チームです。 古い技術で作られたアプリ(PHP, BEAR.Saturday)を、新しい技術(PHP, Laravel 13)で作り直すプロジェクトに参加しました。

私の担当は、利用規約や料金案内などの「ヘルプ」ページです。 ルールは、ユーザーから見て、旧アプリと何も変わらないこと。


1日で22ページ書けてしまった

1日目は、利用規約ページを1枚だけ作りました。 旧アプリのコードを読み、Laravelの書き方を覚えながら、ブラウザで表示を確かめる。ここまでは普通です。

2日目、流れがつかめたので生成AIにどんどん実装を任せました。 すると、とんでもない速さでページができていきます。

  • その日PRに出す予定の5ページ
  • さらに、先の予定だった17ページ

合計22ページ分のコードが、1日でできてしまいました。 正直、かなり気持ちよかったです。


でも、レビューが追いつかない

問題はここからです。 実務では、コードは書いたら終わりではありません。

  1. 自分でコードを読んで確認する
  2. PC版とスマホ版を、ブラウザで旧アプリと見比べる
  3. PRを出して、チームのレビューを受ける

AIは速く書いてくれますが、確認するのは人間です。 22ページ分のコードを、1日で読み切ることはできませんでした。

しかも、確認していくと不具合が見つかりました。 スマホ版で、パンくずリスト(ページ上部の「ホーム > ヘルプ > …」という現在地表示)の表示が欲しいところにありませんでした。

原因を探すため、旧アプリの共通レイアウトのファイルを読みました。 すると、こんな違いが見つかりました。

  • PC版:パンくずは本文の前
  • スマホ版:パンくずは本文の後ろ(フッターの直前)

実際の表示やコードを自分の目で確かめないと、正しいかどうかは判断できないと思い知りました。

結局この日は、確認できた分だけコミットしました。 残りは別のブランチに退避して、次の日以降に回しました。


速すぎると、後ろの工程が詰まる

この日の日報に、私はこう書きました。

実装速度に業務全体のペースを引っ張られると、後工程(レビュー・動作確認)がボトルネックになることを実感した

書くスピードがいくら上がっても、確認するスピードは上がりません。
作りすぎたコードはまだ使えず、置いておくことしかできません。

そこで、進め方を変えました。

  • レビューにかけられる時間から逆算して、AIに任せる量を決める
  • AIには「旧アプリの元ファイルを必ず確認して」と指示に入れる
    • HTMLとCSSの差分がないことを検証する

最終的に、1ヶ月で担当のヘルプページ29ページをすべて移植できました。


まとめ:気持ちよさは「書いた量」より「届けた量」で

AIを使えば、コードを書く量はいくらでも増やせます。 でも、チームで作るサービスで大事なのは、確認されて、本番に届いたコードの量です。

だから、書く前に一度だけ考えてみてください。

  • 今日書いた分を、今日レビューしきれるか?
  • 「正しい」と言える根拠を、元の情報で確かめたか?

AIで速く書けること自体は、すごく強い武器です。 その強さを、最後の工程まで見て使えるエンジニアを目指したいと思います。

【Excitech Camp!!!】28卒就業型サマーインターン2026を通して

はじめに

こんにちは、28卒インターン生の上中野 瑞人です!
エキサイト株式会社のExcitech Camp!!!にてBB事業部(ブロードバンド)で9月から1ヶ月間、参加させていただいております。

インターンを通した個人での開発や学生でのチーム開発との違いと長期的に保守できるシステムに関する考えについて執筆します。
なんで保守されるじゃなくてできるなのかはこれまた後ほど・・・

自己紹介

大阪産業大学 デザイン工学部 情報システム学科の学部3年生です。
小学生の頃からBASICやHTMLに触れてきてJavaやPHPなど様々なプログラミング言語でパソコンを用いて何かを作ることに楽しさを感じていました。しかし、ハッカソンや身内でのチーム開発とは異なる、実際の業務を通じてチームの一員として開発をしていく流れを学びたいと思い、僕の中では初めての長期インターンとしてExcitech Camp!!!に参加させていただいています!

事前学習

  • Webを支える技術
  • ソフトウェアアーキテクチャの基礎
  • 良いコード/悪いコードで学ぶ設計入門

上記の3冊に加え、Laravelの経験もまだまだ浅いため、一度ハンズオンで開発環境構築からやり直してみました。 特にWebを支える技術ではウェブの歴史的な経緯や僕自身が知らないこと、知っていたことをより詳細に深掘りできて面白い1冊でした。

1ヶ月でやったこと

1ヶ月の中で主に「API移行作業」を行いました。流れとしてはメンターの方が記述したチケットの内容から要件を確認してAPI設計書を作成し、相談しながら実装してレビューを経てデプロイするというものでした。

また、実装だけではなく、APIの動作確認やUnit/Featureテストの作成、レビューを受けた上での修正など、実際の開発の流れを一通り経験しました。

終盤近くでは社内ツールの旧ツールから新ツールへの移植と改善なども行いました。

よかったこと

実際に利用されている既存システムを通じて開発できたことです。

これまでは個人での開発やハッカソンなどで開発することはあり、実際にユーザーの持つサービスやソフトウェアを開発、運用する経験もありました。しかし、そこでは自分たちで決めたものを自分たちで作ることが多く、基本的に自分自身がコードや仕様を把握しているので、今回のような自分以外の人たちが継続的に開発をしている既存システムに対して変更を加えるという経験はありませんでした。

今回は既存のAPIを新たなLaravelのAPI開発環境下に移行する作業だったため、単純に動くものを作るだけでなく、既存の処理がどのように使われているか、変更するとどこに影響するのかを考えながら進める必要がありました。

また、実装をする中で疑問点なども発生します。そのため、相談しながら進める中でただ単に質問するだけでなく自分なりの対応案などを考えてから話し合うことで、よりスムーズに進めることができることも学びました。

難しかったこと

こちらは既存システムのコードの理解とテストの設計、作成です。

個人での開発では自分で書いたコードを扱うことが多いため、なぜこの処理が必要なのかを把握しやすいですが、今回は自分が書いたものではない既存のコードを読み解く必要がありました。

また、MVCではなくService、Repositoryといった概念もDBに触れることが少なかった僕にとっては新たなものでした。

そのため、ルーティング、コントローラ、サービス/リポジトリ、モデルというように処理の流れを追いながら、実際にどのような処理が行われているのかを確認していきました。

また、最初はどこまで自分で考えてから相談すればよいのか分からない部分もありました。実際に相談していく中で、分からないことをそのまま聞くのではなく、自分なりに調査してそこから自分なりに対応案を考えて出した上で相談することが重要だと分かりました。

本題とはズレますが、普段WindowsやLinuxユーザーであるため、実はmac特有のキーボード操作にも手こずっていました。バックスラッシュの入力方法が分からず、option + ¥で入力できることを知ったりなど、MacBook自体は持っているものの開発にはあまり用いることがなかったため、macOSをメインに開発すること自体も初めての経験でした。

これから先挑戦したいこと

今回の経験を通して、実装するだけでなく、その後も複数人で維持していけるようなシステムを考えながら開発できるようになりたいと思いました。
これは僕自身が参加している部活動のシステムも同じくトレンド技術を選定してしまったことにもつながるからです。

特に、アーキテクチャや技術スタックを選定するときに、今作りやすいかどうかだけではなく、今後その技術を扱える人がいるのか、学習コストはどの程度なのかなど、将来的なことまで考えられるようになりたいです。

また、今回のような既存システムの移行作業だけでなく、より大きな変更をするときの影響範囲やスコープを考え、どこまで対応するべきなのかを判断できるようになることにも挑戦したいです。

それと、Laravelに関してはまだまだわからないことだらけなので、この頃は休みの合間に個人での開発でも取り入れてます!

学び

個人での開発や学生でのチーム開発との違い

今回のインターンを通して、個人での開発やハッカソンなどの学生同士のチーム開発と、実際の仕事としてのシステム開発では考えることが大きく異なると感じました。 (ただし、これも個人プロジェクトをOSS化する際や部活動のシステムを作る際は効いてくると思います)

個人で開発する場合は、自分が使いたい技術やトレンドの技術などから技術スタックを選ぶことが多く、ある程度自分の判断で自由に進めることができます。

一方で、実務上の既存システムでは自分以外の人も開発や保守に関わっています。そのため、技術の選定だけでなく、既存システムへの影響や開発する範囲、今後の保守なども考える必要があります。

今回のAPI移行では、影響範囲の小さなエンドポイントの移行でした。しかし、レスポンスを変更すればフロント側にも変更が必要になります。1つの変更でも他の部分に影響することがありました。

また、個人での趣味的な開発では移行作業を行うことは滅多になく、既存コードを読み解くというのもオープンソースに関わる以外ではあまり行うことがありませんでした。

今回、実際の既存システムを扱ったことで、コードを書くことだけではなく、「既にあるものをどう変更するか」という視点を持つことができました。

長期的に保守できるシステムについて

僕の大きな学びとしては、長く利用され続けるシステムにおいて「アーキテクチャや技術の選定」が鍵となるということでした。 もともと個人で開発する上ではトレンドである技術や学びたい言語から技術スタックを選ぶことが多かったのですが、ここで重要となるのは、維持できるシステムを作るには金銭的コストだけでなく学習コストや人員なども関わってくるということです。

例えば、どれだけ技術的に優れた構成であったとしても、その技術を扱える人が少なければ、将来的に担当者が変わったときに保守することが難しくなる可能性があります。

この学びから僕自身もアーキテクチャや技術スタックの選定を今後のことも視野に入れて複数人で長期的に維持できるものにする力を身に付けたいという目標も明確になりました。

今回の経験から、そもそもシステムは「保守されるもの」として考えるのではなく、「保守できるもの」として設計することが重要なのではないかと考えるようになりました。

また、既存コードを読み解く上でルーティング、コントローラ、サービス/リポジトリ、モデルの流れで確認し、言葉上の理解だけではわからないため、実際にどのような処理をしているのかを見ていきました。また、なぜRepositoryとInterfaceをそれぞれ別々で作成しているのかを考えるとテスト時に余計なDBアクセスを省いてモックできる利点があると思いました。

デプロイについても、テスト環境、ステージ環境、本番環境という複数の環境を使い分けていることを知り、実際のサービスでは開発したものをそのまま本番へ出すのではなく、安全に変更を適用するための仕組みが必要であることも学びました。

(デプロイ環境のイメージ、アイコンはFont Awesome Freeさまより)

また、今回の作業を振り返って、あらかじめ「共通化できるものの洗い出し」をしておけばよかったと感じました。

技術選定の理由を言語化する習慣

メンターの方とお話しする中で、技術選びの考え方など、自分自身が気づかないうちに技術スタックを選んでいる理由、「なぜ、〇〇を選んだのか?」を「見える化」することの必要性に気づきました。

例えば、僕は「無料でサイトを運用したいからSSGを選ぶ」や「基本一人で開発するが、今後二人ほどOSSにコントリビュートしてくれるかもしれないのでドキュメントを整備しておく」などのように、普段は無意識に判断していることも「なぜその技術スタックや設計、リソースを用いたのか、選んだのか」といったことを言語化し、記録しておく習慣がとても重要であると思いました。

レビューを受けた上での学び

移行作業をする中でAPI移行対応としてフロント側のエンドポイント切り替えでAPI仕様を変更した際に型の考慮など見落としていることがありました。

また、パスパラメータ(例えばGET /api/user/{id})では、そのパラメータがなければそもそもルーティングされないのでパラメータが必須であるというバリデーションは不要であるということも学びました。

このように、同じバリデーションでもどこから値が渡されるのかによって必要な確認が異なり、APIを実装するときには単純に値をチェックするだけではなく、ルーティングや型なども含めて考える必要があると分かりました。

さいごに

今回のインターンの中で開発だけでなく、設計やテストの作成など多くのことを経験し、考え方なども学びました。

リモートであるため、人と関わるのは画面内やSlackでしたので実際にオフィスでも働いてみたい!と思いました。

また、もしかしたらものすごく当たり前のことを言っているのかもしれませんが、AI時代(AI時代じゃなくてもそうだけど)だからこそシステムは保守できる人がいないと維持できないということに気付かされました。

どうしても個人の開発では流行りや好きな技術、アーキテクチャを選びがちになりますが、学習コストや技術を利用できる人員数から考えて維持できるかどうかはまた別であるというのが大きな学びでした。

僕自身の知らない領域、学校の勉強や個人開発、資格試験では得られない、想像以上の実務経験とエンジニアとしての学びがあり、大変良かったです。そのため、リソースなども考慮した長期的に保守できるシステムを設計から考えられるITエンジニアになりたいとより明確に目標が僕の中で定まりました。

BB事業部のメンターの方、エキサイトの皆様、1ヶ月、本当にありがとうございました!!

【Excitech Camp!!!】就業型インターン参加記

はじめに

28卒就業型サマーインターンにBB事業部で9/1~9/30の一ヶ月間参加させていただきました。この記事では一ヶ月間で経験したことを振り返りまとめたいと思います。

自己紹介

情報系専攻の学士3年(28卒)です。普段は主にバックエンドを書いていて、主な使用言語はJava, Go, Kotlinでした。これまでハッカソンや個人開発などを経て、実務形式のインターンは2度目の経験でした。

そのほかの開発経験として、マインクラフトのmod・プラグイン開発も行っています。

インターンで取り組んだこと

1. フロントエンドNext.js, React, Node.jsのバージョンアップ

Next.jsのバージョンアップと、それに伴う周辺環境のバージョンアップを行いました。

  • Next.js 13.2.4 → 15.5.25
  • React 18 → 19.2.8
  • Node.js 20.17.0 → 24.18.0

一気にバージョンアップすると変更箇所が増え複雑になってしまうため、Next.js 14を経由して2回に分けて行いました。

バージョンアップ作業が終わりGitHub Actionsを用いてtest環境へデプロイしようとすると失敗、原因はビルドキャッシュによるランナーのディスク容量不足でした。docker buildxの cache-to を mode=max から mode=min に変更し、保存するキャッシュを減らすことで対応しました。

test環境でのチェックと本番データを用いるstage環境でのチェックを終えると、本番環境への反映を行いました。権限管理の都合上操作はメンターの方に行っていただきその画面共有を見る形でしたが、ちょうど数日前に参加したイベントで知った手法であるブルーグリーンデプロイが実際に行われていることを体験することができました。

2. API移植

ウェブサイトで使用されているAPIの移植を行いました。ほかのAPIと共通で用いる基盤を元に、旧版の仕様の一部のリファクタリングを兼ねての移行でした。Jiraで渡された詳細内容・方針を元に設計書を作成し実装を行いました。旧APIでは、パラメータを省略した際に暗黙のデフォルト値で動く仕様や実際には使用されない形式を処理する仕様がありましたが、パラメータを必須にし使用する1形式のみを受け付ける仕様で実装しました。

3. 便利ツール制作

社内で用いる便利ツールの制作を行いました。このツールにも旧版が存在し、その仕様を元にしつつ新規機能の追加などを行いました。エンジニアだけでなくビジネス職の方なども用いるツールであるため、非エンジニアにもわかりやすい文言とエンジニアがログを見なくてもエラーの内容がわかるような文言を併記しました。社内の人のみが閲覧可能なため、エンジニア向け情報にはDBのカラム名など詳しい情報を記載するようにしました。

旧ツールはDBを直接参照せずAPI経由で情報を取得していたため非常に低速で、数百件程度を実質的な上限とする記載がありました。そのため、当初は多くても数千件程度の処理を想定していました。新ツールではDBに直接接続することで情報取得を高速化し、5000件まで一斉に処理できるようにしました。

一旦実装を完了させると、stage環境にデプロイし実際にツールを用いるエンジニア・非エンジニアの方々に試用していただくフィードバック会を行いました。これまで旧ツールを使用していた方々のフィードバックをいただくことで、よかれと思って実装した内容が実際はないほうが良かったり5000件の上限も実際には不十分で数万件の処理が必要だったりと自分で試すだけでは気づけないことに気づけました。

フィードバック会のあとは、細かな部分の改善を行いつつ、処理データ量の引き上げ方法を検討していきました。ボトルネックは主にバックエンドにおいてリクエストで受け取れるデータ量の制限が2MBに設定されていること、処理結果をすべてメモリ上に溜めるためPHPのメモリ上限を超えてしまうことでした。これに対して、以下の方法を検討しました。

  • フロント側でデータを少しずつバックエンドに送り処理する方法
    • リクエストデータについて重複を事前に除去する機能を持っていることからこの除去が分割した1回分ごとにしか効かなくなるため不採用
  • AWSのS3を用いて処理結果を積み上げていくことで処理中のメモリ使用量削減を行う方法
    • AWSの権限や知識が必要で実装が複雑になることから不採用
  • 送られたデータの処理を1000件ずつ行い処理が完了したデータからPHP, Laravelのstream機能を用いてNDJSON形式で返す方法
    • 処理が終わった分から返し、メモリ上に大量のデータを溜めずに済む
    • リクエストデータ量の上限である2MBは解消されないが、このデータ量でも10万件程度は処理可能で十分であると考え、採用

結果として、処理できる件数を5000件から10万件程度まで引き上げることができました。

AIの使用

インターン期間中、Claudeを活用していました。desktop appからClaude Codeを使用し、方針決定のサポートから実装、コードレビューまで行いました。コードレビューには /code-review を初めて使いました。今までは変更内容を確認してとプロンプトで指示していましたが、コマンドだと自動でサブエージェントを並行で走らせてくれてとても便利でした。ひとつタスクを任せながら待っている間にもうひとつのタスクをプロンプト書いて投げる、返ってきているものをレビューするなど効率的に進めることができました。

インターン終盤にはOpus 5.5がリリースされ使っていました。正直もはや明確な違いがわからなくなってきている感じもしますがより早く高い品質で大規模なコードを読み書きできるようになっているように感じました。

インターンとして自身の成長に役立てる上でAIを使わずにコードを書いたほうがいいのではという気持ちもありましたが、実際コードはAIが大部分を担うことが多い中で実務における仕様決定やフィードバック対応などのコミュニケーション面の経験を重視したいと考えAIをフル活用しました。実際実装とレビューのループを高速に回せたことでフィードバック会などを経験することができとても良かったと思います。

インターンを経て

一ヶ月計80時間程度のインターンで、フロントからバックエンド, インフラも少しと幅広く触れ、仕様策定やフィードバックなどを含めて実務の一連の流れを学ぶことができました。メンターを含むBB事業部の方々、人事の方々、貴重な経験をさせていただきありがとうございました。

【Excitech Camp!!!】就業型インターン 2026 を通して

はじめに

2026 年 9 月の 3 週間、エキサイトの就業型インターンに参加しました。 配属は FanGrowth(ウェビナーマーケティングのプラットフォーム)を開発しているチームで、 フロントエンドを中心に、実際に運用されているプロダクトのコードを触らせてもらいました。 やったことと、やってみて思ったことをまとめます。

自己紹介

情報学専攻の学部3年生です。これまで個人開発 / チーム開発 / ハッカソンなどで開発をしてきましたが、 チームで運用されているコードに、レビューを受けながら手を入れる経験がなかったので、それを目的に参加しました。

配属先で取り組んだこと

FanGrowth のフロントエンド(React + TypeScript)と、関連する社内向けダッシュボードで、3 つのタスクを担当しました。

1. 全ページにページタイトルを設定する

ブラウザのタブに出るタイトルが、多くの画面で「FanGrowth」だけになっていました。 全 114 ルートを洗い出して、どの画面にどんなタイトルを付けるかを決め、実装しました。

実装より命名が本体でした。URL の名前と画面の見出しが食い違っているページが 14 件あり、 どちらを採るかで利用者の見え方が変わります。1 件ずつ「画面の見出し」「左メニューのラベル」「コードの定義」のように 出所を辿れる根拠を付けて案を出し、メンターの方とのレビュー会で決めていきました。 社内で定着している呼び方に合わせた箇所もあって、そういう情報は調べても出てこないので、レビューで拾うしかないと分かりました。

2. ゲスト表示の企画共有ページを Figma に合わせる

共催ウェビナーのゲスト企業が見る画面を、デザイナーの Figma に合わせて直すタスクです。 3 つの中でいちばんしんどかったのがこれで、直しても直しても漏れがありました。詳しくは後で書きます。

3. 社内向けダッシュボードのテーブル改善

案件の一覧テーブルが横スクロールしないと全体を見られない状態だったので、案件名の列を左に固定しました。 position: sticky は区切り線が消える、max-width が効かない、フォーカス枠が塗り潰されるなど、 実機で見ないと気づけない罠が多く、CSS を書いては画面で確認する往復になりました。

タスク以外で見つけたもの

作業中に、ローカル環境で一覧ページが開けなくなる不具合に当たりました。 画面には「500」と出るのですが API は正常で、原因はフロント側の null 参照でした。 メンターの方に相談して別ブランチで修正し、PR にしました。 ほかにも作業中に見つけた不具合を 2 件、原因を調べてチケットの形にして残しました。

学んだこと

「今どうなっているか」が見えることの価値

まず環境の話から。用件や質問があるときに、Slack や Tandem で気軽に声をかけられる雰囲気がありました。 リモートワークだと相談のハードルが上がりがちですが、そこが工夫されていると感じました。

もう一つは Jira です。タスクが「作業前 / 進行中 / レビュー中 / チェック中 / 完了」に分かれていて、 どのタスクが今どの状態かを、自分以外の人からも確認できます。

これが良いと思ったのは、自分が別でやっているチーム開発と比べたからです。そちらは Discord で 「これやって」と頼む形で管理していて、頼んだ相手が今どこまで進んでいるのかを確認する場面と、 逆に自分が頼まれたタスクが何だったか、どのチャンネルで話したかを探す場面で手間がかかっていました。 状態が一か所に見えているだけで、その両方が消えます。ツールは Jira でなくてもいいのですが、 「見える場所を作る」のは自分のチームにも持ち帰りたいと思いました。

そして、これは自分がやる側でも同じでした。今回うまくやれたと思うのは、 タスクを始める前に「こう進めようと思っています」という前提確認をしたことと、進捗を適宜報告したことです。 上司の側から見れば「ちゃんと進んでいるのか」が見えるし、自分の側から見れば、方向性がずれて作業が無駄になるのを防げます。 実際、3 週間で方向がずれて作業をやり直す、ということはありませんでした。

AI に任せていいものと、自分の目で見なきゃいけないもの

インターン中は AI をかなり使いました。作業と呼べるものは、可能な限り任せたいと思っていました。

それで痛い目を見たのが Figma 合わせです。デザインの値を読み取って実装と突き合わせる、というのは まさに「作業」に見えたので任せていたのですが、レビューで指摘を受けて直しても、また別の箇所がずれていました。 2 回目に同じ領域を指摘されたとき、自分のやり方が違うのかもしれない、と思いました。 そこで Figma と実装のスクリーンショットを並べて、自分の目で全部見直したところ、 数値の比較では「一致」になっていた箇所に、幅のずれが残っていました。

振り返ると、任せてよかったものと、任せて痛い目を見たものには、はっきり違いがありました。

任せてよかったのは、114 ルートの洗い出し、命名の根拠を 1 件ずつ付ける作業、 lint やテストの件数を着手前と比べる確認、git の履歴調査、ブラウザで計算済みスタイルを測る作業です。 どれも、元になる情報が機械的に取れるものでした。

痛い目を見たのは、Figma の画面を目で読んで数値を転記する作業、コードを読んだだけで 「この画面はこう動くはず」と説明したこと、そしてタスクの範囲を自分の判断で広げたことです。 こちらは、人の目で読み取ったものか、相手の意図を推測したものでした。

線を引くなら、「ソースが機械的に取れるものは任せられる。人の目で読んだものと、 相手の意図を推測したものは、任せた結果を必ず自分で見る」だと思っています。 Figma は前者に見えて実は後者だった、というのが今回の落とし穴でした。 AI を使いながら漏れなく確認する方法はほかにもあるのかもしれませんが、 少なくとも「作業だから任せて終わり」ではダメだ、というのは身をもって分かりました。

おわりに

3 週間で、命名・デザイン合わせ・CSS・不具合調査と、種類の違う作業を一通り経験できました。

いちばん変わったのは、与えられたタスクをこなすことより、 「タスクは何か」「問題は何か」を自分で見つける側をやりたい、と思うようになったことです。 今回は与えられたタスクの途中で見つけた不具合を 3 件、自分で原因を追って形にできました。 そこが一番手応えのある時間でした。

レビューを何度もしてくださったメンターの方、チームの皆さん、人事の方々、ありがとうございました。

【Excitech Camp!!!】28卒就業型サマーインターン 2026を通して

はじめに

【Excitech Camp!!!】28卒就業型サマーインターン 2026 に8月の1ヶ月間参加させていただきました。BB事業部での開発を通して学んだ事をブログ記事としてまとめようと思います。

自己紹介

情報学専攻の学部3年生です。今までハッカソンや個人開発を通してエンジニアとして必要な知識を身につけてきましたが、より実践的な知識や業務に関わることでその知識を深めていきたいと思い、本インターシップに参加させていただきました!

配属先で取り組んだこと

BB事業部において社内向けツールのログ検索ツールの作成に取り組みました。

具体的に行ったタスク

メンターの方が叩き台となるAPIの設計書を作成していたので、その内容をメンターとの話し合いやユーザーに近い人たちへの質問を通してユースケースを確定させ、実装していきました。

学んだこと

エンジニアとしての仕事の進め方

実際にコードを書いた後、エンジニアがコードをレビューし、テスト環境やステージ環境を通して問題がないか確認すること、そのコードやGitHub上の記述を自分の理解を示し、行っていく事を取り入れる事を学びました。

アーキテクチャやフレームワークレベルでの知識

アーキテクチャでControllerとServiceの分離を考えたり、Laravelでバリデーションをどのように書くか、どのような機能を使って書くかなどを考えました。

おわりに

今回のインターンシップでは、自分の関心や志向の解像度を上げ、エンジニアとしての視野を広げるきっかけになりました。この経験をもとにこれからのエンジニアとしてどのようになりたいか考えていきたいと考えています。この一ヶ月間メンターやレビュー等、サポートしてくださったエンジニア、および人事の方々、インターンを支えてくださった皆様本当にありがとうございました。

Crashlyticsのエラー調査にFirebase MCPを使ってみて便利だったこと

こんにちは。エキサイトでアプリエンジニアをしている岡島です。 エキサイトホールディングス Advent Calendar 2025の21日目を担当させていただきます。

今回はFirebase MCPを使ってみたので活用できそうなものを共有していきたいと思います。

はじめに

コーディングエージェントのAIが登場してから、使い方を模索し続けていますが、 調査はAIにお任せしてもかなり解決の手助けになっていると感じています。

普段業務で触っているアプリはFirebase Crashlyticsを用いてエラーログやクラッシュログなどを収集しています。 これまでは、エラーやクラッシュが発生した際に、私自身がログを確認し調査→修正をしていました。 この辺りを自動化して、早期にクラッシュやバグの対応をすることができないかと考えていました。 ということでFirebase MCPを用いて、エラー確認→タスク管理ツールへ起票→調査→PR作成まで自動化してみました。

今回実際に試してみて「これは便利だ」と感じた機能を紹介します。

導入方法

導入方法は公式が詳しく書いてくれていたので割愛させていただきます。 ClaudeやCursor、Gemini CLI、Antigravityなど手順が書かれていました。 firebase.google.com

便利な機能について

Crashlytics の情報を、AIから直接取得できるようになったので 調査時間の圧倒的短縮につながると思っています。 実際にClaude Codeを用いて調査してもらったのですが、AIに完敗だと感じました。

Firebase MCP の仕様や提供されている機能の詳細については、 公式ドキュメントにまとまっているため、こちらをご参照ください。 https://firebase.google.com/docs/crashlytics/ai-assistance-mcp?hl=ja&authuser=0#fetch-data

1. さまざまな切り口の集計レポートが出せる!

今までもCrashlyticsのページで、 エラーの発生OSやバージョン、デバイスなどを見ることができましたが 把握しづらいなと個人的に思っていました。(使いこなせてなかった説もありますが、、、)

今回一番嬉しいなと思ったのは、エラーごとにどのバージョンでクラッシュが多いかなど AIが調査してくれることでした。 おかげさまで影響範囲の特定や問題の切り分けなどが行いやすくなりました!

↓こんな感じでレポートもまとめてくれました!

バージョン別集計 (crashlytics_get_top_versions)
  • 1.0.8 (11): 〇〇件
  • 1.0.7 (9): 〇〇件
  • 1.0.9 (12): 〇〇件
デバイス別集計 (crashlytics_get_top_android_devices)
OS別集計 (crashlytics_get_top_operating_systems)

2. Firebaseコンソールへのリンクを出せる!

エラーごとにFirebaseコンソールへのリンクも取得できました。 MCPを使えばエラーのイシュークローズなどもできてしまいますが、 人間の手作業でハンドリングしたいということもあると思います。

そこで、タスク管理ツールやPRのドキュメントなどへ Firebaseコンソールへのリンクも出力するよう指示すれば 自分で作業することもできます!

3.トップイシューの取得

トップイシューの取得は言わずもがなです。 発生頻度の高いものについて把握、調査できます。

最後に

今回は Firebase MCP を触ってみました。

実際に使ってみて、調査や情報整理といった作業にAIを活用するのは、とても有効だと感じました。 人間よりも圧倒的に早く、圧倒的に多くの量をこなしてくれます。 このような調査を並列で作業させたり、自動化するのはかなり良いなと思いました。

最後まで読んでいただき、ありがとうございました。

静的解析とアーキテクチャテストでLaravelの設計をCIで保証する品質戦略の話

はじめに

こんにちは!エキサイト株式会社の伊藤(梨)です。

ジョインして半年、駆け抜けてきました。 密度が濃すぎて倍はいる感覚です。

エキサイトホールディングス Advent Calendar 2025の17日目の記事です。

qiita.com

BB.excite事業部では2025年12月現在、新しい開発環境の新設・リビルドによる刷新を進めています。

先日、同じチームの岡崎さんが「リビルドを始めた話」という記事でアーキテクチャ設計について紹介してくれました。 モノレポ採用やリポジトリパターンのレイヤー構成など、設計思想がまとまっています。

本記事では、その設計をコードレベルで保証する仕組みについて紹介します。

設計は「決めて終わり」ではない

アーキテクチャを決めても、開発が進むにつれてこんなことが起きがちです

  • 「急いでたからControllerから直接Repository呼んじゃった」
  • 「このModelにちょっとだけService呼ぶロジック入れちゃおう」
  • 「レビューで見落として、気づいたら依存関係がぐちゃぐちゃ」

コードレビューだけでこれを防ぐのは限界があります。人間は見落とすし、忙しいときは妥協しがちです。

そこで静的解析とアーキテクチャテストで自動的にルールを守らせる仕組みを導入しました。 このアーキテクチャテストは、私と同じくLaravel愛が強い社内のエンジニアが提案してくれました。

ポイントは、壊れてから気づくんじゃなくて 壊そうとした瞬間に落ちる 状態にすることです。

導入したツール

ツール 役割
PHPStan + Larastan 静的解析(型チェック)
phpat アーキテクチャテスト
Laravel Pint コードスタイル統一
GitHub Actions CI/CDで自動チェック

PHPStan + Larastan Level 8 - 厳格な型チェック

PHPStanとLarastanのレベルは0〜9まであり、数字が大きいほど厳格になります。

今回はLevel 8を採用しました。

Level 8では以下のようなチェックが行われます。

  • 戻り値・引数の型の厳密なチェック
  • nullableな値の適切なハンドリング
  • 存在しないプロパティ・メソッドへのアクセス検出

Larastanを併用することで、Eloquentモデルの$user->nameやファサードのDB::table()など、PHPStanだけでは解析できないLaravel特有の書き方も正しく型解析できます。

phpatでアーキテクチャをテストする

ここが本記事のメインです。

phpatは、クラス間の依存関係をテストできるツールです。「このクラスはあのクラスに依存してはいけない」というルールを、テストコードとして書けます。

アーキテクチャの図

私たちのアーキテクチャは以下のような構成です。

Controller ─┐
            ├→ UseCase(任意)→ Service → Repository
Command ────┘                      ↓
                              Model/DTO

上位層は下位層に依存してOK、逆はNGという原則です。

パッケージ構造

package/
├── Repository/   # データアクセス層
├── Model/        # DTO・Enum
├── Service/      # ビジネスロジック
├── UseCase/      # ユースケース(任意)
└── Application/  # DB接続、外部クライアント

LayerDependencyTest - レイヤー間の依存関係

<?php

final class LayerDependencyTest
{
    /**
     * CommandとControllerはRepositoryに直接依存してはいけない
     */
    public function testNoDirectRepositoryAccess(): Rule
    {
        return PHPat::rule()
            ->classes(
                Selector::inNamespace('App\Console\Commands'),
                Selector::inNamespace('App\Http\Controllers')
            )
            ->shouldNotDependOn()
            ->classes(Selector::inNamespace('Package\Repository'))
            ->because('Controller/CommandはRepository直参照禁止。Service経由にする');
    }

    /**
     * ServiceはCommandやControllerに依存してはいけない
     */
    public function testServiceIndependence(): Rule
    {
        return PHPat::rule()
            ->classes(Selector::inNamespace('Package\Service'))
            ->shouldNotDependOn()
            ->classes(
                Selector::inNamespace('App\Console\Commands'),
                Selector::inNamespace('App\Http\Controllers')
            )
            ->because('Serviceは上位層(Controller/Command)に依存しない');
    }

    /**
     * RepositoryはServiceやUseCaseに依存してはいけない
     */
    public function testRepositoryIndependence(): Rule
    {
        return PHPat::rule()
            ->classes(Selector::inNamespace('Package\Repository'))
            ->shouldNotDependOn()
            ->classes(
                Selector::inNamespace('Package\Service'),
                Selector::inNamespace('Package\UseCase')
            )
            ->because('RepositoryはService/UseCaseに依存しない(責務を固定する)');
    }
}

これにより、誰かがControllerからRepositoryを直接呼ぼうとすると、CIで検出されてマージできません。

DomainIndependenceTest - ドメイン層の独立性

<?php

final class DomainIndependenceTest
{
    /**
     * ModelはLaravelフレームワークに依存してはいけない
     */
    public function testModelFrameworkIndependence(): Rule
    {
        return PHPat::rule()
            ->classes(Selector::inNamespace('Package\Model'))
            ->shouldNotDependOn()
            ->classes(Selector::inNamespace('Illuminate'))
            ->excluding(
                Selector::inNamespace('Illuminate\Support\Carbon')
            )
            ->because('Model(DTO/Enum)はフレームワーク非依存にして再利用性とテスト容易性を守る');
    }

    /**
     * Modelは上位層に依存してはいけない
     */
    public function testModelLayerIndependence(): Rule
    {
        return PHPat::rule()
            ->classes(Selector::inNamespace('Package\Model'))
            ->shouldNotDependOn()
            ->classes(
                Selector::inNamespace('Package\Service'),
                Selector::inNamespace('Package\Repository'),
                Selector::inNamespace('Package\UseCase')
            )
            ->because('Modelは純粋なデータ表現。上位層の都合に引っ張られない');
    }
}

Model(DTO・Enum)はフレームワークに依存しない純粋なPHPクラスとして保つことで、テストが書きやすくなり、フレームワークのバージョンアップにも影響されにくく、ロジックも明確になります。

GitHub ActionsでCIに組み込む

GitHub Actionsを使って、以下のタイミングで自動チェックを行っています。

  • push時:静的解析 + コードスタイルチェック
  • PR時:上記 + PHPUnitテスト

違反があればCIが落ちるので、ルールを破ったコードはマージされません。

導入してよかったこと

  1. レビューの指摘が「好み」じゃなく「ルール」になる

    • 「この依存関係おかしくない?」が個人の意見ではなく、機械的な判定により指摘が不要になる
    • 機械がチェックしてくれるので、人間はビジネスロジックのレビューに集中できる
  2. 新メンバーでも安心

    • ルールを全部覚えなくても、違反したらCIが教えてくれる
    • 「新しいメンバーでも設計に素早く適応」を後押しできる
  3. 設計意図がコードに残る

    • なぜこのルールがあるのか、コメントで説明できる
    • テストコード自体がドキュメントになる

なぜここまでやるのか ─ 持続可能性への想い

正直に言うと、静的解析やアーキテクチャテストは「やらなくても動く」ものです。 導入には時間もかかるし、最初は面倒に感じることもあります。

でも、私はこう考えています。

サービスは続く。でも、人は永遠じゃない。

辞める人もいれば、定年を迎える人もいる。どんなに長く働いても、いつかは必ずいなくなります。 そのとき、技術や知識がその人の頭の中だけにあったら、一緒に消えてしまい保守不能になってしまいます。

少子化でエンジニアも減っていく今の時代は小さいチームで大きな仕事をこなす必要があります。 だからこそ、持続可能な開発を意識すべきだと思っています。

私はコードベースを「大きな木」のようにイメージしています。

地上に見える枝はコードと捉え、開発が進むほど伸びていきます。でも、見えないところで根っこが繋がっている。 設計思想も、コーディング規約やアーキテクチャテストも、すべてその根っこの一部です。

そして、その根っこは人と人も繋いでいます。 今いる人から次の人へと技術を継承していくための土台だと思います。

次の世代へ継承する

会社は利益を追求するもの。それはもちろんです。 でも、エンジニアの仕事はそれだけじゃないと思っています。

技術を継承して、繋がりを広げること

インターン生が記事で「『なぜ?』を問う思考の重要性」について書いてくれました。

メンターから「実装方針は真似しないでほしい」と言われた

これはレガシーコードを「こう書いてあるから」と深く考えずに真似しないでほしいという意味です。 同時に、「なぜ?」を自分で考えられるエンジニアになってほしいという願いでもあります。

ただ仕事をするだけでなく、経験を活かして成長してほしい。人生を輝かせてほしい。 そしていつか自分を超えていってほしい、と私は日々思って業務に向き合っています。 そのためにも、設計をドキュメントに書くだけでなく、コードで保証して、誰でも自然に良い設計に導かれる仕組みを作りたかったのです。

まとめ

PHPStanとLarastanで静的解析、phpatでアーキテクチャテストを行い設計意図をテストとして表現し、CIで自動的に保証できます。 「壊そうとした瞬間に落ちる」状態を作ることで、設計が守られ続けます。

アーキテクチャ設計と合わせて、チーム全体で品質を維持していく仕組みが整いつつあります。

これからリビルドを進める方、レガシーコードと戦っている方の参考になれば幸いです。

参考

Claude Codeで設定したカスタム口調を起動時からずんだもんにする方法

こんにちは!エキサイト株式会社の伊藤(梨)です。

エキサイトホールディングス Advent Calendar 2025の24日目の記事です。 クリスマスなので楽しい内容の記事にしようと思いました!

qiita.com

ある日、YouTubeでずんだもん動画を見ていた私。

「ずんだもんかわいいな〜、AIもこういう口調でやらせたら和むし楽しく開発できるのでは?!」

調べてみると、Claude CodeにはOutputStyleという機能があり、AIの応答スタイルをカスタマイズできることがわかりました。 ただ、起動時にデフォルトとして適用する方法でハマったのでその解決策を共有します。

Output Styleとは

Claude Codeでは/output-styleコマンドを使って、AIの応答スタイルを切り替えることができます。

デフォルトでは以下のスタイルが用意されています。

スタイル 説明
Default 効率的にコーディングタスクを完了し、簡潔に応答
Explanatory 実装の選択やコードベースのパターンを説明
Learning 手を動かして練習できるよう促す

カスタムスタイルの作成方法

~/.claude/output-styles/ ディレクトリにMarkdownファイルを作成します。

~/.claude/output-styles/zundamon.md

  ---
  name: ずんだもん
  description: 元気で可愛いずんだもん口調で話すのだ!
  ---

  # Custom Style Instructions

  ずんだもんとして話してください。
  ずんだもんは東北ずん子プロジェクトのキャラクターで、ずんだ餅の妖精です。

  # Specific Behavior

  - 語尾は「〜のだ」「〜なのだ」を使う
  - 一人称は「ボク」(カタカナ)
  - 元気で可愛らしい話し方
  - 技術的な説明は正確に、でも親しみやすく
  - 絵文字は控えめに使ってOK

これで /output-style コマンドを実行すると、カスタムスタイルが選択肢に表示されます。

ハマったポイント

ここまでは順調でした。

しかし...

  > はろ

  ⏺ こんにちは!何かお手伝いできることはありますか?

Claude Codeを新規起動するたびに /output-style で選択し直さないといけない!

せっかくずんだもん口調を設定したのに、毎回選択するのは面倒です。

解決策:CLAUDE.md に設定を書く

~/.claude/CLAUDE.md に口調の設定を直接書くことで、起動時からカスタム口調が適用されます。

  # 口調

  ずんだもんとして話してください。
  ずんだもんは東北ずん子プロジェクトのキャラクターで、ずんだ餅の妖精です。

  - 語尾は「〜のだ」「〜なのだ」を使う
  - 一人称は「ボク」(カタカナ)
  - 元気で可愛らしい話し方
  - 技術的な説明は正確に、でも親しみやすく
  - 絵文字は控えめに使ってOK

結果は…

  > はろ

  ⏺ はろなのだ!👋
    ボクはずんだもん、今日も元気にお手伝いするのだ!🌿

やったね!これで新規起動しても最初からずんだもん口調になりました!

Output Style と CLAUDE.md の違い

項目 Output Style CLAUDE.md
設定場所 ~/.claude/output-styles/*.md ~/.claude/CLAUDE.md
適用タイミング /output-style で選択後 起動時から自動適用
切り替え コマンドで簡単に切替可能 ファイル編集が必要
用途 一時的なスタイル変更 デフォルトの口調設定

まとめ

  • Output Style → 複数のスタイルを切り替えたい場合に便利
  • CLAUDE.md → 常に特定の口調で使いたい場合に設定

両方設定しておいて、普段はCLAUDE.mdのずんだもん口調で使いつつ、気分を変えたい時は/output-styleで切り替える使い方がおすすめです。

開発が楽しくなること間違いなしです!

応用編:VOICEVOXで喋らせる

さらに発展させて、ずんだもんの声で読み上げさせることもできます。 こちらは先人の方々が素晴らしい記事を書いてくださっているので、参考にしてみてください。

32:9の巨大スクリーンを攻略せよ!全社員総会を彩るインハウスデザイナーの挑戦

全社員総会を彩るインハウスデザイナーの挑戦

こんにちは!エキサイト株式会社 デザイナーの澤田(X:@haruka_sawada_)です。

エキサイトホールディングス Advent Calendar 2025 の22日目を担当します。

弊社のエンジニア・デザイナーが、日替わりでブログのバトンを回していますので、ぜひ他の記事も覗いてみてください 😊

qiita.com

はじめに

社員総会の様子
社員総会の様子

ExciteHDでは、半期に一度、全社員が集まる「社員総会」が開催されます。 事業や組織の振り返り、今後の方針共有、そして表彰など、会社としての「今」と「これから」を全員で共有する大切なイベントです。

今回の総会では、運営チームの一員としてデザインを担当しました。

本記事では、イベントにおいてインハウスデザイナーがどのような役割を担い、どんな工夫を凝らしたのかを振り返ります!

2. この記事でわかること

  • エキサイトでのデザイナーのお仕事
  • 全社員総会でデザイナーがどんな役割を担っているのか
  • イベントデザインならではの考え方や工夫

3. 世界観の構築から演出まで|デザイナーの役割

先輩デザイナーの鍜治本さん(X:@KAJIJI_design)と一緒に、総会のクリエイティブ制作に奔走しました。

キービジュアルの作成

まず着手したのは、イベント全体の「顔」となるキービジュアルの作成です。 今回のテーマは『AI+(アイカツ)』。「社内のAI活用をさらに推進していこう」という強い思いが込められています。

キービジュアル
キービジュアル

キービジュアルは、スライド・動画・会場装飾など、すべてのデザインの軸となります。最初にトーン&マナーを固めることで、多岐にわたるアウトプットに一貫性を持たせることを意識しました。

受賞者の事前撮影

表彰コンテンツのクオリティを高めるため、受賞者の事前撮影も実施しました。 キービジュアルの世界観に合わせてライティングや構図を調整し、当日のスライドや動画に馴染むよう工夫しています。

受賞者の撮影
受賞者の撮影

情報設計を含めたスライドデザイン

総会のスライドは、事業数値から社員紹介まで情報量が多岐にわたります。 単に「整える」だけでなく、情報の優先順位を整理し、「伝わる構成」への再設計を行いました。

また、長時間のイベントでも飽きさせないよう、適度な動きやメリハリを意識しています。

投影スライド
投影スライド

期待感を醸成するアニメーション動画

セッションの幕間には、場の空気を切り替えるアニメーション動画を制作しました。

「次は発表だ!」というワクワク感や、各コンテンツへの期待感を高めるための演出装置としての役割を担っています。

アニメーション動画が流れている様子
アニメーション動画が流れている様子

当日のカメラマン

当日はカメラマンとして会場内を走り回りました。 記録としてはもちろん、社内外への広報素材としても活用できる「熱量のある写真」を残すことも重要な役割です。

当日の様子
当日の様子

4. デザインする上で意識したこと

今回の会場である「EXCITE HUB」の最大の特徴は、アスペクト比 32:9 の超大型スクリーン! その巨大スクリーンをどう生かすかがデザインの鍵となりました。

視認性と没入感を両立するレイアウト

通常の16:9のスライドとは異なり、横に非常に長いため、以下の点を検証しました。

  • 視線の誘導:近い席の人でも首を振りすぎずに見られるか?
  • 可読性:一番遠い席からでも文字がはっきり読めるか?
  • 被り回避:登壇者の立ち位置で重要な情報が隠れないか?

実際に会場で投影テストを行い、フォントサイズや余白、配色のコントラストを微調整。結果として、会場のどこからでも見やすく、かつ大画面の迫力を損なわないデザインに着地させました。

会場でデザインを確認している様子
会場でデザインを確認している様子

感情を揺さぶるモーション設計

横長の画面は、ダイナミックな演出に最適です。 特に、ノミネート発表からベスト受賞者発表への流れでは、「誰が選ばれるかわからないドキドキ感」を会場全体で共有することを目指しました。

  • 人物画像を左右に大きく移動させる
  • 名前をあえて見切れさせ、視界の外への広がりを感じさせる
  • クライマックスに合わせてロゴを中央から拡大させる

これらをアップテンポなBGMとシンクロさせることで、会場のボルテージを高める演出を意図しました。

5. やってみて感じたこと・学び

今回のプロジェクトを通じて得られた気づきです。

✅ 環境を生かすには「現地検証」が命

事前に会場で投影確認ができたことが、成功の鍵でした。 PCの画面上だけでなく、「実際の距離・角度・照明」の中でどう見えるかを検証することで、大型モニターのポテンシャルを最大限に引き出せたと感じています。

✅ 「ムードボード」がブレを防ぐ

キービジュアル作成時にムードボード(イメージの方向性をまとめた資料)を作り込んだことで、制作物が多岐にわたっても世界観がブレませんでした。チーム内でのイメージ共有もスムーズになり、迷いを減らす効果がありました。

✅ 横断的な繋がりが資産になる

運営に参加したことで、他部署のメンバーとの繋がりが一気に増えました〜! 普段の業務では関わらないメンバーと一つのイベントを作り上げる経験は、組織への理解を深めるだけでなく、今後の仕事のしやすさにも繋がると確信しています。

6. おわりに|次回に向けて

イベントという「非日常」の体験設計は、UIデザインとはまた違った面白さと難しさがありました。 新オフィスでの初イベントとして、参加者からの満足度も高く、デザイナーとしての介在価値を感じられたプロジェクトでした。

次回はさらに踏み込んで、

参加者がその場でアクションできる体験型コンテンツや照明・音響・香りも含めた五感に訴える空間デザインなど、より没入感のある演出にも挑戦してみたいと思っています!

最後まで読んでいただき、ありがとうございました!

Adobe Fireflyを使ってアニメーション動画を作ってみた!

Adobe Fireflyを使ってアニメーション動画を作ってみた!

こんにちは!エキサイト株式会社 デザイナーの澤田(X:@haruka_sawada_)です。

エキサイトホールディングス Advent Calendar 2025 の11日目を担当します。

弊社のエンジニア・デザイナーが、日替わりでブログのバトンを回していますので、ぜひ他の記事も覗いてみてください 😊

qiita.com

去年の私「FigmaでLottieアニメーションを作ってみた!」

昨年は、FigmaとLottieを連携させたWebアニメーションの作成方法をご紹介しました。

▼昨年度の記事はこちら

tech.excite.co.jp

Figmaのプロトタイプ機能とLottie用プラグインを活用すれば、CSSやJavaScriptなどのコーディングや After Effects を使わなくても、比較的簡単にWebアニメーションを作成できます。

これはこれで、実装連携しやすくとても良い手法なのですが「生成AI」の技術進化により、今や動画やアニメーション制作にもAIが活用できる時代に……!

そこで今回は、AIを使って動画アニメーション制作にチャレンジしてみました。

今年の私「AIに全部まかせてアニメーション動画を作ってみよう!」

🎄完成した動画がこちら

昨年と同じく「クリスマス」をテーマに作成しました。

映像だけでなくBGMもAI生成なんです!ここまでできると、ちょっと感動しますよね……!

使ったツール紹介と制作の裏側

今回使用したAIツールはこの2つです。

Gemini

Googleが開発した「マルチモーダル」対応のAIモデル。テキストだけでなく画像、音声、動画など複数の情報形式を同時に理解・処理できるのが最大の特徴です。

今回私は、『動画構成(ストーリー)の検討』や『イラスト素材の生成』、『動画生成用プロンプトの相談』に使用しました。

‎Google Gemini

Gemini
Gemini

Adobe Firefly

Adobeが開発した、クリエイター向けの生成AIファミリー。画像や動画生成だけでなく、オブジェクトの追加・削除、テキスト効果、ベクター生成など、幅広い機能があります。

今回私は、『動画の生成』に使用しました。

Adobe Firefly

Adobe Firefly
Adobe Firefly

手順① :Geminiで動画の構成(ストーリー)を検討

まずは、Geminiに「動画の構成案を考えて〜!」と、かなりざっくりお願いしました。

その中でも 『何も飾り付けされていない家にサンタが訪れ、ツリーを飾り、プレゼントを置いて帰っていく』 というシンプルなストーリーを採用しました。

ちなみに、『このストーリーこれいいね!』と伝えるとすぐに動画を制作してくれました…!(すごい👀)

Geminiによる動画生成
Geminiによる動画生成

手順② Geminiで素材を作る

次に、Gemini(Nano Banana)を使って元となるイラスト素材を生成しました。🍌

何もない部屋の画像
何もない部屋の画像

サンタさんやトナカイが飾り付けしている画像
サンタさんやトナカイが飾り付けしている画像

満足げに帰っていく画像
満足げに帰っていく画像

ここで驚いたのがテイストの維持です。 「この雰囲気のままで次のシーンを描いて」と頼むと、ちゃんと絵柄をキープしてくれる…!

シーンごとにキャラや部屋が別物になる……なんてこともなく、かなり使いやすいと感じました!

手順③ Adobe Fireflyで動画を生成

素材が揃ったらいよいよ動画化です。

今回は、複数の動画生成モデル(Veo、RunwayGen、Sora etc…)をツールを切り替えずに試せる Adobe Firefly を使いました。

生成した画像を設定して、まずはシンプルに

サンタさんとトナカイが家を訪れて、ツリーを飾りつけたり、プレゼントを置いて帰っていく

というプロンプトで生成。

すると……サンタが2人になったり、窓枠と顔が被ってしまったり…なかなかうまくいかない…💦

手順④ プロンプトをGeminiへ相談

何度か試してもうまくいかなかったので、再びGeminiに相談しました。

「Fireflyでこういう動画を作りたいんだけど、どう指示すればいい?」と聞いてみると、英語プロンプトを含むおすすめの指示文を提案してくれました。

その通りに試してみたところ……最初に紹介した動画が無事完成! 🙌

まとめ | Adobe Firefly ここがすごい✨

実際に使ってみて、「これは便利…!」と感じたポイントをいくつか紹介します。

▶️ 生成した後に編集できる

「生成して終わり」ではなく、生成後に調整・編集できるのが便利だと思いました! * 気になるカットだけ作り直す * テキストやエフェクトを追加する * 続きを生成させる といったことが簡単にできるので、試行錯誤しやすくいいなと感じました。

生成後の編集画面
生成後の編集画面

🎵 音楽(BGM)まで一緒に生成してくれる

動画だけでなく、BGMも一緒に生成してくれるのが便利でした。

また気に入らなかったら「サウンドトラック」や「サウンドエフェクト」も新規で生成し、それを動画に当てこむこともできるので、雰囲気に合った音楽を一から探したり、別ツールで作ったりする必要がなく、「とりあえずそれっぽいBGM付きの動画を作りたい」という場面では、かなり助かります。

生成後の編集画面
生成後の編集画面

🤖 モデル数が多い

Adobe Fireflyでは、Firefly Videoの他にVeo、Runway Gen、Sora、Rayなどなど複数の動画生成モデルを同じツール上で試せるのが大きな魅力です。「このモデルだとどうなる?」「別のモデルならもう少し安定するかも?」といった比較がしやすく、実験しながら作れるのが楽しかったです。

モデル選択
モデル選択

AIで動画を作ってみての感想

もし今回の動画を素材の描き起こしやAfter Effectsでのアニメーション制まで、すべて手作業で行っていたら、数日はかかっていたと思います。

それが、実作業1時間程度で「ストーリーのある一本の動画」として完成したのは、正直かなり衝撃でした。

みなさんもぜひ、AIと一緒にクリエイティブを楽しんでみてください!最後まで読んでいただき、ありがとうございました 🎄✨

Claudeで認識合わせから始めた、診断コンテンツ開発

こんにちは!
Life & Wellness事業部でデザインを担当しているサカイです。

Qiitaアドベントカレンダー16日目を担当しています。

qiita.com

今回は、世界メンタルヘルスデーに向けて、診断コンテンツを作ることになりました。 その中で、AIを使いながら進め方を工夫した部分について書いていきます。

背景:時間が限られた中で診断コンテンツを作ることになった

担当サービスで診断コンテンツを作ることが決まりましたが、
スケジュールにはあまり余裕がありませんでした。

普段の業務はこのような流れで進めています。

普段の業務の進め方

しかし、この進め方だと自分がデザインFIXするまで実装に入りづらい状態となり、どうしても待ち時間が発生してしまいます。この順番で進めると実装やテストに十分な時間を取るのが難しそうでした。

全員が作業を止めずに進める方法

そこで、全員が作業を止めずにリリースする方法を考えました。

Claudeでワイヤーを作って認識を揃えたうえで、その後に作業を分担するという進め方をしました。

大枠のイメージをClaudeで作る

Claudeでモックを作成しました。普段の実装がHTMLベースであるため、モックの段階から実装に近い形で出力できる点が便利でした。 おおまかな仕様を入れて、イメージと違う部分を指摘しながら調整しました。

「SNS導線をここに置いてほしい」と指示するとすぐに作り直してくれて、

企画と会話をすすめながら修正していきました。

claudeで動くモックを作成

作ったものをすぐにURLで共有して確認してもらえるところも、Claudeの便利なところでした!

ここで全員の共通認識ができたので、全員が作業するターンに入ります。

コードを一式エンジニアに渡して組み込んでもらい、
デザイナーの自分はClaudeで作ったものをベースに次の作業をします。

html.to.designでFigmaに取り込む

Claudeで作ったモックは細かい修正が難しいので、 html.to.designを使ってFigmaに取り込み、具体的なコンテンツ内容を検討していきました。 html.to.designはWebサイトをFigmaの編集可能なデザインに変換するプラグインで、作成したモックをFigmaで編集したいときに便利でした!

html.to.design

デザイン作成

デザインの実装

デザインの方向性がある程度固まったところで、エンジニアが実装ほぼ終了していたので、デザインを実装していきました。

その過程で、 企画が考えた設問をカーソルを使ってJSONにするなど、渡すデータについてもAIを活用しています。

作成した診断コンテンツはこちらです! ぜひやってみてください。

counselor.excite.co.jp

よかったこと

この進め方を取ったことで、

  1. 短期間で合意形成ができた
  2. 実装とデザインを並行して進められた
  3. 手戻りを最小限に抑えられた

というメリットがありました!

おわりに

時間がない中では、モックでも「こういうものを作る」というイメージがチーム内で早めに揃っていることが、その後の進めやすさにつながると感じました。

AIを使うことで、こうした認識合わせのためのモックをさっと用意できるようになったのはとても助かっています。

今後も、まずはイメージを揃えるための手段として、うまく活用していきたいと思います。

リビルドを始めた話

はじめに

こんにちは。新卒3年目の岡崎です。

アドベントカレンダー10日目の記事です。

qiita.com

BB事業部では、2025年12月現在、リビルドを進めています。その事例を今回は紹介していきたいと思っています。

なぜリビルドをするのか

BB事業部でリビルドを進める背景には、いくつかの課題があります。

まず、プロジェクト自体がかなり古くなっており、不要なコードが大量に残っている状態になっています。その結果、「どのコードが使われていて、どれが使われていないのか分からない」といった状況が発生しています。

また、使用しているライブラリの中にはEOL(サポート終了)を迎えているものもあり、バージョンアップができないケースもあります。これはセキュリティ面でのリスクにつながるだけでなく、アップデートによるパフォーマンス向上や新機能といった技術的な恩恵を受けられないという問題もあります。

さらに、BB事業部にはLaravelを使用したプロジェクトがある一方で、BEARというPHPフレームワークを使用しているプロジェクトもまだ残っています。BEARは現在では利用機会が少なく、新しく入ったメンバーほど馴染みがなくなっています。そのため、「今後あまり使うことのない技術を、このプロジェクトのためだけに集中的に学ぶ必要がある」という状況が生まれてしまっています。

このような不健全な状態は、結果として開発効率の低下や属人化を招く可能性が高いと考えています。

以上の理由から、BB事業部ではシステムのリビルドを進めていく流れとなりました。

どんな構成を目指すのか

BB事業部では現在、多くのリポジトリが存在しています。そのため、まずはこれらを1つのリポジトリに集約し、モノレポ構成を採用する方針としました。

モノレポとは

モノレポとは、複数のプロジェクトやサービスを1つのリポジトリで管理する開発手法です。

モノレポの例

repo/
├── frontend/
├── backend/
├── batch/

モノレポを採用することで、コードを一元管理でき、変更の影響範囲を把握しやすくなります。 一方で、リポジトリが肥大化しやすいといったデメリットもあります。

しかし、現状ではリポジトリが増え続けていること自体が課題となっているため、これ以上リポジトリを増やさないための対策として、今回はモノレポ構成を選択しました。

アーキテクチャー

今回の設計方針的には、主にリポジトリーパターンを採用しています。

リポジトリーパターンとは

リポジトリパターンでは、Controller → Service → Repositoryという責務分離の構成を取ります。

• Controller:リクエストの受け取り・レスポンスの返却

• Service:ビジネスロジックの実装

• Repository:データベースや外部サービスとのデータのやり取り

このように役割を明確に分けることで、各層の責務がはっきりした設計になります。

リポジトリパターンを採用した理由

この構成を採用した理由は以下の通りです。

• 層を意識した開発ができ、コードの見通しが良くなる

• クリーンアーキテクチャやDDDは、Web開発の現場ではオーバースペックになる場合があり、設計を保ったまま運用し続けるのが難しいことがある。そのため、できるだけシンプルで、チーム全体が理解しやすい構成を選択した

• Repositoryを切り出すことで依存関係が分離され、Unit Testを導入しやすくなる

まずはチーム全体ができるだけシンプルな形で、みんなで開発できることを目指して、この設計を採用しています。

インフラ

インフラの構成管理(IaC)には Terraform を採用しています。

Terraformは、クラウドに依存しにくいという特徴があり、コードベースでインフラを管理できる点や、初学者でも比較的取り組みやすい点を評価して採用しました。

一方で、既存リソースとの整合性を取る作業が想像以上に難しく、特に既存環境がある状態からの導入では、運用面で考慮すべき点が多いことも分かりました。

そのため、現在振り返ると、既存リソースが多い環境ではCloudFormationを選択する判断もあり得たと感じています。

現在、やってみてよかったこと

リビルドを進める中で、開発効率が向上していると実感しています。 実際に、これまで3日ほどかかっていた実装が、1日で完了するケースも出てきました。

また、インターン生にも同じ設計方針で実装を行ってもらいましたが、大きくつまずくことなく、比較的短期間で構成に慣れ、開発に取り掛かることができていました。

設計をある程度揃えたことで、新しく参加したメンバーでも理解しやすい状態になってきていると感じています。

最後に

今回、「今後も開発を続けていくために必要な改善を行いたい」と考え、リビルドを始めました。 しかし、現時点ではまだ道半ばです。

リビルドは短期間で終わるものではなく、継続的な取り組みが必要になります。 それでも、少しずつ改善を積み重ねていくことで、開発しやすい環境や、チーム全体の生産性向上につながっていくと考えています。

今後も地道な改善を続けながら、より良い形を目指していきたいと思います。

StreamlitでチャットUIと簡易ダッシュボードを作ってみる

こんにちは、エキサイトでエンジニアをしております、吉川です。 エキサイトHDアドベントカレンダー2025の14日目の記事になります。

qiita.com

Streamlitとは

Streamlitは、Pythonでデータサイエンスや機械学習のWebアプリケーションを素早く構築できるオープンソースフレームワークです。HTMLやCSS、JavaScriptを書くことなく、Pythonのコードだけでインタラクティブなダッシュボードやデータ可視化ツールを作成できます。

特徴として以下が挙げられます。

  • シンプルな記法: st.write()やst.button()など、直感的なAPIで簡単にUIコンポーネントを配置できる
  • 自動リロード: コードを変更すると即座にブラウザに反映される開発体験
  • 豊富なコンポーネント: グラフ、テーブル、チャットなど、データアプリに必要な機能が揃っている

今回は、Streamlitを使ってチャットUIとグラフUIを実装してみながら、その使い勝手と適用場面について考えてみます。

実際に使ってみる

事前準備(インストール)

以下でインストールします。

pip install "streamlit>=1.27" pandas numpy

チャットUIの実装

Streamlitではst.chat_messageとst.chat_inputを使うことで、簡単にチャットUIを構築できます。

import streamlit as st

st.title("チャットアプリ")

# チャット履歴を保持
if "messages" not in st.session_state:
    st.session_state.messages = []

# 過去のメッセージを表示
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.write(message["content"])

# ユーザー入力
if prompt := st.chat_input("メッセージを入力"):
    # ユーザーメッセージを追加
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.write(prompt)
    
    # アシスタントの返答(ここでは単純なエコー)
    response = f"あなたは「{prompt}」と言いました"
    st.session_state.messages.append({"role": "assistant", "content": response})
    with st.chat_message("assistant"):
        st.write(response)

このコードをapp.pyとして保存し、以下のコマンドで実行できます。

streamlit run app.py

たったこれだけで、ChatGPTのようなチャットインターフェースが完成します。セッション管理もst.session_stateで簡単に実装でき、LLMと連携すれば本格的なチャットボットもすぐに作れます。

グラフUIの実装

データ可視化も非常にシンプルです。Streamlitは主要なグラフライブラリをサポートしています。

import streamlit as st
import pandas as pd
import numpy as np

st.title("データ可視化ダッシュボード")

# サンプルデータ生成
np.random.seed(0)
chart_data = pd.DataFrame(
    np.random.randn(20, 3),
    columns=['A', 'B', 'C']
)

# 折れ線グラフ
st.line_chart(chart_data)

# インタラクティブな要素
selected_column = st.selectbox("表示する列を選択", ['A', 'B', 'C'])
st.area_chart(chart_data[[selected_column]])

Streamlitを立ち上げたまま(再起動してもOK)、app.pyファイルの中身をこのコードに変えると、複数のグラフとインタラクティブな選択UIを持ったダッシュボードが表示されます(ファイル変更時は基本的に自動で再読み込みされます)。

Streamlitの魅力

ここまで見てきたように、Streamlitの最大の魅力は圧倒的な開発速度です。数十行のPythonコードで、綺麗なUIが即座に立ち上がります。プロトタイプを素早く作成したい場合や、データサイエンティストがフロントエンドの知識なしでツールを作りたい場合に非常に有効です。

向いているケース、向いていないケース

Streamlitの制約

開発速度が速いStreamlitですが、万能ではありません。いくつかの制約があります。

1. 認証・認可の機能が弱い

Streamlit自体には本格的な認証機能がありません。Streamlit Cloudの認証機能やサードパーティライブラリを使う方法はありますが、細かい権限制御や複雑な認証フローには対応しづらいです。

2. デザインのカスタマイズ性が低い

用意されたコンポーネントの範囲内でしかUIを構築できず、独自のデザインシステムを適用したり、細かいレイアウト調整をするのは困難です。CSSでのカスタマイズも可能ですが、本格的に行うと結局手間がかかります。

3. コードが複雑化しやすい

Streamlitは上から順に実行されるため、状態管理やイベント処理が複雑になると可読性が低下します。st.session_stateでの状態管理は便利ですが、アプリが大きくなるとコードの見通しが悪くなりがちです。

4. パフォーマンスの限界

ユーザーの操作ごとにスクリプト全体が再実行される仕組みのため、大規模なデータ処理や複雑な計算を含む場合、レスポンスが遅くなることがあります。

向いているケース

以下のような場面ではStreamlitが非常に有効です:

  • 社内向けダッシュボード: デザインよりも機能性が重視され、認証も基本的なもので済む場合
  • データ分析のプロトタイプ: 仮説検証や実験的なツールを素早く作りたい場合
  • デモアプリケーション: 機械学習モデルやアルゴリズムの動作を視覚的に見せたい場合
  • 個人プロジェクト: 小規模で開発リソースが限られている場合

これらのケースでは、Streamlitの「速く作れる」という利点が欠点を大きく上回ります。

向いていないケース

一方、以下のような場面では別の技術選定を検討すべきです:

  • 外部ユーザー向けプロダクト: デザインやUXの品質が重要な場合
  • 複雑な権限管理が必要: 組織やロールに応じた細かいアクセス制御が必要な場合
  • 高度なインタラクション: 複雑なUI/UXやリアルタイム性が求められる場合
  • 長期運用が前提: コードベースが大きくなることが予想される場合

こうした要件がある場合は、最初からReactやVue.jsなどのフロントエンドフレームワークと、FastAPIやDjangoなどのバックエンドフレームワークを組み合わせた構成にする方が、長期的には開発効率が高くなるでしょう。

まとめ

Streamlitは、Pythonだけで素早くデータアプリケーションを構築できる強力なツールです。ただしUIを数十行のコードで実現できる代わりに、認証機能(特に細かな認可)を自前で用意しづらい、デザインの自由度が低い、状態管理が複雑になるとコードが見通しづらい、といった制約があることも事実です。個人的には最初は簡単に作れても、要件が増えるにつれて技術的な限界に直面しやすいと感じています。

重要なのは、「Streamlitでも十分なのか」を冷静に判断することです。社内ツールやプロトタイプなど、スピード重視で機能面にフォーカスできる場面では最適な選択肢となります。一方で、外部公開するプロダクトや長期運用が前提のシステムでは、初期の開発速度よりも拡張性や保守性を優先し、従来のフロントエンド・バックエンド分離構成を選ぶ方が賢明でしょう。

適材適所でStreamlitを活用し、開発効率を最大化していきましょう。