はじめに
こんにちは。株式会社エヌ・エフ・ラボラトリーズ(以下NFLabs.)学生インターンの林です。NFLabs.ではセキュリティエンジニアを育成するための技術学習プラットフォームを開発しています。この学習プラットフォームはWebアプリケーションとして開発されており、私はフロントエンド、バックエンドの両方に関わっています。
この記事では、長期インターンシップでの私の取り組みの一部を紹介します。
プロフィール
私は長崎県立大学大学院 地域創生研究科 情報工学専攻 情報セキュリティコース 修士2年の学生です。大学院ではプロセッサから得られる情報を用いてハードウェア上でマルウェアを検知する研究を行っています。
本インターンには長崎からフルリモートで勤務をしています。
参加経緯
私は本インターンに2022年11月(学部4年の頃)から現在まで参加しています。
NFLabs.を知ったきっかけは2022年4月頃に私の所属している大学で行われた企業説明会でした。
私はセキュリティをメインの事業として行っている企業に興味を持っていたため、企業説明会後もWebでNFLabs.に関する情報を調べていました。
そのときにC0MPUSという長期インターンシップ募集サイトで本インターンのことを知りました。
以前からCTF等に興味があり、「セキュリティを学ぶための環境やコンテンツを独自で構築できないか」と考えていました。そのため、インターンの内容は自分のやりたいことに近いと思い応募しました。
業務内容の紹介
私が関わった業務の一部であるコース機能の実装とその過程でのパフォーマンス改善の取り組みについて紹介します。
コース機能の実装
現在開発中のプラットフォームにはさまざまな分野の学習コンテンツが多数存在します。
開発中のシステムを一部のユーザに試験的に提供したところ、体系的・順序立って学びたい・学ばせたいというニーズがありました。
そこで特定のテーマのコンテンツだけをまとめて、指定された順番に表示する「コース機能」を実装し、よりコンテンツに取り組みやすくしました。
概要


コース一覧にはそれぞれのコースが並んで表示されています。コースのタイトルと説明文、コースの進捗状態が記載されており、どのようなテーマに沿ったコースなのかがわかりやすくなっています。
また、コース内のコンテンツはStepごとに並べられているため、どの順番で取り組めばよいかがわかりやすくなっています。
コースの進捗状況はコース内のすべてのコンテンツを攻略すると完了状態になります。
どのようなユーザ体験が可能になるか
100を超えるコンテンツの中から得意、不得意を考慮した自身の学びたいテーマを重点的に学ぶことが可能になります。また、コース詳細画面にはStep表記があり、あらかじめ指定された順番でコンテンツに取り組むことが可能となります。例えば、Step 1として説明がメインとなるチュートリアル問題、Step 2として基礎問題、Step 3として応用問題に取り組むといった流れで学習することが可能になります。 これにより、自己学習においてもstep by stepで成長しながら解き進められます。
さらに、コース機能を授業や研修に活用することで、その授業や研修のカリキュラムに沿ってコンテンツに取り組むことが可能になります。
技術的に苦労した点
このプラットフォームにはコース機能とは別に、個々のコンテンツの表示・非表示を切り替える機能があります。コンテンツの表示・非表示はチーム管理者がチーム単位で設定することができ、授業や研修に関連するものだけを表示する、といったことが可能です。

コースの進捗状況(CoursesRecords)は各ユーザ(Users)ごとに算出し、かつ非表示設定になっているコンテンツ(TeamsContentsHidden)を除外して算出する必要があります。そのため、コースの進捗状況を算出する際に、「コース内にどのようなコンテンツが存在するか(CoursesContentsの内容)」「そのユーザが所属しているチームで非表示に設定されているコンテンツはあるか(TeamsContentsHiddenの内容)」「そのユーザはどの問題を攻略済みか(ContentsRecordsの内容)」といった情報を組み合わせる必要があります。
コースの進捗状況を算出するタイミングは「ユーザがコンテンツを解き始めた/解き終わった場合」「(チーム管理者が)コンテンツの表示/非表示を切り替えた場合」「(システム管理者が)コース内のコンテンツを追加/削除した場合」の3パターン存在します。
つまり、ユーザがコンテンツを解き始めた/解き終わった場合はそのコンテンツが属しているコース毎、コンテンツの表示/非表示を切り替えた場合はチーム内のユーザ毎かつコンテンツが属しているコース毎、コース内のコンテンツを追加/削除した場合は全ユーザ毎に処理を行う必要があります。
例えば、下記のテーブルが作成されている場合を考えます。
Courses
id title description 1 サーバセキュリティコース Webアプリケーション、プラットフォームのセキュリティの基礎を学ぼう 2 SQLインジェクション特訓コース SQLインジェクションを重点的に学ぶためのコースです Contents
id title description 1 SQLインジェクションの学習 SQLインジェクションについて学習してみましょう 2 ネットワークスキャンの学習 ネットワークスキャンを実行してみましょう 3 SQLインジェクション攻撃検証 SQLインジェクション脆弱性を検証してみましょう CoursesContents
course content 1 1 1 2 2 1 2 3 ContentsRecords
user content started completed 1 1 2024-11-08 13:05:30 null 1 2 2024-11-08 11:28:23 2024-11-08 12:01:11 1 3 2024-11-08 10:14:50 2024-11-08 10:45:49 CoursesRecords
user course started completed 1 1 2024-11-08 11:28:23 null 1 2 2024-11-08 10:14:50 null TeamsContentsHidden
team content null null
チームID 1に所属するユーザID 1がコンテンツID 1を解き終わった場合のSQLはこのようになります。
UPDATE ContentsRecords SET completed="2024-11-08 13:33:37" WHERE user = 1 AND content = 1; SELECT course FROM CoursesContents WHERE content = 1; SELECT content FROM TeamsContentsHidden WHERE team = 1; SELECT content FROM CoursesContents WHERE course = 1; SELECT completed FROM ContentsRecords WHERE content = 2 AND user = 1; UPDATE CoursesRecords SET completed = "2024-11-08 13:33:37" WHERE user = 1 AND course = 1; SELECT content FROM CoursesContents WHERE course = 2; SELECT completed FROM ContentsRecords WHERE content = 3 AND user = 1; UPDATE CoursesRecords SET completed = "2024-11-08 13:33:37" WHERE user = 1 AND course = 2;
上記のように対象となるコースの数だけデータの取得、更新を繰り返す必要があります。(いわゆるN+1問題が発生してしまいます)
その結果、SQLの実行回数が増え、処理待ち時間やシステムへの負荷に大きな影響を与えてしまいます。
そこで、この問題を防ぐために、必要なデータをすべてDBから事前に取得し(eager loading)、コース進捗状況の算出処理を行い、最後に変更があるデータのみまとめてDBに更新する(bulk update)という実装を行いました。
この方法は大量のデータを一度にロードするため、メモリ消費が増加するデメリットはありますが、今回は許容しています。
UPDATE ContentsRecords SET completed = "2024-11-08 13:33:37" WHERE user = 1 AND content = 1; SELECT * FROM TeamsContentsHidden; SELECT * FROM CoursesContents; SELECT * FROM ContentsRecords; UPDATE CoursesRecords SET completed = "2024-11-08 13:33:37" WHERE user = 1 AND course = 1 OR course = 2;
これにより、都度DBにアクセスすることがなくなり、必要最低限のDBへのアクセス(事前取得+まとめて更新)で実装でき、パフォーマンスを大幅に改善することができました。
インターンシップを振り返って
私はこのインターンに参加するまでチーム開発の経験はほとんどありませんでした。インターンに参加することで学生のうちから技術的な学びはもちろん、チーム開発を行う際のノウハウを知ることができるのはとてもよい機会だと感じています。
また、コードレビューではより効率的な実装方法やパフォーマンスを意識した実装などの意見をいただくことがあり、私にとってはすごく学びになっています。
最近ではGatherというコミュニケーションツールが導入され、より気軽に「ちょっと相談する」が可能になったように感じています。
本インターンに参加して2年ほど経ちますが、プロダクトがどんどん出来上がっていくタイミングで携わることができ、かなり貴重な経験をさせていただいています。加えて、自分の書いたコードがプロダクトに反映されていくのはとてもワクワクします。
おわりに
今回は学習プラットフォームの開発に関わっている学生インターンの業務内容の紹介を行いました。
NFLabs.のインターンについて興味を持たれている方の参考になれば幸いです。
(代理投稿 by hysnf)