就業型インターン「Booost!!!」:【お悩み相談室】コラム記事の新規アプリケーション移植

背景(過去フレームワークからの移行)

インターンシップでは、既存の「お悩み相談室」のコラム記事機能を旧フレームワーク(BEAR.Saturday)から新規フレームワーク(Laravel基盤)へ移植する作業を担当しました。

BEAR.Saturdayについて

移行元のシステムはBEAR.SaturdayというPHPフレームワークで構築されていました。 BEAR.Saturdayの紹介記事によると、このフレームワークは主に次の3つの要素で構成されています。

  • ページ(Page): URLに対応するコントローラーの役割。onInject(パラメータ取得)、onInit(ロジック実行)、onOutput(ビュー割り当て)というライフサイクルを持ちます。
  • リソース(Resource): DBや外部APIとのインターフェース。onReadonCreateなどのメソッドでCRUD操作を実行します。
  • ビュー(View): Smartyテンプレートエンジン(.tpl)を使用した表示層。

アーキテクチャのデータフロー:

新規フレームワークの構造

移行先のシステムはLaravelをベースとしたモダンアーキテクチャを採用しています。 主な構成要素は以下の通りです。

  • Controller: リクエストを受け取ってUseCaseを呼び出します。
  • UseCase: ビジネスロジックカプセル化し、Repositoryを利用してデータを取得します。
  • Repository: データアクセス層(DB操作など)を担当します。
  • ViewModel: ビューに渡すデータを整形・保持するクラス。ビュー側のロジックを排除します。
  • View: Bladeテンプレートエンジン(.blade.php)を使用。

新規アーキテクチャのデータフロー:


実際の作業内容

リポジトリ〜コントローラー開発

新規アプリケーションは各レイヤーの責務が明確に分離されたアーキテクチャを採用しており、今回の移植作業もこの構造に合わせて開発を進めました。

  1. Controller:

    • リクエスト処理: HTTPリクエストのエントリポイントとして、URLパラメータ(columnKey)を受信します。
    • ビジネスロジック呼び出し: 直接的なデータ処理をせず、UseCaseを実行して必要なコラムデータをリクエストします。
    • 結果ハンドリング: UseCaseの実行結果状態を確認し、データが無い場合は404エラー、システムエラーの場合は500エラーを返すなど、適切なエラーハンドリングを実行します。
    • ビュー応答: データ取得成功時、ViewModelにデータを格納してビューに渡します。この際、ユーザーエージェント(User Agent)に応じてPC用(index)またはSP用(index_sp)ビューファイルを動的に選択して返却します。
  2. UseCase & Repository:

    • UseCase: ビジネスロジックの中心として、コントローラーのリクエストを受けて具体的な処理フローを制御します。
    • Repository: 実際のデータベースアクセスはRepository内の実装クラスに委譲されています。これによりビジネスロジックとデータアクセス技術が分離され、保守性とテスト容易性が確保された構造になっています。

実際のデータ取得フロー(例: columnKey=12 リクエスト時):

View Composer活用及びメリット

コラム機能には「過去記事一覧」のように複数のページで共通に表示される要素がありました。 このような共通要素を効率的に管理するため、View Composerを導入しました。

View Composerとは? View Composerはビューがレンダリングされる直前に、特定のデータやロジックを該当ビューにバインドできるようにするLaravelの機能です。これにより、コントローラーで毎回データを渡さなくても、ビューが呼び出される際に自動的に必要なデータが注入されます。

今回のプロジェクトではこの機能を活用してバックナンバー表示ロジックを以下のように実装しました。

class ViewComposer
{
    public function __construct(
        private UseCaseInterface $useCase
    ) {}

    public function compose(View $view): void
    {
        // 1. UseCaseを通じてデータ取得
        $useCaseOutput = $this->useCase->handle();

        // 2. ViewModelでラップしてビューに'vm'変数として渡す
        $view->with(
            'vm',
            new ViewModel($useCaseOutput)
        );
    }
}

テンプレートでの使用例:

{{-- ビューコンポーザーがバインドされたビューをinclude --}}
@include('elements.viewComposer')

View Composerのメリット: * コントローラー肥大化防止: 共通パーツのデータ取得ロジックを各コントローラーに記述する必要がなくなります。 * 再利用性向上: どのビューでも@includeするだけで必要なデータが自動的に供給されます。 * 責務分離: ビュー構築に必要なロジックを専用クラスとして分離できます。

.tplから.blade.phpへの変換(Pythonによる自動化)

移行対象のビューファイル(.tpl)は数が多く、手作業での変換は時間的コストとミスのリスクが高い状態でした。 そこで変換パターンを分析し、Pythonスクリプトconverter.py)を作成して一括変換を実行しました。

自動変換アプローチ

スクリプトでは正規表現を使用して次の変換処理を自動化しました。

  1. 構文変換:

    • Smarty変数展開 {$var} → Blade {{ $var }}
    • コメント {* ... *}{{-- ... --}}
    • Include文 {include file="..."}@include('...')
  2. 静的HTMLからViewModelへの移行:

    • 旧ファイルではHTML内に直接記述されていたタイトルや日付などをViewModelメソッド呼び出しに置換しました。
    • 例: <h1 class="ttl-column">...</h1><h1>{{ $vm->getTitle() }}</h1>
    • 例: <time datetime="..."><time datetime="{{ $vm->getDateTime() }}">
  3. ヘルパー関数適用:

    • 画像パスとリンクをLaravelのasset()url()ヘルパーを使用する形式に変換しました。
    • 例: {$config.img}/path/to/img{{ asset('path/to/img') }}
  4. ヘッダー・レイアウト生成:

    • YAML設定ファイル(config.yml)からメタデータ(タイトル、description、CSS)を読み込み、Bladeの@section@pushディレクティブを自動生成しました。

変換スクリプト例(正規表現による置換ロジック):

# HTMLタグ内の静的テキストをViewModelメソッド呼び出しに置換
content = re.sub(r'(<h1 class="ttl-column">).*?(</h1>)', r'\1{{ $vm->getTitle() }}\2', content)

# datetime属性と表示用日付の置換
content = re.sub(
    r'(<time datetime=").*?(" itemprop="datepublished">).*?(</time>)', 
    r'\1{{ $vm->getDateTime() }}\2{{ $vm->getDateTimeJapanese() }}\3', 
    content
)

# 画像パス置換 (assetヘルパーへ)
content = re.sub(r'\{\$config\.img\}([\w\-\./]+)', lambda m: f"{{{{ asset('{m.group(1)}') }}}}", content)

この自動化により、大量のファイルを短時間で、そして統一された品質で新フォーマットに移行することができました。

結果

🎉

感想

今回のインターンシップは、始まりから予想外の困難がありました。私は現在韓国に在住しており、日本から業務用PCを配送してもらう必要があったのですが、通関手続きなどにより受領が遅れ、実際に作業に投入できる時間はわずか5日間だけでした。

限られた作業時間の制約よりも大きな負担は技術的な部分でした。私はPHP言語自体が初めてだっただけでなく、過去のフレームワークであるBEAR.Saturdayと現在のLaravelの動作方式をどちらも学習し理解しながら作業を進めなければなりませんでした。

「果たして5日という短い時間で、慣れない言語と2つのフレームワークを理解し、課題を完遂できるのか?」という不安が大きかったです。

AIを活用した突破口

このような不安を解消し、スピードを上げることができた核心要因は、Exciteの積極的なAI活用文化でした。

会社レベルで業務にAIツールを積極的に導入し活用する雰囲気だったため、私も躊躇なくAIをメンターのように活用することができました。初めて接するPHP文法やBEAR.Saturdayの不慣れな構造についてAIに絶えず質問してフィードバックを受け、おかげで膨大なコードベースを素早く把握してビジネスロジックを理解する時間を画期的に短縮することができました。

5日間の旅程

限られた時間を効率的に使うため、以下のようにスケジュールを圧縮的に運用しました。

  1. 1日目: プロジェクト開始のためのPC環境設定及びオンボーディング
  2. 2〜4日目: レガシーコード分析及びマイグレーションコード実装集中
  3. 5日目: 最終仕上げ及びブログ振り返り作成

AIという強力なツールのおかげで、期間内に課題を完了することができました。

最後に

物理的距離があるにもかかわらず、5日間細やかにケアしていただき多くのサポートをいただいた伊藤さんに深く感謝申し上げます。