メインコンテンツへスキップ
見出し画像

AIと共創する開発 ― NOT A HOTELオーナーアプリWebチームの取り組み

    この記事は、NOT A HOTELのソフトウェア開発連載「Inside the SOFTWARE TEAM」の第4日目です。

    はじめに


    こんにちは。NOT A HOTELでWebエンジニアをしている手嶋です。
    NOT A HOTELでは、エンジニアに限らず全職種で積極的にAIを活用し、業務フローの改善や生産性の向上に取り組んでいます。

    私たちのチームでも、さまざまなAIツールを手探りしながら活用してきました。本記事では、WebチームがどのようにAIを活用しているのか、実装とコードレビューを例に具体的な方法と得られた成果をご紹介します。

    実装


    コーディングルール

    実装においては、チームで定めたコーディングルールに沿ってAIを活用しています。
    Reactの設計やTypeScriptの方針を詳細に記載しており、チーム全体で一貫性のある開発を支える重要な基盤となっています。

    このルールは、GitHub Copilot ・Cursor・Cline・Devinなど複数のAIエージェントを活用する際にも一貫性を保てる共通基盤として機能するように定めました。AI導入初期にさまざまなツールを試していたことから、個別にルールを設けるよりもマスターとなる共通ルールを定める方が効果的だと判断し、この運用を開始しています。(各エージェント固有の設定は個別に追加しています)。

    その後、Claude Codeを使い始めたメンバーもいますが、こうしたツール切り替え時にも運用コストが低いというメリットがあったと思います。
    こちらのコーディングルールについては、AIエージェント(Cline)に既存のコードベースを解析してもらいベースとなるルールを生成してもらった上で、チームメンバー間でのレビューや議論を経て作成しました。

    また一度作成したら終わりではなく、運用開始後も記載漏れや新しい論点が見つかるたびにルールを継続的にアップデートし続けています。これによりAIを活用したより良いチーム開発を追求することができていると感じます。
    (ex.Reactコンポーネントのpropsに関するルールを追加)

    画像
    実際にルールを更新するPRでの議論

    具体的には、現在以下のようなルールを明記しています。(セクション毎に一部抜粋)

    ## コンポーネント構造
    - コンポーネントはReact関数コンポーネントとして実装し、型も `FC` を明示する
    - **重要**: `src/pages/` 配下のファイル以外では、default exportしないこと
    
    ## スタイリング
    - カラーコードの直接指定は避け、テーマのカラートークンを使用する
    - ボタンに固定値のwidthを入れない
      - 多言語対応でテキストが長くなる場合もあるため
    
    ## TypeScript
    - `any`型の使用を避ける
    - `as` の使用を避ける
    - propsはinterfaceで定義する
    
    ## コードスタイル
    - コードスタイルの基本的なルール(セミコロン、クォート、インポート順序など)はPrettierとESLintで自動的に適用される
    
    ## URL設計
    - ページのURLは以下のルールに従う
      - 静的な文字列部分はkebab-case
      - 動的なパス部分(pages/配下でファイル名もしくはディレクトリ名になる部分)はsnake_case
      - クエリパラメータの変数名はsnake_case
      - クエリパラメータの変数のvalue部分はcamelCase
    
    ## 命名規則
    - ファイル名: コンポーネントはPascalCase、それ以外はcamelCase、pages/配下のファイル名は「URL設計」に記載のルールに従う
    
    ## フォームとインタラクション
    - リンクはonClickでpush()ではなく、aタグのhref属性でURLを指定する
    
    ## React Hooks
    - 不要な`useEffect`の使用を避ける
    - `useEffect`と`useMemo`の依存配列は適切に設定する
      - `eslint-disable-next-line react-hooks/exhaustive-deps`は原則使用しない
      
    ## 状態管理
    - 管理する`state`に論理的な重複がないようにする
    
    ## セキュリティとエラーハンドリング
    - エラーハンドリングは適切に行う
    - 異常の場合に正常に処理されてしまうような初期値を設定しない
      
    ## テスト
    - Cypressのコンポーネントテストファイルはテスト対象のコンポーネントと同階層に配置する
    

    Figma MCP(Model Context Protocol)の活用

    直近では、Figma MCPの活用も始めています。
    これまでも既存UIに関しては、AIがある程度正確に実装を補助してくれていましたが、新規UIの作成となると参照できる情報が少なく、精度に課題がありました。

    そこで、Figma MCPと前述のコーディングルールを組み合わせることで、Figmaのデザインデータを読み取るだけで、基本的なUI実装が可能になる基盤が整いつつあります。

    画像
    例.Figmaの要素を与えるプロンプト

    以下はFigma MCPを使用してみた所感です。

    メリット
    ・新規UIの場合、費用対効果が高い(細かい修正はあるが、人の実装よりはスピードが出る)
    ・Figmaとアプリケーションのバリアブル(colorの定義など)を合わせることで、実装ミスが限りなく減少する

    デメリット
    ・Figma側に定義されているスタイル情報をAIがそのまま読み取って実装に反映しようとするため、不要なCSSや要素が含まれるケースもある
    ・既存UIの場合は、アプリケーションで実装されているコンポーネントの情報を直接与える方が精度が高い
    (Code Connect UIを使うとFigma上のコンポーネントをコードベースにリンクすることができるとのことなので、今後試す予定です)

    上記の通りまだまだ人手による修正は必要ですが、コーディングルールやプロンプトを調整することで、実用的なコードをスピーディーに実装できそうな感覚もあるので、今後も活用を進めていきたいと思っています。

    特に、Figmaファイルを適切に構造化することで、より精度の高いコード生成が実現できるとされているため、UI実装の前段となるFigma作成時の改善点についてもチームで議論を進めている最中です。

    多言語対応

    NOT A HOTELのオーナーやゲストの方の中には、海外のユーザーもいるためアプリケーションとして英語表記にも対応しています。webの実装ではnext-i18next を使用し、機能毎に以下のようなjsonファイルに文言を定義しています。

    以前はこちらの適切なkey名を考えることに少なからず時間がかかっている状態でしたが、現在はFigmaMCPでFigmaの情報を読み取る際に、文言はjsonに定義するように指示しているので、上記の課題が解決できていると感じます。
    細かい部分ではありますが、機能によっては定義するjsonが非常に多いこともあるので、かなり助かっている部分でもあります。

    "receive": {
      "pageTitle": "Receive a gift | {{pageTitle}} | Booking",
      "title": "Receive a gift",
      "giftedNights": "Number of nights gifted",
      "receiveGiftButton": "Receiving a gift",
      "warningMessage": {
        "selfGift": "This gift was given by you"
      },
      "error": "Due to an issue, the gift could not be received. Please contact NOT A HOTEL for assistance.",
      "dated": {
        "giftDetails": "Gift Details",
        "giftedSlots": "Number of nights gifted",
        "giftExpiration": "Gift claim deadline",
        "giftExpirationDate": "Until {{date}}",
        "daysStandard": "Standard Season",
        "daysHigh": "High Season",
        "daysTotal": "Total Nights",
        "bookingButton": "Book a stay with gift",
        "warningMessage": "This gift was given by you",
        "cancelMessage": "The gift will not be received until you make a reservation.\\nIf you don't complete your booking by <accent>{{date}}</accent>,\\nthe gift will be automatically canceled."
      }
    }
    

    テストの充実度

    AIの活用は、テストの面でも良い効果をもたらしています。
    現在はCypressとJestを用いてReactのコンポーネントテストを中心に実装していますが、AIにテストコードを生成してもらうことで、新規ファイルのテストカバレッジを拡大できています。テストコードは比較的AIが得意な領域でもあり、チーム内でテスト実装への積極性が高まっている実感があります。

    実装者の負担軽減だけでなく、実装されたテスト上でUIを確認できるため、仕様理解や動作確認がしやすくなり、レビューの負荷軽減にもつながっています。

    レビュー


    レビュー工程では、Claude Code Actionを用いたPRレビューを実施しています。このレビューもコーディングルールに沿って行われており、従来レビュワーが時間をかけて行っていたルールとの整合確認を、AIに任せられるようになりました。

    また、PRでの変更箇所だけでなく、同じファイル内に存在するルール違反も自動でチェックされるため、小規模なリファクタリングが自然と進むという副次的な効果も得られています。

    例:PRレビューのなかでコーディングルールとの整合を確認する部分

    画像
    レビューでOKとなるパターン
    画像
    レビューでNGとなるパターン

    まとめ


    私たちのチームでは、実装からレビューまでAIを取り入れることで、開発効率と品質の向上を図っています。AIの進化は非常に速く、今後もさまざまなツールが登場すると考えられるため、チーム内でAI活用のベストプラクティスを継続的に蓄積していくことが、効率的な開発に繋がると考えます。

    また、直近では他の技術レイヤーのメンバーがWebチームの開発に加わることがありましたが、コーディングルールや自動PRレビューのおかげで、想定より障壁少なく開発を進めることができたという成功事例もありました。

    今後もAIを活用しながらこうした領域横断の動きも加速させ、NOT A HOTELアプリの価値を最大限に高める開発チームをつくっていきます。

    現在、NOT A HOTELのSoftwareチームでは採用強化中です。
    カジュアル面談も受け付けておりますので、お気軽にご連絡ください。


     
     
    NOT A HOTELでwebエンジニアをしています

    あなたへのおすすめ