はじめに
こんにちは!2025 年 8 月の一カ月の間、エキサイト株式会社の BB 事業部で就業型インターシップ「Booost!!!」に参加させていただいた久々津 歩です。今回は、インターンで学んだことを中心に紹介できたらなと考えています!!
自己紹介
私は大学 3 年生で、データサイエンス系の専攻です。これまでは主に個人開発をしており、Web アプリケーションであれば個人ブログを自作したり、最近は VSCode の拡張機能を作成しました。インターンはこの夏から参加するようになりまして、Booost!!!は二回目のインターン参加になります。一回目はハッカソン形式のインターンだったので、就業型で設計やドキュメント作成などまで携わる、「エンジニアとして仕事する」は今回のインターンが初めてです。
インターンシップの業務内容
BB 事業部のバッチ処理等で扱われている API の一部が独自フレームワークを使用しており、そのうち二つの API を Laravel に移行する業務に取り組みました。私は Ruby on Rails,Spring Boot には触れたことがあったのですが Laravel は初めて、PHP という言語はとても扱いやすく、すぐに手に馴染んでくれたので安心しました。私の場合はバックエンドにしっかり取り組みたかったので、メンターのエンジニアの方に提案をいただいた業務の中から、バックエンドのみ集中できるタスクを選択してやらせていただきました。
学んだこと
このインターンを通して、すごく多くのことを学ぶことができました。特にインターンとしては珍しく設計の部分に触れることできたので、設計思想のことにも触れつつ、印象に残っている点をまとめようと思います。
開発を通して学んだこと
今回のインターンで学びになったことは、依存性の逆転と責務の分離を考えて実装するという一連のフローを経験できたことだと思います。どちらも、オブジェクト間の関係を疎結合に保ち、オブジェクトの変更・削除・追加を行いやすくする目的をしやすくする目的で、取り入れらていると思います。
依存性の逆転
ネットで調べたりすると、「依存性の逆転」の説明には、「上位の層が下位の層に頼るのではなく、お互いに抽象的なルール interface に頼ると言う原則」とかなり難しい言葉で書かれていたので、困惑しました。
そこで私は、社員の方が実装したコードを「Service 層と Repository 層」に絞って、まず読んでみることにしました。
そうすると「どうやら Service 層では Repository 層の interface をコンストラクタで登録しているらしい、実際の実装クラスは、どうやら別のところで DI*1しているらしいぞ」と理解しました。
interface には、「どのようなメソッドがあって、それがどんな値を返すか?」しか記載されていません。
// Repository層のInterface
interface SomeRepositoryInterface
{
/**
* @param int $id
* @return SomeModel
*/
public function findSome(int $id): SomeModel;
}
// Repository層の実装クラス
class SomeRepository implements SomeRepositoryInterface
{
public function findSome(int $id): SomeModel
{
// 実際の実装
}
}
// Service層の実装クラス
class SomeService implements SomeServiceInterface
{
// コンストラクタで渡しているのはinterfaceだけ!!
public function __construct(
private SomeRepositoryInterface $someRepostiroy
){}
// その他の実装
}
SomRepositoryInterfaceに対して、実際に SomeRepository という実装を渡してくれるのは、Laravel の DI コンテナが担当してくれます。
これによって、Service 層は Repository 層の具体的な実装から完全に独立できます。
例えば、将来的にデータベースを PostgreSQL から MySQL へ変更したり、利用する ORM を変更したりしても、findSomeメソッドがSomeModelを返すということさえ守られていれば、Service 層のコードには一切変更が必要ないのです。
この関係を、クリスマスのサンタクロースに例えてみました。
子供(Sservice 層):「プレゼントが欲しい」とお願いする人。
サントクロースという役割(Repository Interface):「プレゼントをくれる存在」
プレゼントを準備する人(Repository の実装):実際におもちゃ屋へ走るお父さん、ネットで注文するお母さんなどの、プレゼント用意する具体的な誰か。
子供は「サンタクロース」という役割(interface)にお願いするだけで、プレゼントが手に入ります。その裏でどうやってプレゼントが準備されているのかは子供は知る必要がありません。プレゼントがどのように準備されても、子供(Service 層)は変わらずプレゼント(結果)を受け取って喜んで遊んで(処理を実行する)くれるわけです。
このように、具体的な実装を知らなくても、決められた役割(interface)さえ果たしてくれればそれで良い、というのが依存性の逆転の強力な点だと理解しました。
責務の分離
依存性の逆転とセットで強く意識したのが責務の分離です。これは、クラスやメソッドごとに役割を一つに絞り、余計な仕事をさせないという考え方です。
私が一番に分離させるので苦労したのは、
- Controller:HTTP リクエストを受け取り、適切な Service を呼び出して、HTTP レスポンスを返してくれる存在
- ResourceModel:要件に合わせて HTTP レスポンスの構造を整形してくれる存在
上記の2種類の役割が分割しにくく、苦戦しました。理由としては、HTTP レスポンスの形式が JSON だけでなく、PHP でシリアライズされた text データなど多岐にわたっていたからです。
結果としては Controller はクエリパラメータによって、レスポンス形式のタイプを切り分ける。Resource Model は JSON やテキストデータでも変わらないデータの構造(JSON Key など)を整形する。という役割分体に落ち着きました。
これから学んだことは、要件定義の段階でオブジェクトの役割をなるべく決めておくことが重要という点です。オブジェクトの役割を言語化しておくというのは、これからの開発で使えそうなテクニックだなと思いました。「このオブジェクトの役割は〇〇」と言えないときは、一つのオブジェクトの役割が肥大していないか確認してみると、責務が分離された丁寧な設計に近づくかもしれません。
開発に対しての姿勢
ジュニアエンジニアに求められるのは素直さだと言うこと
インターン中と言うか、面接の時からずっと身に染みています。
「どれだけのコードを読み吸収して、ちゃんと行ったことを他のエンジニアに相談できるか?」がインターン中に一番求められたかなと思いました。
インターンを始める前は依存性の逆転も Trait *2も全く知りませんでしたし、依存関係を閉じ込める理由も理解できていませんでした。
上記のことを知って実際にコードを書くということができたのは、わからないことを直ぐに調べて、社員の方が実装したコードを読んだからだと思います。忘れないようにしたいです。
YAGNI の法則(You Aren't Going Need It.)
訳すると「きっとそれは必要にならない」だそうです。この考えからは非常に勉強になりました、必要になったら追加するという簡単な法則ですが、やっぱり色々な想定をしてしまうものだと思います。開発する API に必要なものを必要な分だけ実装する、無駄なクエリパラメータ等を思い切って削除した経験ができたのは良い経験だったと考えています。
コミュニケーションの重要性
素直さの話にも通づるものがあると思いますが、PR 作成時のコメントについてインターン中にご指摘いただきました。PR のレビューには時間がかかります、だから PR コメントは要点を絞ってできる限り見やすく書く必要があるということに気付かされました。より良いコードを生産するのも重要ですが、より良くコードを伝えるのも重要だと知ることができました。
最後に
メンターのエンジニアの方々、面接をしてくださった人事の方々とエンジニアの方々、またインターンを開催するにあたりご尽力いただいたエキサイト株式会社の方々本当にありがとうございます。
技術的な知見も大きく増えたのはもちろん、実際に仕事として開発をするにあたり、求められることや自身の見つめ直すことの発見等、本当に様々なことを学ばせていただきました。
私が作成した API はバッチ処理に組み込まれることもあるようなので、長い時間コードが駆動して、そして誰かに改修される時に、読みやすいコードであることを祈っています。
約一ヶ月という本当に短い期間でしたが、充実したインターンシップとなりました、エキサイト株式会社の皆様ありがとうございました!!
*1:Dependency Injection: 依存性の注入,外部からオブジェクトをセットする仕組み
*2:PHPの言語機能の一つ、呼び出すことで、どのクラスでも同じ処理を行わせることができる。公式マニュアル:PHP: トレイト - Manual