はじめに
こんにちは。株式会社エヌ・エフ・ラボラトリーズ(以下 NFLabs)学生インターンの中辻です。 NFLabsではセキュリティエンジニアを育成するための技術学習プラットフォームを開発しています。この学習プラットフォームは Web アプリケーションとして開発されており、私はデザインとフロントエンド開発の業務に携わっています。
プロフィール
私は金沢工業大学 情報フロンティア学部 メディア情報学科の学部 3 年生です。大学では、アセンブラからネットワーク、Web 全般などの幅広い情報技術と、それらを活かしたコンテンツ制作を学習しています。
UI デザインと Web 開発に興味があり、個人や大学の課外活動、有志のチームと共に Web サイトやサービスのデザインと開発に関わっています。
本インターンには石川県金沢市の自宅からフルリモートで参加しています。
参加経緯
私は 2024 年 2 月からこのインターンに参加しています。
インターン参加前、実務経験を積みたいと考え、UI デザインとフロントエンド開発を両方経験できる長期インターンを探していました。しかし、デザイナーとしてのインターン募集は少なく、フロントエンド開発ができるものも見つけるのが難しい状況でした。
そんな中で、NFLabs の CTO からインターンのお誘いのメールを頂き、業務内容を確認後、二つ返事で参加しました。
業務内容の紹介
プラットフォーム開発における UI デザインとフロントエンド開発の具体的な業務を紹介します。
UI デザイン
UI デザインの業務は主に3つに分けられます。改善案のデザイン制作、作成したデザインの改善、新機能のデザイン作成です。それぞれの内容を紹介します。
1.改善案のデザイン制作
アジャイル開発で MVP を優先した結果、当初は既存テンプレートを流用する形で UI が構築されていました。そこで、当初は実際のプラットフォームを触りながら問題点を抽出し、Figma 上でワイヤーフレーム化する業務を主に担当しました。しかし、当時のプラットフォーム理解が浅かったことや、大きなデザイン変更に伴う API 側の仕様調整の必要性などがあり、解決すべき課題が多くありました。

例えば、画像のようなコンテンツの入り口となるコンポーネントひとつだけでも、図に示したような課題がいくつか見つかりました。
2.作成したデザインの改善
そのため、社員の方々と話し合いを繰り返しながら、仕様を満たしつつ、ユーザー体験を向上させるためのワイヤーフレーム改善を進めています。このプロセスを繰り返すことで、当初のデザインから大きく変わりましたが、現在のデザインは確実に良いものになっていると自負しています。

上の画像は、先ほど紹介したコンポーネントを改善したものです。複数タグなどの仕様に対応し、目に優しく、シンプルでありながら遊び心のあるデザインを目指しました。
このプロセスで改善されたものをいくつか紹介します。
-
メニューバー
メニューバーの初代と 2 代目は、レッドチームとブルーチームの双方の知識を学べるプラットフォームであることを示す、赤と青のグラデーションを用いていました。しかし、派手なグラデーションや常に表示されているメニューは、長時間の滞在に不向きであり、学習の妨げになることなどへの懸念や、ストレスフリーな操作を追求した結果、現在のハンバーガーメニューに改善しました。
-
チャレンジ環境管理メニュー
本プラットフォームは、ブラウザからリモートでアクセスできる仮想マシンを立ち上げてチャレンジを進めます。仮想マシンの管理をするメニューのデザインには長い時間をかけました。メニューの使い方は初回のチュートリアルで学習してもらうことで、文字情報の多いメニューにうんざりしないよう、表示する文字情報は必要最低限に留めました。
もしアイコンの意味を忘れてしまってもツールチップで補足できるように設計しました!
今後もユーザーからのフィードバックや、プラットフォームを使う中で気づいた点を反映させ、継続的に改善を行っていきます。
3.新機能のデザイン作成
この業務は、構想段階のアイデアを可視化するもので、様々な画面案を出し、社員の方々と相談して案を絞り込み、ブラッシュアップします。具体的な例として、現在実装済みのスキル分析機能を紹介します。
スキル分析機能は当初、レーダーチャート案から始まりましたが、ヒートマップによる可視化が提案され、草案が二つある状態でした。議論を重ねた末にヒートマップに決定し、レイアウトや配色の改善、最大レベル到達時の色変化、新しいデザインテイストの適用を行い、現在のデザインが完成しています。
このように作成した新機能も、継続的にデザインの改善を進めています。
その他のデザイン業務
紹介した UI デザイン以外にも、2024年夏に開催された学生向けイベントのバナー画像の作成や、プラットフォームのロゴ案の作成など、デザイン全般の業務にも携わっています!
フロントエンド
デザイン業務に加えて、フロントエンドの開発も担当しています。主に Next.js (Typescript + Tailwind CSS) を使用し、機能やコンポーネントの実装・改善を行なっています。大きく分けて 2 つの具体的な業務について紹介します。
ワイヤーフレームの落とし込み
Figma で作成したワイヤーフレームをコードに落とし込み、同様の見た目と機能を実装します。新しいデザインテイストに合わせる作業や、新機能の実装も行っています。
UX の改善
ワイヤーフレーム通りに実装しても、実際の使用時に次のような問題が見つかることがあります。
- カーソルホバー時などのインタラクションの不足
- 画面サイズの変更時のレイアウト崩れ
- ユーザーにとって分かりにくい操作の流れ
- 不適切なコントラスト
- デザインテイストの不統一
これらの問題は発見次第、迅速に改修を行っています。
そのため、ワイヤーフレームの完全な再現よりも、優れた UX の実現を優先しています。ただし、通常、デザイナーがステークホルダーとのヒアリングを経て確定したデザインを、開発者が独自の判断で修正することは認められませんが、現在のプロジェクトでは、私自身がデザインとフロントエンドの両方を担当しているため、例外的にそのような判断が可能な状況にあります。とはいえ、この体制を継続することは開発の持続可能性に難があると感じているため、後述する対策を講じていきたいと考えています。
具体例の紹介
ワイヤーフレームの落とし込み・UX の改善を施した一例を紹介します。
一枚目がワイヤーフレーム、二枚目が実際の画面です。
全体的な見た目は同じですが、より良いユーザー体験を実現するため、実際の画面では以下のような改善を加えています。
import React from 'react'
import MissionAccordion from '@/features/Challenges/components/ChallengeDetail/MissionAccordion'
import AdviceChatBot from './AdviceChatBot'
import { Mission, ChallengeRecord } from '@/types/Problem'
import { Challenge } from '@/types/Problems'
import SanitizedHTML from '@/features/Challenges/components/ChallengeDetail/SanitizedHTML'
import { useAuth } from '@/context/AuthProvider'
import ProblemProgressBar from './ChallengeProgressBar'
import Link from 'next/link'
import Icon from '@/components/common/Icon/Icon'
import { ADVANCED_FEATURE_MOCK_CONTENT_ID } from '@/features/Challenges/types'
import { useSearchParams } from 'next/navigation'
import { path } from '@/utils/path'
type Props = {
challenge: Challenge
challengeRecord: ChallengeRecord | null
missions: Mission[]
prologue: string | null
updateTask: (taskId: string) => void
}
const BackListButton = () => {
const searchParams = useSearchParams()
const courseId = searchParams.get('courseId')
const label = courseId ? 'コース詳細へ' : 'チャレンジ一覧へ'
const href = courseId ? path.courses.course(courseId) : path.challenges.top()
return (
<Link
href={href}
className="flex w-fit items-center gap-2 pt-12 text-neutral-300 opacity-70 duration-300 hover:opacity-40"
>
<Icon type={'book'} width={16} height={16} />
<p>{label}</p>
</Link>
)
}
const ChallengeDetail: React.FC<Props> = ({
challenge,
challengeRecord,
missions,
prologue,
updateTask,
}) => {
const { user } = useAuth()
if (prologue == null) return <div>No prologue found</div>
return (
<>
<div className="pointer-events-none fixed left-0 right-0 top-0 z-10 h-28 w-full bg-gradient-to-b from-neutral-900 from-75% to-transparent" />
<div className="scrollbar-hide mx-auto w-screen space-y-4 overflow-y-auto text-gray-200">
<div className="bg-neutral-80 bg-neutral-900 px-[10vw] pb-8 pt-16">
<BackListButton />
<div className="flex gap-2 pt-6">
{challenge.tags.map((tag, index) => (
<div
key={index}
className="mt-0.5 whitespace-nowrap rounded-md bg-neutral-700 px-1 py-0.5 text-sm font-medium leading-[normal] tracking-wide text-purple-200"
>
# {tag.name}
</div>
))}
</div>
<h1 className="w-full py-8 text-4xl font-bold">{challenge.title}</h1>
<ProblemProgressBar missions={missions} />
</div>
<div className="w-full px-[10vw]">
<SanitizedHTML html={prologue} enableBlur={false} />
<div className="mx-auto space-y-4 overflow-y-auto py-12 text-gray-200">
<div className="flex w-full flex-col gap-8">
{missions.map((mission) => {
return (
<MissionAccordion
key={mission.order}
mission={mission}
challengeRecord={challengeRecord}
challengeId={challenge.id.toString()}
updateTask={updateTask}
/>
)
})}
</div>
<div className="pt-12">
<BackListButton />
</div>
</div>
{/* adviceの利用が許可されている、かつ、3大機能が有効の場合、またはモックコンテンツのみ表示 */}
{user?.team?.is_advice_enabled &&
(challenge.id === ADVANCED_FEATURE_MOCK_CONTENT_ID ||
challenge.advice_enabled) && (
<AdviceChatBot
challengeId={challenge.id}
givenup_at=""
analysisStatus="completed"
/>
)}
</div>
</div>
<div className="pointer-events-none fixed bottom-0 left-0 right-0 h-16 rounded-lg bg-gradient-to-t from-neutral-900 to-transparent opacity-60" />
</>
)
}
export default ChallengeDetail
- コンテンツの表示幅を広くする
- 進捗バーの全問数の表示サイズを大きくする
- 進捗バーの各回答状況に色をつける
- 「一覧に戻る」を追加し動線を確保する
- タグに背景色を追加する
このように、ワイヤーフレームを基礎としながら、実際の使いやすさを重視した改善を重ねています。
デザイナーとエンジニアの連携強化への取り組み
デザイナーとエンジニアの連携を強化するために、当初の課題、解決したこと、そして今後の展望について説明します。
当初課題
当初の課題として、デザイン共有のための公式な窓口が存在せず、コミュニケーション不足が発生していました。
具体的には、デザインを作成しても実装者に詳細な仕様を十分に伝えられず、実装された結果が想定していたデザインや挙動と異なることがありました。
さらに、デザイナーの作成物が絶対的に正しいという空気感があり、ワイヤーフレームに対する建設的なフィードバックを得にくい状況がありました。
現状
解決できたこと
現在に至るまで以下のような遍歴があり、コミュニケーション不足は解消されていきました。
-
Slack 上にデザインチャンネルが設置
社員の方々とワイヤーフレームに関する質問や意見を交換できる窓口となりました。メッセージのやりとりに加え、Canvas を活用した質問リストなども設置され、デザイナーと実装者間の情報共有がより円滑になりました。
また、パドルミーティングでワイヤーフレームのデザインレビューを実施するようになり、議論を重ねながらデザインを作成できる体制が整いました。
現在このチャンネルは、ワイヤーフレームだけでなく、新機能の実装前のアイデア出しや、デザインに関する気づきやトレンドを気軽に共有する場としても活用されています。
-
Gather の導入
その後、バーチャルオフィスサービスであるGatherが導入されました。そのため、メンバーとのコミュニケーションがテキストベースで行われていた以前よりもスムーズに取れるようになりました。
以前使用していた Teams や Slack のパドルよりも手軽になり、より頻繁にデイリースクラムやデザインレビューを行うようになりました。
-
Github でタスクの一元管理
デザインに関するタスクを徐々に Github の issue で一元管理し、フィードバックやメモを issue のコメントに記載するようになりました。これにより、次のようなメリットが生まれました。
- タスクの管理が容易になった
- デイリースクラムや Slack 上での共有がスムーズになった
- 細かなデザイン修正を PR と紐付けることで、コードの迅速な修正が可能になった
このように、デザインのタスクも Github 上で一元管理することで、大幅な効率化を実現できています。
また、当初はデザインの業務のみでしたが、フロントエンド部分にも携わるようになりました。
そのため、デザインとコードに溝がある箇所は、デザインを作成した自分自身と、デザインについて頻繁に話し合うメンバーでコードを改善することで、その溝をシームレスに埋められるようになりました。
課題
現状、デザインテイストというふわふわしたものに頼りながらデザインを進めているため、実装者全員が開発しやすい環境とは言い難い現状です。また、ワイヤーフレームを作成している現在の Figma ページには、以下のような課題があります。
- 未使用のワイヤーフレームの散乱
- どのページのワイヤーフレームなのかわかりづらい
- 再利用可能なコンポーネントが少ない
- レスポンシブに対応したワイヤーフレームが存在しない
- Dev モードできれいなコードを出力できない
今後の展望
実装者全員が開発しやすく、誰が実装しても同じデザインになるよう、以下のことを進めていきたいと考えています。
Figma の整理
デザイナーと実装者をつなぐインターフェイスである Figma を、以下のように改善していこうと考えています。
- 未使用のワイヤーフレームをメインのページから削除
- フレーム名の改善
- 階層のわかりやすい位置に配置
- 再利用可能なコンポーネントの作成
デザインシステムの実装
記事内で「デザインテイスト」という言葉を繰り返し使用してきましたが、これは明文化されたルールは存在しないものの、ある程度の方針が定まっている現状を表しています。
デジタル庁や独自のデザイン組織を持つ企業が公開しているデザインシステムを参考に、現在の「デザインテイスト」を体系的な「デザインシステム」として確立していきたいと考えています。
また、現在は類似した UI 要素でもコンポーネント化されていないものが多いため、デザインシステムに基づいたコンポーネントを Figma とコードの両方で作成し、既存の要素を置き換えていく予定です。
インターンシップを振り返って
参加当初は開発段階だったプラットフォームが、現在は β テストの段階まで進展しており、開発から運用への過渡期という貴重な時期にインターンとして関われていることを非常に誇りに感じています。
現在はユーザーの生の声を直接聞けるようになったため、それらのフィードバックを活かしながら、社員やインターン生と共により質の高いプラットフォームに仕上げていきたいと考えています。
このインターン期間を通して、デザイン力と技術力の両面で大きな成長を実感できたため、それぞれの観点から振り返ってみたいと思います。
デザイン力
インターンを始める前は一人で作成することの多かったデザイン制作ですが、複数人でデザインを進めるようになり、一人だけではわからなかった視点からの意見や、さまざまなアイデアを取り入れながら進められるようになりました。
そのため、開発メンバーやユーザーからのフィードバック、仕様を鑑みながらのデザインなど、参加以前までは経験できなかったデザインを通して、広い視点からのデザインができるようになったと実感しています。
技術力
インターン参加以前は Next.js の経験があったものの、静的な Web サイトを作成できる程度の技術力に留まっており、本格的なアプリケーション開発の経験はありませんでした。
しかし、業務を通して API との連携、アニメーション実装、複雑なロジックの組み込みなど、実践的な開発経験を積むことができる上、レビュー時に記述したコードに対するフィードバックをいただけることもあり、技術力は飛躍的に向上しました。
おわりに
NFLabs.は、豊富なセキュリティ知識を持ち、バックエンドとフロントエンドの枠を超えた幅広い技術領域を活用してプラットフォーム開発を進めています。
そのため、インターン生は自身の興味関心に合わせた業務に取り組むことができ、得意分野をさらに伸ばすことも、興味のある新しい分野に挑戦することもできる環境が整っています。
この記事が NFLabs のインターンについて興味を持たれている方の参考になれば幸いです。