Excite就業型インターンでのフレームワーク移行タスク

2024年8月5日からおよそ一ヶ月間に渡ってエキサイト株式会社のLife&Wellness事業部で就業型インターンをさせていただいたかわいです。インターンの参加理由からこのインターンで得られたことを書いていきます。

誰向け?

インターンを探している、または参加しようか迷っている人向けです。私はインターン参加にあたりいくつか狙いを持って参加し、その狙いがどうだったかについて学びで書いています。何ができたかについても触れているので、私と同じような課題感を持っている人がインターンに参加するきっかけになれば、と思っています。

自己紹介

普段は大学院でセキュリティ関連の研究を行っています。研究とは別に個人の趣味でTypeScriptやGoを使ったWebアプリの開発を2年ほど行っています。これまで技術系のインターンやアルバイトに参加したことがなく、開発経験が足りていないと感じていました。経験不足を埋めるために、個人ではできないチーム開発の経験を積むこと、実運用されているコードがどのようなものかを知ること、が可能であるインターンに参加することを考えました。

そのような中でエキサイト株式会社のLife&Wellness事業部にインターン生として関わらせていただきました。リポジトリパターンやユースケースなど、これまで気にしてこなかった変更の容易さや保守性の点で大いに助けていただきました。

インターンでやったこと

Life&Wellness事業部は主に占いサービスの運営を行っています。その中で私が関わったタスクは「excite電話占い」のPHPフレームワークをBEARからLaravelへと移行するタスクです。同じタイミングでインターンに参加していた方とメンティー二人、メンター二人体制で進めていきました。

占い特集ページの移植が担当範囲でしたが、私にPHPの経験がなかったことから、ロジックを含まないページの表示のみを行うことから割り振っていただきました。その後、データの処理のロジックを含むページの移植に取り組みました。2つ目のタスクで移植元と処理のフローが変わったのでサンプルとして一部のクラスを用意してくださりました。開発をしやすくするためのCI/CDツールも豊富で、レビューも丁寧に行ってくださいました。何より、何故変更するのかの理由を明確に説明してくださりとても参考になりました。

学び

2種類の経験を積むことを目的にインターンに参加しました。それぞれどんな結果が得られたのかまとめました。

チーム開発

個人開発と最も異なる点として「明確にタスクが割り振られ期限が存在する」という点がありました。そのため「どこに時間を掛ければいいのか」に気を使いました。そのため、どこに時間を掛ければいいのか、という点には気を使いました。とはいえ、普段あまり意識していなかった時間の割り振りがすぐにできるとは考えていなかったので、自分で抱え込みすぎないことを意識していました。気をつけていたのは自分ができていない、または理解していないことへの対処方法です。自分が詰まっていることが調べればわかることなのか、それともプロジェクト固有で聞かなければわからないことなのかの判別をつけることが出来ないため、時間制限を設けていました。決まった時間調べ、それでも成果が得られなかったときにメンターに質問していました。どの程度時間をかけていいのかは初め自分で決めてしまいましたが、途中でメンターに聞いた方が良い事に気づきました。気づいた後で、ミーティングの際にどれだけ時間をかけて良いのか確認することができたので共通認識を作ることができました。自分の学びと進捗のバランスについてはある程度うまくいっていたと思います。

逆にもっと別のやり方があったかなと思ったことはメンターへの質問の仕方です。わからないところに対して何がわからないのかを把握して、調べたことや取り組んだことを説明することは意識していましたが、あまりうまくいきませんでした。ロジックを含むページの移植でデータ取得があったのですが、初めてユースケースに触れたので、全てがわからないことでした。そのため、調べた事と理解したことの区別がうまくできませんでした。実装のサンプルと睨めっこしながら、まだ整理できていないことをメンターに聞き続けることになってしまいました。わからないことがひとつ解消されたら、焦らず自分でまた次のエラーに取り組めば良かったのですが、大量のわからない事に押し流されてしまいました。今回の経験でわからない事を一度に全て解消しようとすることはかなり無謀だと分かりました。わからないことを整理するために問題の構造化をできるようになる、という課題が見つかりました。これは個人開発でもできることなので、意識して取り組んでいくつもりです。

コーディング

今回のインターンでの一番の学びは変更容易性やテストしやすい書き方です。

あるページの実装において、コンフィグからデータを読み込んでいるところがありました。このプロジェクトでは、レイヤードアーキテクチャのような構成になっています。そのため、ロジックの分離がリポジトリーやユースケースを用いることで行われています。私が取り組んだタスクでは次のような処理の流れになっていました。

  1. コンフィグからリポジトリーがデータの読み込みを行う
  2. ユースケースリポジトリーが取ってきたデータを整形し、コントローラーに渡す
  3. コントローラーはビューモデルを作り、bladeファイル(Laravelのテンプレートファイル)に引き渡しページビューになる

リポジトリーの実装として初めに私が書いたのは次のようなコードになります。

<?php

final readonly class ResultRepository implements RepositoryInterface
{
    public function __construct(ResultKey $resultKey)
    {
        $resultList = $this->getResultList()
        return $resultList[$resultKey]
    }

    public function get(): Result
    {
        return $this->result;
    }

    /**
     * @return array<string, Result> string is resultKey
     */
    private function resultList(): array
    {
        $result = include './resultList.php';
        return $result;
    }
}

問題点

  • includeで直接読み込みを行なっているのでテストしにくい

相対パスで指定先から読み込みをして、指定されたキーの有無で結果が変わります。テストを書いた方が望ましいコードですが、テストのたびに毎回ファイルアクセスをしなければなりません。並列実行できなくなってしまう上にコンフィグに正しく結果が入っている保証さえありません。

  • get()で直接result | nullを返している

たまたま返却値が1種類のデータのみで済んでいますが、複数のデータを返却しなければならなくなった時に大きな変更が必要になります。

解決策

  • ファイル読み込み

Laravelのヘルパー関数でファイル読み込みを行いました。この変更によって、相対パスを使わなくてよくなった上に、テストではモックすることでファイルアクセスをなくせました。

  • get()の返り値

値オブジェクトResultOutputを作り、resultOutputからのデータ取り出しはユースケースに任せます。ユースケースgetResult(), getKey()メソッドなど、取得データの処理を行ってもらいました。

これらの変更をコードに反映させると次のようになります。

<?php

use Illuminate\Contracts\Config\Repository as ConfigContract;

final readonly class ResultRepository implements ResultRepositoryInterface
{
    public function __construct(private ConfigContract $config)
    {
    }

    public function get(ResultKey $resultKey): ResultRepositoryGetOutput
    {
        $resultList = $this->getResultList();

        return new ResultRepositoryGetOutput($resultList[$resultKey->toString()] ?? null);
    }

    /**
     * @return array<string, Result> string is ResultKey
     */
    private function resultList(): array
    {
        $resultMaster = $this->config->get('Feature.resultMaster');
        $result = [];
        foreach ($resultMaster as $key => $value) {
            $result[$key] = new result(
               ...
            );
        }

        return $result;
    }
}

合わせてファイル読み込みのテストは次のようにモックできます。

<?php
$configMock = Mockery::mock(ConfigContract::class);
$configMock->shouldReceive('get')
        ->andReturn([...]);

これで問題になっていたテストしにくいファイル読み込みの処理をなくすこと、リポジトリーとユースケースの責任の分割が行えました。よりテストしやすく、変更に強いコードを書くことが出来ました。

最後に

今回のインターンで関わってくださった皆様に、この場を借りてお礼申し上げます。インターン期間中はメンターの方はもちろん、上長や話したいと希望した人との面談まで行ってくださいました。どなたも私の質問や説明に対して答えを返すだけでなく、理由や他の案も考慮に入れて応えてくださいました。就活やインターンの短い期間に限らず、社会に出た後のキャリアについてもとても参考になりました。

メンターやLife&Wellness事業部の方々のサポートによりインターンに参加した2つの目的は十二分に達成することが出来ました。目的を持ってこれができるようになろう、と参加するとそれ以上のものができるようになり、新しく課題も見つかります。エキサイトの就業型インターンは経験を積み、できることを増やしたい人にとてもおすすめです。ぜひ、申し込みましょう。